diff --git a/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysis.java b/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysis.java index 4f5aebd540..e8c240c962 100644 --- a/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysis.java +++ b/tycho-apitools-plugin/src/main/java/org/eclipse/tycho/apitools/ApiAnalysis.java @@ -236,9 +236,9 @@ private BundleComponent importProject() throws CoreException, IOException { } private void createOutputFolder(IProject project, IPath projectPath) throws IOException, CoreException { - Map outputJars = computeOutputJars(project); IJavaProject javaProject = JavaCore.create(project); if (javaProject != null) { + Map outputJars = computeOutputJars(project, javaProject); IFolder outputFolder = project.getFolder(outputDir); // FIXME see bug https://github.com/eclipse-pde/eclipse.pde/issues/801 // it can happen that project output location != maven compiled classes, usually @@ -258,7 +258,7 @@ private void createOutputFolder(IProject project, IPath projectPath) throws IOEx } } - private Map computeOutputJars(IProject project) throws CoreException { + private Map computeOutputJars(IProject project, IJavaProject javaProject) throws CoreException { Map outputJars = new HashMap(); IPluginModelBase base = PluginRegistry.findModel(project); if (base != null) { @@ -278,23 +278,20 @@ private Map computeOutputJars(IProject project) throws CoreExcep // are some cases where this is not true... lets cheat and look at the // classpath instead... String key = name.substring(IBuildEntry.JAR_PREFIX.length()); - IJavaProject javaProject = JavaCore.create(project); - if (javaProject != null) { - IClasspathEntry[] rawClasspath = javaProject.getRawClasspath(); - for (String token : entry.getTokens()) { - IPath srcPath = project.getFolder(token).getFullPath(); - for (IClasspathEntry classpathEntry : rawClasspath) { - if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { - IPath path = classpathEntry.getPath(); - if (srcPath.equals(path)) { - IPath outputLocation = classpathEntry.getOutputLocation(); - if (outputLocation == null) { - outputLocation = javaProject.getOutputLocation(); - } - IFolder folder = getProjectFolder(outputLocation); - String output = folder.getProjectRelativePath().toString(); - outputJars.putIfAbsent(output, key); + IClasspathEntry[] rawClasspath = javaProject.getRawClasspath(); + for (String token : entry.getTokens()) { + IPath srcPath = project.getFolder(token).getFullPath(); + for (IClasspathEntry classpathEntry : rawClasspath) { + if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + IPath path = classpathEntry.getPath(); + if (srcPath.equals(path)) { + IPath outputLocation = classpathEntry.getOutputLocation(); + if (outputLocation == null) { + outputLocation = javaProject.getOutputLocation(); } + IFolder folder = getProjectFolder(outputLocation); + String tokenOutput = folder.getProjectRelativePath().toString(); + outputJars.putIfAbsent(tokenOutput, key); } } } @@ -316,6 +313,13 @@ private IPath getRealPath(IPath eclipseOutputLocation, Map outpu if (jarFolder.equals(projectFolder)) { String jarOutputPath = entry.getValue(); if (".".equals(jarOutputPath)) { + // TODO need to handle this special case: +// if (".".equals(jarName) || jarToSourceFolderEntries.size() == 1) { +// // in case of one classpath entry which is not ".", also use standard +// // maven output dir for better interoperability with plain maven plugins +// dotJarName = jarName; +// outputDirectory = project.getBuildDirectory().getOutputDirectory(); +// } return mavenOutputFolder.getFullPath(); } return mavenOutputFolder.getParent() @@ -427,7 +431,7 @@ private IApiBaseline createBaseline(Collection bundles, String name) thr IApiComponent component = ApiModelFactory.newApiComponent(baseline, baselineBundle); if (component != null) { debug(component.getSymbolicName() + " " + component.getVersion() + " -- " - + new File(Objects.requireNonNullElse(component.getLocation(), "Unknown")).getName()); + + new File(Objects.requireNonNullElse(component.getLocation(), "Unknown")).getAbsolutePath()); baselineComponents.add(component); } } diff --git a/tycho-its/projects/api-tools/single-jar/.mvn/extensions.xml b/tycho-its/projects/api-tools/single-jar/.mvn/extensions.xml new file mode 100644 index 0000000000..79a6c51e8d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/.mvn/extensions.xml @@ -0,0 +1,7 @@ + + + org.eclipse.tycho + tycho-build + ${tycho-version} + + diff --git a/tycho-its/projects/api-tools/single-jar/.mvn/maven.config b/tycho-its/projects/api-tools/single-jar/.mvn/maven.config new file mode 100644 index 0000000000..babb6c469f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/.mvn/maven.config @@ -0,0 +1 @@ +-Dtycho-version=5.0.0-SNAPSHOT diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.classpath b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.classpath new file mode 100644 index 0000000000..3bc414e51b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.classpath @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.gitignore b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.gitignore new file mode 100644 index 0000000000..2b5da58023 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.gitignore @@ -0,0 +1 @@ +/jdi-bin/ diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.options b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.options new file mode 100644 index 0000000000..7f3e82f4e9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.options @@ -0,0 +1,7 @@ +org.eclipse.jdt.debug/debug=false +org.eclipse.jdt.debug/debug/jdiEvents=false +org.eclipse.jdt.debug/debug/jdiRequestTimes=false +org.eclipse.jdt.debug/debug/astEvaluations=false +org.eclipse.jdt.debug/debug/astEvaluations/callingThreads=false +org.eclipse.jdt.debug/debug/jdi/verbose=false +org.eclipse.jdt.debug/debug/jdi/verbose/file= diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.project b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.project new file mode 100644 index 0000000000..e700941ac6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.project @@ -0,0 +1,34 @@ + + + org.eclipse.jdt.debug + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/.api_filters b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/.api_filters new file mode 100644 index 0000000000..3a969362f8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.core.runtime.prefs b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 0000000000..5a0ad22d2a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.jdt.core.prefs b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..311a6ec65e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,437 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=error +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=ignore +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=error +org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=error +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=enabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=ignore +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=error +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=error +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=error +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=error +org.eclipse.jdt.core.compiler.problem.unusedLocal=error +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=error +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,HIGH,NORMAL,HIGH,HIGH +org.eclipse.jdt.core.compiler.taskTags=TODO,FIXME,XXX,EXPERIMENTAL,CONTEXTLAUNCHING +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=0 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=150 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=150 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.jdt.ui.prefs b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000000..121cc3d48a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,64 @@ +cleanup_settings_version=2 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Platform Debug Formatting +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.update_ibm_copyright_to_current_year=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=true +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.pde.api.tools.prefs b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.pde.api.tools.prefs new file mode 100644 index 0000000000..14ef7d2e3a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.pde.api.tools.prefs @@ -0,0 +1,104 @@ +ANNOTATION_ELEMENT_TYPE_ADDED_FIELD=Error +ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error +ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error +ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error +ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error +ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error +API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error +API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error +API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error +API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error +API_USE_SCAN_FIELD_SEVERITY=Error +API_USE_SCAN_METHOD_SEVERITY=Error +API_USE_SCAN_TYPE_SEVERITY=Error +CLASS_ELEMENT_TYPE_ADDED_FIELD=Error +CLASS_ELEMENT_TYPE_ADDED_METHOD=Error +CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error +CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error +CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error +CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error +CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error +CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error +CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error +CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error +CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error +CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error +CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error +CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error +CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error +CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error +CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error +CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error +CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error +ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error +ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error +ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error +ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error +ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error +ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error +FIELD_ELEMENT_TYPE_ADDED_VALUE=Error +FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error +FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error +FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error +FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error +FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error +FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error +FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error +FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error +FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error +ILLEGAL_EXTEND=Warning +ILLEGAL_IMPLEMENT=Warning +ILLEGAL_INSTANTIATE=Warning +ILLEGAL_OVERRIDE=Warning +ILLEGAL_REFERENCE=Warning +INTERFACE_ELEMENT_TYPE_ADDED_DEFAULT_METHOD=Error +INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error +INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error +INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error +INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error +INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error +INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error +INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error +INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error +INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error +INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error +INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error +INVALID_ANNOTATION=Ignore +INVALID_JAVADOC_TAG=Warning +INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Warning +LEAK_EXTEND=Warning +LEAK_FIELD_DECL=Warning +LEAK_IMPLEMENT=Warning +LEAK_METHOD_PARAM=Warning +LEAK_METHOD_RETURN_TYPE=Warning +METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error +METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error +METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error +METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error +METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error +METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error +METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error +METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error +METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error +METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error +MISSING_EE_DESCRIPTIONS=Warning +TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error +TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error +TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error +TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error +TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error +TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error +UNUSED_PROBLEM_FILTERS=Warning +automatically_removed_unused_problem_filters=false +changed_execution_env=Error +eclipse.preferences.version=1 +incompatible_api_component_version=Error +incompatible_api_component_version_include_major_without_breaking_change=Disabled +incompatible_api_component_version_include_minor_without_api_change=Disabled +incompatible_api_component_version_report_major_without_breaking_change=Error +incompatible_api_component_version_report_minor_without_api_change=Error +invalid_since_tag_version=Error +malformed_since_tag=Error +missing_since_tag=Error +report_api_breakage_when_major_version_incremented=Disabled +report_resolution_errors_api_component=Warning diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.pde.prefs b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.pde.prefs new file mode 100644 index 0000000000..45e1620486 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/.settings/org.eclipse.pde.prefs @@ -0,0 +1,36 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=1 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=2 +compilers.p.discouraged-class=1 +compilers.p.illegal-att-value=0 +compilers.p.internal=1 +compilers.p.matching-pom-version=0 +compilers.p.missing-packages=0 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=2 +compilers.p.missing-version-require-bundle=2 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=0 +compilers.p.unknown-attribute=0 +compilers.p.unknown-class=1 +compilers.p.unknown-element=2 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=0 +compilers.p.unresolved-ex-points=1 +compilers.p.unresolved-import=0 +compilers.p.unused-element-or-attribute=1 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +compilers.use-project=true +eclipse.preferences.version=1 diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..0649d71d75 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/META-INF/MANIFEST.MF @@ -0,0 +1,36 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true +Bundle-Version: 3.22.0.qualifier +Bundle-ClassPath: jdimodel.jar +Bundle-Activator: org.eclipse.jdt.internal.debug.core.JDIDebugPlugin +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Export-Package: org.eclipse.jdi, + org.eclipse.jdi.hcr, + org.eclipse.jdi.internal;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdi.internal.connect;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdi.internal.event;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdi.internal.jdwp;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdi.internal.request;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdi.internal.spy;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.debug.core, + org.eclipse.jdt.debug.eval, + org.eclipse.jdt.internal.debug.core;x-friends:="org.eclipse.jdt.debug.ui,org.eclipse.jdt.launching", + org.eclipse.jdt.internal.debug.core.breakpoints;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.core.hcr;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.core.logicalstructures;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.core.model;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.eval;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.eval.ast.engine;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.eval.ast.instructions;x-friends:="org.eclipse.jdt.debug.ui" +Require-Bundle: org.eclipse.core.resources;bundle-version="[3.19.0,4.0.0)", + org.eclipse.debug.core;bundle-version="[3.21.0,4.0.0)", + org.eclipse.jdt.core;bundle-version="[3.34.0,4.0.0)", + org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", + org.eclipse.core.expressions;bundle-version="[3.9.0,4.0.0)" +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Eclipse-BundleShape: dir +Automatic-Module-Name: org.eclipse.jdt.debug diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/about.html b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/about.html new file mode 100644 index 0000000000..164f781a8f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

November 30, 2017

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/build.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/build.properties new file mode 100644 index 0000000000..8031351d05 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/build.properties @@ -0,0 +1,31 @@ +############################################################################### +# Copyright (c) 2000, 2012 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +bin.includes = plugin.xml,\ + plugin.properties,\ + *.jar,\ + about.html,\ + META-INF/,\ + .options + +source.jdimodel.jar = model/,\ + jdi/,\ + eval/ +output.jdimodel.jar = bin/ +src.includes = about.html,\ + schema/ +jars.compile.order = jdimodel.jar +javacWarnings..=-unavoidableGenericProblems +javacWarnings.jdimodel.jar=-unavoidableGenericProblems + +#output..=bin/ diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/EvaluationManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/EvaluationManager.java new file mode 100644 index 0000000000..5cdd25de8e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/EvaluationManager.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +import java.io.File; + +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.internal.debug.eval.LocalEvaluationEngine; +import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine; + +/** + * The evaluation manager provides factory methods for creating evaluation + * engines. + * + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine + * @see org.eclipse.jdt.debug.eval.IClassFileEvaluationEngine + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine + * @see org.eclipse.jdt.debug.eval.IEvaluationResult + * @see org.eclipse.jdt.debug.eval.IEvaluationListener + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + */ +public class EvaluationManager { + + /** + * Not to be instantiated + */ + private EvaluationManager() { + } + + /** + * Creates and returns a new evaluation engine that performs evaluations for + * local Java applications by deploying class files. + * + * @param project + * the Java project in which expressions are to be compiled + * @param target + * the Java debug target in which expressions are to be evaluated + * @param directory + * the directory where support class files are deployed to assist + * in the evaluation. The directory must exist. + * @return an evaluation engine + */ + public static IClassFileEvaluationEngine newClassFileEvaluationEngine( + IJavaProject project, IJavaDebugTarget target, File directory) { + return new LocalEvaluationEngine(project, target, directory); + } + + /** + * Creates and returns a new evaluation engine that performs evaluations by + * compiling expressions into abstract syntax trees (ASTs), and interpreting + * the AST over a JDI connection. This type of evaluation engine is capable + * of performing remote evaluations. + * + * @param project + * the Java project in which expressions are to be compiled + * @param target + * the Java debug target in which expressions are to be evaluated + * @return an evaluation engine + */ + public static IAstEvaluationEngine newAstEvaluationEngine( + IJavaProject project, IJavaDebugTarget target) { + return new ASTEvaluationEngine(project, target); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IAstEvaluationEngine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IAstEvaluationEngine.java new file mode 100644 index 0000000000..394f322f36 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IAstEvaluationEngine.java @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +import java.util.Map; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; + +/** + * An evaluation engine that performs evaluations by interpreting abstract + * syntax trees. An AST evaluation engine is capable of creating compiled + * expressions that can be evaluated multiple times in a given runtime context. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IAstEvaluationEngine extends IEvaluationEngine { + + /** + * Instructs the evaluation engine to disable garbage collection on the result object. The caller is then responsible to call + * {@link IJavaObject#enableCollection()} on the evaluated result. Can be passed as a bit flag to the evaluationDetail parameter. + * + * @since 3.17 + */ + int DISABLE_GC_ON_RESULT = 0x0100; + + /** + * Asynchronously evaluates the given expression in the context of the + * specified stack frame, reporting the result back to the given listener. + * The thread is resumed from the location at which it is currently + * suspended to perform the evaluation. When the evaluation completes, the + * thread will be suspended at this original location. The thread runs the + * evaluation with the given evaluation detail (@see + * IJavaThread#runEvaluation(IEvaluationRunnable, IProgressMonitor, int)). + * Compilation and runtime errors are reported in the evaluation result. + * + * @param expression + * expression to evaluate + * @param frame + * the stack frame context in which to run the evaluation. + * @param listener + * the listener that will receive notification when/if the + * evaluation completes + * @param evaluationDetail + * bitmask of one of DebugEvent.EVALUATION or + * DebugEvent.EVALUATION_IMPLICIT and + * optionally DISABLE_GC_ON_RESULT + * @param hitBreakpoints + * whether or not breakpoints should be honored in the evaluation + * thread during the evaluation. If false, + * breakpoints hit in the evaluation thread will be ignored. + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target + * associated with this evaluation engine
  • + *
  • The associated thread is suspended in the middle of an + * evaluation that has not completed. It is not possible to + * perform nested evaluations
  • + *
+ */ + public void evaluateExpression(ICompiledExpression expression, + IJavaStackFrame frame, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) throws DebugException; + + /** + * Asynchronously evaluates the given expression in the context of the + * specified type, reporting the result back to the given listener. The + * expression is evaluated in the context of the Java project this + * evaluation engine was created on. If the expression is determined to have + * no errors, the expression is evaluated in the thread associated with the + * given stack frame. When the evaluation completes, the thread will be + * suspended at this original location. The thread runs the evaluation with + * the given evaluation detail (@see + * IJavaThread#runEvaluation(IEvaluationRunnable, IProgressMonitor, int)). + * Compilation and runtime errors are reported in the evaluation result. + * + * @param expression + * the expression to evaluate + * @param object + * the 'this' context for the evaluation + * @param thread + * the thread in which to run the evaluation, which must be + * suspended + * @param listener + * the listener that will receive notification when/if the + * evaluation completes + * @param evaluationDetail + * bitmask of one of DebugEvent.EVALUATION or + * DebugEvent.EVALUATION_IMPLICIT and + * optionally DISABLE_GC_ON_RESULT + * @param hitBreakpoints + * whether or not breakpoints should be honored in the evaluation + * thread during the evaluation. If false, + * breakpoints hit in the evaluation thread will be ignored. + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target + * associated with this evaluation engine
  • + *
  • The associated thread is suspended in the middle of an + * evaluation that has not completed. It is not possible to + * perform nested evaluations
  • + *
+ */ + public void evaluateExpression(ICompiledExpression expression, + IJavaObject object, IJavaThread thread, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException; + + /** + * Synchronously generates a compiled expression from the given expression + * in the context of the specified stack frame. The generated expression can + * be stored and evaluated later in a valid runtime context. Compilation + * errors are reported in the returned compiled expression. + * + * @param expression + * expression to compile + * @param frame + * the context in which to compile the expression + * @return the compiled expression + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target + * associated with this evaluation engine
  • + *
+ */ + public ICompiledExpression getCompiledExpression(String expression, + IJavaStackFrame frame) throws DebugException; + + /** + * Synchronously generates a compiled expression from the given expression + * in the context of the specified object. The generated expression can be + * stored and evaluated later in a valid runtime context. Compilation errors + * are reported in the returned compiled expression. + * + * @param expression + * expression to compile + * @param object + * the context in which to compile the expression + * @return the compiled epxression + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target + * associated with this evaluation engine
  • + *
+ */ + public ICompiledExpression getCompiledExpression(String expression, + IJavaObject object) throws DebugException; + + /** + * Synchronously generates a compiled expression from the given expression + * in the context of the specified type. The generated expression can be + * stored and evaluated later in a valid runtime context. Compilation errors + * are reported in the returned compiled expression. + * + * @param expression + * expression to compile + * @param type + * the context in which to compile the expression + * @return the compiled expression + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target + * associated with this evaluation engine
  • + *
+ * @since 3.1 + */ + public ICompiledExpression getCompiledExpression(String expression, + IJavaReferenceType type) throws DebugException; + + /** + * Synchronously generates a compiled expression from the given expression in the context of the specified type. The generated expression can be + * stored and evaluated later in a valid runtime context. Compilation errors are reported in the returned compiled expression. + * + * @param expression + * expression to compile + * @param type + * the context in which to compile the expression + * @param compileOptions + * options to use during the compile + * @return the compiled expression + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target associated with this evaluation engine
  • + *
+ * @since 3.13 + */ + public ICompiledExpression getCompiledExpression(String expression, + IJavaReferenceType type, Map compileOptions) throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IClassFileEvaluationEngine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IClassFileEvaluationEngine.java new file mode 100644 index 0000000000..bef148c5d3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IClassFileEvaluationEngine.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaThread; + +/** + * An evaluation engine that performs evaluations by deploying and executing + * class files locally. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IClassFileEvaluationEngine extends IEvaluationEngine { + /** + * Returns the import declarations for this evaluation context. An empty + * list indicates there are no imports. The syntax for the import + * corresponds to a fully qualified type name, or to an on-demand package + * name as defined by ImportDeclaration (JLS2 7.5). For example, + * "java.util.Hashtable" or "java.util.*". + * + * @return the list of import names + */ + public String[] getImports(); + + /** + * Sets the import declarations for this evaluation context. An empty list + * indicates there are no imports. The syntax for the import corresponds to + * a fully qualified type name, or to an on-demand package name as defined + * by ImportDeclaration (JLS2 7.5). For example, + * "java.util.Hashtable" or "java.util.*". + * + * @param imports + * the list of import names + */ + public void setImports(String[] imports); + + /** + * Asynchronously evaluates the given snippet in the specified target + * thread, reporting the result back to the given listener. The snippet is + * evaluated in the context of the Java project this evaluation engine was + * created on. If the snippet is determined to be a valid expression, the + * expression is evaluated in the specified thread, which resumes its + * execution from the location at which it is currently suspended. When the + * evaluation completes, the thread will be suspened at this original + * location. Compilation and runtime errors are reported in the evaluation + * result. + * + * @param snippet + * code snippet to evaluate + * @param thread + * the thread in which to run the evaluation, which must be + * suspended + * @param listener + * the listener that will receive notification when/if the + * evalaution completes + * @param hitBreakpoints + * whether or not breakpoints should be honored in the evaluation + * thread during the evaluation. If false, + * breakpoints hit in the evaluation thread will be ignored. + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The specified thread is not currently suspended
  • + *
  • The specified thread is not contained in the debug + * target associated with this evaluation engine
  • + *
  • The specified thread is suspended in the middle of an + * evaluation that has not completed. It is not possible to + * perform nested evaluations
  • + *
+ */ + public void evaluate(String snippet, IJavaThread thread, + IEvaluationListener listener, boolean hitBreakpoints) + throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/ICompiledExpression.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/ICompiledExpression.java new file mode 100644 index 0000000000..ce05640074 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/ICompiledExpression.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +import org.eclipse.jdt.core.dom.Message; + +/** + * A compiled expression can be compiled once and evaluated multiple times in a + * runtime context. + * + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface ICompiledExpression { + + /** + * Returns the source snippet from which this compiled expression was + * created. + * + * @return the source snippet from which this compiled expression was + * created + */ + public String getSnippet(); + + /** + * Returns whether this compiled expression has any compilation errors. + * + * @return whether this compiled expression has any compilation errors + */ + public boolean hasErrors(); + + /** + * Returns any errors which occurred while creating this compiled + * expression. + * + * @return any errors which occurred while creating this compiled expression + * @deprecated use getErrorMessages() + */ + @Deprecated + public Message[] getErrors(); + + /** + * Returns an array of problem messages. Each message describes a problem + * that occurred while while creating this compiled expression. + * + * @return error messages, or an empty array if no errors occurred + * @since 2.1 + */ + public String[] getErrorMessages(); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationEngine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationEngine.java new file mode 100644 index 0000000000..d535e1ec1d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationEngine.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; + +/** + * An evaluation engine performs an evaluation of a code snippet or expression + * in a specified thread of a debug target. An evaluation engine is associated + * with a specific debug target and Java project on creation. + * + * @see IEvaluationResult + * @see IEvaluationListener + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface IEvaluationEngine { + /** + * Asynchronously evaluates the given snippet in the context of the + * specified stack frame, reporting the result back to the given listener. + * The snippet is evaluated in the context of the Java project this + * evaluation engine was created on. If the snippet is determined to be a + * valid expression, the expression is evaluated in the thread associated + * with the given stack frame. The thread is resumed from the location at + * which it is currently suspended to perform the evaluation. When the + * evaluation completes, the thread will be suspended at this original + * location. The thread runs the evaluation with the given evaluation detail + * (@see IJavaThread#runEvaluation(IEvaluationRunnable, IProgressMonitor, + * int)). Compilation and runtime errors are reported in the evaluation + * result. + * + * @param snippet + * code snippet to evaluate + * @param frame + * the stack frame context in which to run the evaluation. + * @param listener + * the listener that will receive notification when/if the + * evaluation completes + * @param evaluationDetail + * one of DebugEvent.EVALUATION or + * DebugEvent.EVALUATION_IMPLICIT + * @param hitBreakpoints + * whether or not breakpoints should be honored in the evaluation + * thread during the evaluation. If false, + * breakpoints hit in the evaluation thread will be ignored. + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The stack frame is not contained in the debug target + * associated with this evaluation engine
  • + *
  • The associated thread is suspended in the middle of an + * evaluation that has not completed. It is not possible to + * perform nested evaluations
  • + *
+ */ + public void evaluate(String snippet, IJavaStackFrame frame, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException; + + /** + * Asynchronously evaluates the given snippet in the context of the + * specified type, reporting the result back to the given listener. The + * snippet is evaluated in the context of the Java project this evaluation + * engine was created on. If the snippet is determined to be a valid + * expression, the expression is evaluated in the thread associated with the + * given stack frame. The thread is resumed from the location at which it is + * currently suspended to perform the evaluation. When the evaluation + * completes, the thread will be suspended at this original location. The + * thread runs the evaluation with the given evaluation detail (@see + * IJavaThread#runEvaluation(IEvaluationRunnable, IProgressMonitor, int)). + * Compilation and runtime errors are reported in the evaluation result. + * + * @param snippet + * code snippet to evaluate + * @param thisContext + * the 'this' context for the evaluation + * @param thread + * the thread in which to run the evaluation, which must be + * suspended + * @param listener + * the listener that will receive notification when/if the + * evaluation completes + * @param evaluationDetail + * one of DebugEvent.EVALUATION or + * DebugEvent.EVALUATION_IMPLICIT + * @param hitBreakpoints + * whether or not breakpoints should be honored in the evaluation + * thread during the evaluation. If false, + * breakpoints hit in the evaluation thread will be ignored. + * @exception DebugException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
  • + *
  • The associated thread is not currently suspended
  • + *
  • The specified thread is not contained in the debug + * target associated with this evaluation engine
  • + *
  • The associated thread is suspended in the middle of an + * evaluation that has not completed. It is not possible to + * perform nested evaluations
  • + *
+ */ + public void evaluate(String snippet, IJavaObject thisContext, + IJavaThread thread, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) throws DebugException; + + /** + * Returns the Java project in which expressions are compiled. + * + * @return Java project context + */ + public IJavaProject getJavaProject(); + + /** + * Returns the debug target for which evaluations are executed. + * + * @return Java debug target + */ + public IJavaDebugTarget getDebugTarget(); + + /** + * Disposes this evaluation engine. This causes the evaluation engine to + * cleanup any resources (such as threads) that it maintains. Clients should + * call this method when they are finished performing evaluations with this + * engine. + * + * This engine must not be used to perform evaluations after it has been + * disposed. + */ + public void dispose(); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationListener.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationListener.java new file mode 100644 index 0000000000..9d9dbc4c1b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationListener.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +/** + * Evaluation results are reported to evaluation listeners on the completion of + * an evaluation. The evaluation may fail but a result will be supplied + * indicating the problems. + *

+ * Clients may implement this interface. + *

+ * + * @see IEvaluationResult + * @since 2.0 + */ + +public interface IEvaluationListener { + + /** + * Notifies this listener that an evaluation has completed, with the given + * result. + * + * @param result + * The result from the evaluation + * @see IEvaluationResult + */ + public void evaluationComplete(IEvaluationResult result); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationResult.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationResult.java new file mode 100644 index 0000000000..8ec4ba4ce1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/IEvaluationResult.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.eval; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; + +/** + * The result of an evaluation. An evaluation result may contain problems and/or + * a result value. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface IEvaluationResult { + + /** + * Returns the value representing the result of the evaluation, or + * null if the associated evaluation failed. If the associated + * evaluation failed, there will be problems, or an exception in this + * result. + *

+ * Since 3.5, this method can also return null if the evaluation was + * terminated before it completed. + *

+ * + * @return the resulting value, possibly null + */ + public IJavaValue getValue(); + + /** + * Returns whether the evaluation had any problems or if an exception + * occurred while performing the evaluation. + * + * @return whether there were any problems. + * @see #getErrors() + * @see #getException() + */ + public boolean hasErrors(); + + /** + * Returns an array of problem messages. Each message describes a problem + * that occurred while compiling the snippet. + * + * @return compilation error messages, or an empty array if no errors + * occurred + * @deprecated use getErrorMessages() + */ + @Deprecated + public Message[] getErrors(); + + /** + * Returns an array of problem messages. Each message describes a problem + * that occurred while compiling the snippet. + * + * @return compilation error messages, or an empty array if no errors + * occurred + * @since 2.1 + */ + public String[] getErrorMessages(); + + /** + * Returns the snippet that was evaluated. + * + * @return The string code snippet. + */ + public String getSnippet(); + + /** + * Returns any exception that occurred while performing the evaluation or + * null if an exception did not occur. The exception will be a + * debug exception or a debug exception that wrappers a JDI exception that + * indicates a problem communicating with the target or with actually + * performing some action in the target. + * + * @return The exception that occurred during the evaluation + * @see com.sun.jdi.InvocationException + * @see org.eclipse.debug.core.DebugException + */ + public DebugException getException(); + + /** + * Returns the thread in which the evaluation was performed. + * + * @return the thread in which the evaluation was performed + */ + public IJavaThread getThread(); + + /** + * Returns the evaluation engine used to evaluate the original snippet. + * + * @return the evaluation engine used to evaluate the original snippet + */ + public IEvaluationEngine getEvaluationEngine(); + + /** + * Returns whether this evaluation was terminated before it completed. + * + * @return whether terminated. + * @since 3.5 + */ + public boolean isTerminated(); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/package.html b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/package.html new file mode 100644 index 0000000000..0b63b63be7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/package.html @@ -0,0 +1,21 @@ + + + + + +Java Debug Model + + + + +Provides a set classes and interfaces that support evaluations in the Java debugger. + +

Package Specification

+ + This package defines a set of classes and interfaces that support evaluations + in the Java debugger. Two evaluation engines are provided - one that performs + evaluations by compiling and deploying class files locally for execution, and + one that performs an interpretation over an abstract syntax tree. The later + supports remote evaluation via JDI. + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationMessages.java new file mode 100644 index 0000000000..bee3ae2ce7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationMessages.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval; + +import org.eclipse.osgi.util.NLS; + +public class EvaluationMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.eval.EvaluationMessages";//$NON-NLS-1$ + + public static String LocalEvaluationEngine_Evaluation_in_context_of_inner_type_not_supported__19; + public static String LocalEvaluationEngine_Evaluation_failed___unable_to_determine_receiving_type_context__18; + public static String LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17; + public static String LocalEvaluationEngine_Evaluation_failed___unable_to_instantiate_code_snippet_class__11; + public static String LocalEvaluationEngine__0__occurred_deploying_class_file_for_evaluation_9; + public static String LocalEvaluationEngine_Evaluation_failed___evaluation_thread_must_be_suspended__8; + public static String LocalEvaluationEngine_Evaluation_failed___evaluation_context_has_been_disposed__7; + public static String LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__6; + public static String LocalEvaluationEngine_Evaluation_failed___unable_to_initialize___this___context__5; + public static String LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4; + public static String RemoteEvaluationEngine_Evaluation_failed___unable_to_instantiate_snippet_class; + public static String RemoteEvaluationEngine_Evaluation_failed___unable_to_find_injected_class; + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, EvaluationMessages.class); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationMessages.properties new file mode 100644 index 0000000000..b970e073a4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationMessages.properties @@ -0,0 +1,26 @@ +############################################################################### +# Copyright (c) 2000, 2020 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +LocalEvaluationEngine_Evaluation_in_context_of_inner_type_not_supported__19=Evaluation in context of inner type not supported. +LocalEvaluationEngine_Evaluation_failed___unable_to_determine_receiving_type_context__18=Evaluation failed - unable to determine receiving type context. +LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17=Evaluation failed - internal error retrieving result. +LocalEvaluationEngine_Evaluation_failed___unable_to_instantiate_code_snippet_class__11=Evaluation failed - unable to instantiate code snippet class. +LocalEvaluationEngine__0__occurred_deploying_class_file_for_evaluation_9={0} occurred deploying class file for evaluation +LocalEvaluationEngine_Evaluation_failed___evaluation_thread_must_be_suspended__8=Evaluation failed - evaluation thread must be suspended. +LocalEvaluationEngine_Evaluation_failed___evaluation_context_has_been_disposed__7=Evaluation failed - evaluation context has been disposed. +LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__6=Evaluation failed - unable to initialize local variables. +LocalEvaluationEngine_Evaluation_failed___unable_to_initialize___this___context__5=Evaluation failed - unable to initialize \'this\' context. +LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4=Evaluation failed - unable to initialize local variables. +RemoteEvaluationEngine_Evaluation_failed___unable_to_instantiate_snippet_class=Evaluation failed - generated class could not be instantiated. +RemoteEvaluationEngine_Evaluation_failed___unable_to_find_injected_class=Evaluation failed - unable to find injected class diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationResult.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationResult.java new file mode 100644 index 0000000000..bc39ed9ae6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/EvaluationResult.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.eval.IEvaluationEngine; +import org.eclipse.jdt.debug.eval.IEvaluationResult; + +/** + * The result of an evaluation. + * + * @see org.eclipse.jdt.debug.eval.IEvaluationResult + */ +public class EvaluationResult implements IEvaluationResult { + + /** + * The result of an evaluation, possibly null + */ + private IJavaValue fValue; + + /** + * Thread in which the associated evaluation was executed. + */ + private IJavaThread fThread; + + /** + * Evaluation engine that created this result + */ + private IEvaluationEngine fEngine; + + /** + * Source that was evaluated. + */ + private String fSnippet; + + /** + * Exception that occurred during evaluation, or null if none. + */ + private DebugException fException; + + /** + * List of Strings describing compilation problems. + */ + private final List fErrors; + + /** + * Whether the evaluation was terminated. + */ + private boolean fTerminated = false; + + /** + * Constructs a new evaluation result for the given engine, thread, and code + * snippet. + */ + public EvaluationResult(IEvaluationEngine engine, String snippet, + IJavaThread thread) { + setEvaluationEngine(engine); + setThread(thread); + setSnippet(snippet); + fErrors = new ArrayList<>(); + } + + /** + * @see IEvaluationResult#getValue() + */ + @Override + public IJavaValue getValue() { + return fValue; + } + + /** + * Sets the result of an evaluation, possibly null. + * + * @param value + * result of an evaluation, possibly null + */ + public void setValue(IJavaValue value) { + fValue = value; + } + + /** + * @see IEvaluationResult#hasProblems() + */ + @Override + public boolean hasErrors() { + return getErrors().length > 0 || getException() != null; + } + + /** + * @see IEvaluationResult#getProblems() + * @deprecated + */ + @Override + @Deprecated + public Message[] getErrors() { + Message[] messages = new Message[fErrors.size()]; + int i = 0; + for (String errMsg : fErrors) { + messages[i++] = new Message(errMsg, -1); + } + return messages; + } + + /** + * @see org.eclipse.jdt.debug.eval.IEvaluationResult#getErrorMessages() + */ + @Override + public String[] getErrorMessages() { + return fErrors.toArray(new String[fErrors.size()]); + } + + /** + * @see IEvaluationResult#getSnippet() + */ + @Override + public String getSnippet() { + return fSnippet; + } + + /** + * Sets the code snippet that was evaluated. + * + * @param snippet + * the source code that was evaluated + */ + private void setSnippet(String snippet) { + fSnippet = snippet; + } + + /** + * @see IEvaluationResult#getException() + */ + @Override + public DebugException getException() { + return fException; + } + + /** + * Sets an exception that occurred while attempting the associated + * evaluation. + * + * @param e + * exception + */ + public void setException(DebugException e) { + fException = e; + } + + /** + * @see IEvaluationResult#getThread() + */ + @Override + public IJavaThread getThread() { + return fThread; + } + + /** + * Sets the thread this result was generated from. + * + * @param thread + * thread in which the associated evaluation was executed + */ + private void setThread(IJavaThread thread) { + fThread = thread; + } + + /** + * @see IEvaluationResult#getEvaluationEngine() + */ + @Override + public IEvaluationEngine getEvaluationEngine() { + return fEngine; + } + + /** + * Sets the evaluation that created this result. + * + * @param engine + * the evaluation that created this result + */ + private void setEvaluationEngine(IEvaluationEngine engine) { + fEngine = engine; + } + + /** + * Adds the given message to the list of error messages. + */ + public void addError(String message) { + fErrors.add(message); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.eval.IEvaluationResult#isTerminated() + */ + @Override + public boolean isTerminated() { + return fTerminated; + } + + /** + * Sets whether terminated. + * + * @param terminated + * whether terminated + */ + public void setTerminated(boolean terminated) { + fTerminated = terminated; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ExpressionBinder.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ExpressionBinder.java new file mode 100644 index 0000000000..2fa84cf423 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ExpressionBinder.java @@ -0,0 +1,10 @@ +package org.eclipse.jdt.internal.debug.eval; + +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; + +public interface ExpressionBinder { + // Record and register the binding specified + void bind(IVariableBinding variableToBind, String asVariableName); + void bindThis(ITypeBinding thisForType, String asVariableName); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/LocalEvaluationEngine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/LocalEvaluationEngine.java new file mode 100644 index 0000000000..d50f2db5e5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/LocalEvaluationEngine.java @@ -0,0 +1,1380 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.eval.ICodeSnippetRequestor; +import org.eclipse.jdt.core.eval.IEvaluationContext; +import org.eclipse.jdt.debug.core.IEvaluationRunnable; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.eval.IClassFileEvaluationEngine; +import org.eclipse.jdt.debug.eval.IEvaluationEngine; +import org.eclipse.jdt.debug.eval.IEvaluationListener; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; + +import com.sun.jdi.InvocationException; +import com.sun.jdi.ObjectReference; + +/** + * An evaluation engine that deploys class files locally + */ + +public class LocalEvaluationEngine implements IClassFileEvaluationEngine, + ICodeSnippetRequestor, IEvaluationRunnable { + + private static final String CODE_SNIPPET_NAME = "CodeSnippet.class"; //$NON-NLS-1$ + + /** + * A count of the number of engines created. Count is incremented on + * instantiation and decremented on dispose. When the count == 0, the + * special CodeSnippet.class is deleted as this class file is shared by all. + */ + private static int ENGINE_COUNT = 0; + + /** + * The Java project context in which to compile snippets. + */ + private IJavaProject fJavaProject; + + /** + * The debug target on which to execute snippets + */ + private IJavaDebugTarget fDebugTarget; + + /** + * The location in which to deploy snippet class files + */ + private File fOutputDirectory; + + /** + * The listener to notify when the current evaluation is complete. + */ + private IEvaluationListener fListener; + + /** + * The stack frame context for the current evaluation or null + * if there is no stack frame context. + */ + private IJavaStackFrame fStackFrame; + + /** + * The result of this evaluation + */ + private EvaluationResult fResult; + + /** + * Collection of deployed snippet class files + */ + private List fSnippetFiles; + + /** + * Collection of directories created by this evaluation engine. + */ + private List fDirectories; + + /** + * Evaluation context for the Java project associated with this evaluation + * engine. + */ + private IEvaluationContext fEvaluationContext; + + /** + * Array of modifier constants for visible local variables in the current + * evaluation. + * + * XXX: constants should be 'default' or 'final'. Where are these constants + * defined. + */ + private int[] fLocalVariableModifiers; + + /** + * Array of names of visible local variables in the current evaluation. + */ + private String[] fLocalVariableNames; + + /** + * Array of type names of visible local variables in the current evaluation. + */ + private String[] fLocalVariableTypeNames; + + /** + * The 'this' object for the current evaluation or null if + * there is no 'this' context (static method, or not context) + */ + private IJavaObject fThis; + + /** + * Whether this engine has been disposed. + */ + private boolean fDisposed = false; + + /** + * The number of evaluations currently being performed. + */ + private int fEvaluationCount = 0; + + /** + * The name of the code snippet class to instantiate + */ + private String fCodeSnippetClassName = null; + + /** + * Whether to hit breakpoints in the evaluation thread + */ + private boolean fHitBreakpoints = false; + + /** + * Constant for empty array of java.lang.String + */ + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + /** + * Constant for empty array of int + */ + private static final int[] EMPTY_INT_ARRAY = new int[0]; + + /** + * Constructs a new evaluation engine for the given VM in the context of the + * specified project. Class files required for the evaluation will be + * deployed to the specified directory (which must be on the class path of + * the VM in order for evaluation to work). + * + * @param project + * context in which to compile snippets + * @param vm + * debug target in which to evaluate snippets + * @param directory + * location where snippet class files will be deployed for + * execution. The directory must exist + */ + public LocalEvaluationEngine(IJavaProject project, IJavaDebugTarget vm, + File directory) { + setJavaProject(project); + setDebugTarget(vm); + setOutputDirectory(directory); + ENGINE_COUNT++; + } + + /** + * @see ICodeSnippetRequestor#acceptClassFiles(byte[][], String[][], String) + */ + @Override + public boolean acceptClassFiles(byte[][] classFileBytes, + String[][] classFileCompoundNames, String codeSnippetClassName) { + try { + deploy(classFileBytes, classFileCompoundNames); + } catch (DebugException e) { + getResult().setException(e); + return false; + } + if (codeSnippetClassName != null) { + setCodeSnippetClassName(codeSnippetClassName); + try { + getThread().runEvaluation(this, null, DebugEvent.EVALUATION, + getHitBreakpoints()); + } catch (DebugException e) { + // exception handling is in evaluation runnable + } + } + return true; + } + + @Override + public void run(IJavaThread thread, IProgressMonitor monitor) { + IJavaObject codeSnippetInstance = null; + try { + codeSnippetInstance = newInstance(getCodeSnippetClassName()); + initializeLocals(codeSnippetInstance); + codeSnippetInstance.sendMessage(RUN_METHOD, "()V", null, getThread(), false); //$NON-NLS-1$ + restoreLocals(codeSnippetInstance); + + // now retrieve the description of the result + IVariable[] fields = codeSnippetInstance.getVariables(); + IJavaVariable resultValue = null; + IJavaVariable resultType = null; + for (IVariable field : fields) { + if (field.getName().equals(RESULT_TYPE_FIELD)) { + resultType = (IJavaVariable) field; + } + if (field.getName().equals(RESULT_VALUE_FIELD)) { + resultValue = (IJavaVariable) field; + } + } + IJavaValue result = convertResult((IJavaClassObject) resultType.getValue(), (IJavaValue) resultValue.getValue()); + getResult().setValue(result); + } catch (DebugException e) { + getResult().setException(e); + + Throwable underlyingException = e.getStatus().getException(); + if (underlyingException instanceof InvocationException) { + ObjectReference theException = ((InvocationException) underlyingException) + .exception(); + if (theException != null) { + try { + try { + IJavaObject v = (IJavaObject) JDIValue.createValue( + (JDIDebugTarget) getDebugTarget(), + theException); + v.sendMessage( + "printStackTrace", "()V", null, getThread(), false); //$NON-NLS-2$ //$NON-NLS-1$ + } catch (DebugException de) { + JDIDebugPlugin.log(de); + } + } catch (RuntimeException re) { + JDIDebugPlugin.log(re); + } + } + } + } + + } + + /** + * Initializes the value of instance variables in the 'code snippet object' + * that are used as place-holders for locals and 'this' in the current stack + * frame. + * + * @param object + * instance of code snippet class that will be run + * @exception DebugException + * if an exception is thrown accessing the given object + */ + protected void initializeLocals(IJavaObject object) throws DebugException { + IJavaVariable[] locals = null; + IJavaObject thisObject = getThis(); + if (getStackFrame() != null) { + locals = getStackFrame().getLocalVariables(); + } + if (locals != null) { + for (IJavaVariable local : locals) { + IJavaVariable field = object.getField( + LOCAL_VAR_PREFIX + local.getName(), false); + // internal error if field is not found + if (field == null) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4, + null)); + } + field.setValue(local.getValue()); + } + } + if (thisObject != null) { + IJavaVariable field = object.getField(DELEGATE_THIS, false); + // internal error if field is not found + if (field == null) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize___this___context__5, + null)); + } + field.setValue(thisObject); + } + } + + /** + * Restores the value local variables from the instance variables in the + * 'code snippet object' that are used as place-holders for locals in the + * current stack frame. + * + * @param object + * instance of code snippet class that was run + * @exception DebugException + * if an exception is thrown accessing the given object + */ + protected void restoreLocals(IJavaObject object) throws DebugException { + IJavaVariable[] locals = null; + if (getStackFrame() != null) { + locals = getStackFrame().getLocalVariables(); + } + if (locals != null) { + for (IJavaVariable local : locals) { + IJavaVariable field = object.getField( + LOCAL_VAR_PREFIX + local.getName(), false); + // internal error if field is not found + if (field == null) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__6, + null)); + } + local.setValue(field.getValue()); + } + } + } + + /** + * @see ICodeSnippetRequestor#acceptProblem(IMarker, String, int) + */ + @Override + public void acceptProblem(IMarker problemMarker, String fragmentSource, + int fragmentKind) { + if (problemMarker.getAttribute(IMarker.SEVERITY, -1) != IMarker.SEVERITY_ERROR) { + return; + } + getResult().addError(problemMarker.getAttribute(IMarker.MESSAGE, "")); //$NON-NLS-1$ + } + + /** + * @see IEvaluationEngine#getDebugTarget() + */ + @Override + public IJavaDebugTarget getDebugTarget() { + return fDebugTarget; + } + + /** + * Sets the debug target in which snippets are executed. + * + * @param debugTarget + * the debug target in which snippets are executed + */ + private void setDebugTarget(IJavaDebugTarget debugTarget) { + fDebugTarget = debugTarget; + } + + /** + * @see IEvaluationEngine#getJavaProject() + */ + @Override + public IJavaProject getJavaProject() { + return fJavaProject; + } + + /** + * Sets the Java project in which snippets are compiled. + * + * @param javaProject + * the Java project in which snippets are compiled + */ + private void setJavaProject(IJavaProject javaProject) { + fJavaProject = javaProject; + } + + /** + * Returns the directory in which snippet class files are deployed. + * + * @return the directory in which snippet class files are deployed. + */ + public File getOutputDirectory() { + return fOutputDirectory; + } + + /** + * Sets the directory in which snippet class files are deployed. + * + * @param outputDirectory + * location to deploy snippet class files + */ + private void setOutputDirectory(File outputDirectory) { + fOutputDirectory = outputDirectory; + } + + /** + * @see IClassFileEvaluationEngine#evaluate(String, IJavaThread, + * IEvaluationListener) + */ + @Override + public void evaluate(String snippet, IJavaThread thread, + IEvaluationListener listener, boolean hitBreakpoints) + throws DebugException { + checkDisposed(); + checkEvaluating(); + try { + evaluationStarted(); + setListener(listener); + setHitBreakpoints(hitBreakpoints); + setResult(new EvaluationResult(this, snippet, thread)); + checkThread(); + // no receiver/stack frame context + setThis(null); + setLocalVariableNames(EMPTY_STRING_ARRAY); + setLocalVariableTypeNames(EMPTY_STRING_ARRAY); + setLocalVariableModifiers(EMPTY_INT_ARRAY); + + // do the evaluation in a different thread + Runnable r = new Runnable() { + @Override + public void run() { + try { + LocalEvaluationEngine.this + .getEvaluationContext() + .evaluateCodeSnippet( + LocalEvaluationEngine.this.getSnippet(), + LocalEvaluationEngine.this, null); + } catch (JavaModelException e) { + LocalEvaluationEngine.this.getResult().setException( + new DebugException(e.getStatus())); + } finally { + LocalEvaluationEngine.this.evaluationComplete(); + } + } + }; + + Thread t = new Thread(r); + t.setDaemon(true); + t.start(); + } catch (DebugException d) { + evaluationAborted(); + throw d; + } + + } + + /** + * @see IEvaluationEngine#evaluate(String, IJavaStackFrame, + * IEvaluationListener, int) + */ + @Override + public void evaluate(String snippet, IJavaStackFrame frame, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException { + checkDisposed(); + checkEvaluating(); + try { + evaluationStarted(); + setListener(listener); + setStackFrame(frame); + setHitBreakpoints(hitBreakpoints); + setResult(new EvaluationResult(this, snippet, + (IJavaThread) frame.getThread())); + checkThread(); + + // set up local variables and 'this' context for evaluation + IJavaVariable[] locals = frame.getLocalVariables(); + + List typeNames = new ArrayList<>(locals.length); + List varNames = new ArrayList<>(locals.length); + + for (IJavaVariable var : locals) { + String typeName = getTranslatedTypeName(var + .getReferenceTypeName()); + if (typeName != null) { + typeNames.add(typeName); + varNames.add(var.getName()); + } + } + + setLocalVariableTypeNames(typeNames + .toArray(new String[typeNames.size()])); + setLocalVariableNames(varNames + .toArray(new String[varNames.size()])); + int[] modifiers = new int[typeNames.size()]; + // cannot determine if local is final, so specify as default + Arrays.fill(modifiers, 0); + setLocalVariableModifiers(modifiers); + setThis(frame.getThis()); + + final boolean isStatic = frame.isStatic(); + final boolean isConstructor = frame.isConstructor(); + final IType receivingType = JavaDebugUtils + .resolveDeclaringType(frame); + validateReceivingType(receivingType); + + // do the evaluation in a different thread + Runnable r = new Runnable() { + @Override + public void run() { + try { + LocalEvaluationEngine.this + .getEvaluationContext() + .evaluateCodeSnippet( + LocalEvaluationEngine.this.getSnippet(), + LocalEvaluationEngine.this + .getLocalVariableTypeNames(), + LocalEvaluationEngine.this + .getLocalVariableNames(), + LocalEvaluationEngine.this + .getLocalVariableModifiers(), + receivingType, isStatic, isConstructor, + LocalEvaluationEngine.this, null); + } catch (JavaModelException e) { + LocalEvaluationEngine.this.getResult().setException( + new DebugException(e.getStatus())); + } finally { + LocalEvaluationEngine.this.evaluationComplete(); + } + } + }; + + Thread t = new Thread(r); + t.setDaemon(true); + t.start(); + } catch (DebugException d) { + evaluationAborted(); + throw d; + } catch (CoreException e) { + evaluationAborted(); + throw new DebugException(e.getStatus()); + } + } + + /** + * Verifies the receiving type was resolved and is not an inner type. + * + * @param receivingType + * @throws DebugException + */ + private void validateReceivingType(final IType receivingType) + throws DebugException { + if (receivingType == null) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_determine_receiving_type_context__18, + null)); + } + + if (receivingType.getDeclaringType() != null) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_in_context_of_inner_type_not_supported__19, + null)); + } + } + + /** + * @see IEvaluationEngine#evaluate(String, IJavaObject, IJavaThread, + * IEvaluationListener, int) + */ + @Override + public void evaluate(String snippet, IJavaObject thisContext, + IJavaThread thread, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) throws DebugException { + checkDisposed(); + checkEvaluating(); + try { + evaluationStarted(); + setListener(listener); + setHitBreakpoints(hitBreakpoints); + setResult(new EvaluationResult(this, snippet, thread)); + checkThread(); + + // no locals + setLocalVariableTypeNames(new String[0]); + setLocalVariableNames(new String[0]); + setLocalVariableModifiers(new int[0]); + + setThis(thisContext); + + final boolean isStatic = false; + final boolean isConstructor = false; + final IType receivingType = JavaDebugUtils.resolveType(thisContext + .getJavaType()); + validateReceivingType(receivingType); + + // do the evaluation in a different thread + Runnable r = new Runnable() { + @Override + public void run() { + try { + LocalEvaluationEngine.this + .getEvaluationContext() + .evaluateCodeSnippet( + LocalEvaluationEngine.this.getSnippet(), + LocalEvaluationEngine.this + .getLocalVariableTypeNames(), + LocalEvaluationEngine.this + .getLocalVariableNames(), + LocalEvaluationEngine.this + .getLocalVariableModifiers(), + receivingType, isStatic, isConstructor, + LocalEvaluationEngine.this, null); + } catch (JavaModelException e) { + LocalEvaluationEngine.this.getResult().setException( + new DebugException(e.getStatus())); + } finally { + LocalEvaluationEngine.this.evaluationComplete(); + } + } + }; + + Thread t = new Thread(r); + t.setDaemon(true); + t.start(); + } catch (DebugException d) { + evaluationAborted(); + throw d; + } catch (CoreException e) { + evaluationAborted(); + throw new DebugException(e.getStatus()); + } + } + + /** + * Throws an exception if this engine has already been disposed. + * + * @exception DebugException + * if this engine has been disposed + */ + protected void checkDisposed() throws DebugException { + if (isDisposed()) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___evaluation_context_has_been_disposed__7, + null)); + } + } + + /** + * Throws an exception if this engine is already in an evaluation. + * + * @exception DebugException + * if this engine is currently performing an evaluation + */ + protected void checkEvaluating() throws DebugException { + if (isEvaluating()) { + throw new DebugException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + "Cannot perform nested evaluations.", null) //$NON-NLS-1$ + ); + } + } + + /** + * Throws an exception if this engine's current evaluation thread is not + * suspended. + * + * @exception DebugException + * if this engine's current evaluation thread is not + * suspended + */ + protected void checkThread() throws DebugException { + if (!getThread().isSuspended()) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___evaluation_thread_must_be_suspended__8, + null)); + } + } + + /** + * Deletes deployed class files, and clears state. + * + * @see IEvaluationEngine#dispose() + */ + @Override + public void dispose() { + fDisposed = true; + ENGINE_COUNT--; + if (isEvaluating()) { + // cannot dispose if in an evaluation, must + // wait for evaluation to complete + return; + } + List snippetFiles = getSnippetFiles(); + Iterator iter = snippetFiles.iterator(); + while (iter.hasNext()) { + File file = iter.next(); + if (file.exists()) { + if (CODE_SNIPPET_NAME.equals(file.getName()) + && ENGINE_COUNT > 0) { + continue; // do not delete the common file for other engines + } + if (!file.delete()) { + JDIDebugPlugin + .log(new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + MessageFormat + .format("Unable to delete temporary evaluation class file {0}.", new Object[] { file.getAbsolutePath() }), null) //$NON-NLS-1$ + ); + } + } + } + List directories = getDirectories(); + // remove directories in bottom up order + int i = directories.size() - 1; + while (i >= 0) { + File dir = directories.get(i); + String[] listing = dir.list(); + if (dir.exists() && listing != null && listing.length == 0 + && !dir.delete()) { + JDIDebugPlugin + .log(new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + MessageFormat + .format("Unable to delete temporary evaluation directory {0}.", new Object[] { dir.getAbsolutePath() }), null) //$NON-NLS-1$ + ); + } + i--; + } + reset(); + setJavaProject(null); + setDebugTarget(null); + setOutputDirectory(null); + setResult(null); + setEvaluationContext(null); + } + + /** + * Resets this engine for another evaluation. + */ + private void reset() { + setThis(null); + setStackFrame(null); + setListener(null); + } + + /** + * Returns the listener to notify when the current evaluation is complete. + * + * @return the listener to notify when the current evaluation is complete + */ + protected IEvaluationListener getListener() { + return fListener; + } + + /** + * Sets the listener to notify when the current evaluation is complete. + * + * @param listener + * the listener to notify when the current evaluation is complete + */ + private void setListener(IEvaluationListener listener) { + fListener = listener; + } + + /** + * Returns the stack frame context for the current evaluation, or + * null if none. + * + * @return the stack frame context for the current evaluation, or + * null if none + */ + protected IJavaStackFrame getStackFrame() { + return fStackFrame; + } + + /** + * Sets the stack frame context for the current evaluation. + * + * @param stackFrame + * stack frame context or null if none + */ + private void setStackFrame(IJavaStackFrame stackFrame) { + fStackFrame = stackFrame; + } + + /** + * Returns the thread in which the current evaluation is to be executed. + * + * @return the thread in which the current evaluation is to be executed + */ + protected IJavaThread getThread() { + return getResult().getThread(); + } + + /** + * Returns the code snippet being evaluated. + * + * @return the code snippet being evaluated. + */ + protected String getSnippet() { + return getResult().getSnippet(); + } + + /** + * Returns the current evaluation result. + * + * @return the current evaluation result + */ + protected EvaluationResult getResult() { + return fResult; + } + + /** + * Sets the current evaluation result. + * + * @param result + * the current evaluation result + */ + private void setResult(EvaluationResult result) { + fResult = result; + } + + /** + * Deploys the given class files to this engine's output location, and adds + * the files to this engines list of temporary files to be deleted when + * disposed. + * + * @exception DebugException + * if this fails due to a lower level exception. + */ + protected void deploy(byte[][] classFiles, String[][] classFileNames) + throws DebugException { + for (int i = 0; i < classFiles.length; i++) { + String[] compoundName = classFileNames[i]; + // create required folders + File dir = LocalEvaluationEngine.this.getOutputDirectory(); + try { + String pkgDirName = dir.getCanonicalPath(); + for (int j = 0; j < (compoundName.length - 1); j++) { + pkgDirName += File.separator + compoundName[j]; + File pkgDir = new File(pkgDirName); + if (!pkgDir.exists()) { + pkgDir.mkdir(); + addDirectory(pkgDir); + } + } + String name = compoundName[compoundName.length - 1] + ".class"; //$NON-NLS-1$ + File classFile = new File(pkgDirName + File.separator + name); + if (!classFile.exists()) { + classFile.createNewFile(); + } + try (FileOutputStream stream = new FileOutputStream(classFile)) { + stream.write(classFiles[i]); + } + LocalEvaluationEngine.this.addSnippetFile(classFile); + } catch (IOException e) { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + MessageFormat + .format(EvaluationMessages.LocalEvaluationEngine__0__occurred_deploying_class_file_for_evaluation_9, + new Object[] { e.toString() }), + e)); + } + } + } + + /** + * Adds the given file to this engine's collection of deployed snippet class + * files, which are to be deleted when this engine is disposed. + * + * @param File + * snippet class file + */ + private void addSnippetFile(File file) { + if (fSnippetFiles == null) { + fSnippetFiles = new ArrayList<>(); + } + fSnippetFiles.add(file); + } + + /** + * Adds the given file to this engine's collection of created directories, + * which are to be deleted when this engine is disposed. + * + * @param file + * directory created for class file deployment + */ + private void addDirectory(File file) { + if (fDirectories == null) { + fDirectories = new ArrayList<>(); + } + fDirectories.add(file); + } + + /** + * Returns an evaluation context for this evaluation engine. An evaluation + * context is associated with a specific Java project. The evaluation context + * is created lazily on the first access. + * + * @return evaluation context + */ + protected IEvaluationContext getEvaluationContext() { + if (fEvaluationContext == null) { + fEvaluationContext = getJavaProject().newEvaluationContext(); + } + return fEvaluationContext; + } + + /** + * Sets the evaluation context for this evaluation engine. + * + * @param context + * evaluation context + */ + private void setEvaluationContext(IEvaluationContext context) { + fEvaluationContext = context; + } + + /** + * Returns a collection of snippet class file deployed by this evaluation + * engine, possibly empty. + * + * @return deployed class files + */ + protected List getSnippetFiles() { + if (fSnippetFiles == null) { + return Collections.EMPTY_LIST; + } + return fSnippetFiles; + } + + /** + * Returns a collection of directories created by this evaluation engine, + * possibly empty. + * + * @return directories created when deploying class files + */ + protected List getDirectories() { + if (fDirectories == null) { + return Collections.EMPTY_LIST; + } + return fDirectories; + } + + /** + * Returns whether this evaluation engine has been disposed. + * + * @return whether this evaluation engine has been disposed + */ + protected boolean isDisposed() { + return fDisposed; + } + + /** + * The evaluation is complete. Notify the current listener and reset for the + * next evaluation. + */ + protected void evaluationComplete() { + // only notify if plug-in not yet shutdown (bug# 8693) + if (JDIDebugPlugin.getDefault() != null) { + getListener().evaluationComplete(getResult()); + } + evaluationEnded(); + reset(); + if (isDisposed()) { + // if the engine was disposed during an evaluation + // do the cleanup now + dispose(); + } + } + + /** + * Increments the evaluation counter. + */ + private void evaluationStarted() { + fEvaluationCount++; + } + + /** + * Decrements the evaluation counter. + */ + private void evaluationEnded() { + if (fEvaluationCount > 0) { + fEvaluationCount--; + } + } + + /** + * Returns whether this engine is currently in the midst of an evaluation. + */ + protected boolean isEvaluating() { + return fEvaluationCount > 0; + } + + /** + * Called when an evaluation is aborted due to an exception. Decrements the + * evaluation count, and disposes this engine if the target VM disconnected + * or terminated during the evaluation attempt. + */ + private void evaluationAborted() { + evaluationEnded(); + if (isDisposed()) { + // if the engine was disposed during an evaluation + // do the cleanup now + dispose(); + } + } + + /** + * Constructs and returns a new instance of the specified class on the + * target VM. + * + * @param className + * fully qualified class name + * @return a new instance on the target, as an IJavaValue + * @exception DebugException + * if creation fails + */ + protected IJavaObject newInstance(String className) throws DebugException { + IJavaObject object = null; + IJavaClassType clazz = null; + IJavaType[] types = getDebugTarget().getJavaTypes(className); + if (types != null && types.length > 0) { + clazz = (IJavaClassType) types[0]; + } + if (clazz == null) { + // The class is not loaded on the target VM. + // Force the load of the class. + types = getDebugTarget().getJavaTypes("java.lang.Class"); //$NON-NLS-1$ + IJavaClassType classClass = null; + if (types != null && types.length > 0) { + classClass = (IJavaClassType) types[0]; + } + if (classClass == null) { + // unable to load the class + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_instantiate_code_snippet_class__11, + null)); + } + IJavaValue[] args = new IJavaValue[] { getDebugTarget().newValue( + className) }; + IJavaObject classObject = (IJavaObject) classClass + .sendMessage( + "forName", "(Ljava/lang/String;)Ljava/lang/Class;", args, getThread()); //$NON-NLS-2$ //$NON-NLS-1$ + object = (IJavaObject) classObject + .sendMessage( + "newInstance", "()Ljava/lang/Object;", null, getThread(), false); //$NON-NLS-2$ //$NON-NLS-1$ + } else { + object = clazz.newInstance("", null, getThread()); //$NON-NLS-1$ + } + return object; + } + + /** + * Interprets and returns the result of the running the snippet class file. + * The type of the result is described by an instance of + * java.lang.Class. The value is interpreted based on the + * result type. + *

+ * Objects as well as primitive data types (boolean, int, etc.), have class + * objects, which are created by the VM. If the class object represents a + * primitive data type, then the associated value is stored in an instance + * of its "object" class. For example, when the result type is the class + * object for int, the result object is an instance of + * java.lang.Integer, and the actual int is stored + * in the intValue(). When the result type is the class object + * for java.lang.Integer the result object is an instance of + * java.lang.Integer, to be interpreted as a + * java.lang.Integer. + *

+ * + * @param resultType + * the class of the result + * @param resultValue + * the value of the result, to be interpreted based on + * resultType + * @return the result of running the code snippet class file + */ + protected IJavaValue convertResult(IJavaClassObject resultType, + IJavaValue result) throws DebugException { + if (resultType == null) { + // there was an exception or compilation problem - no result + return null; + } + + // check the type of the result - if a primitive type, convert it + String sig = resultType.getInstanceType().getSignature(); + if (sig.equals("V") || sig.equals("Lvoid;")) { //$NON-NLS-2$ //$NON-NLS-1$ + // void + return getDebugTarget().voidValue(); + } + + if (result.getJavaType() == null) { + // null result + return result; + } + + if (sig.length() == 1) { + // primitive type - find the instance variable with the + // signature of the result type we are looking for + IVariable[] vars = result.getVariables(); + IJavaVariable var = null; + for (IVariable var2 : vars) { + IJavaVariable jv = (IJavaVariable) var2; + if (!jv.isStatic() && jv.getSignature().equals(sig)) { + var = jv; + break; + } + } + if (var != null) { + return (IJavaValue) var.getValue(); + } + } else { + // an object + return result; + } + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17, + null)); + } + + /** + * Returns the modifiers of the local variables visible in this evaluation, + * possibly empty. + * + * @return array of modifiers + */ + private int[] getLocalVariableModifiers() { + return fLocalVariableModifiers; + } + + /** + * Sets the modifiers of the local variables visible in this evaluation, + * possibly empty. + * + * @param localVariableModifiers + * array of modifiers + */ + private void setLocalVariableModifiers(int[] localVariableModifiers) { + fLocalVariableModifiers = localVariableModifiers; + } + + /** + * Returns the names of the local variables visible in this evaluation, + * possibly empty. + * + * @param array + * of names + */ + private String[] getLocalVariableNames() { + return fLocalVariableNames; + } + + /** + * Sets the names of the local variables visible in this evaluation, + * possibly empty. + * + * @param localVariableNames + * array of names + */ + private void setLocalVariableNames(String[] localVariableNames) { + fLocalVariableNames = localVariableNames; + } + + /** + * Returns the type names of the local variables visible in this evaluation, + * possibly empty. + * + * @param array + * of type names + */ + private String[] getLocalVariableTypeNames() { + return fLocalVariableTypeNames; + } + + /** + * Sets the type names of the local variables visible in this evaluation, + * possibly empty. + * + * @param localVariableTypeNames + * array of type names + */ + private void setLocalVariableTypeNames(String[] localVariableTypeNames) { + fLocalVariableTypeNames = localVariableTypeNames; + } + + /** + * Sets the receiver context for the associated evaluation, possibly + * null if the evaluation is in the context of a static method + * or there is no object context. + * + * @param thisObject + * the receiver content of the associated evaluation, or + * null + */ + private void setThis(IJavaObject thisObject) { + fThis = thisObject; + } + + /** + * Returns the receiver context for the associated evaluation, or + * null if the evaluation is in the context of a static method + * or there is no object context. + * + * @return the receiver context of the associated evaluation or + * null + */ + private IJavaObject getThis() { + return fThis; + } + + /** + * Returns a copy of the type name with '$' replaced by '.', or returns + * null if the given type name refers to an anonymous inner + * class. + * + * @param typeName + * a fully qualified type name + * @return a copy of the type name with '$' replaced by '.', or returns + * null if the given type name refers to an anonymous + * inner class. + */ + protected String getTranslatedTypeName(String typeName) { + int index = typeName.lastIndexOf('$'); + if (index == -1) { + return typeName; + } + if (index + 1 > typeName.length()) { + // invalid name + return typeName; + } + String last = typeName.substring(index + 1); + try { + Integer.parseInt(last); + return null; + } catch (NumberFormatException e) { + return typeName.replace('$', '.'); + } + } + + /** + * Returns an array of simple type names that are part of the given type's + * qualified name. For example, if the given name is x.y.A$B, + * an array with ["A", "B"] is returned. + * + * @param typeName + * fully qualified type name + * @return array of nested type names + */ + protected String[] getNestedTypeNames(String typeName) { + int index = typeName.lastIndexOf('.'); + if (index >= 0) { + typeName = typeName.substring(index + 1); + } + index = typeName.indexOf('$'); + ArrayList list = new ArrayList<>(1); + while (index >= 0) { + list.add(typeName.substring(0, index)); + typeName = typeName.substring(index + 1); + index = typeName.indexOf('$'); + } + list.add(typeName); + return list.toArray(new String[list.size()]); + } + + /** + * @see IClassFileEvaluationEngine#getImports() + */ + @Override + public String[] getImports() { + return getEvaluationContext().getImports(); + } + + /** + * @see IClassFileEvaluationEngine#setImports(String[]) + */ + @Override + public void setImports(String[] imports) { + getEvaluationContext().setImports(imports); + } + + /** + * Sets the name of the code snippet to instantiate to run the current + * evaluation. + * + * @param name + * the name of the deployed code snippet to instantiate and run + */ + private void setCodeSnippetClassName(String name) { + fCodeSnippetClassName = name; + } + + /** + * Returns the name of the code snippet to instantiate to run the current + * evaluation. + * + * @return the name of the deployed code snippet to instantiate and run + */ + protected String getCodeSnippetClassName() { + return fCodeSnippetClassName; + } + + /** + * @see ICodeSnippetRequestor#isRequestingClassFiles() + */ + public boolean isRequestingClassFiles() { + return true; + } + + /** + * Returns whether to hit breakpoints in the evaluation thread. + * + * @return whether to hit breakpoints in the evaluation thread + */ + protected boolean getHitBreakpoints() { + return fHitBreakpoints; + } + + /** + * Sets whether to hit breakpoints in the evaluation thread. + * + * @param hit + * whether to hit breakpoints in the evaluation thread + */ + private void setHitBreakpoints(boolean hit) { + fHitBreakpoints = hit; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluator.java new file mode 100644 index 0000000000..97e51e35cd --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluator.java @@ -0,0 +1,364 @@ +/******************************************************************************* + + * Copyright (c) 2019, 2020 Jesper Steen Møller and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Jesper Steen Møller - initial API and implementation + * IBM Corporation - Bug 448473 - [1.8][debug] Cannot use lambda expressions in breakpoint properties and display/expression view + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval; + +import static org.eclipse.jdt.core.eval.ICodeSnippetRequestor.LOCAL_VAR_PREFIX; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.core.eval.ICodeSnippetRequestor; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; + +import com.sun.jdi.InvocationException; +import com.sun.jdi.ObjectReference; + +/** + * An evaluation engine that deploys class files to a debuggee by using Unsafe through the JDWP. + */ + +public class RemoteEvaluator { + + private final LinkedHashMap classFiles; + + private final String codeSnippetClassName; + + private final List variableNames; + + private final IJavaClassObject loadedClass = null; + + private final String enclosingTypeName; + + /** + * Constructs a new evaluation engine for the given VM in the context of the specified project. Class files required for the evaluation will be + * deployed to the specified directory (which must be on the class path of the VM in order for evaluation to work). + * + * @param classFiles + * @param codeSnippetClassName + * @param variableNames + * @param enclosingTypeName + */ + public RemoteEvaluator(LinkedHashMap classFiles, String codeSnippetClassName, List variableNames, String enclosingTypeName) { + this.classFiles = classFiles; + this.enclosingTypeName = enclosingTypeName; + this.codeSnippetClassName = codeSnippetClassName.replace('.', '/'); + this.variableNames = variableNames; + } + + private IJavaClassObject loadTheClasses(IJavaThread theThread) throws DebugException { + + if (loadedClass != null) { + return loadedClass; + } + JDIDebugTarget debugTarget = ((JDIDebugTarget) theThread.getDebugTarget()); + IJavaClassObject theMainClass = null; + IJavaObject classloader = null; + + IJavaReferenceType surroundingClass = findType(this.enclosingTypeName, debugTarget); + classloader = surroundingClass.getClassLoaderObject(); + + for (Map.Entry entry : classFiles.entrySet()) { + String className = entry.getKey(); + + IJavaReferenceType existingClass = tryLoadType(className, debugTarget); + if (existingClass != null) { + if (codeSnippetClassName.equals(className)) { + theMainClass = existingClass.getClassObject(); + } + } else { + IJavaArray byteArray = createClassBytes(theThread, debugTarget, entry); + IJavaValue[] defineClassArgs = new IJavaValue[] { // args for defineClass + debugTarget.newValue(className.replaceAll("/", ".")), // class name //$NON-NLS-1$ //$NON-NLS-2$ + byteArray, // classBytes, + debugTarget.newValue(0), // offset + debugTarget.newValue(entry.getValue().length), // length + debugTarget.nullValue() // protection domain + }; + + IJavaClassObject theClass = (IJavaClassObject) classloader.sendMessage("defineClass", "(Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;", defineClassArgs, theThread, false); //$NON-NLS-1$//$NON-NLS-2$ + if (codeSnippetClassName.equals(className)) { + theMainClass = theClass; + } + } + } + return theMainClass; + } + + private IJavaArray createClassBytes(IJavaThread theThread, JDIDebugTarget debugTarget, Map.Entry entry) throws DebugException { + IJavaReferenceType byteArrayType = findType("byte[]", debugTarget);//$NON-NLS-1$ + byte[] classBytes = entry.getValue(); + IJavaArray byteArray = ((IJavaArrayType) byteArrayType).newInstance(classBytes.length); + + IJavaValue[] debugClassBytes = new IJavaValue[classBytes.length]; + for (int ix = 0; ix < classBytes.length; ++ix) { + debugClassBytes[ix] = ((JDIDebugTarget) theThread.getDebugTarget()).newValue(classBytes[ix]); + } + byteArray.setValues(debugClassBytes); + return byteArray; + } + + private IJavaReferenceType findType(String typeName, IJavaDebugTarget debugTarget) throws DebugException { + IJavaReferenceType theClass = tryLoadType(typeName, debugTarget); + if (theClass == null) { + // unable to load the class + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.RemoteEvaluationEngine_Evaluation_failed___unable_to_find_injected_class, + null)); + } + return theClass; + } + + private IJavaReferenceType tryLoadType(String typeName, IJavaDebugTarget debugTarget) throws DebugException { + IJavaReferenceType clazz = null; + IJavaType[] types = debugTarget.getJavaTypes(typeName); + if (types != null && types.length > 0) { + clazz = (IJavaReferenceType) types[0]; + } + return clazz; + } + + /** + * Initializes the value of instance variables in the 'code snippet object' that are used as place-holders for free variables and 'this' in the + * current stack frame. + * + * @param object + * instance of code snippet class that will be run + * @param boundValues + * popped values which should be injected into the code snippet object. + * @exception DebugException + * if an exception is thrown accessing the given object + */ + protected void initializeFreeVars(IJavaObject object, IJavaValue boundValues[]) throws DebugException { + if (boundValues.length != this.variableNames.size()) { + throw new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4, null)); + } + + for (int i = 0; i < boundValues.length; ++i) { + IJavaVariable field = object.getField(new String(LOCAL_VAR_PREFIX) + this.variableNames.get(i), false); + if (field != null) { + IJavaValue bound = boundValues[i]; + field.setValue(bound); + } else { + // System.out.print(Arrays.asList(((IJavaReferenceType) object.getJavaType()).getAllFieldNames())); + throw new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4, null)); + } + } + } + + /** + * Constructs and returns a new instance of the specified class on the + * target VM. + * + * @param className + * fully qualified class name + * @return a new instance on the target, as an IJavaValue + * @exception DebugException + * if creation fails + */ + protected IJavaObject newInstance(IJavaThread theThread) throws DebugException { + IJavaDebugTarget debugTarget = ((IJavaDebugTarget) theThread.getDebugTarget()); + + IJavaObject object = null; + IJavaClassObject clazz = loadTheClasses(theThread); + if (clazz == null) { + // The class is not loaded on the target VM. + // Force the load of the class. + IJavaType[] types = debugTarget.getJavaTypes("java.lang.Class"); //$NON-NLS-1$ + IJavaClassType classClass = null; + if (types != null && types.length > 0) { + classClass = (IJavaClassType) types[0]; + } + if (classClass == null) { + // unable to load the class + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_instantiate_code_snippet_class__11, + null)); + } + IJavaValue[] args = new IJavaValue[] { debugTarget.newValue( + this.codeSnippetClassName) }; + IJavaObject classObject = (IJavaObject) classClass + .sendMessage( + "forName", "(Ljava/lang/String;)Ljava/lang/Class;", args, theThread); //$NON-NLS-2$ //$NON-NLS-1$ + object = (IJavaObject) classObject + .sendMessage( + "newInstance", "()Ljava/lang/Object;", null, theThread, false); //$NON-NLS-2$ //$NON-NLS-1$ + } else { + object = (IJavaObject) clazz.sendMessage("newInstance", "()Ljava/lang/Object;", null, theThread, false); //$NON-NLS-2$ //$NON-NLS-1$ + // object = clazz.newInstance("", null, theThread); //$NON-NLS-1$ + } + return object; + } + + /** + * Interprets and returns the result of the running the snippet class file. + * The type of the result is described by an instance of + * java.lang.Class. The value is interpreted based on the + * result type. + *

+ * Objects as well as primitive data types (boolean, int, etc.), have class + * objects, which are created by the VM. If the class object represents a + * primitive data type, then the associated value is stored in an instance + * of its "object" class. For example, when the result type is the class + * object for int, the result object is an instance of + * java.lang.Integer, and the actual int is stored + * in the intValue(). When the result type is the class object + * for java.lang.Integer the result object is an instance of + * java.lang.Integer, to be interpreted as a + * java.lang.Integer. + *

+ * + * @param resultType + * the class of the result + * @param resultValue + * the value of the result, to be interpreted based on + * resultType + * @return the result of running the code snippet class file + */ + protected IJavaValue convertResult(IJavaDebugTarget debugTarget, IJavaClassObject resultType, + IJavaValue result) throws DebugException { + if (resultType == null) { + // there was an exception or compilation problem - no result + return null; + } + + // check the type of the result - if a primitive type, convert it + String sig = resultType.getInstanceType().getSignature(); + if (sig.equals("V") || sig.equals("Lvoid;")) { //$NON-NLS-2$ //$NON-NLS-1$ + // void + return debugTarget.voidValue(); + } + + if (result.getJavaType() == null) { + // null result + return result; + } + + if (sig.length() == 1) { + // primitive type - find the instance variable with the + // signature of the result type we are looking for + IVariable[] vars = result.getVariables(); + IJavaVariable var = null; + for (IVariable var2 : vars) { + IJavaVariable jv = (IJavaVariable) var2; + if (!jv.isStatic() && jv.getSignature().equals(sig)) { + var = jv; + break; + } + } + if (var != null) { + return (IJavaValue) var.getValue(); + } + } else { + // an object + return result; + } + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17, + null)); + } + + /** + * Returns the name of the code snippet to instantiate to run the current + * evaluation. + * + * @return the name of the deployed code snippet to instantiate and run + */ + protected String getCodeSnippetClassName() { + return codeSnippetClassName; + } + + public IJavaValue evaluate(IJavaThread theThread, IJavaValue[] args) throws DebugException { + IJavaObject codeSnippetInstance = null; + IJavaDebugTarget debugTarget = ((IJavaDebugTarget) theThread.getDebugTarget()); + try { + codeSnippetInstance = newInstance(theThread); + initializeFreeVars(codeSnippetInstance, args); + codeSnippetInstance.sendMessage(ICodeSnippetRequestor.RUN_METHOD, "()V", null, theThread, false); //$NON-NLS-1$ + + // now retrieve the description of the result + IVariable[] fields = codeSnippetInstance.getVariables(); + IJavaVariable resultValue = null; + IJavaVariable resultType = null; + for (IVariable field : fields) { + if (field.getName().equals(ICodeSnippetRequestor.RESULT_TYPE_FIELD)) { + resultType = (IJavaVariable) field; + } + if (field.getName().equals(ICodeSnippetRequestor.RESULT_VALUE_FIELD)) { + resultValue = (IJavaVariable) field; + } + } + IJavaValue result = convertResult(debugTarget, (IJavaClassObject) resultType.getValue(), (IJavaValue) resultValue.getValue()); + return result; + } catch (DebugException e) { + Throwable underlyingException = e.getStatus().getException(); + if (underlyingException instanceof InvocationException) { + ObjectReference theException = ((InvocationException) underlyingException).exception(); + if (theException != null) { + try { + try { + IJavaObject v = (IJavaObject) JDIValue.createValue((JDIDebugTarget) debugTarget, theException); + v.sendMessage("printStackTrace", "()V", null, theThread, false); //$NON-NLS-2$ //$NON-NLS-1$ + } catch (DebugException de) { + JDIDebugPlugin.log(de); + } + } catch (RuntimeException re) { + JDIDebugPlugin.log(re); + } + } + } + throw e; + } + } + + public int getVariableCount() { + return this.variableNames.size(); + } + + public String getVariableName(int i) { + return this.variableNames.get(i); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java new file mode 100644 index 0000000000..fb9b3eaafa --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java @@ -0,0 +1,2124 @@ +/******************************************************************************* + * Copyright (c) 2019, 2020 Jesper Steen Møller and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Jesper Steen Møller - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval; + +import static org.eclipse.jdt.core.eval.ICodeSnippetRequestor.LOCAL_VAR_PREFIX; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.*; +import org.eclipse.jdt.core.eval.ICodeSnippetRequestor; +import org.eclipse.jdt.core.eval.IEvaluationContext; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationEngineMessages; + +/** + * A builder for a reuseable expression evaluator against a runnng VM. + */ + +@SuppressWarnings("rawtypes") +public class RemoteEvaluatorBuilder { + + private final IJavaProject javaProject; + private final ExpressionBinder binder; + private final String enclosingTypeName; + private final String packageName; + private final boolean isStatic; + private final boolean isConstructor; + private final List argumentNames = new ArrayList<>(); + private final List argumentTypeNames = new ArrayList<>(); + + /** + * The names and bytecodes of the code snippet class to instantiate + */ + private final LinkedHashMap classFiles = new LinkedHashMap<>(); + + /** + * The name of the code snippet class to instantiate + */ + private String codeSnippetClassName = null; + private String snippet = null; + private final ITypeBinding enclosingClass; + + public RemoteEvaluatorBuilder(IJavaProject javaProject, ExpressionBinder binder, ITypeBinding enclosingClass, boolean isStatic, boolean isConstructor) { + this.javaProject = javaProject; + this.binder = binder; + this.enclosingClass = enclosingClass; + this.enclosingTypeName = enclosingClass.getQualifiedName(); + this.packageName = enclosingClass.getPackage().getName(); + this.isStatic = isStatic; + this.isConstructor = isConstructor; + } + + public void acceptLambda(LambdaExpression lambda, ITypeBinding expectedResult) { + acceptFunctionalExpression(lambda, expectedResult); + } + + public void acceptMethodReference(MethodReference node, ITypeBinding expectedResult) { + acceptFunctionalExpression(node, expectedResult); + } + + public void acceptAnonymousClass(ClassInstanceCreation node, ITypeBinding expectedResult) { + acceptFunctionalExpression(node, expectedResult); + } + + + private void acceptFunctionalExpression(Expression node, ITypeBinding expectedResult) { + FunctionalEvalVisitor visitor = new FunctionalEvalVisitor(); + node.accept(visitor); + String castExpression = "(" + expectedResult.getQualifiedName() + ")"; //$NON-NLS-1$//$NON-NLS-2$ + this.snippet = castExpression + "(" + visitor.buffer.toString() + ")"; //$NON-NLS-1$//$NON-NLS-2$ + } + + public String getSnippet() { + return snippet; + } + + private static Object EVALUATE_CODE_SNIPPET_LOCK = new Object(); + + public RemoteEvaluator build() throws JavaModelException, DebugException { + + List boundVariableNames = getVariableNames(); + List boundVariableTypeNames = getVariableTypeNames(); + + List errors = new ArrayList<>(); + IType enclosingType = this.javaProject.findType(enclosingTypeName); + + if (enclosingType == null) { + throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), EvaluationEngineMessages.ASTInstructionCompiler_Functional_expressions_cannot_be_evaluated_inside_local_and_or_anonymous_classes)); + } + + synchronized (EVALUATE_CODE_SNIPPET_LOCK) { + IEvaluationContext context = this.javaProject.newEvaluationContext(); + if (!packageName.startsWith("java.")) { //$NON-NLS-1$ + context.setPackageName(this.packageName); + } + // System.out.println(this.snippet); + context.evaluateCodeSnippet(this.snippet, boundVariableTypeNames.toArray(new String[boundVariableNames.size()]), boundVariableNames.toArray(new String[boundVariableNames.size()]), new int[boundVariableNames.size()], enclosingType, isStatic, isConstructor, new ICodeSnippetRequestor() { + + @Override + public void acceptProblem(IMarker problemMarker, String fragmentSource, int fragmentKind) { + if (problemMarker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO) >= IMarker.SEVERITY_ERROR) { + errors.add(toString(problemMarker)); + } + } + + private String toString(IMarker marker) { + return marker.getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$ + } + + @Override + public boolean acceptClassFiles(byte[][] classFileBytes, String[][] classFileCompoundNames, String mainCodeSnippetClassName) { + for (int i = 0; i < classFileCompoundNames.length; ++i) { + String className = makeClassName(classFileCompoundNames[i]); + classFiles.put(className, classFileBytes[i]); + } + if (mainCodeSnippetClassName != null) { + setCodeSnippetClassName(mainCodeSnippetClassName); + } + return true; + } + }, null); + } + + if (!errors.isEmpty()) { + throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), errors.toString())); + } + + return new RemoteEvaluator(classFiles, codeSnippetClassName, getVariableNames(), enclosingType.getFullyQualifiedName('$')); + } + + private void setCodeSnippetClassName(String codeSnippetClassName) { + this.codeSnippetClassName = codeSnippetClassName; + } + + private static String makeClassName(String[] names) { + return String.join(String.valueOf('/'), names); + } + + public List getVariableTypeNames() { + return Collections.unmodifiableList(argumentTypeNames); + } + + public List getVariableNames() { + return Collections.unmodifiableList(argumentNames); + } + + public String allocateNewVariable(ITypeBinding binding, String hint) { + String varName = hint + "$" + argumentNames.size(); //$NON-NLS-1$ + argumentNames.add(varName); + argumentTypeNames.add(binding.getQualifiedName()); + return varName; + } + + public IJavaProject getJavaProject() { + return javaProject; + } + + public String getEnclosingTypeName() { + return enclosingTypeName; + } + + public boolean isStatic() { + return isStatic; + } + + /** + * Internal synonym for {@link MethodDeclaration#getReturnType()}. Use to alleviate deprecation warnings. + * + * @deprecated + * @since 3.4 + */ + @Deprecated + private static Type getReturnType(MethodDeclaration node) { + return node.getReturnType(); + } + + /** + * Internal synonym for {@link TypeDeclaration#getSuperclass()}. Use to alleviate deprecation warnings. + * + * @deprecated + * @since 3.4 + */ + @Deprecated + private static Name getSuperclass(TypeDeclaration node) { + return node.getSuperclass(); + } + + /** + * Internal synonym for {@link TypeDeclarationStatement#getTypeDeclaration()}. Use to alleviate deprecation warnings. + * + * @deprecated + * @since 3.4 + */ + @Deprecated + private static TypeDeclaration getTypeDeclaration(TypeDeclarationStatement node) { + return node.getTypeDeclaration(); + } + + /** + * Internal synonym for {@link MethodDeclaration#thrownExceptions()}. Use to alleviate deprecation warnings. + * + * @deprecated + * @since 3.10 + */ + @Deprecated + private static List thrownExceptions(MethodDeclaration node) { + return node.thrownExceptions(); + } + + private class FunctionalEvalVisitor extends ASTVisitor { + + /** + * The string buffer into which the serialized representation of the AST is written. + */ + protected StringBuilder buffer = new StringBuilder(); + + private int indent = 2; + + private final Map localBindings = new HashMap<>(); + + public FunctionalEvalVisitor() { + } + + boolean isLocalBinding(IBinding binding) { + return localBindings.containsKey(binding); + } + + private boolean isParentInLocalBinding(ASTNode parent) { + if (parent instanceof QualifiedName) { + // this will avoid unwanted upward traversals + if (isLocalBinding(((QualifiedName) parent).getQualifier().resolveBinding())) { + return true; + } + // traverse upstream to see if a parent is already handled + return isParentInLocalBinding(parent.getParent()); + } + return false; + } + + void addLocalBinding(IBinding binding, String name) { + localBindings.put(binding, name); + } + + void printIndent() { + for (int i = 0; i < indent; i++) { + buffer.append(" ");//$NON-NLS-1$ + } + } + + /** + * Internal synonym for {@link AST#JLS2}. Use to alleviate deprecation warnings. + * + * @deprecated + */ + @Deprecated + private static final int JLS2 = AST.JLS2; + + /** + * Internal synonym for {@link AST#JLS3}. Use to alleviate deprecation warnings. + * + * @deprecated + */ + @Deprecated + private static final int JLS3 = AST.JLS3; + + /** + * Internal synonym for {@link AST#JLS4}. Use to alleviate deprecation warnings. + * + * @deprecated + */ + @Deprecated + private static final int JLS4 = AST.JLS4; + + /** + * Internal synonym for {@link AST#JLS8}. Use to alleviate deprecation warnings. + * + * @deprecated + */ + @Deprecated + private static final int JLS8 = AST.JLS8; + + /** + * Internal synonym for {@link AST#JLS9}. Use to alleviate deprecation warnings. + * + * @deprecated + */ + @Deprecated + private static final int JLS9 = AST.JLS9; + + /** + * Internal synonym for {@link ClassInstanceCreation#getName()}. Use to alleviate deprecation warnings. + * + * @deprecated + */ + @Deprecated + private Name getName(ClassInstanceCreation node) { + return node.getName(); + } + + /** + * Appends the text representation of the given modifier flags, followed by a single space. Used for JLS2 modifiers. + * + * @param modifiers + * the modifier flags + */ + void printModifiers(int modifiers) { + if (Modifier.isPublic(modifiers)) { + buffer.append("public ");//$NON-NLS-1$ + } + if (Modifier.isProtected(modifiers)) { + buffer.append("protected ");//$NON-NLS-1$ + } + if (Modifier.isPrivate(modifiers)) { + buffer.append("private ");//$NON-NLS-1$ + } + if (Modifier.isStatic(modifiers)) { + buffer.append("static ");//$NON-NLS-1$ + } + if (Modifier.isAbstract(modifiers)) { + buffer.append("abstract ");//$NON-NLS-1$ + } + if (Modifier.isFinal(modifiers)) { + buffer.append("final ");//$NON-NLS-1$ + } + if (Modifier.isSynchronized(modifiers)) { + buffer.append("synchronized ");//$NON-NLS-1$ + } + if (Modifier.isVolatile(modifiers)) { + buffer.append("volatile ");//$NON-NLS-1$ + } + if (Modifier.isNative(modifiers)) { + buffer.append("native ");//$NON-NLS-1$ + } + if (Modifier.isStrictfp(modifiers)) { + buffer.append("strictfp ");//$NON-NLS-1$ + } + if (Modifier.isTransient(modifiers)) { + buffer.append("transient ");//$NON-NLS-1$ + } + } + + /** + * Appends the text representation of the given modifier flags, followed by a single space. Used for 3.0 modifiers and annotations. + * + * @param ext + * the list of modifier and annotation nodes (element type: IExtendedModifiers) + */ + void printModifiers(List ext) { + for (Iterator it = ext.iterator(); it.hasNext();) { + ASTNode p = (ASTNode) it.next(); + p.accept(this); + buffer.append(" ");//$NON-NLS-1$ + } + } + + private void printTypes(List types, String prefix) { + if (types.size() > 0) { + buffer.append(" " + prefix + " ");//$NON-NLS-1$ //$NON-NLS-2$ + Type type = types.get(0); + type.accept(this); + for (int i = 1, l = types.size(); i < l; ++i) { + buffer.append(","); //$NON-NLS-1$ + type = types.get(0); + type.accept(this); + } + } + } + + /** + * reference node helper function that is common to all the difference reference nodes. + * + * @param typeArguments + * list of type arguments + */ + private void visitReferenceTypeArguments(List typeArguments) { + buffer.append("::");//$NON-NLS-1$ + if (!typeArguments.isEmpty()) { + buffer.append('<'); + for (Iterator it = typeArguments.iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(','); + } + } + buffer.append('>'); + } + } + + private void visitTypeAnnotations(AnnotatableType node) { + if (node.getAST().apiLevel() >= JLS8) { + visitAnnotationsList(node.annotations()); + } + } + + private void visitAnnotationsList(List annotations) { + for (Iterator it = annotations.iterator(); it.hasNext();) { + Annotation annotation = (Annotation) it.next(); + annotation.accept(this); + buffer.append(' '); + } + } + + /** + * Internal synonym for {@link TypeDeclaration#superInterfaces()}. Use to alleviate deprecation warnings. + * + * @deprecated + * @since 3.4 + */ + @Deprecated + private List superInterfaces(TypeDeclaration node) { + return node.superInterfaces(); + } + + @Override + public boolean visit(AnnotationTypeDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + buffer.append("@interface ");//$NON-NLS-1$ + node.getName().accept(this); + buffer.append(" {");//$NON-NLS-1$ + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext();) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + } + buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + node.getType().accept(this); + buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + buffer.append("()");//$NON-NLS-1$ + if (node.getDefault() != null) { + buffer.append(" default ");//$NON-NLS-1$ + node.getDefault().accept(this); + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(AnonymousClassDeclaration node) { + buffer.append("{\n");//$NON-NLS-1$ + indent++; + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext();) { + BodyDeclaration b = (BodyDeclaration) it.next(); + b.accept(this); + } + indent--; + printIndent(); + buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ArrayAccess node) { + node.getArray().accept(this); + buffer.append("[");//$NON-NLS-1$ + node.getIndex().accept(this); + buffer.append("]");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ArrayCreation node) { + buffer.append("new ");//$NON-NLS-1$ + ArrayType at = node.getType(); + int dims = at.getDimensions(); + Type elementType = at.getElementType(); + elementType.accept(this); + for (Iterator it = node.dimensions().iterator(); it.hasNext();) { + buffer.append("[");//$NON-NLS-1$ + Expression e = (Expression) it.next(); + e.accept(this); + buffer.append("]");//$NON-NLS-1$ + dims--; + } + // add empty "[]" for each extra array dimension + for (int i = 0; i < dims; i++) { + buffer.append("[]");//$NON-NLS-1$ + } + if (node.getInitializer() != null) { + node.getInitializer().accept(this); + } + return false; + } + + @Override + public boolean visit(ArrayInitializer node) { + buffer.append("{");//$NON-NLS-1$ + for (Iterator it = node.expressions().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append("}");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ArrayType node) { + if (node.getAST().apiLevel() < JLS8) { + visitComponentType(node); + buffer.append("[]");//$NON-NLS-1$ + } else { + node.getElementType().accept(this); + List dimensions = node.dimensions(); + int size = dimensions.size(); + for (int i = 0; i < size; i++) { + Dimension aDimension = (Dimension) dimensions.get(i); + aDimension.accept(this); + } + } + return false; + } + + @Override + public boolean visit(AssertStatement node) { + printIndent(); + buffer.append("assert ");//$NON-NLS-1$ + node.getExpression().accept(this); + if (node.getMessage() != null) { + buffer.append(" : ");//$NON-NLS-1$ + node.getMessage().accept(this); + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(Assignment node) { + node.getLeftHandSide().accept(this); + buffer.append(node.getOperator().toString()); + node.getRightHandSide().accept(this); + return false; + } + + @Override + public boolean visit(Block node) { + buffer.append("{\n");//$NON-NLS-1$ + indent++; + for (Iterator it = node.statements().iterator(); it.hasNext();) { + Statement s = (Statement) it.next(); + s.accept(this); + } + indent--; + printIndent(); + buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(BlockComment node) { + printIndent(); + buffer.append("/* */");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(BooleanLiteral node) { + if (node.booleanValue() == true) { + buffer.append("true");//$NON-NLS-1$ + } else { + buffer.append("false");//$NON-NLS-1$ + } + return false; + } + + @Override + public boolean visit(BreakStatement node) { + printIndent(); + buffer.append("break");//$NON-NLS-1$ + if (node.getLabel() != null) { + buffer.append(" ");//$NON-NLS-1$ + node.getLabel().accept(this); + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(CastExpression node) { + buffer.append("(");//$NON-NLS-1$ + node.getType().accept(this); + buffer.append(")");//$NON-NLS-1$ + node.getExpression().accept(this); + return false; + } + + @Override + public boolean visit(CatchClause node) { + buffer.append("catch (");//$NON-NLS-1$ + node.getException().accept(this); + buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(CharacterLiteral node) { + buffer.append(node.getEscapedValue()); + return false; + } + + @Override + public boolean visit(ClassInstanceCreation node) { + if (node.getExpression() != null) { + node.getExpression().accept(this); + buffer.append(".");//$NON-NLS-1$ + } + buffer.append("new ");//$NON-NLS-1$ + if (node.getAST().apiLevel() == JLS2) { + getName(node).accept(this); + } + if (node.getAST().apiLevel() >= JLS3) { + if (!node.typeArguments().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + node.getType().accept(this); + } + buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + if (node.getAnonymousClassDeclaration() != null) { + node.getAnonymousClassDeclaration().accept(this); + } + return false; + } + + @Override + public boolean visit(CompilationUnit node) { + if (node.getAST().apiLevel() >= JLS9) { + if (node.getModule() != null) { + node.getModule().accept(this); + } + } + if (node.getPackage() != null) { + node.getPackage().accept(this); + } + for (Iterator it = node.imports().iterator(); it.hasNext();) { + ImportDeclaration d = (ImportDeclaration) it.next(); + d.accept(this); + } + for (Iterator it = node.types().iterator(); it.hasNext();) { + AbstractTypeDeclaration d = (AbstractTypeDeclaration) it.next(); + d.accept(this); + } + return false; + } + + @Override + public boolean visit(ConditionalExpression node) { + node.getExpression().accept(this); + buffer.append(" ? ");//$NON-NLS-1$ + node.getThenExpression().accept(this); + buffer.append(" : ");//$NON-NLS-1$ + node.getElseExpression().accept(this); + return false; + } + + @Override + public boolean visit(ConstructorInvocation node) { + printIndent(); + if (node.getAST().apiLevel() >= JLS3) { + if (!node.typeArguments().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + } + buffer.append("this(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(");\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ContinueStatement node) { + printIndent(); + buffer.append("continue");//$NON-NLS-1$ + if (node.getLabel() != null) { + buffer.append(" ");//$NON-NLS-1$ + node.getLabel().accept(this); + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(CreationReference node) { + node.getType().accept(this); + visitReferenceTypeArguments(node.typeArguments()); + buffer.append("new");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(Dimension node) { + List annotations = node.annotations(); + if (annotations.size() > 0) { + buffer.append(' '); + } + visitAnnotationsList(annotations); + buffer.append("[]"); //$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(DoStatement node) { + printIndent(); + buffer.append("do ");//$NON-NLS-1$ + node.getBody().accept(this); + buffer.append(" while (");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(");\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(EmptyStatement node) { + printIndent(); + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(EnhancedForStatement node) { + printIndent(); + buffer.append("for (");//$NON-NLS-1$ + node.getParameter().accept(this); + buffer.append(" : ");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(EnumConstantDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + node.getName().accept(this); + if (!node.arguments().isEmpty()) { + buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + } + if (node.getAnonymousClassDeclaration() != null) { + node.getAnonymousClassDeclaration().accept(this); + } + return false; + } + + @Override + public boolean visit(EnumDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + buffer.append("enum ");//$NON-NLS-1$ + node.getName().accept(this); + buffer.append(" ");//$NON-NLS-1$ + if (!node.superInterfaceTypes().isEmpty()) { + buffer.append("implements ");//$NON-NLS-1$ + for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + } + buffer.append("{");//$NON-NLS-1$ + for (Iterator it = node.enumConstants().iterator(); it.hasNext();) { + EnumConstantDeclaration d = (EnumConstantDeclaration) it.next(); + d.accept(this); + // enum constant declarations do not include punctuation + if (it.hasNext()) { + // enum constant declarations are separated by commas + buffer.append(", ");//$NON-NLS-1$ + } + } + if (!node.bodyDeclarations().isEmpty()) { + buffer.append("; ");//$NON-NLS-1$ + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext();) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + // other body declarations include trailing punctuation + } + } + buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ExportsDirective node) { + return visit(node, "exports"); //$NON-NLS-1$ + } + + @Override + public boolean visit(ExpressionMethodReference node) { + node.getExpression().accept(this); + visitReferenceTypeArguments(node.typeArguments()); + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(ExpressionStatement node) { + printIndent(); + node.getExpression().accept(this); + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(FieldAccess node) { + /* TODO: Make tricks here when we access fields where we have non-public access */ + ITypeBinding instanceType = node.getExpression().resolveTypeBinding(); + if (instanceType.isAssignmentCompatible(RemoteEvaluatorBuilder.this.enclosingClass)) { + node.getExpression().accept(this); + buffer.append(".");//$NON-NLS-1$ */ + buffer.append(node.getName().getIdentifier()); + return false; + } + node.getExpression().accept(this); + buffer.append(".");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(FieldDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.fragments().iterator(); it.hasNext();) { + VariableDeclarationFragment f = (VariableDeclarationFragment) it.next(); + f.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ForStatement node) { + printIndent(); + buffer.append("for (");//$NON-NLS-1$ + for (Iterator it = node.initializers().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append("; ");//$NON-NLS-1$ + if (node.getExpression() != null) { + node.getExpression().accept(this); + } + buffer.append("; ");//$NON-NLS-1$ + for (Iterator it = node.updaters().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(IfStatement node) { + printIndent(); + buffer.append("if (");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(") ");//$NON-NLS-1$ + node.getThenStatement().accept(this); + if (node.getElseStatement() != null) { + buffer.append(" else ");//$NON-NLS-1$ + node.getElseStatement().accept(this); + } + return false; + } + + @Override + public boolean visit(ImportDeclaration node) { + printIndent(); + buffer.append("import ");//$NON-NLS-1$ + if (node.getAST().apiLevel() >= JLS3) { + if (node.isStatic()) { + buffer.append("static ");//$NON-NLS-1$ + } + } + node.getName().accept(this); + if (node.isOnDemand()) { + buffer.append(".*");//$NON-NLS-1$ + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(InfixExpression node) { + node.getLeftOperand().accept(this); + buffer.append(' '); // for cases like x= i - -1; or x= i++ + ++i; + buffer.append(node.getOperator().toString()); + buffer.append(' '); + node.getRightOperand().accept(this); + final List extendedOperands = node.extendedOperands(); + if (extendedOperands.size() != 0) { + buffer.append(' '); + for (Iterator it = extendedOperands.iterator(); it.hasNext();) { + buffer.append(node.getOperator().toString()).append(' '); + Expression e = (Expression) it.next(); + e.accept(this); + } + } + return false; + } + + @Override + public boolean visit(Initializer node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + } + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(InstanceofExpression node) { + node.getLeftOperand().accept(this); + buffer.append(" instanceof ");//$NON-NLS-1$ + node.getRightOperand().accept(this); + return false; + } + + @Override + public boolean visit(IntersectionType node) { + for (Iterator it = node.types().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(" & "); //$NON-NLS-1$ + } + } + return false; + } + + @Override + public boolean visit(Javadoc node) { + printIndent(); + buffer.append("/** ");//$NON-NLS-1$ + for (Iterator it = node.tags().iterator(); it.hasNext();) { + ASTNode e = (ASTNode) it.next(); + e.accept(this); + } + buffer.append("\n */\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(LabeledStatement node) { + printIndent(); + node.getLabel().accept(this); + buffer.append(": ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(LambdaExpression node) { + boolean hasParentheses = node.hasParentheses(); + if (hasParentheses) { + buffer.append('('); + } + for (Iterator it = node.parameters().iterator(); it.hasNext();) { + VariableDeclaration v = (VariableDeclaration) it.next(); + v.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + if (hasParentheses) { + buffer.append(')'); + } + buffer.append(" -> "); //$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(LineComment node) { + buffer.append("//\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(MarkerAnnotation node) { + buffer.append("@");//$NON-NLS-1$ + node.getTypeName().accept(this); + return false; + } + + @Override + public boolean visit(MemberRef node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + } + buffer.append("#");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(MemberValuePair node) { + node.getName().accept(this); + buffer.append("=");//$NON-NLS-1$ + node.getValue().accept(this); + return false; + } + + @Override + public boolean visit(MethodDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + if (!node.typeParameters().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeParameters().iterator(); it.hasNext();) { + TypeParameter t = (TypeParameter) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + } + if (!node.isConstructor()) { + if (node.getAST().apiLevel() == JLS2) { + getReturnType(node).accept(this); + } else { + if (node.getReturnType2() != null) { + node.getReturnType2().accept(this); + } else { + // methods really ought to have a return type + buffer.append("void");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + } + node.getName().accept(this); + buffer.append("(");//$NON-NLS-1$ + if (node.getAST().apiLevel() >= JLS8) { + Type receiverType = node.getReceiverType(); + if (receiverType != null) { + receiverType.accept(this); + buffer.append(' '); + SimpleName qualifier = node.getReceiverQualifier(); + if (qualifier != null) { + qualifier.accept(this); + buffer.append('.'); + } + buffer.append("this"); //$NON-NLS-1$ + if (node.parameters().size() > 0) { + buffer.append(','); + } + } + } + for (Iterator it = node.parameters().iterator(); it.hasNext();) { + SingleVariableDeclaration v = (SingleVariableDeclaration) it.next(); + v.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + int size = node.getExtraDimensions(); + if (node.getAST().apiLevel() >= JLS8) { + List dimensions = node.extraDimensions(); + for (int i = 0; i < size; i++) { + visit((Dimension) dimensions.get(i)); + } + } else { + for (int i = 0; i < size; i++) { + buffer.append("[]"); //$NON-NLS-1$ + } + } + if (node.getAST().apiLevel() < JLS8) { + if (!thrownExceptions(node).isEmpty()) { + buffer.append(" throws ");//$NON-NLS-1$ + for (Iterator it = thrownExceptions(node).iterator(); it.hasNext();) { + Name n = (Name) it.next(); + n.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + } + } else { + if (!node.thrownExceptionTypes().isEmpty()) { + buffer.append(" throws ");//$NON-NLS-1$ + for (Iterator it = node.thrownExceptionTypes().iterator(); it.hasNext();) { + Type n = (Type) it.next(); + n.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + } + } + if (node.getBody() == null) { + buffer.append(";\n");//$NON-NLS-1$ + } else { + node.getBody().accept(this); + } + return false; + } + + @Override + public boolean visit(MethodInvocation node) { + if (node.getExpression() != null) { + node.getExpression().accept(this); + buffer.append(".");//$NON-NLS-1$ + } else { + String newVarName = new String(LOCAL_VAR_PREFIX) + allocateNewVariable(node.resolveMethodBinding().getDeclaringClass(), "this"); //$NON-NLS-1$ + binder.bindThis(RemoteEvaluatorBuilder.this.enclosingClass, newVarName); + // buffer.append("this."); //$NON-NLS-1$ + buffer.append(newVarName); + buffer.append(".");//$NON-NLS-1$ + } + if (node.getAST().apiLevel() >= JLS3) { + if (!node.typeArguments().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + } + node.getName().accept(this); + buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(MethodRef node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + } + buffer.append("#");//$NON-NLS-1$ + node.getName().accept(this); + buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.parameters().iterator(); it.hasNext();) { + MethodRefParameter e = (MethodRefParameter) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(MethodRefParameter node) { + node.getType().accept(this); + if (node.getAST().apiLevel() >= JLS3) { + if (node.isVarargs()) { + buffer.append("...");//$NON-NLS-1$ + } + } + if (node.getName() != null) { + buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + } + return false; + } + + @Override + public boolean visit(Modifier node) { + buffer.append(node.getKeyword().toString()); + return false; + } + + @Override + public boolean visit(ModuleDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printModifiers(node.annotations()); + if (node.isOpen()) { + buffer.append("open "); //$NON-NLS-1$ + } + buffer.append("module"); //$NON-NLS-1$ + buffer.append(" "); //$NON-NLS-1$ + node.getName().accept(this); + buffer.append(" {\n"); //$NON-NLS-1$ + indent++; + for (ModuleDirective stmt : (List) node.moduleStatements()) { + stmt.accept(this); + } + indent--; + buffer.append("}"); //$NON-NLS-1$ + return false; + } + + @Override + /* + * @see ASTVisitor#visit(ModuleModifier) + * + * @since 3.14 + */ + public boolean visit(ModuleModifier node) { + buffer.append(node.getKeyword().toString()); + return false; + } + + private boolean visit(ModulePackageAccess node, String keyword) { + printIndent(); + buffer.append(keyword); + buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + printTypes(node.modules(), "to"); //$NON-NLS-1$ + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(NameQualifiedType node) { + node.getQualifier().accept(this); + buffer.append('.'); + visitTypeAnnotations(node); + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(NormalAnnotation node) { + buffer.append("@");//$NON-NLS-1$ + node.getTypeName().accept(this); + buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.values().iterator(); it.hasNext();) { + MemberValuePair p = (MemberValuePair) it.next(); + p.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(NullLiteral node) { + buffer.append("null");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(NumberLiteral node) { + buffer.append(node.getToken()); + return false; + } + + @Override + public boolean visit(OpensDirective node) { + return visit(node, "opens"); //$NON-NLS-1$ + } + + @Override + public boolean visit(PackageDeclaration node) { + if (node.getAST().apiLevel() >= JLS3) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + for (Iterator it = node.annotations().iterator(); it.hasNext();) { + Annotation p = (Annotation) it.next(); + p.accept(this); + buffer.append(" ");//$NON-NLS-1$ + } + } + printIndent(); + buffer.append("package ");//$NON-NLS-1$ + node.getName().accept(this); + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ParameterizedType node) { + node.getType().accept(this); + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ParenthesizedExpression node) { + buffer.append("(");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(")");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(PostfixExpression node) { + node.getOperand().accept(this); + buffer.append(node.getOperator().toString()); + return false; + } + + @Override + public boolean visit(PrefixExpression node) { + buffer.append(node.getOperator().toString()); + node.getOperand().accept(this); + return false; + } + + @Override + public boolean visit(PrimitiveType node) { + visitTypeAnnotations(node); + buffer.append(node.getPrimitiveTypeCode().toString()); + return false; + } + + @Override + public boolean visit(ProvidesDirective node) { + printIndent(); + buffer.append("provides");//$NON-NLS-1$ + buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + printTypes(node.implementations(), "with"); //$NON-NLS-1$ + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(QualifiedName node) { + node.getQualifier().accept(this); + buffer.append(".");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(QualifiedType node) { + node.getQualifier().accept(this); + buffer.append(".");//$NON-NLS-1$ + visitTypeAnnotations(node); + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(RequiresDirective node) { + printIndent(); + buffer.append("requires");//$NON-NLS-1$ + buffer.append(" ");//$NON-NLS-1$ + printModifiers(node.modifiers()); + node.getName().accept(this); + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(ReturnStatement node) { + printIndent(); + buffer.append("return");//$NON-NLS-1$ + if (node.getExpression() != null) { + buffer.append(" ");//$NON-NLS-1$ + node.getExpression().accept(this); + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + private boolean needToQualify(SimpleName node) { + if (node.getParent() instanceof QualifiedName || node.getParent() instanceof QualifiedType) { + return false; + } + return true; + } + @Override + public boolean visit(SimpleName node) { + IBinding binding = node.resolveBinding(); + // when having code like arr.length the length is identified as a field variable. But since the arr is + // already pushed as a variable we don't need to handle length here. So if we have chained field access like + // obj.f1.f2 we will only push the obj as a variable. + if (!isLocalBinding(binding) && !isParentInLocalBinding(node.getParent())) { + if (binding instanceof IVariableBinding) { + IVariableBinding vb = ((IVariableBinding) binding); + // For future optimization: Check for duplicates, so same value is only bound once + if (vb.isField()) { + if (Modifier.isStatic(vb.getModifiers())) { + if (needToQualify(node)) { + ITypeBinding declaringClass = vb.getDeclaringClass(); + buffer.append(declaringClass.getQualifiedName()); + buffer.append("."); //$NON-NLS-1$ + } + + buffer.append(node.getIdentifier()); + + } else { + // TODO: Fix this to use same method as visit(FieldAccess) + ITypeBinding declaringClass = vb.getDeclaringClass(); + String newVarName = allocateNewVariable(declaringClass, LOCAL_VAR_PREFIX.concat("this")); //$NON-NLS-1$ + binder.bindThis(declaringClass, newVarName); + // buffer.append("this."); //$NON-NLS-1$ + buffer.append(newVarName); + buffer.append("."); //$NON-NLS-1$ + buffer.append(node.getIdentifier()); + } + } else { + String newVarName = new String(LOCAL_VAR_PREFIX) + allocateNewVariable(vb.getType(), node.getIdentifier()); + binder.bind((IVariableBinding) binding, newVarName); + // buffer.append("this."); //$NON-NLS-1$ + buffer.append(newVarName); + } + return false; + } + } + + buffer.append(node.getIdentifier()); + return false; + } + + @Override + public boolean visit(SimpleType node) { + visitTypeAnnotations(node); + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + buffer.append("@");//$NON-NLS-1$ + node.getTypeName().accept(this); + buffer.append("(");//$NON-NLS-1$ + node.getValue().accept(this); + buffer.append(")");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(SingleVariableDeclaration node) { + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + if (node.getAST().apiLevel() >= JLS3) { + if (node.isVarargs()) { + if (node.getAST().apiLevel() >= JLS8) { + List annotations = node.varargsAnnotations(); + if (annotations.size() > 0) { + buffer.append(' '); + } + visitAnnotationsList(annotations); + } + buffer.append("...");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + int size = node.getExtraDimensions(); + if (node.getAST().apiLevel() >= JLS8) { + List dimensions = node.extraDimensions(); + for (int i = 0; i < size; i++) { + visit((Dimension) dimensions.get(i)); + } + } else { + for (int i = 0; i < size; i++) { + buffer.append("[]"); //$NON-NLS-1$ + } + } + if (node.getInitializer() != null) { + buffer.append("=");//$NON-NLS-1$ + node.getInitializer().accept(this); + } + return false; + } + + @Override + public boolean visit(StringLiteral node) { + buffer.append(node.getEscapedValue()); + return false; + } + + @Override + public boolean visit(SuperConstructorInvocation node) { + printIndent(); + if (node.getExpression() != null) { + node.getExpression().accept(this); + buffer.append(".");//$NON-NLS-1$ + } + if (node.getAST().apiLevel() >= JLS3) { + if (!node.typeArguments().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + } + buffer.append("super(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(");\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(SuperFieldAccess node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + buffer.append(".");//$NON-NLS-1$ + } + buffer.append("super.");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(SuperMethodInvocation node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + buffer.append(".");//$NON-NLS-1$ + } + buffer.append("super.");//$NON-NLS-1$ + if (node.getAST().apiLevel() >= JLS3) { + if (!node.typeArguments().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + } + node.getName().accept(this); + buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext();) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SuperMethodReference) + * + * @since 3.10 + */ + @Override + public boolean visit(SuperMethodReference node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + buffer.append('.'); + } + buffer.append("super");//$NON-NLS-1$ + visitReferenceTypeArguments(node.typeArguments()); + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(SwitchCase node) { + if ((node.getAST().isPreviewEnabled())) { + if (node.isDefault()) { + buffer.append("default");//$NON-NLS-1$ + buffer.append(node.isSwitchLabeledRule() ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$ + } else { + buffer.append("case ");//$NON-NLS-1$ + for (Iterator it = node.expressions().iterator(); it.hasNext();) { + Expression t = (Expression) it.next(); + t.accept(this); + buffer.append(it.hasNext() ? ", " : //$NON-NLS-1$ + node.isSwitchLabeledRule() ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$ + } + } + } else { + if (node.isDefault()) { + buffer.append("default :\n");//$NON-NLS-1$ + } else { + buffer.append("case ");//$NON-NLS-1$ + getSwitchExpression(node).accept(this); + buffer.append(":\n");//$NON-NLS-1$ + } + } + indent++; // decremented in visit(SwitchStatement) + return false; + } + + /** + * @deprecated + */ + @Deprecated + private Expression getSwitchExpression(SwitchCase node) { + return node.getExpression(); + } + + private void visitSwitchNode(ASTNode node) { + buffer.append("switch (");//$NON-NLS-1$ + if (node instanceof SwitchExpression) { + ((SwitchExpression) node).getExpression().accept(this); + } else if (node instanceof SwitchStatement) { + ((SwitchStatement) node).getExpression().accept(this); + } + buffer.append(") ");//$NON-NLS-1$ + buffer.append("{\n");//$NON-NLS-1$ + indent++; + if (node instanceof SwitchExpression) { + for (Iterator it = ((SwitchExpression) node).statements().iterator(); it.hasNext();) { + Statement s = (Statement) it.next(); + s.accept(this); + indent--; // incremented in visit(SwitchCase) + } + } else if (node instanceof SwitchStatement) { + for (Iterator it = ((SwitchStatement) node).statements().iterator(); it.hasNext();) { + Statement s = (Statement) it.next(); + s.accept(this); + indent--; // incremented in visit(SwitchCase) + } + } + indent--; + printIndent(); + buffer.append("}\n");//$NON-NLS-1$ + + } + + @Override + public boolean visit(SwitchExpression node) { + visitSwitchNode(node); + return false; + } + + @Override + public boolean visit(SwitchStatement node) { + visitSwitchNode(node); + return false; + } + + @Override + public boolean visit(SynchronizedStatement node) { + buffer.append("synchronized (");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(TagElement node) { + return false; + } + + @Override + public boolean visit(TextBlock node) { + buffer.append(node.getEscapedValue()); + return false; + } + + @Override + public boolean visit(TextElement node) { + buffer.append(node.getText()); + return false; + } + + @Override + public boolean visit(ThisExpression node) { + ITypeBinding thisType = node.resolveTypeBinding(); + + String newVarName = allocateNewVariable(thisType, LOCAL_VAR_PREFIX.concat("this")); //$NON-NLS-1$ + binder.bindThis(thisType, newVarName); + // buffer.append("this."); //$NON-NLS-1$ + buffer.append(newVarName); + return false; + } + + @Override + public boolean visit(ThrowStatement node) { + printIndent(); + buffer.append("throw ");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(TryStatement node) { + printIndent(); + buffer.append("try ");//$NON-NLS-1$ + if (node.getAST().apiLevel() >= JLS4) { + List resources = node.resources(); + if (!resources.isEmpty()) { + buffer.append('('); + for (Iterator it = resources.iterator(); it.hasNext();) { + Expression variable = (Expression) it.next(); + variable.accept(this); + if (it.hasNext()) { + buffer.append(';'); + } + } + buffer.append(')'); + } + } + node.getBody().accept(this); + buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.catchClauses().iterator(); it.hasNext();) { + CatchClause cc = (CatchClause) it.next(); + cc.accept(this); + } + if (node.getFinally() != null) { + buffer.append(" finally ");//$NON-NLS-1$ + node.getFinally().accept(this); + } + return false; + } + + @Override + public boolean visit(TypeDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + } + buffer.append(node.isInterface() ? "interface " : "class ");//$NON-NLS-2$//$NON-NLS-1$ + node.getName().accept(this); + if (node.getAST().apiLevel() >= JLS3) { + if (!node.typeParameters().isEmpty()) { + buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeParameters().iterator(); it.hasNext();) { + TypeParameter t = (TypeParameter) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(",");//$NON-NLS-1$ + } + } + buffer.append(">");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + if (node.getAST().apiLevel() == JLS2) { + if (getSuperclass(node) != null) { + buffer.append("extends ");//$NON-NLS-1$ + getSuperclass(node).accept(this); + buffer.append(" ");//$NON-NLS-1$ + } + if (!superInterfaces(node).isEmpty()) { + buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$ + for (Iterator it = superInterfaces(node).iterator(); it.hasNext();) { + Name n = (Name) it.next(); + n.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + } + } + if (node.getAST().apiLevel() >= JLS3) { + if (node.getSuperclassType() != null) { + buffer.append("extends ");//$NON-NLS-1$ + node.getSuperclassType().accept(this); + buffer.append(" ");//$NON-NLS-1$ + } + if (!node.superInterfaceTypes().isEmpty()) { + buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$ + for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(" ");//$NON-NLS-1$ + } + } + buffer.append("{\n");//$NON-NLS-1$ + indent++; + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext();) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + } + indent--; + printIndent(); + buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(TypeDeclarationStatement node) { + if (node.getAST().apiLevel() == JLS2) { + getTypeDeclaration(node).accept(this); + } + if (node.getAST().apiLevel() >= JLS3) { + node.getDeclaration().accept(this); + } + return false; + } + + @Override + public boolean visit(TypeLiteral node) { + node.getType().accept(this); + buffer.append(".class");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(TypeMethodReference) + * + * @since 3.10 + */ + @Override + public boolean visit(TypeMethodReference node) { + node.getType().accept(this); + visitReferenceTypeArguments(node.typeArguments()); + node.getName().accept(this); + return false; + } + + @Override + public boolean visit(TypeParameter node) { + if (node.getAST().apiLevel() >= JLS8) { + printModifiers(node.modifiers()); + } + node.getName().accept(this); + if (!node.typeBounds().isEmpty()) { + buffer.append(" extends ");//$NON-NLS-1$ + for (Iterator it = node.typeBounds().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append(" & ");//$NON-NLS-1$ + } + } + } + return false; + } + + @Override + public boolean visit(UnionType node) { + for (Iterator it = node.types().iterator(); it.hasNext();) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + buffer.append('|'); + } + } + return false; + } + + @Override + public boolean visit(UsesDirective node) { + printIndent(); + buffer.append("uses");//$NON-NLS-1$ + buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(VariableDeclarationExpression node) { + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.fragments().iterator(); it.hasNext();) { + VariableDeclarationFragment f = (VariableDeclarationFragment) it.next(); + f.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + return false; + } + + @Override + public boolean visit(VariableDeclarationFragment node) { + addLocalBinding(node.resolveBinding(), node.getName().getIdentifier()); + + buffer.append(node.getName().getIdentifier()); + int size = node.getExtraDimensions(); + if (node.getAST().apiLevel() >= JLS8) { + List dimensions = node.extraDimensions(); + for (int i = 0; i < size; i++) { + visit((Dimension) dimensions.get(i)); + } + } else { + for (int i = 0; i < size; i++) { + buffer.append("[]");//$NON-NLS-1$ + } + } + if (node.getInitializer() != null) { + buffer.append("=");//$NON-NLS-1$ + node.getInitializer().accept(this); + } + return false; + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.fragments().iterator(); it.hasNext();) { + VariableDeclarationFragment f = (VariableDeclarationFragment) it.next(); + f.accept(this); + if (it.hasNext()) { + buffer.append(", ");//$NON-NLS-1$ + } + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + @Override + public boolean visit(WhileStatement node) { + printIndent(); + buffer.append("while (");//$NON-NLS-1$ + node.getExpression().accept(this); + buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + @Override + public boolean visit(WildcardType node) { + visitTypeAnnotations(node); + buffer.append("?");//$NON-NLS-1$ + Type bound = node.getBound(); + if (bound != null) { + if (node.isUpperBound()) { + buffer.append(" extends ");//$NON-NLS-1$ + } else { + buffer.append(" super ");//$NON-NLS-1$ + } + bound.accept(this); + } + return false; + } + + @Override + public boolean visit(YieldStatement node) { + if ((node.getAST().isPreviewEnabled()) && node.isImplicit() && node.getExpression() == null) { + return false; + } + printIndent(); + buffer.append("yield"); //$NON-NLS-1$ + if (node.getExpression() != null) { + buffer.append(" ");//$NON-NLS-1$ + node.getExpression().accept(this); + } + buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /** + * @deprecated + */ + @Deprecated + private void visitComponentType(ArrayType node) { + node.getComponentType().accept(this); + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java new file mode 100644 index 0000000000..154fbff7c2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java @@ -0,0 +1,986 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Moller - Bugs 341232, 427089 + * Chris West (Faux) - Bug 45507 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventFilter; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.debug.core.IEvaluationRunnable; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; +import org.eclipse.jdt.debug.eval.ICompiledExpression; +import org.eclipse.jdt.debug.eval.IEvaluationListener; +import org.eclipse.jdt.debug.eval.IEvaluationResult; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.debug.core.JDIDebugOptions; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDILambdaVariable; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIReturnValueVariable; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIThisVariable; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; +import org.eclipse.jdt.internal.debug.core.model.LambdaUtils; +import org.eclipse.jdt.internal.debug.core.model.SyntheticVariableUtils; +import org.eclipse.jdt.internal.debug.eval.EvaluationResult; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence; + +import com.sun.jdi.InvocationException; +import com.sun.jdi.ObjectReference; + +@SuppressWarnings("restriction") +public class ASTEvaluationEngine implements IAstEvaluationEngine { + public static final String ANONYMOUS_VAR_PREFIX = "val$"; //$NON-NLS-1$ + private static final int EVALUATION_DETAIL_BITMASK = DebugEvent.EVALUATION | DebugEvent.EVALUATION_IMPLICIT; + private static final String QN_OBJECT = "java.lang.Object"; //$NON-NLS-1$ + private IJavaProject fProject; + + private IJavaDebugTarget fDebugTarget; + + /** + * Regex to find occurrences of 'this' in a code snippet + */ + private static Pattern fgThisPattern = Pattern + .compile("(.*[^a-zA-Z0-9]+|^)(this)([^a-zA-Z0-9]+|$).*"); //$NON-NLS-1$ + + /** + * Filters variable change events during an evaluation to avoid refreshing + * the variables view until done. + */ + class EventFilter implements IDebugEventFilter { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.IDebugEventFilter#filterDebugEvents(org.eclipse + * .debug.core.DebugEvent[]) + */ + @Override + public DebugEvent[] filterDebugEvents(DebugEvent[] events) { + if (events.length == 1) { + DebugEvent event = events[0]; + if (event.getSource() instanceof IJavaVariable + && event.getKind() == DebugEvent.CHANGE) { + if (((IJavaVariable) event.getSource()).getDebugTarget() + .equals(getDebugTarget())) { + return null; + } + } + } + return events; + } + + } + + public ASTEvaluationEngine(IJavaProject project, + IJavaDebugTarget debugTarget) { + setJavaProject(project); + setDebugTarget(debugTarget); + } + + public void setJavaProject(IJavaProject project) { + fProject = project; + } + + public void setDebugTarget(IJavaDebugTarget debugTarget) { + fDebugTarget = debugTarget; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IEvaluationEngine#evaluate(java.lang.String, + * org.eclipse.jdt.debug.core.IJavaStackFrame, + * org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + @Override + public void evaluate(String snippet, IJavaStackFrame frame, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException { + traceCaller(snippet, frame.getThread()); + ICompiledExpression expression = getCompiledExpression(snippet, frame); + evaluateExpression(expression, frame, listener, evaluationDetail, + hitBreakpoints); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IEvaluationEngine#evaluate(java.lang.String, + * org.eclipse.jdt.debug.core.IJavaObject, + * org.eclipse.jdt.debug.core.IJavaThread, + * org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + @Override + public void evaluate(String snippet, IJavaObject thisContext, + IJavaThread thread, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) throws DebugException { + traceCaller(snippet, thread); + ICompiledExpression expression = getCompiledExpression(snippet, + thisContext); + evaluateExpression(expression, thisContext, thread, listener, + evaluationDetail, hitBreakpoints); + } + + /** + * Writes a stack dump to trace the calling thread. + * + * @param snippet + * expression to evaluate + * @param thread + * thread to evaluate in + */ + private void traceCaller(String snippet, IThread thread) { + if (JDIDebugOptions.DEBUG_AST_EVAL_THREAD_TRACE) { + StringBuilder buf = new StringBuilder(); + buf.append(JDIDebugOptions.FORMAT.format(Instant.now())); + buf.append(" : Evaluation Request Trace - Expression: "); //$NON-NLS-1$ + buf.append(snippet); + buf.append("\n\tThread: "); //$NON-NLS-1$ + try { + String name = thread.getName(); + buf.append('['); + buf.append(name); + buf.append("] "); //$NON-NLS-1$ + } catch (DebugException e) { + buf.append(thread.toString()); + } + JDIDebugOptions.trace(buf.toString()); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IAstEvaluationEngine#evaluateExpression(org + * .eclipse.jdt.debug.eval.ICompiledExpression, + * org.eclipse.jdt.debug.core.IJavaStackFrame, + * org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + @Override + public void evaluateExpression(ICompiledExpression expression, + IJavaStackFrame frame, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) throws DebugException { + traceCaller(expression.getSnippet(), frame.getThread()); + RuntimeContext context = new RuntimeContext(getJavaProject(), frame); + doEvaluation(expression, context, (IJavaThread) frame.getThread(), + listener, evaluationDetail, hitBreakpoints); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IAstEvaluationEngine#evaluateExpression(org + * .eclipse.jdt.debug.eval.ICompiledExpression, + * org.eclipse.jdt.debug.core.IJavaObject, + * org.eclipse.jdt.debug.core.IJavaThread, + * org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + @Override + public void evaluateExpression(ICompiledExpression expression, + IJavaObject thisContext, IJavaThread thread, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException { + traceCaller(expression.getSnippet(), thread); + IRuntimeContext context = null; + if (thisContext instanceof IJavaArray) { + context = new ArrayRuntimeContext((IJavaArray) thisContext, thread, + getJavaProject()); + } else { + context = new JavaObjectRuntimeContext(thisContext, + getJavaProject(), thread); + } + doEvaluation(expression, context, thread, listener, evaluationDetail, + hitBreakpoints); + } + + /** + * Evaluates the given expression in the given thread and the given runtime + * context. + */ + private void doEvaluation(ICompiledExpression expression, + IRuntimeContext context, IJavaThread thread, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException { + if (expression instanceof InstructionSequence) { + // don't queue explicit evaluation if the thread is all ready + // performing an evaluation. + if (thread.isSuspended() && ((JDIThread) thread).isInvokingMethod() + || thread.isPerformingEvaluation() + && evaluationDetail == DebugEvent.EVALUATION) { + EvaluationResult result = new EvaluationResult(this, + expression.getSnippet(), thread); + result.addError(EvaluationEngineMessages.ASTEvaluationEngine_Cannot_perform_nested_evaluations); + listener.evaluationComplete(result); + return; + } + thread.queueRunnable(new EvalRunnable( + (InstructionSequence) expression, thread, context, + listener, evaluationDetail, hitBreakpoints)); + } else { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + EvaluationEngineMessages.ASTEvaluationEngine_AST_evaluation_engine_cannot_evaluate_expression, + null)); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression + * (java.lang.String, org.eclipse.jdt.debug.core.IJavaStackFrame) + */ + @Override + public ICompiledExpression getCompiledExpression(String snippet, + IJavaStackFrame frame) { + IJavaProject javaProject = getJavaProject(); + RuntimeContext context = new RuntimeContext(javaProject, frame); + + EvaluationSourceGenerator mapper = null; + CompilationUnit unit = null; + try { + List localsVar = new ArrayList<>(); + localsVar.addAll(Arrays.asList(context.getLocals())); + IJavaObject thisClass = context.getThis(); + IVariable[] innerClassFields; // For anonymous classes, getting variables from outer class + if (null != thisClass) { + innerClassFields = extractVariables(thisClass); + } else { + innerClassFields = new IVariable[0]; + } + List lambdaFrameVariables = LambdaUtils.getLambdaFrameVariables(frame); + int numLocalsVar = localsVar.size(); + Set names = new HashSet<>(); + // ****** + // to hide problems with local variable declare as instance of Local + // Types + // and to remove locals with duplicate names + // IJavaVariable[] locals = new IJavaVariable[numLocalsVar]; + IJavaVariable[] locals = new IJavaVariable[numLocalsVar + innerClassFields.length + lambdaFrameVariables.size()]; + String[] localVariablesWithNull = new String[numLocalsVar + innerClassFields.length + lambdaFrameVariables.size()]; + int numLocals = 0; + for (int i = 0; i < numLocalsVar; i++) { + IJavaVariable variable = localsVar.get(i); + if (!isLocalType(variable.getSignature()) && !names.contains(variable.getName())) { + locals[numLocals] = variable; + names.add(variable.getName()); + localVariablesWithNull[numLocals++] = variable.getName(); + } + } + /* + * If we are in a lambda frame, the variable context is not complete; names of outer-scope variables are mangled by the compiler. So we + * check variables one stack frame above the lambda frames, in order to also include outer-scope variables. This is necessary to use local + * variables defined in a method, within a breakpoint condition inside a lambda also defined in that method. + */ + for (IVariable variable : lambdaFrameVariables) { + if (variable instanceof IJavaVariable && !isLambdaOrImplicitVariable(variable)) { + IJavaVariable javaVariable = (IJavaVariable) variable; + final boolean lambdaField = LambdaUtils.isLambdaField(variable); + String name = variable.getName(); + String variableName = (lambdaField && name.startsWith(ANONYMOUS_VAR_PREFIX)) ? name.substring(ANONYMOUS_VAR_PREFIX.length()) : name; + if (variableName != null && (!variableName.contains("$") || lambdaField)) { //$NON-NLS-1$ + if (!isLocalType(javaVariable.getSignature()) && !names.contains(variableName)) { + locals[numLocals] = javaVariable; + names.add(variableName); + localVariablesWithNull[numLocals++] = variableName; + } + } + } + } + // Adding outer class variables to inner class scope + for (IVariable var : innerClassFields) { + if (var instanceof IJavaVariable && var.getName().startsWith(ANONYMOUS_VAR_PREFIX)) { + String name = var.getName().substring(ANONYMOUS_VAR_PREFIX.length()); + if (!names.contains(name)) { + locals[numLocals] = (IJavaVariable) var; + names.add(name); + localVariablesWithNull[numLocals++] = name; + } + } + } + // to solve and remove + // ****** + String[] localTypesNames = new String[numLocals]; + for (int i = 0; i < numLocals; i++) { + localTypesNames[i] = getFixedUnresolvableGenericTypes(locals[i]); + } + // Copying local variables removing the nulls in the last + // String[] localVariables = Arrays.clonesub(localVariablesWithNull, names.size()); + String[] localVariables = new String[names.size()]; + System.arraycopy(localVariablesWithNull, 0, localVariables, 0, localVariables.length); + mapper = new EvaluationSourceGenerator(localTypesNames, + localVariables, snippet, getJavaProject()); + // Compile in context of declaring type to get proper visibility of + // locals and members. + // Compiling in context of receiving type potentially provides + // access to more members, + // but does not allow access to privates members in declaring type + IJavaReferenceType receivingType = frame.getReferenceType(); + + // currently disabled - see bugs 99416 and 106492 + // if (frame.isStatic()) { + // receivingType= frame.getReferenceType(); + // } else { + // receivingType= (IJavaReferenceType) + // frame.getThis().getJavaType(); + // } + + Map extraOptions = Collections.emptyMap(); + // if target runtime is above java 1.8 then switch the compiler to debug mode to ignore java 9 module system + if (JavaCore.compareJavaVersions(((IJavaDebugTarget) frame.getDebugTarget()).getVersion(), JavaCore.VERSION_1_8) > 0) { + extraOptions = Collections.singletonMap(CompilerOptions.OPTION_IgnoreUnnamedModuleForSplitPackage, JavaCore.ENABLED); + } + + unit = parseCompilationUnit( + mapper.getSource(receivingType, frame.getLineNumber(), javaProject, + frame.isStatic()).toCharArray(), + mapper.getCompilationUnitName(), javaProject, extraOptions); + } catch (CoreException e) { + InstructionSequence expression = new InstructionSequence(snippet); + expression.addError(e.getStatus().getMessage()); + return expression; + } + + return createExpressionFromAST(snippet, mapper, unit); + } + + private IVariable[] extractVariables(IJavaObject thisClass) throws DebugException { + IVariable[] vars = thisClass.getVariables(); + List varList = new ArrayList<>(Arrays.asList(vars)); + varList.addAll(Arrays.asList(SyntheticVariableUtils.findSyntheticVariables(vars))); + return varList.toArray(new IVariable[0]); + } + + private String getFixedUnresolvableGenericTypes(IJavaVariable variable) throws DebugException { + StringBuilder fixedSignature = new StringBuilder(); + scanAndFixSignature(variable.getGenericSignature(), Signature.toString(variable.getSignature()), fixedSignature); + return fixedSignature.toString(); + } + + private void scanAndFixSignature(String genericSignature, String erasureSignature, StringBuilder fixedSignature) { + /* + * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current context. + * For example variable type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate) + * + * and also generic signature such as Ljava/util/function/Predicate<+Ljava/util/List;>; Ljava/util/Comparator<-TT;>; + * which will fail to properly resolved to the type. + */ + if (genericSignature.startsWith(String.valueOf(Signature.C_TYPE_VARIABLE)) || + genericSignature.startsWith(String.valueOf(Signature.C_CAPTURE)) || + genericSignature.startsWith(String.valueOf(Signature.C_SUPER))) + { + fixedSignature.append(toDotQualified(erasureSignature)); + return; + } + + if(genericSignature.startsWith(String.valueOf(Signature.C_EXTENDS))) { + fixedSignature.append(toDotQualified(Signature.toString(getUpperBoundTypeSignature(genericSignature)))); + return; + } + + // we have a proper type which might be parameterized so extract the type FQN + fixedSignature.append(toDotQualified(Signature.toString(Signature.getTypeErasure(genericSignature)))); + + String[] typeArguments = Signature.getTypeArguments(genericSignature); + if (typeArguments.length > 0) { + if (typeArguments.length == 1 && + (typeArguments[0].equals(String.valueOf(Signature.C_STAR)) || + typeArguments[0].startsWith(String.valueOf(new char[] { Signature.C_EXTENDS, Signature.C_TYPE_VARIABLE })))) { + // this is when we have recursive generics or we have a upper bound type variable + // so remove the generics to avoid compilation issues. + return; + } + + fixedSignature.append(Signature.C_GENERIC_START); + for (int i = 0; i < typeArguments.length; i++) { + if (i > 0) { + fixedSignature.append(','); + } + scanAndFixSignature(typeArguments[i], QN_OBJECT, fixedSignature); + } + fixedSignature.append(Signature.C_GENERIC_END); + } + } + + private String toDotQualified(String fqn) { + return fqn.replace('/', '.'); + } + + private String getUpperBoundTypeSignature(String typeParamaterSignature) { + // +Ljava/util/List; + return String.valueOf(getBoudTypeParameterSignature(typeParamaterSignature.toCharArray(), Signature.C_EXTENDS)); + } + + private char[] getBoudTypeParameterSignature(char[] typeParamaterSignature, char boundType) { + if (typeParamaterSignature.length < 2 || typeParamaterSignature[0] != boundType) { + throw new IllegalArgumentException(Signature.toString(String.valueOf(typeParamaterSignature))); + } + return CharOperation.subarray(typeParamaterSignature, 1, typeParamaterSignature.length); + } + + private CompilationUnit parseCompilationUnit(char[] source, + String unitName, IJavaProject project) { + return parseCompilationUnit(source, unitName, project, Collections.EMPTY_MAP); + } + + private CompilationUnit parseCompilationUnit(char[] source, + String unitName, IJavaProject project, Map extraCompileOptions) { + ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); + parser.setSource(source); + parser.setUnitName(unitName); + parser.setProject(project); + parser.setResolveBindings(true); + Map options = EvaluationSourceGenerator + .getCompilerOptions(project); + options = new LinkedHashMap<>(options); + for (Entry extraCompileOption : extraCompileOptions.entrySet()) { + options.put(extraCompileOption.getKey(), extraCompileOption.getValue()); + } + parser.setCompilerOptions(options); + return (CompilationUnit) parser.createAST(null); + } + + // ****** + // to hide problems with local variable declare as instance of Local Types + private boolean isLocalType(String typeName) { + StringTokenizer strTok = new StringTokenizer(typeName, "$"); //$NON-NLS-1$ + strTok.nextToken(); + while (strTok.hasMoreTokens()) { + char char0 = strTok.nextToken().charAt(0); + if ('0' <= char0 && char0 <= '9') { + return true; + } + } + return false; + } + + // ****** + + /** + * Returns a compiled expression for an evaluation in the context of an + * array as a receiver. + */ + private ICompiledExpression getCompiledExpression(String snippet, + IJavaArrayType arrayType) { + EvaluationSourceGenerator mapper = null; + CompilationUnit unit = null; + try { + IJavaProject javaProject = getJavaProject(); + // replace all occurrences of 'this' with '_a_t' + String newSnippet = replaceThisReferences(snippet); + + int dimension = 1; + IJavaType componentType = arrayType.getComponentType(); + while (componentType instanceof IJavaArrayType) { + componentType = ((IJavaArrayType) componentType) + .getComponentType(); + dimension++; + } + + // Primitive arrays are evaluated in the context of Object. + // Arrays with a base component type of a class or interface are + // treated + // as Object arrays and evaluated in Object. + String recTypeName = QN_OBJECT; + String typeName = arrayType.getName(); + if (componentType instanceof IJavaReferenceType) { + StringBuilder buf = new StringBuilder(); + buf.append(QN_OBJECT); + for (int i = 0; i < dimension; i++) { + buf.append("[]"); //$NON-NLS-1$ + } + typeName = buf.toString(); + } + + String[] localTypesNames = new String[] { typeName }; + String[] localVariables = new String[] { ArrayRuntimeContext.ARRAY_THIS_VARIABLE }; + mapper = new EvaluationSourceGenerator(localTypesNames, + localVariables, newSnippet, getJavaProject()); + + int index = typeName.indexOf('$'); + // if the argument is an inner type, compile in context of outer + // type so type is visible + if (index >= 0) { + recTypeName = typeName.substring(0, index); + } + IJavaType[] javaTypes = getDebugTarget().getJavaTypes(recTypeName); + if (javaTypes.length > 0) { + IJavaReferenceType recType = (IJavaReferenceType) javaTypes[0]; + unit = parseCompilationUnit( + mapper.getSource(recType, -1, getJavaProject(), false) + .toCharArray(), + mapper.getCompilationUnitName(), javaProject); + } else { + IStatus status = new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.ERROR, + EvaluationEngineMessages.ASTEvaluationEngine_1, null); + throw new CoreException(status); + } + } catch (CoreException e) { + InstructionSequence expression = new InstructionSequence(snippet); + expression.addError(e.getStatus().getMessage()); + return expression; + } + + return createExpressionFromAST(snippet, mapper, unit); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression + * (java.lang.String, org.eclipse.jdt.debug.core.IJavaObject) + */ + @Override + public ICompiledExpression getCompiledExpression(String snippet, + IJavaObject thisContext) { + try { + if (thisContext instanceof IJavaArray) { + return getCompiledExpression(snippet, + (IJavaArrayType) thisContext.getJavaType()); + } + return getCompiledExpression(snippet, + (IJavaReferenceType) thisContext.getJavaType()); + } catch (DebugException e) { + InstructionSequence expression = new InstructionSequence(snippet); + expression.addError(e.getStatus().getMessage()); + return expression; + } + + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression + * (java.lang.String, org.eclipse.jdt.debug.core.IJavaType) + */ + @Override + public ICompiledExpression getCompiledExpression(String snippet, + IJavaReferenceType type) { + return getCompiledExpression(snippet, type, Collections.EMPTY_MAP); + } + + @Override + public ICompiledExpression getCompiledExpression(String snippet, + IJavaReferenceType type, Map compileOptions) { + if (type instanceof IJavaArrayType) { + return getCompiledExpression(snippet, (IJavaArrayType) type); + } + IJavaProject javaProject = getJavaProject(); + + EvaluationSourceGenerator mapper = null; + CompilationUnit unit = null; + + mapper = new EvaluationSourceGenerator(new String[0], new String[0], + snippet, getJavaProject()); + + try { + unit = parseCompilationUnit( + mapper.getSource(type, -1, javaProject, false).toCharArray(), + mapper.getCompilationUnitName(), javaProject, compileOptions); + } catch (CoreException e) { + InstructionSequence expression = new InstructionSequence(snippet); + expression.addError(e.getStatus().getMessage()); + return expression; + } + return createExpressionFromAST(snippet, mapper, unit); + } + + /** + * Creates a compiled expression for the given snippet using the given + * mapper and compilation unit (AST). + * + * @param snippet + * the code snippet to be compiled + * @param mapper + * the object which will be used to create the expression + * @param unit + * the compilation unit (AST) generated for the snippet + */ + private ICompiledExpression createExpressionFromAST(String snippet, + EvaluationSourceGenerator mapper, CompilationUnit unit) { + IProblem[] problems = unit.getProblems(); + if (problems.length != 0) { + boolean snippetError = false; + boolean runMethodError = false; + InstructionSequence errorSequence = new InstructionSequence(snippet); + int codeSnippetStart = mapper.getSnippetStart(); + int codeSnippetEnd = codeSnippetStart + + mapper.getSnippet().length(); + int runMethodStart = mapper.getRunMethodStart(); + int runMethodEnd = runMethodStart + mapper.getRunMethodLength(); + for (IProblem problem : problems) { + int errorOffset = problem.getSourceStart(); + int problemId = problem.getID(); + if (problemId == IProblem.IsClassPathCorrect) { + errorSequence.addError(problem.getMessage()); + snippetError = true; + } + if (problemId == IProblem.VoidMethodReturnsValue + || problemId == IProblem.NotVisibleMethod + || problemId == IProblem.NotVisibleConstructor + || problemId == IProblem.NotVisibleField + || problemId == IProblem.NotVisibleType + || problemId == IProblem.UnexpectedStaticModifierForMethod) { + continue; + } + if (problem.isError()) { + if (codeSnippetStart <= errorOffset + && errorOffset <= codeSnippetEnd) { + errorSequence.addError(problem.getMessage()); + snippetError = true; + } else if (runMethodStart <= errorOffset + && errorOffset <= runMethodEnd) { + runMethodError = true; + DebugPlugin.log(new Status(IStatus.WARNING, DebugPlugin.getUniqueIdentifier(), "Compile error during code evaluation: " //$NON-NLS-1$ + + problem.getMessage())); + } + } + } + if (snippetError || runMethodError) { + if (runMethodError) { + errorSequence + .addError(EvaluationEngineMessages.ASTEvaluationEngine_Evaluations_must_contain_either_an_expression_or_a_block_of_well_formed_statements_1); + } + return errorSequence; + } + } + + ASTInstructionCompiler visitor = new ASTInstructionCompiler( + mapper.getSnippetStart(), snippet, getJavaProject()); + unit.accept(visitor); + + return visitor.getInstructions(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#getJavaProject() + */ + @Override + public IJavaProject getJavaProject() { + return fProject; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#getDebugTarget() + */ + @Override + public IJavaDebugTarget getDebugTarget() { + return fDebugTarget; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#dispose() + */ + @Override + public void dispose() { + } + + class EvalRunnable implements Runnable { + + private final InstructionSequence fExpression; + + private final IJavaThread fThread; + + private final int fEvaluationDetail; + + private final boolean fHitBreakpoints; + + private final IRuntimeContext fContext; + + private final IEvaluationListener fListener; + + private final boolean fDisableGcOnResult; + + public EvalRunnable(InstructionSequence expression, IJavaThread thread, + IRuntimeContext context, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) { + fExpression = expression; + fThread = thread; + fContext = context; + fListener = listener; + fEvaluationDetail = (evaluationDetail & EVALUATION_DETAIL_BITMASK); + fHitBreakpoints = hitBreakpoints; + fDisableGcOnResult = (evaluationDetail & IAstEvaluationEngine.DISABLE_GC_ON_RESULT) != 0; + } + + @Override + public void run() { + if (JDIDebugOptions.DEBUG_AST_EVAL) { + StringBuilder buf = new StringBuilder(); + buf.append(JDIDebugOptions.FORMAT.format(Instant.now())); + buf.append(" : AST Evaluation"); //$NON-NLS-1$ + buf.append("\n\tExpression: "); //$NON-NLS-1$ + buf.append(fExpression.getSnippet()); + buf.append("\n\tThread: "); //$NON-NLS-1$ + try { + String name = fThread.getName(); + buf.append('['); + buf.append(name); + buf.append("] "); //$NON-NLS-1$ + } catch (DebugException e) { + } + buf.append(fThread.toString()); + buf.append("\n\tDetail: "); //$NON-NLS-1$ + if (fEvaluationDetail == DebugEvent.EVALUATION) { + buf.append("EVALUATION"); //$NON-NLS-1$ + } else if (fEvaluationDetail == DebugEvent.EVALUATION_IMPLICIT) { + buf.append("EVALUATION_IMPLICIT"); //$NON-NLS-1$ + } else { + buf.append(fEvaluationDetail); + } + buf.append(" Hit Breakpoints: "); //$NON-NLS-1$ + buf.append(fHitBreakpoints); + JDIDebugOptions.trace(buf.toString()); + } + EvaluationResult result = new EvaluationResult( + ASTEvaluationEngine.this, fExpression.getSnippet(), fThread); + if (fExpression.hasErrors()) { + String[] errors = fExpression.getErrorMessages(); + for (String error : errors) { + result.addError(error); + } + evaluationFinished(result); + if (JDIDebugOptions.DEBUG_AST_EVAL) { + StringBuilder buf = new StringBuilder(); + buf.append("\tErrors: "); //$NON-NLS-1$ + for (int i = 0; i < errors.length; i++) { + if (i > 0) { + buf.append('\n'); + } + buf.append("\t\t"); //$NON-NLS-1$ + buf.append(errors[i]); + } + JDIDebugOptions.trace(buf.toString()); + } + return; + } + final Interpreter interpreter = new Interpreter(fExpression, + fContext); + + class EvaluationRunnable implements IEvaluationRunnable, ITerminate { + + CoreException fException; + boolean fTerminated = false; + + @Override + public void run(IJavaThread jt, IProgressMonitor pm) { + EventFilter filter = new EventFilter(); + try { + DebugPlugin.getDefault().addDebugEventFilter(filter); + interpreter.execute(fDisableGcOnResult); + } catch (CoreException exception) { + fException = exception; + if (fEvaluationDetail == DebugEvent.EVALUATION + && exception.getStatus().getException() instanceof InvocationException) { + // print the stack trace for the exception if an + // *explicit* evaluation + InvocationException invocationException = (InvocationException) exception + .getStatus().getException(); + ObjectReference exObject = invocationException + .exception(); + IJavaObject modelObject = (IJavaObject) JDIValue + .createValue( + (JDIDebugTarget) getDebugTarget(), + exObject); + try { + modelObject + .sendMessage( + "printStackTrace", "()V", null, jt, false); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (DebugException e) { + // unable to print stack trace + } + } + } finally { + DebugPlugin.getDefault().removeDebugEventFilter(filter); + } + } + + @Override + public void terminate() { + fTerminated = true; + interpreter.stop(); + } + + @Override + public boolean canTerminate() { + return true; + } + + @Override + public boolean isTerminated() { + return false; + } + + public CoreException getException() { + return fException; + } + } + + EvaluationRunnable er = new EvaluationRunnable(); + CoreException exception = null; + long start = System.currentTimeMillis(); + try { + fThread.runEvaluation(er, null, fEvaluationDetail, + fHitBreakpoints); + } catch (DebugException e) { + exception = e; + } + long end = System.currentTimeMillis(); + + IJavaValue value = interpreter.getResult(); + + if (exception == null) { + exception = er.getException(); + } + + result.setTerminated(er.fTerminated); + if (exception != null) { + if (JDIDebugOptions.DEBUG_AST_EVAL) { + StringBuilder buf = new StringBuilder(); + buf.append("\tException: "); //$NON-NLS-1$ + buf.append(exception.toString()); + JDIDebugOptions.trace(buf.toString()); + } + if (exception instanceof DebugException) { + result.setException((DebugException) exception); + } else { + result.setException(new DebugException(exception + .getStatus())); + } + } else { + if (value != null) { + result.setValue(value); + if (JDIDebugOptions.DEBUG_AST_EVAL) { + StringBuilder buf = new StringBuilder(); + buf.append("\tResult: "); //$NON-NLS-1$ + buf.append(value); + JDIDebugOptions.trace(buf.toString()); + } + } else { + result.addError(EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation); + } + } + + if (JDIDebugOptions.DEBUG_AST_EVAL) { + StringBuilder buf = new StringBuilder(); + buf.append("\tDuration: "); //$NON-NLS-1$ + buf.append(end - start); + buf.append("ms"); //$NON-NLS-1$ + JDIDebugOptions.trace(buf.toString()); + } + + evaluationFinished(result); + } + + private void evaluationFinished(IEvaluationResult result) { + // only notify if plug-in not yet shutdown - bug# 8693 + if (JDIDebugPlugin.getDefault() != null) { + fListener.evaluationComplete(result); + } + } + + } + + /** + * Replaces references to 'this' with the 'array_this' variable. + * + * @param snippet + * code snippet + * @return snippet with 'this' references replaced + */ + public static String replaceThisReferences(String snippet) { + // replace all occurrences of 'this' with 'array_this' + StringBuilder updatedSnippet = new StringBuilder(); + Matcher matcher = fgThisPattern.matcher(snippet); + int start = 0; + while (matcher.find()) { + int end = matcher.start(2); + updatedSnippet.append(snippet.substring(start, end)); + updatedSnippet.append(ArrayRuntimeContext.ARRAY_THIS_VARIABLE); + start = end + 4; + } + if (start < snippet.length()) { + updatedSnippet.append(snippet.substring(start, snippet.length())); + } + return updatedSnippet.toString(); + } + + private static boolean isLambdaOrImplicitVariable(IVariable variable) { + boolean isLambdaOrImplicitVariable = variable instanceof JDILambdaVariable || variable instanceof JDIReturnValueVariable + || variable instanceof JDIThisVariable; + return isLambdaOrImplicitVariable; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java new file mode 100644 index 0000000000..09376e00ed --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java @@ -0,0 +1,4759 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Moller - Bug 427089 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.EmptyStackException; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.*; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.eval.ExpressionBinder; +import org.eclipse.jdt.internal.debug.eval.RemoteEvaluator; +import org.eclipse.jdt.internal.debug.eval.RemoteEvaluatorBuilder; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.AndAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.AndOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAllocation; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayInitializerInstruction; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.AssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Cast; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.CompoundInstruction; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.ConditionalJump; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Constructor; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.DivideAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.DivideOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Dup; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.DupX1; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.EqualEqualOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.GreaterEqualOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.GreaterOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstanceOfOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Jump; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.LeftShiftAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.LeftShiftOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.LessEqualOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.LessOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.LocalVariableCreation; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.MinusAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.MinusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.MultiplyAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.MultiplyOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.NoOp; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.NotOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.OrAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.OrOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PlusAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PlusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Pop; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PostfixMinusMinusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PostfixPlusPlusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PrefixMinusMinusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PrefixPlusPlusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushArrayLength; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushArrayType; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushBoolean; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushChar; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushClassLiteralValue; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushDouble; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushFieldVariable; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushFloat; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushInt; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushLocalVariable; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushLong; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushNull; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushPrimitiveType; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushStaticFieldVariable; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushString; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushThis; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.PushType; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemainderAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemainderOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.RemoteOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.ReturnInstruction; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.RightShiftAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.RightShiftOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.SendMessage; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.SendStaticMessage; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.ThrowInstruction; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.TwiddleOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnaryMinusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnaryPlusOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnsignedRightShiftAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.UnsignedRightShiftOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Value; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.XorAssignmentOperator; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.XorOperator; +import org.eclipse.osgi.util.NLS; + + +/** + * The AST instruction compiler generates a sequence of instructions + * (InstructionSequence) from a DOM AST. + */ +public class ASTInstructionCompiler extends ASTVisitor { + + /** + * Represent a break or a continue instruction. These instructions needs are + * stored and managed later by their related statement. + */ + static class CompleteInstruction { + Jump fInstruction; + String fLabel; + boolean fIsBreak; + + public CompleteInstruction(Jump instruction, String label, + boolean isBreak) { + fInstruction = instruction; + fLabel = label; + fIsBreak = isBreak; + } + } + + /** + * Whether to print debug messages to the console + */ + private static boolean VERBOSE = false; + + private final InstructionSequence fInstructions; + + /** + * The list of pending break and continue instruction. + */ + private final List fCompleteInstructions; + + private final int fStartPosition; + + private boolean fActive; + + private boolean fHasErrors; + + private final Stack fStack; + + private int fCounter; + + // internal index used to create unique variable name + private int fUniqueIdIndex = 0; + + private final IJavaProject fJavaProject; + + /** + * Create a new AST instruction compiler + */ + public ASTInstructionCompiler(int startPosition, String snippet, IJavaProject javaProject) { + fStartPosition = startPosition; + fInstructions = new InstructionSequence(snippet); + fStack = new Stack<>(); + fCompleteInstructions = new ArrayList<>(); + fJavaProject = javaProject; + } + + /** + * Returns the instruction sequence generated by this AST instruction + * compiler + */ + public InstructionSequence getInstructions() { + return fInstructions; + } + + /** + * Returns whether the generated instruction sequence has errors. Errors + * include: + *
    + *
  1. AST contains unimplemented operations (features which will be + * supported, but aren't yet)
  2. + *
  3. AST contains unsupported operations (features which are not yet + * implemented and are likely NOT to be implemented)
  4. + *
+ */ + public boolean hasErrors() { + return fHasErrors; + } + + private void setHasError(boolean value) { + fHasErrors = value; + } + + private void addErrorMessage(String message) { + fInstructions.addError(message); + } + + private boolean isActive() { + return fActive; + } + + private void setActive(boolean active) { + fActive = active; + } + + private void push(Instruction i) { + fStack.push(i); + } + + private void storeInstruction() { + Instruction instruction = null; + try { + instruction = fStack.pop(); + } + catch(EmptyStackException ese) { + JDIDebugPlugin.log(new Status( + IStatus.WARNING, + JDIDebugPlugin.getUniqueIdentifier(), + NLS.bind(EvaluationEngineMessages.ASTInstructionCompiler_4, fCounter), + ese)); + } + if(instruction != null) { + fCounter++; + if (instruction instanceof CompoundInstruction) { + ((CompoundInstruction) instruction).setEnd(fCounter); + } + fInstructions.add(instruction); + //System.out.println("Added: " + instruction.toString()); //$NON-NLS-1$ + verbose("Add " + instruction.toString()); //$NON-NLS-1$ + } + } + + /** + * Prints the given message to the console if verbose mode is on. + * + * @param message + * the message to display + */ + private void verbose(String message) { + if (VERBOSE) { + System.out.println(message); + } + } + + private String getTypeName(ITypeBinding typeBinding) { + if (typeBinding.isRawType()) { + typeBinding = typeBinding.getErasure(); + } + if (typeBinding.isTypeVariable()) { + ITypeBinding[] typeBounds = typeBinding.getTypeBounds(); + if (typeBounds.length > 0) { + String name = getTypeName(typeBounds[0]); + if (typeBounds.length > 1 && "java.lang.Object".equals(name)) { //$NON-NLS-1$ + return getTypeName(typeBounds[1]); + } + return name; + } + return "java.lang.Object"; //$NON-NLS-1$ + } + StringBuilder name; + if (typeBinding.isArray()) { + name = new StringBuilder(getTypeName(typeBinding.getElementType())); + int dimensions = typeBinding.getDimensions(); + for (int i = 0; i < dimensions; i++) { + name.append("[]"); //$NON-NLS-1$ + } + return name.toString(); + } + //try it the old way + name = new StringBuilder(Signature.getTypeErasure(typeBinding.getName())); + IPackageBinding packageBinding = typeBinding.getPackage(); + typeBinding = typeBinding.getDeclaringClass(); + while (typeBinding != null) { + name.insert(0, '$').insert(0, Signature.getTypeErasure(typeBinding.getName())); + typeBinding = typeBinding.getDeclaringClass(); + } + if (packageBinding != null && !packageBinding.isUnnamed()) { + name.insert(0, '.').insert(0, packageBinding.getName()); + } + return name.toString(); + } + + private String getTypeSignature(ITypeBinding typeBinding) { + return Signature.createTypeSignature(getTypeName(typeBinding), true) + .replace('.', '/'); + } + + private boolean isALocalType(ITypeBinding typeBinding) { + while (typeBinding != null) { + if (typeBinding.isLocal()) { + return true; + } + typeBinding = typeBinding.getDeclaringClass(); + } + return false; + } + + private boolean containsALocalType(IMethodBinding methodBinding) { + ITypeBinding[] typeBindings = methodBinding.getParameterTypes(); + for (ITypeBinding typeBinding : typeBindings) { + if (isALocalType(typeBinding)) { + return true; + } + } + return false; + } + + private int getEnclosingLevel(ASTNode node, + ITypeBinding referenceTypeBinding) { + ASTNode parent = node; + ITypeBinding refbinding = referenceTypeBinding.isParameterizedType() ? referenceTypeBinding + .getTypeDeclaration() : referenceTypeBinding; + do { + parent = parent.getParent(); + } while (parent != null + && !(parent instanceof AbstractTypeDeclaration || parent instanceof AnonymousClassDeclaration)); + if (parent == null) { + return 0; + } + ITypeBinding parentBinding = null; + if (parent instanceof AbstractTypeDeclaration) { + parentBinding = ((AbstractTypeDeclaration) parent).resolveBinding(); + } else if (parent instanceof AnonymousClassDeclaration) { + parentBinding = ((AnonymousClassDeclaration) parent) + .resolveBinding(); + } + if (parentBinding != null + && (parentBinding.isEqualTo(refbinding) || parentBinding + .isCastCompatible(refbinding))) { + return 0; + } + return getEnclosingLevel(parent, referenceTypeBinding) + 1; + } + + private int getSuperLevel(ITypeBinding current, ITypeBinding reference) { + if (current.equals(reference)) { + return 0; + } + return getSuperLevel(current.getSuperclass(), reference); + } + + /** + * Return the label associated with the given statement. + * + * @param statement + * the statement. + * @return the associated label, or null if there is none. + */ + private String getLabel(Statement statement) { + ASTNode parent = statement.getParent(); + if (parent instanceof LabeledStatement) { + return ((LabeledStatement) parent).getLabel().getIdentifier(); + } + return null; + } + + /** + * Append a pop instruction in the instruction list if needed. A pop + * instruction is added when the expression has a return value, i.e. all + * expressions expect method invocation expressions which have + * void as return type and variable declaration expression. + * + * @param expression + * the expression to test. + */ + private void addPopInstructionIfNeeded(Expression expression) { + boolean pop = true; + + if (expression instanceof MethodInvocation) { + IMethodBinding methodBinding = (IMethodBinding) ((MethodInvocation) expression) + .getName().resolveBinding(); + if (methodBinding != null + && "void".equals(methodBinding.getReturnType().getName())) { //$NON-NLS-1$ + pop = false; + } + } else if (expression instanceof SuperMethodInvocation) { + IMethodBinding methodBinding = (IMethodBinding) ((SuperMethodInvocation) expression) + .getName().resolveBinding(); + if (methodBinding != null + && "void".equals(methodBinding.getReturnType().getName())) { //$NON-NLS-1$ + pop = false; + } + } else if (expression instanceof VariableDeclarationExpression) { + pop = false; + } + + if (pop) { + addPopInstruction(); + } + } + + /** + * + */ + private void addPopInstruction() { + Instruction lastInstruction = fInstructions + .getInstruction(fInstructions.getEnd()); + push(new Pop(lastInstruction.getSize() + 1)); + storeInstruction(); + } + + /** + * Check the current type of a value and the requested type to decide if + * boxing/un-boxing is required. If needed, the correct instruction is added + * to the stack Returns true if a storeInstruction() is needed after + * visiting the expression + */ + private boolean checkAutoBoxing(ITypeBinding valueBinding, + ITypeBinding requestedBinding) { + if (valueBinding == null) { + return false; // unresolved + } + if (valueBinding.isPrimitive() == requestedBinding.isPrimitive()) { + return false; + } + if (requestedBinding.isPrimitive()) { + unBoxing(valueBinding); + } else { + boxing(requestedBinding, valueBinding); + } + return true; + } + + /** + * Add to the stack the instruction to box a primitive value. + */ + private void boxing(ITypeBinding requestedBinding, ITypeBinding valueBinding) { + String requestedTypeName = requestedBinding.getQualifiedName(); + if ("java.lang.Object".equals(requestedTypeName)) { //$NON-NLS-1$ + switch (valueBinding.getBinaryName().charAt(0)) { + case 'I': + push(new SendStaticMessage( + "java.lang.Integer", "valueOf", "(I)Ljava/lang/Integer;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'C': + push(new SendStaticMessage( + "java.lang.Character", "valueOf", "(C)Ljava/lang/Character;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'B': + push(new SendStaticMessage( + "java.lang.Byte", "valueOf", "(B)Ljava/lang/Byte;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'S': + push(new SendStaticMessage( + "java.lang.Short", "valueOf", "(S)Ljava/lang/Short;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'J': + push(new SendStaticMessage( + "java.lang.Long", "valueOf", "(J)Ljava/lang/Long;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'F': + push(new SendStaticMessage( + "java.lang.Float", "valueOf", "(F)Ljava/lang/Float;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'D': + push(new SendStaticMessage( + "java.lang.Double", "valueOf", "(D)Ljava/lang/Double;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case 'Z': + push(new SendStaticMessage( + "java.lang.Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } else if ("java.lang.Integer".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(I)Ljava/lang/Integer;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Character".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(C)Ljava/lang/Character;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Byte".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(B)Ljava/lang/Byte;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Short".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(S)Ljava/lang/Short;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Long".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(J)Ljava/lang/Long;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Float".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(F)Ljava/lang/Float;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Double".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(D)Ljava/lang/Double;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Boolean".equals(requestedTypeName)) { //$NON-NLS-1$ + push(new SendStaticMessage(requestedTypeName, + "valueOf", "(Z)Ljava/lang/Boolean;", 1, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + /** + * Add the instruction to un-box a non-primitive value if needed. Returns + * true if a storeInstruction() is needed after visiting the expression + */ + private boolean unBoxing(ITypeBinding valueBinding) { + String valueTypeName = valueBinding.getQualifiedName(); + if ("java.lang.Integer".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("intValue", "()I", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Character".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("charValue", "()C", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Byte".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("byteValue", "()B", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Short".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("shortValue", "()S", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Long".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("longValue", "()J", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Float".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("floatValue", "()F", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Double".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("doubleValue", "()D", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else if ("java.lang.Boolean".equals(valueTypeName)) { //$NON-NLS-1$ + push(new SendMessage("booleanValue", "()Z", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + return false; + } + return true; + } + + /** + * End visit methods + * + * There are two paths to ending a visit to a node: + *
    + *
  1. For control statements, the necessary control instructions (jump, + * conditional jump) are inserted into the instruction sequence
  2. + *
  3. For other cases, we simply remove the node's instruction from the + * stack and add it to the instruction sequence.
  4. + *
+ */ + + /** + * @see ASTVisitor#endVisit(AnonymousClassDeclaration) + */ + @Override + public void endVisit(AnonymousClassDeclaration node) { + + } + + /** + * @see ASTVisitor#endVisit(ArrayAccess) + */ + @Override + public void endVisit(ArrayAccess node) { + if (!isActive() || hasErrors()) { + return; + } + ITypeBinding typeBinding = node.getIndex().resolveTypeBinding(); + if (typeBinding != null && unBoxing(typeBinding)) { + // un-box the index, if required + storeInstruction(); + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ArrayCreation) + */ + @Override + public void endVisit(ArrayCreation node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ArrayInitializer) + */ + @Override + public void endVisit(ArrayInitializer node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ArrayType) + */ + @Override + public void endVisit(ArrayType node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(AssertStatement) + */ + @Override + public void endVisit(AssertStatement node) { + + } + + /** + * @see ASTVisitor#endVisit(Assignment) + */ + @Override + public void endVisit(Assignment node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(Block) + */ + @Override + public void endVisit(Block node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(BooleanLiteral) + */ + @Override + public void endVisit(BooleanLiteral node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(BreakStatement) + */ + @Override + public void endVisit(BreakStatement node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(CastExpression) + */ + @Override + public void endVisit(CastExpression node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(CatchClause) + */ + @Override + public void endVisit(CatchClause node) { + + } + + /** + * @see ASTVisitor#endVisit(CharacterLiteral) + */ + @Override + public void endVisit(CharacterLiteral node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ClassInstanceCreation) + */ + @Override + public void endVisit(ClassInstanceCreation node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(CompilationUnit) + */ + @Override + public void endVisit(CompilationUnit node) { + while(!fStack.isEmpty()) { + storeInstruction(); + } + } + + /** + * @see ASTVisitor#endVisit(ConditionalExpression) + */ + @Override + public void endVisit(ConditionalExpression node) { + if (!isActive() || hasErrors()) { + return; + } + + // Get the instructions + int ifFalseAddress = fInstructions.getEnd(); + Instruction ifFalse = fInstructions.get(ifFalseAddress); + int ifTrueAddress = ifFalseAddress - ifFalse.getSize(); + Instruction ifTrue = fInstructions.get(ifTrueAddress); + int conditionalAddress = ifTrueAddress - ifTrue.getSize(); + + // Insert the conditional jump + ConditionalJump conditionalJump = new ConditionalJump(false); + fInstructions.insert(conditionalJump, conditionalAddress + 1); + + // Insert the jump + int jumpAddress = ifTrueAddress + 2; + Jump jump = new Jump(); + fInstructions.insert(jump, jumpAddress); + + // Set the jump offsets + conditionalJump.setOffset(ifTrue.getSize() + 1); + jump.setOffset(ifFalse.getSize() + 1); + + fCounter += 2; + storeInstruction(); + + } + + /** + * @see ASTVisitor#endVisit(ConstructorInvocation) + */ + @Override + public void endVisit(ConstructorInvocation node) { + + } + + /** + * @see ASTVisitor#endVisit(ContinueStatement) + */ + @Override + public void endVisit(ContinueStatement node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(DoStatement) + */ + @Override + public void endVisit(DoStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + /* + * The structure of generated instructions is : + * + * -- | body -- -- |condition -- - jump to the first instruction of the + * body if the condition is true. + */ + + String label = getLabel(node); + + // get address of each part + int conditionAddress = fInstructions.getEnd(); + Instruction condition = fInstructions.getInstruction(conditionAddress); + int bodyAddress = conditionAddress - condition.getSize(); + Instruction body = fInstructions.getInstruction(bodyAddress); + int bodyStartAddress = bodyAddress - body.getSize(); + + // add the conditionnalJump + ConditionalJump conditionalJump = new ConditionalJump(true); + fInstructions.add(conditionalJump); + fCounter++; + + // set jump offsets + conditionalJump.setOffset(-(condition.getSize() + body.getSize() + 1)); + + // for each pending break or continue instruction which are related to + // this loop, set the offset of the corresponding jump. + for (Iterator iter = fCompleteInstructions.iterator(); iter.hasNext();) { + CompleteInstruction instruction = iter.next(); + Jump jumpInstruction = instruction.fInstruction; + int instructionAddress = fInstructions.indexOf(jumpInstruction); + if (instructionAddress > bodyStartAddress + && (instruction.fLabel == null || instruction.fLabel + .equals(label))) { + iter.remove(); + if (instruction.fIsBreak) { + // jump to the instruction after the last jump + jumpInstruction + .setOffset((conditionAddress - instructionAddress) + 1); + } else { + // jump to the first instruction of the condition + jumpInstruction.setOffset(bodyAddress - instructionAddress); + } + } + } + + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(EmptyStatement) + */ + @Override + public void endVisit(EmptyStatement node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom + * .EnhancedForStatement) + */ + @Override + public void endVisit(EnhancedForStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + /* + * The structure of generated instructions is : + * + * For an array: -- | [] a= Expression | int i= 0 | + * -- -- | i < a.length - jump to the + * instruction after the last jump if the condition is false. -- -- | s= + * a[i] | Body -- -- - jump to the first instruction of the condition. + * + * For an Iterable: -- | Iterator i= Expression.iterator() | + * -- -- | i.hasNext() - jump to the + * instruction after the last jump if the condition is false. -- -- | s= + * i.next() | Body -- -- - jump to the first instruction of the + * condition. + */ + + int bodyAddress = fInstructions.getEnd(); + Instruction body = fInstructions.getInstruction(bodyAddress); + int conditionAddress = bodyAddress - body.getSize(); + Instruction condition = fInstructions.getInstruction(conditionAddress); + int initAddress = conditionAddress - condition.getSize(); + + // add conditional jump + ConditionalJump condJump = new ConditionalJump(false); + fInstructions.insert(condJump, conditionAddress + 1); + bodyAddress++; + fCounter++; + condJump.setOffset(body.getSize() + 1); + + // add jump + Jump jump = new Jump(); + fInstructions.add(jump); + fCounter++; + jump.setOffset(initAddress - (bodyAddress + 1)); + + // for each pending break or continue instruction which are related to + // this loop, set the offset of the corresponding jump. + String label = getLabel(node); + for (Iterator iter = fCompleteInstructions.iterator(); iter.hasNext();) { + CompleteInstruction instruction = iter.next(); + Jump jumpInstruction = instruction.fInstruction; + int instructionAddress = fInstructions.indexOf(jumpInstruction); + if (instructionAddress > conditionAddress + && (instruction.fLabel == null || instruction.fLabel + .equals(label))) { + iter.remove(); + if (instruction.fIsBreak) { + // jump to the instruction after the last jump + jumpInstruction + .setOffset((bodyAddress - instructionAddress) + 1); + } else { + // jump to the first instruction of the condition + jumpInstruction.setOffset(initAddress - instructionAddress); + } + } + } + + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ExpressionStatement) + */ + @Override + public void endVisit(ExpressionStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + addPopInstructionIfNeeded(node.getExpression()); + } + + /** + * @see ASTVisitor#endVisit(FieldAccess) + */ + @Override + public void endVisit(FieldAccess node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(FieldDeclaration) + */ + @Override + public void endVisit(FieldDeclaration node) { + + } + + /** + * @see ASTVisitor#endVisit(ForStatement) + */ + @Override + public void endVisit(ForStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + /* + * The structure of generated instructions is : + * + * -- |initialization -- -- |condition -- - jump to the instruction + * after the last jump if the condition is false. -- | body -- -- | + * updaters -- - jump to the first instruction of the condition. + */ + + String label = getLabel(node); + boolean hasCondition = node.getExpression() != null; + + // get address of each part + int updatersAddress = fInstructions.getEnd(); + Instruction updaters = fInstructions.getInstruction(updatersAddress); + int bodyAddress = updatersAddress - updaters.getSize(); + Instruction body = fInstructions.getInstruction(bodyAddress); + int bodyStartAddress = bodyAddress - body.getSize(); + + int conditionAddress; + Instruction condition; + + if (hasCondition) { + conditionAddress = bodyStartAddress; + condition = fInstructions.getInstruction(conditionAddress); + } else { + conditionAddress = 0; + condition = null; + } + + // add jump + Jump jump = new Jump(); + fInstructions.add(jump); + fCounter++; + + if (hasCondition) { + // add conditional jump + ConditionalJump condJump = new ConditionalJump(false); + fInstructions.insert(condJump, conditionAddress + 1); + bodyAddress++; + bodyStartAddress++; + updatersAddress++; + fCounter++; + // set conditional jump offset + condJump.setOffset(body.getSize() + updaters.getSize() + 1); + } + + // set jump offset + jump.setOffset(-((hasCondition && (condition != null) ? condition + .getSize() : 0) + body.getSize() + updaters.getSize() + 2)); + + // for each pending break or continue instruction which are related to + // this loop, set the offset of the corresponding jump. + for (Iterator iter = fCompleteInstructions.iterator(); iter.hasNext();) { + CompleteInstruction instruction = iter.next(); + Jump jumpInstruction = instruction.fInstruction; + int instructionAddress = fInstructions.indexOf(jumpInstruction); + if (instructionAddress > bodyStartAddress + && (instruction.fLabel == null || instruction.fLabel + .equals(label))) { + iter.remove(); + if (instruction.fIsBreak) { + // jump to the instruction after the last jump + jumpInstruction + .setOffset((updatersAddress - instructionAddress) + 1); + } else { + // jump to the first instruction of the condition + jumpInstruction.setOffset(bodyAddress - instructionAddress); + } + } + } + + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(IfStatement) + */ + @Override + public void endVisit(IfStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + boolean hasElseStatement = node.getElseStatement() != null; + + // Get the instructions + + int ifFalseAddress = 0; + Instruction ifFalse = null; + int ifTrueAddress = 0; + Instruction ifTrue = null; + + if (hasElseStatement) { + ifFalseAddress = fInstructions.getEnd(); + ifFalse = fInstructions.get(ifFalseAddress); + ifTrueAddress = ifFalseAddress - ifFalse.getSize(); + ifTrue = fInstructions.get(ifTrueAddress); + } else { + ifTrueAddress = fInstructions.getEnd(); + ifTrue = fInstructions.get(ifTrueAddress); + } + + int conditionalAddress = ifTrueAddress - ifTrue.getSize(); + + // Insert the conditional jump + ConditionalJump conditionalJump = new ConditionalJump(false); + fInstructions.insert(conditionalJump, conditionalAddress + 1); + // Set the jump offset + conditionalJump.setOffset(ifTrue.getSize() + + ((hasElseStatement) ? 1 : 0)); + fCounter++; + + if (hasElseStatement) { + // Insert the jump + int jumpAddress = ifTrueAddress + 2; + Jump jump = new Jump(); + fInstructions.insert(jump, jumpAddress); + // Set the jump offset + jump.setOffset(ifFalse.getSize() + 1); + fCounter++; + } + + storeInstruction(); + + } + + /** + * @see ASTVisitor#endVisit(ImportDeclaration) + */ + @Override + public void endVisit(ImportDeclaration node) { + + } + + /** + * @see ASTVisitor#endVisit(InfixExpression) + */ + @Override + public void endVisit(InfixExpression node) { + } + + /** + * @see ASTVisitor#endVisit(Initializer) + */ + @Override + public void endVisit(Initializer node) { + + } + + /** + * @see ASTVisitor#endVisit(InstanceofExpression) + */ + @Override + public void endVisit(InstanceofExpression node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(Javadoc) + */ + @Override + public void endVisit(Javadoc node) { + + } + + /** + * @see ASTVisitor#endVisit(LabeledStatement) + */ + @Override + public void endVisit(LabeledStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + String label = node.getLabel().getIdentifier(); + + // for each pending continue instruction which are related to + // this statement, set the offset of the corresponding jump. + for (Iterator iter = fCompleteInstructions.iterator(); iter.hasNext();) { + CompleteInstruction instruction = iter.next(); + if (instruction.fLabel != null && instruction.fLabel.equals(label)) { + iter.remove(); + Jump jumpInstruction = instruction.fInstruction; + int instructionAddress = fInstructions.indexOf(jumpInstruction); + if (instruction.fIsBreak) { + // jump to the instruction after the statement + jumpInstruction.setOffset(fInstructions.getEnd() + - instructionAddress); + } + } + } + } + + /** + * @see ASTVisitor#endVisit(MethodDeclaration) + */ + @Override + public void endVisit(MethodDeclaration node) { + setActive(false); + } + + /** + * @see ASTVisitor#endVisit(MethodInvocation) + */ + @Override + public void endVisit(MethodInvocation node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(NullLiteral) + */ + @Override + public void endVisit(NullLiteral node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(NumberLiteral) + */ + @Override + public void endVisit(NumberLiteral node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(PackageDeclaration) + */ + @Override + public void endVisit(PackageDeclaration node) { + + } + + /** + * @see ASTVisitor#endVisit(SimpleType) + */ + @Override + public void endVisit(ParameterizedType node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ParenthesizedExpression) + */ + @Override + public void endVisit(ParenthesizedExpression node) { + + } + + /** + * @see ASTVisitor#endVisit(PostfixExpression) + */ + @Override + public void endVisit(PostfixExpression node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(PrefixExpression) + */ + @Override + public void endVisit(PrefixExpression node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(PrimitiveType) + */ + @Override + public void endVisit(PrimitiveType node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(QualifiedName) + */ + @Override + public void endVisit(QualifiedName node) { + } + + /** + * @see ASTVisitor#endVisit(SimpleType) + */ + @Override + public void endVisit(QualifiedType node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ReturnStatement) + */ + @Override + public void endVisit(ReturnStatement node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(SimpleName) + */ + @Override + public void endVisit(SimpleName node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(SimpleType) + */ + @Override + public void endVisit(SimpleType node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(SingleVariableDeclaration) + */ + @Override + public void endVisit(SingleVariableDeclaration node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(StringLiteral) + */ + @Override + public void endVisit(StringLiteral node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + @Override + public void endVisit(TextBlock node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(SuperConstructorInvocation) + */ + @Override + public void endVisit(SuperConstructorInvocation node) { + + } + + /** + * @see ASTVisitor#endVisit(SuperFieldAccess) + */ + @Override + public void endVisit(SuperFieldAccess node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(SuperMethodInvocation) + */ + @Override + public void endVisit(SuperMethodInvocation node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(SwitchCase) + */ + @Override + public void endVisit(SwitchCase node) { + // never called + } + + /** + * @see ASTVisitor#endVisit(SwitchStatement) + */ + @Override + public void endVisit(SwitchStatement node) { + // nothing to do + } + + /** + * @see ASTVisitor#endVisit(SynchronizedStatement) + */ + @Override + public void endVisit(SynchronizedStatement node) { + + } + + /** + * @see ASTVisitor#endVisit(ThisExpression) + */ + @Override + public void endVisit(ThisExpression node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(ThrowStatement) + */ + @Override + public void endVisit(ThrowStatement node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(TryStatement) + */ + @Override + public void endVisit(TryStatement node) { + + } + + /** + * @see ASTVisitor#endVisit(TypeDeclaration) + */ + @Override + public void endVisit(TypeDeclaration node) { + + } + + /** + * @see ASTVisitor#endVisit(TypeDeclarationStatement) + */ + @Override + public void endVisit(TypeDeclarationStatement node) { + + } + + /** + * @see ASTVisitor#endVisit(TypeLiteral) + */ + @Override + public void endVisit(TypeLiteral node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(VariableDeclarationExpression) + */ + @Override + public void endVisit(VariableDeclarationExpression node) { + + } + + /** + * @see ASTVisitor#endVisit(VariableDeclarationFragment) + */ + @Override + public void endVisit(VariableDeclarationFragment node) { + if (!isActive() || hasErrors()) { + return; + } + storeInstruction(); + } + + /** + * @see ASTVisitor#endVisit(VariableDeclarationStatement) + */ + @Override + public void endVisit(VariableDeclarationStatement node) { + + } + + /** + * @see ASTVisitor#endVisit(WhileStatement) + */ + @Override + public void endVisit(WhileStatement node) { + if (!isActive() || hasErrors()) { + return; + } + + /* + * The structure of generated instructions is : + * + * -- |condition -- - jump to the instruction after the last jump if the + * condition is false. -- | body -- - jump to the first instruction of + * the condition. + */ + + String label = getLabel(node); + + // get address of each part + int bodyAddress = fInstructions.getEnd(); + Instruction body = fInstructions.getInstruction(bodyAddress); + int conditionAddress = bodyAddress - body.getSize(); + Instruction condition = fInstructions.getInstruction(conditionAddress); + + // add the conditionnalJump + ConditionalJump conditionalJump = new ConditionalJump(false); + fInstructions.insert(conditionalJump, conditionAddress + 1); + + // add the jump + Jump jump = new Jump(); + fInstructions.add(jump); + + // set jump offsets + conditionalJump.setOffset(body.getSize() + 1); + jump.setOffset(-(condition.getSize() + body.getSize() + 2)); + + // for each pending break or continue instruction which are related to + // this loop, set the offset of the corresponding jump. + for (Iterator iter = fCompleteInstructions.iterator(); iter.hasNext();) { + CompleteInstruction instruction = iter.next(); + Jump jumpInstruction = instruction.fInstruction; + int instructionAddress = fInstructions.indexOf(jumpInstruction); + if (instructionAddress > conditionAddress + && (instruction.fLabel == null || instruction.fLabel + .equals(label))) { + iter.remove(); + if (instruction.fIsBreak) { + // jump to the instruction after the last jump + jumpInstruction + .setOffset((bodyAddress - instructionAddress) + 2); + } else { + // jump to the first instruction of the condition + jumpInstruction.setOffset((conditionAddress - condition + .getSize()) - instructionAddress); + } + } + } + + fCounter += 2; + storeInstruction(); + } + + /* + * Visit methods + * + * There are two variations of node visiting:
  1. Push the instruction + * corresponding to the node onto the stack and return true to + * visit the children of the node.
  2. Push the instruction + * corresponding to the node onto the stack and visit the children of the + * node manually (return false to avoid the default child + * visiting implementation).
+ */ + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * AnnotationTypeDeclaration) + */ + @Override + public boolean visit(AnnotationTypeDeclaration node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * AnnotationTypeMemberDeclaration) + */ + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + return false; + } + + /** + * @see ASTVisitor#visit(AnonymousClassDeclaration) + */ + @Override + public boolean visit(AnonymousClassDeclaration node) { + if (!isActive()) { + return true; + } + return false; + } + + /** + * @see ASTVisitor#visit(ArrayAccess) + */ + @Override + public boolean visit(ArrayAccess node) { + if (!isActive()) { + return false; + } + + push(new org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAccess( + fCounter)); + + return true; + } + + /** + * @see ASTVisitor#visit(ArrayCreation) + */ + @Override + public boolean visit(ArrayCreation node) { + if (!isActive()) { + return false; + } + + ArrayType arrayType = node.getType(); + + ITypeBinding binding = resolveTypeBinding(arrayType); + if (binding != null && isALocalType(binding.getElementType())) { + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Local_type_array_instance_creation_cannot_be_used_in_an_evaluation_expression_29); + setHasError(true); + return false; + } + + push(new ArrayAllocation(arrayType.getDimensions(), node.dimensions() + .size(), node.getInitializer() != null, fCounter)); + + return true; + } + + /** + * @see ASTVisitor#visit(ArrayInitializer) + */ + @Override + public boolean visit(ArrayInitializer node) { + if (!isActive()) { + return false; + } + + ITypeBinding typeBinding = resolveTypeBinding(node); + if (typeBinding != null) { + int dimension = typeBinding.getDimensions(); + String signature = getTypeSignature(typeBinding.getElementType()); + push(new ArrayInitializerInstruction(signature, node.expressions() + .size(), dimension, fCounter)); + } + + return true; + } + + /** + * @see ASTVisitor#visit(ArrayType) + */ + @Override + public boolean visit(ArrayType node) { + if (!isActive()) { + return false; + } + ITypeBinding arrayTypeBinding = resolveTypeBinding(node); + if (arrayTypeBinding != null) { + int dimension = arrayTypeBinding.getDimensions(); + String signature = getTypeSignature(arrayTypeBinding + .getElementType()); + push(new PushArrayType(signature, dimension, fCounter)); + } + + return false; + } + + /** + * @see ASTVisitor#visit(AssertStatement) + */ + @Override + public boolean visit(AssertStatement node) { + if (!isActive()) { + return false; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3); + return false; + } + + /** + * @see ASTVisitor#visit(Assignment) + */ + @Override + public boolean visit(Assignment node) { + if (!isActive()) { + return false; + } + Expression leftHandSide = node.getLeftHandSide(); + Expression rightHandSide = node.getRightHandSide(); + int variableTypeId = getTypeId(leftHandSide); + int valueTypeId = getTypeId(rightHandSide); + + String opToken = node.getOperator().toString(); + int opTokenLength = opToken.length(); + char char0 = opToken.charAt(0); + char char2 = '\0'; + if (opTokenLength > 2) { + char2 = opToken.charAt(2); + } + + ITypeBinding rightBinding = resolveTypeBinding(rightHandSide); + if (rightBinding == null) { + return false; + } + ITypeBinding leftBinding = resolveTypeBinding(leftHandSide); + if (leftBinding == null) { + return false; + } + if (variableTypeId == Instruction.T_Object) { + // If the variable is an object, the value may need to be boxed for + // the simple assignment. + // For the compound assignment operators, the value of the variable + // have to be un-boxed before the operation is done, then re-boxed + // to + // to be stored in the variable. + + int unboxedVariableTypeId = getUnBoxedTypeId(leftHandSide); + int unboxedValueTypeId = getUnBoxedTypeId(rightHandSide); + int unboxedResultTypeId = Instruction.getBinaryPromotionType( + unboxedVariableTypeId, unboxedValueTypeId); + + push(new AssignmentOperator(variableTypeId, variableTypeId, + fCounter)); + + leftHandSide.accept(this); + + if (char0 == '=') { + + boolean storeRequired = false; + if (rightBinding.isPrimitive()) { + boxing(leftBinding, rightBinding); + storeRequired = true; + } + rightHandSide.accept(this); + if (storeRequired) { + storeInstruction(); // boxing + } + + } else { + boolean unrecognized = false; + + boxing(leftBinding, rightBinding); + + switch (char0) { + case '=': // equal + break; + case '+': // plus equal + push(new PlusOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '-': // minus equal + push(new MinusOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '*': // multiply equal + push(new MultiplyOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '/': // divide equal + push(new DivideOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '%': // remainder equal + push(new RemainderOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '^': // XOr equal + push(new XorOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '|': // or equal + push(new OrOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '&': // and equal + push(new AndOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '<': // left shift equal + push(new LeftShiftOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, fCounter)); + break; + case '>': // right shift equal or unsigned right shift equal + switch (char2) { + case '=': // right shift equal + push(new RightShiftOperator(unboxedVariableTypeId, + unboxedValueTypeId, unboxedResultTypeId, + fCounter)); + break; + case '>': // unsigned right shift equal + push(new UnsignedRightShiftOperator( + unboxedVariableTypeId, unboxedValueTypeId, + unboxedResultTypeId, fCounter)); + break; + default: + unrecognized = true; + break; + } + break; + default: + unrecognized = true; + break; + } + + if (unrecognized) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_assignment_operator____4 + + opToken); + return false; + } + + unBoxing(leftBinding); + push(new Dup()); + storeInstruction(); // dupe + storeInstruction(); // un-boxing + + boolean storeRequired = unBoxing(rightBinding); + rightHandSide.accept(this); + if (storeRequired) { + storeInstruction(); // un-boxing + } + + storeInstruction(); // operation + storeInstruction(); // boxing + + } + + } else { + boolean unrecognized = false; + + switch (char0) { + case '=': // equal + push(new AssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '+': // plus equal + push(new PlusAssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '-': // minus equal + push(new MinusAssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '*': // multiply equal + push(new MultiplyAssignmentOperator(variableTypeId, + valueTypeId, fCounter)); + break; + case '/': // divide equal + push(new DivideAssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '%': // remainder equal + push(new RemainderAssignmentOperator(variableTypeId, + valueTypeId, fCounter)); + break; + case '^': // XOr equal + push(new XorAssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '|': // or equal + push(new OrAssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '&': // and equal + push(new AndAssignmentOperator(variableTypeId, valueTypeId, + fCounter)); + break; + case '<': // left shift equal + push(new LeftShiftAssignmentOperator(variableTypeId, + valueTypeId, fCounter)); + break; + case '>': // right shift equal or unsigned right shift equal + switch (char2) { + case '=': // right shift equal + push(new RightShiftAssignmentOperator(variableTypeId, + valueTypeId, fCounter)); + break; + case '>': // unsigned right shift equal + push(new UnsignedRightShiftAssignmentOperator( + variableTypeId, valueTypeId, fCounter)); + break; + default: + unrecognized = true; + break; + } + break; + default: + unrecognized = true; + break; + } + + if (unrecognized) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_assignment_operator____4 + + opToken); + return false; + } + + leftHandSide.accept(this); + boolean storeRequired = unBoxing(rightBinding); + rightHandSide.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + + return false; + + } + + /** + * @see ASTVisitor#visit(Block) + */ + @Override + public boolean visit(Block node) { + int start = node.getStartPosition(); + if (start == fStartPosition || start == (fStartPosition + 1)) { + setActive(true); + } + if (!isActive()) { + return true; + } + + push(new NoOp(fCounter)); + + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * BlockComment) + */ + @Override + public boolean visit(BlockComment node) { + return false; + } + + /** + * @see ASTVisitor#visit(BooleanLiteral) + */ + @Override + public boolean visit(BooleanLiteral node) { + if (!isActive()) { + return false; + } + + push(new PushBoolean(node.booleanValue())); + + return true; + } + + /** + * @see ASTVisitor#visit(BreakStatement) + */ + @Override + public boolean visit(BreakStatement node) { + if (!isActive()) { + return false; + } + // create the equivalent jump instruction in the instruction + // and add an element in the list of pending break and continue + // instructions + Jump instruction = new Jump(); + SimpleName labelName = node.getLabel(); + String label = null; + if (labelName != null) { + label = labelName.getIdentifier(); + } + push(instruction); + fCompleteInstructions.add(new CompleteInstruction(instruction, label, + true)); + + return false; + } + + /** + * @see ASTVisitor#visit(CastExpression) + */ + @Override + public boolean visit(CastExpression node) { + if (!isActive()) { + return false; + } + + Type type = node.getType(); + int typeId = getTypeId(type); + ITypeBinding typeBinding = resolveTypeBinding(type); + + if (typeBinding != null) { + String baseTypeSignature; + int dimension = typeBinding.getDimensions(); + if (typeBinding.isArray()) { + typeBinding = typeBinding.getElementType(); + } + baseTypeSignature = getTypeName(typeBinding); + push(new Cast(typeId, baseTypeSignature, dimension, fCounter)); + node.getExpression().accept(this); + } + + return false; + } + + /** + * @see ASTVisitor#visit(CatchClause) + */ + @Override + public boolean visit(CatchClause node) { + if (!isActive()) { + return false; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Catch_clause_cannot_be_used_in_an_evaluation_expression_6); + return false; + } + + /** + * @see ASTVisitor#visit(CharacterLiteral) + */ + @Override + public boolean visit(CharacterLiteral node) { + if (!isActive()) { + return false; + } + + push(new PushChar(node.charValue())); + + return true; + } + + /** + * return false, visit expression, type name & arguments, don't visit body + * declaration + * + * @see ASTVisitor#visit(ClassInstanceCreation) + */ + @Override + public boolean visit(ClassInstanceCreation node) { + if (!isActive()) { + return true; + } + + String rewrittenLocalType = null; + if (node.getAnonymousClassDeclaration() != null) { + try { + RemoteEvaluatorBuilder builder = makeBuilder(node); + builder.acceptAnonymousClass(node, node.getType().resolveBinding()); + RemoteEvaluator remoteEvaluator = builder.build(); + push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator)); + + push(new PushType(getTypeName(node.getType().resolveBinding()))); + storeInstruction(); + return false; + + } catch (JavaModelException | DebugException e) { + addErrorMessage(e.getMessage()); + setHasError(true); + } + } + + IMethodBinding methodBinding = node.resolveConstructorBinding(); + if (methodBinding == null) { + setHasError(true); + addErrorMessage(MessageFormat.format( + EvaluationEngineMessages.ASTInstructionCompiler_1, + new Object[] { node.toString() })); + return false; + } + ITypeBinding typeBinding = methodBinding.getDeclaringClass(); + + boolean isInstanceMemberType = typeBinding.isMember() + && !Modifier.isStatic(typeBinding.getModifiers()); + + boolean isLocalType = isALocalType(typeBinding); + + if (containsALocalType(methodBinding)) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Constructor_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_30); + } + + if (hasErrors()) { + return false; + } + + int paramCount = methodBinding.getParameterTypes().length; + + String enclosingTypeSignature = null; + ITypeBinding enclosingTypeBinding = null; + if (isInstanceMemberType) { + enclosingTypeBinding = typeBinding.getDeclaringClass(); + if (enclosingTypeBinding == null) { + setHasError(true); + addErrorMessage(MessageFormat.format( + EvaluationEngineMessages.ASTInstructionCompiler_2, + new Object[] { typeBinding.getQualifiedName() })); + return false; + } + enclosingTypeSignature = getTypeSignature(enclosingTypeBinding); + paramCount++; + } + + String signature = null; + if(isLocalType) { + String methodSignature = getMethodSignature(methodBinding, null); + signature = methodSignature.replace(methodBinding.getReturnType().getQualifiedName(), rewrittenLocalType).replace('.', '/'); + } else { + signature = getMethodSignature(methodBinding, + enclosingTypeSignature).replace('.', '/'); + } + + push(new Constructor(signature, paramCount, fCounter)); + + push(new PushType(isLocalType ? rewrittenLocalType : getTypeName(typeBinding))); + storeInstruction(); + + if (isInstanceMemberType) { + Expression optionalExpression = node.getExpression(); + if (optionalExpression != null) { + optionalExpression.accept(this); + } else { + // for a non-static inner class, check if we are not in a static + // context (method) + ASTNode parent = node; + do { + parent = parent.getParent(); + } while (!(parent instanceof MethodDeclaration)); + if (Modifier.isStatic(((MethodDeclaration) parent) + .getModifiers())) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Must_explicitly_qualify_the_allocation_with_an_instance_of_the_enclosing_type_33); + return false; + } + + push(new PushThis(getEnclosingLevel(node, enclosingTypeBinding))); + storeInstruction(); + } + } + + List arguments = node.arguments(); + pushMethodArguments(methodBinding, arguments); + + return false; + } + + /** + * @see ASTVisitor#visit(CompilationUnit) + */ + @Override + public boolean visit(CompilationUnit node) { + return true; + } + + /** + * @see ASTVisitor#visit(ConditionalExpression) + */ + @Override + public boolean visit(ConditionalExpression node) { + if (!isActive()) { + return true; + } + + push(new NoOp(fCounter)); + + return true; + } + + /** + * @see ASTVisitor#visit(ConstructorInvocation) + */ + @Override + public boolean visit(ConstructorInvocation node) { + if (!isActive()) { + return false; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_this_constructor_invocation_cannot_be_used_in_an_evaluation_expression_9); + return false; + } + + /** + * @see ASTVisitor#visit(ContinueStatement) + */ + @Override + public boolean visit(ContinueStatement node) { + if (!isActive()) { + return false; + } + // create the equivalent jump instruction in the instruction + // and add an element in the list of pending break and continue + // instructions + Jump instruction = new Jump(); + SimpleName labelName = node.getLabel(); + String label = null; + if (labelName != null) { + label = labelName.getIdentifier(); + } + push(instruction); + fCompleteInstructions.add(new CompleteInstruction(instruction, label, + false)); + + return false; + } + + /** + * @see ASTVisitor#visit(CreationReference) + */ + @Override + public boolean visit(CreationReference node) { + if (!isActive()) { + return true; + } + try { + RemoteEvaluatorBuilder builder = makeBuilder(node); + builder.acceptMethodReference(node, node.resolveTypeBinding()); + RemoteEvaluator remoteEvaluator = builder.build(); + push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator)); + storeInstruction(); + } catch (JavaModelException | DebugException e) { + addErrorMessage(e.getMessage()); + setHasError(true); + } + return false; + } + + /** + * @see ASTVisitor#visit(DoStatement) + */ + @Override + public boolean visit(DoStatement node) { + if (!isActive()) { + return false; + } + + push(new NoOp(fCounter)); + return true; + } + + /** + * @see ASTVisitor#visit(EmptyStatement) + */ + @Override + public boolean visit(EmptyStatement node) { + if (!isActive()) { + return false; + } + push(new NoOp(fCounter)); + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnhancedForStatement) + */ + @Override + public boolean visit(EnhancedForStatement node) { + if (!isActive()) { + return false; + } + + push(new NoOp(fCounter)); + + ITypeBinding typeBinding = resolveTypeBinding(node.getExpression()); + if (typeBinding == null) { + return false; + } + Type paramType = node.getParameter().getType(); + ITypeBinding paramBinding = resolveTypeBinding(paramType); + if (paramBinding == null) { + return false; + } + String typeSignature = getTypeSignature(paramBinding); + int paramTypeId = getTypeId(paramType); + boolean isParamPrimitiveType = paramTypeId != Instruction.T_Object + && paramTypeId != Instruction.T_String; + String paramIdentifier = node.getParameter().getName().getIdentifier(); + + if (typeBinding.isArray()) { + // the expression returns an array + int idIndex = fUniqueIdIndex++; + String arrayIdentifier = "#a" + idIndex; //$NON-NLS-1$ + String varIdentifier = "#i" + idIndex; //$NON-NLS-1$ + push(new LocalVariableCreation(arrayIdentifier, typeSignature, 1, + isParamPrimitiveType, true, fCounter)); + node.getExpression().accept(this); + storeInstruction(); + push(new LocalVariableCreation(varIdentifier, + "I", 0, true, true, fCounter)); //$NON-NLS-1$ + push(new PushInt(0)); + storeInstruction(); + storeInstruction(); + push(new LocalVariableCreation(paramIdentifier, typeSignature, 0, + isParamPrimitiveType, false, fCounter)); + storeInstruction(); + + push(new LessOperator(Instruction.T_int, Instruction.T_int, + fCounter)); + push(new PushLocalVariable(varIdentifier)); + storeInstruction(); + push(new PushArrayLength(fCounter)); + push(new PushLocalVariable(arrayIdentifier)); + storeInstruction(); + storeInstruction(); + storeInstruction(); + + // conditional jump will be added here + + push(new NoOp(fCounter)); + push(new AssignmentOperator(paramTypeId, paramTypeId, fCounter)); + push(new PushLocalVariable(paramIdentifier)); + storeInstruction(); + push(new org.eclipse.jdt.internal.debug.eval.ast.instructions.ArrayAccess( + fCounter)); + push(new PushLocalVariable(arrayIdentifier)); + storeInstruction(); + push(new PostfixPlusPlusOperator(Instruction.T_int, fCounter)); + push(new PushLocalVariable(varIdentifier)); + storeInstruction(); + storeInstruction(); + storeInstruction(); + if (checkAutoBoxing(typeBinding.getElementType(), paramBinding)) { + storeInstruction(); + } + storeInstruction(); + addPopInstruction(); + node.getBody().accept(this); + storeInstruction(); + + // jump will be added here + + } else { + // the expression returns a collection + String iteratorIdentifier = "#i" + fUniqueIdIndex++; //$NON-NLS-1$ + push(new LocalVariableCreation(iteratorIdentifier, + "Ljava/util/Iterator;", 0, false, true, fCounter)); //$NON-NLS-1$ + push(new SendMessage( + "iterator", "()Ljava/util/Iterator;", 0, null, fCounter)); //$NON-NLS-1$//$NON-NLS-2$ + node.getExpression().accept(this); + storeInstruction(); + storeInstruction(); + push(new LocalVariableCreation(paramIdentifier, typeSignature, 0, + isParamPrimitiveType, false, fCounter)); + storeInstruction(); + + push(new SendMessage("hasNext", "()Z", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + push(new PushLocalVariable(iteratorIdentifier)); + storeInstruction(); + storeInstruction(); + + // conditional jump will be added here + + push(new NoOp(fCounter)); + push(new AssignmentOperator(paramTypeId, paramTypeId, fCounter)); + push(new PushLocalVariable(paramIdentifier)); + storeInstruction(); + push(new SendMessage( + "next", "()Ljava/lang/Object;", 0, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + push(new PushLocalVariable(iteratorIdentifier)); + storeInstruction(); + storeInstruction(); + ITypeBinding[] typeArguments = typeBinding.getTypeArguments(); + if (typeArguments != null && typeArguments.length > 0) { + if (checkAutoBoxing(typeArguments[0], paramBinding)) { + storeInstruction(); + } + } + storeInstruction(); + addPopInstruction(); + node.getBody().accept(this); + storeInstruction(); + + // jump will be added here + + } + + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnumConstantDeclaration) + */ + @Override + public boolean visit(EnumConstantDeclaration node) { + if (!isActive()) { + return true; + } + + // nothing to do, we shouldn't hit this node + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnumDeclaration) + */ + @Override + public boolean visit(EnumDeclaration node) { + if (!isActive()) { + return true; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_0); + return false; + } + + /** + * @see ASTVisitor#visit(ExpressionMethodReference) + */ + @Override + public boolean visit(ExpressionMethodReference node) { + if (!isActive()) { + return true; + } + + try { + RemoteEvaluatorBuilder builder = makeBuilder(node); + builder.acceptMethodReference(node, node.resolveTypeBinding()); + RemoteEvaluator remoteEvaluator = builder.build(); + push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator)); + storeInstruction(); + } catch (JavaModelException | DebugException e) { + addErrorMessage(e.getMessage()); + setHasError(true); + } + + return false; + } + + @SuppressWarnings("unused") + private RemoteEvaluatorBuilder makeBuilder(ASTNode node) throws DebugException { + RemoteEvaluatorBuilder builder = new RemoteEvaluatorBuilder(fJavaProject, new ExpressionBinder() { + @Override + public void bind(IVariableBinding variableBinding, String asVariableName) { + String variableId = variableBinding.getName(); + push(new PushLocalVariable(variableId)); + storeInstruction(); + } + + @Override + public void bindThis(ITypeBinding typeBinding, String asVariableName) { + push(new PushThis(getEnclosingLevel(node, typeBinding))); + storeInstruction(); + } + + }, getEnclosingClass(node), isStaticContext(node), false); + return builder; + } + + private ITypeBinding getEnclosingClass(ASTNode node) { + while (node != null) { + if (node instanceof MethodDeclaration) { + return ((MethodDeclaration) node).resolveBinding().getDeclaringClass(); + } + if (node instanceof TypeDeclaration) { + return ((TypeDeclaration) node).resolveBinding(); + } + node = node.getParent(); + } + return null; + } + + private boolean isStaticContext(ASTNode node) { + while (node != null) { + if (node instanceof MethodDeclaration) { + return Modifier.isStatic(((MethodDeclaration) node).getModifiers()); + } else if (node instanceof Initializer) { + return Modifier.isStatic(((Initializer) node).getModifiers()); + } + node = node.getParent(); + } + return false; + } + + /** + * @see ASTVisitor#visit(ExpressionStatement) + */ + @Override + public boolean visit(ExpressionStatement node) { + return true; + } + + /** + * return false, visit expression, don't visit name + * + * @see ASTVisitor#visit(FieldAccess) + */ + @Override + public boolean visit(FieldAccess node) { + if (!isActive()) { + return false; + } + + SimpleName fieldName = node.getName(); + IVariableBinding fieldBinding = (IVariableBinding) fieldName + .resolveBinding(); + if (fieldBinding != null) { + ITypeBinding declaringTypeBinding = fieldBinding + .getDeclaringClass(); + Expression expression = node.getExpression(); + String fieldId = fieldName.getIdentifier(); + + if (Modifier.isStatic(fieldBinding.getModifiers())) { + push(new PushStaticFieldVariable(fieldId, + getTypeName(declaringTypeBinding), fCounter)); + expression.accept(this); + addPopInstruction(); + } else { + if (declaringTypeBinding == null) { // it is a field without + // declaring type => it is + // the special length array + // field + push(new PushArrayLength(fCounter)); + } else { + if (isALocalType(declaringTypeBinding)) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Qualified_local_type_field_access_cannot_be_used_in_an_evaluation_expression_31); + return false; + } + push(new PushFieldVariable(fieldId, + getTypeSignature(declaringTypeBinding), fCounter)); + } + expression.accept(this); + } + } + return false; + } + + /** + * @see ASTVisitor#visit(FieldDeclaration) + */ + @Override + public boolean visit(FieldDeclaration node) { + return true; + } + + /** + * @see ASTVisitor#visit(ForStatement) return false, don't use + * the standard accept order. order used for visiting children : + * initializers, condition, body, updaters + */ + @Override + public boolean visit(ForStatement node) { + if (!isActive()) { + return false; + } + + push(new NoOp(fCounter)); + + push(new NoOp(fCounter)); + for (Iterator iter = node.initializers().iterator(); iter.hasNext();) { + Expression expr = iter.next(); + expr.accept(this); + addPopInstructionIfNeeded(expr); + } + storeInstruction(); + + Expression condition = node.getExpression(); + if (condition != null) { + condition.accept(this); + } + + node.getBody().accept(this); + + push(new NoOp(fCounter)); + for (Iterator iter = node.updaters().iterator(); iter.hasNext();) { + Expression expr = iter.next(); + expr.accept(this); + addPopInstructionIfNeeded(expr); + } + storeInstruction(); + + return false; + } + + /** + * @see ASTVisitor#visit(IfStatement) + */ + @Override + public boolean visit(IfStatement node) { + if (!isActive()) { + return false; + } + + push(new NoOp(fCounter)); + + return true; + } + + /** + * @see ASTVisitor#visit(ImportDeclaration) + */ + @Override + public boolean visit(ImportDeclaration node) { + return false; + } + + /** + * return false, don't use the standard accept order. + * + * @see ASTVisitor#visit(InfixExpression) + */ + @Override + public boolean visit(InfixExpression node) { + if (!isActive()) { + return false; + } + + String opToken = node.getOperator().toString(); + int opTokenLength = opToken.length(); + char char0 = opToken.charAt(0); + char char1 = '\0'; + char char2 = '\0'; + if (opTokenLength > 1) { + char1 = opToken.charAt(1); + if (opTokenLength > 2) { + char2 = opToken.charAt(2); + } + } + + List extendedOperands = node.extendedOperands(); + + int operatorNumber = extendedOperands.size() + 1; + + int[][] types = new int[operatorNumber][3]; + + Iterator iterator = extendedOperands.iterator(); + + Expression leftOperand = node.getLeftOperand(); + Expression rightOperand = node.getRightOperand(); + int leftTypeId; + int rightTypeId; + boolean unbox = false; + // for == and != un-box when at least operand is primitive (otherwise + // compare the objects) + ITypeBinding leftBinding = resolveTypeBinding(leftOperand); + if (leftBinding == null) { + return false; + } + ITypeBinding rightBinding = resolveTypeBinding(rightOperand); + if (rightBinding == null) { + return false; + } + if ((char0 == '=' || char0 == '!') && char1 == '=') { + unbox = leftBinding.isPrimitive() || rightBinding.isPrimitive(); + } else { + unbox = true; + } + if (unbox) { + leftTypeId = getUnBoxedTypeId(leftOperand); + rightTypeId = getUnBoxedTypeId(rightOperand); + } else { + leftTypeId = getTypeId(leftOperand); + rightTypeId = getTypeId(rightOperand); + } + int resultTypeId = Instruction.getBinaryPromotionType(leftTypeId, + rightTypeId); + + types[0][0] = resultTypeId; + types[0][1] = leftTypeId; + types[0][2] = rightTypeId; + + for (int i = 1; i < operatorNumber; i++) { + Expression operand = iterator.next(); + leftTypeId = resultTypeId; + rightTypeId = getUnBoxedTypeId(operand); + resultTypeId = Instruction.getBinaryPromotionType(leftTypeId, + rightTypeId); + types[i][0] = resultTypeId; + types[i][1] = leftTypeId; + types[i][2] = rightTypeId; + } + + boolean unrecognized = false; + + switch (char0) { + case '*': // multiply + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new MultiplyOperator(types[i][0], types[i][1], + types[i][2], fCounter)); + } + break; + case '/': // divide + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new DivideOperator(types[i][0], types[i][1], types[i][2], + fCounter)); + } + break; + case '%': // remainder + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new RemainderOperator(types[i][0], types[i][1], + types[i][2], fCounter)); + } + break; + case '+': // plus + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new PlusOperator(types[i][0], types[i][1], types[i][2], + fCounter)); + } + break; + case '-': // minus + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new MinusOperator(types[i][0], types[i][1], types[i][2], + fCounter)); + } + break; + case '<': // left shift or less or less equal + switch (char1) { + case '\0': // less + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new LessOperator(types[i][1], types[i][2], fCounter)); + } + break; + case '<': // left shift + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new LeftShiftOperator( + Instruction.getUnaryPromotionType(types[i][1]), + types[i][1], types[i][2], fCounter)); + } + break; + case '=': // less equal + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new LessEqualOperator(types[i][1], types[i][2], + fCounter)); + } + break; + default: + unrecognized = true; + break; + } + break; + case '>': // right shift or unsigned right shift or greater or greater + // equal + switch (char1) { + case '\0': // greater + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new GreaterOperator(types[i][1], types[i][2], fCounter)); + } + break; + case '>': // right shift or unsigned right shift + switch (char2) { + case '\0': // right shift + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new RightShiftOperator( + Instruction.getUnaryPromotionType(types[i][1]), + types[i][1], types[i][2], fCounter)); + } + break; + case '>': // unsigned right shift + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new UnsignedRightShiftOperator( + Instruction.getUnaryPromotionType(types[i][1]), + types[i][1], types[i][2], fCounter)); + } + break; + } + break; + case '=': // greater equal + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new GreaterEqualOperator(types[i][1], types[i][2], + fCounter)); + } + break; + default: + unrecognized = true; + break; + } + break; + case '=': // equal equal + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new EqualEqualOperator(types[i][1], types[i][2], true, + fCounter)); + } + break; + case '!': // not equal + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new EqualEqualOperator(types[i][1], types[i][2], false, + fCounter)); + } + break; + case '^': // XOr + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new XorOperator(types[i][0], types[i][1], types[i][2], + fCounter)); + } + break; + case '|': // or or or or + switch (char1) { + case '\0': // or + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new OrOperator(types[i][0], types[i][1], types[i][2], + fCounter)); + } + break; + case '|': // or or + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new NoOp(fCounter)); + } + break; + default: + unrecognized = true; + break; + } + break; + case '&': // and or and and + switch (char1) { + case '\0': // and + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new AndOperator(types[i][0], types[i][1], types[i][2], + fCounter)); + } + break; + case '&': // and and + for (int i = operatorNumber - 1; i >= 0; i--) { + push(new NoOp(fCounter)); + } + break; + default: + unrecognized = true; + break; + } + break; + default: + unrecognized = true; + break; + } + if (unrecognized) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Unrecognized_infix_operator____13 + + opToken); + } + if (hasErrors()) { + return false; + } + + iterator = extendedOperands.iterator(); + + if ((char0 == '&' && char1 == '&') || (char0 == '|' && char1 == '|')) { + boolean isOrOr = char0 == '|'; + + ConditionalJump[] conditionalJumps = new ConditionalJump[operatorNumber]; + int[] conditionalJumpAddresses = new int[operatorNumber]; + + boolean storeRequired = unBoxing(leftBinding); + leftOperand.accept(this); + if (storeRequired) { + storeInstruction(); + } + + ConditionalJump conditionalJump = new ConditionalJump(isOrOr); + conditionalJumps[0] = conditionalJump; + conditionalJumpAddresses[0] = fCounter; + push(conditionalJump); + storeInstruction(); + + storeRequired = unBoxing(rightBinding); + rightOperand.accept(this); + if (storeRequired) { + storeInstruction(); + } + + for (int i = 1; i < operatorNumber; i++) { + conditionalJump = new ConditionalJump(isOrOr); + conditionalJumps[i] = conditionalJump; + conditionalJumpAddresses[i] = fCounter; + push(conditionalJump); + storeInstruction(); + Expression operand = iterator.next(); + ITypeBinding typeBinding = resolveTypeBinding(operand); + if (typeBinding == null) { + return false; + } + storeRequired = unBoxing(typeBinding); + operand.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + + Jump jump = new Jump(); + jump.setOffset(1); + push(jump); + storeInstruction(); + + for (int i = 0; i < operatorNumber; i++) { + conditionalJumps[i].setOffset(fCounter + - conditionalJumpAddresses[i] - 1); + } + + push(new PushBoolean(isOrOr)); + storeInstruction(); + + // store the no-op + // since we add no-op for number of operators (there will be more than one when we have extendedOperands), + // we need to store them as well to make sure the next expression such as PrefixExpressions can properly + // store the instruction in correct place. + for (int i = 0; i < operatorNumber; i++) { + storeInstruction(); + } + + } else { // other operators + + boolean storeRequired = false; + if (unbox) { + storeRequired = unBoxing(leftBinding); + } + leftOperand.accept(this); + if (storeRequired) { + storeInstruction(); + } + if (unbox) { + storeRequired = unBoxing(rightBinding); + } + rightOperand.accept(this); + if (storeRequired) { + storeInstruction(); + } + + storeInstruction(); + for (int i = 1; i < operatorNumber; i++) { + Expression operand = iterator.next(); + if (unbox) { + ITypeBinding typeBinding = resolveTypeBinding(operand); + if (typeBinding == null) { + return false; + } + storeRequired = unBoxing(typeBinding); + } + operand.accept(this); + if (storeRequired) { + storeInstruction(); + } + storeInstruction(); + } + } + + return false; + } + + /** + * @see ASTVisitor#visit(Initializer) + */ + @Override + public boolean visit(Initializer node) { + return true; + } + + /** + * @see ASTVisitor#visit(InstanceofExpression) + */ + @Override + public boolean visit(InstanceofExpression node) { + if (!isActive()) { + return false; + } + push(new InstanceOfOperator(fCounter)); + return true; + } + + /** + * @see ASTVisitor#visit(Javadoc) + */ + @Override + public boolean visit(Javadoc node) { + return false; + } + + /** + * @see ASTVisitor#visit(LabeledStatement) return false, don't + * use the standard accept order. + */ + @Override + public boolean visit(LabeledStatement node) { + node.getBody().accept(this); + return false; + } + + /** + * @see ASTVisitor#visit(LambdaExpression) + */ + @Override + public boolean visit(LambdaExpression node) { + if (!isActive()) { + return true; + } + + try { + RemoteEvaluatorBuilder builder = makeBuilder(node); + builder.acceptLambda(node, node.resolveTypeBinding()); + RemoteEvaluator remoteEvaluator = builder.build(); + push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator)); + storeInstruction(); + } catch (JavaModelException | DebugException e) { + addErrorMessage(e.getMessage()); + setHasError(true); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * LineComment) + */ + @Override + public boolean visit(LineComment node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MarkerAnnotation) + */ + @Override + public boolean visit(MarkerAnnotation node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef + * ) + */ + @Override + public boolean visit(MemberRef node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MemberValuePair) + */ + @Override + public boolean visit(MemberValuePair node) { + return false; + } + + /** + * @see ASTVisitor#visit(MethodDeclaration) + */ + @Override + public boolean visit(MethodDeclaration node) { + int start = node.getStartPosition(); + int end = start + node.getLength(); + if (start < fStartPosition && end > fStartPosition) { + return true; + } + return false; + } + + /** + * return false, don't visit name, visit expression & arguments + * + * @see ASTVisitor#visit(MethodInvocation) + */ + @Override + public boolean visit(MethodInvocation node) { + if (!isActive()) { + return false; + } + + IMethodBinding methodBinding = (IMethodBinding) node.getName().resolveBinding(); + if (methodBinding == null) { + // could be the receiver is not visible - for example a private + // field access from super class + ASTNode root = node.getRoot(); + if (root instanceof CompilationUnit) { + CompilationUnit cu = (CompilationUnit) root; + IProblem[] problems = cu.getProblems(); + for (IProblem problem : problems) { + setHasError(true); + addErrorMessage(problem.getMessage()); + } + } + } + + if (hasErrors()) { + return false; + } + + if (containsALocalType(methodBinding)) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32); + return false; + } + + int paramCount = methodBinding.getParameterTypes().length; + String selector = methodBinding.getName(); + + String signature = getMethodSignature(methodBinding, null).replace('.', + '/'); + + boolean isStatic = Flags.isStatic(methodBinding.getModifiers()); + Expression expression = node.getExpression(); + + if (isStatic) { + String typeName = getTypeName(methodBinding.getDeclaringClass()); + push(new SendStaticMessage(typeName, selector, signature, + paramCount, fCounter)); + if (expression != null) { + node.getExpression().accept(this); + addPopInstruction(); + } + } else { + push(new SendMessage(selector, signature, paramCount, null, + fCounter)); + if (expression == null) { + push(new PushThis(getEnclosingLevel(node, + methodBinding.getDeclaringClass()))); + storeInstruction(); + } else { + node.getExpression().accept(this); + } + } + + List arguments = node.arguments(); + pushMethodArguments(methodBinding, arguments); + + return false; + } + + /** + * Pushes method arguments onto the stack for a method or constructor + * invocation taking variable arguments and auto-boxing into consideration. + * + * @param methodBinding + * method or constructor being called + * @param arguments + * argument list + */ + private void pushMethodArguments(IMethodBinding methodBinding, List arguments) { + int argCount = arguments.size(); + ITypeBinding[] parameterTypes = methodBinding.getParameterTypes(); + int paramCount = parameterTypes.length; + ITypeBinding lastArgBinding = null; + if (methodBinding.isVarargs()) { + Expression lastArg = arguments.get(argCount - 1); + lastArgBinding = resolveTypeBinding(lastArg); + if (lastArgBinding == null) { + return; + } + } + if (methodBinding.isVarargs() && + !(paramCount == argCount && + parameterTypes[paramCount - 1].getDimensions() == lastArgBinding.getDimensions())) { + // if this method is a varargs, and if the method is invoked using + // the varargs syntax + // (multiple arguments) and not an array + Iterator iterator = arguments.iterator(); + // process the first arguments (no part of the variable argument) + for (int i = 0; i < paramCount - 1; i++) { + Expression argument = iterator.next(); + boolean storeRequired = checkAutoBoxing( + argument.resolveTypeBinding(), parameterTypes[i]); + argument.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + // create a array of the remainder arguments + ITypeBinding varargsParameterType = parameterTypes[paramCount - 1]; + ITypeBinding varargsElementType = varargsParameterType + .getElementType(); + push(new ArrayInitializerInstruction( + getTypeSignature(varargsElementType), argCount - paramCount + + 1, varargsParameterType.getDimensions(), fCounter)); + while (iterator.hasNext()) { + Expression argument = iterator.next(); + boolean storeRequired = checkAutoBoxing( + argument.resolveTypeBinding(), varargsElementType); + argument.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + storeInstruction(); + } else { + Iterator iterator = arguments.iterator(); + int i = 0; + while (iterator.hasNext()) { + Expression argument = iterator.next(); + boolean storeRequired = checkAutoBoxing( + argument.resolveTypeBinding(), parameterTypes[i++]); + argument.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef + * ) + */ + @Override + public boolean visit(MethodRef node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MethodRefParameter) + */ + @Override + public boolean visit(MethodRefParameter node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier + * ) + */ + @Override + public boolean visit(Modifier node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * NormalAnnotation) + */ + @Override + public boolean visit(NormalAnnotation node) { + return false; + } + + /** + * @see ASTVisitor#visit(NullLiteral) + */ + @Override + public boolean visit(NullLiteral node) { + if (!isActive()) { + return false; + } + + push(new PushNull()); + + return true; + } + + /** + * @see ASTVisitor#visit(NumberLiteral) + */ + @Override + public boolean visit(NumberLiteral node) { + if (!isActive()) { + return false; + } + + int literalType = getTypeId(node); + String token = node.getToken(); + int tokenLastCharOffset = token.length() - 1; + char lastChar = token.charAt(tokenLastCharOffset); + String subToken = token.substring(0, tokenLastCharOffset); + + switch (literalType) { + case Instruction.T_byte: + push(new PushInt(parseByteValue(token))); + break; + case Instruction.T_short: + push(new PushInt(parseShortValue(token))); + break; + case Instruction.T_int: + push(new PushInt(parseIntValue(token))); + break; + case Instruction.T_long: + push(new PushLong(parseLongValue(subToken))); + break; + case Instruction.T_float: + push(new PushFloat( + Float.parseFloat(removePrefixZerosAndUnderscores(subToken, + false)))); + break; + case Instruction.T_double: + if (lastChar == 'D' || lastChar == 'd') { + push(new PushDouble( + Double.parseDouble(removePrefixZerosAndUnderscores( + subToken, false)))); + } else { + push(new PushDouble( + Double.parseDouble(removePrefixZerosAndUnderscores( + token, false)))); + } + break; + } + + return true; + } + + /** + * Removes all preamble typing and underscores and returns the base integer + * value + * + * @param token + * the token to parse + * @return the int value of the token + */ + public static int parseIntValue(String token) { + token = removePrefixZerosAndUnderscores(token, false); + switch (getBase(token)) { + case 8: + return Integer.parseInt(token.substring(1), 8); + case 16: + return Integer.parseInt(token.substring(2), 16); + case 2: + return Integer.parseInt(token.substring(2), 2); + default: + return Integer.parseInt(token, 10); + } + } + + /** + * Removes all preamble typing and underscores and returns the base short + * value + * + * @param token + * the token to parse + * @return the short value of the token + */ + public static short parseShortValue(String token) { + token = removePrefixZerosAndUnderscores(token, false); + switch (getBase(token)) { + case 8: + return Short.parseShort(token.substring(1), 8); + case 16: + return Short.parseShort(token.substring(2), 16); + case 2: + return Short.parseShort(token.substring(2), 2); + default: + return Short.parseShort(token, 10); + } + } + + /** + * Removes all preamble typing and underscores and returns the base byte + * value + * + * @param token + * the token to parse + * @return the byte value of the token + */ + public static byte parseByteValue(String token) { + token = removePrefixZerosAndUnderscores(token, false); + switch (getBase(token)) { + case 8: + return Byte.parseByte(token.substring(1), 8); + case 16: + return Byte.parseByte(token.substring(2), 16); + case 2: + return Byte.parseByte(token.substring(2), 2); + default: + return Byte.parseByte(token, 10); + } + } + + /** + * Removes all preamble typing and underscores and returns the base long + * value + * + * @param token + * the token to parse + * @return the long value of the token + */ + public static long parseLongValue(String token) { + token = removePrefixZerosAndUnderscores(token, true); + switch (getBase(token)) { + case 8: + return Long.parseLong(token.substring(1), 8); + case 16: + return Long.parseLong(token.substring(2), 16); + case 2: + return Long.parseLong(token.substring(2), 2); + default: + return Long.parseLong(token, 10); + } + } + + /** + * Returns the numeric base for the given token according to the Java + * specification. Returns 8, 10, or 16. + * + * @param token + * the token to get the base from + * @return the numeric base for the given token + */ + public static int getBase(String token) { + if (token.charAt(0) == '0' && (token.length() > 1)) { + switch (token.charAt(1)) { + case 'x': + case 'X': + // "0x" prefix: Hexadecimal + return 16; + case 'b': + case 'B': + // "0b" prefix: binary + return 2; + default: + // "0" prefix: Octal + return 8; + } + } + return 10; // No prefix: Decimal + } + + /** + * @see ASTVisitor#visit(PackageDeclaration) + */ + @Override + public boolean visit(PackageDeclaration node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * ParameterizedType) + */ + @Override + public boolean visit(ParameterizedType node) { + if (!isActive()) { + return false; + } + ITypeBinding typeBinding = resolveTypeBinding(node); + if (typeBinding != null) { + push(new PushType(getTypeName(typeBinding))); + } + return false; + } + + /** + * @see ASTVisitor#visit(ParenthesizedExpression) + */ + @Override + public boolean visit(ParenthesizedExpression node) { + if (!isActive()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(PostfixExpression) + */ + @Override + public boolean visit(PostfixExpression node) { + if (!isActive()) { + return false; + } + + Expression operand = node.getOperand(); + int expressionTypeId = getTypeId(operand); + + String opToken = node.getOperator().toString(); + char char0 = opToken.charAt(0); + + if (expressionTypeId == Instruction.T_Object) { + + int expressionUnBoxedTypeId = getUnBoxedTypeId(operand); + + AssignmentOperator assignmentInstruction = new AssignmentOperator( + Instruction.T_Object, Instruction.T_Object, fCounter); + push(assignmentInstruction); + operand.accept(this); + switch (char0) { + case '+': // plus plus + push(new PlusOperator(expressionUnBoxedTypeId, + expressionUnBoxedTypeId, expressionUnBoxedTypeId, + fCounter)); + break; + case '-': // minus minus + push(new MinusOperator(expressionUnBoxedTypeId, + expressionUnBoxedTypeId, expressionUnBoxedTypeId, + fCounter)); + break; + default: + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_postfix_operator____15 + + opToken); + return false; + } + push(new Value(fCounter)); + push(new Dup()); + storeInstruction(); // dupe + storeInstruction(); // value + push(new DupX1()); + storeInstruction(); // dup_x1 + ITypeBinding typeBinding = resolveTypeBinding(operand); + if (typeBinding == null) { + return false; + } + unBoxing(typeBinding); + storeInstruction(); // un-boxing + push(new PushInt(1)); + storeInstruction(); // push 1 + storeInstruction(); // operator + boxing(typeBinding, null); + storeInstruction(); // boxing + storeInstruction(); // assignment + push(new Pop(assignmentInstruction.getSize() + 1)); + + return false; + } + + switch (char0) { + case '+': // plus plus + push(new PostfixPlusPlusOperator(expressionTypeId, fCounter)); + break; + case '-': // minus minus + push(new PostfixMinusMinusOperator(expressionTypeId, fCounter)); + break; + default: + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_postfix_operator____15 + + opToken); + return false; + } + + return true; + } + + /** + * @see ASTVisitor#visit(PrefixExpression) + */ + @Override + public boolean visit(PrefixExpression node) { + if (!isActive()) { + return false; + } + + Expression operand = node.getOperand(); + int expressionTypeId = getTypeId(operand); + + String opToken = node.getOperator().toString(); + int opTokenLength = opToken.length(); + char char0 = opToken.charAt(0); + char char1 = '\0'; + if (opTokenLength > 1) { + char1 = opToken.charAt(1); + } + + boolean unrecognized = false; + + if (expressionTypeId == Instruction.T_Object) { + + int expressionUnBoxedTypeId = getUnBoxedTypeId(operand); + + ITypeBinding typeBinding = resolveTypeBinding(operand); + if (typeBinding == null) { + return false; + } + if (char1 == '\0') { + switch (char0) { + case '+': // unary plus + push(new UnaryPlusOperator(expressionUnBoxedTypeId, + fCounter)); + break; + case '-': // unary minus + push(new UnaryMinusOperator(expressionUnBoxedTypeId, + fCounter)); + break; + case '~': // twiddle + push(new TwiddleOperator(expressionUnBoxedTypeId, fCounter)); + break; + case '!': // not + push(new NotOperator(expressionUnBoxedTypeId, fCounter)); + break; + default: + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16 + + opToken); + return false; + } + + unBoxing(typeBinding); + operand.accept(this); + storeInstruction(); // un-boxing + + } else { + // plus plus and minus minus operators + + push(new AssignmentOperator(Instruction.T_Object, + Instruction.T_Object, fCounter)); + + operand.accept(this); + + boxing(typeBinding, null); + + switch (char1) { + case '+': + push(new PlusOperator(expressionUnBoxedTypeId, + expressionUnBoxedTypeId, expressionUnBoxedTypeId, + fCounter)); + break; + case '-': + push(new MinusOperator(expressionUnBoxedTypeId, + expressionUnBoxedTypeId, expressionUnBoxedTypeId, + fCounter)); + break; + default: + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16 + + opToken); + return false; + } + + unBoxing(typeBinding); + push(new Dup()); + storeInstruction(); // dupe + storeInstruction(); // un-boxing + push(new PushInt(1)); + storeInstruction(); // push 1 + + storeInstruction(); // operator + storeInstruction(); // boxing + + } + + return false; + } + + switch (char0) { + case '+': // plus plus or unary plus + switch (char1) { + case '\0': // unary plus + push(new UnaryPlusOperator(expressionTypeId, fCounter)); + break; + case '+': // plus plus + push(new PrefixPlusPlusOperator(expressionTypeId, fCounter)); + break; + default: + unrecognized = true; + break; + } + break; + case '-': // minus minus or unary minus + switch (char1) { + case '\0': // unary minus + push(new UnaryMinusOperator(expressionTypeId, fCounter)); + break; + case '-': // minus minus + push(new PrefixMinusMinusOperator(expressionTypeId, fCounter)); + break; + default: + unrecognized = true; + break; + } + break; + case '~': // twiddle + push(new TwiddleOperator(expressionTypeId, fCounter)); + break; + case '!': // not + push(new NotOperator(expressionTypeId, fCounter)); + break; + default: + unrecognized = true; + break; + } + + if (unrecognized) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_unrecognized_prefix_operator____16 + + opToken); + return false; + } + + return true; + } + + /** + * @see ASTVisitor#visit(PrimitiveType) + */ + @Override + public boolean visit(PrimitiveType node) { + if (!isActive()) { + return false; + } + ITypeBinding typeBinding = resolveTypeBinding(node); + if (typeBinding != null) { + push(new PushPrimitiveType(getTypeName(typeBinding))); + } + return false; + } + + /** + * @see ASTVisitor#visit(QualifiedName) + */ + @Override + public boolean visit(QualifiedName node) { + if (!isActive()) { + return false; + } + + if (hasErrors()) { + return true; + } + + IBinding binding = resolveBinding(node); + if (binding == null) { + return false; + } + switch (binding.getKind()) { + case IBinding.TYPE: + node.getName().accept(this); + break; + case IBinding.VARIABLE: + SimpleName fieldName = node.getName(); + IVariableBinding fieldBinding = (IVariableBinding) resolveBinding(fieldName); + if (fieldBinding == null) { + return false; + } + ITypeBinding declaringTypeBinding = fieldBinding + .getDeclaringClass(); + String fieldId = fieldName.getIdentifier(); + + if (Modifier.isStatic(fieldBinding.getModifiers())) { + push(new PushStaticFieldVariable(fieldId, + getTypeName(declaringTypeBinding), fCounter)); + } else { + if (declaringTypeBinding == null) { + push(new PushArrayLength(fCounter)); + } else { + push(new PushFieldVariable(fieldId, + getTypeSignature(declaringTypeBinding), fCounter)); + } + node.getQualifier().accept(this); + } + storeInstruction(); + break; + } + + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * QualifiedType) + */ + @Override + public boolean visit(QualifiedType node) { + if (!isActive()) { + return false; + } + ITypeBinding typeBinding = resolveTypeBinding(node); + if (typeBinding != null) { + push(new PushType(getTypeName(typeBinding))); + } + return false; + } + + /** + * @see ASTVisitor#visit(ReturnStatement) + */ + @Override + public boolean visit(ReturnStatement node) { + if (!isActive()) { + return false; + } + push(new ReturnInstruction(fCounter)); + return true; + } + + /** + * @see ASTVisitor#visit(SimpleName) + */ + @Override + public boolean visit(SimpleName node) { + if (!isActive()) { + return false; + } + + if (hasErrors()) { + return true; + } + + IBinding binding = resolveBinding(node); + if (binding == null) { + return true; + } + String variableId = node.getIdentifier(); + + switch (binding.getKind()) { + case IBinding.TYPE: + ITypeBinding typeBinding = (ITypeBinding) binding; + push(new PushType(getTypeName(typeBinding))); + break; + case IBinding.VARIABLE: + IVariableBinding variableBinding = (IVariableBinding) binding; + ITypeBinding declaringTypeBinding = variableBinding + .getDeclaringClass(); + if (variableBinding.isField()) { + if (Modifier.isStatic(variableBinding.getModifiers())) { + push(new PushStaticFieldVariable(variableId, + getTypeName(declaringTypeBinding), fCounter)); + } else { + push(new PushFieldVariable(variableId, + getTypeSignature(declaringTypeBinding), fCounter)); + push(new PushThis(getEnclosingLevel(node, + declaringTypeBinding))); + storeInstruction(); + } + } else { + push(new PushLocalVariable(variableId)); + } + break; + } + return true; + } + + /** + * return false, don't visit child + * + * @see ASTVisitor#visit(SimpleType) + */ + @Override + public boolean visit(SimpleType node) { + if (!isActive()) { + return false; + } + + ITypeBinding typeBinding = resolveTypeBinding(node); + if (typeBinding != null) { + push(new PushType(getTypeName(typeBinding))); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * SingleMemberAnnotation) + */ + @Override + public boolean visit(SingleMemberAnnotation node) { + return false; + } + + /** + * @see ASTVisitor#visit(SingleVariableDeclaration) return + * false, don't use the standard accept order. + */ + @Override + public boolean visit(SingleVariableDeclaration node) { + if (!isActive()) { + return false; + } + ITypeBinding typeBinding = resolveTypeBinding(node.getType()); + if (typeBinding != null) { + int typeDimension = typeBinding.getDimensions(); + if (typeDimension != 0) { + typeBinding = typeBinding.getElementType(); + } + Expression initializer = node.getInitializer(); + push(new LocalVariableCreation(node.getName().getIdentifier(), + getTypeSignature(typeBinding), typeDimension, + typeBinding.isPrimitive(), initializer != null, fCounter)); + if (initializer != null) { + initializer.accept(this); + } + } + return false; + } + + /** + * @see ASTVisitor#visit(StringLiteral) + */ + @Override + public boolean visit(StringLiteral node) { + if (!isActive()) { + return false; + } + + push(new PushString(node.getLiteralValue())); + + return true; + } + + @Override + public boolean visit(TextBlock node) { + if (!isActive()) { + return false; + } + + push(new PushString(node.getLiteralValue())); + + return true; + } + + /** + * @see ASTVisitor#visit(SuperConstructorInvocation) + */ + @Override + public boolean visit(SuperConstructorInvocation node) { + if (!isActive()) { + return false; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_super_constructor_invocation_cannot_be_used_in_an_evaluation_expression_19); + return false; + } + + /** + * @see ASTVisitor#visit(SuperFieldAccess) + */ + @Override + public boolean visit(SuperFieldAccess node) { + if (!isActive()) { + return false; + } + + SimpleName fieldName = node.getName(); + IVariableBinding fieldBinding = (IVariableBinding) resolveBinding(fieldName); + if (fieldBinding == null) { + return false; + } + ITypeBinding declaringTypeBinding = fieldBinding.getDeclaringClass(); + String fieldId = fieldName.getIdentifier(); + + if (Modifier.isStatic(fieldBinding.getModifiers())) { + push(new PushStaticFieldVariable(fieldId, + getTypeName(declaringTypeBinding), fCounter)); + } else { + Name qualifier = node.getQualifier(); + int superLevel = 1; + int enclosingLevel = 0; + if (qualifier != null) { + ITypeBinding typeBinding = resolveTypeBinding(qualifier); + if (typeBinding == null) { + return false; + } + superLevel = getSuperLevel(typeBinding, declaringTypeBinding); + ITypeBinding binding = (ITypeBinding) resolveBinding(qualifier); + if (binding == null) { + return false; + } + enclosingLevel = getEnclosingLevel(node, binding); + } + push(new PushFieldVariable(fieldId, superLevel, fCounter)); + push(new PushThis(enclosingLevel)); + storeInstruction(); + } + + return false; + } + + /** + * return false, don't visit name, visit arguments + * + * @see ASTVisitor#visit(SuperMethodInvocation) + */ + @Override + public boolean visit(SuperMethodInvocation node) { + if (!isActive()) { + return false; + } + + IMethodBinding methodBinding = (IMethodBinding) resolveBinding(node + .getName()); + if (methodBinding == null) { + return false; + } + + if (containsALocalType(methodBinding)) { + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32); + return false; + } + + ITypeBinding[] parameterTypes = methodBinding.getParameterTypes(); + int paramCount = parameterTypes.length; + String selector = methodBinding.getName(); + String signature = getMethodSignature(methodBinding, null); + + Name qualifier = node.getQualifier(); + if (Modifier.isStatic(methodBinding.getModifiers())) { + push(new SendStaticMessage( + getTypeName(methodBinding.getDeclaringClass()), selector, + signature, paramCount, fCounter)); + } else { + push(new SendMessage(selector, signature, paramCount, + getTypeSignature(methodBinding.getDeclaringClass()), + fCounter)); + int enclosingLevel = 0; + if (qualifier != null) { + ITypeBinding typeBinding = (ITypeBinding) resolveBinding(qualifier); + if (typeBinding == null) { + return false; + } + enclosingLevel = getEnclosingLevel(node, typeBinding); + } + push(new PushThis(enclosingLevel)); + storeInstruction(); + } + + List arguments = node.arguments(); + int argCount = arguments.size(); + ITypeBinding lastArgBinding = null; + if (methodBinding.isVarargs()) { + lastArgBinding = resolveTypeBinding(arguments.get(argCount - 1)); + if (lastArgBinding == null) { + return false; + } + } + if (methodBinding.isVarargs() && + !(paramCount == argCount && + parameterTypes[paramCount - 1].getDimensions() == lastArgBinding.getDimensions())) { + // if this method is a varargs, and if the method is invoked using + // the varargs syntax + // (multiple arguments) and not an array + Iterator iterator = arguments.iterator(); + // process the first arguments (no part of the variable argument) + for (int i = 0; i < paramCount - 1; i++) { + Expression argument = iterator.next(); + boolean storeRequired = checkAutoBoxing( + argument.resolveTypeBinding(), parameterTypes[i]); + argument.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + // create a array of the remainder arguments + ITypeBinding varargsParameterType = parameterTypes[paramCount - 1]; + ITypeBinding varargsElementType = varargsParameterType + .getElementType(); + push(new ArrayInitializerInstruction( + getTypeSignature(varargsElementType), argCount - paramCount + + 1, varargsParameterType.getDimensions(), fCounter)); + while (iterator.hasNext()) { + Expression argument = iterator.next(); + boolean storeRequired = checkAutoBoxing( + argument.resolveTypeBinding(), varargsElementType); + argument.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + storeInstruction(); + } else { + Iterator iterator = arguments.iterator(); + int i = 0; + while (iterator.hasNext()) { + Expression argument = iterator.next(); + boolean storeRequired = checkAutoBoxing( + argument.resolveTypeBinding(), parameterTypes[i++]); + argument.accept(this); + if (storeRequired) { + storeInstruction(); + } + } + } + + return false; + } + + /** + * @see ASTVisitor#visit(SuperMethodReference) + */ + @Override + public boolean visit(SuperMethodReference node) { + if (!isActive()) { + return true; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Reference_expressions_cannot_be_used_in_an_evaluation_expression); + return false; + } + + @Override + public boolean visit(SwitchExpression node) { + if (!isActive()) { + return true; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Switch_expressions_cannot_be_used_in_an_evaluation_expression); + return false; + } + + /** + * @see ASTVisitor#visit(SwitchCase) + */ + @Override + public boolean visit(SwitchCase node) { + // never called + return false; + } + + static class slot { + ArrayList jumps = new ArrayList<>(); + ArrayList stmts = null; + } + + /** + * @see ASTVisitor#visit(SwitchStatement) + */ + @SuppressWarnings("deprecation") + @Override + public boolean visit(SwitchStatement node) { + if (!isActive()) { + return false; + } + push(new NoOp(fCounter)); + int switchStart = fCounter; + node.getExpression().accept(this); + + ArrayList statementsDefault = null; + Jump jumpDefault = null; + ArrayList jumpsStatements = new ArrayList<>(); + slot currentslot = new slot(); + jumpsStatements.add(currentslot); + + for (Iterator iter = node.statements().iterator(); iter.hasNext();) { + Statement statement = iter.next(); + if (statement instanceof SwitchCase) { + SwitchCase switchCase = (SwitchCase) statement; + if (switchCase.isDefault()) { + jumpDefault = new Jump(); + push(jumpDefault); + storeInstruction(); // jump + statementsDefault = new ArrayList<>(); + } else { + if (node.getAST().apiLevel() >= AST.JLS14) { + for (Object expression : switchCase.expressions()) { + if (expression instanceof StringLiteral || expression instanceof TextBlock) { + push(new SendMessage("equals", "(Ljava/lang/Object;)Z", 1, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + push(new EqualEqualOperator(Instruction.T_int, Instruction.T_int, true, fCounter)); + } + push(new Dup()); + storeInstruction(); // dupe + ((Expression) expression).accept(this); + storeInstruction(); // equal-equal + } + } else { + if (switchCase.getExpression() instanceof StringLiteral || switchCase.getExpression() instanceof TextBlock) { + push(new SendMessage("equals", "(Ljava/lang/Object;)Z", 1, null, fCounter)); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + push(new EqualEqualOperator(Instruction.T_int, Instruction.T_int, true, fCounter)); + } + push(new Dup()); + storeInstruction(); // dupe + switchCase.getExpression().accept(this); + storeInstruction(); // equal-equal + } + ConditionalJump condJump = new ConditionalJump(true); + push(condJump); + storeInstruction(); // conditional jump + if (currentslot.stmts != null) { + currentslot = new slot(); + jumpsStatements.add(currentslot); + } + currentslot.jumps.add(condJump); + } + } else { + if (statementsDefault != null) { + statementsDefault.add(statement); + } else { + if (currentslot.stmts == null) { + currentslot.stmts = new ArrayList<>(); + } + currentslot.stmts.add(statement); + } + } + } + + Jump jumpEnd = null; + if (jumpDefault == null) { + push(new Pop(0)); + storeInstruction(); // pop + jumpEnd = new Jump(); + push(jumpEnd); + storeInstruction(); // jump + } + + for (slot slot : jumpsStatements) { + for (ConditionalJump condJump : slot.jumps) { + condJump.setOffset((fCounter - fInstructions.indexOf(condJump)) - 1); + } + if (currentslot.stmts != null) { + push(new Pop(0)); + storeInstruction(); // pop + for (Statement statement : currentslot.stmts) { + statement.accept(this); + } + } + } + + // default case + if (jumpDefault != null) { + jumpDefault.setOffset((fCounter - fInstructions.indexOf(jumpDefault)) - 1); + push(new Pop(0)); + storeInstruction(); // pop + for (Statement statement : statementsDefault) { + statement.accept(this); + } + } else if(jumpEnd != null){ + jumpEnd.setOffset((fCounter - fInstructions.indexOf(jumpEnd)) - 1); + } + + // for each pending break or continue instruction which are related to + // this loop, set the offset of the corresponding jump. + String label = getLabel(node); + for (Iterator iter = fCompleteInstructions.iterator(); iter.hasNext();) { + CompleteInstruction instruction = iter.next(); + Jump jumpInstruction = instruction.fInstruction; + int instructionAddress = fInstructions.indexOf(jumpInstruction); + if (instructionAddress > switchStart && (instruction.fLabel == null || instruction.fLabel.equals(label))) { + iter.remove(); + if (instruction.fIsBreak) { + // jump to the instruction after the last instruction of the + // switch + jumpInstruction.setOffset((fCounter - instructionAddress) - 1); + } + } + } + return false; + } + + /** + * @see ASTVisitor#visit(SynchronizedStatement) + */ + @Override + public boolean visit(SynchronizedStatement node) { + if (!isActive()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement + * ) + */ + @Override + public boolean visit(TagElement node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * TextElement) + */ + @Override + public boolean visit(TextElement node) { + return false; + } + + /** + * @see ASTVisitor#visit(ThisExpression) + */ + @Override + public boolean visit(ThisExpression node) { + if (!isActive()) { + return false; + } + + Name qualifier = node.getQualifier(); + int enclosingLevel = 0; + if (qualifier != null) { + ITypeBinding binding = (ITypeBinding) resolveBinding(qualifier); + if (binding == null) { + return false; + } + enclosingLevel = getEnclosingLevel(node, binding); + } + push(new PushThis(enclosingLevel)); + + return false; + } + + /** + * @see ASTVisitor#visit(ThrowStatement) + */ + @Override + public boolean visit(ThrowStatement node) { + if (!isActive()) { + return false; + } + push(new ThrowInstruction(fCounter)); + return true; + } + + /** + * @see ASTVisitor#visit(TryStatement) + */ + @Override + public boolean visit(TryStatement node) { + if (!isActive()) { + return false; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Try_statement_cannot_be_used_in_an_evaluation_expression_23); + return false; + } + + /** + * @see ASTVisitor#visit(TypeDeclaration) + */ + @Override + public boolean visit(TypeDeclaration node) { + if (!isActive()) { + return true; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Type_declaration_cannot_be_used_in_an_evaluation_expression_24); + return false; + } + + /** + * @see ASTVisitor#visit(TypeDeclarationStatement) + */ + @Override + public boolean visit(TypeDeclarationStatement node) { + if (!isActive()) { + return true; + } + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Type_declaration_statement_cannot_be_used_in_an_evaluation_expression_25); + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * TypeParameter) + */ + @Override + public boolean visit(TypeParameter node) { + return false; + } + + /** + * @see ASTVisitor#visit(TypeLiteral) + */ + @Override + public boolean visit(TypeLiteral node) { + if (!isActive()) { + return false; + } + + push(new PushClassLiteralValue(fCounter)); + + return true; + } + + /** + * @see ASTVisitor#visit(TypeMethodReference) + */ + @Override + public boolean visit(TypeMethodReference node) { + if (!isActive()) { + return true; + } + + try { + RemoteEvaluatorBuilder builder = makeBuilder(node); + builder.acceptMethodReference(node, node.resolveTypeBinding()); + RemoteEvaluator remoteEvaluator = builder.build(); + push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator)); + storeInstruction(); + } catch (JavaModelException | DebugException e) { + addErrorMessage(e.getMessage()); + setHasError(true); + } + + return false; + } + + /** + * @see ASTVisitor#visit(VariableDeclarationExpression) + */ + @Override + public boolean visit(VariableDeclarationExpression node) { + /* + * if it is in the code to execute, return false, we don't + * use the standard accept order. Otherwise, return true. We want to + * search the code to execute in variable declarations (in case of inner + * classes). + */ + if (!isActive()) { + return true; + } + for (Iterator iter = node.fragments().iterator(); iter.hasNext();) { + iter.next().accept(this); + } + return false; + } + + /** + * @see ASTVisitor#visit(VariableDeclarationFragment) + */ + @Override + public boolean visit(VariableDeclarationFragment node) { + /* + * if it is in the code to execute, return false, we don't + * use the standard accept order. Otherwise, return true. We want to + * search the code to execute in variable declarations (in case of inner + * classes). + */ + if (!isActive()) { + return true; + } + // get the type of the variable + ITypeBinding varTypeBinding; + ASTNode parent = node.getParent(); + switch (parent.getNodeType()) { + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + varTypeBinding = resolveTypeBinding(((VariableDeclarationExpression) parent) + .getType()); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + varTypeBinding = resolveTypeBinding(((VariableDeclarationStatement) parent) + .getType()); + break; + default: + setHasError(true); + addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Error_in_type_declaration_statement); + return false; + } + if (varTypeBinding == null) { + return false; + } + int typeDimension = varTypeBinding.getDimensions(); + ITypeBinding elementBinding = varTypeBinding; + if (typeDimension != 0) { + elementBinding = elementBinding.getElementType(); + } + + Expression initializer = node.getInitializer(); + push(new LocalVariableCreation(node.getName().getIdentifier(), + getTypeSignature(elementBinding), typeDimension, + elementBinding.isPrimitive(), initializer != null, fCounter)); + if (initializer != null) { + initializer.accept(this); + ITypeBinding expBindnig = initializer.resolveTypeBinding(); + if (expBindnig != null) { + if (checkAutoBoxing(expBindnig, varTypeBinding)) { + storeInstruction(); + } + } + } + + return false; + } + + /** + * @see ASTVisitor#visit(VariableDeclarationStatement) + */ + @Override + public boolean visit(VariableDeclarationStatement node) { + /* + * if it is in the code to execute, return false, we don't + * use the standard accept order. Otherwise, return true. We want to + * search the code to execute in variable declarations (in case of inner + * classes). + */ + if (!isActive()) { + return true; + } + for (Iterator iter = node.fragments().iterator(); iter.hasNext();) { + iter.next().accept(this); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * WildcardType) + */ + @Override + public boolean visit(WildcardType node) { + // we shouldn't have to do anything + return false; + } + + /** + * @see ASTVisitor#visit(WhileStatement) + */ + @Override + public boolean visit(WhileStatement node) { + if (!isActive()) { + return false; + } + + push(new NoOp(fCounter)); + return true; + } + + // -------------------------- + + private int getTypeId(Expression expression) { + ITypeBinding typeBinding = expression.resolveTypeBinding(); + if (typeBinding == null) { + return Instruction.T_undefined; + } + String typeName = typeBinding.getQualifiedName(); + if (typeBinding.isPrimitive()) { + return getPrimitiveTypeId(typeName); + } else if ("java.lang.String".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_String; + } else { + return Instruction.T_Object; + } + } + + private int getUnBoxedTypeId(Expression expression) { + ITypeBinding typeBinding = expression.resolveTypeBinding(); + if (typeBinding == null) { + return Instruction.T_undefined; + } + String typeName = typeBinding.getQualifiedName(); + if (typeBinding.isPrimitive()) { + return getPrimitiveTypeId(typeName); + } else if ("java.lang.String".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_String; + } else { + // un-boxing + if ("java.lang.Integer".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_int; + } else if ("java.lang.Character".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_char; + } else if ("java.lang.Byte".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_byte; + } else if ("java.lang.Short".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_short; + } else if ("java.lang.Long".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_long; + } else if ("java.lang.Float".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_float; + } else if ("java.lang.Double".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_double; + } else if ("java.lang.Boolean".equals(typeName)) { //$NON-NLS-1$ + return Instruction.T_boolean; + } + return Instruction.T_Object; + } + } + + private int getTypeId(Type type) { + if (type.isPrimitiveType()) { + return getPrimitiveTypeId(((PrimitiveType) type) + .getPrimitiveTypeCode().toString()); + } else if (type.isSimpleType()) { + SimpleType simpleType = (SimpleType) type; + if ("java.lang.String".equals(simpleType.getName().getFullyQualifiedName())) { //$NON-NLS-1$ + return Instruction.T_String; + } + return Instruction.T_Object; + } else if (type.isArrayType()) { + return Instruction.T_Object; + } else if (type.isParameterizedType()) { + return Instruction.T_Object; + } else { + return Instruction.T_undefined; + } + + } + + public static String removePrefixZerosAndUnderscores(String tokenString, + boolean isLong) { + char[] token = tokenString.toCharArray(); + int max = token.length; + int start = 0; + int end = max - 1; + if (isLong) { + end--; // remove the 'L' or 'l' + } + if (max > 1 && token[0] == '0') { + if (max > 2 && (token[1] == 'x' || token[1] == 'X')) { + start = 2; + } else if (max > 2 && (token[1] == 'b' || token[1] == 'B')) { + start = 2; + } else { + start = 1; + } + } + boolean modified = false; + boolean ignore = true; + loop: for (int i = start; i < max; i++) { + char currentChar = token[i]; + switch (currentChar) { + case '0': + // this is a prefix '0' + if (ignore && !modified && (i < end)) { + modified = true; + } + break; + case '_': + modified = true; + break loop; + default: + ignore = false; + } + } + if (!modified) { + return tokenString; + } + ignore = true; + StringBuilder buffer = new StringBuilder(); + buffer.append(token, 0, start); + loop: for (int i = start; i < max; i++) { + char currentChar = token[i]; + switch (currentChar) { + case '0': + if (ignore && (i < end)) { + // this is a prefix '0' + continue loop; + } + break; + case '_': + continue loop; + default: + ignore = false; + } + buffer.append(currentChar); + } + return buffer.toString(); + } + + /** + * Returns the method signature given the binding and the enclosing type + * signature (if there is one) + * + * @param methodBinding + * the binding to get the signature for + * @param enclosingTypeSignature + * the enclosing type signature or null + * @return the method signature for the given binding and enclosing type + * signature + */ + private String getMethodSignature(IMethodBinding methodBinding, + String enclosingTypeSignature) { + methodBinding = methodBinding.getMethodDeclaration(); + ITypeBinding[] parameterTypes = methodBinding.getParameterTypes(); + int offset = 0; + int argCount; + String[] parameterSignatures; + if (enclosingTypeSignature == null) { + argCount = parameterTypes.length; + parameterSignatures = new String[argCount]; + } else { + offset = 1; + argCount = parameterTypes.length + 1; + parameterSignatures = new String[argCount]; + parameterSignatures[0] = enclosingTypeSignature; + } + for (int i = 0; i < parameterTypes.length; i++) { + parameterSignatures[i + offset] = getTypeSignature(parameterTypes[i]); + } + String signature = Signature.createMethodSignature(parameterSignatures, + getTypeSignature(methodBinding.getReturnType())); + return signature; + } + + public static int getPrimitiveTypeId(String typeName) { + switch (typeName.charAt(0)) { + case 'b': // byte or boolean + switch (typeName.charAt(1)) { + case 'o': // boolean; + return Instruction.T_boolean; + case 'y': // byte + return Instruction.T_byte; + } + break; + case 'c': // char + return Instruction.T_char; + case 'd': // double + return Instruction.T_double; + case 'f': // float + return Instruction.T_float; + case 'i': // int + return Instruction.T_int; + case 'l': // long + return Instruction.T_long; + case 'n': + return Instruction.T_null; + case 's': // short + return Instruction.T_short; + case 'v': // void + return Instruction.T_void; + } + return Instruction.T_undefined; + } + + /** + * Resolves and returns the type binding from the given expression reporting + * an error if the binding is null. + * + * @param expression + * expression to resolve type binding for + * @return type binding or null if not available + */ + private ITypeBinding resolveTypeBinding(Expression expression) { + ITypeBinding typeBinding = expression.resolveTypeBinding(); + if (typeBinding == null) { + setHasError(true); + addErrorMessage(MessageFormat.format( + EvaluationEngineMessages.ASTInstructionCompiler_3, + new Object[] { expression.toString() })); + } + return typeBinding; + } + + /** + * Resolves and returns the type binding for the give type reporting an + * error if the binding is null. + * + * @param type + * type to resolve binding for + * @return type binding or null if not available + */ + private ITypeBinding resolveTypeBinding(Type type) { + ITypeBinding typeBinding = type.resolveBinding(); + if (typeBinding == null) { + setHasError(true); + addErrorMessage(MessageFormat.format( + EvaluationEngineMessages.ASTInstructionCompiler_3, + new Object[] { type.toString() })); + } + return typeBinding; + } + + /** + * Resolves and returns the binding for the given name reporting an error if + * the binding is null. + * + * @param name + * name to resolve binding for + * @return binding or null if not available + */ + private IBinding resolveBinding(Name name) { + IBinding binding = name.resolveBinding(); + if (binding == null) { + setHasError(true); + addErrorMessage(MessageFormat.format( + EvaluationEngineMessages.ASTInstructionCompiler_5, + new Object[] { name.getFullyQualifiedName() })); + } + return binding; + } + + /** + * Resolves and returns the type binding for the given name reporting an + * error if the binding is null. + * + * @param name + * name to resolve type binding for + * @return type binding or null if not available + */ + private ITypeBinding resolveTypeBinding(Name name) { + ITypeBinding typeBinding = name.resolveTypeBinding(); + if (typeBinding == null) { + setHasError(true); + addErrorMessage(MessageFormat.format( + EvaluationEngineMessages.ASTInstructionCompiler_3, + new Object[] { name.getFullyQualifiedName() })); + } + return typeBinding; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java new file mode 100644 index 0000000000..e02bc936f9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * Copyright (c) 2005, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.text.MessageFormat; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdi.internal.TypeImpl; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionsEvaluationMessages; + +import com.sun.jdi.InvocationException; + +/** + * Common runtime context code for class loading and cache of class + * loader/java.lang.Class. + * + * @since 3.2 + */ + +public abstract class AbstractRuntimeContext implements IRuntimeContext { + + /** + * Cache of class loader for this runtime context + */ + private IJavaObject fClassLoader; + + /** + * Cache of java.lang.Class type + */ + private IJavaClassType fJavaLangClass; + + /** + * Java project context + */ + protected IJavaProject fProject; + + public static final String CLASS = "java.lang.Class"; //$NON-NLS-1$ + public static final String FOR_NAME = "forName"; //$NON-NLS-1$ + public static final String FOR_NAME_SIGNATURE = "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"; //$NON-NLS-1$ + + public AbstractRuntimeContext(IJavaProject project) { + fProject = project; + } + + /** + * Returns the class loader used to load classes for this runtime context or + * null when loaded by the bootstrap loader + * + * @return the class loader used to load classes for this runtime context or + * null when loaded by the bootstrap loader + * @throws CoreException + * if unable to resolve a class loader + */ + protected IJavaObject getClassLoaderObject() throws CoreException { + if (fClassLoader == null) { + fClassLoader = getReceivingType().getClassLoaderObject(); + } + return fClassLoader; + } + + /** + * Return the java.lang.Class type. + * + * @return the java.lang.Class type + * @throws CoreException + * if unable to retrieve the type + */ + protected IJavaClassType getJavaLangClass() throws CoreException { + if (fJavaLangClass == null) { + IJavaType[] types = getVM().getJavaTypes(CLASS); + if (types == null || types.length != 1) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + MessageFormat + .format(InstructionsEvaluationMessages.Instruction_No_type, + new Object[] { CLASS }), null)); + } + fJavaLangClass = (IJavaClassType) types[0]; + } + return fJavaLangClass; + } + + /** + * Invokes Class.classForName(String, boolean, ClassLoader) on the target to + * force load the specified class. + * + * @param qualifiedName + * name of class to load + * @param loader + * the class loader to use or null if the bootstrap + * loader + * @return the loaded class + * @throws CoreException + * if loading fails + */ + protected IJavaClassObject classForName(String qualifiedName, + IJavaObject loader) throws CoreException { + String tname = qualifiedName; + if (tname.startsWith("[")) { //$NON-NLS-1$ + tname = TypeImpl.signatureToName(qualifiedName); + } + IJavaType[] types = getVM().getJavaTypes(tname); + if (types != null && types.length > 0) { + // find the one with the right class loader + for (IJavaType type2 : types) { + if ( type2 instanceof IJavaReferenceType){ + IJavaReferenceType type = (IJavaReferenceType) type2; + IJavaObject cloader = type.getClassLoaderObject(); + if (isCompatibleLoader(loader, cloader)) { + return type.getClassObject(); + } + } + } + } + IJavaValue loaderArg = loader; + if (loader == null) { + loaderArg = getVM().nullValue(); + } + // prevent the name string from being collected during the class lookup + // call + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=301412 + final IJavaValue name = getVM().newValue(qualifiedName); + ((IJavaObject) name).disableCollection(); + IJavaValue[] args = new IJavaValue[] { name, getVM().newValue(true), + loaderArg }; + try { + return (IJavaClassObject) getJavaLangClass().sendMessage(FOR_NAME, + FOR_NAME_SIGNATURE, args, getThread()); + } catch (CoreException e) { + if (e.getStatus().getException() instanceof InvocationException) { + // Don't throw ClassNotFoundException + if (((InvocationException) e.getStatus().getException()) + .exception().referenceType().name() + .equals("java.lang.ClassNotFoundException")) { //$NON-NLS-1$ + return null; + } + } + throw e; + } finally { + ((IJavaObject) name).enableCollection(); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#classForName + * (java.lang.String) + */ + @Override + public IJavaClassObject classForName(String name) throws CoreException { + return classForName(name, getClassLoaderObject()); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getProject + * () + */ + @Override + public IJavaProject getProject() { + return fProject; + } + + /** + * Returns whether the class loaded by the otherLoader is + * compatible with the receiver's class loader. To be compatible, the + * other's loader must be the same or a parent of the receiver's loader. + * + * @param recLoader + * class loader of receiver + * @param otherLoader + * class loader of other class + * @return whether compatible + */ + private boolean isCompatibleLoader(IJavaObject recLoader, + IJavaObject otherLoader) throws CoreException { + if (recLoader == null || otherLoader == null) { + // if either class is a bootstrap loader, then they are compatible + // since all loaders + // stem from the bootstrap loader + return true; + } + if (recLoader.equals(otherLoader)) { + return true; + } + // check parent loaders + IJavaObject parent = getParentLoader(recLoader); + while (parent != null) { + if (parent.equals(otherLoader)) { + return true; + } + parent = getParentLoader(parent); + } + return false; + } + + /** + * Returns the parent class loader of the given class loader object or + * null if none. + * + * @param loader + * class loader object + * @return parent class loader or null + * @throws CoreException + */ + private IJavaObject getParentLoader(IJavaObject loader) + throws CoreException { + // to avoid message send, first check for 'parent' field + IJavaFieldVariable field = loader.getField("parent", false); //$NON-NLS-1$ + if (field != null) { + IJavaValue value = (IJavaValue) field.getValue(); + if (value.isNull()) { + return null; + } + return (IJavaObject) value; + } + IJavaValue result = loader + .sendMessage( + "getParent", "()Ljava/lang/ClassLoader;", null, getThread(), false); //$NON-NLS-1$ //$NON-NLS-2$ + if (result.isNull()) { + return null; + } + return (IJavaObject) result; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java new file mode 100644 index 0000000000..cdb9df69f7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable; + +/** + * Context for evaluation of an expression in the receiver context of an array. + */ +public class ArrayRuntimeContext extends AbstractRuntimeContext { + + /** + * Name used for temp variable referring to array (replaces 'this'). The + * same length as "this" so it does not affect code assist. + */ + public static String ARRAY_THIS_VARIABLE = "_a_t"; //$NON-NLS-1$ + + private IJavaArray fArray = null; + private IJavaReferenceType fReceivingType = null; + private IJavaThread fThread = null; + private IJavaVariable fLocalArray = null; + + public ArrayRuntimeContext(IJavaArray arrayObject, IJavaThread thread, + IJavaProject project) { + super(project); + fArray = arrayObject; + fThread = thread; + fLocalArray = new JDIPlaceholderVariable(ARRAY_THIS_VARIABLE, + arrayObject); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getVM() + */ + @Override + public IJavaDebugTarget getVM() { + return (IJavaDebugTarget) fArray.getDebugTarget(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThis() + */ + @Override + public IJavaObject getThis() throws CoreException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext# + * getReceivingType() + */ + @Override + public IJavaReferenceType getReceivingType() throws CoreException { + if (fReceivingType == null) { + IJavaType[] javaTypes = getVM().getJavaTypes("java.lang.Object"); //$NON-NLS-1$ + if (javaTypes.length > 0) { + fReceivingType = (IJavaReferenceType) javaTypes[0]; + } else { + IStatus status = new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.INTERNAL_ERROR, + EvaluationEngineMessages.ArrayRuntimeContext_0, null); + throw new CoreException(status); + } + } + return fReceivingType; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getLocals + * () + */ + @Override + public IJavaVariable[] getLocals() throws CoreException { + return new IJavaVariable[] { fLocalArray }; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThread + * () + */ + @Override + public IJavaThread getThread() { + return fThread; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor + * () + */ + @Override + public boolean isConstructor() throws CoreException { + return false; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/BinaryBasedSourceGenerator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/BinaryBasedSourceGenerator.java new file mode 100644 index 0000000000..b44108a8e6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/BinaryBasedSourceGenerator.java @@ -0,0 +1,622 @@ +/******************************************************************************* + * Copyright (c) 2000, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Holger Schill - Bug 455199 - [debug] Debugging doesn't work properly when inner classes are used + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.internal.debug.core.model.JDIReferenceType; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Method; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; + +public class BinaryBasedSourceGenerator { + + private static final String RUN_METHOD_NAME = "___run"; //$NON-NLS-1$ + private static final String EVAL_METHOD_NAME = "___eval"; //$NON-NLS-1$ + private static final String ANONYMOUS_CLASS_NAME = "___EvalClass"; //$NON-NLS-1$ + + private final String[] fLocalVariableTypeNames; + + private final String[] fLocalVariableNames; + + private final boolean fIsInStaticMethod; + + private StringBuilder fSource; + + private int fRunMethodStartOffset; + private int fRunMethodLength; + private int fCodeSnippetPosition; + + private String fCompilationUnitName; + + /** + * Level of source code to generate (major, minor). For example 1 and 4 + * indicates 1.4. + */ + private final int fSourceMajorLevel; + private int fSourceMinorLevel; + + public BinaryBasedSourceGenerator(String[] localTypesNames, + String[] localVariables, boolean isInStaticMethod, + String sourceLevel) { + fLocalVariableTypeNames = localTypesNames; + fLocalVariableNames = localVariables; + fIsInStaticMethod = isInStaticMethod; + int index = sourceLevel.indexOf('.'); + String num; + if (index != -1) { + num = sourceLevel.substring(0, index); + } else { + num = sourceLevel; + } + fSourceMajorLevel = Integer.parseInt(num); + if (index != -1) { + num = sourceLevel.substring(index + 1); + fSourceMinorLevel = Integer.parseInt(num); + } else { + fSourceMinorLevel = 0; + } + } + + /** + * Build source for an object value (instance context) + */ + public void buildSource(JDIReferenceType referenceType) { + ReferenceType reference = (ReferenceType) referenceType + .getUnderlyingType(); + fSource = buildTypeDeclaration(reference, buildRunMethod(reference), + null); + } + + /** + * Build source for a class type (static context) + */ + public void buildSourceStatic(IJavaReferenceType type) { + Type underlyingType = ((JDIReferenceType) type).getUnderlyingType(); + if (!(underlyingType instanceof ReferenceType)) { + return; + } + ReferenceType refType = (ReferenceType) underlyingType; + fSource = buildTypeDeclaration(refType, buildRunMethod(refType), null, + false); + String packageName = getPackageName(refType.name()); + if (packageName != null) { + fSource.insert(0, "package " + packageName + ";\n"); //$NON-NLS-1$ //$NON-NLS-2$ + fCodeSnippetPosition += 10 + packageName.length(); + } + fCompilationUnitName = getSimpleName(refType.name()); + } + + protected String getUniqueMethodName(String methodName, ReferenceType type) { + List methods = type.methodsByName(methodName); + while (!methods.isEmpty()) { + methodName += '_'; + methods = type.methodsByName(methodName); + } + return methodName; + } + + private StringBuilder buildRunMethod(ReferenceType type) { + StringBuilder source = new StringBuilder(); + + if (isInStaticMethod()) { + source.append("static "); //$NON-NLS-1$ + } + + source.append("void "); //$NON-NLS-1$ + source.append(getUniqueMethodName(RUN_METHOD_NAME, type)); + source.append('('); + for (int i = 0, length = fLocalVariableNames.length; i < length; i++) { + source.append(getDotName(fLocalVariableTypeNames[i])); + source.append(' '); + source.append(fLocalVariableNames[i]); + if (i + 1 < length) + { + source.append(", "); //$NON-NLS-1$ + } + } + source.append(") throws Throwable {"); //$NON-NLS-1$ + source.append('\n'); + fCodeSnippetPosition = source.length(); + fRunMethodStartOffset = fCodeSnippetPosition; + + source.append('\n'); + source.append('}').append('\n'); + fRunMethodLength = source.length(); + return source; + } + + private StringBuilder buildTypeDeclaration(ReferenceType referenceType, + StringBuilder buffer, String nestedTypeName) { + + Field thisField = null; + + for (Field field : referenceType.visibleFields()) { + if (field.name().startsWith("this$")) { //$NON-NLS-1$ + thisField = field; + break; + } + } + + StringBuilder source = buildTypeDeclaration(referenceType, buffer, + nestedTypeName, thisField != null); + + if (thisField == null) { + String packageName = getPackageName(referenceType.name()); + if (packageName != null) { + source.insert(0, "package " + packageName + ";\n"); //$NON-NLS-1$ //$NON-NLS-2$ + fCodeSnippetPosition += 10 + packageName.length(); + } + if (isAnonymousTypeName(referenceType.name())) { + fCompilationUnitName = ANONYMOUS_CLASS_NAME; + } else { + fCompilationUnitName = getSimpleName(referenceType.name()); + } + } else { + try { + return buildTypeDeclaration((ReferenceType) thisField.type(), + source, referenceType.name()); + } catch (ClassNotLoadedException e) { + } + } + + return source; + } + + private StringBuilder buildTypeDeclaration(ReferenceType referenceType, + StringBuilder buffer, String nestedTypeName, + boolean hasEnclosingInstance) { + StringBuilder source = new StringBuilder(); + + String typeName = referenceType.name(); + + boolean isAnonymousType = isAnonymousTypeName(typeName); + + if (isAnonymousType) { + ClassType classType = (ClassType) referenceType; + + List interfaceList = classType.interfaces(); + String superClassName = classType.superclass().name(); + if (hasEnclosingInstance) { + source.append("void "); //$NON-NLS-1$ + source.append(getUniqueMethodName(EVAL_METHOD_NAME, + referenceType)); + source.append("() {\nnew "); //$NON-NLS-1$ + if (!interfaceList.isEmpty()) { + source.append(getDotName(interfaceList + .get(0).name())); + } else { + source.append(getDotName(superClassName)); + } + source.append("()"); //$NON-NLS-1$ + } else { + source.append("public class ").append(ANONYMOUS_CLASS_NAME).append(" "); //$NON-NLS-1$ //$NON-NLS-2$ + if (!interfaceList.isEmpty()) { + source.append(" implements ").append(getDotName(interfaceList.get(0).name())); //$NON-NLS-1$ + } else { + source.append(" extends ").append(getDotName(superClassName)); //$NON-NLS-1$ + } + } + + } else { + if (referenceType.isFinal()) { + source.append("final "); //$NON-NLS-1$ + } + + if (referenceType.isStatic()) { + source.append("static "); //$NON-NLS-1$ + } + + if (referenceType instanceof ClassType) { + ClassType classType = (ClassType) referenceType; + + if (classType.isAbstract()) { + source.append("abstract "); //$NON-NLS-1$ + } + + source.append("class "); //$NON-NLS-1$ + + source.append(getSimpleName(typeName)).append(' '); + + String genericSignature = referenceType.genericSignature(); + if (genericSignature != null + && isSourceLevelGreaterOrEqual(1, 5)) { + String[] typeParameters = Signature + .getTypeParameters(genericSignature); + if (typeParameters.length > 0) { + source.append('<'); + source.append(Signature + .getTypeVariable(typeParameters[0])); + String[] typeParameterBounds = Signature + .getTypeParameterBounds(typeParameters[0]); + source.append(" extends ").append(Signature.toString(typeParameterBounds[0]).replace('/', '.')); //$NON-NLS-1$ + for (int i = 1; i < typeParameterBounds.length; i++) { + source.append(" & ").append(Signature.toString(typeParameterBounds[i]).replace('/', '.')); //$NON-NLS-1$ + } + for (int j = 1; j < typeParameters.length; j++) { + source.append(',') + .append(Signature + .getTypeVariable(typeParameters[j])); + typeParameterBounds = Signature + .getTypeParameterBounds(typeParameters[j]); + source.append(" extends ").append(Signature.toString(typeParameterBounds[0]).replace('/', '.')); //$NON-NLS-1$ + for (int i = 1; i < typeParameterBounds.length; i++) { + source.append(" & ").append(Signature.toString(typeParameterBounds[i]).replace('/', '.')); //$NON-NLS-1$ + } + } + source.append("> "); //$NON-NLS-1$ + } + String[] superClassInterfaces = SignatureExt + .getTypeSuperClassInterfaces(genericSignature); + int length = superClassInterfaces.length; + if (length > 0) { + source.append("extends ").append(Signature.toString(superClassInterfaces[0]).replace('/', '.')); //$NON-NLS-1$ + if (length > 1) { + source.append(" implements ").append(Signature.toString(superClassInterfaces[1]).replace('/', '.')); //$NON-NLS-1$ + for (int i = 2; i < length; i++) { + source.append(',') + .append(Signature + .toString(superClassInterfaces[1])); + } + } + } + } else { + + ClassType superClass = classType.superclass(); + if (superClass != null) { + source.append("extends ").append(getDotName(superClass.name())).append(' '); //$NON-NLS-1$ + } + + List interfaces; + try { + interfaces = classType.interfaces(); + } catch (ClassNotPreparedException e) { + return new StringBuilder(); + } + if (!interfaces.isEmpty()) { + source.append("implements "); //$NON-NLS-1$ + Iterator iterator = interfaces.iterator(); + InterfaceType interface_ = iterator + .next(); + source.append(getDotName(interface_.name())); + while (iterator.hasNext()) { + source.append(',') + .append(getDotName(iterator + .next().name())); + } + } + } + } else if (referenceType instanceof InterfaceType) { + if (buffer != null) { + source.append("abstract class "); //$NON-NLS-1$ + source.append(getSimpleName(typeName)).append("___ implements "); //$NON-NLS-1$ + source.append(typeName.replace('$', '.')).append(" {\n"); //$NON-NLS-1$ + fCodeSnippetPosition += source.length(); + source.append(buffer).append("}\n"); //$NON-NLS-1$ + return source; + } + source.append("interface "); //$NON-NLS-1$ + source.append(getSimpleName(typeName)); + } + } + + source.append(" {\n"); //$NON-NLS-1$ + + if (buffer != null && !(referenceType instanceof InterfaceType)) { + fCodeSnippetPosition += source.length(); + source.append(buffer); + } + + for (Field field : referenceType.fields()) { + if (!field.name().startsWith("this$")) { //$NON-NLS-1$ + source.append(buildFieldDeclaration(field)); + } + } + + for (Method method : referenceType.methods()) { + if (!method.isConstructor() && !method.isStaticInitializer() + && !method.isBridge()) { + source.append(buildMethodDeclaration(method)); + } + } + + List nestedTypes = referenceType.nestedTypes(); + if (nestedTypeName == null) { + for (ReferenceType nestedType : nestedTypes) { + if (isADirectInnerType(typeName, nestedType.name())) { + source.append(buildTypeDeclaration(nestedType, null, null, + true)); + } + } + } else { + for (ReferenceType nestedType : nestedTypes) { + if (!nestedTypeName.equals(nestedType.name()) + && isADirectInnerType(typeName, nestedType.name())) { + source.append(buildTypeDeclaration(nestedType, null, null, + true)); + } + } + } + + if (isAnonymousType && hasEnclosingInstance) { + source.append("};\n"); //$NON-NLS-1$ + } + + source.append("}\n"); //$NON-NLS-1$ + + return source; + } + + private StringBuilder buildFieldDeclaration(Field field) { + StringBuilder source = new StringBuilder(); + + if (field.isFinal()) { + source.append("final "); //$NON-NLS-1$ + } + + if (field.isStatic()) { + source.append("static "); //$NON-NLS-1$ + } + + if (field.isPublic()) { + source.append("public "); //$NON-NLS-1$ + } else if (field.isPrivate()) { + source.append("private "); //$NON-NLS-1$ + } else if (field.isProtected()) { + source.append("protected "); //$NON-NLS-1$ + } + + source.append(getDotName(field.typeName())).append(' ') + .append(field.name()).append(';').append('\n'); + + return source; + } + + private StringBuilder buildMethodDeclaration(Method method) { + StringBuilder source = new StringBuilder(); + + if (method.isFinal()) { + source.append("final "); //$NON-NLS-1$ + } + + if (method.isStatic()) { + source.append("static "); //$NON-NLS-1$ + } + + if (method.isNative()) { + source.append("native "); //$NON-NLS-1$ + } else if (method.isAbstract()) { + source.append("abstract "); //$NON-NLS-1$ + } + + if (method.isPublic()) { + source.append("public "); //$NON-NLS-1$ + } else if (method.isPrivate()) { + source.append("private "); //$NON-NLS-1$ + } else if (method.isProtected()) { + source.append("protected "); //$NON-NLS-1$ + } + + String genericSignature = method.genericSignature(); + if (genericSignature != null && isSourceLevelGreaterOrEqual(1, 5)) { + String[] typeParameters = Signature + .getTypeParameters(genericSignature); + if (typeParameters.length > 0) { + source.append('<'); + source.append(Signature.getTypeVariable(typeParameters[0])); + String[] typeParameterBounds = Signature + .getTypeParameterBounds(typeParameters[0]); + source.append(" extends ").append(Signature.toString(typeParameterBounds[0]).replace('/', '.')); //$NON-NLS-1$ + for (int i = 1; i < typeParameterBounds.length; i++) { + source.append(" & ").append(Signature.toString(typeParameterBounds[i]).replace('/', '.')); //$NON-NLS-1$ + } + for (int j = 1; j < typeParameters.length; j++) { + source.append(',').append( + Signature.getTypeVariable(typeParameters[j])); + typeParameterBounds = Signature + .getTypeParameterBounds(typeParameters[j]); + source.append(" extends ").append(Signature.toString(typeParameterBounds[0]).replace('/', '.')); //$NON-NLS-1$ + for (int i = 1; i < typeParameterBounds.length; i++) { + source.append(" & ").append(Signature.toString(typeParameterBounds[i]).replace('/', '.')); //$NON-NLS-1$ + } + } + source.append("> "); //$NON-NLS-1$ + } + + source.append( + Signature.toString( + Signature.getReturnType(genericSignature)).replace( + '/', '.')).append(' ').append(method.name()) + .append('('); + + String[] parameterTypes = Signature + .getParameterTypes(genericSignature); + int i = 0; + if (parameterTypes.length != 0) { + source.append( + Signature.toString(parameterTypes[0]).replace('/', '.')) + .append(" arg").append(i++); //$NON-NLS-1$ + if (method.isVarArgs()) { + for (int j = 1; j < parameterTypes.length - 1; j++) { + source.append(',') + .append(Signature.toString(parameterTypes[j]) + .replace('/', '.')) + .append(" arg").append(i++); //$NON-NLS-1$ + } + String typeName = Signature.toString( + parameterTypes[parameterTypes.length - 1]).replace( + '/', '.'); + source.append(',') + .append(typeName.substring(0, typeName.length() - 2)) + .append("...").append(" arg").append(i++); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + for (int j = 1; j < parameterTypes.length; j++) { + source.append(',') + .append(Signature.toString(parameterTypes[j]) + .replace('/', '.')) + .append(" arg").append(i++); //$NON-NLS-1$ + } + } + } + source.append(')'); + } else { + source.append(getDotName(method.returnTypeName())).append(' ') + .append(method.name()).append('('); + + List arguments = method.argumentTypeNames(); + int i = 0; + if (!arguments.isEmpty()) { + Iterator iterator = arguments.iterator(); + source.append(getDotName(iterator.next())) + .append(" arg").append(i++); //$NON-NLS-1$ + if (method.isVarArgs()) { + while (iterator.hasNext()) { + source.append(','); + String argName = getDotName(iterator.next()); + if (!iterator.hasNext()) { + source.append( + argName.substring(0, argName.length() - 2)) + .append("..."); //$NON-NLS-1$ + } else { + source.append(argName); + } + source.append(" arg").append(i++); //$NON-NLS-1$ + } + } else { + while (iterator.hasNext()) { + source.append(',') + .append(getDotName(iterator.next())) + .append(" arg").append(i++); //$NON-NLS-1$ + } + } + } + source.append(')'); + } + + if (method.isAbstract() || method.isNative()) { + // No body for abstract and native methods + source.append(";\n"); //$NON-NLS-1$ + } else { + source.append('{').append('\n'); + source.append(getReturnStatement(method.returnTypeName())); + source.append('}').append('\n'); + } + + return source; + } + + private String getReturnStatement(String returnTypeName) { + String typeName = getSimpleName(returnTypeName); + if (typeName.charAt(typeName.length() - 1) == ']') { + return "return null;\n"; //$NON-NLS-1$ + } + switch (typeName.charAt(0)) { + case 'v': + return ""; //$NON-NLS-1$ + case 'b': + if (typeName.length() >= 1 && typeName.charAt(1) == 'o') { + return "return false;\n"; //$NON-NLS-1$ + } + case 's': + case 'c': + case 'i': + case 'l': + case 'd': + case 'f': + return "return 0;\n"; //$NON-NLS-1$ + default: + return "return null;\n"; //$NON-NLS-1$ + } + } + + private String getDotName(String typeName) { + return typeName.replace('$', '.'); + } + + private boolean isAnonymousTypeName(String typeName) { + char char0 = getSimpleName(typeName).charAt(0); + return '0' <= char0 && char0 <= '9'; + } + + private String getSimpleName(String qualifiedName) { + int pos = qualifiedName.lastIndexOf('$'); + if (pos == -1) { + pos = qualifiedName.lastIndexOf('.'); + } + return ((pos == -1) ? qualifiedName : qualifiedName.substring(pos + 1)); + } + + private String getPackageName(String qualifiedName) { + int pos = qualifiedName.lastIndexOf('.'); + return ((pos == -1) ? null : qualifiedName.substring(0, pos)); + } + + private boolean isADirectInnerType(String typeName, String nestedTypeName) { + String end = nestedTypeName.substring(typeName.length() + 1); + return end.indexOf('$') == -1; + } + + private boolean isInStaticMethod() { + return fIsInStaticMethod; + } + + public StringBuilder getSource() { + return fSource; + } + + public int getCodeSnippetPosition() { + return fCodeSnippetPosition; + } + + public String getCompilationUnitName() { + return fCompilationUnitName; + } + + public int getSnippetStart() { + return fCodeSnippetPosition - 2; + } + + public int getRunMethodStart() { + return fCodeSnippetPosition - fRunMethodStartOffset; + } + + public int getRunMethodLength() { + return fRunMethodLength; + } + + /** + * Returns whether the source to be generated is greater than or equal to + * the given source level. + * + * @param major + * major level - e.g. 1 from 1.4 + * @param minor + * minor level - e.g. 4 from 1.4 + * @return + */ + public boolean isSourceLevelGreaterOrEqual(int major, int minor) { + return (fSourceMajorLevel > major) + || (fSourceMajorLevel == major && fSourceMinorLevel >= minor); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java new file mode 100644 index 0000000000..ae7589025c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + * Jesper Steen Moller - 427089: [1.8] Change value in Variables view with lambda or method reference + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.osgi.util.NLS; + +public class EvaluationEngineMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationEngineMessages";//$NON-NLS-1$ + + public static String ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3; + public static String ASTInstructionCompiler_Unrecognized_assignment_operator____4; + + public static String ASTInstructionCompiler_Catch_clause_cannot_be_used_in_an_evaluation_expression_6; + public static String ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_7; + public static String ASTInstructionCompiler_Constructor_of_a_local_type_cannot_be_used_in_an_evaluation_expression_8; + public static String ASTInstructionCompiler_this_constructor_invocation_cannot_be_used_in_an_evaluation_expression_9; + public static String ASTInstructionCompiler_Error_in_type_declaration_statement; + public static String ASTInstructionCompiler_Unrecognized_infix_operator____13; + + public static String ASTInstructionCompiler_unrecognized_postfix_operator____15; + public static String ASTInstructionCompiler_unrecognized_prefix_operator____16; + + public static String ASTInstructionCompiler_super_constructor_invocation_cannot_be_used_in_an_evaluation_expression_19; + public static String ASTInstructionCompiler_Try_statement_cannot_be_used_in_an_evaluation_expression_23; + public static String ASTInstructionCompiler_Type_declaration_cannot_be_used_in_an_evaluation_expression_24; + public static String ASTInstructionCompiler_Type_declaration_statement_cannot_be_used_in_an_evaluation_expression_25; + public static String ASTInstructionCompiler_Local_type_array_instance_creation_cannot_be_used_in_an_evaluation_expression_29; + public static String ASTInstructionCompiler_Constructor_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_30; + public static String ASTInstructionCompiler_Qualified_local_type_field_access_cannot_be_used_in_an_evaluation_expression_31; + public static String ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32; + public static String ASTInstructionCompiler_Must_explicitly_qualify_the_allocation_with_an_instance_of_the_enclosing_type_33; + public static String ASTEvaluationEngine_Evaluations_must_contain_either_an_expression_or_a_block_of_well_formed_statements_1; + + public static String InterpreterVariable_setValue_String__not_supported_for_interpreter_variable_1; + public static String InterpreterVariable_verifyValue_IValue__not_supported_for_interpreter_variable_2; + public static String InterpreterVariable_verifyValue_String__not_supported_for_interpreter_variable_3; + + public static String ASTEvaluationEngine_AST_evaluation_engine_cannot_evaluate_expression; + public static String ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation; + public static String ASTEvaluationEngine_Cannot_perform_nested_evaluations; + public static String ASTInstructionCompiler_3; + public static String ASTInstructionCompiler_0; + public static String ASTInstructionCompiler_1; + public static String ASTInstructionCompiler_2; + + public static String ASTInstructionCompiler_4; + public static String ASTInstructionCompiler_5; + + public static String ASTInstructionCompiler_Lambda_expressions_cannot_be_used_in_an_evaluation_expression; + public static String ASTInstructionCompiler_Reference_expressions_cannot_be_used_in_an_evaluation_expression; + public static String ASTInstructionCompiler_Switch_expressions_cannot_be_used_in_an_evaluation_expression; + public static String ASTInstructionCompiler_Functional_expressions_cannot_be_evaluated_inside_local_and_or_anonymous_classes; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, EvaluationEngineMessages.class); + } + + public static String ASTEvaluationEngine_1; + public static String ArrayRuntimeContext_0; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties new file mode 100644 index 0000000000..61f40cd7b4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties @@ -0,0 +1,60 @@ +############################################################################### +# Copyright (c) 2000, 2019 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jesper Steen Moller - 427089: [1.8] Change value in Variables view with lambda or method reference +############################################################################### + +ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3=Assert statement cannot be used in an evaluation expression +ASTInstructionCompiler_Unrecognized_assignment_operator____4=Unrecognized assignment operator : + +ASTInstructionCompiler_Catch_clause_cannot_be_used_in_an_evaluation_expression_6=Catch clause cannot be used in an evaluation expression +ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_7=Anonymous type declaration cannot be used in an evaluation expression +ASTInstructionCompiler_Constructor_of_a_local_type_cannot_be_used_in_an_evaluation_expression_8=Constructor of a local type cannot be used in an evaluation expression +ASTInstructionCompiler_this_constructor_invocation_cannot_be_used_in_an_evaluation_expression_9=this constructor invocation cannot be used in an evaluation expression +ASTInstructionCompiler_Error_in_type_declaration_statement= Error in declaration statement. +ASTInstructionCompiler_Unrecognized_infix_operator____13=Unrecognized infix operator : + +ASTInstructionCompiler_unrecognized_postfix_operator____15=unrecognized postfix operator : +ASTInstructionCompiler_unrecognized_prefix_operator____16=unrecognized prefix operator : + +ASTInstructionCompiler_super_constructor_invocation_cannot_be_used_in_an_evaluation_expression_19=super constructor invocation cannot be used in an evaluation expression +ASTInstructionCompiler_Try_statement_cannot_be_used_in_an_evaluation_expression_23=Try statement cannot be used in an evaluation expression +ASTInstructionCompiler_Type_declaration_cannot_be_used_in_an_evaluation_expression_24=Type declaration cannot be used in an evaluation expression +ASTInstructionCompiler_Type_declaration_statement_cannot_be_used_in_an_evaluation_expression_25=Type declaration statement cannot be used in an evaluation expression +ASTInstructionCompiler_Local_type_array_instance_creation_cannot_be_used_in_an_evaluation_expression_29=Local type array instance creation cannot be used in an evaluation expression +ASTInstructionCompiler_Constructor_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_30=Constructor which contains a local type as parameter cannot be used in an evaluation expression +ASTInstructionCompiler_Qualified_local_type_field_access_cannot_be_used_in_an_evaluation_expression_31=Qualified local type field access cannot be used in an evaluation expression +ASTInstructionCompiler_Method_which_contains_a_local_type_as_parameter_cannot_be_used_in_an_evaluation_expression_32=Method which contains a local type as parameter cannot be used in an evaluation expression +ASTInstructionCompiler_Must_explicitly_qualify_the_allocation_with_an_instance_of_the_enclosing_type_33=Must explicitly qualify the allocation with an instance of the enclosing type +ASTEvaluationEngine_Evaluations_must_contain_either_an_expression_or_a_block_of_well_formed_statements_1=Evaluations must contain either an expression or a block of well-formed statements + +InterpreterVariable_setValue_String__not_supported_for_interpreter_variable_1=setValue(String) not supported for interpreter variable +InterpreterVariable_verifyValue_IValue__not_supported_for_interpreter_variable_2=verifyValue(IValue) not supported for interpreter variable +InterpreterVariable_verifyValue_String__not_supported_for_interpreter_variable_3=verifyValue(String) not supported for interpreter variable + +ASTEvaluationEngine_AST_evaluation_engine_cannot_evaluate_expression=The AST evaluation engine cannot evaluate this expression. +ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation=An unknown error occurred during evaluation +ASTEvaluationEngine_Cannot_perform_nested_evaluations=Cannot perform nested evaluations. + +ASTInstructionCompiler_3=Unable to resolve type binding for: {0} +ASTInstructionCompiler_0=Enum declaration cannot be used in an evaluation expression +ASTInstructionCompiler_1=Unable to resolve type binding of constructor: {0} +ASTInstructionCompiler_2=Unable to resolve type binding of declaring type of: {0} +ASTInstructionCompiler_4=The ASTInstruction compiler failed to store instruction at counter: {0} +ASTInstructionCompiler_5=Unable to resolve binding for: {0} +ASTEvaluationEngine_1=Unable to retrieve type for java.lang.Object +ArrayRuntimeContext_0=Unable to retrieve type for java.lang.Object + +ASTInstructionCompiler_Lambda_expressions_cannot_be_used_in_an_evaluation_expression=Lambda expressions cannot be used in an evaluation expression +ASTInstructionCompiler_Reference_expressions_cannot_be_used_in_an_evaluation_expression=Reference expressions cannot be used in an evaluation expression +ASTInstructionCompiler_Switch_expressions_cannot_be_used_in_an_evaluation_expression=Switch expressions cannot be used in an evaluation expression +ASTInstructionCompiler_Functional_expressions_cannot_be_evaluated_inside_local_and_or_anonymous_classes=Functional expressions cannot be evaluated inside local and or anonymous classes \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java new file mode 100644 index 0000000000..3c4f66301f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java @@ -0,0 +1,421 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Moller - bug 341232 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.compiler.IScanner; +import org.eclipse.jdt.core.compiler.ITerminalSymbols; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.model.JDIReferenceType; + +/** + * Creates the source code necessary to evaluate a code snippet. The + * (simplified) structure of the source is as follows: [package ;] + * [import ;]* public class + * extends { + * public void run() { + * + * } + * } + */ +public class EvaluationSourceGenerator { + + private final String fCodeSnippet; + + private final String[] fLocalVariableTypeNames; + private final String[] fLocalVariableNames; + + private String fSource; + private String fCompilationUnitName; + private int fSnippetStartPosition; + private int fRunMethodStartPosition; + private int fRunMethodLength; + private final IJavaProject fJavaProject; + + /** + * Rebuild source in presence of external local variables + */ + public EvaluationSourceGenerator(String[] localVariableTypesNames, + String[] localVariableNames, String codeSnippet, IJavaProject javaProject) { + fLocalVariableTypeNames = localVariableTypesNames; + fLocalVariableNames = localVariableNames; + fJavaProject = javaProject; + fCodeSnippet = getCompleteSnippet(codeSnippet); + } + + public EvaluationSourceGenerator(String codeSnippet, IJavaProject javaProject) { + this(new String[0], new String[0], codeSnippet, javaProject); + } + + + /** + * Returns the completed codeSnippet by adding required semicolon and + * return + */ + protected String getCompleteSnippet(String codeSnippet) { + codeSnippet = codeSnippet.trim(); // remove whitespaces at the end + boolean inString = false; + char[] chars = codeSnippet.toCharArray(); + + int semicolonIndex = -1; + int lastSemilcolonIndex = -1; + for (int i = 0, numChars = chars.length; i < numChars; i++) { + switch (chars[i]) { + case '\\': + if (inString) { // skip the char after an escape char + i++; + } + break; + case '\"': + case '\'': + inString = !inString; + break; + case ';': + if (!inString) { // mark the last 2 semicolon + semicolonIndex = lastSemilcolonIndex; + lastSemilcolonIndex = i; + } + break; + } + } + StringBuilder wordBuffer = new StringBuilder(); + // if semicolon missing at the end + if (lastSemilcolonIndex != chars.length-1) { + semicolonIndex = lastSemilcolonIndex; + } + int i ; + for (i=0; i < chars.length; i++) { + // copy everything before the last statement or if whitespace + if (i<= semicolonIndex || Character.isWhitespace(chars[i]) || chars[i] == '}' + || (i > 0 && (chars[i - 1] == '}' && (chars[i] == ')' || chars[i] == ',')))) { + wordBuffer.append(codeSnippet.charAt(i)); + } else { + break; + } + } + String lastSentence = codeSnippet.substring(i); + // don't add return if it there in some condition + String returnString = "return "; //$NON-NLS-1$ + int index = codeSnippet.lastIndexOf(returnString); + if (index == -1){ + // empty lastSentence means we have statement block above which requires a empty return + if (needsReturn(lastSentence)) { + wordBuffer.append(returnString); + } else if (lastSentence.isBlank()) { + wordBuffer.append(returnString + ';'); + } + } + else if (index > i){ + if (!Character.isWhitespace(chars[index-1]) || !(Character.isWhitespace(chars[index+6]) || chars[index+6] == '}')){ + if (needsReturn(lastSentence)) { + wordBuffer.append(returnString); + } + } + } else if (chars[chars.length -1] !='}' && ( (i+7 > chars.length && lastSentence.length() > 1) || (i + 7 <= chars.length && !codeSnippet.substring(i, i+7).equals(returnString)))){ + // add return if last statement does not have return + if (needsReturn(lastSentence)) { + wordBuffer.append(returnString); + } + } + for (; i < chars.length; i++) { + // copy the last statement + wordBuffer.append(codeSnippet.charAt(i)); + } + // add semicolon at the end if missing + if (chars.length > 0) { + if (chars[chars.length - 1] != ';' && chars[chars.length - 1] != '}') { + wordBuffer.append(';'); + } else if (chars[chars.length - 1] != ';' && chars[chars.length - 1] == '}') { + int j = lastSentence.lastIndexOf('='); + int k = lastSentence.lastIndexOf("=="); //$NON-NLS-1$ + if (j != -1 && (j != k)) { + wordBuffer.append(';'); + } + } + } + + // make sure last char is not at end of a block before treating this as a statement + if (lastSentence.length() <= 1 && needsReturn(wordBuffer.toString())) { + wordBuffer.insert(0, returnString).append(' '); + } + + return wordBuffer.toString(); + } + + + /** + * Returns true if the snippet required return to be added, or + * false if the snippet does not require return to be added. + */ + + @SuppressWarnings("deprecation") + private boolean needsReturn(String codeSnippet){ + if ( codeSnippet.length() == 0) { + return false; + } + IScanner scanner = ToolFactory.createScanner(false, false, false, fJavaProject.getOption(JavaCore.COMPILER_SOURCE, true), fJavaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true), true); + scanner.setSource(codeSnippet.toCharArray()); + int token; + try { + token = scanner.getNextToken(); + if (token == ITerminalSymbols.TokenNameEOF) { + return false; + } + int count = 0; + while (token != ITerminalSymbols.TokenNameEOF) { + if (count == 0 && (token == ITerminalSymbols.TokenNameIdentifier || token == ITerminalSymbols.TokenNameint || token == ITerminalSymbols.TokenNamefloat || + token == ITerminalSymbols.TokenNamedouble || token == ITerminalSymbols.TokenNameboolean || token == ITerminalSymbols.TokenNamechar || + token == ITerminalSymbols.TokenNameshort || token == ITerminalSymbols.TokenNamelong)) { + int currentToken = token; + token = scanner.getNextToken(); + if ( token == ITerminalSymbols.TokenNameEOF && currentToken == ITerminalSymbols.TokenNameIdentifier ){ + return true; + } + count = 1; + } + else if ( count == 0 && (token == ITerminalSymbols.TokenNamestatic || token == ITerminalSymbols.TokenNamefinal || token == ITerminalSymbols.TokenNamepackage || + token == ITerminalSymbols.TokenNameprivate || token == ITerminalSymbols.TokenNameprotected || token == ITerminalSymbols.TokenNamepublic)){ + token = scanner.getNextToken(); + } + else if (count == 0 && (token == ITerminalSymbols.TokenNamethrow)){ + return false; + } + else if (count == 0 && (token == ITerminalSymbols.TokenNameif || token == ITerminalSymbols.TokenNamewhile + || token == ITerminalSymbols.TokenNamedo || token == ITerminalSymbols.TokenNamefor || token == ITerminalSymbols.TokenNametry + || token == ITerminalSymbols.TokenNameswitch)) { + return false; + } + else if (count ==1 && (token == ITerminalSymbols.TokenNameLBRACE || token == ITerminalSymbols.TokenNameEQUAL)){ + return true; + } + else if (count ==1 && (token == ITerminalSymbols.TokenNameLESS || token == ITerminalSymbols.TokenNameLBRACKET)){ + int currentToken = token; + token = scanner.getNextToken(); + if ( currentToken == ITerminalSymbols.TokenNameLESS && ( token == ITerminalSymbols.TokenNameIdentifier + || (token >= ITerminalSymbols.TokenNameIntegerLiteral && token <= ITerminalSymbols.TokenNameTextBlock))) { + token = scanner.getNextToken(); + if (token == ITerminalSymbols.TokenNameEOF) { + return true; + } + } + count = 2; + } + else if (count ==2 && (token == ITerminalSymbols.TokenNameGREATER || token == ITerminalSymbols.TokenNameRBRACKET)){ + int currentToken = token; + token = scanner.getNextToken(); + if ( token == ITerminalSymbols.TokenNameEOF && currentToken == ITerminalSymbols.TokenNameRBRACKET ){ + return true; + } + if ( currentToken == ITerminalSymbols.TokenNameGREATER && ( token == ITerminalSymbols.TokenNameIdentifier || (token >= ITerminalSymbols.TokenNameIntegerLiteral && token <= ITerminalSymbols.TokenNameTextBlock))){ + token = scanner.getNextToken(); + if (token == ITerminalSymbols.TokenNameEOF) { + return true; + } else if (token == ITerminalSymbols.TokenNameEQUAL) { + return false; + } + } + count = 3; + } + else if (count == 2) { + token = scanner.getNextToken(); + } else if ( (count == 3 || count == 1 ) && token == ITerminalSymbols.TokenNameIdentifier ){ + return false; + } + else if (count == 0 && token == ITerminalSymbols.TokenNamereturn) { + return false; + } else { + // ignore and continue the tokens specified here, handling following types of statements + // {return i > 0;}, {/**/};{return true;} + switch (token) { + case ITerminalSymbols.TokenNameLBRACE: + case ITerminalSymbols.TokenNameRBRACE: + case ITerminalSymbols.TokenNameSEMICOLON: + token = scanner.getNextToken(); + break; + default: + return true; + } + } + + } + } + catch (InvalidInputException e) { + // ignore + } + + return true; + } + + public String getCompilationUnitName() { + return fCompilationUnitName; + } + + public int getSnippetStart() { + return fSnippetStartPosition; + } + + public int getRunMethodStart() { + return fRunMethodStartPosition; + } + + public int getRunMethodLength() { + return fRunMethodLength; + } + + protected void setSnippetStart(int position) { + fSnippetStartPosition = position; + } + + protected void setRunMethodStart(int position) { + fRunMethodStartPosition = position; + } + + protected void setRunMethodLength(int length) { + fRunMethodLength = length; + } + + public String getSnippet() { + return fCodeSnippet; + } + + private void createEvaluationSourceFromSource(String source, IType type, + int line, boolean createInAStaticMethod, IJavaProject project) + throws DebugException { + ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); + parser.setSource(source.toCharArray()); + Map options = getCompilerOptions(project); + String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true); + parser.setCompilerOptions(options); + CompilationUnit unit = (CompilationUnit) parser.createAST(null); + SourceBasedSourceGenerator visitor = new SourceBasedSourceGenerator( + type, line, createInAStaticMethod, fLocalVariableTypeNames, + fLocalVariableNames, fCodeSnippet, sourceLevel); + unit.accept(visitor); + + if (visitor.hasError()) { + throw new DebugException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + visitor.getError(), null)); + } + + String sourceRes = visitor.getSource(); + if (sourceRes == null) { + return; + } + setSource(sourceRes); + setCompilationUnitName(visitor.getCompilationUnitName()); + setSnippetStart(visitor.getSnippetStart()); + setRunMethodStart(visitor.getRunMethodStart()); + setRunMethodLength(visitor.getRunMethodLength()); + } + + /** + * Returns the compiler options used for compiling the expression. + *

+ * Turns all errors and warnings into ignore and disables task tags. The + * customizable set of compiler options only contains additional Eclipse + * options. The standard JDK compiler options can't be changed anyway. + * + * @param element + * an element (not the Java model) + * @return compiler options + */ + public static Map getCompilerOptions(IJavaProject project) { + Map options = project.getOptions(true); + for (String key : options.keySet()) { + String value = options.get(key); + if (JavaCore.ERROR.equals(value) || JavaCore.WARNING.equals(value) || JavaCore.INFO.equals(value)) { + options.put(key, JavaCore.IGNORE); + } + } + options.put(JavaCore.COMPILER_TASK_TAGS, ""); //$NON-NLS-1$ + return options; + } + + private void createEvaluationSourceFromJDIObject( + BinaryBasedSourceGenerator objectToEvaluationSourceMapper) { + + setCompilationUnitName(objectToEvaluationSourceMapper + .getCompilationUnitName()); + setSnippetStart(objectToEvaluationSourceMapper.getSnippetStart()); + setRunMethodStart(objectToEvaluationSourceMapper.getRunMethodStart()); + setRunMethodLength(fCodeSnippet.length() + + objectToEvaluationSourceMapper.getRunMethodLength()); + setSource(objectToEvaluationSourceMapper + .getSource() + .insert(objectToEvaluationSourceMapper.getCodeSnippetPosition(), + fCodeSnippet).toString()); + } + + private BinaryBasedSourceGenerator getInstanceSourceMapper( + JDIReferenceType referenceType, boolean isInStaticMethod, + IJavaProject project) { + String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true); + BinaryBasedSourceGenerator objectToEvaluationSourceMapper = new BinaryBasedSourceGenerator( + fLocalVariableTypeNames, fLocalVariableNames, isInStaticMethod, + sourceLevel); + objectToEvaluationSourceMapper.buildSource(referenceType); + return objectToEvaluationSourceMapper; + } + + public String getSource(IJavaReferenceType type, int line, IJavaProject javaProject, + boolean isStatic) throws CoreException { + if (fSource == null) { + IType iType = JavaDebugUtils.resolveType(type); + if (iType != null && !iType.isInterface()) { + String baseSource = null; + if (iType.isBinary()) { + baseSource = iType.getClassFile().getSource(); + } else { + baseSource = iType.getCompilationUnit().getSource(); + } + if (baseSource != null) { + createEvaluationSourceFromSource(baseSource, iType, + line, isStatic, javaProject); + } + } + if (fSource == null) { + BinaryBasedSourceGenerator mapper = getInstanceSourceMapper( + (JDIReferenceType) type, isStatic, javaProject); + createEvaluationSourceFromJDIObject(mapper); + } + } + return fSource; + } + + protected void setCompilationUnitName(String name) { + fCompilationUnitName = name; + } + + protected void setSource(String source) { + fSource = source; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java new file mode 100644 index 0000000000..521f93aef6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaVariable; + +/** + * The context in which an evaluation is to be performed. An evaluation is + * performed in the context of an object or class. The evaluation may be in the + * context of a method, in which case there could be local variables. + *

+ * Clients are not intended to implement this interface. + */ + +public interface IRuntimeContext { + + /** + * Returns the virtual machine in which to perform the evaluation. + * + * @return virtual machine + */ + IJavaDebugTarget getVM(); + + /** + * Returns the receiving object context in which to perform the evaluation - + * equivalent to 'this'. Returns null if the context of an + * evaluation is in a class rather than an object. + * + * @return 'this', or null + * @exception EvaluationException + * if this method fails. Reasons include: + *

    + *
  • Failure communicating with the VM. The exception's + * status code contains the underlying exception responsible + * for the failure.
  • + *
+ */ + IJavaObject getThis() throws CoreException; + + /** + * Returns the receiving type context in which to perform the evaluation. + * The type of 'this', or in the case of a static context, the class or + * interface in which the evaluation is being performed. + * + * @return receiving class + * @exception EvaluationException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The exception's + * status code contains the underlying exception responsible + * for the failure.
  • + *
+ */ + IJavaReferenceType getReceivingType() throws CoreException; + + /** + * Returns the local variables visible for the evaluation. This includes + * method arguments, if any. Does not return null returns an + * empty collection if there are no locals. + * + * @return local variables + * @exception EvaluationException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The exception's + * status code contains the underlying exception responsible + * for the failure.
  • + *
+ */ + IJavaVariable[] getLocals() throws CoreException; + + /** + * Returns the Java project context in which this expression should be + * compiled. + * + * @return project + */ + IJavaProject getProject(); + + /** + * Returns the thread in which message sends may be performed. + * + * @return thread + */ + IJavaThread getThread(); + + /** + * Returns whether the context of this evaluation is within a constructor. + * + * @return whether the context of this evaluation is within a constructor + * @exception EvaluationException + * if this method fails. Reasons include: + *
    + *
  • Failure communicating with the VM. The exception's + * status code contains the underlying exception responsible + * for the failure.
  • + *
+ */ + public boolean isConstructor() throws CoreException; + + /** + * Loads, prepares and returns the class with the given name in this runtime + * context's receiving type's class loader. If the class is already loaded, + * it is simply returned. + * + * @param name + * fully qualified class name + * @return class object + * @throws CoreException + * if unable to load the class + * @since 3.2 + */ + public IJavaClassObject classForName(String name) throws CoreException; + + /** + * Returns the stack frame in which the evaluation is performed on. + * + * @return stack frame + * @throws DebugException + * if unable to load the stack frame. + */ + default IJavaStackFrame getFrame() throws DebugException { + return (IJavaStackFrame) getThread().getTopStackFrame(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/Interpreter.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/Interpreter.java new file mode 100644 index 0000000000..314c3a6b3b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/Interpreter.java @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2000, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction; +import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence; + +import com.sun.jdi.VMDisconnectedException; + +public class Interpreter { + private final Instruction[] fInstructions; + private int fInstructionCounter; + private final IRuntimeContext fContext; + private Stack fStack; + private IJavaValue fLastValue; + + /** + * The list of internal variables + */ + private final Map fInternalVariables; + + /** + * List of objects for which GC has been disabled + */ + private List fPermStorage = null; + + private boolean fStopped = false; + + public Interpreter(InstructionSequence instructions, IRuntimeContext context) { + fInstructions = instructions.getInstructions(); + fContext = context; + fInternalVariables = new HashMap<>(); + } + + public void execute(boolean disableGcOnResult) throws CoreException { + try { + reset(); + while (fInstructionCounter < fInstructions.length && !fStopped) { + Instruction instruction = fInstructions[fInstructionCounter++]; + instruction.setInterpreter(this); + instruction.execute(); + instruction.setInterpreter(null); + } + } catch (CoreException e) { + throw e; + } catch (Exception e) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), e.getMessage(), e)); + } finally { + releaseObjects(disableGcOnResult); + } + } + + public void stop() { + fStopped = true; + } + + private void reset() { + fStack = new Stack<>(); + fInstructionCounter = 0; + } + + /** + * Jumps to a given address + */ + public void jump(int offset) { + fInstructionCounter += offset; + } + + /** + * Pushes an object onto the stack. Disables garbage collection for any + * interim object pushed onto the stack. Objects are released after the + * evaluation completes. + */ + public void push(Object object) { + fStack.push(object); + if (object instanceof IJavaObject) { + disableCollection((IJavaObject) object); + } + } + + /** + * Avoid garbage collecting interim results. + * + * @param value + * object to disable garbage collection for + */ + private void disableCollection(IJavaObject value) { + if (fPermStorage == null) { + fPermStorage = new ArrayList<>(5); + } + try { + value.disableCollection(); + fPermStorage.add(value); + } catch (CoreException e) { + // don't worry about GC if the VM has terminated + if ((e.getStatus().getException() instanceof VMDisconnectedException)) { + return; + } + JDIDebugPlugin.log(e); + } + } + + /** + * Re-enable garbage collection if interim results. + */ + private void releaseObjects(boolean disableGcOnResult) { + if (fPermStorage != null) { + IJavaValue result = getResult(); + Iterator iterator = fPermStorage.iterator(); + while (iterator.hasNext()) { + IJavaObject object = iterator.next(); + try { + if (!disableGcOnResult || object != result) { + object.enableCollection(); + } + } catch (CoreException e) { + // don't worry about GC if the VM has terminated + if ((e.getStatus().getException() instanceof VMDisconnectedException)) { + break; + } + JDIDebugPlugin.log(e); + } + } + fPermStorage = null; + } + } + + /** + * Peeks at the top object of the stack + */ + public Object peek() { + return fStack.peek(); + } + + /** + * Pops an object off of the stack + */ + public Object pop() { + return fStack.pop(); + } + + /** + * Answers the context for the interpreter + */ + public IRuntimeContext getContext() { + return fContext; + } + + public IJavaValue getResult() { + if (fStack == null || fStack.isEmpty()) { + if (fLastValue == null) { + return getContext().getVM().voidValue(); + } + return fLastValue; + } + Object top = fStack.peek(); + if (top instanceof IJavaVariable) { + try { + return (IJavaValue) ((IJavaVariable) top).getValue(); + } catch (CoreException exception) { + return getContext().getVM().newValue( + exception.getStatus().getMessage()); + } + } + if (top instanceof IJavaValue) { + return (IJavaValue) top; + } + // XXX: exception + return null; + } + + public void setLastValue(IJavaValue value) { + fLastValue = value; + } + + /** + * Create a new variable in the interpreter with the given name and the + * given type. + * + * @param name + * the name of the variable to create. + * @param type + * the type of the variable to create. + * @return the created variable. + */ + public IVariable createInternalVariable(String name, IJavaType referencType) { + IVariable var = new InterpreterVariable(name, referencType, + fContext.getVM()); + fInternalVariables.put(name, var); + return var; + } + + /** + * Return the variable with the given name. This method only looks in the + * list of internal variable (i.e. created by + * Interpreter#createInternalVariable(String, IJavaType)) + * + * @param name + * the name of the variable to retrieve. + * @return the corresponding variable, or null if there is + * none. + */ + public IVariable getInternalVariable(String name) { + return fInternalVariables.get(name); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/InterpreterVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/InterpreterVariable.java new file mode 100644 index 0000000000..9577ce7e27 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/InterpreterVariable.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; + +public class InterpreterVariable implements IJavaVariable { + + /** + * The reference type of this variable. + */ + private final IJavaType fReferenceType; + + /** + * The variable name. + */ + private final String fName; + + /** + * The variable value. + */ + private IValue fValue; + + private final IDebugTarget fDebugTarget; + + public InterpreterVariable(String name, IJavaType referenceType, + IDebugTarget debugTarget) { + fName = name; + fReferenceType = referenceType; + fDebugTarget = debugTarget; + } + + /** + * @see org.eclipse.debug.core.model.IVariable#getValue() + */ + @Override + public IValue getValue() { + return fValue; + } + + /** + * @see org.eclipse.debug.core.model.IVariable#getName() + */ + @Override + public String getName() { + return fName; + } + + /** + * @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + return fReferenceType.getName(); + } + + /** + * @see org.eclipse.debug.core.model.IVariable#hasValueChanged() + */ + @Override + public boolean hasValueChanged() { + return false; + } + + /** + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + @Override + public String getModelIdentifier() { + return JDIDebugModel.getPluginIdentifier(); + } + + /** + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + @Override + public IDebugTarget getDebugTarget() { + return fDebugTarget; + } + + /** + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + @Override + public ILaunch getLaunch() { + return fDebugTarget.getLaunch(); + } + + /** + * @see org.eclipse.debug.core.model.IValueModification#setValue(String) + */ + @Override + public void setValue(String expression) throws DebugException { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.NOT_SUPPORTED, + EvaluationEngineMessages.InterpreterVariable_setValue_String__not_supported_for_interpreter_variable_1, + null)); + } + + /** + * @see org.eclipse.debug.core.model.IValueModification#setValue(IValue) + */ + @Override + public void setValue(IValue value) { + fValue = value; + } + + /** + * @see org.eclipse.debug.core.model.IValueModification#supportsValueModification() + */ + @Override + public boolean supportsValueModification() { + return false; + } + + /** + * @see org.eclipse.debug.core.model.IValueModification#verifyValue(IValue) + */ + @Override + public boolean verifyValue(IValue value) throws DebugException { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.NOT_SUPPORTED, + EvaluationEngineMessages.InterpreterVariable_verifyValue_IValue__not_supported_for_interpreter_variable_2, + null)); + } + + /** + * @see org.eclipse.debug.core.model.IValueModification#verifyValue(String) + */ + @Override + public boolean verifyValue(String expression) throws DebugException { + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.NOT_SUPPORTED, + EvaluationEngineMessages.InterpreterVariable_verifyValue_String__not_supported_for_interpreter_variable_3, + null)); + } + + /** + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(Class) + */ + @Override + public T getAdapter(Class adapter) { + return null; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaVariable#getJavaType() + */ + @Override + public IJavaType getJavaType() { + return fReferenceType; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaVariable#getSignature() + */ + @Override + public String getSignature() throws DebugException { + return fReferenceType.getSignature(); + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isFinal() + */ + @Override + public boolean isFinal() { + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPackagePrivate() + */ + @Override + public boolean isPackagePrivate() { + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPrivate() + */ + @Override + public boolean isPrivate() { + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isProtected() + */ + @Override + public boolean isProtected() { + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPublic() + */ + @Override + public boolean isPublic() { + return true; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isStatic() + */ + @Override + public boolean isStatic() { + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isSynthetic() + */ + @Override + public boolean isSynthetic() { + return true; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaVariable#isLocal() + */ + @Override + public boolean isLocal() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + return getSignature(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java new file mode 100644 index 0000000000..5aae44a244 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public class JavaObjectRuntimeContext extends AbstractRuntimeContext { + + /** + * this object or this context. + */ + private final IJavaObject fThisObject; + + /** + * The thread for this context. + */ + private final IJavaThread fThread; + + /** + * ObjectValueRuntimeContext constructor. + * + * @param thisObject + * this object of this context. + * @param javaProject + * the project for this context. + * @param thread + * the thread for this context. + */ + public JavaObjectRuntimeContext(IJavaObject thisObject, + IJavaProject javaProject, IJavaThread thread) { + super(javaProject); + fThisObject = thisObject; + fThread = thread; + } + + /** + * @see IRuntimeContext#getVM() + */ + @Override + public IJavaDebugTarget getVM() { + return (IJavaDebugTarget) fThisObject.getDebugTarget(); + } + + /** + * @see IRuntimeContext#getThis() + */ + @Override + public IJavaObject getThis() { + return fThisObject; + } + + /** + * @see IRuntimeContext#getReceivingType() + */ + @Override + public IJavaReferenceType getReceivingType() throws CoreException { + return (IJavaReferenceType) getThis().getJavaType(); + } + + /** + * @see IRuntimeContext#getLocals() + */ + @Override + public IJavaVariable[] getLocals() { + return new IJavaVariable[0]; + } + + /** + * @see IRuntimeContext#getThread() + */ + @Override + public IJavaThread getThread() { + return fThread; + } + + /** + * @see IRuntimeContext#isConstructor() + */ + @Override + public boolean isConstructor() { + return false; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java new file mode 100644 index 0000000000..6ad02a5911 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public class RuntimeContext extends AbstractRuntimeContext { + + /** + * Stack frame context + */ + private IJavaStackFrame fFrame; + + /** + * Creates a runtime context for the given java project and stack frame. + * + * @param project + * Java project context used to compile expressions in + * @param frame + * stack frame used to define locals and receiving type context + * @return a new runtime context + */ + public RuntimeContext(IJavaProject project, IJavaStackFrame frame) { + super(project); + setFrame(frame); + } + + /** + * @see IRuntimeContext#getVM() + */ + @Override + public IJavaDebugTarget getVM() { + return (IJavaDebugTarget) getFrame().getDebugTarget(); + } + + /** + * @see IRuntimeContext#getThis() + */ + @Override + public IJavaObject getThis() throws CoreException { + return getFrame().getThis(); + } + + /** + * @see IRuntimeContext#getReceivingType() + */ + @Override + public IJavaReferenceType getReceivingType() throws CoreException { + IJavaObject rec = getThis(); + if (rec != null) { + return (IJavaReferenceType) rec.getJavaType(); + } + return getFrame().getReferenceType(); + } + + /** + * @see IRuntimeContext#getLocals() + */ + @Override + public IJavaVariable[] getLocals() throws CoreException { + return getFrame().getLocalVariables(); + } + + /** + * Sets the stack frame context used to compile/run expressions + * + * @param frame + * the stack frame context used to compile/run expressions + */ + @Override + public IJavaStackFrame getFrame() { + return fFrame; + } + + /** + * Sets the stack frame context used to compile/run expressions + * + * @param frame + * the stack frame context used to compile/run expressions + */ + private void setFrame(IJavaStackFrame frame) { + fFrame = frame; + } + + /** + * @see IRuntimeContext#getThread() + */ + @Override + public IJavaThread getThread() { + return (IJavaThread) getFrame().getThread(); + } + + /** + * @see IRuntimeContext#isConstructor() + */ + @Override + public boolean isConstructor() throws CoreException { + return getFrame().isConstructor(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/SignatureExt.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/SignatureExt.java new file mode 100644 index 0000000000..2cbce4aa49 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/SignatureExt.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2005, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.util.ArrayList; + +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.util.Util; + +@SuppressWarnings("restriction") +public class SignatureExt { + + public static char[][] getTypeSuperClassInterfaces(char[] typeSignature) + throws IllegalArgumentException { + try { + int length = typeSignature.length; + if (length == 0) { + return CharOperation.NO_CHAR_CHAR; + } + int i = 0; + if (typeSignature[0] == Signature.C_GENERIC_START) { + i++; // leading '<' + while (i < length + && typeSignature[i] != Signature.C_GENERIC_END) { + i = CharOperation.indexOf(Signature.C_COLON, typeSignature, + i); + if (i < 0 || i >= length) { + throw new IllegalArgumentException(); + } + // iterate over bounds + nextBound: while (typeSignature[i] == ':') { + i++; // skip colon + if (typeSignature[i] == ':') { + continue nextBound; // empty bound + } + i = Util.scanTypeSignature(typeSignature, i); + i++; // position at start of next param if any + } + } + if (i < 0 || i >= length) { + throw new IllegalArgumentException(); + } + i++; // trailing '>' + } + ArrayList superList = new ArrayList<>(); + while (i < length) { + int superStart = i; + i = Util.scanTypeSignature(typeSignature, i); + i++; + superList.add(CharOperation.subarray(typeSignature, superStart, + i)); + } + char[][] result; + superList.toArray(result = new char[superList.size()][]); + return result; + } catch (ArrayIndexOutOfBoundsException e) { + // invalid signature, fall through + } + throw new IllegalArgumentException(); + } + + public static String[] getTypeSuperClassInterfaces(String typeSignature) + throws IllegalArgumentException { + char[][] params = getTypeSuperClassInterfaces(typeSignature + .toCharArray()); + return CharOperation.toStrings(params); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/SourceBasedSourceGenerator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/SourceBasedSourceGenerator.java new file mode 100644 index 0000000000..0d14a6c08f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/SourceBasedSourceGenerator.java @@ -0,0 +1,2235 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Moller - bug 341232 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.engine; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Stack; + +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.SourceRange; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.ArrayAccess; +import org.eclipse.jdt.core.dom.ArrayCreation; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.AssertStatement; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BlockComment; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.CastExpression; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.CharacterLiteral; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ConditionalExpression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EmptyStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.EnumConstantDeclaration; +import org.eclipse.jdt.core.dom.EnumDeclaration; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.InstanceofExpression; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.LabeledStatement; +import org.eclipse.jdt.core.dom.LineComment; +import org.eclipse.jdt.core.dom.MarkerAnnotation; +import org.eclipse.jdt.core.dom.MemberRef; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.MethodRef; +import org.eclipse.jdt.core.dom.MethodRefParameter; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.NullLiteral; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.ParenthesizedExpression; +import org.eclipse.jdt.core.dom.PostfixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.QualifiedType; +import org.eclipse.jdt.core.dom.RecordDeclaration; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SwitchCase; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.TagElement; +import org.eclipse.jdt.core.dom.TextBlock; +import org.eclipse.jdt.core.dom.TextElement; +import org.eclipse.jdt.core.dom.ThisExpression; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.TypeLiteral; +import org.eclipse.jdt.core.dom.TypeParameter; +import org.eclipse.jdt.core.dom.UnionType; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.core.dom.WildcardType; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +public class SourceBasedSourceGenerator extends ASTVisitor { + + private static final String RUN_METHOD_NAME = "___run"; //$NON-NLS-1$ + private static final String EVAL_METHOD_NAME = "___eval"; //$NON-NLS-1$ + private static final String EVAL_FIELD_NAME = "___field"; //$NON-NLS-1$ + + private final String[] fLocalVariableTypeNames; + private final String[] fLocalVariableNames; + private final String fCodeSnippet; + + private boolean fRightTypeFound; + + private final boolean fCreateInAStaticMethod; + + private boolean fEvaluateNextEndTypeDeclaration; + + private String fError; + + private final IType fType; + private final int fLine; + + private StringBuilder fSource; + + private String fLastTypeName; + + private String fCompilationUnitName; + + private int fSnippetStartPosition; + private int fRunMethodStartOffset; + private int fRunMethodLength; + + /** + * Level of source code to generate (major, minor). For example 1 and 4 + * indicates 1.4. + */ + private final int fSourceMajorLevel; + private int fSourceMinorLevel; + + private final Stack> fTypeParameterStack = new Stack<>(); + private Map fMatchingTypeParameters = null; + + private enum TypeParameterLocation { + TYPE, METHOD, EMPTY; + } + + private final Stack fTypeParameterTypeStack = new Stack<>(); + private CompilationUnit fCompilationUnit; + { + fTypeParameterStack.push(Collections.emptyMap()); + fTypeParameterTypeStack.push(TypeParameterLocation.EMPTY); + } + + /** + * if the createInAnInstanceMethod flag is set, the method + * created which contains the code snippet is an no-static method, even if + * position is in a static method. + * + * @param type + * the root {@link IType} + * @param sourcePosition + * the reference position in the type's source + * @param createInAStaticMethod + * if the source should be generated + * @param localTypesNames + * the array of local type names + * @param localVariables + * the listing of local variable names + * @param codeSnippet + * the code snippet + * @param sourceLevel + * the desired source level + */ + public SourceBasedSourceGenerator(IType type, + int line, boolean createInAStaticMethod, String[] localTypesNames, + String[] localVariables, String codeSnippet, String sourceLevel) { + fRightTypeFound = false; + fType = type; + fLine = line; + fLocalVariableTypeNames = localTypesNames; + fLocalVariableNames = localVariables; + fCodeSnippet = codeSnippet; + fCreateInAStaticMethod = createInAStaticMethod; + int index = sourceLevel.indexOf('.'); + String num; + if (index != -1) { + num = sourceLevel.substring(0, index); + } else { + num = sourceLevel; + } + fSourceMajorLevel = Integer.parseInt(num); + if (index != -1) { + num = sourceLevel.substring(index + 1); + fSourceMinorLevel = Integer.parseInt(num); + } else { + fSourceMinorLevel = 0; + } + } + + /** + * Returns the generated source or null if no source can be + * generated. + * + * @return returns the backing source from the generator + */ + public String getSource() { + if (fSource == null) { + return null; + } + return fSource.toString(); + } + + public String getCompilationUnitName() { + return fCompilationUnitName; + } + + public int getSnippetStart() { + return fSnippetStartPosition; + } + + public int getRunMethodStart() { + return fSnippetStartPosition - fRunMethodStartOffset; + } + + public int getRunMethodLength() { + return fRunMethodLength; + } + + private boolean rightTypeFound() { + return fRightTypeFound; + } + + private void setRightTypeFound(boolean value) { + fRightTypeFound = value; + } + + public boolean hasError() { + return fError != null; + } + + public void setError(String errorDesc) { + fError = errorDesc; + } + + public String getError() { + return fError; + } + + private StringBuilder buildRunMethod(List bodyDeclarations) { + StringBuilder buffer = new StringBuilder(); + + if (fCreateInAStaticMethod) { + buffer.append("static "); //$NON-NLS-1$ + } + + adddTypeParameters(buffer); + + buffer.append("void "); //$NON-NLS-1$ + buffer.append(getUniqueMethodName(RUN_METHOD_NAME, bodyDeclarations)); + buffer.append('('); + for (int i = 0, length = fLocalVariableNames.length; i < length; i++) { + buffer.append(getDotName(fLocalVariableTypeNames[i])); + buffer.append(' '); + buffer.append(fLocalVariableNames[i]); + if (i + 1 < length) + { + buffer.append(", "); //$NON-NLS-1$ + } + } + buffer.append(") throws Throwable {"); //$NON-NLS-1$ + buffer.append('\n'); + fSnippetStartPosition = buffer.length() - 2; + fRunMethodStartOffset = fSnippetStartPosition; + String codeSnippet = new String(fCodeSnippet).trim(); + + buffer.append(codeSnippet); + + buffer.append('\n'); + buffer.append('}').append('\n'); + fRunMethodLength = buffer.length(); + return buffer; + } + + private String getDotName(String typeName) { + return typeName.replace('$', '.'); + } + + /** + * Adds generic type parameters as needed to the given buffer + * + * @param buffer + * @since 3.8.0 + */ + void adddTypeParameters(StringBuilder buffer) { + if (isSourceLevelGreaterOrEqual(1, 5)) { + Collection activeTypeParameters = Optional.ofNullable(fMatchingTypeParameters) + .map(Map::values).orElse(Collections.emptyList()); + + if (!activeTypeParameters.isEmpty()) { + Iterator iterator = activeTypeParameters.iterator(); + buffer.append(Signature.C_GENERIC_START); + while (iterator.hasNext()) { + String name = iterator.next(); + buffer.append(name); + if (iterator.hasNext()) { + buffer.append(", "); //$NON-NLS-1$ + } + } + buffer.append(Signature.C_GENERIC_END); + buffer.append(' '); + } + } + } + + /** + * Returns if the specified {@link ASTNode} has the 'correct' parent type to + * match the current type name context + * + * @param node + * the {@link ASTNode} to check source ranges for + * @return true if the parent type of the given node matches the current + * type name context, false otherwise + */ + private boolean isRightType(ASTNode node) { + try { + switch(node.getNodeType()) { + case ASTNode.ANNOTATION_TYPE_DECLARATION: + case ASTNode.ENUM_DECLARATION: + case ASTNode.TYPE_DECLARATION: { + AbstractTypeDeclaration decl = (AbstractTypeDeclaration) node; + SimpleName name = decl.getName(); + ISourceRange range = new SourceRange(name.getStartPosition(), name.getLength()); + return fType.getNameRange().equals(range); + } + case ASTNode.ANONYMOUS_CLASS_DECLARATION: { + return isRightType(node.getParent()); + } + case ASTNode.CLASS_INSTANCE_CREATION: { + ClassInstanceCreation decl = (ClassInstanceCreation) node; + Type type = decl.getType(); + ISourceRange name = fType.getNameRange(); + return name.getOffset() >= type.getStartPosition() && + name.getOffset()+name.getLength() <= type.getStartPosition()+type.getLength(); + } + } + } + catch(JavaModelException jme) { + JDIDebugPlugin.log(jme); + } + return false; + } + + private StringBuilder buildTypeBody(StringBuilder buffer, List list) { + StringBuilder source = new StringBuilder(); + + source.append('{').append('\n'); + + if (buffer != null) { + fSnippetStartPosition += source.length(); + } + + source.append(buildBody(buffer, list)); + source.append('}').append('\n'); + + return source; + } + + private StringBuilder buildEnumBody(StringBuilder buffer, + List constantDeclarations, List bodyDeclarations) { + StringBuilder source = new StringBuilder(); + + source.append('{').append('\n'); + if (constantDeclarations.isEmpty()) { + source.append(';').append('\n'); + } else { + for (Iterator iter = constantDeclarations.iterator(); iter + .hasNext();) { + source.append(iter.next().getName() + .getIdentifier()); + if (iter.hasNext()) { + source.append(','); + } else { + source.append(';'); + } + source.append('\n'); + } + } + + if (buffer != null) { + fSnippetStartPosition += source.length(); + } + + source.append(buildBody(buffer, bodyDeclarations)); + source.append('}').append('\n'); + + return source; + + } + + /** + * Builds up the given buffer with the source from each of + * {@link BodyDeclaration}s in the given list + * + * @param buffer + * the buffer to clone and append to + * @param list + * the list of {@link BodyDeclaration}s + * @return the new source buffer + */ + private StringBuilder buildBody(StringBuilder buffer, List list) { + StringBuilder source = new StringBuilder(); + if (buffer != null) { + fSnippetStartPosition += source.length(); + source.append(buffer.toString()); + } + for (BodyDeclaration bodyDeclaration : list) { + if (bodyDeclaration instanceof FieldDeclaration) { + source.append(buildFieldDeclaration((FieldDeclaration) bodyDeclaration)); + } else if (bodyDeclaration instanceof MethodDeclaration) { + source.append(buildMethodDeclaration((MethodDeclaration) bodyDeclaration)); + } else if (bodyDeclaration instanceof TypeDeclaration) { + TypeDeclaration typeDeclaration = (TypeDeclaration) bodyDeclaration; + if (!typeDeclaration.getName().getIdentifier() + .equals(fLastTypeName)) { + source.append(buildTypeDeclaration(null, typeDeclaration)); + } + } else if (bodyDeclaration instanceof EnumDeclaration) { + EnumDeclaration enumDeclaration = (EnumDeclaration) bodyDeclaration; + if (!enumDeclaration.getName().getIdentifier() + .equals(fLastTypeName)) { + source.append(buildEnumDeclaration(null, enumDeclaration)); + } + } else if (bodyDeclaration instanceof RecordDeclaration) { + var recordDeclaration = (RecordDeclaration) bodyDeclaration; + if (!recordDeclaration.getName().getIdentifier().equals(fLastTypeName)) { + source.append(buildRecordDeclaration(null, recordDeclaration)); + } + } + } + return source; + } + + private StringBuilder buildFieldDeclaration(FieldDeclaration fieldDeclaration) { + StringBuilder source = new StringBuilder(); + + source.append(Flags.toString(fieldDeclaration.getModifiers())); + source.append(' '); + source.append(getDotName(getTypeName(fieldDeclaration.getType()))); + source.append(' '); + + boolean first = true; + for (Iterator iterator = fieldDeclaration.fragments().iterator(); iterator + .hasNext();) { + VariableDeclarationFragment variableDeclarationFragment = iterator + .next(); + if (first) { + first = false; + } else { + source.append(','); + } + source.append(variableDeclarationFragment.getName().getIdentifier()); + for (int i = 0, dim = variableDeclarationFragment + .getExtraDimensions(); i < dim; i++) { + source.append('[').append(']'); + } + } + + source.append(';').append('\n'); + + return source; + } + + private StringBuilder buildMethodDeclaration( + MethodDeclaration methodDeclaration) { + StringBuilder source = new StringBuilder(); + int modifiers = methodDeclaration.getModifiers(); + source.append(Flags.toString(modifiers)); + source.append(' '); + + appendTypeParameters(source, methodDeclaration.typeParameters()); + + boolean isConstructor = methodDeclaration.isConstructor(); + if (!isConstructor) { + source.append(getDotName(getTypeName(methodDeclaration + .getReturnType2()))); + source.append(' '); + } + + source.append(methodDeclaration.getName().getIdentifier()); + source.append(' ').append('('); + + boolean first = true; + for (Iterator iterator = methodDeclaration.parameters().iterator(); iterator + .hasNext();) { + SingleVariableDeclaration singleVariableDeclaration = iterator + .next(); + if (first) { + first = false; + } else { + source.append(','); + } + source.append(getDotName(getTypeName(singleVariableDeclaration + .getType()))); + if (singleVariableDeclaration.isVarargs()) { + source.append("..."); //$NON-NLS-1$ + } + source.append(' '); + source.append(singleVariableDeclaration.getName().getIdentifier()); + appendExtraDimensions(source, + singleVariableDeclaration.getExtraDimensions()); + } + + source.append(')'); + + appendExtraDimensions(source, methodDeclaration.getExtraDimensions()); + + first = true; + for (Object exceptionType : methodDeclaration.thrownExceptionTypes()) { + if (first) { + first = false; + source.append(" throws "); //$NON-NLS-1$ + } else { + source.append(','); + } + source.append(getTypeName((Type) exceptionType)); + } + + if (Flags.isAbstract(modifiers) || Flags.isNative(modifiers)) { + // No body for abstract and native methods + source.append(";\n"); //$NON-NLS-1$ + } else { + source.append('{').append('\n'); + if (!isConstructor) { + source.append(getReturnExpression(methodDeclaration + .getReturnType2())); + } + source.append('}').append('\n'); + } + + return source; + } + + private void appendExtraDimensions(StringBuilder source, int extraDimension) { + if (extraDimension > 0) { + source.append(' '); + for (int i = 0; i < extraDimension; i++) { + source.append("[]"); //$NON-NLS-1$ + } + } + } + + private StringBuilder buildEnumDeclaration(StringBuilder buffer, + EnumDeclaration enumDeclaration) { + StringBuilder source = new StringBuilder(); + source.append(Flags.toString(enumDeclaration.getModifiers())); + source.append(" enum "); //$NON-NLS-1$ + + source.append(enumDeclaration.getName().getIdentifier()); + + Iterator iterator = enumDeclaration.superInterfaceTypes().iterator(); + if (iterator.hasNext()) { + source.append(" implements "); //$NON-NLS-1$ + source.append(getTypeName(iterator.next())); + while (iterator.hasNext()) { + source.append(','); + source.append(getTypeName(iterator.next())); + } + } + + if (buffer != null) { + fSnippetStartPosition += source.length(); + } + source.append(buildEnumBody(buffer, enumDeclaration.enumConstants(), + enumDeclaration.bodyDeclarations())); + + return source; + } + + private StringBuilder buildTypeDeclaration(StringBuilder buffer, + TypeDeclaration typeDeclaration) { + + StringBuilder source = new StringBuilder(); + source.append(Flags.toString(typeDeclaration.getModifiers())); + if (typeDeclaration.isInterface()) { + source.append(" interface "); //$NON-NLS-1$ + } else { + source.append(" class "); //$NON-NLS-1$ + } + + source.append(typeDeclaration.getName().getIdentifier()); + + buildTypeParameterList(source, typeDeclaration.typeParameters()); + + Type superClass = typeDeclaration.getSuperclassType(); + if (superClass != null) { + source.append(" extends "); //$NON-NLS-1$ + source.append(getTypeName(superClass)); + } + + buildSuperInterfaceTypeList(source, typeDeclaration.superInterfaceTypes().iterator(), typeDeclaration.isInterface()); + + if (buffer != null) { + fSnippetStartPosition += source.length(); + } + source.append(buildTypeBody(buffer, typeDeclaration.bodyDeclarations())); + + return source; + } + + void buildSuperInterfaceTypeList(StringBuilder source, Iterator superInterfaceTypes, boolean isTypeInterface) { + if (superInterfaceTypes.hasNext()) { + if (isTypeInterface) { + source.append(" extends "); //$NON-NLS-1$ + } else { + source.append(" implements "); //$NON-NLS-1$ + } + source.append(getTypeName(superInterfaceTypes.next())); + while (superInterfaceTypes.hasNext()) { + source.append(','); + source.append(getTypeName(superInterfaceTypes.next())); + } + } + } + + private StringBuilder buildRecordDeclaration(StringBuilder buffer, RecordDeclaration typeDeclaration) { + + StringBuilder source = new StringBuilder(); + source.append(Flags.toString(typeDeclaration.getModifiers())); + source.append(" record "); //$NON-NLS-1$ + + source.append(typeDeclaration.getName().getIdentifier()); + + buildTypeParameterList(source, typeDeclaration.typeParameters()); + + boolean first = true; + source.append('('); + for (SingleVariableDeclaration field : (List) typeDeclaration.recordComponents()) { + if (first) { + first = false; + } else { + source.append(','); + } + source.append(getTypeName(field.getType())).append(' ').append(field.getName()); + } + source.append(')'); + buildSuperInterfaceTypeList(source, typeDeclaration.superInterfaceTypes().iterator(), false); + + if (buffer != null) { + fSnippetStartPosition += source.length(); + } + source.append(buildTypeBody(buffer, typeDeclaration.bodyDeclarations())); + + return source; + } + + void buildTypeParameterList(StringBuilder source, List typeParameters) { + if (!typeParameters.isEmpty() && isSourceLevelGreaterOrEqual(1, 5)) { + source.append('<'); + Iterator iter = typeParameters.iterator(); + TypeParameter typeParameter = iter.next(); + source.append(typeParameter.getName().getIdentifier()); + List typeBounds = typeParameter.typeBounds(); + if (!typeBounds.isEmpty()) { + source.append(" extends "); //$NON-NLS-1$ + Iterator iter2 = typeBounds.iterator(); + source.append(getTypeName(iter2.next())); + while (iter2.hasNext()) { + source.append('&'); + source.append(getTypeName(iter2.next())); + } + } + while (iter.hasNext()) { + source.append(','); + typeParameter = iter.next(); + source.append(typeParameter.getName().getIdentifier()); + typeBounds = typeParameter.typeBounds(); + if (!typeBounds.isEmpty()) { + source.append(" extends "); //$NON-NLS-1$ + Iterator iter2 = typeBounds.iterator(); + source.append(getTypeName(iter2.next())); + while (iter2.hasNext()) { + source.append('&'); + source.append(getTypeName(iter2.next())); + } + } + } + source.append('>'); + } + } + + private StringBuilder buildCompilationUnit(StringBuilder buffer, + CompilationUnit compilationUnit) { + StringBuilder source = new StringBuilder(); + + PackageDeclaration packageDeclaration = compilationUnit.getPackage(); + if (packageDeclaration != null) { + source.append("package "); //$NON-NLS-1$ + source.append(getQualifiedIdentifier(packageDeclaration.getName())); + source.append(";\n"); //$NON-NLS-1$ + } + + for (Iterator iterator = compilationUnit.imports().iterator(); iterator + .hasNext();) { + ImportDeclaration importDeclaration = iterator + .next(); + source.append("import "); //$NON-NLS-1$ + if (importDeclaration.isStatic()) { + source.append("static "); //$NON-NLS-1$ + } + source.append(getQualifiedIdentifier(importDeclaration.getName())); + if (importDeclaration.isOnDemand()) { + source.append(".*"); //$NON-NLS-1$ + } + source.append(";\n"); //$NON-NLS-1$ + } + + fSnippetStartPosition += source.length(); + source.append(buffer); + + for (Iterator iterator = compilationUnit.types().iterator(); iterator + .hasNext();) { + AbstractTypeDeclaration typeDeclaration = iterator.next(); + if (Flags.isPublic(typeDeclaration.getModifiers())) { + fCompilationUnitName = typeDeclaration.getName() + .getIdentifier(); + } + if (!fLastTypeName + .equals(typeDeclaration.getName().getIdentifier())) { + if (typeDeclaration instanceof TypeDeclaration) { + source.append(buildTypeDeclaration(null, + (TypeDeclaration) typeDeclaration)); + } else if (typeDeclaration instanceof EnumDeclaration) { + source.append(buildEnumDeclaration(null, + (EnumDeclaration) typeDeclaration)); + } + } + } + if (fCompilationUnitName == null) { + // If no public class was found, the compilation unit + // name doesn't matter. + fCompilationUnitName = "Eval"; //$NON-NLS-1$ + } + return source; + } + + /** + * Returns a method name that will be unique in the generated source. The + * generated name is baseName plus as many '_' characters as necessary to + * not duplicate an existing method name. + * + * @param methodName + * the method name to look for + * @param bodyDeclarations + * the listing of {@link BodyDeclaration}s to search through + * @return the unique method name + */ + private String getUniqueMethodName(String methodName, List bodyDeclarations) { + Iterator iter = bodyDeclarations.iterator(); + BodyDeclaration bodyDeclaration; + MethodDeclaration method; + String foundName; + while (iter.hasNext()) { + bodyDeclaration = iter.next(); + if (bodyDeclaration instanceof MethodDeclaration) { + method = (MethodDeclaration) bodyDeclaration; + foundName = method.getName().getIdentifier(); + if (foundName.startsWith(methodName)) { + methodName = foundName + '_'; + } + } + } + return methodName; + } + + /** + * Returns a field name that will be unique in the generated source. The + * generated name is baseName plus as many '_' characters as necessary to + * not duplicate an existing method name. + * + * @param fieldName + * the name of the field to look for + * @param bodyDeclarations + * the list of {@link BodyDeclaration}s to search through + * @return the unique field name + */ + private String getUniqueFieldName(String fieldName, List bodyDeclarations) { + Iterator iter = bodyDeclarations.iterator(); + BodyDeclaration bodyDeclaration; + FieldDeclaration fieldDeclaration; + String foundName; + while (iter.hasNext()) { + bodyDeclaration = iter.next(); + if (bodyDeclaration instanceof FieldDeclaration) { + fieldDeclaration = (FieldDeclaration) bodyDeclaration; + for (Iterator iterator = fieldDeclaration.fragments() + .iterator(); iterator.hasNext();) { + foundName = iterator.next() + .getName().getIdentifier(); + if (foundName.startsWith(fieldName)) { + fieldName = foundName + '_'; + } + } + } + } + return fieldName; + } + + private String getQualifiedIdentifier(Name name) { + String typeName = ""; //$NON-NLS-1$ + while (name.isQualifiedName()) { + QualifiedName qualifiedName = (QualifiedName) name; + typeName = "." + qualifiedName.getName().getIdentifier() + typeName; //$NON-NLS-1$ + name = qualifiedName.getQualifier(); + } + if (name.isSimpleName()) { + typeName = ((SimpleName) name).getIdentifier() + typeName; + } else { + return null; + } + return typeName; + } + + public String getTypeName(Type type) { + if (type.isSimpleType()) { + String name = getQualifiedIdentifier(((SimpleType) type).getName()); + if (!isSourceLevelGreaterOrEqual(1, 5) + && fTypeParameterStack.peek().containsKey(name)) { + return "Object"; //$NON-NLS-1$ + } + return name; + } else if (type.isArrayType()) { + return getTypeName(((ArrayType) type).getElementType()) + "[]"; //$NON-NLS-1$ + } else if (type.isPrimitiveType()) { + return ((PrimitiveType) type).getPrimitiveTypeCode().toString(); + } else if (type.isQualifiedType()) { + QualifiedType qualifiedType = (QualifiedType) type; + return getTypeName(qualifiedType.getQualifier()) + '.' + + qualifiedType.getName().getIdentifier(); + } else if (type.isParameterizedType()) { + ParameterizedType parameterizedType = (ParameterizedType) type; + StringBuilder buff = new StringBuilder( + getTypeName(parameterizedType.getType())); + Iterator iter = parameterizedType.typeArguments().iterator(); + if (iter.hasNext() && isSourceLevelGreaterOrEqual(1, 5)) { + buff.append('<'); + buff.append(getTypeName(iter.next())); + while (iter.hasNext()) { + buff.append(','); + buff.append(getTypeName(iter.next())); + } + buff.append('>'); + } + return buff.toString(); + } else if (type.isWildcardType()) { + WildcardType wildcardType = (WildcardType) type; + StringBuilder buff = new StringBuilder("?"); //$NON-NLS-1$ + Type bound = wildcardType.getBound(); + if (bound != null) { + buff.append(wildcardType.isUpperBound() ? " extends " : " super "); //$NON-NLS-1$ //$NON-NLS-2$ + buff.append(getTypeName(bound)); + } + return buff.toString(); + } + return null; + + } + + public String getReturnExpression(Type type) { + if (type.isSimpleType() || type.isArrayType() || type.isQualifiedType() + || type.isWildcardType() || type.isParameterizedType()) { + return "return null;"; //$NON-NLS-1$ + } else if (type.isPrimitiveType()) { + String typeName = ((PrimitiveType) type).getPrimitiveTypeCode() + .toString(); + char char0 = typeName.charAt(0); + if (char0 == 'v') { + return ""; //$NON-NLS-1$ + } + char char1 = typeName.charAt(1); + if (char0 == 'b' && char1 == 'o') { + return "return false;"; //$NON-NLS-1$ + } + return "return 0;"; //$NON-NLS-1$ + } + return null; + } + + // ---------------------- + + /** + * @see ASTVisitor#endVisit(ClassInstanceCreation) + */ + @Override + public void endVisit(ClassInstanceCreation node) { + if (hasError()) { + return; + } + AnonymousClassDeclaration anonymousClassDeclaration = node + .getAnonymousClassDeclaration(); + if (anonymousClassDeclaration != null) { + if (!rightTypeFound() && isRightType(node)) { + setRightTypeFound(true); + + fSource = buildRunMethod(anonymousClassDeclaration + .bodyDeclarations()); + fEvaluateNextEndTypeDeclaration = true; + } + + if (rightTypeFound()) { + + List bodyDeclarations = anonymousClassDeclaration + .bodyDeclarations(); + + StringBuilder source = buildTypeBody(fSource, bodyDeclarations); + + ASTNode parent = node.getParent(); + while (!(parent instanceof MethodDeclaration + || parent instanceof FieldDeclaration || parent instanceof Initializer) + && parent != null) { + parent = parent.getParent(); + } + + fSource = new StringBuilder(); + + if (parent instanceof Initializer) { + buildAnonymousEvalMethod(true, bodyDeclarations, + getTypeName(node.getType()), source); + } else if (parent instanceof MethodDeclaration) { + MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration) parent; + buildAnonymousEvalMethod( + Flags.isStatic(enclosingMethodDeclaration + .getModifiers()), bodyDeclarations, + getTypeName(node.getType()), source); + + } else if (parent instanceof FieldDeclaration) { + FieldDeclaration enclosingFieldDeclaration = (FieldDeclaration) parent; + + if (Flags + .isStatic(enclosingFieldDeclaration.getModifiers())) { + fSource.append("static "); //$NON-NLS-1$ + } + + Type type = getParentType(enclosingFieldDeclaration + .getType()); + fSource.append(getQualifiedIdentifier(((SimpleType) type) + .getName())); + fSource.append(' '); + fSource.append(getUniqueFieldName(EVAL_FIELD_NAME, + bodyDeclarations)); + fSource.append(" = new "); //$NON-NLS-1$ + fSource.append(getTypeName(node.getType())); + fSource.append("()"); //$NON-NLS-1$ + + fSnippetStartPosition += fSource.length(); + fSource.append(source); + fSource.append(";\n"); //$NON-NLS-1$ + + } + fLastTypeName = ""; //$NON-NLS-1$ + } + } + } + + /** + * Create a void ____eval() method considering the given + * {@link BodyDeclaration}s, type name and existing body source when an + * anonymous {@link ClassInstanceCreation} is visited.
+ *
+ * This method adds the new ___eval method source to the root + * {@link #fSource} variable directly + * + * @param isstatic + * if the keyword static should be added to the + * method source + * @param bodydecls + * the existing listing of {@link BodyDeclaration}s to consider + * when creating the ___eval method name + * @param typename + * the raw type name of the type to instantiate in the + * ___eval method + * @param body + * the existing body of source to append to the remainder of the + * new method + * @since 3.7 + */ + void buildAnonymousEvalMethod(boolean isstatic, List bodydecls, + String typename, StringBuilder body) { + if (isstatic) { + fSource.append("static "); //$NON-NLS-1$ + } + adddTypeParameters(fSource); + fSource.append("void "); //$NON-NLS-1$ + fSource.append(getUniqueMethodName(EVAL_METHOD_NAME, bodydecls)); + fSource.append("() {\n"); //$NON-NLS-1$ + fSource.append("new "); //$NON-NLS-1$ + fSource.append(typename); + fSource.append("()"); //$NON-NLS-1$ + + fSnippetStartPosition += fSource.length(); + fSource.append(body); + fSource.append(";}\n"); //$NON-NLS-1$ + } + + /** + * Recursively finds the parent {@link Type} from the given type, in the + * cases where the type is an {@link ArrayType} or a + * {@link ParameterizedType} + * + * @param type + * the {@link Type} + * @return the parent {@link Type} + */ + @SuppressWarnings("deprecation") + private Type getParentType(Type type) { + if (type instanceof ArrayType) { + return getParentType(((ArrayType) type).getComponentType()); + } + if (type instanceof ParameterizedType) { + return getParentType(((ParameterizedType) type).getType()); + } + return type; + } + + /** + * @see ASTVisitor#endVisit(CompilationUnit) + */ + @Override + public void endVisit(CompilationUnit node) { + if (hasError()) { + return; + } + if (!rightTypeFound()) { // if the right type hasn't been found + fSource = null; + return; + } + fSource = buildCompilationUnit(fSource, node); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom + * .EnumDeclaration) + */ + @Override + public void endVisit(EnumDeclaration node) { + + if (hasError()) { + return; + } + + if (!rightTypeFound() && isRightType(node)) { + setRightTypeFound(true); + + fSource = buildRunMethod(node.bodyDeclarations()); + fEvaluateNextEndTypeDeclaration = true; + } + + if (!fEvaluateNextEndTypeDeclaration) { + fEvaluateNextEndTypeDeclaration = true; + return; + } + + if (rightTypeFound()) { + + StringBuilder source = buildEnumDeclaration(fSource, node); + + if (node.isLocalTypeDeclaration()) { + // enclose in a method if necessary + + ASTNode parent = node.getParent(); + while (!(parent instanceof MethodDeclaration)) { + parent = parent.getParent(); + } + MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration) parent; + + fSource = new StringBuilder(); + + if (Flags.isStatic(enclosingMethodDeclaration.getModifiers())) { + fSource.append("static "); //$NON-NLS-1$ + } + + fSource.append("void ___eval() {\n"); //$NON-NLS-1$ + fSnippetStartPosition += fSource.length(); + fSource.append(source); + fSource.append("}\n"); //$NON-NLS-1$ + + fLastTypeName = ""; //$NON-NLS-1$ + } else { + fSource = source; + fLastTypeName = node.getName().getIdentifier(); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.MethodDeclaration) + */ + @Override + public void endVisit(MethodDeclaration node) { + fTypeParameterStack.pop(); + fTypeParameterTypeStack.pop(); + } + + /** + * @see ASTVisitor#endVisit(TypeDeclaration) + */ + @Override + public void endVisit(TypeDeclaration node) { + if (hasError()) { + fTypeParameterStack.pop(); + fTypeParameterTypeStack.pop(); + return; + } + + if (!rightTypeFound() && isRightType(node)) { + setRightTypeFound(true); + + fSource = buildRunMethod(node.bodyDeclarations()); + fEvaluateNextEndTypeDeclaration = true; + } + + if (!fEvaluateNextEndTypeDeclaration) { + fEvaluateNextEndTypeDeclaration = true; + fTypeParameterStack.pop(); + fTypeParameterTypeStack.pop(); + return; + } + + if (rightTypeFound()) { + + StringBuilder source = buildTypeDeclaration(fSource, node); + + if (node.isLocalTypeDeclaration()) { + // enclose in a method if nessecary + + ASTNode parent = node.getParent(); + while (!(parent instanceof MethodDeclaration)) { + parent = parent.getParent(); + } + MethodDeclaration enclosingMethodDeclaration = (MethodDeclaration) parent; + + fSource = new StringBuilder(); + + if (Flags.isStatic(enclosingMethodDeclaration.getModifiers())) { + fSource.append("static "); //$NON-NLS-1$ + } + + fSource.append("void ___eval() {\n"); //$NON-NLS-1$ + fSnippetStartPosition += fSource.length(); + fSource.append(source); + fSource.append("}\n"); //$NON-NLS-1$ + + fLastTypeName = ""; //$NON-NLS-1$ + } else { + fSource = source; + fLastTypeName = node.getName().getIdentifier(); + } + } + fTypeParameterStack.pop(); + fTypeParameterTypeStack.pop(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * AnnotationTypeDeclaration) + */ + @Override + public boolean visit(AnnotationTypeDeclaration node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * AnnotationTypeMemberDeclaration) + */ + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + return false; + } + + /** + * @see ASTVisitor#visit(AnonymousClassDeclaration) + */ + @Override + public boolean visit(AnonymousClassDeclaration node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ArrayAccess) + */ + @Override + public boolean visit(ArrayAccess node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ArrayCreation) + */ + @Override + public boolean visit(ArrayCreation node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ArrayInitializer) + */ + @Override + public boolean visit(ArrayInitializer node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ArrayType) + */ + @Override + public boolean visit(ArrayType node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(AssertStatement) + */ + @Override + public boolean visit(AssertStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(Assignment) + */ + @Override + public boolean visit(Assignment node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(Block) + */ + @Override + public boolean visit(Block node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * BlockComment) + */ + @Override + public boolean visit(BlockComment node) { + return false; + } + + /** + * @see ASTVisitor#visit(BooleanLiteral) + */ + @Override + public boolean visit(BooleanLiteral node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(BreakStatement) + */ + @Override + public boolean visit(BreakStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(CastExpression) + */ + @Override + public boolean visit(CastExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(CatchClause) + */ + @Override + public boolean visit(CatchClause node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(CharacterLiteral) + */ + @Override + public boolean visit(CharacterLiteral node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ClassInstanceCreation) + */ + @Override + public boolean visit(ClassInstanceCreation node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(CompilationUnit) + */ + @Override + public boolean visit(CompilationUnit node) { + fCompilationUnit = node; + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ConditionalExpression) + */ + @Override + public boolean visit(ConditionalExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ConstructorInvocation) + */ + @Override + public boolean visit(ConstructorInvocation node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ContinueStatement) + */ + @Override + public boolean visit(ContinueStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(DoStatement) + */ + @Override + public boolean visit(DoStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(EmptyStatement) + */ + @Override + public boolean visit(EmptyStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnhancedForStatement) + */ + @Override + public boolean visit(EnhancedForStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnumConstantDeclaration) + */ + @Override + public boolean visit(EnumConstantDeclaration node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnumDeclaration) + */ + @Override + public boolean visit(EnumDeclaration node) { + if (rightTypeFound()) { + fEvaluateNextEndTypeDeclaration = false; + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ExpressionStatement) + */ + @Override + public boolean visit(ExpressionStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(FieldAccess) + */ + @Override + public boolean visit(FieldAccess node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(FieldDeclaration) + */ + @Override + public boolean visit(FieldDeclaration node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ForStatement) + */ + @Override + public boolean visit(ForStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(IfStatement) + */ + @Override + public boolean visit(IfStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ImportDeclaration) + */ + @Override + public boolean visit(ImportDeclaration node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(InfixExpression) + */ + @Override + public boolean visit(InfixExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(Initializer) + */ + @Override + public boolean visit(Initializer node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * InstanceofExpression) + */ + @Override + public boolean visit(InstanceofExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(Javadoc) + */ + @Override + public boolean visit(Javadoc node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(LabeledStatement) + */ + @Override + public boolean visit(LabeledStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * LineComment) + */ + @Override + public boolean visit(LineComment node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MarkerAnnotation) + */ + @Override + public boolean visit(MarkerAnnotation node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef + * ) + */ + @Override + public boolean visit(MemberRef node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MemberValuePair) + */ + @Override + public boolean visit(MemberValuePair node) { + return false; + } + + /** + * @see ASTVisitor#visit(MethodDeclaration) + */ + @Override + public boolean visit(MethodDeclaration node) { + int firstLine = fCompilationUnit.getLineNumber(node.getStartPosition()); + int lastLine = fCompilationUnit.getLineNumber(node.getStartPosition() + node.getLength()); + + List typeParameters = node.typeParameters(); + pushTypeParameters(typeParameters, TypeParameterLocation.METHOD); + if (isRightType(node.getParent()) && firstLine <= fLine && fLine <= lastLine + && fTypeParameterTypeStack.peek() == TypeParameterLocation.METHOD) { + fMatchingTypeParameters = fTypeParameterStack.peek(); + } + if (rightTypeFound()) { + return false; + } + return true; + } + + private void pushTypeParameters(List typeParameters, TypeParameterLocation location) { + if (!typeParameters.isEmpty()) { + HashMap newTypeParameters = new HashMap<>(fTypeParameterStack.peek()); + Iterator iterator = typeParameters.iterator(); + while (iterator.hasNext()) { + TypeParameter typeParameter = iterator.next(); + String boundName = typeParameter.getName().getIdentifier(); + newTypeParameters.put(boundName, typeParameter.toString()); + } + fTypeParameterStack.push(newTypeParameters); // Push the new "scope" + fTypeParameterTypeStack.push(location); + } else { + fTypeParameterStack.push(fTypeParameterStack.peek()); // Push the same + fTypeParameterTypeStack.push(fTypeParameterTypeStack.peek()); + } + } + + /** + * @see ASTVisitor#visit(MethodInvocation) + */ + @Override + public boolean visit(MethodInvocation node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef + * ) + */ + @Override + public boolean visit(MethodRef node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MethodRefParameter) + */ + @Override + public boolean visit(MethodRefParameter node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier + * ) + */ + @Override + public boolean visit(Modifier node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * NormalAnnotation) + */ + @Override + public boolean visit(NormalAnnotation node) { + return false; + } + + /** + * @see ASTVisitor#visit(NullLiteral) + */ + @Override + public boolean visit(NullLiteral node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(NumberLiteral) + */ + @Override + public boolean visit(NumberLiteral node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(PackageDeclaration) + */ + @Override + public boolean visit(PackageDeclaration node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * ParameterizedType) + */ + @Override + public boolean visit(ParameterizedType node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ParenthesizedExpression) + */ + @Override + public boolean visit(ParenthesizedExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(PostfixExpression) + */ + @Override + public boolean visit(PostfixExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(PrefixExpression) + */ + @Override + public boolean visit(PrefixExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(PrimitiveType) + */ + @Override + public boolean visit(PrimitiveType node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(QualifiedName) + */ + @Override + public boolean visit(QualifiedName node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * QualifiedType) + */ + @Override + public boolean visit(QualifiedType node) { + return false; + } + + /** + * @see ASTVisitor#visit(ReturnStatement) + */ + @Override + public boolean visit(ReturnStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SimpleName) + */ + @Override + public boolean visit(SimpleName node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SimpleType) + */ + @Override + public boolean visit(SimpleType node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * SingleMemberAnnotation) + */ + @Override + public boolean visit(SingleMemberAnnotation node) { + return false; + } + + /** + * @see ASTVisitor#visit(SingleVariableDeclaration) + */ + @Override + public boolean visit(SingleVariableDeclaration node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(StringLiteral) + */ + @Override + public boolean visit(StringLiteral node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + @Override + public boolean visit(TextBlock node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SuperConstructorInvocation) + */ + @Override + public boolean visit(SuperConstructorInvocation node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SuperFieldAccess) + */ + @Override + public boolean visit(SuperFieldAccess node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SuperMethodInvocation) + */ + @Override + public boolean visit(SuperMethodInvocation node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SwitchCase) + */ + @Override + public boolean visit(SwitchCase node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SwitchStatement) + */ + @Override + public boolean visit(SwitchStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(SynchronizedStatement) + */ + @Override + public boolean visit(SynchronizedStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement + * ) + */ + @Override + public boolean visit(TagElement node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * TextElement) + */ + @Override + public boolean visit(TextElement node) { + return false; + } + + /** + * @see ASTVisitor#visit(ThisExpression) + */ + @Override + public boolean visit(ThisExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(ThrowStatement) + */ + @Override + public boolean visit(ThrowStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(TryStatement) + */ + @Override + public boolean visit(TryStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.UnionType + * ) + */ + @Override + public boolean visit(UnionType node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(TypeDeclaration) + */ + @Override + public boolean visit(TypeDeclaration node) { + List typeParameters = node.typeParameters(); + pushTypeParameters(typeParameters, TypeParameterLocation.TYPE); + if (rightTypeFound()) { + fEvaluateNextEndTypeDeclaration = false; + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(TypeDeclarationStatement) + */ + @Override + public boolean visit(TypeDeclarationStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(TypeLiteral) + */ + @Override + public boolean visit(TypeLiteral node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * TypeParameter) + */ + @Override + public boolean visit(TypeParameter node) { + return false; + } + + /** + * @see ASTVisitor#visit(VariableDeclarationExpression) + */ + @Override + public boolean visit(VariableDeclarationExpression node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(VariableDeclarationFragment) + */ + @Override + public boolean visit(VariableDeclarationFragment node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(VariableDeclarationStatement) + */ + @Override + public boolean visit(VariableDeclarationStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /** + * @see ASTVisitor#visit(WhileStatement) + */ + @Override + public boolean visit(WhileStatement node) { + if (rightTypeFound()) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * WildcardType) + */ + @Override + public boolean visit(WildcardType node) { + return false; + } + + /** + * Returns whether the source to be generated is greater than or equal to + * the given source level. + * + * @param major + * major level - e.g. 1 from 1.4 + * @param minor + * minor level - e.g. 4 from 1.4 + * @return true if the given major / minor version is less than + * or equal to the backing source level + */ + public boolean isSourceLevelGreaterOrEqual(int major, int minor) { + return (fSourceMajorLevel > major) + || (fSourceMajorLevel == major && fSourceMinorLevel >= minor); + } + + /** + * Appends type parameters to source. + * + * @param source + * the current buffer of source to append to + * @param typeParameters + * the list of {@link TypeParameter}s to add + */ + private void appendTypeParameters(StringBuilder source, List typeParameters) { + if (!typeParameters.isEmpty() && isSourceLevelGreaterOrEqual(1, 5)) { + source.append('<'); + Iterator iter = typeParameters.iterator(); + TypeParameter typeParameter = iter.next(); + source.append(typeParameter.getName().getIdentifier()); + List typeBounds = typeParameter.typeBounds(); + if (!typeBounds.isEmpty()) { + source.append(" extends "); //$NON-NLS-1$ + Iterator iter2 = typeBounds.iterator(); + source.append(getTypeName(iter2.next())); + while (iter2.hasNext()) { + source.append('&'); + source.append(getTypeName(iter2.next())); + } + } + while (iter.hasNext()) { + source.append(','); + typeParameter = iter.next(); + source.append(typeParameter.getName().getIdentifier()); + typeBounds = typeParameter.typeBounds(); + if (!typeBounds.isEmpty()) { + source.append(" extends "); //$NON-NLS-1$ + Iterator iter2 = typeBounds.iterator(); + source.append(getTypeName(iter2.next())); + while (iter2.hasNext()) { + source.append('&'); + source.append(getTypeName(iter2.next())); + } + } + } + source.append('>'); + source.append(' '); + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AndAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AndAssignmentOperator.java new file mode 100644 index 0000000000..a8bf56d91a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AndAssignmentOperator.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class AndAssignmentOperator extends AndOperator { + + public AndAssignmentOperator(int variableTypeId, int valueTypeId, int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.AndAssignmentOperator_operator_1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AndOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AndOperator.java new file mode 100644 index 0000000000..59227c45a6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AndOperator.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class AndOperator extends BinaryOperator { + public AndOperator(int resultId, int leftTypeId, int rightTypeId, int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected AndOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperateur, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperateur, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getBooleanValue() + & ((IJavaPrimitiveValue) rightOperand).getBooleanValue(); + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getIntValue() + & ((IJavaPrimitiveValue) rightOperand).getIntValue(); + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getLongValue() + & ((IJavaPrimitiveValue) rightOperand).getLongValue(); + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.AndOperator_____operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayAccess.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayAccess.java new file mode 100644 index 0000000000..7acc335a4e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayAccess.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import java.text.MessageFormat; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + + +/** + * Resolves an array access - the top of the stack is the position, and the + * second from top is the array object. + */ +public class ArrayAccess extends ArrayInstruction { + + public ArrayAccess(int start) { + super(start); + } + + @Override + public void execute() throws CoreException { + int index = ((IJavaPrimitiveValue) popValue()).getIntValue(); + IJavaArray array = popArray(); + if (index >= array.getLength() || index < 0) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + MessageFormat + .format(InstructionsEvaluationMessages.ArrayAccess_illegal_index, + new Object[] { Integer.valueOf(index) }), + null)); + } + push(array.getVariable(index)); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.ArrayAccess_array_access_1; + } + + /** + * Pops an array object off the top of the stack. Throws an exception if not + * an array object or null. + * + * @return array object on top of the stack + * @throws CoreException + * if not available + */ + protected IJavaArray popArray() throws CoreException { + IJavaValue value = popValue(); + if (value instanceof IJavaArray) { + return (IJavaArray) value; + } else if (value.isNull()) { + // null pointer + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + InstructionsEvaluationMessages.ArrayAccess_0, null)); + } else { + // internal error + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + "Internal error: attempt to access non-array object", null)); //$NON-NLS-1$ + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayAllocation.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayAllocation.java new file mode 100644 index 0000000000..8050137fd5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayAllocation.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaType; + +public class ArrayAllocation extends ArrayInstruction { + + private final int fDimension; + + private final int fExprDimension; + + private final boolean fHasInitializer; + + private IJavaArrayType[] fCachedArrayTypes; + + /** + * Constructor for ArrayAllocation. + * + * @param start + */ + public ArrayAllocation(int dimension, int exprDimension, + boolean hasInitializer, int start) { + super(start); + fDimension = dimension; + fExprDimension = exprDimension; + fHasInitializer = hasInitializer; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + if (fHasInitializer) { + IJavaArray array = (IJavaArray) popValue(); + pop(); // pop the type + push(array); + } else { + + int[] exprDimensions = new int[fExprDimension]; + + for (int i = fExprDimension - 1; i >= 0; i--) { + exprDimensions[i] = ((IJavaPrimitiveValue) popValue()) + .getIntValue(); + } + + IJavaType type = (IJavaType) pop(); + + fCachedArrayTypes = new IJavaArrayType[fDimension + 1]; + + for (int i = fDimension, lim = fDimension - fExprDimension; i > lim; i--) { + fCachedArrayTypes[i] = (IJavaArrayType) type; + type = ((IJavaArrayType) type).getComponentType(); + } + + IJavaArray array = createArray(fDimension, exprDimensions); + + push(array); + } + } + + /** + * Create and populate an array. + */ + private IJavaArray createArray(int dimension, int[] exprDimensions) + throws CoreException { + + IJavaArray array = fCachedArrayTypes[dimension] + .newInstance(exprDimensions[0]); + + if (exprDimensions.length > 1) { + int[] newExprDimension = new int[exprDimensions.length - 1]; + for (int i = 0; i < newExprDimension.length; i++) { + newExprDimension[i] = exprDimensions[i + 1]; + } + + for (int i = 0; i < exprDimensions[0]; i++) { + array.setValue(i, createArray(dimension - 1, newExprDimension)); + } + + } + + return array; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.ArrayAllocation_array_allocation_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayInitializerInstruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayInitializerInstruction.java new file mode 100644 index 0000000000..323f7c20f9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayInitializerInstruction.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaArrayType; + +public class ArrayInitializerInstruction extends ArrayInstruction { + + private final String fTypeSignature; + + private final int fDimensions; + + private final int fLength; + + /** + * Constructor for ArrayInitializerInstruction. + * + * @param start + */ + public ArrayInitializerInstruction(String typeSignature, int length, + int dimensions, int start) { + super(start); + fTypeSignature = typeSignature; + fDimensions = dimensions; + fLength = length; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + + IJavaArrayType arrayType = getArrayType( + fTypeSignature.replace('/', '.'), fDimensions); + IJavaArray array = arrayType.newInstance(fLength); + + for (int i = fLength - 1; i >= 0; i--) { + array.setValue(i, popValue()); + } + + push(array); + + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.ArrayInitializerInstruction_array_initializer_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayInstruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayInstruction.java new file mode 100644 index 0000000000..f3d5595872 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ArrayInstruction.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public abstract class ArrayInstruction extends CompoundInstruction { + + public ArrayInstruction(int start) { + super(start); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AssignmentOperator.java new file mode 100644 index 0000000000..9b50463bc3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/AssignmentOperator.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2000, 2021 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.model.JDIPrimitiveValue; + +public class AssignmentOperator extends CompoundInstruction { + + protected int fVariableTypeId; + protected int fValueTypeId; + + public AssignmentOperator(int variableTypeId, int valueTypeId, int start) { + super(start); + fVariableTypeId = variableTypeId; + fValueTypeId = valueTypeId; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaValue value = popValue(); + Object val = pop(); + IJavaVariable variable = null; + if (val instanceof IJavaVariable) { + variable = (IJavaVariable) val; + } else if (val instanceof JDIPrimitiveValue) { + JDIPrimitiveValue jdiPrimitiveValue = (JDIPrimitiveValue) val; + switch (fVariableTypeId) { + case T_boolean: + push(newValue(jdiPrimitiveValue.getBooleanValue())); + break; + case T_byte: + push(newValue(jdiPrimitiveValue.getByteValue())); + break; + case T_short: + push(newValue(jdiPrimitiveValue.getShortValue())); + break; + case T_char: + push(newValue(jdiPrimitiveValue.getCharValue())); + break; + case T_int: + push(newValue(jdiPrimitiveValue.getIntValue())); + break; + case T_long: + push(newValue(jdiPrimitiveValue.getLongValue())); + break; + case T_float: + push(newValue(jdiPrimitiveValue.getFloatValue())); + break; + case T_double: + push(newValue(jdiPrimitiveValue.getDoubleValue())); + break; + } + return; + } + + if (value instanceof IJavaPrimitiveValue) { + IJavaPrimitiveValue primitiveValue = (IJavaPrimitiveValue) value; + switch (fVariableTypeId) { + case T_boolean: + variable.setValue(newValue(primitiveValue.getBooleanValue())); + break; + case T_byte: + variable.setValue(newValue(primitiveValue.getByteValue())); + break; + case T_short: + variable.setValue(newValue(primitiveValue.getShortValue())); + break; + case T_char: + variable.setValue(newValue(primitiveValue.getCharValue())); + break; + case T_int: + variable.setValue(newValue(primitiveValue.getIntValue())); + break; + case T_long: + variable.setValue(newValue(primitiveValue.getLongValue())); + break; + case T_float: + variable.setValue(newValue(primitiveValue.getFloatValue())); + break; + case T_double: + variable.setValue(newValue(primitiveValue.getDoubleValue())); + break; + } + } else { + variable.setValue(value); + } + push(variable.getValue()); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.AssignmentOperator_operator_1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/BinaryOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/BinaryOperator.java new file mode 100644 index 0000000000..753efd617e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/BinaryOperator.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public abstract class BinaryOperator extends CompoundInstruction { + protected int fResultTypeId; + protected int fLeftTypeId; + protected int fRightTypeId; + protected boolean fIsAssignmentOperator; + + protected BinaryOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignementOperator, int start) { + super(start); + fResultTypeId = resultId; + fLeftTypeId = leftTypeId; + fRightTypeId = rightTypeId; + fIsAssignmentOperator = isAssignementOperator; + } + + /* + * @see Instruction#execute() + */ + @Override + final public void execute() throws CoreException { + if (fIsAssignmentOperator) { + executeAssignment(); + } else { + executeBinary(); + } + } + + private void executeAssignment() throws CoreException { + IJavaValue value = popValue(); + IJavaVariable variable = (IJavaVariable) pop(); + IJavaValue variableValue = (IJavaValue) variable.getValue(); + + switch (fResultTypeId) { + case T_byte: + variableValue = getByteValueResult(variableValue, value); + break; + case T_short: + variableValue = getShortValueResult(variableValue, value); + break; + case T_char: + variableValue = getCharValueResult(variableValue, value); + break; + case T_int: + variableValue = getIntValueResult(variableValue, value); + break; + case T_long: + variableValue = getLongValueResult(variableValue, value); + break; + case T_float: + variableValue = getFloatValueResult(variableValue, value); + break; + case T_double: + variableValue = getDoubleValueResult(variableValue, value); + break; + case T_boolean: + variableValue = getBooleanValueResult(variableValue, value); + break; + case T_String: + variableValue = getStringValueResult(variableValue, value); + break; + } + variable.setValue(variableValue); + push(variableValue); + } + + private void executeBinary() throws CoreException { + IJavaValue right = popValue(); + IJavaValue left = popValue(); + + switch (fResultTypeId) { + case T_String: + pushNewValue(getStringResult(left, right)); + break; + case T_double: + pushNewValue(getDoubleResult(left, right)); + break; + case T_float: + pushNewValue(getFloatResult(left, right)); + break; + case T_long: + pushNewValue(getLongResult(left, right)); + break; + case T_int: + pushNewValue(getIntResult(left, right)); + break; + case T_boolean: + pushNewValue(getBooleanResult(left, right)); + break; + } + } + + private IJavaValue getByteValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue((byte) getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue((byte) getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue((byte) getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue((byte) getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getShortValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue((short) getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue((short) getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue((short) getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue((short) getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getCharValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue((char) getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue((char) getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue((char) getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue((char) getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getIntValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue((int) getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue((int) getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue((int) getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue(getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getLongValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue((long) getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue((long) getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue(getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue((long) getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getFloatValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue((float) getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue(getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue((float) getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue((float) getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getDoubleValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + switch (getInternResultType()) { + case T_double: + return newValue(getDoubleResult(leftOperand, rightOperand)); + case T_float: + return newValue((double) getFloatResult(leftOperand, rightOperand)); + case T_long: + return newValue((double) getLongResult(leftOperand, rightOperand)); + case T_int: + return newValue((double) getIntResult(leftOperand, rightOperand)); + default: + return null; + } + } + + private IJavaValue getBooleanValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return newValue(getBooleanResult(leftOperand, rightOperand)); + } + + private IJavaValue getStringValueResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + return newValue(getStringResult(leftOperand, rightOperand)); + } + + protected abstract int getIntResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException; + + protected abstract long getLongResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException; + + protected abstract float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand); + + protected abstract double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand); + + protected abstract boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand); + + protected abstract String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException; + + protected int getInternResultType() { + return getBinaryPromotionType(fLeftTypeId, fRightTypeId); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Cast.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Cast.java new file mode 100644 index 0000000000..1763c87be5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Cast.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDINullValue; +import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTInstructionCompiler; +import org.eclipse.osgi.util.NLS; + +public class Cast extends CompoundInstruction { + + public static final String IS_INSTANCE = "isInstance"; //$NON-NLS-1$ + public static final String IS_INSTANCE_SIGNATURE = "(Ljava/lang/Object;)Z"; //$NON-NLS-1$ + + private final int fTypeTypeId; + + private final String fBaseTypeName; + + private final int fDimension; + + /** + * Cast instruction constructor. + * + * @param typeTypeId + * the id of the type to cast into. + * @param baseTypeName + * the base type name of the type (the type name if the type is + * not an array type. + * @param dimension + * the dimension of the array type, 0 if the type is not an array + * type. + */ + public Cast(int typeTypeId, String baseTypeName, int dimension, int start) { + super(start); + fTypeTypeId = typeTypeId; + fBaseTypeName = baseTypeName; + fDimension = dimension; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaValue value = popValue(); + + if (value instanceof IJavaPrimitiveValue) { + IJavaPrimitiveValue primitiveValue = (IJavaPrimitiveValue) value; + int newTypeId = fTypeTypeId; + if (fTypeTypeId == T_Object) { + newTypeId = ASTInstructionCompiler.getPrimitiveTypeId(value.getJavaType().getName()); + } + switch (newTypeId) { + case T_double: + push(newValue(primitiveValue.getDoubleValue())); + break; + case T_float: + push(newValue(primitiveValue.getFloatValue())); + break; + case T_long: + push(newValue(primitiveValue.getLongValue())); + break; + case T_int: + push(newValue(primitiveValue.getIntValue())); + break; + case T_short: + push(newValue(primitiveValue.getShortValue())); + break; + case T_byte: + push(newValue(primitiveValue.getByteValue())); + break; + case T_char: + push(newValue(primitiveValue.getCharValue())); + break; + } + + } else if (value instanceof JDINullValue) { + // null value can be cast to all non-primitive types (bug 31637). + push(value); + } else { + IJavaObject classObject; + if (fDimension == 0) { + classObject = getClassObject(getType(fBaseTypeName)); + } else { + classObject = getClassObject(getArrayType( + Signature.createTypeSignature(fBaseTypeName, true), + fDimension)); + } + if (classObject == null) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + NLS.bind(InstructionsEvaluationMessages.Cast_No_class_object, + new String[] { typeName() }), + null)); + } + IJavaPrimitiveValue resultValue = (IJavaPrimitiveValue) classObject + .sendMessage(IS_INSTANCE, IS_INSTANCE_SIGNATURE, + new IJavaValue[] { value }, getContext() + .getThread(), false); + if (!resultValue.getBooleanValue()) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + NLS.bind(InstructionsEvaluationMessages.Cast_ClassCastException__Cannot_cast__0__as__1___1, + new String[] { + value.toString(), + typeName() }), null)); + } + + push(value); + } + } + + private String typeName() { + String result = fBaseTypeName; + for (int i = 0; i < fDimension; i++) { + result += "[]"; //$NON-NLS-1$ + } + return result; + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.Cast_cast_3; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/CompoundInstruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/CompoundInstruction.java new file mode 100644 index 0000000000..f60640dec9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/CompoundInstruction.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * A CompoundInstruction is a container instruction and may have a + * size greater than one. + */ +public abstract class CompoundInstruction extends Instruction { + + private int fSize; + + /** + * Constructor for CompoundInstruction. + * + * @param start + */ + protected CompoundInstruction(int start) { + fSize = -start; + } + + public void setEnd(int end) { + fSize += end; + } + + @Override + public int getSize() { + return fSize; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ConditionalJump.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ConditionalJump.java new file mode 100644 index 0000000000..a8f82fb97a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ConditionalJump.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2014 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jacob Saoumi - Bug 434722 error in ConditionalJump Instruction + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class ConditionalJump extends Jump { + private final boolean fJumpOnTrue; + + public ConditionalJump(boolean jumpOnTrue) { + fJumpOnTrue = jumpOnTrue; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaValue conditionValue = popValue(); + IJavaPrimitiveValue condition = null; + if (conditionValue instanceof IJavaPrimitiveValue) { + condition = (IJavaPrimitiveValue) conditionValue; + } else if (conditionValue instanceof IJavaObject) { + if (((IJavaObject) conditionValue).getJavaType().getName().equals("java.lang.Boolean")) { //$NON-NLS-1$ + condition = (IJavaPrimitiveValue) ((IJavaObject) conditionValue).getField("value", false).getValue(); //$NON-NLS-1$ + } + } + + if (!(fJumpOnTrue ^ condition.getBooleanValue())) { + jump(fOffset); + } + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.ConditionalJump_conditional_jump_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Constructor.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Constructor.java new file mode 100644 index 0000000000..cb63cb3499 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Constructor.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaValue; + +/** + * Invokes a constructor. The arguments are on the stack in reverse order, + * followed by the type. Pushes the result onto the stack + */ +public class Constructor extends CompoundInstruction { + + private final int fArgCount; + private final String fSignature; + + public Constructor(String signature, int argCount, int start) { + super(start); + fArgCount = argCount; + fSignature = signature; + } + + @Override + public void execute() throws CoreException { + IJavaValue[] args = new IJavaValue[fArgCount]; + // args are in reverse order + for (int i = fArgCount - 1; i >= 0; i--) { + args[i] = popValue(); + } + IJavaClassType clazz = (IJavaClassType) pop(); + IJavaValue result = clazz.newInstance(fSignature, args, getContext() + .getThread()); + push(result); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.Constructor_constructor__1 + + fSignature; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DivideAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DivideAssignmentOperator.java new file mode 100644 index 0000000000..13bfa4b569 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DivideAssignmentOperator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class DivideAssignmentOperator extends DivideOperator { + + public DivideAssignmentOperator(int variableTypeId, int valueTypeId, + int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.DivideAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DivideOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DivideOperator.java new file mode 100644 index 0000000000..d27b62d0dc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DivideOperator.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +public class DivideOperator extends BinaryOperator { + public DivideOperator(int resultId, int leftTypeId, int rightTypeId, + int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected DivideOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() + / ((IJavaPrimitiveValue) rightOperand).getDoubleValue(); + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() + / ((IJavaPrimitiveValue) rightOperand).getFloatValue(); + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) + throws CoreException { + int divisor = ((IJavaPrimitiveValue) rightOperand).getIntValue(); + if (divisor == 0) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.DivideOperator_Divide_by_zero_1, + null)); + } + return ((IJavaPrimitiveValue) leftOperand).getIntValue() / divisor; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) + throws CoreException { + long divisor = ((IJavaPrimitiveValue) rightOperand).getLongValue(); + if (divisor == 0) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.DivideOperator_Divide_by_zero_2, + null)); + } + return ((IJavaPrimitiveValue) leftOperand).getLongValue() / divisor; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.DivideOperator______operator_3; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Dup.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Dup.java new file mode 100644 index 0000000000..6ba0e36489 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Dup.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +/** + * Duplicate the top element of the stack + * + * Element ... + * + * -> + * + * Element Element ... + * + */ +public class Dup extends SimpleInstruction { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction#execute + * () + */ + @Override + public void execute() throws CoreException { + Object element = pop(); + push(element); + push(element); + } + + @Override + public String toString() { + return "Dup"; //$NON-NLS-1$ + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DupX1.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DupX1.java new file mode 100644 index 0000000000..97026209df --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/DupX1.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +/** + * Duplicate the top element of the stack and put in it behind the second + * element of the stack. + * + * Element1 Element2 ... + * + * -> + * + * Element1 Element2 Element3 ... + * + */ +public class DupX1 extends SimpleInstruction { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction#execute + * () + */ + @Override + public void execute() throws CoreException { + Object element1 = pop(); + Object element2 = pop(); + push(element1); + push(element2); + push(element1); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/EqualEqualOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/EqualEqualOperator.java new file mode 100644 index 0000000000..03d4ee22f3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/EqualEqualOperator.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class EqualEqualOperator extends BinaryOperator { + + private final boolean fIsEquals; + + public EqualEqualOperator(int leftTypeId, int rightTypeId, + boolean isEquals, int start) { + super(T_boolean, leftTypeId, rightTypeId, false, start); + fIsEquals = isEquals; + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + boolean equals = false; + switch (getInternResultType()) { + case T_double: + equals = ((IJavaPrimitiveValue) leftOperand).getDoubleValue() == ((IJavaPrimitiveValue) rightOperand) + .getDoubleValue(); + break; + case T_float: + equals = ((IJavaPrimitiveValue) leftOperand).getFloatValue() == ((IJavaPrimitiveValue) rightOperand) + .getFloatValue(); + break; + case T_long: + equals = ((IJavaPrimitiveValue) leftOperand).getLongValue() == ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + break; + case T_int: + if (leftOperand instanceof IJavaObject) { + // enumerations in switch statement + equals = leftOperand.equals(rightOperand); + } else { + equals = ((IJavaPrimitiveValue) leftOperand).getIntValue() == ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + } + break; + case T_boolean: + equals = ((IJavaPrimitiveValue) leftOperand).getBooleanValue() == ((IJavaPrimitiveValue) rightOperand) + .getBooleanValue(); + break; + default: + equals = leftOperand.equals(rightOperand); + break; + } + return ((fIsEquals) ? equals : !equals); + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.EqualEqualOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/GreaterEqualOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/GreaterEqualOperator.java new file mode 100644 index 0000000000..6e7cd81c39 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/GreaterEqualOperator.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class GreaterEqualOperator extends BinaryOperator { + public GreaterEqualOperator(int leftTypeId, int rightTypeId, int start) { + super(T_boolean, leftTypeId, rightTypeId, false, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + switch (getInternResultType()) { + case T_double: + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() >= ((IJavaPrimitiveValue) rightOperand) + .getDoubleValue(); + case T_float: + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() >= ((IJavaPrimitiveValue) rightOperand) + .getFloatValue(); + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() >= ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() >= ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return false; + } + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.GreaterEqualOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/GreaterOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/GreaterOperator.java new file mode 100644 index 0000000000..9a39d7f967 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/GreaterOperator.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class GreaterOperator extends BinaryOperator { + public GreaterOperator(int leftTypeId, int rightTypeId, int start) { + super(T_boolean, leftTypeId, rightTypeId, false, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + switch (getInternResultType()) { + case T_double: + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() > ((IJavaPrimitiveValue) rightOperand) + .getDoubleValue(); + case T_float: + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() > ((IJavaPrimitiveValue) rightOperand) + .getFloatValue(); + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() > ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() > ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return false; + } + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.GreaterOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstanceOfOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstanceOfOperator.java new file mode 100644 index 0000000000..210e204cc7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstanceOfOperator.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDINullValue; +import org.eclipse.osgi.util.NLS; + +public class InstanceOfOperator extends CompoundInstruction { + public static final String IS_INSTANCE = "isInstance"; //$NON-NLS-1$ + public static final String IS_INSTANCE_SIGNATURE = "(Ljava/lang/Object;)Z"; //$NON-NLS-1$ + + public InstanceOfOperator(int start) { + super(start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaType type = (IJavaType) pop(); + IJavaValue value = popValue(); + if (value instanceof JDINullValue) { + pushNewValue(false); + return; + } + IJavaObject object = (IJavaObject) value; + + IJavaObject classObject = getClassObject(type); + if (classObject == null) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + NLS.bind(InstructionsEvaluationMessages.InstanceOfOperator_No_class_object, + new String[] { type.getName() }), + null)); + } + push(classObject.sendMessage(IS_INSTANCE, IS_INSTANCE_SIGNATURE, + new IJavaValue[] { object }, getContext().getThread(), false)); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.InstanceOfOperator__instanceof___operator_3; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Instruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Instruction.java new file mode 100644 index 0000000000..c33cd8554f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Instruction.java @@ -0,0 +1,388 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; +import org.eclipse.jdt.internal.debug.eval.ast.engine.Interpreter; +import org.eclipse.osgi.util.NLS; + +/** + * Common behavior for instructions. + */ +public abstract class Instruction { + + private Interpreter fInterpreter; + + public abstract int getSize(); + + public void setInterpreter(Interpreter interpreter) { + fInterpreter = interpreter; + } + + public void setLastValue(IJavaValue value) { + fInterpreter.setLastValue(value); + } + + public void stop() { + fInterpreter.stop(); + } + + public static int getBinaryPromotionType(int left, int right) { + return fTypeTable[left][right]; + } + + public abstract void execute() throws CoreException; + + protected IRuntimeContext getContext() { + return fInterpreter.getContext(); + } + + protected IJavaDebugTarget getVM() { + return getContext().getVM(); + } + + /** + * Return the internal variable with the given name. + * + * @see Interpreter#getInternalVariable(String) + */ + protected IVariable getInternalVariable(String name) { + return fInterpreter.getInternalVariable(name); + } + + /** + * Create and return a new internal variable with the given name and the + * given type. + * + * @see Interpreter#createInternalVariable(String, String) + */ + protected IVariable createInternalVariable(String name, + IJavaType referencType) { + return fInterpreter.createInternalVariable(name, referencType); + } + + /** + * Answers the instance of Class that the given type represents. + */ + protected IJavaObject getClassObject(IJavaType type) throws CoreException { + if (type instanceof IJavaReferenceType) { + return ((IJavaReferenceType) type).getClassObject(); + } + return null; + } + + protected void jump(int offset) { + fInterpreter.jump(offset); + } + + protected void push(Object object) { + fInterpreter.push(object); + } + + protected Object pop() { + return fInterpreter.pop(); + } + + protected IJavaValue popValue() throws CoreException { + Object element = fInterpreter.pop(); + if (element instanceof IJavaVariable) { + return (IJavaValue) ((IJavaVariable) element).getValue(); + } + return (IJavaValue) element; + } + + protected void pushNewValue(boolean value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(boolean value) { + return getVM().newValue(value); + } + + protected void pushNewValue(byte value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(byte value) { + return getVM().newValue(value); + } + + protected void pushNewValue(short value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(short value) { + return getVM().newValue(value); + } + + protected void pushNewValue(int value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(int value) { + return getVM().newValue(value); + } + + protected void pushNewValue(long value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(long value) { + return getVM().newValue(value); + } + + protected void pushNewValue(char value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(char value) { + return getVM().newValue(value); + } + + protected void pushNewValue(float value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(float value) { + return getVM().newValue(value); + } + + protected void pushNewValue(double value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(double value) { + return getVM().newValue(value); + } + + protected void pushNewValue(String value) { + fInterpreter.push(newValue(value)); + } + + protected IJavaValue newValue(String value) { + return getVM().newValue(value); + } + + protected void pushNullValue() { + fInterpreter.push(nullValue()); + } + + protected IJavaValue nullValue() { + return getVM().nullValue(); + } + + public static int getUnaryPromotionType(int typeId) { + return fTypeTable[typeId][T_int]; + } + + protected IJavaType getType(String qualifiedName) throws CoreException { + // Force the class to be loaded, and record the class reference + // for later use if there are multiple classes with the same name. + IJavaClassObject classReference = getContext().classForName( + qualifiedName); + // Found many classes, look for the right one for this scope. + if (classReference == null) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + NLS.bind( + InstructionsEvaluationMessages.Instruction_No_type, + new String[] { qualifiedName }), null)); + } + return classReference.getInstanceType(); + } + + /** + * Returns the primitive type with the given name. + * + * @param name + * type name, for example - "int" + * @return primitive type + * @throws CoreException + */ + protected IJavaType getPrimitiveType(String name) throws CoreException { + IJavaReferenceType type = null; + if (name != null) { + switch (name) { + case "boolean": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Boolean"); //$NON-NLS-1$ + break; + case "byte": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Byte"); //$NON-NLS-1$ + break; + case "char": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Character"); //$NON-NLS-1$ + break; + case "double": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Double"); //$NON-NLS-1$ + break; + case "float": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Float"); //$NON-NLS-1$ + break; + case "int": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Integer"); //$NON-NLS-1$ + break; + case "long": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Long"); //$NON-NLS-1$ + break; + case "short": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Short"); //$NON-NLS-1$ + break; + case "void": //$NON-NLS-1$ + type = (IJavaReferenceType) getType("java.lang.Void"); //$NON-NLS-1$ + break; + default: + break; + } + } + if (type != null) { + IJavaFieldVariable field = type.getField("TYPE"); //$NON-NLS-1$ + IJavaClassObject clazz = (IJavaClassObject) field.getValue(); + return clazz.getInstanceType(); + } + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + NLS.bind( + InstructionsEvaluationMessages.Instruction_No_type, + new String[] { name }), null)); + } + + protected IJavaArrayType getArrayType(String typeSignature, int dimension) + throws CoreException { + String qualifiedName = RuntimeSignature.toString(typeSignature); + String braces = ""; //$NON-NLS-1$ + for (int i = 0; i < dimension; i++) { + qualifiedName += "[]"; //$NON-NLS-1$ + braces += "["; //$NON-NLS-1$ + } + String signature = braces + typeSignature; + // Force the class to be loaded, and record the class reference + // for later use if there are multiple classes with the same name. + IJavaObject classReference = getContext().classForName(signature); + if (classReference == null) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + NLS.bind( + InstructionsEvaluationMessages.Instruction_No_type, + new String[] { qualifiedName }), null)); + } + IJavaType[] types = getVM().getJavaTypes(qualifiedName); + checkTypes(types, qualifiedName); + if (types.length == 1) { + // Found only one class. + return (IJavaArrayType) types[0]; + } + // Found many classes, look for the right one for this scope. + for (IJavaType type : types) { + if (classReference.equals(getClassObject(type))) { + return (IJavaArrayType) type; + } + } + + // At this point a very strange thing has happened, + // the VM was able to return multiple types in the classesByName + // call, but none of them were the class that was returned in + // the classForName call. + + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + NLS.bind( + InstructionsEvaluationMessages.Instruction_No_type, + new String[] { qualifiedName }), null)); + } + + protected void checkTypes(IJavaType[] types, String qualifiedName) + throws CoreException { + if (types == null || types.length == 0) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + NLS.bind( + InstructionsEvaluationMessages.Instruction_No_type, + new String[] { qualifiedName }), null)); + } + } + + static public final int T_undefined = 0; + static public final int T_Object = 1; + static public final int T_char = 2; + static public final int T_byte = 3; + static public final int T_short = 4; + static public final int T_boolean = 5; + static public final int T_void = 6; + static public final int T_long = 7; + static public final int T_double = 8; + static public final int T_float = 9; + static public final int T_int = 10; + static public final int T_String = 11; + static public final int T_null = 12; + + private static final int[][] fTypeTable = { + /* undefined */{ T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined }, + /* object */{ T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_String, + T_undefined }, + /* char */{ T_undefined, T_undefined, T_int, T_int, T_int, + T_undefined, T_undefined, T_long, T_double, T_float, T_int, + T_String, T_undefined }, + /* byte */{ T_undefined, T_undefined, T_int, T_int, T_int, + T_undefined, T_undefined, T_long, T_double, T_float, T_int, + T_String, T_undefined }, + /* short */{ T_undefined, T_undefined, T_int, T_int, T_int, + T_undefined, T_undefined, T_long, T_double, T_float, T_int, + T_String, T_undefined }, + /* boolean */{ T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_boolean, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_String, + T_undefined }, + /* void */{ T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined }, + /* long */{ T_undefined, T_undefined, T_long, T_long, T_long, + T_undefined, T_undefined, T_long, T_double, T_float, + T_long, T_String, T_undefined }, + /* double */{ T_undefined, T_undefined, T_double, T_double, + T_double, T_undefined, T_undefined, T_double, T_double, + T_double, T_double, T_String, T_undefined }, + /* float */{ T_undefined, T_undefined, T_float, T_float, T_float, + T_undefined, T_undefined, T_float, T_double, T_float, + T_float, T_String, T_undefined }, + /* int */{ T_undefined, T_undefined, T_int, T_int, T_int, + T_undefined, T_undefined, T_long, T_double, T_float, T_int, + T_String, T_undefined }, + /* String */{ T_undefined, T_String, T_String, T_String, T_String, + T_String, T_undefined, T_String, T_String, T_String, + T_String, T_String, T_String }, + /* null */{ T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_undefined, + T_undefined, T_undefined, T_undefined, T_String, + T_undefined }, }; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionSequence.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionSequence.java new file mode 100644 index 0000000000..750c7dc8b6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionSequence.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.debug.eval.ICompiledExpression; + +public class InstructionSequence implements ICompiledExpression { + + private final List fInstructions; + /** + * A collection of error messages (String) that occurred while + * creating this expression + */ + private final List fErrors; + private final String fSnippet; + private CoreException fException; + + public InstructionSequence(String snippet) { + fInstructions = new ArrayList<>(10); + fErrors = new ArrayList<>(); + fSnippet = snippet; + } + + /** + * Returns the runtime exception that occurred while evaluating this + * expression or null if no exception occurred. + */ + public CoreException getException() { + return fException; + } + + /** + * @see ICompiledExpression#getSnippet() + */ + @Override + public String getSnippet() { + return fSnippet; + } + + /** + * Adds the given error to the list of errors that occurred while compiling + * this instruction sequence + */ + public void addError(String error) { + fErrors.add(error); + } + + /** + * @see ICompiledExpression#hasErrors() + */ + @Override + public boolean hasErrors() { + return !fErrors.isEmpty(); + } + + /** + * @see ICompiledExpression#getErrors() + * @deprecated + */ + @Override + @Deprecated + public Message[] getErrors() { + Message[] messages = new Message[fErrors.size()]; + int i = 0; + for (String errorMsg : fErrors) { + messages[i++] = new Message(errorMsg, -1); + } + return messages; + } + + /** + * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getErrorMessages() + */ + @Override + public String[] getErrorMessages() { + return fErrors.toArray(new String[fErrors.size()]); + } + + /** + * Answers the array of instructions, or an empty array. + */ + public Instruction[] getInstructions() { + int size = fInstructions.size(); + Instruction[] instructions = new Instruction[size]; + if (size > 0) { + fInstructions.toArray(instructions); + } + return instructions; + } + + /** + * Answer the instruction at the given address + */ + public Instruction getInstruction(int address) { + return fInstructions.get(address); + } + + /** + * Add the given instruction to the end of the list + */ + public void add(Instruction instruction) { + fInstructions.add(instruction); + } + + public int indexOf(Instruction instruction) { + return fInstructions.indexOf(instruction); + } + + /** + * Answers true if there are no instructions in this sequence + */ + public boolean isEmpty() { + return fInstructions.isEmpty(); + } + + /** + * Inserts the instruction at the given index. If the index is less than 0 + * or greater than the current instruction count, the instruction is added + * at the end of the sequence. + * + * Instructs the instructions to update their program counters. + */ + public void insert(Instruction instruction, int index) { + fInstructions.add(index, instruction); + } + + public Instruction get(int address) { + return fInstructions.get(address); + } + + public int getEnd() { + return fInstructions.size() - 1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionsEvaluationMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionsEvaluationMessages.java new file mode 100644 index 0000000000..9d92c16a27 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionsEvaluationMessages.java @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.osgi.util.NLS; + +public class InstructionsEvaluationMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionsEvaluationMessages";//$NON-NLS-1$ + + public static String AndAssignmentOperator_operator_1; + public static String AndOperator_____operator_1; + public static String ArrayAccess_0; + + public static String ArrayAccess_array_access_1; + public static String ArrayAccess_illegal_index; + public static String ArrayAllocation_array_allocation_1; + public static String ArrayInitializerInstruction_array_initializer_1; + public static String AssignmentOperator_operator_1; + public static String Cast_ClassCastException__Cannot_cast__0__as__1___1; + public static String Cast_cast_3; + public static String Run_Remote_1; + public static String ConditionalJump_conditional_jump_1; + public static String Constructor_constructor__1; + public static String LocalVariableCreation_create_local_variable__0___1___1; + public static String DivideAssignmentOperator_operator_1; + public static String DivideOperator_Divide_by_zero_1; + public static String DivideOperator_Divide_by_zero_2; + public static String DivideOperator______operator_3; + public static String EqualEqualOperator_operator_1; + public static String GreaterEqualOperator_operator_1; + public static String GreaterOperator______operator_1; + public static String InstanceOfOperator__instanceof___operator_3; + + public static String Jump_jump_1; + public static String LeftShiftAssignmentOperator_operator_1; + public static String LeftShiftOperator_______operator_1; + public static String LessEqualOperator_operator_1; + public static String LessOperator______operator_1; + public static String MinusAssignmentOperator_operator_1; + public static String MinusOperator______operator_1; + public static String MultiplyAssignmentOperator_operator_1; + public static String MultiplyOperator______operator_1; + public static String NoOp_no_op_1; + public static String NotOperator______operator_1; + public static String OrAssignmentOperator_operator_1; + public static String OrOperator______operator_1; + public static String PlusAssignmentOperator_operator_1; + public static String PlusOperator______operator_2; + public static String Pop_pop_1; + public static String PostfixMinusMinusOperator_postfix________operator_1; + public static String PostfixPlusPlusOperator_postfix________operator_1; + public static String PrefixMinusMinusOperator_prefix________operator_1; + public static String PrefixPlusPlusOperator_prefix________operator_1; + public static String PushBoolean_push__1; + public static String PushFieldVariable_0; + public static String PushChar_push__1; + public static String PushClassLiteralValue_push_class_literal_value_1; + public static String PushDouble_push__1; + public static String PushFieldVariable_Cannot_find_the_field__0__for_the_object__1__1; + public static String PushFieldVariable_push_field__0__2; + public static String PushArrayLength_push_array_length__1; + public static String PushFloat_push__1; + public static String PushInt_push__1; + public static String PushLong_push__1; + public static String PushNull_push___null__1; + public static String PushString_push__1; + public static String PushThis_push___this__1; + public static String PushThis_Unable_to_retrieve_the_correct_enclosing_instance_of__this__2; + public static String PushType_push_type__1; + public static String RemainderAssignmentOperator_operator_1; + public static String RemainderOperator_Divide_by_zero_1; + public static String RemainderOperator_Divide_by_zero_2; + public static String RemainderOperator______operator_3; + public static String ReturnInstruction_return; + public static String RightShiftAssignmentOperator_operator_1; + public static String RightShiftOperator_______operator_1; + public static String TwiddleOperator______operator_1; + public static String UnaryMinusOperator_unary_minus_operator_1; + public static String UnaryPlusOperator_unary_plus_operator_1; + public static String UnsignedRightShiftAssignmentOperator_operator_1; + public static String UnsignedRightShiftOperator________operator_1; + public static String XorAssignmentOperator_operator_1; + public static String XorOperator______operator_1; + public static String PushLocalVariable_Cannot_find_the_variable____1; + public static String PushLocalVariable_push____0___2; + public static String PushStaticFieldVariable_Cannot_find_the_field__0__in__1__1; + public static String PushStaticFieldVariable_push_static_field__0__2; + public static String SendMessage_Attempt_to_send_a_message_to_a_non_object_value_1; + public static String SendMessage_send_message__0___1__2; + public static String SendStaticMessage_Cannot_send_a_static_message_to_a_non_class_type_object_1; + public static String SendStaticMessage_send_static_message__0___1__2; + public static String Instruction_No_type; + public static String InstanceOfOperator_No_class_object; + public static String Cast_No_class_object; + public static String LocalVariableCreation_Execution_failed___VM_disconnected__1; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, + InstructionsEvaluationMessages.class); + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionsEvaluationMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionsEvaluationMessages.properties new file mode 100644 index 0000000000..15f12608a7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/InstructionsEvaluationMessages.properties @@ -0,0 +1,99 @@ +############################################################################### +# Copyright (c) 2000, 2009 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +AndAssignmentOperator_operator_1='&=\' operator +AndOperator_____operator_1='&\' operator +ArrayAccess_0=Null pointer exception: attempt to access null array object +ArrayAccess_array_access_1=array access +ArrayAccess_illegal_index=Attempt to access illegal array index: {0} +ArrayAllocation_array_allocation_1=array allocation +ArrayInitializerInstruction_array_initializer_1=array initializer +AssignmentOperator_operator_1='=\' operator +Cast_ClassCastException__Cannot_cast__0__as__1___1=ClassCastException: Cannot cast {0} to {1} +Cast_cast_3=cast +ConditionalJump_conditional_jump_1=conditional jump +Constructor_constructor__1=constructor +Run_Remote_1=run remote code +LocalVariableCreation_create_local_variable__0___1___1=Create local variable {1} {0} +DivideAssignmentOperator_operator_1='/=\' operator +DivideOperator_Divide_by_zero_1=Divide by zero +DivideOperator_Divide_by_zero_2=Divide by zero +DivideOperator______operator_3='/\' operator +EqualEqualOperator_operator_1='==\' operator +GreaterEqualOperator_operator_1='>=\' operator +GreaterOperator______operator_1='>\' operator +InstanceOfOperator__instanceof___operator_3='instanceof\' operator + +Jump_jump_1=jump +LeftShiftAssignmentOperator_operator_1='<<=\' operator +LeftShiftOperator_______operator_1='<<\' operator +LessEqualOperator_operator_1='<=\' operator +LessOperator______operator_1='<\' operator +MinusAssignmentOperator_operator_1='-=\' operator +MinusOperator______operator_1='-\' operator +MultiplyAssignmentOperator_operator_1='*=\' operator +MultiplyOperator______operator_1='*\' operator +NoOp_no_op_1=no op +NotOperator______operator_1='!\' operator +OrAssignmentOperator_operator_1='|=\' operator +OrOperator______operator_1='|\' operator +PlusAssignmentOperator_operator_1='+=\' operator +PlusOperator______operator_2='+\' operator +Pop_pop_1=pop +PostfixMinusMinusOperator_postfix________operator_1=postfix \'--\' operator +PostfixPlusPlusOperator_postfix________operator_1=postfix \'++\' operator +PrefixMinusMinusOperator_prefix________operator_1=prefix \'--\' operator +PrefixPlusPlusOperator_prefix________operator_1=prefix \'++\' operator +PushBoolean_push__1=push +PushFieldVariable_0=Field access attempt on a null object +PushChar_push__1=push +PushClassLiteralValue_push_class_literal_value_1=push class literal value +PushDouble_push__1=push +PushFieldVariable_Cannot_find_the_field__0__for_the_object__1__1=Cannot find the field {0} for the object {1} +PushFieldVariable_push_field__0__2=push field {0} +PushArrayLength_push_array_length__1=push array length +PushFloat_push__1=push +PushInt_push__1=push +PushLong_push__1=push +PushNull_push___null__1=push \'null' +PushString_push__1=push +PushThis_push___this__1=push \'this' +PushThis_Unable_to_retrieve_the_correct_enclosing_instance_of__this__2=Unable to retrieve the correct enclosing instance of \'this' +PushType_push_type__1=push type +RemainderAssignmentOperator_operator_1='%=\' operator +RemainderOperator_Divide_by_zero_1=Divide by zero +RemainderOperator_Divide_by_zero_2=Divide by zero +RemainderOperator______operator_3='%\' operator +ReturnInstruction_return=return +RightShiftAssignmentOperator_operator_1='>>=\' operator +RightShiftOperator_______operator_1='>>\' operator +TwiddleOperator______operator_1='~\' operator +UnaryMinusOperator_unary_minus_operator_1=unary minus operator +UnaryPlusOperator_unary_plus_operator_1=unary plus operator +UnsignedRightShiftAssignmentOperator_operator_1='>>>=\' operator +UnsignedRightShiftOperator________operator_1='>>>\' operator +XorAssignmentOperator_operator_1='^=\' operator +XorOperator______operator_1='^\' operator +PushLocalVariable_Cannot_find_the_variable____1=Cannot find the variable {0}: +PushLocalVariable_push____0___2=push \"{0}\" +PushStaticFieldVariable_Cannot_find_the_field__0__in__1__1=Cannot find the field {0} in {1} +PushStaticFieldVariable_push_static_field__0__2=push static field {0} +SendMessage_Attempt_to_send_a_message_to_a_non_object_value_1=Attempt to send a message to a non object value +SendMessage_send_message__0___1__2=send message {0} {1} +SendStaticMessage_Cannot_send_a_static_message_to_a_non_class_type_object_1=Cannot send a static message to a non class type object +SendStaticMessage_send_static_message__0___1__2=send static message {0} {1} +Instruction_No_type=could not resolve type: {0} +InstanceOfOperator_No_class_object=could not get the class object for {0} +Cast_No_class_object=could not get the class object for {0} +LocalVariableCreation_Execution_failed___VM_disconnected__1=Execution failed - VM disconnected. diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Jump.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Jump.java new file mode 100644 index 0000000000..7b556b7a9a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Jump.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +public class Jump extends SimpleInstruction { + protected int fOffset; + + public void setOffset(int offset) { + fOffset = offset; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + jump(fOffset); + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.Jump_jump_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LeftShiftAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LeftShiftAssignmentOperator.java new file mode 100644 index 0000000000..2db80c579c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LeftShiftAssignmentOperator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class LeftShiftAssignmentOperator extends LeftShiftOperator { + + public LeftShiftAssignmentOperator(int variableTypeId, int valueTypeId, + int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.LeftShiftAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LeftShiftOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LeftShiftOperator.java new file mode 100644 index 0000000000..66f87b65e6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LeftShiftOperator.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class LeftShiftOperator extends BinaryOperator { + public LeftShiftOperator(int resultId, int leftTypeId, int rightTypeId, + int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected LeftShiftOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + // unary type promotion on both operands see 5.6.1 and 15.18 + switch (fRightTypeId) { + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() << ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + case T_short: + case T_byte: + case T_char: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() << ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return 0; + } + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + // unary type promotion on both operands see 5.6.1 and 15.18 + switch (fRightTypeId) { + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() << ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + case T_short: + case T_byte: + case T_char: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() << ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return 0; + } + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + protected int getInternResultType() { + // unary type promotion on both operands see 5.6.1 and 15.18 + return getUnaryPromotionType(fLeftTypeId); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.LeftShiftOperator_______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LessEqualOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LessEqualOperator.java new file mode 100644 index 0000000000..0ddd9ccb12 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LessEqualOperator.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class LessEqualOperator extends BinaryOperator { + public LessEqualOperator(int leftTypeId, int rightTypeId, int start) { + super(T_boolean, leftTypeId, rightTypeId, false, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + switch (getInternResultType()) { + case T_double: + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() <= ((IJavaPrimitiveValue) rightOperand) + .getDoubleValue(); + case T_float: + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() <= ((IJavaPrimitiveValue) rightOperand) + .getFloatValue(); + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() <= ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() <= ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return false; + } + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.LessEqualOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LessOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LessOperator.java new file mode 100644 index 0000000000..5adf620f5c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LessOperator.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class LessOperator extends BinaryOperator { + public LessOperator(int leftTypeId, int rightTypeId, int start) { + super(T_boolean, leftTypeId, rightTypeId, false, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + switch (getInternResultType()) { + case T_double: + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() < ((IJavaPrimitiveValue) rightOperand) + .getDoubleValue(); + case T_float: + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() < ((IJavaPrimitiveValue) rightOperand) + .getFloatValue(); + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() < ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() < ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return false; + } + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.LessOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LocalVariableCreation.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LocalVariableCreation.java new file mode 100644 index 0000000000..63bd3bb4cf --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/LocalVariableCreation.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdi.internal.PrimitiveTypeImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIType; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; + +public class LocalVariableCreation extends CompoundInstruction { + + /** + * Indicate if the type is a primitive type. + */ + private final boolean fIsPrimitiveType; + + /** + * The name of the variable to create. + */ + private final String fName; + + /** + * The signature of the type, or of the element type in case of an array + * type. + */ + private final String fTypeSignature; + + /** + * The dimension of the array type. + */ + private final int fDimension; + + /** + * Indicate if there is an initializer for this variable. + */ + private final boolean fHasInitializer; + + /** + * Constructor for LocalVariableCreation. + * + * @param name + * the name of the variable to create. + * @param typeSignature + * the signature of the type, or of the element type in case of + * an array type. + * @param dimension + * the dimension of the array type, 0 if it's not an + * array type. + * @param isPrimitiveType + * indicate if the type is a primitive type. + * @param hasInitializer + * indicate if there is an initializer for this variable. + * @param start + */ + public LocalVariableCreation(String name, String typeSignature, + int dimension, boolean isPrimitiveType, boolean hasInitializer, + int start) { + super(start); + fName = name; + fTypeSignature = typeSignature.replace('/', '.'); + fIsPrimitiveType = isPrimitiveType; + fHasInitializer = hasInitializer; + fDimension = dimension; + } + + /** + * @see org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaType type; + if (fIsPrimitiveType) { + JDIDebugTarget debugTarget = (JDIDebugTarget) getVM(); + VirtualMachine vm = debugTarget.getVM(); + if (vm == null) { + debugTarget + .requestFailed( + InstructionsEvaluationMessages.LocalVariableCreation_Execution_failed___VM_disconnected__1, + new VMDisconnectedException()); + } + type = JDIType.createType(debugTarget, PrimitiveTypeImpl.create( + (VirtualMachineImpl) vm, fTypeSignature)); + } else if (fDimension == 0) { + type = getType(RuntimeSignature.toString(fTypeSignature)); // See + // Bug + // 22165 + } else { + type = getArrayType(fTypeSignature, fDimension); + } + IVariable var = createInternalVariable(fName, type); + if (fHasInitializer) { + var.setValue(popValue()); + } + } + + @Override + public String toString() { + return NLS.bind(InstructionsEvaluationMessages.LocalVariableCreation_create_local_variable__0___1___1, + new String[] { fName, fTypeSignature }); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MinusAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MinusAssignmentOperator.java new file mode 100644 index 0000000000..0bb0153ca4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MinusAssignmentOperator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class MinusAssignmentOperator extends MinusOperator { + + public MinusAssignmentOperator(int variableTypeId, int valueTypeId, + int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.MinusAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MinusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MinusOperator.java new file mode 100644 index 0000000000..126dd52810 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MinusOperator.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class MinusOperator extends BinaryOperator { + + public MinusOperator(int resultId, int leftTypeId, int rightTypeId, + int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected MinusOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() + - ((IJavaPrimitiveValue) rightOperand).getDoubleValue(); + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() + - ((IJavaPrimitiveValue) rightOperand).getFloatValue(); + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getIntValue() + - ((IJavaPrimitiveValue) rightOperand).getIntValue(); + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getLongValue() + - ((IJavaPrimitiveValue) rightOperand).getLongValue(); + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.MinusOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MultiplyAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MultiplyAssignmentOperator.java new file mode 100644 index 0000000000..790ad6cdc7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MultiplyAssignmentOperator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class MultiplyAssignmentOperator extends MultiplyOperator { + + public MultiplyAssignmentOperator(int variableTypeId, int valueTypeId, + int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.MultiplyAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MultiplyOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MultiplyOperator.java new file mode 100644 index 0000000000..5145e8b08d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/MultiplyOperator.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class MultiplyOperator extends BinaryOperator { + public MultiplyOperator(int resultId, int leftTypeId, int rightTypeId, + int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected MultiplyOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() + * ((IJavaPrimitiveValue) rightOperand).getDoubleValue(); + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() + * ((IJavaPrimitiveValue) rightOperand).getFloatValue(); + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getIntValue() + * ((IJavaPrimitiveValue) rightOperand).getIntValue(); + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getLongValue() + * ((IJavaPrimitiveValue) rightOperand).getLongValue(); + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.MultiplyOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/NoOp.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/NoOp.java new file mode 100644 index 0000000000..31afe29dbc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/NoOp.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class NoOp extends CompoundInstruction { + + public NoOp(int start) { + super(start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() { + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.NoOp_no_op_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/NotOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/NotOperator.java new file mode 100644 index 0000000000..4aafa22c6d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/NotOperator.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; + +public class NotOperator extends UnaryOperator { + + public NotOperator(int expressionTypeId, int start) { + super(expressionTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaPrimitiveValue value = (IJavaPrimitiveValue) popValue(); + pushNewValue(!value.getBooleanValue()); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.NotOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/OrAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/OrAssignmentOperator.java new file mode 100644 index 0000000000..47143275ef --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/OrAssignmentOperator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class OrAssignmentOperator extends OrOperator { + + public OrAssignmentOperator(int variableTypeId, int valueTypeId, int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.OrAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/OrOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/OrOperator.java new file mode 100644 index 0000000000..dfab66ef2e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/OrOperator.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class OrOperator extends BinaryOperator { + public OrOperator(int resultId, int leftTypeId, int rightTypeId, int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected OrOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getBooleanValue() + | ((IJavaPrimitiveValue) rightOperand).getBooleanValue(); + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getIntValue() + | ((IJavaPrimitiveValue) rightOperand).getIntValue(); + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getLongValue() + | ((IJavaPrimitiveValue) rightOperand).getLongValue(); + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.OrOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PlusAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PlusAssignmentOperator.java new file mode 100644 index 0000000000..7de1960a8f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PlusAssignmentOperator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class PlusAssignmentOperator extends PlusOperator { + + public PlusAssignmentOperator(int variableTypeId, int valueTypeId, int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PlusAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PlusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PlusOperator.java new file mode 100644 index 0000000000..ddb2618021 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PlusOperator.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.model.JDINullValue; + +public class PlusOperator extends BinaryOperator { + + public static final String NULL = "null"; //$NON-NLS-1$ + public static final String TOSTRING_SELECTOR = "toString"; //$NON-NLS-1$ + public static final String TOSTRING_SIGNATURE = "()Ljava/lang/String;"; //$NON-NLS-1$ + + public PlusOperator(int resultId, int leftTypeId, int rightTypeId, int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected PlusOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + private String getString(IJavaValue value, int typeId) + throws DebugException { + + // test if value == null + if (value instanceof JDINullValue) { + return NULL; + } + + if (value instanceof IJavaObject) { + if (typeId == T_String) { + return value.getValueString(); + } + return ((IJavaObject) value).sendMessage(TOSTRING_SELECTOR, + TOSTRING_SIGNATURE, null, getContext().getThread(), null) + .getValueString(); + } + + IJavaPrimitiveValue primitiveValue = (IJavaPrimitiveValue) value; + switch (typeId) { + case T_boolean: + return Boolean.toString(primitiveValue.getBooleanValue()); + case T_byte: + return Integer.toString(primitiveValue.getByteValue()); + case T_char: + return Character.toString(primitiveValue.getCharValue()); + case T_double: + return Double.toString(primitiveValue.getDoubleValue()); + case T_float: + return Float.toString(primitiveValue.getFloatValue()); + case T_int: + return Integer.toString(primitiveValue.getIntValue()); + case T_long: + return Long.toString(primitiveValue.getLongValue()); + case T_short: + return Integer.toString(primitiveValue.getShortValue()); + } + return NULL; + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() + + ((IJavaPrimitiveValue) rightOperand).getDoubleValue(); + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() + + ((IJavaPrimitiveValue) rightOperand).getFloatValue(); + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getIntValue() + + ((IJavaPrimitiveValue) rightOperand).getIntValue(); + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getLongValue() + + ((IJavaPrimitiveValue) rightOperand).getLongValue(); + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) throws CoreException { + return getString(leftOperand, fLeftTypeId) + + getString(rightOperand, fRightTypeId); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PlusOperator______operator_2; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Pop.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Pop.java new file mode 100644 index 0000000000..af268ed6c1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Pop.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class Pop extends Instruction { + + private final int fSize; + + /** + * @param start + */ + public Pop(int size) { + fSize = size; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() { + pop(); + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.Pop_pop_1; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction#getSize + * () + */ + @Override + public int getSize() { + return fSize; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PostfixMinusMinusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PostfixMinusMinusOperator.java new file mode 100644 index 0000000000..e0d03736a5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PostfixMinusMinusOperator.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public class PostfixMinusMinusOperator extends XfixOperator { + + public PostfixMinusMinusOperator(int variableTypeId, int start) { + super(variableTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaVariable variable = (IJavaVariable) pop(); + push(variable.getValue()); + + switch (fVariableTypeId) { + case T_byte: + variable.setValue(newValue((byte) (((IJavaPrimitiveValue) variable + .getValue()).getByteValue() - 1))); + break; + case T_short: + variable.setValue(newValue((short) (((IJavaPrimitiveValue) variable + .getValue()).getShortValue() - 1))); + break; + case T_char: + variable.setValue(newValue((char) (((IJavaPrimitiveValue) variable + .getValue()).getCharValue() - 1))); + break; + case T_int: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getIntValue() - 1)); + break; + case T_long: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getLongValue() - 1)); + break; + case T_float: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getFloatValue() - 1)); + break; + case T_double: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getDoubleValue() - 1)); + break; + } + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PostfixMinusMinusOperator_postfix________operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PostfixPlusPlusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PostfixPlusPlusOperator.java new file mode 100644 index 0000000000..0c1f2b094d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PostfixPlusPlusOperator.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public class PostfixPlusPlusOperator extends XfixOperator { + + public PostfixPlusPlusOperator(int variableTypeId, int start) { + super(variableTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaVariable variable = (IJavaVariable) pop(); + push(variable.getValue()); + + switch (fVariableTypeId) { + case T_byte: + variable.setValue(newValue((byte) (((IJavaPrimitiveValue) variable + .getValue()).getByteValue() + 1))); + break; + case T_short: + variable.setValue(newValue((short) (((IJavaPrimitiveValue) variable + .getValue()).getShortValue() + 1))); + break; + case T_char: + variable.setValue(newValue((char) (((IJavaPrimitiveValue) variable + .getValue()).getCharValue() + 1))); + break; + case T_int: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getIntValue() + 1)); + break; + case T_long: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getLongValue() + 1)); + break; + case T_float: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getFloatValue() + 1)); + break; + case T_double: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getDoubleValue() + 1)); + break; + } + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PostfixPlusPlusOperator_postfix________operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PrefixMinusMinusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PrefixMinusMinusOperator.java new file mode 100644 index 0000000000..468489a6dc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PrefixMinusMinusOperator.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public class PrefixMinusMinusOperator extends XfixOperator { + + public PrefixMinusMinusOperator(int variableTypeId, int start) { + super(variableTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaVariable variable = (IJavaVariable) pop(); + + switch (fVariableTypeId) { + case T_byte: + variable.setValue(newValue((byte) (((IJavaPrimitiveValue) variable + .getValue()).getByteValue() - 1))); + break; + case T_short: + variable.setValue(newValue((short) (((IJavaPrimitiveValue) variable + .getValue()).getShortValue() - 1))); + break; + case T_char: + variable.setValue(newValue((char) (((IJavaPrimitiveValue) variable + .getValue()).getCharValue() - 1))); + break; + case T_int: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getIntValue() - 1)); + break; + case T_long: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getLongValue() - 1)); + break; + case T_float: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getFloatValue() - 1)); + break; + case T_double: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getDoubleValue() - 1)); + break; + } + + push(variable.getValue()); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PrefixMinusMinusOperator_prefix________operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PrefixPlusPlusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PrefixPlusPlusOperator.java new file mode 100644 index 0000000000..8fd80fe9ff --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PrefixPlusPlusOperator.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +public class PrefixPlusPlusOperator extends XfixOperator { + + public PrefixPlusPlusOperator(int variableTypeId, int start) { + super(variableTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaVariable variable = (IJavaVariable) pop(); + + switch (fVariableTypeId) { + case T_byte: + variable.setValue(newValue((byte) (((IJavaPrimitiveValue) variable + .getValue()).getByteValue() + 1))); + break; + case T_short: + variable.setValue(newValue((short) (((IJavaPrimitiveValue) variable + .getValue()).getShortValue() + 1))); + break; + case T_char: + variable.setValue(newValue((char) (((IJavaPrimitiveValue) variable + .getValue()).getCharValue() + 1))); + break; + case T_int: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getIntValue() + 1)); + break; + case T_long: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getLongValue() + 1)); + break; + case T_float: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getFloatValue() + 1)); + break; + case T_double: + variable.setValue(newValue(((IJavaPrimitiveValue) variable + .getValue()).getDoubleValue() + 1)); + break; + } + + push(variable.getValue()); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PrefixPlusPlusOperator_prefix________operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushArrayLength.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushArrayLength.java new file mode 100644 index 0000000000..868b613386 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushArrayLength.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaArray; + +/** + * Pops an array object off the stack, and pushes its length. + */ +public class PushArrayLength extends ArrayAccess { + + public PushArrayLength(int start) { + super(start); + } + + @Override + public void execute() throws CoreException { + IJavaArray receiver = popArray(); + int length = receiver.getLength(); + pushNewValue(length); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushArrayLength_push_array_length__1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushArrayType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushArrayType.java new file mode 100644 index 0000000000..918b0736ac --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushArrayType.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +public class PushArrayType extends ArrayInstruction { + + private final String fTypeSignature; + + private final int fDimension; + + public PushArrayType(String typeSignature, int dimension, int start) { + super(start); + fTypeSignature = typeSignature; + fDimension = dimension; + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + push(getArrayType(fTypeSignature.replace('/', '.'), fDimension)); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushBoolean.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushBoolean.java new file mode 100644 index 0000000000..2ec3db923c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushBoolean.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes a boolean literal onto the stack. + */ +public class PushBoolean extends SimpleInstruction { + private final boolean fValue; + + public PushBoolean(boolean value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushBoolean_push__1 + fValue; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushChar.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushChar.java new file mode 100644 index 0000000000..b55e205723 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushChar.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes a char literal onto the stack. + */ +public class PushChar extends SimpleInstruction { + + private final char fValue; + + public PushChar(char value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushChar_push__1 + fValue; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushClassLiteralValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushClassLiteralValue.java new file mode 100644 index 0000000000..918763ec24 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushClassLiteralValue.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaType; + +/** + * Handles code like "new Object().class" + */ +public class PushClassLiteralValue extends CompoundInstruction { + public PushClassLiteralValue(int start) { + super(start); + } + + /** + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaType type = (IJavaType) pop(); + push(getClassObject(type)); + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.PushClassLiteralValue_push_class_literal_value_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushDouble.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushDouble.java new file mode 100644 index 0000000000..75b2c1bce3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushDouble.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes a double literal onto the stack. + */ +public class PushDouble extends SimpleInstruction { + + private final double fValue; + + public PushDouble(double value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushDouble_push__1 + fValue; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushFieldVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushFieldVariable.java new file mode 100644 index 0000000000..48d41b2e3b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushFieldVariable.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDINullValue; +import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; +import org.eclipse.osgi.util.NLS; + +/** + * Pops an object off the stack, and pushes the value of one of its fields onto + * the stack. + */ +public class PushFieldVariable extends CompoundInstruction { + + private String fDeclaringTypeSignature; + + private final String fName; + + private int fSuperClassLevel; + + public PushFieldVariable(String name, int superClassLevel, int start) { + super(start); + fName = name; + fSuperClassLevel = superClassLevel; + } + + public PushFieldVariable(String name, String declaringTypeSignature, + int start) { + super(start); + fName = name; + fDeclaringTypeSignature = declaringTypeSignature; + } + + @Override + public void execute() throws CoreException { + Object value = popValue(); + if (value instanceof JDINullValue) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, + InstructionsEvaluationMessages.PushFieldVariable_0, null)); + } + IJavaObject receiver = (IJavaObject) value; + + IJavaVariable field = null; + + if (fDeclaringTypeSignature == null) { + field = ((JDIObjectValue) receiver).getField(fName, + fSuperClassLevel); + } else { + field = receiver.getField(fName, fDeclaringTypeSignature); + } + + if (field == null) { + // For anonymous classes, getting variables from outer class + IRuntimeContext context = getContext(); + final IJavaObject innerThis = context.getThis(); + if (null != innerThis) { + int i = fDeclaringTypeSignature.indexOf('$'); + if (i > 0) { + IJavaFieldVariable f = innerThis.getField(fName, false); + if (null != f) { + push(f); + return; + } + } + } + + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + NLS.bind(InstructionsEvaluationMessages.PushFieldVariable_Cannot_find_the_field__0__for_the_object__1__1, + new String[] { fName, + receiver.toString() }), + null)); // + } + push(field); + } + + @Override + public String toString() { + return NLS.bind(InstructionsEvaluationMessages.PushFieldVariable_push_field__0__2, + new String[] { fName }); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushFloat.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushFloat.java new file mode 100644 index 0000000000..49f918ec24 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushFloat.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes a float literal onto the stack. + */ +public class PushFloat extends SimpleInstruction { + + private final float fValue; + + public PushFloat(float value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushFloat_push__1 + fValue; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushInt.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushInt.java new file mode 100644 index 0000000000..b209bbcd47 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushInt.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes an int literal onto the stack. + */ +public class PushInt extends SimpleInstruction { + + private final int fValue; + + public PushInt(int value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushInt_push__1 + fValue; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushLocalVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushLocalVariable.java new file mode 100644 index 0000000000..a41379d451 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushLocalVariable.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Chris West (Faux) - Bug 45507 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.LambdaUtils; +import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; +import org.eclipse.osgi.util.NLS; + +/** + * Pushes the value of a local, instance, or static variable onto the stack. + */ +public class PushLocalVariable extends SimpleInstruction { + + /** + * Name of variable to push. + */ + private final String fName; + + public PushLocalVariable(String name) { + fName = name; + } + + @Override + public void execute() throws CoreException { + IVariable internalVariable = getInternalVariable(fName); + if (internalVariable != null) { + push(internalVariable); + return; + } + IRuntimeContext context = getContext(); + IJavaVariable[] locals = context.getLocals(); + for (IJavaVariable local : locals) { + if (local.getName().equals(getName())) { + push(local); + return; + } + } + // For anonymous classes, getting variables from outer class + final IJavaObject innerThis = context.getThis(); + if (null != innerThis) { + IJavaFieldVariable f = innerThis.getField(ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX + getName(), false); + if (null != f) { + push(f); + return; + } + } + IVariable variable = LambdaUtils.findLambdaFrameVariable(context, getName()); + if (variable != null) { + push(variable); + return; + } + + // Try search for lambda object variable + variable = LambdaUtils.findLambdaFrameVariable(context, ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX + getName()); + if (variable != null) { + push(variable); + return; + } + + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + NLS.bind(InstructionsEvaluationMessages.PushLocalVariable_Cannot_find_the_variable____1, + new String[] { fName }), null)); + } + + /** + * Returns the name of the variable to push onto the stack. + * + * @return the name of the variable to push onto the stack + */ + protected String getName() { + return fName; + } + + @Override + public String toString() { + return NLS.bind( + InstructionsEvaluationMessages.PushLocalVariable_push____0___2, + new String[] { getName() }); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushLong.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushLong.java new file mode 100644 index 0000000000..035f461e10 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushLong.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes a long literal onto the stack. + */ +public class PushLong extends SimpleInstruction { + + private final long fValue; + + public PushLong(long value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushLong_push__1 + fValue; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushNull.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushNull.java new file mode 100644 index 0000000000..877c73aa74 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushNull.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes the 'null' onto the stack. + */ +public class PushNull extends SimpleInstruction { + + @Override + public void execute() { + pushNullValue(); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushNull_push___null__1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushPrimitiveType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushPrimitiveType.java new file mode 100644 index 0000000000..42aa3dd083 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushPrimitiveType.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +/** + * Pushes a primitive type onto the stack. + * + * @since 3.4 + */ +public class PushPrimitiveType extends SimpleInstruction { + + private final String fName; + + public PushPrimitiveType(String name) { + fName = name; + } + + @Override + public void execute() throws CoreException { + push(getPrimitiveType(fName)); + } + + @Override + public String toString() { + return "Push Primitive Type: " + fName; //$NON-NLS-1$ + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushStaticFieldVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushStaticFieldVariable.java new file mode 100644 index 0000000000..eda32e36ff --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushStaticFieldVariable.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.osgi.util.NLS; + +/** + * Pushes the value of the static fields of the given type onto the stack. + */ +public class PushStaticFieldVariable extends CompoundInstruction { + + private final String fFieldName; + + private final String fQualifiedTypeName; + + public PushStaticFieldVariable(String fieldName, String qualifiedTypeName, + int start) { + super(start); + fFieldName = fieldName; + fQualifiedTypeName = qualifiedTypeName; + } + + @Override + public void execute() throws CoreException { + IJavaType receiver = getType(fQualifiedTypeName); + + IJavaVariable field = null; + + if (receiver instanceof IJavaInterfaceType) { + field = ((IJavaInterfaceType) receiver).getField(fFieldName); + } else if (receiver instanceof IJavaClassType) { + field = ((IJavaClassType) receiver).getField(fFieldName); + } + if (field == null) { + String message = NLS.bind(InstructionsEvaluationMessages.PushStaticFieldVariable_Cannot_find_the_field__0__in__1__1, + new String[] { fFieldName, fQualifiedTypeName }); + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, message, + null)); // couldn't find the field + } + push(field); + } + + @Override + public String toString() { + return NLS.bind(InstructionsEvaluationMessages.PushStaticFieldVariable_push_static_field__0__2, + new String[] { fFieldName }); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushString.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushString.java new file mode 100644 index 0000000000..56ba65d142 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushString.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * Pushes a String literal onto the stack. + */ +public class PushString extends SimpleInstruction { + + private final String fValue; + + public PushString(String value) { + fValue = value; + } + + @Override + public void execute() { + pushNewValue(fValue); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushString_push__1 + fValue; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushThis.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushThis.java new file mode 100644 index 0000000000..725e915364 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushThis.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; + +/** + * Pushes the 'this' object onto the stack. + */ +public class PushThis extends SimpleInstruction { + + private final int fEnclosingLevel; + + public PushThis(int enclosingLevel) { + fEnclosingLevel = enclosingLevel; + } + + @Override + public void execute() throws CoreException { + IRuntimeContext context = getContext(); + IJavaObject thisInstance = context.getThis(); + if (thisInstance == null) { + // static context + push(context.getReceivingType()); + } else { + if (fEnclosingLevel != 0) { + thisInstance = ((JDIObjectValue) thisInstance) + .getEnclosingObject(fEnclosingLevel); + if (thisInstance == null) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.PushThis_Unable_to_retrieve_the_correct_enclosing_instance_of__this__2, + null)); + } + } + push(thisInstance); + } + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushThis_push___this__1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushType.java new file mode 100644 index 0000000000..148bc9ef4e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/PushType.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +/** + * Pushes a reference type onto the stack. + */ +public class PushType extends SimpleInstruction { + + private final String fTypeName; + + public PushType(String signature) { + fTypeName = signature; + } + + @Override + public void execute() throws CoreException { + push(getType(fTypeName)); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.PushType_push_type__1 + fTypeName; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemainderAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemainderAssignmentOperator.java new file mode 100644 index 0000000000..d25173b8ce --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemainderAssignmentOperator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class RemainderAssignmentOperator extends RemainderOperator { + + public RemainderAssignmentOperator(int variableTypeId, int valueTypeId, + int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.RemainderAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemainderOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemainderOperator.java new file mode 100644 index 0000000000..b774b5cc75 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemainderOperator.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +public class RemainderOperator extends BinaryOperator { + public RemainderOperator(int resultId, int leftTypeId, int rightTypeId, + int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected RemainderOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getDoubleValue() + % ((IJavaPrimitiveValue) rightOperand).getDoubleValue(); + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getFloatValue() + % ((IJavaPrimitiveValue) rightOperand).getFloatValue(); + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) + throws CoreException { + int divisor = ((IJavaPrimitiveValue) rightOperand).getIntValue(); + if (divisor == 0) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.RemainderOperator_Divide_by_zero_1, + null)); + } + return ((IJavaPrimitiveValue) leftOperand).getIntValue() % divisor; + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) + throws CoreException { + long divisor = ((IJavaPrimitiveValue) rightOperand).getLongValue(); + if (divisor == 0) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.RemainderOperator_Divide_by_zero_2, + null)); + } + return ((IJavaPrimitiveValue) leftOperand).getLongValue() % divisor; + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.RemainderOperator______operator_3; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemoteOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemoteOperator.java new file mode 100644 index 0000000000..b6d0d7d91a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RemoteOperator.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2020, Jesper Steen Møller and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Jesper Steen Møller - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.eval.RemoteEvaluator; + +/** + * Invokes a method on a object in a class injected into the debug target. The arguments are on the stack in reverse order, followed by the type. + * Pushes the result onto the stack + */ +public class RemoteOperator extends CompoundInstruction { + + private final RemoteEvaluator fEvaluator; + private final String fSignature; + + public RemoteOperator(String body, int start, RemoteEvaluator evaluator) { + super(start); + fSignature = body; + fEvaluator = evaluator; + } + + @Override + public void execute() throws CoreException { + int variableCount = fEvaluator.getVariableCount(); + IJavaValue[] args = new IJavaValue[variableCount]; + // args are in reverse order + for (int i = variableCount - 1; i >= 0; i--) { + args[i] = popValue(); + } + IJavaValue result = fEvaluator.evaluate(this.getContext().getThread(), args); + push(result); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.Run_Remote_1 + + fSignature; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ReturnInstruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ReturnInstruction.java new file mode 100644 index 0000000000..cc32117a4b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ReturnInstruction.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class ReturnInstruction extends CompoundInstruction { + + /** + * Constructor for ReturnInstruction. + * + * @param start + */ + public ReturnInstruction(int start) { + super(start); + } + + /** + * @see Instruction#execute() + */ + @Override + public void execute() { + stop(); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.ReturnInstruction_return; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RightShiftAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RightShiftAssignmentOperator.java new file mode 100644 index 0000000000..32069357e8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RightShiftAssignmentOperator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class RightShiftAssignmentOperator extends RightShiftOperator { + + public RightShiftAssignmentOperator(int variableTypeId, int valueTypeId, + int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.RightShiftAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RightShiftOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RightShiftOperator.java new file mode 100644 index 0000000000..4ad6555577 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RightShiftOperator.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class RightShiftOperator extends BinaryOperator { + public RightShiftOperator(int resultId, int leftTypeId, int rightTypeId, + int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + protected RightShiftOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + // unary type promotion on both operands see 5.6.1 and 15.18 + switch (fRightTypeId) { + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() >> ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + case T_short: + case T_byte: + case T_char: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() >> ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return 0; + } + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + // unary type promotion on both operands see 5.6.1 and 15.18 + switch (fRightTypeId) { + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() >> ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + case T_short: + case T_byte: + case T_char: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() >> ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return 0; + } + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + protected int getInternResultType() { + // unary type promotion on both operands see 5.6.1 and 15.18 + return getUnaryPromotionType(fLeftTypeId); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.RightShiftOperator_______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RuntimeSignature.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RuntimeSignature.java new file mode 100644 index 0000000000..59d1493876 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/RuntimeSignature.java @@ -0,0 +1,391 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.core.compiler.CharOperation; + +/** + * Copy of org.eclipse.jdt.core.Signature. The class is copied here solely for + * the purpose of commenting out the line: CharOperation.replace(result, + * C_DOLLAR, C_DOT); in the method toCharArray(char[]). See Bug 22165 + */ +public class RuntimeSignature { + public static final char C_BOOLEAN = 'Z'; + public static final char C_BYTE = 'B'; + public static final char C_CHAR = 'C'; + public static final char C_DOUBLE = 'D'; + public static final char C_FLOAT = 'F'; + public static final char C_INT = 'I'; + public static final char C_SEMICOLON = ';'; + public static final char C_LONG = 'J'; + public static final char C_SHORT = 'S'; + public static final char C_VOID = 'V'; + public static final char C_DOT = '.'; + public static final char C_DOLLAR = '$'; + public static final char C_ARRAY = '['; + public static final char C_RESOLVED = 'L'; + public static final char C_UNRESOLVED = 'Q'; + public static final char C_NAME_END = ';'; + public static final char C_PARAM_START = '('; + public static final char C_PARAM_END = ')'; + public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$ + public static final String SIG_BYTE = "B"; //$NON-NLS-1$ + public static final String SIG_CHAR = "C"; //$NON-NLS-1$ + public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$ + public static final String SIG_FLOAT = "F"; //$NON-NLS-1$ + public static final String SIG_INT = "I"; //$NON-NLS-1$ + public static final String SIG_LONG = "J"; //$NON-NLS-1$ + public static final String SIG_SHORT = "S"; //$NON-NLS-1$ + public static final String SIG_VOID = "V"; //$NON-NLS-1$ + private static final char[] NO_CHAR = new char[0]; + private static final char[] BOOLEAN = { 'b', 'o', 'o', 'l', 'e', 'a', 'n' }; + private static final char[] BYTE = { 'b', 'y', 't', 'e' }; + private static final char[] CHAR = { 'c', 'h', 'a', 'r' }; + private static final char[] DOUBLE = { 'd', 'o', 'u', 'b', 'l', 'e' }; + private static final char[] FLOAT = { 'f', 'l', 'o', 'a', 't' }; + private static final char[] INT = { 'i', 'n', 't' }; + private static final char[] LONG = { 'l', 'o', 'n', 'g' }; + private static final char[] SHORT = { 's', 'h', 'o', 'r', 't' }; + private static final char[] VOID = { 'v', 'o', 'i', 'd' }; + + public static String toString(String signature) + throws IllegalArgumentException { + return new String(toCharArray(signature.toCharArray())); + } + + public static char[] toCharArray(char[] signature) + throws IllegalArgumentException { + try { + int sigLength = signature.length; + + if (sigLength == 0 || signature[0] == C_PARAM_START) { + return toCharArray(signature, NO_CHAR, null, true, true); + } + + // compute result length + int resultLength = 0; + int index = -1; + while (signature[++index] == C_ARRAY) { + resultLength += 2; // [] + } + switch (signature[index]) { + case C_BOOLEAN: + resultLength += BOOLEAN.length; + break; + case C_BYTE: + resultLength += BYTE.length; + break; + case C_CHAR: + resultLength += CHAR.length; + break; + case C_DOUBLE: + resultLength += DOUBLE.length; + break; + case C_FLOAT: + resultLength += FLOAT.length; + break; + case C_INT: + resultLength += INT.length; + break; + case C_LONG: + resultLength += LONG.length; + break; + case C_SHORT: + resultLength += SHORT.length; + break; + case C_VOID: + resultLength += VOID.length; + break; + case C_RESOLVED: + case C_UNRESOLVED: + int end = CharOperation.indexOf(C_SEMICOLON, signature, index); + if (end == -1) + throw new IllegalArgumentException(); + int start = index + 1; + resultLength += end - start; + break; + default: + throw new IllegalArgumentException(); + } + + char[] result = new char[resultLength]; + copyType(signature, 0, result, 0, true); + + /** + * Converts '$' separated type signatures into '.' separated type + * signature. NOTE: This assumes that the type signature is an inner + * type signature. This is true in most cases, but someone can + * define a non-inner type name containing a '$'. However to tell + * the difference, we would have to resolve the signature, which + * cannot be done at this point. + */ + // CharOperation.replace(result, C_DOLLAR, C_DOT); + + return result; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } + } + + public static char[] toCharArray(char[] methodSignature, char[] methodName, + char[][] parameterNames, boolean fullyQualifyTypeNames, + boolean includeReturnType) { + try { + int firstParen = CharOperation.indexOf(C_PARAM_START, + methodSignature); + if (firstParen == -1) + throw new IllegalArgumentException(); + + int sigLength = methodSignature.length; + + // compute result length + + // method signature + int paramCount = 0; + int lastParen = -1; + int resultLength = 0; + signature: for (int i = firstParen; i < sigLength; i++) { + switch (methodSignature[i]) { + case C_ARRAY: + resultLength += 2; // [] + continue signature; + case C_BOOLEAN: + resultLength += BOOLEAN.length; + break; + case C_BYTE: + resultLength += BYTE.length; + break; + case C_CHAR: + resultLength += CHAR.length; + break; + case C_DOUBLE: + resultLength += DOUBLE.length; + break; + case C_FLOAT: + resultLength += FLOAT.length; + break; + case C_INT: + resultLength += INT.length; + break; + case C_LONG: + resultLength += LONG.length; + break; + case C_SHORT: + resultLength += SHORT.length; + break; + case C_VOID: + resultLength += VOID.length; + break; + case C_RESOLVED: + case C_UNRESOLVED: + int end = CharOperation.indexOf(C_SEMICOLON, + methodSignature, i); + if (end == -1) + throw new IllegalArgumentException(); + int start; + if (fullyQualifyTypeNames) { + start = i + 1; + } else { + start = CharOperation.lastIndexOf(C_DOT, + methodSignature, i, end) + 1; + if (start == 0) + start = i + 1; + } + resultLength += end - start; + i = end; + break; + case C_PARAM_START: + // add space for "(" + resultLength++; + continue signature; + case C_PARAM_END: + lastParen = i; + if (includeReturnType) { + if (paramCount > 0) { + // remove space for ", " that was added with last + // parameter and remove space that is going to be + // added for ", " after return type + // and add space for ") " + resultLength -= 2; + } // else + // remove space that is going to be added for ", " + // after return type + // and add space for ") " + // -> noop + + // decrement param count because it is going to be added + // for return type + paramCount--; + continue signature; + } + if (paramCount > 0) { + // remove space for ", " that was added with last + // parameter and add space for ")" + resultLength--; + } else { + // add space for ")" + resultLength++; + } + break signature; + default: + throw new IllegalArgumentException(); + } + resultLength += 2; // add space for ", " + paramCount++; + } + + // parameter names + if(parameterNames != null) { + for (char[] parameterName : parameterNames) { + resultLength += parameterName.length + 1; + // parameter name + space + } + } + + // selector + int selectorLength = methodName == null ? 0 : methodName.length; + resultLength += selectorLength; + + // create resulting char array + char[] result = new char[resultLength]; + + // returned type + int index = 0; + if (includeReturnType) { + long pos = copyType(methodSignature, lastParen + 1, result, + index, fullyQualifyTypeNames); + index = (int) (pos >>> 32); + result[index++] = ' '; + } + + // selector + if (methodName != null) { + System.arraycopy(methodName, 0, result, index, selectorLength); + index += selectorLength; + } + + // parameters + result[index++] = C_PARAM_START; + int sigPos = firstParen + 1; + for (int i = 0; i < paramCount; i++) { + long pos = copyType(methodSignature, sigPos, result, index, + fullyQualifyTypeNames); + index = (int) (pos >>> 32); + sigPos = (int) pos; + if (parameterNames != null) { + result[index++] = ' '; + char[] parameterName = parameterNames[i]; + int paramLength = parameterName.length; + System.arraycopy(parameterName, 0, result, index, + paramLength); + index += paramLength; + } + if (i != paramCount - 1) { + result[index++] = ','; + result[index++] = ' '; + } + } + if (sigPos >= sigLength) { + throw new IllegalArgumentException(); + // should be on last paren + } + result[index++] = C_PARAM_END; + + return result; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } + } + + private static long copyType(char[] signature, int sigPos, char[] dest, + int index, boolean fullyQualifyTypeNames) { + int arrayCount = 0; + loop: while (true) { + switch (signature[sigPos++]) { + case C_ARRAY: + arrayCount++; + break; + case C_BOOLEAN: + int length = BOOLEAN.length; + System.arraycopy(BOOLEAN, 0, dest, index, length); + index += length; + break loop; + case C_BYTE: + length = BYTE.length; + System.arraycopy(BYTE, 0, dest, index, length); + index += length; + break loop; + case C_CHAR: + length = CHAR.length; + System.arraycopy(CHAR, 0, dest, index, length); + index += length; + break loop; + case C_DOUBLE: + length = DOUBLE.length; + System.arraycopy(DOUBLE, 0, dest, index, length); + index += length; + break loop; + case C_FLOAT: + length = FLOAT.length; + System.arraycopy(FLOAT, 0, dest, index, length); + index += length; + break loop; + case C_INT: + length = INT.length; + System.arraycopy(INT, 0, dest, index, length); + index += length; + break loop; + case C_LONG: + length = LONG.length; + System.arraycopy(LONG, 0, dest, index, length); + index += length; + break loop; + case C_SHORT: + length = SHORT.length; + System.arraycopy(SHORT, 0, dest, index, length); + index += length; + break loop; + case C_VOID: + length = VOID.length; + System.arraycopy(VOID, 0, dest, index, length); + index += length; + break loop; + case C_RESOLVED: + case C_UNRESOLVED: + int end = CharOperation.indexOf(C_SEMICOLON, signature, sigPos); + if (end == -1) + throw new IllegalArgumentException(); + int start; + if (fullyQualifyTypeNames) { + start = sigPos; + } else { + start = CharOperation.lastIndexOf(C_DOT, signature, sigPos, + end) + 1; + if (start == 0) + start = sigPos; + } + length = end - start; + System.arraycopy(signature, start, dest, index, length); + sigPos = end + 1; + index += length; + break loop; + } + } + while (arrayCount-- > 0) { + dest[index++] = '['; + dest[index++] = ']'; + } + return (((long) index) << 32) + sigPos; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SendMessage.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SendMessage.java new file mode 100644 index 0000000000..b0ed71d833 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SendMessage.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.osgi.util.NLS; + +/** + * Sends an message to an instance. The arguments are on the stack in reverse + * order, followed by the receiver. Pushes the result, if any, onto the stack + */ +public class SendMessage extends CompoundInstruction { + + private final int fArgCount; + private final String fSelector; + private final String fSignature; + private final String fDeclaringType; + + public SendMessage(String selector, String signature, int argCount, + String declaringType, int start) { + super(start); + fArgCount = argCount; + fSelector = selector; + fSignature = signature; + fDeclaringType = declaringType; + } + + @Override + public void execute() throws CoreException { + IJavaValue[] args = new IJavaValue[fArgCount]; + // args are in reverse order + for (int i = fArgCount - 1; i >= 0; i--) { + args[i] = popValue(); + } + Object receiver = pop(); + IJavaValue result = null; + + if (receiver instanceof IJavaVariable) { + receiver = ((IJavaVariable) receiver).getValue(); + } + + if (receiver instanceof IJavaObject) { + result = ((IJavaObject) receiver).sendMessage(fSelector, + fSignature, args, getContext().getThread(), fDeclaringType); + } else { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.SendMessage_Attempt_to_send_a_message_to_a_non_object_value_1, + null)); + } + setLastValue(result); + if (!fSignature.endsWith(")V")) { //$NON-NLS-1$ + // only push the result if not a void method + push(result); + } + } + + @Override + public String toString() { + return NLS.bind(InstructionsEvaluationMessages.SendMessage_send_message__0___1__2, + new String[] { fSelector, fSignature }); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SendStaticMessage.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SendStaticMessage.java new file mode 100644 index 0000000000..2dc213e9df --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SendStaticMessage.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.osgi.util.NLS; + +/** + * Sends a message. The arguments are on the stack in reverse order, followed by + * the receiver. Pushes the result, if any, onto the stack + */ +public class SendStaticMessage extends CompoundInstruction { + + private final int fArgCount; + private final String fSelector; + private final String fSignature; + private final String fTypeName; + + public SendStaticMessage(String typeName, String selector, + String signature, int argCount, int start) { + super(start); + fArgCount = argCount; + fSelector = selector; + fSignature = signature; + fTypeName = typeName; + } + + @Override + public void execute() throws CoreException { + IJavaValue[] args = new IJavaValue[fArgCount]; + // args are in reverse order + for (int i = fArgCount - 1; i >= 0; i--) { + args[i] = popValue(); + } + + IJavaType receiver = getType(fTypeName); + IJavaValue result; + if (receiver instanceof IJavaClassType) { + result = ((IJavaClassType) receiver).sendMessage(fSelector, + fSignature, args, getContext().getThread()); + } else if (receiver instanceof IJavaInterfaceType) { + result = ((IJavaInterfaceType) receiver).sendMessage(fSelector, + fSignature, args, getContext().getThread()); + } else { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IStatus.OK, + InstructionsEvaluationMessages.SendStaticMessage_Cannot_send_a_static_message_to_a_non_class_type_object_1, + null)); + } + setLastValue(result); + if (!fSignature.endsWith(")V")) { //$NON-NLS-1$ + // only push the result if not a void method + push(result); + } + } + + @Override + public String toString() { + return NLS.bind(InstructionsEvaluationMessages.SendStaticMessage_send_static_message__0___1__2, + new String[] { fSelector, fSignature }); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SimpleInstruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SimpleInstruction.java new file mode 100644 index 0000000000..afada32ff1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/SimpleInstruction.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +/** + * A simple instruction cannot contain other instructions so its size is always + * one. + */ +public abstract class SimpleInstruction extends Instruction { + + /** + * Constructor for SimpleInstruction. + */ + protected SimpleInstruction() { + super(); + } + + @Override + public int getSize() { + return 1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ThrowInstruction.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ThrowInstruction.java new file mode 100644 index 0000000000..353fd016b7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/ThrowInstruction.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2003, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; + +/** + * Represent a throw instruction. + */ +public class ThrowInstruction extends CompoundInstruction { + + /** + * @param start + */ + public ThrowInstruction(int start) { + super(start); + } + + /** + * @see org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaObject exception = (IJavaObject) popValue(); + final IJavaThread javaThread = getContext().getThread(); + javaThread.stop(exception); + javaThread.queueRunnable(new Runnable() { + @Override + public void run() { + try { + javaThread.resume(); + } catch (DebugException e) { + e.printStackTrace(); + } + } + }); + stop(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/TwiddleOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/TwiddleOperator.java new file mode 100644 index 0000000000..2832ace808 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/TwiddleOperator.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; + +public class TwiddleOperator extends UnaryOperator { + + public TwiddleOperator(int expressionTypeId, int start) { + super(expressionTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaPrimitiveValue value = (IJavaPrimitiveValue) popValue(); + switch (fExpressionTypeId) { + case T_long: + pushNewValue(~value.getLongValue()); + break; + case T_byte: + case T_short: + case T_int: + case T_char: + pushNewValue(~value.getIntValue()); + break; + } + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.TwiddleOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryMinusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryMinusOperator.java new file mode 100644 index 0000000000..5c4dcd473a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryMinusOperator.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; + +public class UnaryMinusOperator extends UnaryOperator { + + public UnaryMinusOperator(int expressionTypeId, int start) { + super(expressionTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaPrimitiveValue value = (IJavaPrimitiveValue) popValue(); + switch (fExpressionTypeId) { + case T_double: + pushNewValue(-value.getDoubleValue()); + break; + case T_float: + pushNewValue(-value.getFloatValue()); + break; + case T_long: + pushNewValue(-value.getLongValue()); + break; + case T_byte: + case T_short: + case T_int: + case T_char: + pushNewValue(-value.getIntValue()); + break; + } + } + + /* + * @see Object#toString() + */ + @Override + public String toString() { + return InstructionsEvaluationMessages.UnaryMinusOperator_unary_minus_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryOperator.java new file mode 100644 index 0000000000..c04d4993ae --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryOperator.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public abstract class UnaryOperator extends CompoundInstruction { + protected int fExpressionTypeId; + + public UnaryOperator(int expressionTypeId, int start) { + super(start); + fExpressionTypeId = expressionTypeId; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryPlusOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryPlusOperator.java new file mode 100644 index 0000000000..ac3ef5c120 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnaryPlusOperator.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; + +public class UnaryPlusOperator extends UnaryOperator { + + public UnaryPlusOperator(int expressionTypeId, int start) { + super(expressionTypeId, start); + } + + /* + * @see Instruction#execute() + */ + @Override + public void execute() throws CoreException { + IJavaPrimitiveValue value = (IJavaPrimitiveValue) popValue(); + switch (fExpressionTypeId) { + case T_double: + pushNewValue(+value.getDoubleValue()); + break; + case T_float: + pushNewValue(+value.getFloatValue()); + break; + case T_long: + pushNewValue(+value.getLongValue()); + break; + case T_byte: + case T_short: + case T_int: + case T_char: + pushNewValue(+value.getIntValue()); + break; + } + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.UnaryPlusOperator_unary_plus_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnsignedRightShiftAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnsignedRightShiftAssignmentOperator.java new file mode 100644 index 0000000000..8a7c506f16 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnsignedRightShiftAssignmentOperator.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class UnsignedRightShiftAssignmentOperator extends + UnsignedRightShiftOperator { + + public UnsignedRightShiftAssignmentOperator(int variableTypeId, + int valueTypeId, int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.UnsignedRightShiftAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnsignedRightShiftOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnsignedRightShiftOperator.java new file mode 100644 index 0000000000..5beb385cd7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/UnsignedRightShiftOperator.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class UnsignedRightShiftOperator extends BinaryOperator { + public UnsignedRightShiftOperator(int resultId, int leftTypeId, + int rightTypeId, int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + public UnsignedRightShiftOperator(int resultId, int leftTypeId, + int rightTypeId, boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return false; + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + // unary type promotion on both operands see 5.6.1 and 15.18 + switch (fRightTypeId) { + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() >>> ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + case T_short: + case T_byte: + case T_char: + return ((IJavaPrimitiveValue) leftOperand).getIntValue() >>> ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return 0; + } + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + // unary type promotion on both operands see 5.6.1 and 15.18 + switch (fRightTypeId) { + case T_long: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() >>> ((IJavaPrimitiveValue) rightOperand) + .getLongValue(); + case T_int: + case T_short: + case T_byte: + case T_char: + return ((IJavaPrimitiveValue) leftOperand).getLongValue() >>> ((IJavaPrimitiveValue) rightOperand) + .getIntValue(); + default: + return 0; + } + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + protected int getInternResultType() { + // unary type promotion on both operands see 5.6.1 and 15.18 + return getUnaryPromotionType(fLeftTypeId); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.UnsignedRightShiftOperator________operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Value.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Value.java new file mode 100644 index 0000000000..412d452527 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/Value.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.core.runtime.CoreException; + +/** + * Pop a variable from the stack and push its value. + */ +public class Value extends CompoundInstruction { + + public Value(int start) { + super(start); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.eval.ast.instructions.Instruction#execute + * () + */ + @Override + public void execute() throws CoreException { + push(popValue()); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XfixOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XfixOperator.java new file mode 100644 index 0000000000..c62916d20c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XfixOperator.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public abstract class XfixOperator extends CompoundInstruction { + + protected int fVariableTypeId; + + public XfixOperator(int variableTypeId, int start) { + super(start); + fVariableTypeId = variableTypeId; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XorAssignmentOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XorAssignmentOperator.java new file mode 100644 index 0000000000..4aef5d710e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XorAssignmentOperator.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +public class XorAssignmentOperator extends XorOperator { + + public XorAssignmentOperator(int variableTypeId, int valueTypeId, int start) { + super(variableTypeId, variableTypeId, valueTypeId, true, start); + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.XorAssignmentOperator_operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XorOperator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XorOperator.java new file mode 100644 index 0000000000..67f9a668d1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/instructions/XorOperator.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.eval.ast.instructions; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaValue; + +public class XorOperator extends BinaryOperator { + public XorOperator(int resultId, int leftTypeId, int rightTypeId, int start) { + this(resultId, leftTypeId, rightTypeId, false, start); + } + + public XorOperator(int resultId, int leftTypeId, int rightTypeId, + boolean isAssignmentOperator, int start) { + super(resultId, leftTypeId, rightTypeId, isAssignmentOperator, start); + } + + /* + * @see BinaryOperator#getBooleanResult(IJavaValue, IJavaValue) + */ + @Override + protected boolean getBooleanResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getBooleanValue() + ^ ((IJavaPrimitiveValue) rightOperand).getBooleanValue(); + } + + /* + * @see BinaryOperator#getDoubleResult(IJavaValue, IJavaValue) + */ + @Override + protected double getDoubleResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getFloatResult(IJavaValue, IJavaValue) + */ + @Override + protected float getFloatResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return 0; + } + + /* + * @see BinaryOperator#getIntResult(IJavaValue, IJavaValue) + */ + @Override + protected int getIntResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getIntValue() + ^ ((IJavaPrimitiveValue) rightOperand).getIntValue(); + } + + /* + * @see BinaryOperator#getLongResult(IJavaValue, IJavaValue) + */ + @Override + protected long getLongResult(IJavaValue leftOperand, IJavaValue rightOperand) { + return ((IJavaPrimitiveValue) leftOperand).getLongValue() + ^ ((IJavaPrimitiveValue) rightOperand).getLongValue(); + } + + /* + * @see BinaryOperator#getStringResult(IJavaValue, IJavaValue) + */ + @Override + protected String getStringResult(IJavaValue leftOperand, + IJavaValue rightOperand) { + return null; + } + + @Override + public String toString() { + return InstructionsEvaluationMessages.XorOperator______operator_1; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/forceQualifierUpdate.txt b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/forceQualifierUpdate.txt new file mode 100644 index 0000000000..e8c3a9e09d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/forceQualifierUpdate.txt @@ -0,0 +1,5 @@ +# To force a version qualifier update, add the bug here +Bug 530709 - Comparator errors in jdt debug and jdt ui in I20180204-2000 +Bug 534597 - Unanticipated comparator errors in I20180511-2000 +Bug 566471 - I20200828-0150 - Comparator Errors Found +https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1184 diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/Bootstrap.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/Bootstrap.java new file mode 100644 index 0000000000..e1960954b3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/Bootstrap.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi; + +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +public class Bootstrap { + private static com.sun.jdi.VirtualMachineManager fVirtualMachineManager; + + public Bootstrap() { + } + + @SuppressWarnings("deprecation") + public static synchronized com.sun.jdi.VirtualMachineManager virtualMachineManager() { + if (fVirtualMachineManager != null) { + return fVirtualMachineManager; + } + + try { + IExtensionRegistry extensionRegistry = Platform + .getExtensionRegistry(); + String className = null; + if (extensionRegistry != null) { // is null if the platform was not + // started + className = extensionRegistry + .getExtensionPoint( + JDIDebugPlugin.getUniqueIdentifier(), + "jdiclient").getLabel(); //$NON-NLS-1$ + } + Class clazz = null; + if (className != null) { + clazz = Class.forName(className); + } + if (clazz != null) { + fVirtualMachineManager = (com.sun.jdi.VirtualMachineManager) clazz + .newInstance(); + } + } catch (ClassNotFoundException e) { + } catch (NoClassDefFoundError e) { + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } + + if (fVirtualMachineManager == null) { + // If any exceptions occurred, we'll end up here + fVirtualMachineManager = new org.eclipse.jdi.internal.VirtualMachineManagerImpl(); + } + + return fVirtualMachineManager; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/OpaqueFrameException.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/OpaqueFrameException.java new file mode 100644 index 0000000000..39c4669bd4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/OpaqueFrameException.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi; + +/** + * Thrown to indicate an operation could not be performed on a frame. + * + * @since 3.20 + */ +public class OpaqueFrameException extends RuntimeException { + + private static final long serialVersionUID = 3779456734107108574L; + + public OpaqueFrameException() { + super(); + } + + public OpaqueFrameException(String message) { + super(message); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/TimeoutException.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/TimeoutException.java new file mode 100644 index 0000000000..bdf53dc0df --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/TimeoutException.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi; + +public class TimeoutException extends RuntimeException { + private static final long serialVersionUID = 6009335074727417445L; + + public TimeoutException() { + } + + public TimeoutException(String message) { + super(message); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/VirtualMachine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/VirtualMachine.java new file mode 100644 index 0000000000..5ce009e424 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/VirtualMachine.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi; + +public interface VirtualMachine { + /** + * Sets request timeout in milliseconds + * + * @param timeout the timeout for the request + */ + public void setRequestTimeout(int timeout); + + /** + * @return Returns request timeout in milliseconds + */ + public int getRequestTimeout(); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/EventRequestManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/EventRequestManager.java new file mode 100644 index 0000000000..f14daa4fa2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/EventRequestManager.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.hcr; + +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.request.DuplicateRequestException; +import com.sun.jdi.request.EventRequest; + +/** + * Hot code replacement extension to + * com.sun.jdi.request.EventRequestManager. + */ +public interface EventRequestManager extends com.sun.jdi.Mirror { + /** + * Creates a new disabled {@link ReenterStepRequest}. The new event request + * is added to the list managed by this EventRequestManager. Use + * {@link EventRequest#enable()} to activate this event request. + *

+ * The returned request will control stepping only in the specified + * thread; all other threads will be unaffected. + *

+ * Only one pending reenter step request is allowed per thread. + *

+ * Note that enabling such a request can throw an + * OperationRefusedException if the VM refused to perform this + * operation. This in recognition that the VM may be in an awkward state and + * unable to comply. For example, execution is suspended in a native method + * and the arguments would be unavailable on return . + * + * @param thread + * the thread in which to step + * @return the created {@link ReenterStepRequest} + * @throws DuplicateRequestException + * if there is already a pending step request for the specified + * thread. + * @throws ObjectCollectedException + * if the thread object has been garbage collected. + */ + public ReenterStepRequest createReenterStepRequest(ThreadReference thread); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/OperationRefusedException.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/OperationRefusedException.java new file mode 100644 index 0000000000..1e08336f02 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/OperationRefusedException.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.hcr; + +/** + * Thrown to indicate that the target VM refused to perform an operation. + */ +public class OperationRefusedException extends RuntimeException { + + /** + * All serializable objects should have a stable serialVersionUID + */ + private static final long serialVersionUID = 1L; + + public OperationRefusedException() { + } + + public OperationRefusedException(String s) { + super(s); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ReenterStepRequest.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ReenterStepRequest.java new file mode 100644 index 0000000000..b74cfaa192 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ReenterStepRequest.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.hcr; + +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.request.StepRequest; + +/** + * A reenter step request is a step event request that will be activated when + * the given thread is about to pop the top stack frame. At this point, the VM + * is expected to do the following: + *

    + *
  1. The arguments to the method are carefully set aside, along with the + * identity of the actual method. + *
  2. The stack frame is popped. Any value being returned is discarded. Any + * exception being thrown is ignored. Instruction counter in caller is set + * at (rather than after) the send bytecode. + *
  3. Suspend the thread depending on the suspend policy and report a + * StepEvent for this request. + *
  4. When the thread is resumed, the method is re-retrieved; if the class had + * recently been reloaded, this must find the new bytecodes. If the method is no + * longer present, throw a java.lang.NoSuchMethodError as specified + * in the Java VM Specification. + *
  5. The method is entered as per normal, using the saved arguments. + *
+ *

+ * Note that other events may need to be reported as well (e.g., hit breakpoint + * on first instruction). Execution does not reenter the caller at any point; so + * no step out or step into events are reported. + * + */ +public interface ReenterStepRequest extends StepRequest { + /** + * Restricts the events generated by this request to those whose location is + * in a class whose name does NOT match this restricted regular expression. + * e.g. "java.*" or "*.Foo". + * + * @param classPattern + * the pattern String to filter against. + */ + @Override + public void addClassExclusionFilter(String classPattern); + + /** + * Restricts the events generated by this request to those whose location is + * in this class.. + * + * @param clazz + * the class to filter on. + */ + @Override + public void addClassFilter(ReferenceType clazz); + + /** + * Restricts the events generated by this request to those whose location is + * in a class whose name matches this restricted regular expression. e.g. + * "java.*" or "*.Foo". + * + * @param classPattern + * the pattern String to filter for. + */ + @Override + public void addClassFilter(String classPattern); + + /** + * @return the thread on which the step event is being requested. + */ + @Override + public ThreadReference thread(); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ReferenceType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ReferenceType.java new file mode 100644 index 0000000000..c775c23f80 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ReferenceType.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.hcr; + +/** + * Hot code replacement extension to com.sun.jdi.ReferenceType. + */ +public interface ReferenceType { + /** + * An HCR-eligible class file may now be loaded and reloaded at some later + * point(s). Methods on the stack may come from any of several versions of + * the same HCR-eligible class. The debugger can query any class file + * related object (class, method, or field) for information about the + * version of the class file from which it came. + *

+ * Classes loaded by a cooperating class loader are flagged as HCR-eligible + * for hot code replacement. + *

+ * Class file versions are identified by the CRC-32 of the entire class file + * contents. + *

+ * The VM typically computes and remembers the CRC when it digests a class + * file. Note this behavior is optional; VM need not retain any CRCs. A + * debugger can query any class for its class CRC and eligibility: + *

    + *
  • The query can be made at at time. + *
  • This is not directed to any specific thread. + *
  • Threads may be running at the time; they are not stopped. + *
  • Other JDI-level operations may be in progress. + *
  • If a debugger knows only about a method or a field, it must first + * query its defining class first to find out what is the CRC for this + * method or field. + *
+ * All information returned does not change over the lifetime of the + * reference type object (replacing the class results in a new reference + * type object). This info can therefore be cached client-side with + * impunity. + *

+ * This simple mechanism allows the IDE to detect that an object does not + * belong to the current class file base (debugger computes CRC of current + * class file and queries VM and compares to its CRC). It also allows the + * debugger to quickly detect whether two objects come from the same class + * file (debugger queries VM and compares CRCs). By checking the + * HCR-eligibility bit, the debugger can determine whether the class could + * be hot replaced in principle. + *

+ * @return the CRC-32 of the entire class file contents for this reference + * type. + * + * @see org.eclipse.jdi.hcr.VirtualMachine#classesHaveChanged + */ + public int getClassFileVersion(); + + /** + * Returns whether this reference type is eligible for hot code replacement. + * + * @return whether this reference type is eligible for hot code replacement + * + * @see org.eclipse.jdi.hcr.ReferenceType#getClassFileVersion + */ + public boolean isHCREligible(); + + /** + * Returns whether this reference type knows its class file version. Returns + * false for ArrayTypes. + * @return whether this reference type knows its class file version + */ + public boolean isVersionKnown(); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ThreadReference.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ThreadReference.java new file mode 100644 index 0000000000..c0c1696cee --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/ThreadReference.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.hcr; + +import com.sun.jdi.Value; + +/** + * Hot code replacement extension to com.sun.jdi.ThreadReference. + */ +public interface ThreadReference { + /** + * Resumes the execution of this thread as if the next instruction was a + * return instruction with the given value. This causes the top stack frame + * to be popped with the given value. + *

+ * A breakpoint instruction at the current instruction is not triggered that + * is, this operation takes precedence over breakpoints. + * try-finally blocks enclosing the current location will be + * triggered in due course. + *

+ * The triggerFinallyAndSynchronizedBlocks option on this operation controls + * whether try-finally and synchronized blocks + * enclosing the current location should be triggered: + *

    + *
  • If no, the stack frame is popped, the return value is returned, and + * execution continues back in the caller. Note that finally + * blocks are not run, and that if the code is nested within a + * synchronized statement, the monitor lock is not released + * (however, if the method is synchronized the monitor lock + * will be properly released). This mechanism is sure-fire, but at the risk + * of not letting the target program clean itself up (e.g., close its + * files). + *
  • If yes, the VM checks to see whether there might be a + * finally or synchronized block enclosing the + * current instruction. + *
      + *
    • If there is no enclosing finally block, the operation + * reduces to the above case. + *
    • If there is an enclosing finally block, the VM creates a + * VM exception and activates the finally block with it. If + * this exception eventually causes the stack frame to be popped, the + * exception is caught by the VM itself, the return value is returned, and + * execution continues back in the caller. + *
        + *
      + *

      + * Note that a finally block manifests itself as (and is + * indistinguishable from) a catch Throwable block. + * synchronized statements also compile to a + * catch Throwable block.The target program may inadventently + * end up catching this exception. + * + * Since the choices each have their pros and cons, making the decision + * is left to the debugger. However the later option is the recommended choice. + *

      + * The reply to the operation contains a flag indicating whether any finally + * or synchronized blocks are enclosing the current + * instruction. + *

      + * This operation is ignored if the thread was not suspended. If the thread + * was suspended multiple times, wait for the same number of resumes before + * executing the return instruction. + *

      + * The returned value is ignored if the method returns void. + *

      + * Throws an OperationRefusedException if the VM refused to + * perform this operation. This in recognition that the VM may be in an + * awkward state and unable to comply: + *

        + *
      • for example, execution is suspended in a native method, + *
      • for example, execution is suspended during class preparation. + *
      + * @param returnValue the value to return from the thread with + * @param triggerFinallyAndSynchronizedBlocks if finally / synchronization blocks should be executed before resuming + * @return if the forced return was successful + */ + public boolean doReturn(Value returnValue, + boolean triggerFinallyAndSynchronizedBlocks); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/VirtualMachine.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/VirtualMachine.java new file mode 100644 index 0000000000..87c871923d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/hcr/VirtualMachine.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.hcr; + +/** + * Hot code replacement extension to com.sun.jdi.VirtualMachine. + */ +public interface VirtualMachine { + /** All the given type were reloaded */ + public static final int RELOAD_SUCCESS = 0; + /** The VM is inconsistent after the reload operation */ + public static final int RELOAD_FAILURE = 1; + /** The reload operation was ignored */ + public static final int RELOAD_IGNORED = 2; + + /** + * Determines if this implementation supports the early return of the top + * stack frame of a thread. + * + * @return true if the feature is supported, false + * otherwise. + */ + public boolean canDoReturn(); + + /** + * Determines if this implementation supports the retrieval of a class file + * version. + * + * @return true if the feature is supported, false + * otherwise. + */ + public boolean canGetClassFileVersion(); + + /** + * Determines if this implementation supports the reenter stepping. + * + * @return true if the feature is supported, false + * otherwise. + */ + public boolean canReenterOnExit(); + + /** + * Determines if this implementation supports the replacement of classes on + * the fly. + * + * @return true if the feature is supported, false + * otherwise. + */ + public boolean canReloadClasses(); + + /** + * Notifies the VM that the class file base that it is running from has + * changed. Classes are given by their names. + *

      + * The class file base is the collection of class files available on the + * various VM's class paths consulted by the class loaders that are integral + * to the system. In JDK 1.2, these would include all files on the boot + * class path (used by the bootstrap class loader), the extension directory + * (used by the extension class loader), and the regular class path (used by + * the application class loader). The notion is important because only those + * classes that the VM knows to be in the class file base will be eligible + * for hot code replacement. Classes that are actually loaded by + * non-standard class loaders cannot be replaced on the fly (because the VM + * has no way of asking non-standard class loaders to reload them). Classes + * loaded from the class file base by cooperating class loaders are said to + * be HCR-eligible. + *

      + * The VM is expected to: + *

        + *
      1. Suspend all running threads. + *
      2. For a given JNI signature, try to find the definition of the + * corresponding class. + *
          + *
        • If the class definition can be found then it replaces the previous + * definition for that class. + *
        • If a definition for the class is not found, then it is unloaded. + *
            + *
          • This operation returns only when the classes have been reloaded + * and/or deleted. + *
          • If the suspend policy of the class unload event is not to suspend the + * VM, then the VM resumes all the threads that it has suspended. + *
          • Finally for each class that has been reloaded, the VM is expected to + *
              + *
            • send a class unload event, + *
            • note the VM is already suspended if the suspend policy of class + * unload event said so, + *
            • when the frontend resumes the VM, send a class prepare event, + *
            • suspend the VM according to the suspend policy of the class prepare + * event request. + *
            + *
          • For each class that has been unloaded, the VM is expected to + *
              + *
            • send a class unload event, + *
            • suspend the VM if it was requested by the class unload event request. + *
            + *
      + *

      + * Subsequent references to classes will work with the new class definition. + * Note the existing com.sun.jdi.ReferenceType, + * com.sun.jdi.Method and com.sun.jdi.Field still + * refer to the old class definition. So they should be discarded when the + * class unload event come in. + *

      + * The VM does not discard stack frames automatically: + *

        + *
      • methods on the stack are not affected, and could therefore be + * referencing obsolete code + *
      • replacing a class does not affect anything on the stack + *
      • subsequent class and method lookups find the replacements + *
      + *

      + * Installed breakpoints are not automatically carried over to the reloaded + * class: + *

        + *
      • breakpoints are resolved to particular locations in particular + * classes and methods + *
      • the VM must clear breakpoints to methods in classes that have been + * reloaded or unloaded (the debugger will reinstall them when it gets the + * class prepare event.) + *
      + *

      + * A change notice encompasses changes to the content of a class file in the + * base, the addition of a class files to the base, and the removal of a + * class file from the base. + *

      + * Change notices apply to all classes that are HCR-eligible (i.e., loaded + * by one of the cooperative system class loaders); other classes are never + * affected. + *

      + * Returns whether the operation could be completed as specified above, + * whether it was ignored (for example if the VM doesn't support this kind + * of replacement), or whether the operation failed and the VM should be + * restarted. + * @param arg1 the names of the classes that have changed + * @return whether the operation could be completed as specified above, + * whether it was ignored (for example if the VM doesn't support this kind + * of replacement), or whether the operation failed and the VM should be + * restarted + * + */ + public int classesHaveChanged(String[] arg1); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/AccessibleImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/AccessibleImpl.java new file mode 100644 index 0000000000..c59d096bbd --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/AccessibleImpl.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import com.sun.jdi.Accessible; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class AccessibleImpl extends MirrorImpl implements Accessible { + /** Modifier bit flag: Is synthetic. see MODIFIER_ACC_SYNTHETIC. */ + public static final int MODIFIER_SYNTHETIC = 0xf0000000; + /** Modifier bit flag: Is public; may be accessed from outside its package. */ + public static final int MODIFIER_ACC_PUBLIC = 0x0001; + /** Modifier bit flag: Is private; usable only within the defining class. */ + public static final int MODIFIER_ACC_PRIVATE = 0x0002; + /** Modifier bit flag: Is protected; may be accessed within subclasses. */ + public static final int MODIFIER_ACC_PROTECTED = 0x0004; + /** Modifier bit flag: Is static. */ + public static final int MODIFIER_ACC_STATIC = 0x0008; + /** Modifier bit flag: Is final; no overriding is allowed. */ + public static final int MODIFIER_ACC_FINAL = 0x0010; + /** Modifier bit flag: Is synchronized; wrap use in monitor lock. */ + public static final int MODIFIER_ACC_SYNCHRONIZED = 0x0020; + /** Modifier bit flag: Treat superclass methods specially in invokespecial. */ + public static final int MODIFIER_ACC_SUPER = 0x0020; + /** + * Modifier bit flag: Is bridge; the method is a synthetic method created to + * support generic types. + */ + public static final int MODIFIER_ACC_BRIDGE = 0x0040; + /** Modifier bit flag: Is volatile; cannot be reached. */ + public static final int MODIFIER_ACC_VOLITILE = 0x0040; + /** + * Modifier bit flag: Is transient; not written or read by a persistent + * object manager. + */ + public static final int MODIFIER_ACC_TRANSIENT = 0x0080; + /** + * Modifier bit flag: Is varargs; the method has been declared with variable + * number of arguments. + */ + public static final int MODIFIER_ACC_VARARGS = 0x0080; + /** + * Modifier bit flag: Is enum; the field hold an element of an enumerated + * type. + */ + public static final int MODIFIER_ACC_ENUM = 0x0100; + /** Modifier bit flag: Is native; implemented in a language other than Java. */ + public static final int MODIFIER_ACC_NATIVE = 0x0100; + /** Modifier bit flag: Is abstract; no implementation is provided. */ + public static final int MODIFIER_ACC_ABSTRACT = 0x0400; + /** + * Modifier bit flag: Is strict; the method floating-point mode is FP-strict + */ + public static final int MODIFIER_ACC_STRICT = 0x0800; + /** Modifier bit flag: Is synthetic. see MODIFIER_SYNTHETIC. */ + public static final int MODIFIER_ACC_SYNTHETIC = 0x1000; + + /** Mapping of command codes to strings. */ + private static String[] fgModifiers = null; + + /** + * Creates new instance. + * @param description the description + * @param vmImpl the VM + */ + public AccessibleImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * @return Returns true if object is package private. + */ + @Override + public boolean isPackagePrivate() { + return !(isPrivate() || isPublic() || isProtected()); + } + + /** + * @return Returns true if object is private. + */ + @Override + public boolean isPrivate() { + return (modifiers() & MODIFIER_ACC_PRIVATE) != 0; + } + + /** + * @return Returns true if object is public. + */ + @Override + public boolean isPublic() { + return (modifiers() & MODIFIER_ACC_PUBLIC) != 0; + } + + /** + * @return Returns true if object is protected. + */ + @Override + public boolean isProtected() { + return (modifiers() & MODIFIER_ACC_PROTECTED) != 0; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgModifiers != null) { + return; + } + + Field[] fields = AccessibleImpl.class.getDeclaredFields(); + fgModifiers = new String[32]; + + for (Field field : fields) { + int modifiers = field.getModifiers(); + if ((modifiers & Modifier.PUBLIC) == 0 + || (modifiers & Modifier.STATIC) == 0 + || (modifiers & Modifier.FINAL) == 0) + continue; + + String name = field.getName(); + if (!name.startsWith("MODIFIER_")) {//$NON-NLS-1$ + continue; + } + + name = name.substring(9); + + try { + int value = field.getInt(null); + + for (int j = 0; j < 32; j++) { + if ((1 << j & value) != 0) { + fgModifiers[j] = name; + break; + } + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns an array with string representations of tags. + */ + public static String[] getModifierStrings() { + getConstantMaps(); + return fgModifiers; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ArrayReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ArrayReferenceImpl.java new file mode 100644 index 0000000000..25e782aa61 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ArrayReferenceImpl.java @@ -0,0 +1,462 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InternalException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.Mirror; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ArrayReferenceImpl extends ObjectReferenceImpl implements + ArrayReference { + /** JDWP Tag. */ + public static final byte tag = JdwpID.ARRAY_TAG; + + private int fLength = -1; + + /** + * Creates new ArrayReferenceImpl. + * @param vmImpl the VM + * @param objectID the object ID + */ + public ArrayReferenceImpl(VirtualMachineImpl vmImpl, JdwpObjectID objectID) { + super("ArrayReference", vmImpl, objectID); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * Returns the {@link Value} from the given index + * @param index the index + * @return the {@link Value} at the given index + * @throws IndexOutOfBoundsException if the index is outside the bounds of the array + * @return Returns an array component value. + */ + @Override + public Value getValue(int index) throws IndexOutOfBoundsException { + return getValues(index, 1).get(0); + } + + /** + * @return all of the components in this array. + */ + @Override + public List getValues() { + return getValues(0, -1); + } + + /** + * Gets all of the values starting at firstIndex and ending at firstIndex+length + * + * @param firstIndex the start + * @param length the number of values to return + * @return the list of {@link Value}s + * @throws IndexOutOfBoundsException if the index is outside the bounds of the array + * @return Returns a range of array components. + */ + @Override + public List getValues(int firstIndex, int length) + throws IndexOutOfBoundsException { + + int arrayLength = length(); + + if (firstIndex < 0 || firstIndex >= arrayLength) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Invalid_index_1); + } + + if (length == -1) { + // length == -1 means all elements to the end. + length = arrayLength - firstIndex; + } else if (length < -1) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Invalid_number_of_value_to_get_from_array_1); + } else if (firstIndex + length > arrayLength) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Attempted_to_get_more_values_from_array_than_length_of_array_2); + } + + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); // arrayObject + writeInt(firstIndex, "firstIndex", outData); //$NON-NLS-1$ + writeInt(length, "length", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.AR_GET_VALUES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_INDEX: + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Invalid_index_of_array_reference_given_1); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + + /* + * NOTE: The JDWP documentation is not clear on this: it turns out + * that the following is received from the VM: - type tag; - length + * of array; - values of elements. + */ + + int type = readByte("type", JdwpID.tagMap(), replyData); //$NON-NLS-1$ + int readLength = readInt("length", replyData); //$NON-NLS-1$ + // See also ValueImpl. + switch (type) { + // Multidimensional array. + case ArrayReferenceImpl.tag: + // Object references. + case ClassLoaderReferenceImpl.tag: + case ClassObjectReferenceImpl.tag: + case StringReferenceImpl.tag: + case ObjectReferenceImpl.tag: + case ThreadGroupReferenceImpl.tag: + case ThreadReferenceImpl.tag: + return readObjectSequence(readLength, replyData); + + // Primitive type. + case BooleanValueImpl.tag: + case ByteValueImpl.tag: + case CharValueImpl.tag: + case DoubleValueImpl.tag: + case FloatValueImpl.tag: + case IntegerValueImpl.tag: + case LongValueImpl.tag: + case ShortValueImpl.tag: + return readPrimitiveSequence(readLength, type, replyData); + + case VoidValueImpl.tag: + case 0: + default: + throw new InternalException( + JDIMessages.ArrayReferenceImpl_Invalid_ArrayReference_Value_tag_encountered___2 + + type); + } + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Reads the given length of objects from the given stream + * @param length the number of objects to read + * @param in the stream to read from + * @return the {@link List} of {@link ValueImpl}s + * @throws IOException if the reading fails + * @return Returns sequence of object reference values. + */ + private List readObjectSequence(int length, DataInputStream in) + throws IOException { + List elements = new ArrayList<>(length); + for (int i = 0; i < length; i++) { + ValueImpl value = ObjectReferenceImpl + .readObjectRefWithTag(this, in); + elements.add(value); + } + return elements; + } + + /** + * @param length + * the number of primitives to read + * @param type + * the type + * @param in + * the input stream + * @return Returns sequence of values of primitive type. + * @throws IOException + * if reading from the stream encounters a problem + */ + private List readPrimitiveSequence(int length, int type, DataInputStream in) + throws IOException { + List elements = new ArrayList<>(length); + for (int i = 0; i < length; i++) { + ValueImpl value = ValueImpl.readWithoutTag(this, type, in); + elements.add(value); + } + return elements; + } + + /** + * @return Returns the number of components in this array. + */ + @Override + public int length() { + if (fLength == -1) { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.AR_LENGTH, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fLength = readInt("length", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + return fLength; + } + + /** + * Replaces an array component with another value. + * + * @param index + * the index to set the value in + * @param value + * the new value + * @throws InvalidTypeException + * thrown if the types of the replacements do not match the + * underlying type of the {@link ArrayReference} + * @throws ClassNotLoadedException + * thrown if the class type for the {@link ArrayReference} is + * not loaded or has been GC'd + * @see #setValues(int, List, int, int) + */ + @Override + public void setValue(int index, Value value) throws InvalidTypeException, + ClassNotLoadedException { + ArrayList list = new ArrayList<>(1); + list.add(value); + setValues(index, list, 0, 1); + } + + /** + * Replaces all array components with other values. + * + * @param values + * the new values to set in the array + * @throws InvalidTypeException + * thrown if the types of the replacements do not match the + * underlying type of the {@link ArrayReference} + * @throws ClassNotLoadedException + * thrown if the class type for the {@link ArrayReference} is + * not loaded or has been GC'd + * @see #setValues(int, List, int, int) + */ + @Override + public void setValues(List values) throws InvalidTypeException, + ClassNotLoadedException { + setValues(0, values, 0, -1); + } + + /** + * Replaces a range of array components with other values. + * + * @param index + * offset in this array to start replacing values at + * @param values + * replacement values + * @param srcIndex + * the first offset where values are copied from the given + * replacement values + * @param length + * the number of values to replace in this array + * @throws InvalidTypeException + * thrown if the types of the replacements do not match the + * underlying type of the {@link ArrayReference} + * @throws ClassNotLoadedException + * thrown if the class type for the {@link ArrayReference} is + * not loaded or has been GC'd + */ + @Override + public void setValues(int index, List values, int srcIndex, int length) + throws InvalidTypeException, ClassNotLoadedException { + if (values == null || values.isEmpty()) { + // trying to set nothing should do no work + return; + } + int valuesSize = values.size(); + int arrayLength = length(); + + if (index < 0 || index >= arrayLength) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Invalid_index_1); + } + if (srcIndex < 0 || srcIndex >= valuesSize) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Invalid_srcIndex_2); + } + + if (length < -1) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Invalid_number_of_value_to_set_in_array_3); + } else if (length == -1) { + // length == -1 indicates as much values as possible. + length = arrayLength - index; + int lengthTmp = valuesSize - srcIndex; + if (lengthTmp < length) { + length = lengthTmp; + } + } else if (index + length > arrayLength) { + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_length_of_array_3); + } else if (srcIndex + length > valuesSize) { + // Check if enough values are given. + throw new IndexOutOfBoundsException( + JDIMessages.ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_given_4); + } + + // check and convert the values if needed. + List checkedValues = checkValues( + values.subList(srcIndex, srcIndex + length), + ((ArrayTypeImpl) referenceType()).componentType()); + + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + writeInt(index, "index", outData); //$NON-NLS-1$ + writeInt(length, "length", outData); //$NON-NLS-1$ + Iterator iterValues = checkedValues.iterator(); + while (iterValues.hasNext()) { + ValueImpl value = (ValueImpl) iterValues.next(); + if (value != null) { + value.write(this, outData); + } else { + ValueImpl.writeNull(this, outData); + } + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.AR_SET_VALUES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException(type().name()); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * Check the type and the VM of the values. If the given type is a primitive + * type, the values may be converted to match this type. + * + * @param values + * the value(s) to check + * @param type + * the type to compare the values to + * @return the list of values converted to the given type + * @throws InvalidTypeException + * if the underlying type of an object in the list is not + * compatible + * + * @see ValueImpl#checkValue(Value, Type, VirtualMachineImpl) + */ + private List checkValues(List values, Type type) + throws InvalidTypeException { + List checkedValues = new ArrayList<>(values.size()); + Iterator iterValues = values.iterator(); + while (iterValues.hasNext()) { + checkedValues.add(ValueImpl.checkValue(iterValues.next(), + type, virtualMachineImpl())); + } + return checkedValues; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdi.internal.ObjectReferenceImpl#toString() + */ + @Override + public String toString() { + try { + StringBuilder buf = new StringBuilder(type().name()); + // Insert length of string between (last) square braces. + buf.insert(buf.length() - 1, length()); + // Append space and idString. + buf.append(' '); + buf.append(idString()); + return buf.toString(); + } catch (ObjectCollectedException e) { + return JDIMessages.ArrayReferenceImpl__Garbage_Collected__ArrayReference_5 + + "[" + length() + "] " + idString(); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (Exception e) { + return fDescription; + } + } + + /** + * Reads JDWP representation and returns new instance. + * + * @param target + * the target {@link Mirror} object + * @param in + * the input stream to read from + * @return Reads JDWP representation and returns new instance. + * @throws IOException + * if there is a problem reading from the stream + */ + public static ArrayReferenceImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpObjectID ID = new JdwpObjectID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("arrayReference", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + + ArrayReferenceImpl mirror = new ArrayReferenceImpl(vmImpl, ID); + return mirror; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ArrayTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ArrayTypeImpl.java new file mode 100644 index 0000000000..22368ffead --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ArrayTypeImpl.java @@ -0,0 +1,357 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdi.internal.jdwp.JdwpArrayID; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ArrayTypeImpl extends ReferenceTypeImpl implements ArrayType { + /** JDWP Tag. */ + public static final byte typeTag = JdwpID.TYPE_TAG_ARRAY; + /** component type */ + private Type fComponentType; + /** Component type name */ + private String fComponentTypeName; + + /** + * Creates new ArrayTypeImpl. + * @param vmImpl the VM + * @param arrayID the array ID + */ + public ArrayTypeImpl(VirtualMachineImpl vmImpl, JdwpArrayID arrayID) { + super("ArrayType", vmImpl, arrayID); //$NON-NLS-1$ + } + + /** + * Creates new ArrayTypeImpl. + * @param vmImpl the VM + * @param arrayID the array ID + * @param signature the array type signature + * @param genericSignature the array type generic signature + */ + public ArrayTypeImpl(VirtualMachineImpl vmImpl, JdwpArrayID arrayID, + String signature, String genericSignature) { + super("ArrayType", vmImpl, arrayID, signature, genericSignature); //$NON-NLS-1$ + } + + /** + * @return Returns type tag. + */ + @Override + public byte typeTag() { + return typeTag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return new ArrayReferenceImpl(virtualMachineImpl(), new JdwpObjectID( + virtualMachineImpl())); + } + + /** + * @return Returns the JNI signature of the components of this array class. + */ + @Override + public String componentSignature() { + return signature().substring(1); + } + + /** + * @return Returns the type of the array components. + * @throws ClassNotLoadedException if the class has not been loaded + */ + @Override + public Type componentType() throws ClassNotLoadedException { + if (fComponentType == null) { + fComponentType = TypeImpl.create(virtualMachineImpl(), + componentSignature(), classLoader()); + } + return fComponentType; + } + + /** + * @return Returns a text representation of the component type. + */ + @Override + public String componentTypeName() { + if (fComponentTypeName == null) { + fComponentTypeName = signatureToName(componentSignature()); + } + return fComponentTypeName; + } + + /** + * @param length the desired length of the new array + * @return Creates and returns a new instance of this array class in the + * target VM. + */ + @Override + public ArrayReference newInstance(int length) { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + writeInt(length, "length", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.AT_NEW_INSTANCE, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + ArrayReferenceImpl arrayRef = (ArrayReferenceImpl) ObjectReferenceImpl + .readObjectRefWithTag(this, replyData); + return arrayRef; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns a List filled with all Location objects that map to the + * given line number. + */ + @Override + public List locationsOfLine(int line) { + // If this reference type is an ArrayType, the returned list is always + // empty. + return Collections.EMPTY_LIST; + } + + /** + * @param target the target + * @param in the stream + * @return Reads JDWP representation and returns new instance. + * @throws IOException if the reading fails + */ + public static ArrayTypeImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpArrayID ID = new JdwpArrayID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("arrayType", ID.value()); //$NON-NLS-1$ + + if (ID.isNull()) + return null; + + ArrayTypeImpl mirror = (ArrayTypeImpl) vmImpl.getCachedMirror(ID); + if (mirror == null) { + mirror = new ArrayTypeImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + return mirror; + } + + /** + * @return Returns modifier bits. + */ + @Override + public int modifiers() { + return MODIFIER_ACC_PUBLIC | MODIFIER_ACC_FINAL; + } + + /** + * @return Returns a list containing each Field declared in this type. + */ + @Override + public List fields() { + return Collections.EMPTY_LIST; + } + + /** + * @return Returns a list containing each Method declared in this type. + */ + @Override + public List methods() { + return Collections.EMPTY_LIST; + } + + /** + * @return a Map of the requested static Field objects with their Value. + */ + @Override + public Map getValues(List fields) { + if (fields.isEmpty()) { + return new HashMap<>(); + } + + throw new IllegalArgumentException( + JDIMessages.ArrayTypeImpl_getValues_not_allowed_on_array_1); + } + + /** + * @return Returns a List containing each ReferenceType declared within this + * type. + */ + @Override + public List nestedTypes() { + return Collections.EMPTY_LIST; + } + + /** + * @return Returns status of class/interface. + */ + @Override + protected int status() { + return ReferenceTypeImpl.JDWP_CLASS_STATUS_INITIALIZED + | ReferenceTypeImpl.JDWP_CLASS_STATUS_PREPARED + | ReferenceTypeImpl.JDWP_CLASS_STATUS_VERIFIED; + } + + /** + * @param target the target + * @param withGenericSignature if the generic signature should be read + * @param in the stream + * @return Reads JDWP representation and returns new instance. + * @throws IOException if the read fails + */ + public static ArrayTypeImpl readWithSignature(MirrorImpl target, + boolean withGenericSignature, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpArrayID ID = new JdwpArrayID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("arrayType", ID.value()); //$NON-NLS-1$ + + String signature = target.readString("signature", in); //$NON-NLS-1$ + String genericSignature = null; + if (withGenericSignature) { + genericSignature = target.readString("generic signature", in); //$NON-NLS-1$ + } + if (ID.isNull()) + return null; + + ArrayTypeImpl mirror = (ArrayTypeImpl) vmImpl.getCachedMirror(ID); + if (mirror == null) { + mirror = new ArrayTypeImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + mirror.setSignature(signature); + mirror.setGenericSignature(genericSignature); + return mirror; + } + + /** + * @see com.sun.jdi.ReferenceType#allLineLocations() + */ + @Override + public List allLineLocations() { + // If this reference type is an ArrayType, the returned list is always + // empty. + return Collections.EMPTY_LIST; + } + + /** + * @see com.sun.jdi.ReferenceType#allMethods() + */ + @Override + public List allMethods() { + return Collections.EMPTY_LIST; + } + + /** + * @see com.sun.jdi.ReferenceType#allFields() + */ + @Override + public List allFields() { + return Collections.EMPTY_LIST; + } + + /** + * @return Returns an identifying name for the source corresponding to the + * declaration of this type. + */ + @Override + public String sourceName() throws AbsentInformationException { + throw new AbsentInformationException( + JDIMessages.ArrayTypeImpl_No_source_name_for_Arrays_1); + } + + /** + * @see com.sun.jdi.ReferenceType#visibleFields() + */ + @Override + public List visibleFields() { + return Collections.EMPTY_LIST; + } + + /** + * @see com.sun.jdi.ReferenceType#visibleMethods() + */ + @Override + public List visibleMethods() { + return Collections.EMPTY_LIST; + } + + /** + * @see com.sun.jdi.ReferenceType#fieldByName(String) + */ + @Override + public Field fieldByName(String arg1) { + return null; + } + + /** + * @see com.sun.jdi.ReferenceType#methodsByName(String) + */ + @Override + public List methodsByName(String arg1) { + return Collections.EMPTY_LIST; + } + + /** + * @see com.sun.jdi.ReferenceType#methodsByName(String, String) + */ + @Override + public List methodsByName(String arg1, String arg2) { + return Collections.EMPTY_LIST; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/BooleanTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/BooleanTypeImpl.java new file mode 100644 index 0000000000..f87b209ef5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/BooleanTypeImpl.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.BooleanType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class BooleanTypeImpl extends PrimitiveTypeImpl implements BooleanType { + /** + * Creates new instance. + * @param vmImpl the VM + */ + public BooleanTypeImpl(VirtualMachineImpl vmImpl) { + super("BooleanType", vmImpl, "boolean", "Z"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return BooleanValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf(false); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/BooleanValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/BooleanValueImpl.java new file mode 100644 index 0000000000..8263f01fcb --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/BooleanValueImpl.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.BooleanValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class BooleanValueImpl extends PrimitiveValueImpl implements + BooleanValue { + /** JDWP Tag. */ + public static final byte tag = JdwpID.BOOLEAN_TAG; + + /** + * Creates new instance. + * @param vmImpl the VM + * @param value the underlying value + */ + public BooleanValueImpl(VirtualMachineImpl vmImpl, Boolean value) { + super("BooleanValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getBooleanType(); + } + + /** + * @return the underlying value + */ + @Override + public boolean value() { + return booleanValue(); + } + + /** + * @param target the target + * @param in the stream + * @return Reads and returns new instance. + * @throws IOException if the read fails + */ + public static BooleanValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + boolean value = target.readBoolean("booleanValue", in); //$NON-NLS-1$ + return new BooleanValueImpl(vmImpl, Boolean.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeBoolean(((Boolean) fValue).booleanValue(), + "booleanValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ByteTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ByteTypeImpl.java new file mode 100644 index 0000000000..aaf0e1641b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ByteTypeImpl.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.ByteType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ByteTypeImpl extends PrimitiveTypeImpl implements ByteType { + /** + * Creates new instance. + * @param vmImpl the VM + */ + public ByteTypeImpl(VirtualMachineImpl vmImpl) { + super("ByteType", vmImpl, "byte", "B"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return ByteValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf((byte) 0); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ByteValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ByteValueImpl.java new file mode 100644 index 0000000000..2e12e35e85 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ByteValueImpl.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.ByteValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ByteValueImpl extends PrimitiveValueImpl implements ByteValue, Comparable { + /** JDWP Tag. */ + public static final byte tag = JdwpID.BYTE_TAG; + + /** + * Creates new instance. + * @param vmImpl the VM + * @param value the underlying byte value + */ + public ByteValueImpl(VirtualMachineImpl vmImpl, Byte value) { + super("ByteValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(ByteValue o) { + return ((Byte)byteValue()).compareTo(o.byteValue()); + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getByteType(); + } + + /** + * @return the underlying byte value + */ + @Override + public byte value() { + return byteValue(); + } + + /** + * @param target the target + * @param in the stream + * @return Reads and returns new instance. + * @throws IOException if the read fails + */ + public static ByteValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + byte value = target.readByte("byteValue", in); //$NON-NLS-1$ + return new ByteValueImpl(vmImpl, Byte.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) throws IOException { + target.writeByte(((Byte) fValue).byteValue(), "byteValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/CharTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/CharTypeImpl.java new file mode 100644 index 0000000000..69791a20c0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/CharTypeImpl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.CharType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class CharTypeImpl extends PrimitiveTypeImpl implements CharType { + /** + * Creates new instance. + */ + public CharTypeImpl(VirtualMachineImpl vmImpl) { + super("CharType", vmImpl, "char", "C"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return CharValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf((char) 0); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/CharValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/CharValueImpl.java new file mode 100644 index 0000000000..232936528c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/CharValueImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.CharValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class CharValueImpl extends PrimitiveValueImpl implements CharValue, Comparable { + /** JDWP Tag. */ + public static final byte tag = JdwpID.CHAR_TAG; + + /** + * Creates new instance. + */ + public CharValueImpl(VirtualMachineImpl vmImpl, Character value) { + super("CharValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getCharType(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(CharValue o) { + return ((Character)charValue()).compareTo(o.charValue()); + } + + /** + * @return Value. + */ + @Override + public char value() { + return charValue(); + } + + /** + * @return Reads and returns new instance. + */ + public static CharValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + char value = target.readChar("charValue", in); //$NON-NLS-1$ + return new CharValueImpl(vmImpl, Character.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeChar(((Character) fValue).charValue(), "charValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassLoaderReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassLoaderReferenceImpl.java new file mode 100644 index 0000000000..c159fe660d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassLoaderReferenceImpl.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.jdwp.JdwpClassLoaderID; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.ClassLoaderReference; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.ReferenceType; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassLoaderReferenceImpl extends ObjectReferenceImpl implements ClassLoaderReference { + /** JDWP Tag. */ + public static final byte tag = JdwpID.CLASS_LOADER_TAG; + + /** + * Creates new ClassLoaderReferenceImpl. + */ + public ClassLoaderReferenceImpl(VirtualMachineImpl vmImpl, + JdwpClassLoaderID classLoaderID) { + super("ClassLoaderReference", vmImpl, classLoaderID); //$NON-NLS-1$ + } + + /** + * @return Value tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return Returns a list of all loaded classes that were defined by this + * class loader. + */ + @Override + public List definedClasses() { + // Note that this information should not be cached. + List visibleClasses = visibleClasses(); + List result = new ArrayList<>(visibleClasses.size()); + Iterator iter = visibleClasses.iterator(); + while (iter.hasNext()) { + try { + ReferenceType type = iter.next(); + // Note that classLoader() is null for the bootstrap + // classloader. + if (type.classLoader() != null && type.classLoader().equals(this)) + result.add(type); + } catch (ClassNotPreparedException e) { + continue; + } + } + return result; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ClassLoaderReference#visibleClasses() + */ + @Override + public List visibleClasses() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.CLR_VISIBLE_CLASSES, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + List elements = new ArrayList<>(nrOfElements); + for (int i = 0; i < nrOfElements; i++) { + ReferenceTypeImpl elt = ReferenceTypeImpl.readWithTypeTag(this, replyData); + if (elt == null) + continue; + elements.add(elt); + } + return elements; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ClassLoaderReferenceImpl read(MirrorImpl target, + DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpClassLoaderID ID = new JdwpClassLoaderID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("classLoaderReference", ID.value()); //$NON-NLS-1$ + + if (ID.isNull()) + return null; + + ClassLoaderReferenceImpl mirror = new ClassLoaderReferenceImpl(vmImpl, + ID); + return mirror; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassObjectReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassObjectReferenceImpl.java new file mode 100644 index 0000000000..001a41f947 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassObjectReferenceImpl.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpClassObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.ClassObjectReference; +import com.sun.jdi.ReferenceType; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassObjectReferenceImpl extends ObjectReferenceImpl implements + ClassObjectReference { + /** JDWP Tag. */ + public static final byte tag = JdwpID.CLASS_OBJECT_TAG; + + /** + * Creates new ClassObjectReferenceImpl. + */ + public ClassObjectReferenceImpl(VirtualMachineImpl vmImpl, + JdwpClassObjectID classObjectID) { + super("ClassObjectReference", vmImpl, classObjectID); //$NON-NLS-1$ + } + + /** + * @return Returns Value tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return Returns the ReferenceType corresponding to this class object. + */ + @Override + public ReferenceType reflectedType() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.COR_REFLECTED_TYPE, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + return ReferenceTypeImpl.readWithTypeTag(this, replyData); + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ClassObjectReferenceImpl read(MirrorImpl target, + DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpClassObjectID ID = new JdwpClassObjectID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + { + target.fVerboseWriter.println("classObjectReference", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + + ClassObjectReferenceImpl mirror = new ClassObjectReferenceImpl(vmImpl, + ID); + return mirror; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassTypeImpl.java new file mode 100644 index 0000000000..e7604adf41 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ClassTypeImpl.java @@ -0,0 +1,389 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.jdwp.JdwpClassID; +import org.eclipse.jdi.internal.jdwp.JdwpClassObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassTypeImpl extends ReferenceTypeImpl implements ClassType { + + /** JDWP Tag. */ + public static final byte typeTag = JdwpID.TYPE_TAG_CLASS; + + /** The following are the stored results of JDWP calls. */ + private ClassTypeImpl fSuperclass = null; + + /** + * Creates new ClassTypeImpl. + */ + public ClassTypeImpl(VirtualMachineImpl vmImpl, JdwpClassID classID) { + super("ClassType", vmImpl, classID); //$NON-NLS-1$ + } + + /** + * Creates new ClassTypeImpl. + */ + public ClassTypeImpl(VirtualMachineImpl vmImpl, JdwpClassID classID, + String signature, String genericSignature) { + super("ClassType", vmImpl, classID, signature, genericSignature); //$NON-NLS-1$ + } + + /** + * @return Returns type tag. + */ + @Override + public byte typeTag() { + return typeTag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return new ClassObjectReferenceImpl(virtualMachineImpl(), + new JdwpClassObjectID(virtualMachineImpl())); + } + + /** + * Flushes all stored Jdwp results. + */ + @Override + public void flushStoredJdwpResults() { + super.flushStoredJdwpResults(); + + // For all classes that have this class cached as superclass, this cache + // must be undone. + Iterator itr = virtualMachineImpl().allCachedRefTypes(); + while (itr.hasNext()) { + ReferenceTypeImpl refType = (ReferenceTypeImpl) itr.next(); + if (refType instanceof ClassTypeImpl) { + ClassTypeImpl classType = (ClassTypeImpl) refType; + if (classType.fSuperclass != null && classType.fSuperclass.equals(this)) { + classType.flushStoredJdwpResults(); + } + } + } + + fSuperclass = null; + } + + /** + * @return Returns a the single non-abstract Method visible from this class + * that has the given name and signature. + */ + @Override + public Method concreteMethodByName(String name, String signature) { + /* + * Recursion is used to find the method: The methods of its own (own + * methods() command); The methods of it's superclass. + */ + + Iterator methods = methods().iterator(); + Method method; + while (methods.hasNext()) { + method = methods.next(); + if (method.name().equals(name) && method.signature().equals(signature)) { + if (method.isAbstract()) { + return null; + } + return method; + } + } + + if (superclass() != null) { + return superclass().concreteMethodByName(name, signature); + } + + return null; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ClassType#invokeMethod(com.sun.jdi.ThreadReference, com.sun.jdi.Method, java.util.List, int) + */ + @Override + public Value invokeMethod(ThreadReference thread, Method method, List arguments, int options) throws InvalidTypeException, + ClassNotLoadedException, IncompatibleThreadStateException, + InvocationException { + return invokeMethod(thread, method, arguments, options, JdwpCommandPacket.CT_INVOKE_METHOD); + } + + /* (non-Javadoc) + * @see com.sun.jdi.ClassType#newInstance(com.sun.jdi.ThreadReference, com.sun.jdi.Method, java.util.List, int) + */ + @Override + public ObjectReference newInstance(ThreadReference thread, Method method, List arguments, int options) throws InvalidTypeException, + ClassNotLoadedException, IncompatibleThreadStateException, + InvocationException { + checkVM(thread); + checkVM(method); + ThreadReferenceImpl threadImpl = (ThreadReferenceImpl) thread; + MethodImpl methodImpl = (MethodImpl) method; + + // Perform some checks for IllegalArgumentException. + if (!methods().contains(method)) + throw new IllegalArgumentException( + JDIMessages.ClassTypeImpl_Class_does_not_contain_given_method_4); + if (method.argumentTypeNames().size() != arguments.size()) + throw new IllegalArgumentException( + JDIMessages.ClassTypeImpl_Number_of_arguments_doesn__t_match_5); + if (!method.isConstructor()) + throw new IllegalArgumentException( + JDIMessages.ClassTypeImpl_Method_is_not_a_constructor_6); + + List checkedArguments = ValueImpl.checkValues(arguments, method.argumentTypes(), virtualMachineImpl()); + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + threadImpl.write(this, outData); + methodImpl.write(this, outData); + + writeInt(checkedArguments.size(), "size", outData); //$NON-NLS-1$ + Iterator iter = checkedArguments.iterator(); + while (iter.hasNext()) { + Value elt = iter.next(); + if (elt instanceof ValueImpl) { + checkVM(elt); + ((ValueImpl)elt).writeWithTag(this, outData); + } else { + ValueImpl.writeNullWithTag(this, outData); + } + } + + writeInt(optionsToJdwpOptions(options), + "options", MethodImpl.getInvokeOptions(), outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.CT_NEW_INSTANCE, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_METHODID: + throw new IllegalArgumentException(); + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException(name()); + case JdwpReplyPacket.INVALID_THREAD: + throw new IncompatibleThreadStateException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + ObjectReferenceImpl object = ObjectReferenceImpl + .readObjectRefWithTag(this, replyData); + ObjectReferenceImpl exception = ObjectReferenceImpl + .readObjectRefWithTag(this, replyData); + if (exception != null) + throw new InvocationException(exception); + return object; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Assigns a value to a static field. . + */ + @Override + public void setValue(Field field, Value value) throws InvalidTypeException, + ClassNotLoadedException { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + writeInt(1, "size", outData); // We only set one field //$NON-NLS-1$ + checkVM(field); + ((FieldImpl) field).write(this, outData); + + // check the type and the VM of the value. Convert the value if + // needed + ValueImpl checkedValue = ValueImpl.checkValue(value, field.type(), + virtualMachineImpl()); + + if (checkedValue != null) { + checkedValue.write(this, outData); + } else { + ValueImpl.writeNull(this, outData); + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.CT_SET_VALUES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException(name()); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ClassType#subclasses() + */ + @Override + public List subclasses() { + // Note that this information should not be cached. + List subclasses = new ArrayList<>(); + Iterator itr = virtualMachineImpl().allRefTypes(); + while (itr.hasNext()) { + try { + ReferenceType refType = itr.next(); + if (refType instanceof ClassTypeImpl) { + ClassTypeImpl classType = (ClassTypeImpl) refType; + if (classType.superclass() != null + && classType.superclass().equals(this)) { + subclasses.add(classType); + } + } + } catch (ClassNotPreparedException e) { + continue; + } + } + return subclasses; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ClassType#superclass() + */ + @Override + public ClassType superclass() { + if (fSuperclass != null) + return fSuperclass; + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.CT_SUPERCLASS, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fSuperclass = ClassTypeImpl.read(this, replyData); + return fSuperclass; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* + * @return Reads ID and returns known ReferenceTypeImpl with that ID, or if + * ID is unknown a newly created ReferenceTypeImpl. + */ + public static ClassTypeImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpClassID ID = new JdwpClassID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("classType", ID.value()); //$NON-NLS-1$ + + if (ID.isNull()) + return null; + + ClassTypeImpl mirror = (ClassTypeImpl) vmImpl.getCachedMirror(ID); + if (mirror == null) { + mirror = new ClassTypeImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + return mirror; + } + + /* + * @return Reads ID and returns known ReferenceTypeImpl with that ID, or if + * ID is unknown a newly created ReferenceTypeImpl. + */ + public static ClassTypeImpl readWithSignature(MirrorImpl target, + boolean withGenericSignature, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpClassID ID = new JdwpClassID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("classType", ID.value()); //$NON-NLS-1$ + + String signature = target.readString("signature", in); //$NON-NLS-1$ + String genericSignature = null; + if (withGenericSignature) { + genericSignature = target.readString("generic signature", in); //$NON-NLS-1$ + } + if (ID.isNull()) + return null; + + ClassTypeImpl mirror = (ClassTypeImpl) vmImpl.getCachedMirror(ID); + if (mirror == null) { + mirror = new ClassTypeImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + mirror.setSignature(signature); + mirror.setGenericSignature(genericSignature); + return mirror; + } + + @Override + public boolean isEnum() { + if (virtualMachineImpl().isJdwpVersionGreaterOrEqual(1, 5)) { + // there is no modifier for this ... :( + ClassType superClass = superclass(); + return superClass != null + && ";>Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable;".equals(superClass.genericSignature()); //$NON-NLS-1$ + } + // jdwp 1.5 only option + return false; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/DoubleTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/DoubleTypeImpl.java new file mode 100644 index 0000000000..44a0e0c8dc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/DoubleTypeImpl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.DoubleType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class DoubleTypeImpl extends PrimitiveTypeImpl implements DoubleType { + /** + * Creates new instance. + */ + public DoubleTypeImpl(VirtualMachineImpl vmImpl) { + super("DoubleType", vmImpl, "double", "D"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return DoubleValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf(0.0D); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/DoubleValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/DoubleValueImpl.java new file mode 100644 index 0000000000..f52fa14d34 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/DoubleValueImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.DoubleValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class DoubleValueImpl extends PrimitiveValueImpl implements DoubleValue, Comparable { + /** JDWP Tag. */ + public static final byte tag = JdwpID.DOUBLE_TAG; + + /** + * Creates new instance. + */ + public DoubleValueImpl(VirtualMachineImpl vmImpl, Double value) { + super("DoubleValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getDoubleType(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(DoubleValue o) { + return ((Double)doubleValue()).compareTo(o.doubleValue()); + } + + /** + * @return Value. + */ + @Override + public double value() { + return doubleValue(); + } + + /** + * @return Reads and returns new instance. + */ + public static DoubleValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + double value = target.readDouble("doubleValue", in); //$NON-NLS-1$ + return new DoubleValueImpl(vmImpl, Double.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeDouble(((Double) fValue).doubleValue(), "doubleValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FieldImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FieldImpl.java new file mode 100644 index 0000000000..7e7abf2478 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FieldImpl.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpFieldID; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class FieldImpl extends TypeComponentImpl implements Field { + /** ID that corresponds to this reference. */ + private final JdwpFieldID fFieldID; + private Type fType; + private String fTypeName; + + /** + * Creates new FieldImpl. + */ + public FieldImpl(VirtualMachineImpl vmImpl, + ReferenceTypeImpl declaringType, JdwpFieldID ID, String name, + String signature, String genericSignature, int modifierBits) { + super( + "Field", vmImpl, declaringType, name, signature, genericSignature, modifierBits); //$NON-NLS-1$ + fFieldID = ID; + } + + /** + * Flushes all stored Jdwp results. + */ + public void flushStoredJdwpResults() { + // Note that no results are cached. + } + + /** + * @return Returns fieldID of field. + */ + public JdwpFieldID getFieldID() { + return fFieldID; + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null + && object.getClass().equals(this.getClass()) + && fFieldID.equals(((FieldImpl) object).fFieldID) + && referenceTypeImpl().equals( + ((FieldImpl) object).referenceTypeImpl()); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(Field object) { + if (object == null || !object.getClass().equals(this.getClass())) + throw new ClassCastException(JDIMessages.FieldImpl_Can__t_compare_field_to_given_object_1); + + // See if declaring types are the same, if not return comparison between + // declaring types. + Field type2 = object; + if (!declaringType().equals(type2.declaringType())) + return declaringType().compareTo(type2.declaringType()); + + // Return comparison of position within declaring type. + int index1 = declaringType().fields().indexOf(this); + int index2 = type2.declaringType().fields().indexOf(type2); + if (index1 < index2) + return -1; + else if (index1 > index2) + return 1; + else + return 0; + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fFieldID.hashCode(); + } + + /** + * @return Returns a text representation of the declared type. + */ + @Override + public String typeName() { + if (fTypeName == null) { + fTypeName = TypeImpl.signatureToName(signature()); + } + return fTypeName; + } + + /** + * @return Returns the type of the this Field. + */ + @Override + public Type type() throws ClassNotLoadedException { + if (fType == null) { + fType = TypeImpl.create(virtualMachineImpl(), signature(), + declaringType().classLoader()); + } + return fType; + } + + /** + * @return Returns true if object is transient. + */ + @Override + public boolean isTransient() { + return (fModifierBits & MODIFIER_ACC_TRANSIENT) != 0; + } + + /** + * @return Returns true if object is volatile. + */ + @Override + public boolean isVolatile() { + return (fModifierBits & MODIFIER_ACC_VOLITILE) != 0; + } + + /** + * Writes JDWP representation. + */ + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + fFieldID.write(out); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("field", fFieldID.value()); //$NON-NLS-1$ + } + + /** + * Writes JDWP representation, including ReferenceType. + */ + public void writeWithReferenceType(MirrorImpl target, DataOutputStream out) + throws IOException { + // See EventRequest case FieldOnly + referenceTypeImpl().write(target, out); + write(target, out); + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static FieldImpl readWithReferenceTypeWithTag(MirrorImpl target, + DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + // See Events FIELD_ACCESS and FIELD_MODIFICATION (refTypeTag + typeID + + // fieldID). + ReferenceTypeImpl referenceType = ReferenceTypeImpl.readWithTypeTag( + target, in); + if (referenceType == null) + return null; + + JdwpFieldID ID = new JdwpFieldID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("field", ID.value()); //$NON-NLS-1$ + + if (ID.isNull()) + return null; + FieldImpl field = referenceType.findField(ID); + if (field == null) + throw new InternalError( + JDIMessages.FieldImpl_Got_FieldID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_2); + return field; + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static FieldImpl readWithNameSignatureModifiers( + ReferenceTypeImpl target, ReferenceTypeImpl referenceType, + boolean withGenericSignature, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpFieldID ID = new JdwpFieldID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("field", ID.value()); //$NON-NLS-1$ + + if (ID.isNull()) + return null; + String name = target.readString("name", in); //$NON-NLS-1$ + String signature = target.readString("signature", in); //$NON-NLS-1$ + String genericSignature = null; + if (withGenericSignature) { + genericSignature = target.readString("generic signature", in); //$NON-NLS-1$ + if ("".equals(genericSignature)) { //$NON-NLS-1$ + genericSignature = null; + } + } + int modifierBits = target.readInt( + "modifiers", AccessibleImpl.getModifierStrings(), in); //$NON-NLS-1$ + + FieldImpl mirror = new FieldImpl(vmImpl, referenceType, ID, name, + signature, genericSignature, modifierBits); + return mirror; + } + + @Override + public boolean isEnumConstant() { + return (fModifierBits & MODIFIER_ACC_ENUM) != 0; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FloatTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FloatTypeImpl.java new file mode 100644 index 0000000000..efef433f0c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FloatTypeImpl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.FloatType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class FloatTypeImpl extends PrimitiveTypeImpl implements FloatType { + /** + * Creates new instance. + */ + public FloatTypeImpl(VirtualMachineImpl vmImpl) { + super("FloatType", vmImpl, "float", "F"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return FloatValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf(0.0f); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FloatValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FloatValueImpl.java new file mode 100644 index 0000000000..53e0075a18 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/FloatValueImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.FloatValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class FloatValueImpl extends PrimitiveValueImpl implements FloatValue, Comparable { + /** JDWP Tag. */ + public static final byte tag = JdwpID.FLOAT_TAG; + + /** + * Creates new instance. + */ + public FloatValueImpl(VirtualMachineImpl vmImpl, Float value) { + super("FloatValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getFloatType(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(FloatValue o) { + return ((Float)floatValue()).compareTo(o.floatValue()); + } + + /** + * @return Value. + */ + @Override + public float value() { + return floatValue(); + } + + /** + * @return Reads and returns new instance. + */ + public static FloatValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + float value = target.readFloat("floatValue", in); //$NON-NLS-1$ + return new FloatValueImpl(vmImpl, Float.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeFloat(((Float) fValue).floatValue(), "floatValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/GenericSignature.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/GenericSignature.java new file mode 100644 index 0000000000..313bfccf20 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/GenericSignature.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2004, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Utility class to perform operations on generic signatures + */ +public class GenericSignature { + + private static final char C_CLASS_TYPE = 'L'; + private static final char C_TYPE_VARIABLE = 'T'; + private static final char C_ARRAY = '['; + private static final char C_WILDCARD_PLUS = '+'; + private static final char C_WILDCARD_MINUS = '-'; + + private static final char C_TYPE_END = ';'; + private static final char C_PARAMETERS_START = '('; + private static final char C_PARAMETERS_END = ')'; + private static final char C_TYPE_ARGUMENTS_START = '<'; + private static final char C_TYPE_ARGUMENTS_END = '>'; + + public static List getParameterTypes(String methodSignature) { + int parameterStart = methodSignature.indexOf(C_PARAMETERS_START); + int parametersEnd = methodSignature.lastIndexOf(C_PARAMETERS_END); + if (parameterStart == -1 || parametersEnd == -1) { + // used to throw illegal argument exception, but now return empty + // list if we can't parse it + return Collections.EMPTY_LIST; + } + return getTypeSignatureList(methodSignature.substring(parameterStart + 1, parametersEnd)); + } + + private static List getTypeSignatureList(String typeSignatureList) { + List list = new ArrayList<>(); + int pos = 0; + while (pos < typeSignatureList.length()) { + int signatureLength = nextTypeSignatureLength(typeSignatureList, pos); + list.add(typeSignatureList.substring(pos, pos += signatureLength)); + } + return list; + } + + private static int nextTypeSignatureLength(String signature, int startPos) { + int inclusionLevel = 0; + for (int i = startPos, length = signature.length(); i < length; i++) { + if (inclusionLevel == 0) { + switch (signature.charAt(i)) { + case C_CLASS_TYPE: + case C_TYPE_VARIABLE: + case C_WILDCARD_PLUS: + case C_WILDCARD_MINUS: + inclusionLevel = 1; + break; + case C_ARRAY: + break; + default: + return i - startPos + 1; + } + } else { + switch (signature.charAt(i)) { + case C_TYPE_END: + if (inclusionLevel == 1) { + return i - startPos + 1; + } + break; + case C_TYPE_ARGUMENTS_START: + inclusionLevel++; + break; + case C_TYPE_ARGUMENTS_END: + inclusionLevel--; + break; + } + } + } + throw new IllegalArgumentException(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/IntegerTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/IntegerTypeImpl.java new file mode 100644 index 0000000000..fdd1300c01 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/IntegerTypeImpl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.IntegerType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class IntegerTypeImpl extends PrimitiveTypeImpl implements IntegerType { + /** + * Creates new instance. + */ + public IntegerTypeImpl(VirtualMachineImpl vmImpl) { + super("IntegerType", vmImpl, "int", "I"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return IntegerValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf(0); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/IntegerValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/IntegerValueImpl.java new file mode 100644 index 0000000000..aba77be8b3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/IntegerValueImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.IntegerValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class IntegerValueImpl extends PrimitiveValueImpl implements IntegerValue, Comparable { + /** JDWP Tag. */ + public static final byte tag = JdwpID.INT_TAG; + + /** + * Creates new instance. + */ + public IntegerValueImpl(VirtualMachineImpl vmImpl, Integer value) { + super("IntegerValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getIntegerType(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(IntegerValue o) { + return ((Integer)intValue()).compareTo(o.intValue()); + } + + /** + * @return Value. + */ + @Override + public int value() { + return intValue(); + } + + /** + * @return Reads and returns new instance. + */ + public static IntegerValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + int value = target.readInt("integerValue", in); //$NON-NLS-1$ + return new IntegerValueImpl(vmImpl, Integer.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeInt(((Integer) fValue).intValue(), "intValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/InterfaceTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/InterfaceTypeImpl.java new file mode 100644 index 0000000000..f20110cb51 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/InterfaceTypeImpl.java @@ -0,0 +1,274 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.jdwp.JdwpClassObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpInterfaceID; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.Method; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class InterfaceTypeImpl extends ReferenceTypeImpl implements + InterfaceType { + /** JDWP Tag. */ + public static final byte typeTag = JdwpID.TYPE_TAG_INTERFACE; + + /** + * Creates new InterfaceTypeImpl. + */ + public InterfaceTypeImpl(VirtualMachineImpl vmImpl, + JdwpInterfaceID interfaceID) { + super("InterfaceType", vmImpl, interfaceID); //$NON-NLS-1$ + } + + /** + * Creates new InterfaceTypeImpl. + */ + public InterfaceTypeImpl(VirtualMachineImpl vmImpl, + JdwpInterfaceID interfaceID, String signature, + String genericSignature) { + super("InterfaceType", vmImpl, interfaceID, signature, genericSignature); //$NON-NLS-1$ + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return new ClassObjectReferenceImpl(virtualMachineImpl(), + new JdwpClassObjectID(virtualMachineImpl())); + } + + /** + * @return Returns type tag. + */ + @Override + public byte typeTag() { + return typeTag; + } + + /** + * Flushes all stored Jdwp results. + */ + @Override + public void flushStoredJdwpResults() { + super.flushStoredJdwpResults(); + + // For all reference types that have this interface cached, this cache must be + // undone. + Iterator itr = virtualMachineImpl().allCachedRefTypes(); + while (itr.hasNext()) { + ReferenceTypeImpl refType = (ReferenceTypeImpl) itr.next(); + if (refType.fInterfaces != null + && refType.fInterfaces.contains(this)) { + refType.flushStoredJdwpResults(); + } + } + + } + + /* (non-Javadoc) + * @see com.sun.jdi.InterfaceType#implementors() + */ + @Override + public List implementors() { + // Note that this information should not be cached. + List implementors = new ArrayList<>(); + Iterator itr = virtualMachineImpl().allRefTypes(); + while (itr.hasNext()) { + ReferenceType refType = itr.next(); + if (refType instanceof ClassTypeImpl) { + try { + ClassTypeImpl classType = (ClassTypeImpl) refType; + List interfaces = classType.interfaces(); + if (interfaces.contains(this)) { + implementors.add(classType); + } + } catch (ClassNotPreparedException e) { + continue; + } + } + } + return implementors; + } + + /* (non-Javadoc) + * @see com.sun.jdi.InterfaceType#subinterfaces() + */ + @Override + public List subinterfaces() { + // Note that this information should not be cached. + List implementors = new ArrayList<>(); + Iterator itr = virtualMachineImpl().allRefTypes(); + while (itr.hasNext()) { + try { + ReferenceType refType = itr.next(); + if (refType instanceof InterfaceTypeImpl) { + InterfaceTypeImpl interFaceType = (InterfaceTypeImpl) refType; + List interfaces = interFaceType.superinterfaces(); + if (interfaces.contains(this)) { + implementors.add(interFaceType); + } + } + } catch (ClassNotPreparedException e) { + continue; + } + } + return implementors; + } + + /* (non-Javadoc) + * @see com.sun.jdi.InterfaceType#superinterfaces() + */ + @Override + public List superinterfaces() { + return interfaces(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.InterfaceType#invokeMethod(com.sun.jdi.ThreadReference, com.sun.jdi.Method, java.util.List, int) + */ + @Override + public Value invokeMethod(ThreadReference thread, Method method, List arguments, int options) throws InvalidTypeException, + ClassNotLoadedException, IncompatibleThreadStateException, + InvocationException { + return invokeMethod(thread, method, arguments, options, JdwpCommandPacket.IT_INVOKE_METHOD); + } + + /** + * @return Returns a the single non-abstract Method visible from this class + * that has the given name and signature. + */ + public Method concreteMethodByName(String name, String signature) { + /* + * Recursion is used to find the method: The methods of its own (own + * methods() command); The methods of it's superclass. + */ + + Iterator methods = methods().iterator(); + Method method; + while (methods.hasNext()) { + method = methods.next(); + if (method.name().equals(name) && method.signature().equals(signature)) { + if (method.isAbstract()) { + return null; + } + return method; + } + } + + if (superinterfaces() != null) { + for (InterfaceType superi: superinterfaces()) { + Method foundMethod = ((InterfaceTypeImpl)superi).concreteMethodByName(name, signature); + if (foundMethod != null) { + return foundMethod; + } + } + } + + return null; + } + + + /** + * @return Returns true if this type has been initialized. + */ + @Override + public boolean isInitialized() { + return isPrepared(); + } + + /** + * @return Reads ID and returns known ReferenceTypeImpl with that ID, or if + * ID is unknown a newly created ReferenceTypeImpl. + */ + public static InterfaceTypeImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpInterfaceID ID = new JdwpInterfaceID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("interfaceType", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + + InterfaceTypeImpl mirror = (InterfaceTypeImpl) vmImpl + .getCachedMirror(ID); + if (mirror == null) { + mirror = new InterfaceTypeImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + return mirror; + } + + /** + * @return Reads ID and returns known ReferenceTypeImpl with that ID, or if + * ID is unknown a newly created ReferenceTypeImpl. + */ + public static InterfaceTypeImpl readWithSignature(MirrorImpl target, + boolean withGenericSignature, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpInterfaceID ID = new JdwpInterfaceID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("interfaceType", ID.value()); //$NON-NLS-1$ + } + + String signature = target.readString("signature", in); //$NON-NLS-1$ + String genericSignature = null; + if (withGenericSignature) { + genericSignature = target.readString("generic signature", in); //$NON-NLS-1$ + } + if (ID.isNull()) { + return null; + } + + InterfaceTypeImpl mirror = (InterfaceTypeImpl) vmImpl + .getCachedMirror(ID); + if (mirror == null) { + mirror = new InterfaceTypeImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + mirror.setSignature(signature); + mirror.setGenericSignature(genericSignature); + return mirror; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/JDIMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/JDIMessages.java new file mode 100644 index 0000000000..b1f5d5734b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/JDIMessages.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import org.eclipse.osgi.util.NLS; + +public class JDIMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdi.internal.JDIMessages";//$NON-NLS-1$ + + public static String ArrayReferenceImpl_Invalid_index_of_array_reference_given_1; + public static String ArrayReferenceImpl_Invalid_ArrayReference_Value_tag_encountered___2; + public static String ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_length_of_array_3; + public static String ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_given_4; + public static String ArrayReferenceImpl__Garbage_Collected__ArrayReference_5; + public static String ArrayTypeImpl_getValues_not_allowed_on_array_1; + public static String ArrayTypeImpl_No_source_name_for_Arrays_1; + + public static String class_or_object_not_known; + public static String ClassTypeImpl_Class_does_not_contain_given_method_1; + public static String ClassTypeImpl_Number_of_arguments_doesn__t_match_2; + public static String ClassTypeImpl_Method_is_constructor_or_intitializer_3; + public static String ClassTypeImpl_Class_does_not_contain_given_method_4; + public static String ClassTypeImpl_Number_of_arguments_doesn__t_match_5; + public static String ClassTypeImpl_Method_is_not_a_constructor_6; + public static String InterfaceTypeImpl_Static_interface_methods_require_newer_JVM; + public static String FieldImpl_Can__t_compare_field_to_given_object_1; + public static String FieldImpl_Got_FieldID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_2; + public static String LocalVariableImpl_Can__t_compare_local_variable_to_given_object_1; + public static String LocalVariableImpl_Code_indexes_are_assumed_to_be_always_positive_2; + public static String LocalVariableImpl_The_stack_frame__s_method_does_not_match_this_variable__s_method_3; + public static String LocalVariableImpl_Code_indexes_are_assumed_to_be_always_positive_4; + public static String LocationImpl_Can__t_compare_location_to_given_object_1; + public static String LocationImpl_Code_indexes_are_assumed_to_be_always_positive_2; + public static String LocationImpl_sourcename___0___line___1__3; + public static String MethodImpl_Got_empty_line_number_table_for_this_method_1; + public static String MethodImpl_No_line_number_information_available_2; + public static String MethodImpl_Got_empty_line_number_table_for_this_method_3; + public static String MethodImpl_Invalid_code_index_of_a_location_given_4; + public static String MethodImpl_Can__t_compare_method_to_given_object_6; + public static String MethodImpl_No_local_variable_information_available_9; + public static String MethodImpl_Got_MethodID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_10; + public static String MethodImpl_No_valid_location_at_the_specified_code_index__0__2; + + public static String MirrorImpl_Got_error_code_in_reply___1; + public static String MirrorImpl_Got_invalid_data___2; + + public static String ObjectReferenceImpl_object_not_known; + + public static String ObjectReferenceImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1; + public static String ObjectReferenceImpl_Class_does_not_contain_given_method_2; + public static String ObjectReferenceImpl_Number_of_arguments_doesn__t_match_3; + public static String ObjectReferenceImpl_Method_is_constructor_or_intitializer_4; + public static String ObjectReferenceImpl_Method_is_abstract_and_can_therefore_not_be_invoked_nonvirtual_5; + public static String ObjectReferenceImpl_One_of_the_arguments_of_ObjectReference_invokeMethod___6; + public static String ObjectReferenceImpl__Garbage_Collected__ObjectReference__8; + public static String ObjectReferenceImpl_Invalid_ObjectID_tag_encountered___9; + + public static String PrimitiveTypeImpl_Invalid_primitive_signature____1; + public static String PrimitiveTypeImpl___2; + public static String PrimitiveTypeImpl_A_PrimitiveType_does_not_have_modifiers_3; + public static String PrimitiveValueImpl_Invalid_Primitive_Value_tag_encountered___2; + + public static String ReferenceTypeImpl_26; + public static String ReferenceTypeImpl_27; + public static String ReferenceTypeImpl_no_class_version_support24; + public static String ReferenceTypeImpl_no_constant_pool_support; + public static String ReferenceTypeImpl_Obsolete_method_1; + public static String ReferenceTypeImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_3; + public static String ReferenceTypeImpl_Can__t_compare_reference_type_to_given_object_4; + public static String ReferenceTypeImpl_Source_name_is_not_known_7; + public static String ReferenceTypeImpl_Invalid_ReferenceTypeID_tag_encountered___8; + public static String ReferenceTypeImpl_Type_has_not_been_loaded_10; + + public static String StackFrameImpl_no_argument_values_available; + public static String StackFrameImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1; + public static String StringReferenceImpl__Garbage_Collected__StringReference__3; + + public static String ThreadReferenceImpl_incapatible_return_type; + public static String ThreadReferenceImpl_no_force_early_return_on_threads; + public static String ThreadReferenceImpl_thread_cannot_force_native_method; + public static String ThreadReferenceImpl_thread_no_stackframes; + public static String ThreadReferenceImpl_thread_not_suspended; + public static String ThreadReferenceImpl_thread_object_invalid; + public static String ThreadReferenceImpl_thread_or_value_unknown; + public static String ThreadReferenceImpl_Thread_was_not_suspended_1; + public static String ThreadReferenceImpl_Invalid_index_of_stack_frames_given_4; + public static String ThreadReferenceImpl_Thread_was_not_suspended_5; + public static String ThreadReferenceImpl_Unknown_thread_status_received___6; + public static String ThreadReferenceImpl_Stop_argument_not_an_instance_of_java_lang_Throwable_in_the_target_VM_7; + public static String ThreadReferenceImpl_8; + public static String ThreadReferenceImpl__Garbage_Collected__ThreadReference__9; + public static String ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_frame_id_was_invalid__The_thread_was_resumed__10; + public static String ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame__The_requested_stack_frame_is_not_suspended_11; + public static String ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_requested_frame_was_the_last_frame_on_the_call_stack__The_requested_frame_was_the_last_frame_above_a_native_frame__12; + public static String ThreadReferenceImpl_vm_read_only; + public static String TypeImpl__Unloaded_Type__1; + public static String TypeImpl_Can__t_covert_method_signature_to_tag___9; + public static String TypeImpl_Invalid_signature____10; + public static String TypeImpl___11; + public static String TypeImpl_Can__t_convert_method_signature_to_name_2; + public static String ValueImpl_Invalid_Value_tag_encountered___1; + + public static String VirtualMachineImpl_2; + public static String VirtualMachineImpl_3; + public static String VirtualMachineImpl_count_less_than_zero; + public static String VirtualMachineImpl_Target_VM__0__does_not_support_Hot_Code_Replacement_1; + public static String VirtualMachineImpl_Failed_to_get_ID_sizes_2; + public static String VirtualMachineImpl_Invalid_result_flag_in_Classes_Have_Changed_response___3; + public static String VirtualMachineImpl__4; + public static String VirtualMachineImpl_0; + public static String VirtualMachineImpl_1; + public static String VirtualMachineManagerImpl_Could_not_open_verbose_file___1; + public static String VirtualMachineManagerImpl_____2; + + public static String vm_dead; + public static String VoidTypeImpl_A_VoidType_does_not_have_modifiers_1; + public static String VirtualMachineImpl_Add_method_not_implemented_1; + public static String VirtualMachineImpl_Scheme_change_not_implemented_2; + public static String VirtualMachineImpl_Hierarchy_change_not_implemented_3; + public static String VirtualMachineImpl_Delete_method_not_implemented_4; + public static String VirtualMachineImpl_Class_modifiers_change_not_implemented_5; + public static String VirtualMachineImpl_Method_modifiers_change_not_implemented_6; + public static String VerboseWriter___unknown_value__1; + public static String VerboseWriter__unknown_bit__2; + public static String VerboseWriter__none__4; + public static String ArrayReferenceImpl_Invalid_index_1; + public static String ArrayReferenceImpl_Invalid_srcIndex_2; + public static String ArrayReferenceImpl_Invalid_number_of_value_to_set_in_array_3; + public static String ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1; + public static String ArrayReferenceImpl_Invalid_number_of_value_to_get_from_array_1; + public static String ArrayReferenceImpl_Attempted_to_get_more_values_from_array_than_length_of_array_2; + public static String ReferenceTypeImpl_28; + public static String ReferenceTypeImpl_29; + public static String ReferenceTypeImpl_30; + public static String ReferenceTypeImpl_31; + public static String ReferenceTypeImpl_32; + public static String ReferenceTypeImpl_34; + public static String SourceDebugExtensionParser_0; + public static String SourceDebugExtensionParser_2; + public static String SourceDebugExtensionParser_3; + public static String SourceDebugExtensionParser_4; + public static String SourceDebugExtensionParser_5; + public static String SourceDebugExtensionParser_6; + public static String SourceDebugExtensionParser_7; + public static String SourceDebugExtensionParser_8; + public static String SourceDebugExtensionParser_9; + public static String SourceDebugExtensionParser_10; + public static String SourceDebugExtensionParser_11; + public static String SourceDebugExtensionParser_12; + public static String SourceDebugExtensionParser_13; + public static String SourceDebugExtensionParser_14; + public static String SourceDebugExtensionParser_16; + public static String SourceDebugExtensionParser_17; + public static String SourceDebugExtensionParser_19; + public static String SourceDebugExtensionParser_22; + public static String SourceDebugExtensionParser_23; + public static String SourceDebugExtensionParser_24; + public static String SourceDebugExtensionParser_25; + public static String SourceDebugExtensionParser_26; + public static String SourceDebugExtensionParser_27; + public static String SourceDebugExtensionParser_28; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, JDIMessages.class); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/JDIMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/JDIMessages.properties new file mode 100644 index 0000000000..394e6ed3e0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/JDIMessages.properties @@ -0,0 +1,157 @@ +############################################################################### +# Copyright (c) 2000, 2012 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +ArrayReferenceImpl_Invalid_index_of_array_reference_given_1=Invalid index of array reference given +ArrayReferenceImpl_Invalid_ArrayReference_Value_tag_encountered___2=Invalid ArrayReference Value tag encountered: +ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_length_of_array_3=Attempted to set more values in array than length of array +ArrayReferenceImpl_Attempted_to_set_more_values_in_array_than_given_4=Attempted to set more values in array than given +ArrayReferenceImpl__Garbage_Collected__ArrayReference_5=(Garbage Collected) ArrayReference +ArrayTypeImpl_getValues_not_allowed_on_array_1=get values not allowed on array +ArrayTypeImpl_No_source_name_for_Arrays_1=No source name for Arrays +ClassTypeImpl_Class_does_not_contain_given_method_1=Class does not contain given method +ClassTypeImpl_Number_of_arguments_doesn__t_match_2=Number of arguments does not match +ClassTypeImpl_Method_is_constructor_or_intitializer_3=Method is constructor or initializer +ClassTypeImpl_Class_does_not_contain_given_method_4=Class does not contain given method +ClassTypeImpl_Number_of_arguments_doesn__t_match_5=Number of arguments does not match +ClassTypeImpl_Method_is_not_a_constructor_6=Method is not a constructor +InterfaceTypeImpl_Static_interface_methods_require_newer_JVM=Static interface method invocation requires newer JVM. +FieldImpl_Can__t_compare_field_to_given_object_1=Cannot compare field to given object +FieldImpl_Got_FieldID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_2=Got FieldID of ReferenceType that is not a member of the ReferenceType +LocalVariableImpl_Can__t_compare_local_variable_to_given_object_1=Cannot compare local variable to given object +LocalVariableImpl_Code_indexes_are_assumed_to_be_always_positive_2=Code indexes are assumed to be always positive +LocalVariableImpl_The_stack_frame__s_method_does_not_match_this_variable__s_method_3=The stack frame\'s method does not match this variable\'s method +LocalVariableImpl_Code_indexes_are_assumed_to_be_always_positive_4=Code indexes are assumed to be always positive +LocationImpl_Can__t_compare_location_to_given_object_1=Cannot compare location to given object +LocationImpl_Code_indexes_are_assumed_to_be_always_positive_2=Code indexes are assumed to be always positive +LocationImpl_sourcename___0___line___1__3=sourcename: {0}, line: {1}, method: {2} +MethodImpl_Got_empty_line_number_table_for_this_method_1=Got empty line number table for this method +MethodImpl_No_line_number_information_available_2=No line number information available +MethodImpl_Got_empty_line_number_table_for_this_method_3=Got empty line number table for this method +MethodImpl_Invalid_code_index_of_a_location_given_4=Invalid code index of a location given +MethodImpl_Can__t_compare_method_to_given_object_6=Cannot compare method to given object +MethodImpl_No_local_variable_information_available_9=No local variable information available +MethodImpl_Got_MethodID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_10=Got MethodID of ReferenceType that is not a member of the ReferenceType +MethodImpl_No_valid_location_at_the_specified_code_index__0__2=No valid location at the specified code index {0} + +MirrorImpl_Got_error_code_in_reply___1=Got error code in reply: +MirrorImpl_Got_invalid_data___2=Got invalid data: +ObjectReferenceImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1=Retrieved a different number of values from the VM than requested +ObjectReferenceImpl_Class_does_not_contain_given_method_2=Class does not contain given method +ObjectReferenceImpl_Number_of_arguments_doesn__t_match_3=Number of arguments does not match +ObjectReferenceImpl_Method_is_constructor_or_intitializer_4=Method is constructor or initializer +ObjectReferenceImpl_Method_is_abstract_and_can_therefore_not_be_invoked_nonvirtual_5=Method is abstract and can therefore not be invoked nonvirtual +ObjectReferenceImpl_One_of_the_arguments_of_ObjectReference_invokeMethod___6=One of the arguments of ObjectReference.invokeMethod() +ObjectReferenceImpl__Garbage_Collected__ObjectReference__8=(Garbage Collected) ObjectReference +ObjectReferenceImpl_Invalid_ObjectID_tag_encountered___9=Invalid ObjectID tag encountered: +PrimitiveTypeImpl_Invalid_primitive_signature____1=Invalid primitive signature: " +PrimitiveTypeImpl___2=" +PrimitiveTypeImpl_A_PrimitiveType_does_not_have_modifiers_3=A PrimitiveType does not have modifiers +PrimitiveValueImpl_Invalid_Primitive_Value_tag_encountered___2=Invalid Primitive Value tag encountered: +ReferenceTypeImpl_Obsolete_method_1=Obsolete method +ReferenceTypeImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_3=Retrieved a different number of values from the VM than requested +ReferenceTypeImpl_Can__t_compare_reference_type_to_given_object_4=Cannot compare reference type to given object +ReferenceTypeImpl_Source_name_is_not_known_7=Source name is not known +ReferenceTypeImpl_no_class_version_support24=VM does not support class file version information. +ReferenceTypeImpl_no_constant_pool_support=VM does not support constant pool information. +ReferenceTypeImpl_Invalid_ReferenceTypeID_tag_encountered___8=Invalid ReferenceTypeID tag encountered: +ReferenceTypeImpl_Type_has_not_been_loaded_10=Type has not been loaded +StackFrameImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1=Retrieved a different number of values from the VM than requested +StringReferenceImpl__Garbage_Collected__StringReference__3=(Garbage Collected) StringReference +ThreadReferenceImpl_Thread_was_not_suspended_1=Thread was not suspended +ThreadReferenceImpl_Invalid_index_of_stack_frames_given_4=Invalid index of stack frames given +ThreadReferenceImpl_Thread_was_not_suspended_5=Thread was not suspended +ThreadReferenceImpl_thread_not_suspended=Thread must be suspended to force early return. +ThreadReferenceImpl_thread_no_stackframes=Thread has no stack frames. +ThreadReferenceImpl_thread_object_invalid=The thread or object is invalid. +ThreadReferenceImpl_thread_or_value_unknown=The thread or value is an unknown ID. +ThreadReferenceImpl_incapatible_return_type=The specified return type is not compatible with the return type of the method. +ThreadReferenceImpl_Unknown_thread_status_received___6=Unknown thread status received: +ThreadReferenceImpl_no_force_early_return_on_threads=VM does not support forcing early return on threads. +ThreadReferenceImpl_thread_cannot_force_native_method=Cannot force return from a native method. +ThreadReferenceImpl_Stop_argument_not_an_instance_of_java_lang_Throwable_in_the_target_VM_7=Stop argument not an instance of java.lang.Throwable in the target VM +ThreadReferenceImpl_8={0} (name={1}, id={2}) +ThreadReferenceImpl_vm_read_only=The VM is read-only and cannot be modified. +ThreadReferenceImpl__Garbage_Collected__ThreadReference__9=(Garbage Collected) ThreadReference +ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_frame_id_was_invalid__The_thread_was_resumed__10=Unable to pop the requested stack frame from the call stack (Reasons include: The frame id was invalid; The thread was resumed) +ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame__The_requested_stack_frame_is_not_suspended_11=Unable to pop the requested stack frame. The requested stack frame is not suspended +ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_requested_frame_was_the_last_frame_on_the_call_stack__The_requested_frame_was_the_last_frame_above_a_native_frame__12=Unable to pop the requested stack frame from the call stack (Reasons include: The requested frame was the last frame on the call stack; The requested frame was the last frame above a native frame) +TypeImpl__Unloaded_Type__1=(Unloaded Type) +TypeImpl_Can__t_covert_method_signature_to_tag___9=Cannot convert method signature to tag: +TypeImpl_Invalid_signature____10=Invalid signature: " +TypeImpl___11=" +TypeImpl_Can__t_convert_method_signature_to_name_2=Cannot convert method signature to name +ValueImpl_Invalid_Value_tag_encountered___1=Invalid Value tag encountered: +VirtualMachineImpl_Target_VM__0__does_not_support_Hot_Code_Replacement_1=Target VM {0} does not support Hot Code Replacement +VirtualMachineImpl_Failed_to_get_ID_sizes_2=Failed to get ID sizes +VirtualMachineImpl_count_less_than_zero=The count of refTypes cannot be less than zero. +VirtualMachineImpl_Invalid_result_flag_in_Classes_Have_Changed_response___3=Invalid result flag in Classes Have Changed response: +VirtualMachineImpl__4= +VirtualMachineImpl_0=Packet Receive Manager +VirtualMachineImpl_1=Packet Send Manager +VirtualMachineImpl_2=Reference type list cannot be null. +VirtualMachineImpl_3=Improper instance counts between VM and client. +VirtualMachineManagerImpl_Could_not_open_verbose_file___1=Could not open verbose file " +VirtualMachineManagerImpl_____2=": +VoidTypeImpl_A_VoidType_does_not_have_modifiers_1=A VoidType does not have modifiers +VirtualMachineImpl_Add_method_not_implemented_1=Add method not implemented +VirtualMachineImpl_Scheme_change_not_implemented_2=Scheme change not implemented +VirtualMachineImpl_Hierarchy_change_not_implemented_3=Hierarchy change not implemented +VirtualMachineImpl_Delete_method_not_implemented_4=Delete method not implemented +VirtualMachineImpl_Class_modifiers_change_not_implemented_5=Class modifiers change not implemented +VirtualMachineImpl_Method_modifiers_change_not_implemented_6=Method modifiers change not implemented +VerboseWriter___unknown_value__1=\ +VerboseWriter__unknown_bit__2= +VerboseWriter__none__4= +ArrayReferenceImpl_Invalid_index_1=Invalid index +ArrayReferenceImpl_Invalid_srcIndex_2=Invalid srcIndex +ArrayReferenceImpl_Invalid_number_of_value_to_set_in_array_3=Invalid number of value to set in array +ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1=Generated value ({0}) is not compatible with declared type ({1}). +ArrayReferenceImpl_Invalid_number_of_value_to_get_from_array_1=Invalid number of value to get from array +ArrayReferenceImpl_Attempted_to_get_more_values_from_array_than_length_of_array_2=Attempted to get more values from array than length of array +ReferenceTypeImpl_28=SMAP parsing: {0} already used as file id in {1} +ReferenceTypeImpl_29=SMAP parsing: {0} is not a valid lineFileId. +ReferenceTypeImpl_27=Heap walking is not supported by this VM. +ReferenceTypeImpl_26=The maximum value cannot be less than zero. +ReferenceTypeImpl_30=No source names for this stratum. +ReferenceTypeImpl_31=Source Debug Extension not defined +ReferenceTypeImpl_32=source debug extension +ReferenceTypeImpl_34=No information for the specified sourceName. +SourceDebugExtensionParser_0=SMAP parsing: Unexpected end of file +SourceDebugExtensionParser_2=SMAP parsing: The default stratum is not defined in a stratum section. +SourceDebugExtensionParser_3=SMAP parsing: Invalid ID. +SourceDebugExtensionParser_4=SMAP parsing: Carriage return expected. +SourceDebugExtensionParser_5=SMAP parsing: Invalid output file name. +SourceDebugExtensionParser_6=SMAP parsing: Invalid default stratum id. +SourceDebugExtensionParser_7=SMAP parsing: Stratum section expected. +SourceDebugExtensionParser_8=SMAP parsing: Invalid stratum id. +SourceDebugExtensionParser_9=SMAP parsing: Stratum ''{0}'' already defined. +SourceDebugExtensionParser_10=SMAP parsing: File section already defined for stratum ''{0}''. +SourceDebugExtensionParser_11=SMAP parsing: Line section already defined for stratum ''{0}''. +SourceDebugExtensionParser_12=SMAP parsing: Unexpected token ''{0}''. +SourceDebugExtensionParser_13=SMAP parsing: No file section defined for stratum ''{0}''. +SourceDebugExtensionParser_14=SMAP parsing: No line section defined for stratum ''{0}''. +SourceDebugExtensionParser_16=SMAP parsing: File name expected. +SourceDebugExtensionParser_17=SMAP parsing: File id expected. +SourceDebugExtensionParser_19=SMAP parsing: Absolute file name expected. +SourceDebugExtensionParser_22=SMAP parsing: Input start line expected. +SourceDebugExtensionParser_23=SMAP parsing: Line file id expected. +SourceDebugExtensionParser_24=SMAP parsing: Repeat count expected. +SourceDebugExtensionParser_25=SMAP parsing: \':\' expected. +SourceDebugExtensionParser_26=SMAP parsing: Output start line expected. +SourceDebugExtensionParser_27=SMAP parsing: Output line increment expected. +SourceDebugExtensionParser_28=SMAP parsing: Carriage return expected. +StackFrameImpl_no_argument_values_available=The selected stack frame is no longer able to get argument values. +ObjectReferenceImpl_object_not_known=Object is not a known ID. +class_or_object_not_known=The class or object is not known or incorrect. +vm_dead=VM is not responding or disconnected. diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LocalVariableImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LocalVariableImpl.java new file mode 100644 index 0000000000..6af3fcb59c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LocalVariableImpl.java @@ -0,0 +1,241 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.StackFrame; +import com.sun.jdi.Type; +import com.sun.jdi.VMMismatchException; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class LocalVariableImpl extends MirrorImpl implements LocalVariable, Comparable { + /** Method that holds local variable. */ + private final MethodImpl fMethod; + /** First code index at which the variable is visible (unsigned). */ + private final long fCodeIndex; + /** The variable's name. */ + private final String fName; + /** The variable type's JNI signature. */ + private final String fSignature; + /** The variable type generic signature. */ + private final String fGenericSignature; + /** The variable's type */ + private Type fType; + /** The variables type name */ + private String fTypeName; + /** + * Unsigned value used in conjunction with codeIndex. The variable can be + * get or set only when the current codeIndex <= current frame code index < + * code index + length. + *

      + * The length is set to -1 when this variable represents an inferred + * argument (when local variable info is unavailable). We assume that such + * arguments are visible for the entire method. + *

      + * */ + private final int fLength; + /** The local variable's index in its frame. */ + private final int fSlot; + /** Is the local variable an argument of its method? */ + private final boolean fIsArgument; + + public LocalVariableImpl(VirtualMachineImpl vmImpl, MethodImpl method, + long codeIndex, String name, String signature, + String genericSignature, int length, int slot, boolean isArgument) { + super("LocalVariable", vmImpl); //$NON-NLS-1$ + fMethod = method; + fCodeIndex = codeIndex; + fName = name; + fSignature = signature; + fGenericSignature = genericSignature; + fLength = length; + fSlot = slot; + fIsArgument = isArgument; + } + + /** + * @return Returns local variable's index in its frame. + */ + public int slot() { + return fSlot; + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fMethod.hashCode() + (int) fCodeIndex + fSlot; + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object). + */ + @Override + public boolean equals(Object object) { + if (object != null && object.getClass().equals(this.getClass())) { + LocalVariableImpl loc = (LocalVariableImpl) object; + return fMethod.equals(loc.fMethod) && fCodeIndex == loc.fCodeIndex + && fSlot == loc.fSlot; + } + return false; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(LocalVariable variable) { + if (variable == null || !variable.getClass().equals(this.getClass())) + throw new ClassCastException( + JDIMessages.LocalVariableImpl_Can__t_compare_local_variable_to_given_object_1); + + // See if methods are the same, if not return comparison between + // methods. + LocalVariableImpl var2 = (LocalVariableImpl) variable; + if (!method().equals(var2.method())) + return method().compareTo(var2.method()); + + // Return comparison between the index of each local variable in its + // stack frame. + // Code indexes must be treated as unsigned. This matters if you have to + // compare them. + if (fCodeIndex < 0 || var2.fCodeIndex < 0) + throw new InternalError( + JDIMessages.LocalVariableImpl_Code_indexes_are_assumed_to_be_always_positive_2); + + long index2 = var2.fCodeIndex; + if (fCodeIndex < index2) + return -1; + else if (fCodeIndex > index2) + return 1; + else + return 0; + } + + /** + * @return Returns true if this variable is an argument to its method. + */ + @Override + public boolean isArgument() { + return fIsArgument; + } + + @Override + public boolean isVisible(StackFrame frame) throws IllegalArgumentException, + VMMismatchException { + checkVM(frame); + StackFrameImpl frameImpl = (StackFrameImpl) frame; + if (!fMethod.equals(frameImpl.location().method())) + throw new IllegalArgumentException( + JDIMessages.LocalVariableImpl_The_stack_frame__s_method_does_not_match_this_variable__s_method_3); + + if (fLength == -1) { + // inferred argument - assume visible for entire method + return true; + } + long currentIndex = frameImpl.location().codeIndex(); + + // Code indexes must be treated as unsigned. This matters if you have to + // compare them. + if (currentIndex >= 0 && fCodeIndex >= 0 && fCodeIndex + fLength >= 0) + return fCodeIndex <= currentIndex + && currentIndex < fCodeIndex + fLength; + + throw new InternalError( + JDIMessages.LocalVariableImpl_Code_indexes_are_assumed_to_be_always_positive_4); + } + + /** + * @return Returns the name of the local variable. + */ + @Override + public String name() { + return fName; + } + + /** + * @return Returns the signature of the local variable. + */ + @Override + public String signature() { + return fSignature; + } + + /** + * @return Returns the type of the this LocalVariable. + */ + @Override + public Type type() throws ClassNotLoadedException { + if (fType == null) { + fType = TypeImpl.create(virtualMachineImpl(), fSignature, method() + .declaringType().classLoader()); + } + return fType; + } + + /** + * @return Returns a text representation of the declared type of this + * variable. + */ + @Override + public String typeName() { + if (fTypeName == null) { + fTypeName = TypeImpl.signatureToName(fSignature); + } + return fTypeName; + } + + /** + * @return Returns the tag of the declared type of this variable. + */ + public byte tag() { + return TypeImpl.signatureToTag(fSignature); + } + + /** + * @return Returns the method that holds the local variable. + */ + public MethodImpl method() { + return fMethod; + } + + /** + * @return Returns true if the local variable is the 'this' pointer. + */ + public boolean isThis() { + return slot() == 0 && !method().isStatic(); + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + return fName; + } + + @Override + public String genericSignature() { + return fGenericSignature; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LocationImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LocationImpl.java new file mode 100644 index 0000000000..222d0704c7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LocationImpl.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.ReferenceType; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class LocationImpl extends MirrorImpl implements Location { + /** Line nr used if line numbers are not available. */ + public static final int LINE_NR_NOT_AVAILABLE = -1; + + /** Method that holds the location. */ + MethodImpl fMethod; + /** + * Index of location within the method, note: this value must be treated as + * UNSIGNED! + */ + long fIndex; + + /** + * Creates new instance. + */ + public LocationImpl(VirtualMachineImpl vmImpl, MethodImpl method, long index) { + super("Location", vmImpl); //$NON-NLS-1$ + fMethod = method; + fIndex = index; + } + + /** + * @return Returns the code position within this location's method. + */ + @Override + public long codeIndex() { + return fIndex; + } + + /** + * @return Returns the type to which this Location belongs. + */ + @Override + public ReferenceType declaringType() { + return fMethod.declaringType(); + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fMethod.hashCode() + (int) fIndex; + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + if (object != null && object.getClass().equals(this.getClass())) { + LocationImpl loc = (LocationImpl) object; + return fMethod.equals(loc.fMethod) && fIndex == loc.fIndex; + } + return false; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(Location locatable) { + if (locatable == null || !locatable.getClass().equals(this.getClass())) { + throw new ClassCastException( + JDIMessages.LocationImpl_Can__t_compare_location_to_given_object_1); + } + + // See if methods are the same, if not return comparison between + // methods. + LocationImpl location2 = (LocationImpl) locatable; + if (!method().equals(location2.method())) { + return method().compareTo(location2.method()); + } + + // Return comparison between code-indexes. + // Code indexes must be treated as unsigned. This matters if you have to + // compare them. + if (codeIndex() < 0 || location2.codeIndex() < 0) { + throw new InternalError( + JDIMessages.LocationImpl_Code_indexes_are_assumed_to_be_always_positive_2); + } + + if (codeIndex() < location2.codeIndex()) { + return -1; + } else if (codeIndex() > location2.codeIndex()) { + return 1; + } else { + return 0; + } + } + + /** + * @return Returns an int specifying the line in the source, return -1 if + * the information is not available. + */ + @Override + public int lineNumber() { + return lineNumber(virtualMachine().getDefaultStratum()); + } + + /** + * @return Returns the Method if this location is in a method. + */ + @Override + public Method method() { + return fMethod; + } + + /** + * @return a string specifying the source. + */ + @Override + public String sourceName() throws AbsentInformationException { + return sourceName(virtualMachine().getDefaultStratum()); + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return NLS.bind(JDIMessages.LocationImpl_sourcename___0___line___1__3, + new String[] { sourceName(), + Integer.toString(lineNumber()), method().toString() }); + } catch (Exception e) { + return fDescription; + } + } + + /** + * Writes JDWP representation. + */ + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + fMethod.writeWithReferenceTypeWithTag(target, out); + target.writeLong(fIndex, "index", out); //$NON-NLS-1$ + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static LocationImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + // Notice that Locations are not stored or cached because they don't + // 'remember' any information. + MethodImpl method = MethodImpl.readWithReferenceTypeWithTag(target, in); + long index = target.readLong("index", in); //$NON-NLS-1$ + if (method == null) { + return null; + } + return new LocationImpl(vmImpl, method, index); + } + + /** + * @see Location#lineNumber(String) + */ + @Override + public int lineNumber(String stratum) { + return fMethod.referenceTypeImpl().lineNumber(fIndex, fMethod, stratum); + } + + /** + * @see Location#sourceName(String) + */ + @Override + public String sourceName(String stratum) throws AbsentInformationException { + return fMethod.referenceTypeImpl().sourceName(fIndex, fMethod, stratum); + } + + /** + * @see Location#sourcePath(String) + */ + @Override + public String sourcePath(String stratum) throws AbsentInformationException { + return fMethod.referenceTypeImpl().sourcePath(fIndex, fMethod, stratum); + } + + /** + * @see Location#sourcePath() + */ + @Override + public String sourcePath() throws AbsentInformationException { + return sourcePath(virtualMachine().getDefaultStratum()); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LongTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LongTypeImpl.java new file mode 100644 index 0000000000..669848101e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LongTypeImpl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.LongType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class LongTypeImpl extends PrimitiveTypeImpl implements LongType { + /** + * Creates new instance. + */ + public LongTypeImpl(VirtualMachineImpl vmImpl) { + super("LongType", vmImpl, "long", "J"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return LongValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf(0L); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LongValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LongValueImpl.java new file mode 100644 index 0000000000..741884823a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/LongValueImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.LongValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class LongValueImpl extends PrimitiveValueImpl implements LongValue { + /** JDWP Tag. */ + public static final byte tag = JdwpID.LONG_TAG; + + /** + * Creates new instance. + */ + public LongValueImpl(VirtualMachineImpl vmImpl, Long value) { + super("LongValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getLongType(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(LongValue o) { + return ((Long)longValue()).compareTo(o.longValue()); + } + + /** + * @return Value. + */ + @Override + public long value() { + return longValue(); + } + + /** + * @return Reads and returns new instance. + */ + public static LongValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + long value = target.readLong("longValue", in); //$NON-NLS-1$ + return new LongValueImpl(vmImpl, Long.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeLong(((Long) fValue).longValue(), "longValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MethodImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MethodImpl.java new file mode 100644 index 0000000000..023b9d4879 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MethodImpl.java @@ -0,0 +1,923 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Tim Tromey - update method signature syntax (bug 31507) + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpMethodID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassLoaderReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.Locatable; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.Type; + +/** + * Implementation of com.sun.jdi.Method. + */ +public class MethodImpl extends TypeComponentImpl implements Method, Locatable { + /** InvokeOptions Constants. */ + public static final int INVOKE_SINGLE_THREADED_JDWP = 0x01; + public static final int INVOKE_NONVIRTUAL_JDWP = 0x02; + + /** Map with Strings for flag bits. */ + private static String[] fgInvokeOptions = null; + + /** MethodTypeID that corresponds to this reference. */ + private final JdwpMethodID fMethodID; + + /** The following are the stored results of JDWP calls. */ + private List fVariables = null; + private long fLowestValidCodeIndex = -1; + private long fHighestValidCodeIndex = -1; + private Map fCodeIndexToLine = null; + private Map> fLineToCodeIndexes = null; + private Map>> fStratumAllLineLocations = null; + private int fArgumentSlotsCount = -1; + private List fArguments = null; + private List fArgumentTypes = null; + private List fArgumentTypeNames = null; + private List fArgumentTypeSignatures = null; + private byte[] fByteCodes = null; + private long[] fCodeIndexTable; + private int[] fJavaStratumLineNumberTable; + + private String fReturnTypeName = null; + + /** + * Creates new MethodImpl. + */ + public MethodImpl(VirtualMachineImpl vmImpl, + ReferenceTypeImpl declaringType, JdwpMethodID methodID, + String name, String signature, String genericSignature, + int modifierBits) { + super( + "Method", vmImpl, declaringType, name, signature, genericSignature, modifierBits); //$NON-NLS-1$ + fMethodID = methodID; + } + + /** + * Flushes all stored Jdwp results. + */ + protected void flushStoredJdwpResults() { + fVariables = null; + fLowestValidCodeIndex = -1; + fHighestValidCodeIndex = -1; + fCodeIndexToLine = null; + fLineToCodeIndexes = null; + fStratumAllLineLocations = null; + fCodeIndexTable = null; + fJavaStratumLineNumberTable = null; + fArgumentSlotsCount = -1; + fArguments = null; + fArgumentTypes = null; + fArgumentTypeNames = null; + fArgumentTypeSignatures = null; + fByteCodes = null; + } + + /** + * @return Returns methodID of method. + */ + protected JdwpMethodID getMethodID() { + return fMethodID; + } + + /** + * @return Returns map of location to line number. + */ + protected Map javaStratumCodeIndexToLine() + throws AbsentInformationException { + if (isAbstract()) { + return Collections.EMPTY_MAP; + } + getLineTable(); + return fCodeIndexToLine; + } + + /** + * @return Returns map of line number to locations. + */ + protected List javaStratumLineToCodeIndexes(int line) throws AbsentInformationException { + if (isAbstract() || isNative()) { + return null; + } + getLineTable(); + + return fLineToCodeIndexes.get(Integer.valueOf(line)); + } + + /** + * Gets line table from VM. + */ + private void getLineTable() throws AbsentInformationException { + if (isObsolete()) { + return; + } + if (fCodeIndexToLine != null) { + if (fCodeIndexToLine.isEmpty()) { + throw new AbsentInformationException( + JDIMessages.MethodImpl_Got_empty_line_number_table_for_this_method_1); + } + return; + } + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeWithReferenceType(this, outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.M_LINE_TABLE, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.ABSENT_INFORMATION: + throw new AbsentInformationException( + JDIMessages.MethodImpl_No_line_number_information_available_2); + case JdwpReplyPacket.NATIVE_METHOD: + throw new AbsentInformationException( + JDIMessages.MethodImpl_No_line_number_information_available_2); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + fLowestValidCodeIndex = readLong("lowest index", replyData); //$NON-NLS-1$ + fHighestValidCodeIndex = readLong("highest index", replyData); //$NON-NLS-1$ + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + fCodeIndexToLine = new HashMap<>(); + fLineToCodeIndexes = new HashMap<>(); + if (nrOfElements == 0) { + throw new AbsentInformationException( + JDIMessages.MethodImpl_Got_empty_line_number_table_for_this_method_3); + } + fCodeIndexTable = new long[nrOfElements]; + fJavaStratumLineNumberTable = new int[nrOfElements]; + for (int i = 0; i < nrOfElements; i++) { + long lineCodeIndex = readLong("code index", replyData); //$NON-NLS-1$ + Long lineCodeIndexLong = Long.valueOf(lineCodeIndex); + int lineNr = readInt("line nr", replyData); //$NON-NLS-1$ + Integer lineNrInt = Integer.valueOf(lineNr); + + // Add entry to code-index to line mapping. + fCodeIndexToLine.put(lineCodeIndexLong, lineNrInt); + + fCodeIndexTable[i] = lineCodeIndex; + fJavaStratumLineNumberTable[i] = lineNr; + + List lineNrEntry = fLineToCodeIndexes.get(lineNrInt); + if (lineNrEntry == null) { + lineNrEntry = new ArrayList<>(); + fLineToCodeIndexes.put(lineNrInt, lineNrEntry); + } + lineNrEntry.add(lineCodeIndexLong); + } + } catch (IOException e) { + fCodeIndexToLine = null; + fLineToCodeIndexes = null; + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the line number that corresponds to the given + * lineCodeIndex. + */ + protected int javaStratumLineNumber(long lineCodeIndex) + throws AbsentInformationException { + if (isAbstract() || isNative() || isObsolete()) { + return -1; + } + getLineTable(); + if (lineCodeIndex > fHighestValidCodeIndex) { + throw new AbsentInformationException(JDIMessages.MethodImpl_Invalid_code_index_of_a_location_given_4); + } + + Long lineCodeIndexObj; + Integer lineNrObj; + long index = lineCodeIndex; + // Search for the line where this code index is located. + do { + lineCodeIndexObj = Long.valueOf(index); + lineNrObj = javaStratumCodeIndexToLine().get(lineCodeIndexObj); + } while (lineNrObj == null && --index >= fLowestValidCodeIndex); + if (lineNrObj == null) { + if (lineCodeIndex >= fLowestValidCodeIndex) { + index = lineCodeIndex; + do { + lineCodeIndexObj = Long.valueOf(index); + lineNrObj = javaStratumCodeIndexToLine().get(lineCodeIndexObj); + } while (lineNrObj == null && ++index <= fHighestValidCodeIndex); + if (lineNrObj != null) { + return lineNrObj.intValue(); + } + } + throw new AbsentInformationException(JDIMessages.MethodImpl_Invalid_code_index_of_a_location_given_4); + } + return lineNrObj.intValue(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#allLineLocations() + */ + @Override + public List allLineLocations() throws AbsentInformationException { + return allLineLocations(virtualMachine().getDefaultStratum(), null); + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#arguments() + */ + @Override + public List arguments() throws AbsentInformationException { + if (isNative() || isAbstract()) { + throw new AbsentInformationException(JDIMessages.MethodImpl_No_local_variable_information_available_9); + } + if (fArguments != null) { + return fArguments; + } + + List result = new ArrayList<>(); + Iterator iter = variables().iterator(); + while (iter.hasNext()) { + LocalVariable var = iter.next(); + if (var.isArgument()) { + result.add(var); + } + } + fArguments = result; + return fArguments; + } + + /** + * @return Returns a text representation of all declared argument types of + * this method. + */ + @Override + public List argumentTypeNames() { + if (fArgumentTypeNames != null) { + return fArgumentTypeNames; + } + List result = new ArrayList<>(); + for (String signature : argumentTypeSignatures()) { + result.add(TypeImpl.signatureToName(signature)); + } + + fArgumentTypeNames = result; + return fArgumentTypeNames; + } + + /** + * @return Returns a signatures of all declared argument types of this + * method. + */ + private List argumentTypeSignatures() { + if (fArgumentTypeSignatures != null) { + return fArgumentTypeSignatures; + } + + fArgumentTypeSignatures = GenericSignature.getParameterTypes(signature()); + return fArgumentTypeSignatures; + } + + /** + * @return Returns the list containing the type of each argument. + */ + @Override + public List argumentTypes() throws ClassNotLoadedException { + if (fArgumentTypes != null) { + return fArgumentTypes; + } + List result = new ArrayList<>(); + Iterator iter = argumentTypeSignatures().iterator(); + ClassLoaderReference classLoaderRef = declaringType().classLoader(); + VirtualMachineImpl vm = virtualMachineImpl(); + while (iter.hasNext()) { + String argumentTypeSignature = iter.next(); + result.add(TypeImpl.create(vm, argumentTypeSignature, classLoaderRef)); + } + fArgumentTypes = result; + return fArgumentTypes; + } + + /** + * @return Returns an array containing the bytecodes for this method. + */ + @Override + public byte[] bytecodes() { + if (fByteCodes != null) { + return fByteCodes; + } + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeWithReferenceType(this, outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.M_BYTECODES, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int length = readInt("length", replyData); //$NON-NLS-1$ + fByteCodes = readByteArray(length, "bytecodes", replyData); //$NON-NLS-1$ + return fByteCodes; + } catch (IOException e) { + fByteCodes = null; + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fMethodID.hashCode(); + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null + && object.getClass().equals(this.getClass()) + && fMethodID.equals(((MethodImpl) object).fMethodID) + && referenceTypeImpl().equals( + ((MethodImpl) object).referenceTypeImpl()); + } + + /** + * @return Returns a negative integer, zero, or a positive integer as this + * {@link Method} is less than, equal to, or greater than the specified + * {@link Method}. + */ + @Override + public int compareTo(Method method) { + if (method == null || !method.getClass().equals(this.getClass())) { + throw new ClassCastException( + JDIMessages.MethodImpl_Can__t_compare_method_to_given_object_6); + } + + // See if declaring types are the same, if not return comparison between + // declaring types. + Method type2 = method; + if (!declaringType().equals(type2.declaringType())) { + return declaringType().compareTo(type2.declaringType()); + } + + // Return comparison of position within declaring type. + int index1 = declaringType().methods().indexOf(this); + int index2 = type2.declaringType().methods().indexOf(type2); + if (index1 < index2) { + return -1; + } else if (index1 > index2) { + return 1; + } else { + return 0; + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isAbstract() + */ + @Override + public boolean isAbstract() { + return (fModifierBits & MODIFIER_ACC_ABSTRACT) != 0; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isConstructor() + */ + @Override + public boolean isConstructor() { + return name().equals(""); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isNative() + */ + @Override + public boolean isNative() { + return (fModifierBits & MODIFIER_ACC_NATIVE) != 0; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isStaticInitializer() + */ + @Override + public boolean isStaticInitializer() { + return name().equals(""); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isSynchronized() + */ + @Override + public boolean isSynchronized() { + return (fModifierBits & MODIFIER_ACC_SYNCHRONIZED) != 0; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#locationOfCodeIndex(long) + */ + @Override + public Location locationOfCodeIndex(long index) { + if (isAbstract() || isNative()) { + return null; + } + try { + Integer lineNrInt = javaStratumCodeIndexToLine().get(Long.valueOf(index)); + if (lineNrInt == null) { + throw new AbsentInformationException(MessageFormat.format(JDIMessages.MethodImpl_No_valid_location_at_the_specified_code_index__0__2, new Object[] { Long.toString(index) })); + } + } catch (AbsentInformationException e) { + } + return new LocationImpl(virtualMachineImpl(), this, index); + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#locationsOfLine(int) + */ + @Override + public List locationsOfLine(int line) throws AbsentInformationException { + return locationsOfLine(virtualMachine().getDefaultStratum(), null, line); + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#returnType() + */ + @Override + public Type returnType() throws ClassNotLoadedException { + int startIndex = signature().lastIndexOf(')') + 1; // Signature position + // is just after + // ending brace. + return TypeImpl.create(virtualMachineImpl(), + signature().substring(startIndex), declaringType() + .classLoader()); + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#returnTypeName() + */ + @Override + public String returnTypeName() { + if (fReturnTypeName != null) { + return fReturnTypeName; + } + int startIndex = signature().lastIndexOf(')') + 1; // Signature position + // is just after + // ending brace. + fReturnTypeName = TypeImpl.signatureToName(signature().substring( + startIndex)); + return fReturnTypeName; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#variables() + */ + @Override + public List variables() throws AbsentInformationException { + if (isNative() || isAbstract()) { + throw new AbsentInformationException(JDIMessages.MethodImpl_No_local_variable_information_available_9); + } + if (fVariables != null) { + return fVariables; + } + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeWithReferenceType(this, outData); + + boolean withGenericSignature = virtualMachineImpl() + .isJdwpVersionGreaterOrEqual(1, 5); + int jdwpCommand = withGenericSignature ? JdwpCommandPacket.M_VARIABLE_TABLE_WITH_GENERIC + : JdwpCommandPacket.M_VARIABLE_TABLE; + JdwpReplyPacket replyPacket = requestVM(jdwpCommand, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.ABSENT_INFORMATION: + return inferArguments(); + } + + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + fArgumentSlotsCount = readInt("arg count", replyData); //$NON-NLS-1$ + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + List variables = new ArrayList<>(nrOfElements); + for (int i = 0; i < nrOfElements; i++) { + long codeIndex = readLong("code index", replyData); //$NON-NLS-1$ + String name = readString("name", replyData); //$NON-NLS-1$ + String signature = readString("signature", replyData); //$NON-NLS-1$ + String genericSignature = null; + if (withGenericSignature) { + genericSignature = readString("generic signature", replyData); //$NON-NLS-1$ + if ("".equals(genericSignature)) { //$NON-NLS-1$ + genericSignature = null; + } + } + int length = readInt("length", replyData); //$NON-NLS-1$ + int slot = readInt("slot", replyData); //$NON-NLS-1$ + boolean isArgument = slot < fArgumentSlotsCount; + + if (!name.equals("this")) { //$NON-NLS-1$ + LocalVariableImpl localVar = new LocalVariableImpl( + virtualMachineImpl(), this, codeIndex, name, + signature, genericSignature, length, slot, + isArgument); + variables.add(localVar); + } + } + fVariables = variables; + return fVariables; + } catch (IOException e) { + fArgumentSlotsCount = -1; + fVariables = null; + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @throws AbsentInformationException + */ + private List inferArguments() throws AbsentInformationException { + // infer arguments, if possible + + // try to generate the right generic signature for each argument + String genericSignature = genericSignature(); + String[] signatures = argumentTypeSignatures().toArray(new String[0]); + String[] genericSignatures; + if (genericSignature == null) { + genericSignatures = new String[signatures.length]; + } else { + genericSignatures = GenericSignature.getParameterTypes(genericSignature).toArray(new String[0]); + for (int i = 0; i < genericSignatures.length; i++) { + if (genericSignatures[i].equals(signatures[i])) { + genericSignatures[i] = null; + } + } + } + + int slot = 0; + if (!isStatic()) { + slot++; + } + if (signatures.length > 0) { + fArgumentSlotsCount = signatures.length; + fVariables = new ArrayList<>(fArgumentSlotsCount); + for (int i = 0; i < signatures.length; i++) { + String name = "arg" + i; //$NON-NLS-1$ + LocalVariableImpl localVar = new LocalVariableImpl(virtualMachineImpl(), this, 0, name, signatures[i], genericSignatures[i], -1, slot, true); + fVariables.add(localVar); + slot++; + } + return fVariables; + } + throw new AbsentInformationException( + JDIMessages.MethodImpl_No_local_variable_information_available_9); + + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#variablesByName(java.lang.String) + */ + @Override + public List variablesByName(String name) throws AbsentInformationException { + Iterator iter = variables().iterator(); + List result = new ArrayList<>(); + while (iter.hasNext()) { + LocalVariable var = iter.next(); + if (var.name().equals(name)) { + result.add(var); + } + } + return result; + } + + /** + * @see com.sun.jdi.Locatable#location() + */ + @Override + public Location location() { + if (isAbstract()) { + return null; + } + if (isNative()) { + return new LocationImpl(virtualMachineImpl(), this, -1); + } + // First retrieve line code table. + try { + getLineTable(); + } catch (AbsentInformationException e) { + return new LocationImpl(virtualMachineImpl(), this, -1); + } + + // Return location with Lowest Valid Code Index. + return new LocationImpl(virtualMachineImpl(), this, + fLowestValidCodeIndex); + } + + /** + * Writes JDWP representation. + */ + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + fMethodID.write(out); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("method", fMethodID.value()); //$NON-NLS-1$ + } + } + + /** + * Writes JDWP representation, including ReferenceType. + */ + protected void writeWithReferenceType(MirrorImpl target, + DataOutputStream out) throws IOException { + referenceTypeImpl().write(target, out); + write(target, out); + } + + /** + * Writes JDWP representation, including ReferenceType with Tag. + */ + protected void writeWithReferenceTypeWithTag(MirrorImpl target, + DataOutputStream out) throws IOException { + referenceTypeImpl().writeWithTag(target, out); + write(target, out); + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + protected static MethodImpl readWithReferenceTypeWithTag(MirrorImpl target, + DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + // See Location. + ReferenceTypeImpl referenceType = ReferenceTypeImpl.readWithTypeTag( + target, in); + if (referenceType == null) { + return null; + } + + JdwpMethodID ID = new JdwpMethodID(vmImpl); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("method", ID.value()); //$NON-NLS-1$ + } + + ID.read(in); + if (ID.isNull()) { + return null; + } + + // The method must be part of a known reference type. + Method method = referenceType.findMethod(ID); + if (method == null) { + throw new InternalError( + JDIMessages.MethodImpl_Got_MethodID_of_ReferenceType_that_is_not_a_member_of_the_ReferenceType_10); + } + return (MethodImpl) method; + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + protected static MethodImpl readWithNameSignatureModifiers( + ReferenceTypeImpl target, ReferenceTypeImpl referenceType, + boolean withGenericSignature, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpMethodID ID = new JdwpMethodID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("method", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + String name = target.readString("name", in); //$NON-NLS-1$ + String signature = target.readString("signature", in); //$NON-NLS-1$ + String genericSignature = null; + if (withGenericSignature) { + genericSignature = target.readString("generic signature", in); //$NON-NLS-1$ + if ("".equals(genericSignature)) { //$NON-NLS-1$ + genericSignature = null; + } + } + int modifierBits = target.readInt( + "modifiers", AccessibleImpl.getModifierStrings(), in); //$NON-NLS-1$ + + MethodImpl mirror = new MethodImpl(vmImpl, referenceType, ID, name, + signature, genericSignature, modifierBits); + return mirror; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgInvokeOptions != null) { + return; + } + + Field[] fields = MethodImpl.class.getDeclaredFields(); + fgInvokeOptions = new String[32]; + + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + + if (name.startsWith("INVOKE_")) { //$NON-NLS-1$ + int value = field.getInt(null); + for (int j = 0; j < fgInvokeOptions.length; j++) { + if ((1 << j & value) != 0) { + fgInvokeOptions[j] = name; + break; + } + } + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + protected static String[] getInvokeOptions() { + getConstantMaps(); + return fgInvokeOptions; + } + + /** + * @see Method#isObsolete() + * + * The JDK 1.4.0 specification states that obsolete methods are given + * an ID of zero. It also states that when a method is redefined, the + * new method gets the ID of the old method. Thus, the JDWP query for + * isObsolete on JDK 1.4 will never return true for a non-zero method + * ID. The query is therefore not needed + */ + @Override + public boolean isObsolete() { + if (virtualMachineImpl().isJdwpVersionGreaterOrEqual(1, 4)) { + return fMethodID.value() == 0; + } + return false; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#allLineLocations(java.lang.String, java.lang.String) + */ + @Override + public List allLineLocations(String stratum, String sourceName) throws AbsentInformationException { + if (isAbstract() || isNative()) { + return Collections.EMPTY_LIST; + } + if (stratum == null) { // if stratum not defined use the default stratum for the declaring type + stratum = declaringType().defaultStratum(); + } + List allLineLocations = null; + Map> sourceNameAllLineLocations = null; + if (fStratumAllLineLocations == null) { // the stratum map doesn't + // exist, create it + fStratumAllLineLocations = new HashMap<>(); + } else { + // get the source name map + sourceNameAllLineLocations = fStratumAllLineLocations.get(stratum); + } + if (sourceNameAllLineLocations == null) { // the source name map doesn't + // exist, create it + sourceNameAllLineLocations = new HashMap<>(); + fStratumAllLineLocations.put(stratum, sourceNameAllLineLocations); + } else { + // get the line locations + allLineLocations = sourceNameAllLineLocations.get(sourceName); + } + if (allLineLocations == null) { // the line locations are not know, + // compute and store them + getLineTable(); + allLineLocations = referenceTypeImpl().allLineLocations(stratum, sourceName, this, fCodeIndexTable, fJavaStratumLineNumberTable); + sourceNameAllLineLocations.put(sourceName, allLineLocations); + } + return allLineLocations; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#locationsOfLine(java.lang.String, java.lang.String, int) + */ + @Override + public List locationsOfLine(String stratum, String sourceName, + int lineNumber) throws AbsentInformationException { + if (isAbstract() || isNative()) { + return Collections.EMPTY_LIST; + } + return referenceTypeImpl().locationsOfLine(stratum, sourceName, lineNumber, this); + } + + /** + * Return a list which contains a location for the each disjoint range of + * code indices that have bean assigned to the given lines (by the compiler + * or/and the VM). Return an empty list if there is not executable code at + * the specified lines. + */ + protected List javaStratumLocationsOfLines(List javaLines) throws AbsentInformationException { + Set tmpLocations = new TreeSet<>(); + for (Integer key : javaLines) { + List indexes = javaStratumLineToCodeIndexes(key.intValue()); + if (indexes != null) { + tmpLocations.addAll(indexes); + } + } + List locations = new ArrayList<>(); + for (Long location : tmpLocations) { + long index = location.longValue(); + int position = Arrays.binarySearch(fCodeIndexTable, index); + if(position < 0) { + //https://bugs.eclipse.org/bugs/show_bug.cgi?id=388172 + //the key is not in the code index, we should not insert it as the line table is supposed to be + //constant unless the parent class is redefined. + //See http://docs.oracle.com/javase/6/docs/platform/jpda/jdwp/jdwp-protocol.html#JDWP_Method_LineTable for more information + continue; + } + if (position == 0 || !tmpLocations.contains(Long.valueOf(fCodeIndexTable[position - 1]))) { + locations.add(new LocationImpl(virtualMachineImpl(), this, index)); + } + } + return locations; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isBridge() + */ + @Override + public boolean isBridge() { + return (fModifierBits & MODIFIER_ACC_BRIDGE) != 0; + } + + /* (non-Javadoc) + * @see com.sun.jdi.Method#isVarArgs() + */ + @Override + public boolean isVarArgs() { + // TODO: remove this test when j9 solve its problem + // it returns invalid 1.5 flags for 1.4 classes. + // see bug 53870 + return !virtualMachine().name().equals("j9") && (fModifierBits & MODIFIER_ACC_VARARGS) != 0; //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MirrorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MirrorImpl.java new file mode 100644 index 0000000000..86a6a6a014 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MirrorImpl.java @@ -0,0 +1,761 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.time.Instant; +import java.util.Map; + +import org.eclipse.jdi.Bootstrap; +import org.eclipse.jdi.TimeoutException; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpPacket; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdi.internal.jdwp.JdwpString; +import org.eclipse.jdt.internal.debug.core.JDIDebugOptions; + +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.InternalException; +import com.sun.jdi.InvalidStackFrameException; +import com.sun.jdi.Mirror; +import com.sun.jdi.NativeMethodException; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VMMismatchException; +import com.sun.jdi.VMOutOfMemoryException; +import com.sun.jdi.VirtualMachine; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class MirrorImpl implements Mirror { + + /** Description of Mirror object. */ + protected String fDescription; + /** Virtual Machine of Mirror object. */ + private final VirtualMachineImpl fVirtualMachineImpl; + /** + * VerboseWriter where verbose info is written to, null if no verbose must + * be given. + */ + protected VerboseWriter fVerboseWriter = null; + /** + * True if a Jdwp request has been sent to the VM and the response is not + * yet (fully) processed. + */ + private boolean fPendingJdwpRequest = false; + + /** + * Constructor only to be used by Virtual Machine objects: stores + * description of Mirror object and Virtual Machine. + */ + public MirrorImpl(String description) { + fDescription = description; + fVirtualMachineImpl = (VirtualMachineImpl) this; + initVerboseWriter(); + } + + /** + * Constructor stores description of Mirror object and its Virtual Machine. + */ + public MirrorImpl(String description, VirtualMachineImpl virtualMachineImpl) { + fVirtualMachineImpl = virtualMachineImpl; + fDescription = description; + initVerboseWriter(); + } + + private void initVerboseWriter() { + if (!VirtualMachineManagerImpl.isVerboseTracingEnabled()) { + return; + } + VirtualMachineManagerImpl machineManagerImpl = (VirtualMachineManagerImpl) org.eclipse.jdi.Bootstrap.virtualMachineManager(); + PrintWriter writer = machineManagerImpl.verbosePrintWriter(); + if (writer != null) { + fVerboseWriter = new VerboseWriter(writer); + } + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + return fDescription; + } + + /** + * @return Returns Virtual Machine of Mirror object. + */ + @Override + public VirtualMachine virtualMachine() { + return fVirtualMachineImpl; + } + + /** + * @return Returns Virtual Machine implementation of Mirror object. + */ + public VirtualMachineImpl virtualMachineImpl() { + return fVirtualMachineImpl; + } + + /** + * Processing before each Jdwp event. + */ + public void initJdwpEventSet(JdwpCommandPacket commandPacket) { + if (fVerboseWriter != null) { + fVerboseWriter.println("Received event set"); //$NON-NLS-1$ + fVerboseWriter.println("length", commandPacket.getLength()); //$NON-NLS-1$ + fVerboseWriter.println("id", commandPacket.getId()); //$NON-NLS-1$ + fVerboseWriter.println( + "flags", commandPacket.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ + fVerboseWriter.println( + "command set", (byte) (commandPacket.getCommand() >>> 8)); //$NON-NLS-1$ + fVerboseWriter + .println("command", (byte) commandPacket.getCommand()); //$NON-NLS-1$ + } + } + + /** + * Processing after each Jdwp Event. + */ + public void handledJdwpEventSet(Throwable t) { + if (fVerboseWriter != null) { + if (t instanceof TimeoutException || t instanceof VMDisconnectedException) { + // do nothing + } else { + if (t != null) { + fVerboseWriter.printStackTrace(t); + } + fVerboseWriter.println(); + } + fVerboseWriter.flush(); + } + } + + /** + * Processing before each Jdwp request. Note that this includes building the + * request message and parsing the response. + */ + public void initJdwpRequest() { + if (fVerboseWriter != null) { + fVerboseWriter.gotoPosition(6); + } + } + + /** + * Writes command packet header if verbose is on. + */ + public void writeVerboseCommandPacketHeader(JdwpCommandPacket commandPacket) { + if (fVerboseWriter != null) { + int command = commandPacket.getCommand(); + int currentPosition = fVerboseWriter.position(); + fVerboseWriter.gotoPosition(0); + fVerboseWriter.print("Sending command ("); //$NON-NLS-1$ + fVerboseWriter.printValue(command, JdwpCommandPacket.commandMap()); + fVerboseWriter.println(")"); //$NON-NLS-1$ + fVerboseWriter.println("length", commandPacket.getLength()); //$NON-NLS-1$ + fVerboseWriter.println("id", commandPacket.getId()); //$NON-NLS-1$ + fVerboseWriter.println( + "flags", commandPacket.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ + fVerboseWriter.println("command set", (byte) (command >>> 8)); //$NON-NLS-1$ + fVerboseWriter.println("command", (byte) command); //$NON-NLS-1$ + fVerboseWriter.gotoPosition(currentPosition); + } + } + + /** + * Processing after each Jdwp Request. + */ + public void handledJdwpRequest() { + if (fVerboseWriter != null && fPendingJdwpRequest) { + fVerboseWriter.println(); + fVerboseWriter.flush(); + } + fPendingJdwpRequest = false; + } + + /** + * Performs a VM request. + * + * @return Returns reply data. + */ + public JdwpReplyPacket requestVM(int command, byte[] outData) { + JdwpCommandPacket commandPacket = new JdwpCommandPacket(command); + commandPacket.setData(outData); + long sent = System.currentTimeMillis(); + fVirtualMachineImpl.packetSendManager().sendPacket(commandPacket); + fPendingJdwpRequest = true; + writeVerboseCommandPacketHeader(commandPacket); + + JdwpReplyPacket reply = fVirtualMachineImpl.packetReceiveManager() + .getReply(commandPacket); + long recieved = System.currentTimeMillis(); + if (JDIDebugOptions.DEBUG_JDI_REQUEST_TIMES) { + StringBuilder buf = new StringBuilder(); + buf.append(JDIDebugOptions.FORMAT.format(Instant.ofEpochMilli(sent))); + buf.append(" JDI Request: "); //$NON-NLS-1$ + buf.append(commandPacket.toString()); + buf.append("\n\tResponse Time: "); //$NON-NLS-1$ + buf.append(recieved - sent); + buf.append("ms"); //$NON-NLS-1$ + buf.append(" length: "); //$NON-NLS-1$ + buf.append(reply.getLength()); + JDIDebugOptions.trace(buf.toString()); + } + if (fVerboseWriter != null) { + fVerboseWriter.println(); + fVerboseWriter.println("Received reply"); //$NON-NLS-1$ + fVerboseWriter.println("length", reply.getLength()); //$NON-NLS-1$ + fVerboseWriter.println("id", reply.getId()); //$NON-NLS-1$ + fVerboseWriter.println( + "flags", reply.getFlags(), JdwpPacket.getFlagMap()); //$NON-NLS-1$ + fVerboseWriter + .println( + "error code", reply.errorCode(), JdwpReplyPacket.errorMap()); //$NON-NLS-1$ + } + + return reply; + } + + /** + * Performs a VM request. + * + * @return Returns reply data. + */ + public JdwpReplyPacket requestVM(int command, ByteArrayOutputStream outData) { + return requestVM(command, outData.toByteArray()); + } + + /** + * Performs a VM request for a specified object. + * + * @return Returns reply data. + */ + public JdwpReplyPacket requestVM(int command, ObjectReferenceImpl object) { + ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); + DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); + try { + object.write(this, dataOutStream); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } + return requestVM(command, byteOutStream); + } + + /** + * Performs a VM request for a specified object. + * + * @return Returns reply data. + */ + public JdwpReplyPacket requestVM(int command, ReferenceTypeImpl refType) { + ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); + DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); + try { + refType.write(this, dataOutStream); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } + return requestVM(command, byteOutStream); + } + + /** + * Performs a VM request. + * + * @return Returns reply data. + */ + public JdwpReplyPacket requestVM(int command) { + return requestVM(command, (byte[]) null); + } + + /** + * Performs default error handling. + */ + public void defaultReplyErrorHandler(int error) { + switch (error) { + case JdwpReplyPacket.NONE: + break; + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotPreparedException(); + case JdwpReplyPacket.CLASS_NOT_PREPARED: + throw new ClassNotPreparedException(); + case JdwpReplyPacket.OUT_OF_MEMORY: + throw new VMOutOfMemoryException(); + case JdwpReplyPacket.ILLEGAL_ARGUMENT: + throw new IllegalArgumentException(); + case JdwpReplyPacket.NATIVE_METHOD: + throw new NativeMethodException(); + case JdwpReplyPacket.INVALID_FRAMEID: + throw new InvalidStackFrameException(); + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException(); + case JdwpReplyPacket.HCR_OPERATION_REFUSED: + throw new org.eclipse.jdi.hcr.OperationRefusedException(); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(); + default: + throw new InternalException( + JDIMessages.MirrorImpl_Got_error_code_in_reply___1 + error, + error); + } + } + + /** + * Performs default handling of IOException in creating or interpreting a + * Jdwp packet. + */ + public void defaultIOExceptionHandler(Exception e) { + throw new InternalException(JDIMessages.MirrorImpl_Got_invalid_data___2 + + e); + } + + /** + * Waits for a specified command packet from the VM. + * + * @return Returns Command Packet from VM. + */ + public final JdwpCommandPacket getCommandVM(int command, long timeout) + throws InterruptedException { + return fVirtualMachineImpl.packetReceiveManager().getCommand(command, + timeout); + } + + /** + * @exception VMMismatchException + * is thrown if the Mirror argument and this mirror do not + * belong to the same VirtualMachine. + */ + public void checkVM(Mirror mirror) throws VMMismatchException { + if (((MirrorImpl) mirror).virtualMachineImpl() != this + .virtualMachineImpl()) { + throw new VMMismatchException(); + } + } + + /** + * Disconnects VM. + */ + public void disconnectVM() { + fVirtualMachineImpl.setDisconnected(true); + fVirtualMachineImpl.packetSendManager().disconnectVM(); + fVirtualMachineImpl.packetReceiveManager().disconnectVM(); + ((VirtualMachineManagerImpl) Bootstrap.virtualMachineManager()) + .removeConnectedVM(fVirtualMachineImpl); + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public byte readByte(String description, DataInputStream in) + throws IOException { + byte result = in.readByte(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public short readShort(String description, DataInputStream in) + throws IOException { + short result = in.readShort(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public int readInt(String description, DataInputStream in) + throws IOException { + int result = in.readInt(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public long readLong(String description, DataInputStream in) + throws IOException { + long result = in.readLong(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public byte readByte(String description, Map valueToString, + DataInputStream in) throws IOException { + byte result = in.readByte(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result, valueToString); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public short readShort(String description, Map valueToString, + DataInputStream in) throws IOException { + short result = in.readShort(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result, valueToString); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public int readInt(String description, Map valueToString, DataInputStream in) + throws IOException { + int result = in.readInt(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result, valueToString); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public String readString(String description, DataInputStream in) + throws IOException { + String result = JdwpString.read(in); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public boolean readBoolean(String description, DataInputStream in) + throws IOException { + boolean result = in.readBoolean(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public char readChar(String description, DataInputStream in) + throws IOException { + char result = in.readChar(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public double readDouble(String description, DataInputStream in) + throws IOException { + double result = in.readDouble(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public float readFloat(String description, DataInputStream in) + throws IOException { + float result = in.readFloat(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public byte[] readByteArray(int length, String description, + DataInputStream in) throws IOException { + byte[] result = new byte[length]; + in.readFully(result); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result); + } + return result; + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeByte(byte value, String description, DataOutputStream out) + throws IOException { + out.writeByte(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeShort(short value, String description, DataOutputStream out) + throws IOException { + out.writeShort(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeInt(int value, String description, DataOutputStream out) + throws IOException { + out.writeInt(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeLong(long value, String description, DataOutputStream out) + throws IOException { + out.writeLong(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeByte(byte value, String description, Map valueToString, + DataOutputStream out) throws IOException { + out.writeByte(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value, valueToString); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeShort(short value, String description, Map valueToString, + DataOutputStream out) throws IOException { + out.writeShort(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value, valueToString); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeInt(int value, String description, Map valueToString, + DataOutputStream out) throws IOException { + out.writeInt(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value, valueToString); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeString(String value, String description, + DataOutputStream out) throws IOException { + JdwpString.write(value, out); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeBoolean(boolean value, String description, + DataOutputStream out) throws IOException { + out.writeBoolean(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeChar(char value, String description, DataOutputStream out) + throws IOException { + out.writeChar(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeDouble(double value, String description, + DataOutputStream out) throws IOException { + out.writeDouble(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeFloat(float value, String description, DataOutputStream out) + throws IOException { + out.writeFloat(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeShort(short value, String description, String[] bitNames, + DataOutputStream out) throws IOException { + out.writeShort(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value, bitNames); + } + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeInt(int value, String description, String[] bitNames, + DataOutputStream out) throws IOException { + out.writeInt(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value, bitNames); + } + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public byte readByte(String description, String[] bitNames, + DataInputStream in) throws IOException { + byte result = in.readByte(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result, bitNames); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public short readShort(String description, String[] bitNames, + DataInputStream in) throws IOException { + short result = in.readShort(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result, bitNames); + } + return result; + } + + /** + * Reads Jdwp data and, if verbose is on, outputs verbose info. + * + * @return Returns value that has been read. + */ + public int readInt(String description, String[] bitNames, DataInputStream in) + throws IOException { + int result = in.readInt(); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, result, bitNames); + } + return result; + } + + /** + * Writes Jdwp data and, if verbose is on, outputs verbose info. + */ + public void writeByte(byte value, String description, String[] bitNames, + DataOutputStream out) throws IOException { + out.writeByte(value); + if (fVerboseWriter != null) { + fVerboseWriter.println(description, value, bitNames); + } + } + + /** + * @return Returns VerboseWriter where verbose info is written to, null if + * no verbose must be given. + */ + public VerboseWriter verboseWriter() { + return fVerboseWriter; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MonitorInfoImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MonitorInfoImpl.java new file mode 100644 index 0000000000..8f334ee69d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/MonitorInfoImpl.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.InvalidStackFrameException; +import com.sun.jdi.MonitorInfo; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ThreadReference; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + * @since 3.3 + */ +public class MonitorInfoImpl extends MirrorImpl implements MonitorInfo { + + private final ThreadReference fThread; + private final ObjectReference fMonitor; + private final int fDepth; + + /** constructor **/ + public MonitorInfoImpl(ThreadReference thread, int depth, + ObjectReference monitor, VirtualMachineImpl virtualMachineImpl) { + super("MonitorInfoImpl", virtualMachineImpl); //$NON-NLS-1$ + fThread = thread; + fDepth = depth; + fMonitor = monitor; + } + + /** + * @see com.sun.jdi.MonitorInfo#monitor() + */ + @Override + public ObjectReference monitor() throws InvalidStackFrameException { + return fMonitor; + } + + /** + * @see com.sun.jdi.MonitorInfo#stackDepth() + */ + @Override + public int stackDepth() throws InvalidStackFrameException { + return fDepth; + } + + /** + * @see com.sun.jdi.MonitorInfo#thread() + */ + @Override + public ThreadReference thread() throws InvalidStackFrameException { + return fThread; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ObjectReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ObjectReferenceImpl.java new file mode 100644 index 0000000000..feb9152777 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ObjectReferenceImpl.java @@ -0,0 +1,681 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InternalException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Type; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ObjectReferenceImpl extends ValueImpl implements ObjectReference { + /** JDWP Tag. */ + public static final byte tag = JdwpID.OBJECT_TAG; + + /** ObjectID of object that corresponds to this reference. */ + private final JdwpObjectID fObjectID; + /** + * Cached reference type. This value is safe for caching because the type of + * an object never changes. + */ + private ReferenceType fReferenceType; + + /** + * Creates new ObjectReferenceImpl. + */ + public ObjectReferenceImpl(VirtualMachineImpl vmImpl, JdwpObjectID objectID) { + this("ObjectReference", vmImpl, objectID); //$NON-NLS-1$ + } + + /** + * Creates new ObjectReferenceImpl. + */ + public ObjectReferenceImpl(String description, VirtualMachineImpl vmImpl, + JdwpObjectID objectID) { + super(description, vmImpl); + fObjectID = objectID; + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return Returns Jdwp Object ID. + */ + public JdwpObjectID getObjectID() { + return fObjectID; + } + + /** + * Prevents garbage collection for this object. + */ + @Override + public void disableCollection() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_DISABLE_COLLECTION, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + } finally { + handledJdwpRequest(); + } + } + + /** + * Permits garbage collection for this object. + */ + @Override + public void enableCollection() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_ENABLE_COLLECTION, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + } finally { + handledJdwpRequest(); + } + } + + /** + * Inner class used to return monitor info. + */ + private static class MonitorInfo { + ThreadReferenceImpl owner; + int entryCount; + ArrayList waiters; + } + + /** + * @return Returns monitor info. + */ + private MonitorInfo monitorInfo() throws IncompatibleThreadStateException { + if (!virtualMachine().canGetMonitorInfo()) { + throw new UnsupportedOperationException(); + } + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_MONITOR_INFO, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new IncompatibleThreadStateException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException(); + } + + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + MonitorInfo result = new MonitorInfo(); + result.owner = ThreadReferenceImpl.read(this, replyData); + result.entryCount = readInt("entry count", replyData); //$NON-NLS-1$ + int nrOfWaiters = readInt("nr of waiters", replyData); //$NON-NLS-1$ + result.waiters = new ArrayList<>(nrOfWaiters); + for (int i = 0; i < nrOfWaiters; i++) + result.waiters.add(ThreadReferenceImpl.read(this, replyData)); + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns an ThreadReference for the thread, if any, which + * currently owns this object's monitor. + */ + @Override + public ThreadReference owningThread() + throws IncompatibleThreadStateException { + return monitorInfo().owner; + } + + /** + * @return Returns the number times this object's monitor has been entered + * by the current owning thread. + */ + @Override + public int entryCount() throws IncompatibleThreadStateException { + return monitorInfo().entryCount; + } + + /** + * @return Returns a List containing a ThreadReference for each thread + * currently waiting for this object's monitor. + */ + @Override + public List waitingThreads() throws IncompatibleThreadStateException { + return monitorInfo().waiters; + } + + /** + * @return Returns the value of a given instance or static field in this + * object. + */ + @Override + public Value getValue(Field field) { + ArrayList list = new ArrayList<>(1); + list.add(field); + return getValues(list).get(field); + } + + /** + * @return Returns objects that directly reference this object. Only objects + * that are reachable for the purposes of garbage collection are + * returned. Note that an object can also be referenced in other + * ways, such as from a local variable in a stack frame, or from a + * JNI global reference. Such non-object referrers are not returned + * by this method. + * + * @since 3.3 + */ + @Override + public List referringObjects(long maxReferrers) + throws UnsupportedOperationException, IllegalArgumentException { + try { + int max = (int) maxReferrers; + if (maxReferrers >= Integer.MAX_VALUE) { + max = Integer.MAX_VALUE; + } + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + this.getObjectID().write(outData); + writeInt(max, "max referrers", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_REFERRING_OBJECTS, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_27); + case JdwpReplyPacket.ILLEGAL_ARGUMENT: + throw new IllegalArgumentException( + JDIMessages.ReferenceTypeImpl_26); + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.ObjectReferenceImpl_object_not_known); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int elements = readInt("elements", replyData); //$NON-NLS-1$ + if (max > 0 && elements > max) { + elements = max; + } + ArrayList list = new ArrayList<>(); + for (int i = 0; i < elements; i++) { + list.add((ObjectReference)ValueImpl.readWithTag(this, replyData)); + } + return list; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the value of multiple instance and/or static fields in + * this object. + */ + @Override + public Map getValues(List allFields) { + // if the field list is empty, nothing to do. + if (allFields.isEmpty()) { + return new HashMap<>(); + } + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + + /* + * Distinguish static fields from non-static fields: For static + * fields ReferenceTypeImpl.getValues() must be used. + */ + List staticFields = new ArrayList<>(); + List nonStaticFields = new ArrayList<>(); + + // Separate static and non-static fields. + int allFieldsSize = allFields.size(); + for (int i = 0; i < allFieldsSize; i++) { + FieldImpl field = (FieldImpl) allFields.get(i); + checkVM(field); + if (field.isStatic()) + staticFields.add(field); + else + nonStaticFields.add(field); + } + + // First get values for the static fields. + Map resultMap; + if (staticFields.isEmpty()) { + resultMap = new HashMap<>(); + } else { + resultMap = referenceType().getValues(staticFields); + } + + // if no non-static fields are requested, return directly the + // result. + if (nonStaticFields.isEmpty()) { + return resultMap; + } + // Then get the values for the non-static fields. + int nonStaticFieldsSize = nonStaticFields.size(); + write(this, outData); + writeInt(nonStaticFieldsSize, "size", outData); //$NON-NLS-1$ + for (int i = 0; i < nonStaticFieldsSize; i++) { + FieldImpl field = nonStaticFields.get(i); + field.write(this, outData); + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_GET_VALUES, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + if (nrOfElements != nonStaticFieldsSize) + throw new InternalError( + JDIMessages.ObjectReferenceImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1); + + for (int i = 0; i < nrOfElements; i++) { + resultMap.put(nonStaticFields.get(i), + ValueImpl.readWithTag(this, replyData)); + } + return resultMap; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fObjectID.hashCode(); + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + + return object != null + && object.getClass().equals(this.getClass()) + && fObjectID.equals(((ObjectReferenceImpl) object).fObjectID) + && virtualMachine().equals( + ((MirrorImpl) object).virtualMachine()); + } + + /** + * @return Returns Jdwp version of given options. + */ + private int optionsToJdwpOptions(int options) { + int jdwpOptions = 0; + if ((options & INVOKE_SINGLE_THREADED) != 0) { + jdwpOptions |= MethodImpl.INVOKE_SINGLE_THREADED_JDWP; + } + if ((options & INVOKE_NONVIRTUAL) != 0) { + jdwpOptions |= MethodImpl.INVOKE_NONVIRTUAL_JDWP; + } + return jdwpOptions; + } + + /** + * Invokes the specified static Method in the target VM. + * + * @return Returns a Value mirror of the invoked method's return value. + */ + @Override + public Value invokeMethod(ThreadReference thread, Method method, List arguments, int options) throws InvalidTypeException, + ClassNotLoadedException, IncompatibleThreadStateException, + InvocationException { + checkVM(thread); + checkVM(method); + ThreadReferenceImpl threadImpl = (ThreadReferenceImpl) thread; + MethodImpl methodImpl = (MethodImpl) method; + + // Perform some checks for IllegalArgumentException. + if (!isAValidMethod(method)) + throw new IllegalArgumentException( + JDIMessages.ObjectReferenceImpl_Class_does_not_contain_given_method_2); + if (method.argumentTypeNames().size() != arguments.size()) + throw new IllegalArgumentException( + JDIMessages.ObjectReferenceImpl_Number_of_arguments_doesn__t_match_3); + if (method.isConstructor() || method.isStaticInitializer()) + throw new IllegalArgumentException( + JDIMessages.ObjectReferenceImpl_Method_is_constructor_or_intitializer_4); + if ((options & INVOKE_NONVIRTUAL) != 0 && method.isAbstract()) + throw new IllegalArgumentException( + JDIMessages.ObjectReferenceImpl_Method_is_abstract_and_can_therefore_not_be_invoked_nonvirtual_5); + + // check the type and the vm of the argument, convert the value if + // needed. + List checkedArguments = ValueImpl.checkValues(arguments, method.argumentTypes(), virtualMachineImpl()); + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + threadImpl.write(this, outData); + ((ReferenceTypeImpl) referenceType()).write(this, outData); + methodImpl.write(this, outData); + + writeInt(checkedArguments.size(), "size", outData); //$NON-NLS-1$ + Iterator iter = checkedArguments.iterator(); + while (iter.hasNext()) { + ValueImpl elt = (ValueImpl) iter.next(); + if (elt != null) { + elt.writeWithTag(this, outData); + } else { + ValueImpl.writeNullWithTag(this, outData); + } + } + + writeInt(optionsToJdwpOptions(options), + "options", MethodImpl.getInvokeOptions(), outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_INVOKE_METHOD, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException( + JDIMessages.ObjectReferenceImpl_One_of_the_arguments_of_ObjectReference_invokeMethod___6); + case JdwpReplyPacket.INVALID_THREAD: + throw new IncompatibleThreadStateException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException(); + case JdwpReplyPacket.INVALID_TYPESTATE: + throw new IncompatibleThreadStateException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + ValueImpl value = ValueImpl.readWithTag(this, replyData); + ObjectReferenceImpl exception = ObjectReferenceImpl + .readObjectRefWithTag(this, replyData); + if (exception != null) + throw new InvocationException(exception); + return value; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + private boolean isAValidMethod(Method method) { + ReferenceType refType = referenceType(); + if (refType instanceof ArrayType) { + // if the object is an array, check if the method is declared in + // java.lang.Object + return "java.lang.Object".equals(method.declaringType().name()); //$NON-NLS-1$ + } + return refType.allMethods().contains(method); + } + + /** + * @return Returns if this object has been garbage collected in the target + * VM. + */ + @Override + public boolean isCollected() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_IS_COLLECTED, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_OBJECT: + return true; + case JdwpReplyPacket.NOT_IMPLEMENTED: + // Workaround for problem in J2ME WTK (wireless toolkit) + // @see Bug 12966 + try { + referenceType(); + } catch (ObjectCollectedException e) { + return true; + } + return false; + default: + defaultReplyErrorHandler(replyPacket.errorCode()); + break; + } + DataInputStream replyData = replyPacket.dataInStream(); + boolean result = readBoolean("is collected", replyData); //$NON-NLS-1$ + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return false; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the ReferenceType that mirrors the type of this object. + */ + @Override + public ReferenceType referenceType() { + if (fReferenceType != null) { + return fReferenceType; + } + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_REFERENCE_TYPE, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fReferenceType = ReferenceTypeImpl.readWithTypeTag(this, replyData); + return fReferenceType; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the Type that mirrors the type of this object. + */ + @Override + public Type type() { + return referenceType(); + } + + /** + * Sets the value of a given instance or static field in this object. + */ + @Override + public void setValue(Field field, Value value) throws InvalidTypeException, + ClassNotLoadedException { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + writeInt(1, "size", outData); // We only set one field //$NON-NLS-1$ + checkVM(field); + ((FieldImpl) field).write(this, outData); + + // check the type and the vm of the value. Convert the value if + // needed + ValueImpl checkedValue = ValueImpl.checkValue(value, field.type(), + virtualMachineImpl()); + + if (checkedValue != null) { + checkedValue.write(this, outData); + } else { + ValueImpl.writeNull(this, outData); + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.OR_SET_VALUES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException(referenceType().name()); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns a unique identifier for this ObjectReference. + */ + @Override + public long uniqueID() { + return fObjectID.value(); + } + + /** + * @return Returns string with value of ID. + */ + public String idString() { + return "(id=" + fObjectID + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return type().toString() + " " + idString(); //$NON-NLS-1$ + } catch (ObjectCollectedException e) { + return JDIMessages.ObjectReferenceImpl__Garbage_Collected__ObjectReference__8 + + idString(); + } catch (Exception e) { + return fDescription; + } + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ObjectReferenceImpl readObjectRefWithoutTag( + MirrorImpl target, DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpObjectID ID = new JdwpObjectID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("objectReference", ID.value()); //$NON-NLS-1$ + + if (ID.isNull()) + return null; + + ObjectReferenceImpl mirror = new ObjectReferenceImpl(vmImpl, ID); + return mirror; + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ObjectReferenceImpl readObjectRefWithTag(MirrorImpl target, + DataInputStream in) throws IOException { + byte objectTag = target.readByte("object tag", JdwpID.tagMap(), in); //$NON-NLS-1$ + switch (objectTag) { + case 0: + return null; + case ObjectReferenceImpl.tag: + return ObjectReferenceImpl.readObjectRefWithoutTag(target, in); + case ArrayReferenceImpl.tag: + return ArrayReferenceImpl.read(target, in); + case ClassLoaderReferenceImpl.tag: + return ClassLoaderReferenceImpl.read(target, in); + case ClassObjectReferenceImpl.tag: + return ClassObjectReferenceImpl.read(target, in); + case StringReferenceImpl.tag: + return StringReferenceImpl.read(target, in); + case ThreadGroupReferenceImpl.tag: + return ThreadGroupReferenceImpl.read(target, in); + case ThreadReferenceImpl.tag: + return ThreadReferenceImpl.read(target, in); + } + throw new InternalException( + JDIMessages.ObjectReferenceImpl_Invalid_ObjectID_tag_encountered___9 + + objectTag); + } + + /** + * Writes JDWP representation without tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + fObjectID.write(out); + if (target.fVerboseWriter != null) + target.fVerboseWriter.println("objectReference", fObjectID.value()); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/PrimitiveTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/PrimitiveTypeImpl.java new file mode 100644 index 0000000000..8733bf3ada --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/PrimitiveTypeImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.PrimitiveType; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class PrimitiveTypeImpl extends TypeImpl implements + PrimitiveType { + /** + * Creates new instance. + */ + public PrimitiveTypeImpl(String description, VirtualMachineImpl vmImpl, + String name, String signature) { + super(description, vmImpl, name, signature); + } + + /** + * Creates new instance based on primitive signature. + */ + public static PrimitiveTypeImpl create(VirtualMachineImpl vmImpl, + String signature) { + // Notice that Primitive Types are not stored or cached because they + // don't 'remember' any information. + + // See JNI 1.1 Specification, Table 3-2 Java VM Type Signatures. + switch (signature.charAt(0)) { + case 'Z': + return new BooleanTypeImpl(vmImpl); + case 'B': + return new ByteTypeImpl(vmImpl); + case 'C': + return new CharTypeImpl(vmImpl); + case 'S': + return new ShortTypeImpl(vmImpl); + case 'I': + return new IntegerTypeImpl(vmImpl); + case 'J': + return new LongTypeImpl(vmImpl); + case 'F': + return new FloatTypeImpl(vmImpl); + case 'D': + return new DoubleTypeImpl(vmImpl); + } + throw new InternalError( + JDIMessages.PrimitiveTypeImpl_Invalid_primitive_signature____1 + + signature + JDIMessages.PrimitiveTypeImpl___2); // + } + + /** + * @return primitive type tag. + */ + public abstract byte tag(); + + /** + * @return Returns modifier bits. + */ + @Override + public int modifiers() { + throw new InternalError( + JDIMessages.PrimitiveTypeImpl_A_PrimitiveType_does_not_have_modifiers_3); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return obj instanceof PrimitiveTypeImpl + && tag() == ((PrimitiveTypeImpl) obj).tag() + && virtualMachine().equals( + ((PrimitiveTypeImpl) obj).virtualMachine()); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/PrimitiveValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/PrimitiveValueImpl.java new file mode 100644 index 0000000000..447bfcc276 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/PrimitiveValueImpl.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import com.sun.jdi.InternalException; +import com.sun.jdi.PrimitiveType; +import com.sun.jdi.PrimitiveValue; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class PrimitiveValueImpl extends ValueImpl implements PrimitiveValue { + /** Primitive value in wrapper. */ + Object fValue; + + /** + * Creates new ValueImpl. + */ + public PrimitiveValueImpl(String description, VirtualMachineImpl vmImpl, + Object value) { + super(description, vmImpl); + fValue = value; + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public boolean booleanValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue(); + else if (fValue instanceof Character) + return ((Character) fValue).charValue() != 0; + else + return ((Number) fValue).doubleValue() != 0; + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public char charValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (char) 1 : (char) 0; + else if (fValue instanceof Character) + return ((Character) fValue).charValue(); + else + return (char) ((Number) fValue).intValue(); + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public byte byteValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (byte) 1 : (byte) 0; + else if (fValue instanceof Character) + return (byte) ((Character) fValue).charValue(); + else + return ((Number) fValue).byteValue(); + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public double doubleValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (double) 1 : (double) 0; + else if (fValue instanceof Character) + return ((Character) fValue).charValue(); + else + return ((Number) fValue).doubleValue(); + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public float floatValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (float) 1 : (float) 0; + else if (fValue instanceof Character) + return ((Character) fValue).charValue(); + else + return ((Number) fValue).floatValue(); + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public int intValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (int) 1 : (int) 0; + else if (fValue instanceof Character) + return ((Character) fValue).charValue(); + else + return ((Number) fValue).intValue(); + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public long longValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (long) 1 : (long) 0; + else if (fValue instanceof Character) + return ((Character) fValue).charValue(); + else + return ((Number) fValue).longValue(); + } + + /** + * @return Returns Primitive Value converted to required type. + */ + @Override + public short shortValue() { + if (fValue instanceof Boolean) + return ((Boolean) fValue).booleanValue() ? (short) 1 : (short) 0; + else if (fValue instanceof Character) + return (short) ((Character) fValue).charValue(); + else + return ((Number) fValue).shortValue(); + } + + /** + * @return Returns true if two values are equal. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null && object.getClass().equals(this.getClass()) + && fValue.equals(((PrimitiveValueImpl) object).fValue); + } + + /** + * @return Returns a has code for this object. + * @see java.lang.Object#hashCode + */ + @Override + public int hashCode() { + return fValue.hashCode(); + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + return fValue.toString(); + } + + /** + * Writes value without value tag. + */ + @Override + public abstract void write(MirrorImpl target, DataOutputStream out) + throws IOException; + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static PrimitiveValueImpl readWithoutTag(MirrorImpl target, + PrimitiveType type, DataInputStream in) throws IOException { + switch (((PrimitiveTypeImpl) type).tag()) { + case 0: + return null; + case BooleanValueImpl.tag: + return BooleanValueImpl.read(target, in); + case ByteValueImpl.tag: + return ByteValueImpl.read(target, in); + case CharValueImpl.tag: + return CharValueImpl.read(target, in); + case DoubleValueImpl.tag: + return DoubleValueImpl.read(target, in); + case FloatValueImpl.tag: + return FloatValueImpl.read(target, in); + case IntegerValueImpl.tag: + return IntegerValueImpl.read(target, in); + case LongValueImpl.tag: + return LongValueImpl.read(target, in); + case ShortValueImpl.tag: + return ShortValueImpl.read(target, in); + } + throw new InternalException( + JDIMessages.PrimitiveValueImpl_Invalid_Primitive_Value_tag_encountered___2 + + type); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java new file mode 100644 index 0000000000..c46772b338 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java @@ -0,0 +1,2491 @@ +/******************************************************************************* + * Copyright (c) 2000, 2023 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Yavor Boyadzhiev - Bug 162399 + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpFieldID; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpMethodID; +import org.eclipse.jdi.internal.jdwp.JdwpReferenceTypeID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassLoaderReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.ClassObjectReference; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.InternalException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.NativeMethodException; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class ReferenceTypeImpl extends TypeImpl implements + ReferenceType, org.eclipse.jdi.hcr.ReferenceType { + + /** ClassStatus Constants. */ + public static final int JDWP_CLASS_STATUS_VERIFIED = 1; + public static final int JDWP_CLASS_STATUS_PREPARED = 2; + public static final int JDWP_CLASS_STATUS_INITIALIZED = 4; + public static final int JDWP_CLASS_STATUS_ERROR = 8; + + /** Mapping of command codes to strings. */ + private static String[] fgClassStatusStrings = null; + + /** + * Represent the data about one file info contained in one stratum in the + * SMAP. + */ + protected static class FileInfo { + + /** + * The id. + */ + protected int fFileId; + + /** + * The name of the source file. + */ + protected String fFileName; + + /** + * The path of the source file. + */ + protected String fAbsoluteFileName; + + /** + * Map line number in the input source file -> list of [start line in + * the output source file, range in the output source file]. (Integer -> + * List of int[2]). + */ + private final HashMap> fLineInfo; + + /** + * FileInfo constructor. + * + * @param fileId + * the id. + * @param fileName + * the name of the source file. + * @param absoluteFileName + * the path of the source file (can be null). + */ + public FileInfo(int fileId, String fileName, String absoluteFileName) { + fFileId = fileId; + fFileName = fileName; + fAbsoluteFileName = absoluteFileName; + fLineInfo = new HashMap<>(); + } + + /** + * Add information about the mapping of one line. Associate a line in + * the input source file to a snippet of code in the output source file. + * + * @param inputLine + * the line number in the input source file. + * @param outputStartLine + * the number of the first line of the corresponding snippet + * in the output source file. + * @param outputLineRange + * the size of the corresponding snippet in the output source + * file. + */ + public void addLineInfo(int inputLine, int outputStartLine, + int outputLineRange) { + Integer key = Integer.valueOf(inputLine); + List outputLines = fLineInfo.get(key); + if (outputLines == null) { + outputLines = new ArrayList<>(); + fLineInfo.put(key, outputLines); + } + outputLines.add(new int[] { outputStartLine, outputLineRange }); + } + + /** + * Return a list of line information about the code in the output source + * file associated to the given line in the input source file. + * + * @param lineNumber + * the line number in the input source file. + * @return a List of int[2]. + */ + public List getOutputLinesForLine(int lineNumber) { + List list = new ArrayList<>(); + List outputLines = fLineInfo.get(Integer.valueOf(lineNumber)); + if (outputLines != null) { + for (int[] info : outputLines) { + int outputLineNumber = info[0]; + int length = info[1]; + if (length == 0) { + length = length + 1; + } + for (int i = 0; i < length; i++) { + list.add(Integer.valueOf(outputLineNumber++)); + } + } + } + return list; + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object object) { + if (!(object instanceof FileInfo)) { + return false; + } + return fFileId == ((FileInfo) object).fFileId; + } + + } + + /** + * Represent the information contained in the SMAP about one stratum. + */ + protected static class Stratum { + + /** + * The id of this stratum. + */ + private final String fId; + + /** + * The file info data associated to this stratum. + */ + private final List fFileInfos; + + /** + * Id of the primary file for this stratum. + */ + private int fPrimaryFileId; + + /** + * Map line number in the output source file -> list of line numbers in + * the input source file. (Integer -> List of Integer) + */ + private final HashMap> fOutputLineToInputLine; + + /** + * Stratum constructor. + * + * @param id + * The id of this stratum. + */ + public Stratum(String id) { + fId = id; + fFileInfos = new ArrayList<>(); + fOutputLineToInputLine = new HashMap<>(); + fPrimaryFileId = -1; + } + + /** + * Add a file info to this stratum. + * + * @param fileId + * the id. + * @param fileName + * the name of the source file. + */ + public void addFileInfo(int fileId, String fileName) + throws AbsentInformationException { + addFileInfo(fileId, fileName, null); + } + + /** + * Add a file info to this stratum. + * + * @param fileId + * the id. + * @param fileName + * the name of the source file. + * @param absoluteFileName + * the path of the source file. + */ + public void addFileInfo(int fileId, String fileName, + String absoluteFileName) throws AbsentInformationException { + if (fPrimaryFileId == -1) { + fPrimaryFileId = fileId; + } + FileInfo fileInfo = new FileInfo(fileId, fileName, absoluteFileName); + if (fFileInfos.contains(fileInfo)) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.ReferenceTypeImpl_28, new String[] { + Integer.toString(fileId), fId })); + } + fFileInfos.add(fileInfo); + } + + /** + * Add line mapping information. + * + * @param inputStartLine + * number of the first line in the input source file. + * @param lineFileId + * id of the input source file. + * @param repeatCount + * number of iterations. + * @param outputStartLine + * number of the first line in the output source file. + * @param outputLineIncrement + * number of line to increment at each iteration. + * @throws AbsentInformationException + */ + public void addLineInfo(int inputStartLine, int lineFileId, + int repeatCount, int outputStartLine, int outputLineIncrement) + throws AbsentInformationException { + FileInfo fileInfo = null; + // get the FileInfo object + for (FileInfo element : fFileInfos) { + if (element.fFileId == lineFileId) { + fileInfo = element; + } + } + if (fileInfo == null) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.ReferenceTypeImpl_29, + new String[] { Integer.toString(lineFileId) })); + } + // add the data to the different hash maps. + for (int i = 0; i < repeatCount; i++, inputStartLine++) { + fileInfo.addLineInfo(inputStartLine, outputStartLine, + outputLineIncrement); + if (outputLineIncrement == 0) { + // see bug 40022 + addLineInfoToMap(inputStartLine, lineFileId, + outputStartLine); + } else { + for (int j = 0; j < outputLineIncrement; j++, outputStartLine++) { + addLineInfoToMap(inputStartLine, lineFileId, + outputStartLine); + } + } + } + } + + /** + * Add the data to the map. + */ + private void addLineInfoToMap(int inputStartLine, int lineFileId, + int outputStartLine) { + Integer key = Integer.valueOf(outputStartLine); + List inputLines = fOutputLineToInputLine.get(key); + if (inputLines == null) { + inputLines = new ArrayList<>(); + fOutputLineToInputLine.put(key, inputLines); + } + inputLines.add(new int[] { lineFileId, inputStartLine }); + } + + /** + * Return the FileInfo object for the specified source name. Return + * null if the specified name is the source name of no file + * info. + * + * @param sourceName + * the source name to search. + */ + public FileInfo getFileInfo(String sourceName) { + for (FileInfo fileInfo : fFileInfos) { + if (fileInfo.fFileName.equals(sourceName)) { + return fileInfo; + } + } + return null; + } + + /** + * @param outputLineNumber + * @return + */ + public List getInputLineInfos(int outputLineNumber) { + return fOutputLineToInputLine.get(Integer.valueOf(outputLineNumber)); + } + + } + + /** ReferenceTypeID that corresponds to this reference. */ + private final JdwpReferenceTypeID fReferenceTypeID; + + /** The following are the stored results of JDWP calls. */ + protected List fInterfaces = null; + private List fMethods = null; + private Map fMethodTable = null; + private List fFields = null; + private List fAllMethods = null; + private List fVisibleMethods = null; + private List fAllFields = null; + private List fVisibleFields = null; + private List fAllInterfaces = null; + private Map>> fStratumAllLineLocations = null; + private String fSourceName = null; + private int fModifierBits = -1; + private ClassLoaderReferenceImpl fClassLoader = null; + private ClassObjectReferenceImpl fClassObject = null; + + private String fGenericSignature; // 1.5 addition + private boolean fGenericSignatureKnown; // 1.5 addition + + private boolean fGotClassFileVersion = false; // HCR addition. + private int fClassFileVersion; // HCR addition. + private boolean fIsHCREligible; // HCR addition. + private boolean fIsVersionKnown; // HCR addition. + + private boolean fSourceDebugExtensionAvailable = true; // JSR-045 addition + + /** + * The default stratum id. + */ + private String fDefaultStratumId; // JSR-045 addition + + /** + * A map of the defined strata. Map stratum id -> Stratum object. (String -> + * Stratum). + */ + private Map fStrata; // JSR-045 addition + + /** + * The source map string returned by the VM. + */ + private String fSmap; // JSR-045 addition + + /** + * Creates new instance. + */ + protected ReferenceTypeImpl(String description, VirtualMachineImpl vmImpl, + JdwpReferenceTypeID referenceTypeID) { + super(description, vmImpl); + fReferenceTypeID = referenceTypeID; + } + + /** + * Creates new instance. + */ + protected ReferenceTypeImpl(String description, VirtualMachineImpl vmImpl, + JdwpReferenceTypeID referenceTypeID, String signature, + String genericSignature) { + super(description, vmImpl); + fReferenceTypeID = referenceTypeID; + setSignature(signature); + setGenericSignature(genericSignature); + } + + /** + * @return Returns type tag. + */ + public abstract byte typeTag(); + + /** + * Flushes all stored Jdwp results. + */ + public void flushStoredJdwpResults() { + // Flush Methods. + if (fMethods != null) { + for (Method method : fMethods) { + ((MethodImpl)method).flushStoredJdwpResults(); + } + fMethods = null; + fMethodTable = null; + } + + // Flush Fields. + if (fFields != null) { + for (Field field : fFields) { + ((FieldImpl)field).flushStoredJdwpResults(); + } + fFields = null; + } + + fInterfaces = null; + fAllMethods = null; + fVisibleMethods = null; + fAllFields = null; + fVisibleFields = null; + fAllInterfaces = null; + fStratumAllLineLocations = null; + fSourceName = null; + fModifierBits = -1; + fClassLoader = null; + fClassObject = null; + fGotClassFileVersion = false; + // java 1.5 + fGenericSignature = null; + fGenericSignatureKnown = false; + + // JSR-045 + fSourceDebugExtensionAvailable = true; + fDefaultStratumId = null; + fStrata = null; + fSmap = null; + + // The following cached results are stored higher up in the class + // hierarchy. + fSignature = null; + fSourceName = null; + } + + /** + * @return Returns the interfaces declared as implemented by this class. + * Interfaces indirectly implemented (extended by the implemented + * interface or implemented by a superclass) are not included. + */ + public List allInterfaces() { + if (fAllInterfaces != null) { + return fAllInterfaces; + } + + /* + * Recursion: The interfaces that it directly implements; All interfaces + * that are implemented by its interfaces; If it is a class, all + * interfaces that are implemented by its superclass. + */ + // The interfaces are maintained in a set, to avoid duplicates. + // The interfaces of its own (own interfaces() command) are first + // inserted. + HashSet allInterfacesSet = new HashSet<>(interfaces()); + + // All interfaces of the interfaces it implements. + Iterator interfaces = interfaces().iterator(); + InterfaceType inter; + while (interfaces.hasNext()) { + inter = interfaces.next(); + allInterfacesSet.addAll(((InterfaceTypeImpl)inter).allInterfaces()); + } + + // If it is a class, all interfaces of it's superclass. + if (this instanceof ClassType) { + ClassType superclass = ((ClassType) this).superclass(); + if (superclass != null) { + allInterfacesSet.addAll(superclass.allInterfaces()); + } + } + + fAllInterfaces = new ArrayList<>(allInterfacesSet); + return fAllInterfaces; + } + + /** + * @return Returns JDWP Reference ID. + */ + public JdwpReferenceTypeID getRefTypeID() { + return fReferenceTypeID; + } + + /** + * @return Returns modifier bits. + */ + @Override + public int modifiers() { + if (fModifierBits != -1) { + return fModifierBits; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_MODIFIERS, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fModifierBits = readInt( + "modifiers", AccessibleImpl.getModifierStrings(), replyData); //$NON-NLS-1$ + return fModifierBits; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * Add methods to a set of methods if they are not overridden, add new + * names+signature combinations to set of names+signature combinations. + */ + private void addVisibleMethods(List inheritedMethods, Set nameAndSignatures, List resultMethods) { + Iterator iter = inheritedMethods.iterator(); + Method inheritedMethod; + while (iter.hasNext()) { + inheritedMethod = iter.next(); + if (!nameAndSignatures.contains(inheritedMethod.name() + + inheritedMethod.signature())) { + resultMethods.add(inheritedMethod); + } + } + } + + /** + * @return Returns a list containing each visible and unambiguous Method in + * this type. + */ + @Override + public List visibleMethods() { + if (fVisibleMethods != null) { + return fVisibleMethods; + } + + /* + * Recursion: The methods of its own (own methods() command); All + * methods of the interfaces it implements; If it is a class, all + * methods of it's superclass. + */ + // The name+signature combinations of methods are maintained in a set, + // to avoid including methods that have been overridden. + Set namesAndSignatures = new HashSet<>(); + List visibleMethods = new ArrayList<>(); + + // The methods of its own (own methods() command). + for (Method m : methods()) { + MethodImpl method = (MethodImpl) m; + namesAndSignatures.add(method.name() + method.signature()); + visibleMethods.add(method); + } + + // All methods of the interfaces it implements. + Iterator interfaces = interfaces().iterator(); + InterfaceType inter; + while (interfaces.hasNext()) { + inter = interfaces.next(); + addVisibleMethods(inter.visibleMethods(), namesAndSignatures, + visibleMethods); + } + + // If it is a class, all methods of it's superclass. + if (this instanceof ClassType) { + ClassType superclass = ((ClassType) this).superclass(); + if (superclass != null) { + addVisibleMethods(superclass.visibleMethods(), + namesAndSignatures, visibleMethods); + } + } + + fVisibleMethods = visibleMethods; + return fVisibleMethods; + } + + /** + * @return Returns a list containing each Method declared in this type, and + * its super-classes, implemented interfaces, and/or + * super-interfaces. + */ + @Override + public List allMethods() { + if (fAllMethods != null) { + return fAllMethods; + } + + /* + * Recursion: The methods of its own (own methods() command); All + * methods of the interfaces it implements; If it is a class, all + * methods of it's superclass. + */ + // The name+signature combinations of methods are maintained in a set. + HashSet resultSet = new HashSet<>(); + + // The methods of its own (own methods() command). + resultSet.addAll(methods()); + + // All methods of the interfaces it implements. + Iterator interfaces = interfaces().iterator(); + InterfaceType inter; + while (interfaces.hasNext()) { + inter = interfaces.next(); + resultSet.addAll(inter.allMethods()); + } + + // If it is a class, all methods of it's superclass. + if (this instanceof ClassType) { + ClassType superclass = ((ClassType) this).superclass(); + if (superclass != null) { + resultSet.addAll(superclass.allMethods()); + } + } + + fAllMethods = new ArrayList<>(resultSet); + return fAllMethods; + } + + /** + * @return Returns the interfaces declared as implemented by this class. + * Interfaces indirectly implemented (extended by the implemented + * interface or implemented by a superclass) are not included. + */ + public List interfaces() { + if (fInterfaces != null) { + return fInterfaces; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_INTERFACES, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.NOT_FOUND: + // Workaround for problem in J2ME WTK (wireless toolkit) + // @see Bug 12966 + return Collections.EMPTY_LIST; + default: + defaultReplyErrorHandler(replyPacket.errorCode()); + } + DataInputStream replyData = replyPacket.dataInStream(); + List elements = new ArrayList<>(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + for (int i = 0; i < nrOfElements; i++) { + InterfaceTypeImpl ref = InterfaceTypeImpl.read(this, replyData); + if (ref == null) { + continue; + } + elements.add(ref); + } + fInterfaces = elements; + return elements; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Add fields to a set of fields if they are not overridden, add new field + * names to set of field names. + */ + private void addVisibleFields(List newFields, Set names, List resultFields) { + Iterator iter = newFields.iterator(); + FieldImpl field; + while (iter.hasNext()) { + field = (FieldImpl) iter.next(); + String name = field.name(); + if (!names.contains(name)) { + resultFields.add(field); + names.add(name); + } + } + } + + /** + * @return Returns a list containing each visible and unambiguous Field in + * this type. + */ + @Override + public List visibleFields() { + if (fVisibleFields != null) { + return fVisibleFields; + } + + /* + * Recursion: The fields of its own (own fields() command); All fields + * of the interfaces it implements; If it is a class, all fields of it's + * superclass. + */ + // The names of fields are maintained in a set, to avoid including + // fields that have been overridden. + HashSet fieldNames = new HashSet<>(); + + // The fields of its own (own fields() command). + List visibleFields = new ArrayList<>(); + addVisibleFields(fields(), fieldNames, visibleFields); + + // All fields of the interfaces it implements. + Iterator interfaces = interfaces().iterator(); + InterfaceType inter; + while (interfaces.hasNext()) { + inter = interfaces.next(); + addVisibleFields(inter.visibleFields(), fieldNames, visibleFields); + } + + // If it is a class, all fields of it's superclass. + if (this instanceof ClassType) { + ClassType superclass = ((ClassType) this).superclass(); + if (superclass != null) { + addVisibleFields(superclass.visibleFields(), fieldNames, + visibleFields); + } + } + + fVisibleFields = visibleFields; + return fVisibleFields; + } + + /** + * @return Returns a list containing each Field declared in this type, and + * its super-classes, implemented interfaces, and/or + * super-interfaces. + */ + @Override + public List allFields() { + if (fAllFields != null) { + return fAllFields; + } + + /* + * Recursion: The fields of its own (own fields() command); All fields + * of the interfaces it implements; If it is a class, all fields of it's + * superclass. + */ + // The names of fields are maintained in a set, to avoid including + // fields that have been inherited double. + HashSet resultSet = new HashSet<>(); + + // The fields of its own (own fields() command). + resultSet.addAll(fields()); + + // All fields of the interfaces it implements. + Iterator interfaces = interfaces().iterator(); + InterfaceType inter; + while (interfaces.hasNext()) { + inter = interfaces.next(); + resultSet.addAll(inter.allFields()); + } + + // If it is a class, all fields of it's superclass. + if (this instanceof ClassType) { + ClassType superclass = ((ClassType) this).superclass(); + if (superclass != null) { + resultSet.addAll(superclass.allFields()); + } + } + + fAllFields = new ArrayList<>(resultSet); + return fAllFields; + } + + /** + * @return Returns the class loader object which loaded the class + * corresponding to this type. + */ + @Override + public ClassLoaderReference classLoader() { + if (fClassLoader != null) { + return fClassLoader; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_CLASS_LOADER, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fClassLoader = ClassLoaderReferenceImpl.read(this, replyData); + return fClassLoader; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the class object that corresponds to this type in the + * target VM. + */ + @Override + public ClassObjectReference classObject() { + if (fClassObject != null) { + return fClassObject; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_CLASS_OBJECT, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fClassObject = ClassObjectReferenceImpl.read(this, replyData); + return fClassObject; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns status of class/interface. + */ + protected int status() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_STATUS, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int status = readInt("status", classStatusStrings(), replyData); //$NON-NLS-1$ + return status; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns true if initialization failed for this class. + */ + @Override + public boolean failedToInitialize() { + return (status() & JDWP_CLASS_STATUS_ERROR) != 0; + } + + /** + * @return Returns true if this type has been initialized. + */ + @Override + public boolean isInitialized() { + return (status() & JDWP_CLASS_STATUS_INITIALIZED) != 0; + } + + /** + * @return Returns true if this type has been prepared. + */ + @Override + public boolean isPrepared() { + return (status() & JDWP_CLASS_STATUS_PREPARED) != 0; + } + + /** + * @return Returns true if this type has been verified. + */ + @Override + public boolean isVerified() { + return (status() & JDWP_CLASS_STATUS_VERIFIED) != 0; + } + + /** + * @return Returns the visible Field with the given non-ambiguous name. + */ + @Override + public Field fieldByName(String name) { + Iterator iter = visibleFields().iterator(); + while (iter.hasNext()) { + FieldImpl field = (FieldImpl) iter.next(); + if (field.name().equals(name)) { + return field; + } + } + return null; + } + + /** + * @return Returns a list containing each Field declared in this type. + */ + @Override + public List fields() { + if (fFields != null) { + return fFields; + } + + // Note: Fields are returned in the order they occur in the class file, + // therefore their + // order in this list can be used for comparisons. + initJdwpRequest(); + try { + boolean withGenericSignature = virtualMachineImpl() + .isJdwpVersionGreaterOrEqual(1, 5); + int jdwpCommand = withGenericSignature ? JdwpCommandPacket.RT_FIELDS_WITH_GENERIC + : JdwpCommandPacket.RT_FIELDS; + JdwpReplyPacket replyPacket = requestVM(jdwpCommand, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + List elements = new ArrayList<>(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + for (int i = 0; i < nrOfElements; i++) { + FieldImpl elt = FieldImpl.readWithNameSignatureModifiers(this, + this, withGenericSignature, replyData); + if (elt == null) { + continue; + } + elements.add(elt); + } + fFields = elements; + return fFields; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns FieldImpl of a field in the reference specified by a + * given fieldID, or null if not found. + */ + public FieldImpl findField(JdwpFieldID fieldID) { + Iterator iter = fields().iterator(); + while (iter.hasNext()) { + FieldImpl field = (FieldImpl) iter.next(); + if (field.getFieldID().equals(fieldID)) { + return field; + } + } + return null; + } + + /** + * @return Returns MethodImpl of a method in the reference specified by a + * given methodID, or null if not found. + */ + public Method findMethod(JdwpMethodID methodID) { + if (methodID.value() == 0) { + return new MethodImpl(virtualMachineImpl(), this, methodID, + JDIMessages.ReferenceTypeImpl_Obsolete_method_1, + "", null, -1); //$NON-NLS-1$ + } + if (fMethodTable == null) { + // 509259 use temporary variable to workaround fMethodTable lazy initialization race + Map methodTable = new HashMap<>(); + Iterator iter = methods().iterator(); + while (iter.hasNext()) { + MethodImpl method = (MethodImpl) iter.next(); + methodTable.put(method.getMethodID(), method); + } + fMethodTable = Collections.unmodifiableMap(methodTable); + } + return fMethodTable.get(methodID); + } + + /** + * @return Returns the Value of a given static Field in this type. + */ + @Override + public Value getValue(Field field) { + ArrayList list = new ArrayList<>(1); + list.add(field); + return getValues(list).get(field); + } + + /** + * @return a Map of the requested static Field objects with their Value. + */ + @Override + public Map getValues(List fields) { + // if the field list is empty, nothing to do + if (fields.isEmpty()) { + return new HashMap<>(); + } + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + int fieldsSize = fields.size(); + write(this, outData); + writeInt(fieldsSize, "size", outData); //$NON-NLS-1$ + for (int i = 0; i < fieldsSize; i++) { + FieldImpl field = (FieldImpl) fields.get(i); + checkVM(field); + field.getFieldID().write(outData); + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_GET_VALUES, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + HashMap map = new HashMap<>(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + if (nrOfElements != fieldsSize) { + throw new InternalError( + JDIMessages.ReferenceTypeImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_3); + } + + for (int i = 0; i < nrOfElements; i++) { + map.put(fields.get(i), ValueImpl.readWithTag(this, replyData)); + } + return map; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fReferenceTypeID.hashCode(); + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null + && object.getClass().equals(this.getClass()) + && fReferenceTypeID + .equals(((ReferenceTypeImpl) object).fReferenceTypeID) + && virtualMachine().equals( + ((MirrorImpl) object).virtualMachine()); + } + + /** + * @return Returns a negative integer, zero, or a positive integer as this + * {@link ReferenceType} is less than, equal to, or greater than the specified + * {@link ReferenceType}. + */ + @Override + public int compareTo(ReferenceType type) { + if (type == null || !type.getClass().equals(this.getClass())) { + throw new ClassCastException(JDIMessages.ReferenceTypeImpl_Can__t_compare_reference_type_to_given_object_4); + } + return name().compareTo(type.name()); + } + + /** + * @return Returns true if the type was declared abstract. + */ + @Override + public boolean isAbstract() { + return (modifiers() & MODIFIER_ACC_ABSTRACT) != 0; + } + + /** + * @return Returns true if the type was declared final. + */ + @Override + public boolean isFinal() { + return (modifiers() & MODIFIER_ACC_FINAL) != 0; + } + + /** + * @return Returns true if the type was declared static. + */ + @Override + public boolean isStatic() { + return (modifiers() & MODIFIER_ACC_STATIC) != 0; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#locationsOfLine(int) + */ + @Override + public List locationsOfLine(int line) throws AbsentInformationException { + return locationsOfLine(virtualMachine().getDefaultStratum(), null, line); + } + + /** + * @return Returns a list containing each Method declared directly in this + * type. + */ + @Override + public List methods() { + // Note that ArrayReference overwrites this method by returning an empty + // list. + if (fMethods != null) { + return fMethods; + } + + // Note: Methods are returned in the order they occur in the class file, + // therefore their + // order in this list can be used for comparisons. + initJdwpRequest(); + try { + boolean withGenericSignature = virtualMachineImpl() + .isJdwpVersionGreaterOrEqual(1, 5); + int jdwpCommand = withGenericSignature ? JdwpCommandPacket.RT_METHODS_WITH_GENERIC + : JdwpCommandPacket.RT_METHODS; + JdwpReplyPacket replyPacket = requestVM(jdwpCommand, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + List elements = new ArrayList<>(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + for (int i = 0; i < nrOfElements; i++) { + MethodImpl elt = MethodImpl.readWithNameSignatureModifiers( + this, this, withGenericSignature, replyData); + if (elt == null) { + continue; + } + elements.add(elt); + } + fMethods = elements; + return fMethods; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns a List containing each visible Method that has the given + * name. + */ + @Override + public List methodsByName(String name) { + List elements = new ArrayList<>(); + Iterator iter = visibleMethods().iterator(); + while (iter.hasNext()) { + Method method = iter.next(); + if (method.name().equals(name)) { + elements.add(method); + } + } + return elements; + } + + /** + * @return Returns a List containing each visible Method that has the given + * name and signature. + */ + @Override + public List methodsByName(String name, String signature) { + List elements = new ArrayList<>(); + Iterator iter = visibleMethods().iterator(); + while (iter.hasNext()) { + MethodImpl method = (MethodImpl) iter.next(); + if (method.name().equals(name) && method.signature().equals(signature)) { + elements.add(method); + } + } + return elements; + } + + /** + * @return Returns the fully qualified name of this type. + */ + @Override + public String name() { + // Make sure that we know the signature, from which the name is derived. + if (fName == null) { + setName(signatureToName(signature())); + } + return fName; + } + + /** + * @return Returns the JNI-style signature for this type. + */ + @Override + public String signature() { + if (fSignature != null) { + return fSignature; + } + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_SIGNATURE, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + setSignature(readString("signature", replyData)); //$NON-NLS-1$ + return fSignature; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns a List containing each ReferenceType declared within this + * type. + */ + @Override + public List nestedTypes() { + // Note that the VM gives an empty reply on RT_NESTED_TYPES, therefore + // we search for the + // nested types in the loaded types. + List result = new ArrayList<>(); + Iterator itr = virtualMachineImpl().allRefTypes(); + while (itr.hasNext()) { + try { + ReferenceTypeImpl refType = (ReferenceTypeImpl) itr.next(); + String refName = refType.name(); + if (refName.length() > name().length() + && refName.startsWith(name()) + && refName.charAt(name().length()) == '$') { + result.add(refType); + } + } catch (ClassNotPreparedException e) { + continue; + } + } + return result; + } + + /** + * @return Returns an identifying name for the source corresponding to the + * declaration of this type. + */ + @Override + public String sourceName() throws AbsentInformationException { + // sourceNames list in never empty, an AbsentInformationException is + // thrown + // if the source name is not known. + return sourceNames(virtualMachine().getDefaultStratum()) + .get(0); + } + + /** + * @return Returns the CRC-32 of the given reference type, undefined if + * unknown. + */ + @Override + public int getClassFileVersion() { + virtualMachineImpl().checkHCRSupported(); + if (fGotClassFileVersion) { + return fClassFileVersion; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.HCR_GET_CLASS_VERSION, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fIsHCREligible = readBoolean("HCR eligible", replyData); //$NON-NLS-1$ + fIsVersionKnown = readBoolean("version known", replyData); //$NON-NLS-1$ + fClassFileVersion = readInt("class file version", replyData); //$NON-NLS-1$ + fGotClassFileVersion = true; + return fClassFileVersion; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns whether the CRC-32 of the given reference type is known. + */ + @Override + public boolean isVersionKnown() { + getClassFileVersion(); + return fIsVersionKnown; + } + + /** + * @return Returns whether the reference type is HCR-eligible. + */ + @Override + public boolean isHCREligible() { + getClassFileVersion(); + return fIsHCREligible; + } + + /** + * Writes JDWP representation. + */ + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + fReferenceTypeID.write(out); + if (target.fVerboseWriter != null) + { + target.fVerboseWriter.println( + "referenceType", fReferenceTypeID.value()); //$NON-NLS-1$ + } + } + + /** + * Writes representation of null referenceType. + */ + public static void writeNull(MirrorImpl target, DataOutputStream out) + throws IOException { + // create null id + JdwpReferenceTypeID ID = new JdwpReferenceTypeID( + target.virtualMachineImpl()); + ID.write(out); + if (target.fVerboseWriter != null) + { + target.fVerboseWriter.println("referenceType", ID.value()); //$NON-NLS-1$ + } + } + + /** + * Writes JDWP representation. + */ + public void writeWithTag(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeByte(typeTag(), "type tag", JdwpID.typeTagMap(), out); //$NON-NLS-1$ + write(target, out); + } + + /** + * @return Reads JDWP representation and returns new or cached instance. + */ + public static ReferenceTypeImpl readWithTypeTag(MirrorImpl target, + DataInputStream in) throws IOException { + byte typeTag = target.readByte("type tag", JdwpID.typeTagMap(), in); //$NON-NLS-1$ + switch (typeTag) { + case 0: + return null; + case ArrayTypeImpl.typeTag: + return ArrayTypeImpl.read(target, in); + case ClassTypeImpl.typeTag: + return ClassTypeImpl.read(target, in); + case InterfaceTypeImpl.typeTag: + return InterfaceTypeImpl.read(target, in); + } + throw new InternalException( + JDIMessages.ReferenceTypeImpl_Invalid_ReferenceTypeID_tag_encountered___8 + + typeTag); + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#allLineLocations() + */ + @Override + public List allLineLocations() throws AbsentInformationException { + return allLineLocations(virtualMachine().getDefaultStratum(), null); + } + + /** + * @return Reads JDWP representation and returns new or cached instance. + */ + public static ReferenceTypeImpl readWithTypeTagAndSignature( + MirrorImpl target, boolean withGenericSignature, DataInputStream in) + throws IOException { + byte typeTag = target.readByte("type tag", JdwpID.typeTagMap(), in); //$NON-NLS-1$ + switch (typeTag) { + case 0: + return null; + case ArrayTypeImpl.typeTag: + return ArrayTypeImpl.readWithSignature(target, + withGenericSignature, in); + case ClassTypeImpl.typeTag: + return ClassTypeImpl.readWithSignature(target, + withGenericSignature, in); + case InterfaceTypeImpl.typeTag: + return InterfaceTypeImpl.readWithSignature(target, + withGenericSignature, in); + } + throw new InternalException( + JDIMessages.ReferenceTypeImpl_Invalid_ReferenceTypeID_tag_encountered___8 + + typeTag); + } + + /** + * @return Returns new instance based on signature and classLoader. + * @throws ClassNotLoadedException + * when the ReferenceType has not been loaded by the specified + * class loader. + */ + public static TypeImpl create(VirtualMachineImpl vmImpl, String signature, + ClassLoaderReference classLoader) throws ClassNotLoadedException { + ReferenceTypeImpl refTypeBootstrap = null; + List classes = vmImpl.classesBySignature(signature); + ReferenceTypeImpl type; + Iterator iter = classes.iterator(); + while (iter.hasNext()) { + // First pass. Look for a class loaded by the given class loader + type = (ReferenceTypeImpl) iter.next(); + if (type.classLoader() == null) { // bootstrap classloader + if (classLoader == null) { + return type; + } + refTypeBootstrap = type; + } + if (classLoader != null && classLoader.equals(type.classLoader())) { + return type; + } + } + // If no ReferenceType is found with the specified classloader, but + // there is one with the + // bootstrap classloader, the latter is returned. + if (refTypeBootstrap != null) { + return refTypeBootstrap; + } + + List visibleTypes; + iter = classes.iterator(); + while (iter.hasNext()) { + // Second pass. Look for a class that is visible to + // the given class loader + type = (ReferenceTypeImpl) iter.next(); + visibleTypes = classLoader.visibleClasses(); + Iterator visibleIter = visibleTypes.iterator(); + while (visibleIter.hasNext()) { + if (type.equals(visibleIter.next())) { + return type; + } + } + } + + throw new ClassNotLoadedException(classSignatureToName(signature), + JDIMessages.ReferenceTypeImpl_Type_has_not_been_loaded_10); + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgClassStatusStrings != null) { + return; + } + + java.lang.reflect.Field[] fields = ReferenceTypeImpl.class + .getDeclaredFields(); + fgClassStatusStrings = new String[32]; + + for (java.lang.reflect.Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + String name = field.getName(); + if (!name.startsWith("JDWP_CLASS_STATUS_")) { //$NON-NLS-1$ + continue; + } + + name = name.substring(18); + + try { + int value = field.getInt(null); + + for (int j = 0; j < fgClassStatusStrings.length; j++) { + if ((1 << j & value) != 0) { + fgClassStatusStrings[j] = name; + break; + } + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + public static String[] classStatusStrings() { + getConstantMaps(); + return fgClassStatusStrings; + } + + /** + * @see TypeImpl#createNullValue() + */ + @Override + public Value createNullValue() { + return null; + } + + /** + * @see ReferenceType#sourceNames(String) + */ + @Override + public List sourceNames(String stratumId) throws AbsentInformationException { + List list = new ArrayList<>(); + Stratum stratum = getStratum(stratumId); + if (stratum != null) { + // return the source names defined for this stratum in the SMAP. + List fileInfos = stratum.fFileInfos; + if (fileInfos.isEmpty()) { + throw new AbsentInformationException( + JDIMessages.ReferenceTypeImpl_30); + } + for (FileInfo fileInfo : stratum.fFileInfos) { + list.add(fileInfo.fFileName); + } + return list; + } + // Java stratum + if (fSourceName == null) { + getSourceName(); + } + list.add(fSourceName); + return list; + } + + /** + * @see ReferenceType#sourcePaths(String) + */ + @Override + public List sourcePaths(String stratumId) throws AbsentInformationException { + List list = new ArrayList<>(); + Stratum stratum = getStratum(stratumId); + if (stratum != null) { + // return the source paths defined for this stratum in the SMAP. + for (FileInfo fileInfo : stratum.fFileInfos) { + String path = fileInfo.fAbsoluteFileName; + if (path == null) { + path = getPath(fileInfo.fFileName); + } + list.add(path); + } + return list; + } + // Java stratum + if (fSourceName == null) { + getSourceName(); + } + list.add(getPath(fSourceName)); + return list; + } + + /** + * @see ReferenceType#sourceDebugExtension() + */ + @Override + public String sourceDebugExtension() throws AbsentInformationException { + if (isSourceDebugExtensionAvailable()) { + return fSmap; + } + if (!virtualMachine().canGetSourceDebugExtension()) { + throw new UnsupportedOperationException("1"); //$NON-NLS-1$ + } + throw new AbsentInformationException(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#allLineLocations(java.lang.String, java.lang.String) + */ + @Override + public List allLineLocations(String stratum, String sourceName) throws AbsentInformationException { + Iterator allMethods = methods().iterator(); + if (stratum == null) { // if stratum not defined use the default stratum + stratum = defaultStratum(); + } + List allLineLocations = null; + Map> sourceNameAllLineLocations = null; + if (fStratumAllLineLocations == null) { // the stratum map doesn't + // exist, create it + fStratumAllLineLocations = new HashMap<>(); + } else { + // get the source name map + sourceNameAllLineLocations = fStratumAllLineLocations.get(stratum); + } + if (sourceNameAllLineLocations == null) { // the source name map doesn't + // exist, create it + sourceNameAllLineLocations = new HashMap<>(); + fStratumAllLineLocations.put(stratum, sourceNameAllLineLocations); + } else { + // get the line locations + allLineLocations = sourceNameAllLineLocations.get(sourceName); + } + if (allLineLocations == null) { // the line locations are not known, compute and store them + allLineLocations = new ArrayList<>(); + boolean hasLineInformation = false; + AbsentInformationException exception = null; + while (allMethods.hasNext()) { + MethodImpl method = (MethodImpl) allMethods.next(); + if (method.isAbstract() || method.isNative()) { + continue; + } + try { + allLineLocations.addAll(method.allLineLocations(stratum, sourceName)); + hasLineInformation = true; + } catch (AbsentInformationException e) { + exception = e; + } + } + if (!hasLineInformation && exception != null) { + throw exception; + } + sourceNameAllLineLocations.put(sourceName, allLineLocations); + } + return allLineLocations; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#locationsOfLine(java.lang.String, java.lang.String, int) + */ + @Override + public List locationsOfLine(String stratum, String sourceName, int lineNumber) throws AbsentInformationException { + Iterator allMethods = methods().iterator(); + List locations = new ArrayList<>(); + boolean hasLineInformation = false; + AbsentInformationException exception = null; + while (allMethods.hasNext()) { + MethodImpl method = (MethodImpl) allMethods.next(); + if (method.isAbstract() || method.isNative()) { + continue; + } + // one line in the input source can be translate in multiple lines + // in different + // methods in the output source. We need all these locations. + try { + locations.addAll(locationsOfLine(stratum, sourceName, lineNumber, method)); + hasLineInformation = true; + } catch (AbsentInformationException e) { + exception = e; + } + } + if (!hasLineInformation && exception != null) { + throw exception; + } + return locations; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#availableStrata() + */ + @Override + public List availableStrata() { + List list = new ArrayList<>(); + // The strata defined in the SMAP. + if (isSourceDebugExtensionAvailable()) { + list.addAll(fStrata.keySet()); + } + // plus the Java stratum + list.add(VirtualMachineImpl.JAVA_STRATUM_NAME); + return list; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#defaultStratum() + */ + @Override + public String defaultStratum() { + if (isSourceDebugExtensionAvailable()) { + return fDefaultStratumId; + } + // if not defined, return Java. + return VirtualMachineImpl.JAVA_STRATUM_NAME; + } + + /** + * Generate a source path from the given source name. The returned string is + * the package name of this type converted to a platform dependent path + * followed by the given source name. For example, on a Unix platform, the + * type org.my.TestJsp with the source name test.jsp would return + * "org/my/test.jsp". + */ + private String getPath(String sourceName) { + String name = name(); + int lastDotOffset = name.lastIndexOf('.'); + if (lastDotOffset == -1) { + return sourceName; + } + return name.substring(0, lastDotOffset).replace('.', File.separatorChar) + File.separatorChar + sourceName; + } + + /** + * Return the stratum object for this stratum Id. If the the specified + * stratum id is not defined for this reference type, return the stratum + * object for the default stratum. If the specified stratum id (or the + * default stratum id, if the specified stratum id is not defined) is + * Java, return null. + */ + private Stratum getStratum(String stratumId) { + if (!VirtualMachineImpl.JAVA_STRATUM_NAME.equals(stratumId) + && isSourceDebugExtensionAvailable()) { + if (stratumId == null || !fStrata.containsKey(stratumId)) { + stratumId = fDefaultStratumId; + } + if (!VirtualMachineImpl.JAVA_STRATUM_NAME.equals(stratumId)) { + return fStrata.get(stratumId); + } + } + return null; + } + + /** + * Get the source debug extension from the VM. + * + * @throws AbsentInformationException + */ + private void getSourceDebugExtension() throws AbsentInformationException { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_SOURCE_DEBUG_EXTENSION, this); + if (replyPacket.errorCode() == JdwpReplyPacket.ABSENT_INFORMATION) { + throw new AbsentInformationException( + JDIMessages.ReferenceTypeImpl_31); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fSmap = readString(JDIMessages.ReferenceTypeImpl_32, replyData); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + // TODO: remove the workaround when the J9SC20030415 bug is fixed (see + // bug 96485 of the vendor bug system). + // Workaround to a J9SC bug. It returns an empty string instead of a + // ABSENT_INFORMATION + // error if the source debug extension is not available. + if ("".equals(fSmap)) { //$NON-NLS-1$ + throw new AbsentInformationException( + JDIMessages.ReferenceTypeImpl_31); + } + // parse the source map. + fStrata = new HashMap<>(); + SourceDebugExtensionParser.parse(fSmap, this); + } + + /** + * Get the name of the Java source file from the VM. + * + * @throws AbsentInformationException + */ + private void getSourceName() throws AbsentInformationException { + if (fSourceName != null || isSourceDebugExtensionAvailable()) { + return; + } + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_SOURCE_FILE, this); + if (replyPacket.errorCode() == JdwpReplyPacket.ABSENT_INFORMATION) { + throw new AbsentInformationException( + JDIMessages.ReferenceTypeImpl_Source_name_is_not_known_7); + } + + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + fSourceName = readString("source name", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * Check in the source debug extension is available. To call before doing + * operations which need data from the SMAP. Return false if + * the source debug extension is not available for any reason. + * true indicates that the source debug extension is available + * and the information has been parsed and stored in the maps and lists. + */ + private synchronized boolean isSourceDebugExtensionAvailable() { + if (!fSourceDebugExtensionAvailable) { + return false; + } + if (!virtualMachine().canGetSourceDebugExtension()) { + fSourceDebugExtensionAvailable = false; + return false; + } + if (fSmap == null) { + try { + getSourceDebugExtension(); + } catch (AbsentInformationException e) { + fSourceDebugExtensionAvailable = false; + return false; + } + } + return true; + } + + /** + * Set the output file name, i.e. the .java file used to generate the + * bytecode. + */ + protected void setOutputFileName(String outputFileName) { + fSourceName = outputFileName; + } + + /** + * Set the default stratum. This stratum will be used for the method on + * strata related data, but with no stratum parameter. + */ + protected void setDefaultStratumId(String defaultStratumId) { + fDefaultStratumId = defaultStratumId; + } + + /** + * Add a new stratum to this type. + */ + protected void addStratum(Stratum stratum) { + fStrata.put(stratum.fId, stratum); + } + + /** + * Return the name of the input source file of which the given code index is + * part of the translation, for this stratum. If the code at the given index + * is not a part of the translation of the given stratum code, return the + * name of the primary input source file. + * + * @param codeIndex + * the index of the code. + * @param method + * the method where is the code. + * @param stratumId + */ + protected String sourceName(long codeIndex, MethodImpl method, + String stratumId) throws AbsentInformationException { + Stratum stratum = getStratum(stratumId); + if (stratum != null) { + FileInfo fileInfo = fileInfo(codeIndex, method, stratum); + if (fileInfo != null) { + return fileInfo.fFileName; + } + } + // Java stratum + if (fSourceName == null) { + getSourceName(); + } + return fSourceName; + } + + /** + * Return the FileInfo object of the input source file of which the given + * code index is part of the translation, for this stratum. If the code at + * the given index is not a part of the translation of the given stratum + * code, return the FileInfo of the primary input source file. + * + * @param codeIndex + * the index of the code. + * @param method + * the method where is the code. + * @param stratum + */ + private FileInfo fileInfo(long codeIndex, MethodImpl method, Stratum stratum) { + int fileId = stratum.fPrimaryFileId; + if (stratum.fFileInfos.size() > 1) { + List lineInfos = null; + try { + lineInfos = lineInfos(codeIndex, method, stratum); + } catch (AbsentInformationException e) { + // nothing to do, use the primary file id. + } + if (lineInfos != null) { + fileId = lineInfos.get(0)[0]; + } + } + for (FileInfo fileInfo : stratum.fFileInfos) { + if (fileInfo.fFileId == fileId) { + return fileInfo; + } + } + // should never return null + return null; + } + + /** + * Return the list of line number in the input files of the stratum + * associated with the code at the given address. + * + * @param codeIndex + * the index of the code. + * @param method + * the method where is the code. + * @param stratum + * @return List of int[2]: [fileId, inputLineNumber] + */ + private List lineInfos(long codeIndex, MethodImpl method, Stratum stratum) throws AbsentInformationException { + int outputLineNumber = -1; + try { + outputLineNumber = method.javaStratumLineNumber(codeIndex); + } catch (NativeMethodException e) { // Occurs in SUN VM. + return null; + } + if (outputLineNumber != -1) { + return stratum.getInputLineInfos(outputLineNumber); + } + return null; + } + + /** + * Return the path of the input source file of which the given code index is + * part of the translation, for this stratum. If the code at the given index + * is not a part of the translation of the given stratum code, return the + * path of the primary input source file. + * + * @param codeIndex + * the index of the code. + * @param method + * the method where is the code. + * @param stratumId + */ + protected String sourcePath(long codeIndex, MethodImpl method, + String stratumId) throws AbsentInformationException { + Stratum stratum = getStratum(stratumId); + if (stratum != null) { + FileInfo fileInfo = fileInfo(codeIndex, method, stratum); + if (fileInfo != null) { + String path = fileInfo.fAbsoluteFileName; + if (path == null) { + return getPath(fileInfo.fFileName); + } + return path; + } + } + // Java stratum + if (fSourceName == null) { + getSourceName(); + } + return getPath(fSourceName); + } + + /** + * Return the number of the line of which the given code index is part of + * the translation, for this stratum. + * + * @param codeIndex + * the index of the code. + * @param method + * the method where is the code. + * @param stratumId + */ + protected int lineNumber(long codeIndex, MethodImpl method, String stratumId) { + Stratum stratum = getStratum(stratumId); + try { + if (stratum != null) { + List lineInfos = lineInfos(codeIndex, method, stratum); + if (lineInfos != null) { + return lineInfos.get(0)[1]; + } + return LocationImpl.LINE_NR_NOT_AVAILABLE; + } + // Java stratum + try { + return method.javaStratumLineNumber(codeIndex); + } catch (NativeMethodException e) { // Occurs in SUN VM. + return LocationImpl.LINE_NR_NOT_AVAILABLE; + } + } catch (AbsentInformationException e) { + return LocationImpl.LINE_NR_NOT_AVAILABLE; + } + } + + /** + * Return the location which are part of the translation of the given line, + * in the given stratum in the source file with the given source name. If + * sourceName is null, return the locations for all source file + * in the given stratum. The returned location are in the given method. + * + * @param stratumId + * the stratum id. + * @param sourceName + * the name of the source file. + * @param lineNumber + * the number of the line. + * @param method + * @throws AbsentInformationException + * if the specified sourceName is not valid. + */ + public List locationsOfLine(String stratumId, String sourceName, int lineNumber, MethodImpl method) throws AbsentInformationException { + Stratum stratum = getStratum(stratumId); + List javaLines = new ArrayList<>(); + if (stratum != null) { + boolean found = false; + for (Iterator iter = stratum.fFileInfos.iterator(); iter.hasNext() && !found;) { + FileInfo fileInfo = iter.next(); + if (sourceName == null || (found = sourceName.equals(fileInfo.fFileName))) { + javaLines.addAll(fileInfo.getOutputLinesForLine(lineNumber)); + } + } + if (sourceName != null && !found) { + throw new AbsentInformationException(JDIMessages.ReferenceTypeImpl_34); + } + } else { // Java stratum + javaLines.add(Integer.valueOf(lineNumber)); + } + return method.javaStratumLocationsOfLines(javaLines); + } + + /** + * Return the locations of all lines in the given source file of the given + * stratum which are included in the given method. If sourceName is + * null, return the locations for all source file in the given + * stratum. + * + * @param stratumId + * the stratum id + * @param sourceName + * the name of the source file + * @param method + * @param codeIndexTable + * the list of code indexes for the method, as get from the + * VM/JDWP + * @param javaStratumLineNumberTable + * the list of line numbers in the java stratum for the method, + * as get from the VM/JDWP + * @return + */ + public List allLineLocations(String stratumId, String sourceName, + MethodImpl method, long[] codeIndexTable, + int[] javaStratumLineNumberTable) throws AbsentInformationException { + Stratum stratum = getStratum(stratumId); + if (stratum != null) { + int[][] lineInfoTable = new int[codeIndexTable.length][]; + if (sourceName == null) { + int lastIndex = 0; + for (int i = 0, length = javaStratumLineNumberTable.length; i < length; i++) { + // for each executable line in the java source, get the + // associated lines in the stratum source + List lineInfos = stratum.getInputLineInfos(javaStratumLineNumberTable[i]); + if (lineInfos != null) { + int[] lineInfo = lineInfos.get(0); + if (!Arrays.equals(lineInfo, lineInfoTable[lastIndex])) { + lineInfoTable[i] = lineInfo; + lastIndex = i; + } + } + } + } else { // sourceName != null + FileInfo fileInfo = stratum.getFileInfo(sourceName); + if (fileInfo == null) { + throw new AbsentInformationException(JDIMessages.ReferenceTypeImpl_34); + } + int fileId = fileInfo.fFileId; + int lastIndex = 0; + for (int i = 0, length = javaStratumLineNumberTable.length; i < length; i++) { + List lineInfos = stratum.getInputLineInfos(javaStratumLineNumberTable[i]); + if (lineInfos != null) { + for (int[] lineInfo : lineInfos) { + if (lineInfo[0] == fileId) { + if (!Arrays.equals(lineInfo, lineInfoTable[lastIndex])) { + lineInfoTable[i] = lineInfo; + lastIndex = i; + } + break; + } + } + } + } + } + List locations = new ArrayList<>(); + for (int i = 0, length = lineInfoTable.length; i < length; i++) { + if (lineInfoTable[i] != null) { + locations.add(new LocationImpl(virtualMachineImpl(), method, codeIndexTable[i])); + } + } + return locations; + } + // Java stratum + List result = new ArrayList<>(); + for (long element : codeIndexTable) { + result.add(new LocationImpl(virtualMachineImpl(), method, element)); + } + return result; + } + + /* + * @since 3.0 + * + * @since java 1.5 + */ + @Override + public String genericSignature() { + if (fGenericSignatureKnown) { + return fGenericSignature; + } + if (virtualMachineImpl().isJdwpVersionGreaterOrEqual(1, 5)) { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_SIGNATURE_WITH_GENERIC, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + setSignature(readString("signature", replyData)); //$NON-NLS-1$ + fGenericSignature = readString("generic signature", replyData); //$NON-NLS-1$ + if (fGenericSignature.length() == 0) { + fGenericSignature = null; + } + fGenericSignatureKnown = true; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } else { + fGenericSignatureKnown = true; + } + return fGenericSignature; + } + + /** + * if genericSignature is null, the generic signature is set to + * not-known (genericSignature() will ask the VM for the generic signature) + * if genericSignature is an empty String, the generic signature is set to + * no-generic-signature (genericSignature() will return null) if + * genericSignature is an non-empty String, the generic signature is set to + * the specified value (genericSignature() will return the specified value) + * + * @since 3.0 + */ + public void setGenericSignature(String genericSignature) { + if (genericSignature == null) { + fGenericSignature = null; + fGenericSignatureKnown = false; + } else { + if (genericSignature.length() == 0) { + fGenericSignature = null; + } else { + fGenericSignature = genericSignature; + } + fGenericSignatureKnown = true; + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ReferenceType#instances(long) + */ + @Override + public List instances(long maxInstances) { + try { + int max = (int) maxInstances; + if (maxInstances >= Integer.MAX_VALUE) { + max = Integer.MAX_VALUE; + } + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + writeInt(max, "max instances", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_INSTANCES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_OBJECT: + case JdwpReplyPacket.INVALID_CLASS: + throw new ObjectCollectedException( + JDIMessages.class_or_object_not_known); + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_27); + case JdwpReplyPacket.ILLEGAL_ARGUMENT: + throw new IllegalArgumentException( + JDIMessages.ReferenceTypeImpl_26); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int elements = readInt("element count", replyData); //$NON-NLS-1$ + if (max > 0 && elements > max) { + elements = max; + } + ArrayList list = new ArrayList<>(); + for (int i = 0; i < elements; i++) { + list.add((ObjectReference) ValueImpl.readWithTag(this, replyData)); + } + return list; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @see com.sun.jdi.ReferenceType#majorVersion() + * @since 3.3 + */ + @Override + public int majorVersion() { + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + getRefTypeID().write(outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_CLASS_VERSION, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_CLASS: + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.class_or_object_not_known); + case JdwpReplyPacket.ABSENT_INFORMATION: + return 0; + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_no_class_version_support24); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + return readInt("major version", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @see com.sun.jdi.ReferenceType#minorVersion() + * @since 3.3 + */ + @Override + public int minorVersion() { + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + getRefTypeID().write(outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_CLASS_VERSION, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_CLASS: + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.class_or_object_not_known); + case JdwpReplyPacket.ABSENT_INFORMATION: + return 0; + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_no_class_version_support24); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + readInt("major version", replyData); //$NON-NLS-1$ + return readInt("minor version", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @see com.sun.jdi.ReferenceType#constantPoolCount() + * @since 3.3 + */ + @Override + public int constantPoolCount() { + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + this.getRefTypeID().write(outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_CONSTANT_POOL, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_CLASS: + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.class_or_object_not_known); + case JdwpReplyPacket.ABSENT_INFORMATION: + return 0; + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_no_constant_pool_support); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + return readInt("pool count", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @see com.sun.jdi.ReferenceType#constantPool() + * @since 3.3 + */ + @Override + public byte[] constantPool() { + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + this.getRefTypeID().write(outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.RT_CONSTANT_POOL, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_CLASS: + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.class_or_object_not_known); + case JdwpReplyPacket.ABSENT_INFORMATION: + return new byte[0]; + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_no_constant_pool_support); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + readInt("pool count", replyData); //$NON-NLS-1$ + int bytes = readInt("byte count", replyData); //$NON-NLS-1$ + byte[] array = new byte[bytes]; + for (int i = 0; i < bytes; i++) { + array[i] = readByte("byte read", replyData); //$NON-NLS-1$ + } + return array; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns Jdwp version of given options. + */ + protected int optionsToJdwpOptions(int options) { + int jdwpOptions = 0; + if ((options & ClassType.INVOKE_SINGLE_THREADED) != 0) { + jdwpOptions |= MethodImpl.INVOKE_SINGLE_THREADED_JDWP; + } + return jdwpOptions; + } + + + /** + * Invoke static method on class or interface type + * + * @param thread the debugger thread in which to invoke + * @param method the resolved chosed Method to invoke + * @param arguments the list of Values to supply as arguments for the method, assigned to arguments in the order they appear in the method signature. + * @param options the integer bit flags + * @param command the JWDP command to invoke + * @return a Value representing the method's return value. + * @throws InvalidTypeException If the arguments do not match + * @throws ClassNotLoadedException if any argument type has not yet been loaded in the VM + * @throws IncompatibleThreadStateException if the specified thread has not been suspended + * @throws InvocationException if the method invocation resulted in an exception + */ + protected Value invokeMethod(ThreadReference thread, Method method, List arguments, int options, int command) throws InvalidTypeException, + ClassNotLoadedException, IncompatibleThreadStateException, + InvocationException { + checkVM(thread); + checkVM(method); + ThreadReferenceImpl threadImpl = (ThreadReferenceImpl) thread; + MethodImpl methodImpl = (MethodImpl) method; + + // Perform some checks for IllegalArgumentException. + if (!visibleMethods().contains(method)) { + throw new IllegalArgumentException( + JDIMessages.ClassTypeImpl_Class_does_not_contain_given_method_1); + } + if (method.argumentTypeNames().size() != arguments.size()) { + throw new IllegalArgumentException( + JDIMessages.ClassTypeImpl_Number_of_arguments_doesn__t_match_2); + } + if (method.isConstructor() || method.isStaticInitializer()) { + throw new IllegalArgumentException( + JDIMessages.ClassTypeImpl_Method_is_constructor_or_intitializer_3); + } + + // check the type and the VM of the arguments. Convert the values if + // needed + List checkedArguments = ValueImpl.checkValues(arguments, method.argumentTypes(), virtualMachineImpl()); + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + threadImpl.write(this, outData); + methodImpl.write(this, outData); + + writeInt(checkedArguments.size(), "size", outData); //$NON-NLS-1$ + Iterator iter = checkedArguments.iterator(); + while (iter.hasNext()) { + Value elt = iter.next(); + if (elt instanceof ValueImpl) { + ((ValueImpl)elt).writeWithTag(this, outData); + } else { + ValueImpl.writeNullWithTag(this, outData); + } + } + + writeInt(optionsToJdwpOptions(options), + "options", MethodImpl.getInvokeOptions(), outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + command, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_METHODID: + throw new IllegalArgumentException(); + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException(name()); + case JdwpReplyPacket.INVALID_THREAD: + throw new IncompatibleThreadStateException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException(); + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException(JDIMessages.InterfaceTypeImpl_Static_interface_methods_require_newer_JVM); + } + + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + ValueImpl value = ValueImpl.readWithTag(this, replyData); + ObjectReferenceImpl exception = ObjectReferenceImpl + .readObjectRefWithTag(this, replyData); + if (exception != null) { + throw new InvocationException(exception); + } + return value; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ShortTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ShortTypeImpl.java new file mode 100644 index 0000000000..e3e6e106bb --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ShortTypeImpl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.ShortType; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ShortTypeImpl extends PrimitiveTypeImpl implements ShortType { + /** + * Creates new instance. + */ + public ShortTypeImpl(VirtualMachineImpl vmImpl) { + super("ShortType", vmImpl, "short", "S"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return primitive type tag. + */ + @Override + public byte tag() { + return ShortValueImpl.tag; + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return virtualMachineImpl().mirrorOf((short) 0); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ShortValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ShortValueImpl.java new file mode 100644 index 0000000000..9889ac538c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ShortValueImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.ShortValue; +import com.sun.jdi.Type; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ShortValueImpl extends PrimitiveValueImpl implements ShortValue { + /** JDWP Tag. */ + public static final byte tag = JdwpID.SHORT_TAG; + + /** + * Creates new instance. + */ + public ShortValueImpl(VirtualMachineImpl vmImpl, Short value) { + super("ShortValue", vmImpl, value); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return virtualMachineImpl().getShortType(); + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(ShortValue o) { + return ((Short)shortValue()).compareTo(o.shortValue()); + } + + /** + * @return Value. + */ + @Override + public short value() { + return shortValue(); + } + + /** + * @return Reads and returns new instance. + */ + public static ShortValueImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + short value = target.readShort("shortValue", in); //$NON-NLS-1$ + return new ShortValueImpl(vmImpl, Short.valueOf(value)); + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeShort(((Short) fValue).shortValue(), "shortValue", out); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java new file mode 100644 index 0000000000..5739e1ca03 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/SourceDebugExtensionParser.java @@ -0,0 +1,608 @@ +/******************************************************************************* + * Copyright (c) 2003, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.AbsentInformationException; + +/** + * + */ +public class SourceDebugExtensionParser { + + private static class Lexer { + + static final int UNKNOWN = 0; + static final int SMAP = 1; + static final int NON_ASTERISK_STRING = 2; + static final int NUMBER = 3; + static final int CR = 4; + static final int ASTERISK_CHAR = 5; + static final int ASTERISK_C = 6; + static final int ASTERISK_E = 7; + static final int ASTERISK_F = 8; + static final int ASTERISK_L = 9; + static final int ASTERISK_O = 10; + static final int ASTERISK_S = 11; + static final int ASTERISK_V = 12; + // never used + // static final int WHITE_SPACE= 13; + static final int COLON = 14; + static final int COMMA = 15; + static final int SHARP = 16; + static final int PLUS = 17; + + private final char[] fSmap; + private int fPointer; + private char fChar; + + private char[] fLexem; + private int fLexemType; + + private boolean fEOF; + + public Lexer(String smap) { + fSmap = smap.toCharArray(); + fLexemType = UNKNOWN; + fPointer = -1; + nextChar(); + } + + /** + * Compute the next lexem. + * + * @return the type of the next lexem. + */ + public int nextLexem() throws AbsentInformationException { + if (fEOF) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_0); + } + startWith(); + return fLexemType; + } + + private char nextChar() { + if (++fPointer == fSmap.length) { + fEOF = true; + return '\000'; + } + fChar = fSmap[fPointer]; + return fChar; + } + + private void startWith() throws AbsentInformationException { + switch (fChar) { + case '\n': + case '\r': + startWithCR(); + break; + case '*': + startWithAsterisk(); + break; + case ':': + fLexem = new char[] { ':' }; + fLexemType = COLON; + nextChar(); + break; + case ',': + fLexem = new char[] { ',' }; + fLexemType = COMMA; + nextChar(); + break; + case '#': + fLexem = new char[] { '#' }; + fLexemType = SHARP; + nextChar(); + break; + case '+': + fLexem = new char[] { '+' }; + fLexemType = PLUS; + nextChar(); + break; + default: + startWithOtherChar(); + break; + } + } + + /** + * + */ + private void startWithOtherChar() { + int lexemStart = fPointer; + consumeWhiteSpace(); + if (fChar >= '0' && fChar <= '9') { // a number + number(lexemStart); + } else { + nonAsteriskString(lexemStart); + } + } + + /** + * @param lexemStart + */ + private void nonAsteriskString(int lexemStart) { + while (fChar != '\n' && fChar != '\r' && !fEOF) { + nextChar(); + } + int length = fPointer - lexemStart; + fLexem = new char[length]; + System.arraycopy(fSmap, lexemStart, fLexem, 0, length); + if (length == 4 && fLexem[0] == 'S' && fLexem[1] == 'M' + && fLexem[2] == 'A' && fLexem[3] == 'P') { + fLexemType = SMAP; + } else { + fLexemType = NON_ASTERISK_STRING; + } + } + + /** + * @param lexemStart + */ + private void number(int lexemStart) { + while (fChar >= '0' && fChar <= '9') { + nextChar(); + } + consumeWhiteSpace(); + fLexemType = NUMBER; + int length = fPointer - lexemStart; + fLexem = new char[length]; + System.arraycopy(fSmap, lexemStart, fLexem, 0, length); + } + + /** + * + */ + private void startWithAsterisk() throws AbsentInformationException { + nextChar(); + if (fEOF) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_0); + } + switch (fChar) { + case 'C': + fLexemType = ASTERISK_C; + break; + case 'E': + fLexemType = ASTERISK_E; + break; + case 'F': + fLexemType = ASTERISK_F; + break; + case 'L': + fLexemType = ASTERISK_L; + break; + case 'O': + fLexemType = ASTERISK_O; + break; + case 'S': + fLexemType = ASTERISK_S; + break; + case 'V': + fLexemType = ASTERISK_V; + break; + default: + fLexemType = ASTERISK_CHAR; + break; + } + fLexem = new char[] { '*', fChar }; + nextChar(); + } + + /** + * + */ + private void startWithCR() { + if (fChar == '\r') { + if (nextChar() == '\n') { + fLexem = new char[] { '\r', '\n' }; + nextChar(); + } else { + fLexem = new char[] { '\r' }; + } + } else { + fLexem = new char[] { fChar }; + nextChar(); + } + fLexemType = CR; + } + + /** + * + */ + private void consumeWhiteSpace() { + while (fChar == ' ' || fChar == '\t') { + nextChar(); + } + } + + /** + * @return the value of the current lexem. + */ + public char[] lexem() { + return fLexem; + } + + /** + * @return the type of the current lexem. + */ + public int lexemType() { + return fLexemType; + } + + } + + /** + * The reference type to which this source debug extension is associated. + */ + private final ReferenceTypeImpl fReferenceType; + + private final List fDefinedStrata; + + // parser data; + private ReferenceTypeImpl.Stratum fCurrentStratum; + private boolean fFileSectionDefinedForCurrentStratum; + private boolean fLineSectionDefinedForCurrentStratum; + private int fCurrentLineFileId; + + public static void parse(String smap, ReferenceTypeImpl referenceType) + throws AbsentInformationException { + new SourceDebugExtensionParser(referenceType).parseSmap(smap); + } + + /** + * SourceDebugExtension constructor. + */ + private SourceDebugExtensionParser(ReferenceTypeImpl referenceType) { + fReferenceType = referenceType; + fDefinedStrata = new ArrayList<>(); + fDefinedStrata.add(VirtualMachineImpl.JAVA_STRATUM_NAME); + } + + /** + * + */ + private void parseSmap(String smap) throws AbsentInformationException { + Lexer lexer = new Lexer(smap); + parseHeader(lexer); + parseSections(lexer); + if (!fDefinedStrata.contains(fReferenceType.defaultStratum())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_2); + } + } + + /** + * @param lexer + */ + private void parseHeader(Lexer lexer) throws AbsentInformationException { + int lexemType = lexer.nextLexem(); + if (lexemType != Lexer.SMAP) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_3); + } + if (lexer.nextLexem() != Lexer.CR) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_4); + } + if (isAsteriskLexem(lexer.nextLexem())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_5); + } + fReferenceType.setOutputFileName(getNonAsteriskString(lexer)); + if (isAsteriskLexem(lexer.lexemType())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_6); + } + fReferenceType.setDefaultStratumId(getNonAsteriskString(lexer)); + } + + /** + * @param lexer + */ + private void parseSections(Lexer lexer) throws AbsentInformationException { + while (lexer.lexemType() != Lexer.ASTERISK_E) { + parseStratumSection(lexer); + } + } + + /** + * @param lexer + */ + private void parseStratumSection(Lexer lexer) + throws AbsentInformationException { + if (lexer.lexemType() != Lexer.ASTERISK_S) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_7); + } + if (isAsteriskLexem(lexer.nextLexem())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_8); + } + String stratumId = getNonAsteriskString(lexer); + if (fDefinedStrata.contains(stratumId)) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_9, + new String[] { stratumId })); + } + fCurrentStratum = new ReferenceTypeImpl.Stratum(stratumId); + fFileSectionDefinedForCurrentStratum = false; + fLineSectionDefinedForCurrentStratum = false; + int lexemType = lexer.lexemType(); + while (lexemType != Lexer.ASTERISK_E && lexemType != Lexer.ASTERISK_S) { + switch (lexemType) { + case Lexer.ASTERISK_F: + if (fFileSectionDefinedForCurrentStratum) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_10, + new String[] { stratumId })); + } + parseFileSection(lexer); + fFileSectionDefinedForCurrentStratum = true; + break; + case Lexer.ASTERISK_L: + if (fLineSectionDefinedForCurrentStratum) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_11, + new String[] { stratumId })); + } + parseLineSection(lexer); + fLineSectionDefinedForCurrentStratum = true; + break; + case Lexer.ASTERISK_V: + parseVendorSection(lexer); + break; + case Lexer.ASTERISK_CHAR: + parseFutureSection(lexer); + break; + default: + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_12, + new String[] { new String(lexer.lexem()) })); + } + lexemType = lexer.lexemType(); + } + if (!fFileSectionDefinedForCurrentStratum) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_13, + new String[] { stratumId })); + } + if (!fLineSectionDefinedForCurrentStratum) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_14, + new String[] { stratumId })); + } + fDefinedStrata.add(stratumId); + fReferenceType.addStratum(fCurrentStratum); + } + + /** + * @param lexer + */ + private void parseFileSection(Lexer lexer) + throws AbsentInformationException { + if (lexer.nextLexem() != Lexer.CR) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_12, + new String[] { new String(lexer.lexem()) })); + } + lexer.nextLexem(); + while (!isAsteriskLexem(lexer.lexemType())) { + parseFileInfo(lexer); + } + } + + /** + * @param lexer + */ + private void parseFileInfo(Lexer lexer) throws AbsentInformationException { + int lexemType = lexer.lexemType(); + switch (lexemType) { + case Lexer.NUMBER: + int fileId = integerValue(lexer.lexem()); + if (isAsteriskLexem(lexer.nextLexem())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_16); + } + fCurrentStratum.addFileInfo(fileId, getNonAsteriskString(lexer)); + break; + case Lexer.PLUS: + if (lexer.nextLexem() != Lexer.NUMBER) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_17); + } + fileId = integerValue(lexer.lexem()); + if (isAsteriskLexem(lexer.nextLexem())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_16); + } + String fileName = getNonAsteriskString(lexer); + if (isAsteriskLexem(lexer.lexemType())) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_19); + } + fCurrentStratum.addFileInfo(fileId, fileName, getNonAsteriskString(lexer)); + break; + default: + throw new AbsentInformationException(NLS.bind(JDIMessages.SourceDebugExtensionParser_12, new String[] { new String(lexer.lexem()) })); + } + } + + /** + * @param lexer + */ + private void parseLineSection(Lexer lexer) + throws AbsentInformationException { + fCurrentLineFileId = 0; + if (lexer.nextLexem() != Lexer.CR) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_12, + new String[] { new String(lexer.lexem()) })); + } + lexer.nextLexem(); + while (!isAsteriskLexem(lexer.lexemType())) { + parseLineInfo(lexer); + } + } + + /** + * @param lexer + */ + private void parseLineInfo(Lexer lexer) throws AbsentInformationException { + if (lexer.lexemType() != Lexer.NUMBER) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_22); + } + int inputStartLine = integerValue(lexer.lexem()); + int lexemType = lexer.nextLexem(); + if (lexemType == Lexer.SHARP) { + if (lexer.nextLexem() != Lexer.NUMBER) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_23); + } + fCurrentLineFileId = integerValue(lexer.lexem()); + lexemType = lexer.nextLexem(); + } + int repeatCount; + if (lexemType == Lexer.COMMA) { + if (lexer.nextLexem() != Lexer.NUMBER) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_24); + } + repeatCount = integerValue(lexer.lexem()); + lexemType = lexer.nextLexem(); + } else { + repeatCount = 1; + } + if (lexemType != Lexer.COLON) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_25); + } + if (lexer.nextLexem() != Lexer.NUMBER) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_26); + } + int outputStartLine = integerValue(lexer.lexem()); + lexemType = lexer.nextLexem(); + int outputLineIncrement; + if (lexemType == Lexer.COMMA) { + if (lexer.nextLexem() != Lexer.NUMBER) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_27); + } + outputLineIncrement = integerValue(lexer.lexem()); + lexemType = lexer.nextLexem(); + } else { + outputLineIncrement = 1; + } + if (lexemType != Lexer.CR) { + throw new AbsentInformationException( + JDIMessages.SourceDebugExtensionParser_28); + } + lexer.nextLexem(); + fCurrentStratum.addLineInfo(inputStartLine, fCurrentLineFileId, + repeatCount, outputStartLine, outputLineIncrement); + } + + /** + * @param lexer + */ + private void parseVendorSection(Lexer lexer) + throws AbsentInformationException { + if (lexer.nextLexem() != Lexer.CR) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_12, + new String[] { new String(lexer.lexem()) })); + } + lexer.nextLexem(); + while (!isAsteriskLexem(lexer.lexemType())) { + // do nothing in this case, just consume the lexems. + getNonAsteriskString(lexer); + } + } + + /** + * @param lexer + */ + private void parseFutureSection(Lexer lexer) + throws AbsentInformationException { + if (lexer.nextLexem() != Lexer.CR) { + throw new AbsentInformationException(NLS.bind( + JDIMessages.SourceDebugExtensionParser_12, + new String[] { new String(lexer.lexem()) })); + } + lexer.nextLexem(); + while (!isAsteriskLexem(lexer.lexemType())) { + // do nothing in this case, just consume the lexems. + getNonAsteriskString(lexer); + } + } + + private String getNonAsteriskString(Lexer lexer) + throws AbsentInformationException { + StringBuilder string = new StringBuilder(); + int lexemType = lexer.lexemType(); + while (lexemType != Lexer.CR) { + string.append(lexer.lexem()); + lexemType = lexer.nextLexem(); + } + lexer.nextLexem(); + // remove the leading white spaces + int i = -1, length = string.length(); + char c; + while (++i < length && ((c = string.charAt(i)) == ' ' || c == '\t')) { + //continue until we chew up all the whitespace or hit the end of the line + } + return string.delete(0, i).toString(); + } + + private int integerValue(char[] lexem) { + int i = 0; + char c = lexem[0]; + while (c == ' ' || c == '\t') { + c = lexem[++i]; + } + int value = 0; + while (c >= '0' && c <= '9') { + value = value * 10 + c - '0'; + if (++i == lexem.length) { + break; + } + c = lexem[i]; + } + return value; + } + + private boolean isAsteriskLexem(int lexemType) { + switch (lexemType) { + case Lexer.ASTERISK_C: + case Lexer.ASTERISK_E: + case Lexer.ASTERISK_F: + case Lexer.ASTERISK_L: + case Lexer.ASTERISK_O: + case Lexer.ASTERISK_S: + case Lexer.ASTERISK_V: + case Lexer.ASTERISK_CHAR: + return true; + default: + return false; + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/StackFrameImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/StackFrameImpl.java new file mode 100644 index 0000000000..7be86ae243 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/StackFrameImpl.java @@ -0,0 +1,373 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpFrameID; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidStackFrameException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.Locatable; +import com.sun.jdi.Location; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.StackFrame; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMMismatchException; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class StackFrameImpl extends MirrorImpl implements StackFrame, Locatable { + /** FrameID that corresponds to this reference. */ + private final JdwpFrameID fFrameID; + /** Thread under which this frame's method is running. */ + private final ThreadReferenceImpl fThread; + /** Location of the current instruction in the frame. */ + private final LocationImpl fLocation; + + /** + * Creates new StackFrameImpl. + */ + public StackFrameImpl(VirtualMachineImpl vmImpl, JdwpFrameID ID, + ThreadReferenceImpl thread, LocationImpl location) { + super("StackFrame", vmImpl); //$NON-NLS-1$ + fFrameID = ID; + fThread = thread; + fLocation = location; + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#getValue(com.sun.jdi.LocalVariable) + */ + @Override + public Value getValue(LocalVariable variable) + throws IllegalArgumentException, InvalidStackFrameException, + VMMismatchException { + ArrayList list = new ArrayList<>(1); + list.add(variable); + return getValues(list).get(variable); + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#getValues(java.util.List) + */ + @Override + public Map getValues(List variables) throws IllegalArgumentException, + InvalidStackFrameException, VMMismatchException { + // Note that this information should not be cached. + Map map = new HashMap<>(variables.size()); + // if the variable list is empty, nothing to do + if (variables.isEmpty()) { + return map; + } + /* + * If 'this' is requested, we have to use a special JDWP request. + * Therefore, we remember the positions in the list of requests for + * 'this'. + */ + int sizeAll = variables.size(); + int sizeThis = 0; + boolean[] isThisValue = new boolean[sizeAll]; + for (int i = 0; i < sizeAll; i++) { + LocalVariableImpl var = (LocalVariableImpl) variables.get(i); + isThisValue[i] = var.isThis(); + if (isThisValue[i]) { + sizeThis++; + } + } + int sizeNotThis = sizeAll - sizeThis; + + if (sizeThis > 0) { + Value thisValue = thisObject(); + for (int i = 0; i < sizeAll; i++) { + if (isThisValue[i]) { + map.put(variables.get(i), thisValue); + } + } + } + + // If only 'this' was requested, we're finished. + if (sizeNotThis == 0) { + return map; + } + + // Request values for local variables other than 'this'. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeWithThread(this, outData); + writeInt(sizeNotThis, "size", outData); //$NON-NLS-1$ + for (int i = 0; i < sizeAll; i++) { + if (!isThisValue[i]) { + LocalVariableImpl var = (LocalVariableImpl) variables + .get(i); + checkVM(var); + writeInt(var.slot(), "slot", outData); //$NON-NLS-1$ + writeByte(var.tag(), "tag", JdwpID.tagMap(), outData); //$NON-NLS-1$ + } + } + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.SF_GET_VALUES, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + if (nrOfElements != sizeNotThis) + throw new InternalError( + JDIMessages.StackFrameImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1); + + for (int i = 0, j = 0; i < sizeAll; i++) { + if (!isThisValue[i]) + map.put(variables.get(j++), + ValueImpl.readWithTag(this, replyData)); + } + return map; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#getArgumentValues() + */ + @Override + public List getArgumentValues() throws InvalidStackFrameException { + if (!thread().isSuspended()) { + throw new InvalidStackFrameException( + JDIMessages.StackFrameImpl_no_argument_values_available); + } + try { + List list = location().method().variables(); + ArrayList ret = new ArrayList<>(); + LocalVariable var = null; + for (Iterator iter = list.iterator(); iter.hasNext();) { + var = iter.next(); + if (var.isArgument()) { + ret.add(getValue(var)); + } + } + return ret; + } catch (AbsentInformationException e) { + JDIDebugPlugin.log(e); + return null; + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#location() + */ + @Override + public Location location() { + return fLocation; + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#setValue(com.sun.jdi.LocalVariable, com.sun.jdi.Value) + */ + @Override + public void setValue(LocalVariable var, Value value) + throws InvalidTypeException, ClassNotLoadedException { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + ((ThreadReferenceImpl) thread()).write(this, outData); + write(this, outData); + writeInt(1, "size", outData); // We only set one field //$NON-NLS-1$ + checkVM(var); + writeInt(((LocalVariableImpl) var).slot(), "slot", outData); //$NON-NLS-1$ + + // check the type and the VM of the value, convert the value if + // needed. + ValueImpl checkedValue = ValueImpl.checkValue(value, var.type(), + virtualMachineImpl()); + + if (checkedValue != null) { + checkedValue.writeWithTag(this, outData); + } else { + ValueImpl.writeNullWithTag(this, outData); + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.SF_SET_VALUES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_CLASS: + throw new ClassNotLoadedException(var.typeName()); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#thisObject() + */ + @Override + public ObjectReference thisObject() throws InvalidStackFrameException { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeWithThread(this, outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.SF_THIS_OBJECT, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + ObjectReference result = ObjectReferenceImpl.readObjectRefWithTag( + this, replyData); + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#thread() + */ + @Override + public ThreadReference thread() { + return fThread; + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#visibleVariableByName(java.lang.String) + */ + @Override + public LocalVariable visibleVariableByName(String name) + throws AbsentInformationException { + Iterator iter = visibleVariables().iterator(); + while (iter.hasNext()) { + LocalVariableImpl var = (LocalVariableImpl) iter.next(); + if (var.name().equals(name)) { + return var; + } + } + + return null; + } + + /* (non-Javadoc) + * @see com.sun.jdi.StackFrame#visibleVariables() + */ + @Override + public List visibleVariables() throws AbsentInformationException { + List variables = fLocation.method().variables(); + Iterator iter = variables.iterator(); + List visibleVars = new ArrayList<>(variables.size()); + while (iter.hasNext()) { + LocalVariableImpl var = (LocalVariableImpl) iter.next(); + // Only return local variables other than the this pointer. + if (var.isVisible(this) && !var.isThis()) { + visibleVars.add(var); + } + } + return visibleVars; + } + + /** + * @return Returns the hash code value. + */ + @Override + public int hashCode() { + return fThread.hashCode() + fFrameID.hashCode(); + } + + /** + * @return Returns true if two mirrors refer to the same entity in the + * target VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null && object.getClass().equals(this.getClass()) + && fThread.equals(((StackFrameImpl) object).fThread) + && fFrameID.equals(((StackFrameImpl) object).fFrameID); + } + + /** + * Writes JDWP representation. + */ + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + fFrameID.write(out); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("stackFrame", fFrameID.value()); //$NON-NLS-1$ + } + } + + /** + * Writes JDWP representation. + */ + public void writeWithThread(MirrorImpl target, DataOutputStream out) + throws IOException { + fThread.write(target, out); + write(target, out); + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static StackFrameImpl readWithLocation(MirrorImpl target, + ThreadReferenceImpl thread, DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpFrameID ID = new JdwpFrameID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("stackFrame", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + LocationImpl location = LocationImpl.read(target, in); + if (location == null) { + return null; + } + + return new StackFrameImpl(vmImpl, ID, thread, location); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/StringReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/StringReferenceImpl.java new file mode 100644 index 0000000000..ad13f074a2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/StringReferenceImpl.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdi.internal.jdwp.JdwpStringID; + +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.StringReference; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class StringReferenceImpl extends ObjectReferenceImpl implements + StringReference { + /** JDWP Tag. */ + public static final byte tag = JdwpID.STRING_TAG; + + /** + * Creates new StringReferenceImpl. + */ + public StringReferenceImpl(VirtualMachineImpl vmImpl, JdwpStringID stringID) { + super("StringReference", vmImpl, stringID); //$NON-NLS-1$ + } + + /** + * @return Value tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return Returns the StringReference as a String. + */ + @Override + public String value() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.SR_VALUE, + this); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + String result = readString("value", replyData); //$NON-NLS-1$ + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static StringReferenceImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpStringID ID = new JdwpStringID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + { + target.fVerboseWriter.println("stringReference", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + + StringReferenceImpl mirror = new StringReferenceImpl(vmImpl, ID); + return mirror; + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return "\"" + value() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ + } catch (ObjectCollectedException e) { + return JDIMessages.StringReferenceImpl__Garbage_Collected__StringReference__3 + + idString(); + } catch (Exception e) { + return fDescription; + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ThreadGroupReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ThreadGroupReferenceImpl.java new file mode 100644 index 0000000000..c4c6f6e82e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ThreadGroupReferenceImpl.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdi.internal.jdwp.JdwpThreadGroupID; + +import com.sun.jdi.ThreadGroupReference; +import com.sun.jdi.ThreadReference; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ThreadGroupReferenceImpl extends ObjectReferenceImpl implements + ThreadGroupReference { + /** JDWP Tag. */ + public static final byte tag = JdwpID.THREAD_GROUP_TAG; + /** + * The cached name of this thread group. This value is safe to cache because + * there is no API for changing the name of a ThreadGroup. + */ + private String fName; + /** + * The cached parent of this thread group. Once set, this value cannot be + * changed + */ + private ThreadGroupReference fParent = fgUnsetParent; + private static ThreadGroupReferenceImpl fgUnsetParent = new ThreadGroupReferenceImpl( + null, null); + + /** + * Creates new ThreadGroupReferenceImpl. + */ + public ThreadGroupReferenceImpl(VirtualMachineImpl vmImpl, + JdwpThreadGroupID threadGroupID) { + super("ThreadGroupReference", vmImpl, threadGroupID); //$NON-NLS-1$ + } + + /** + * @return Value tag. + */ + @Override + public byte getTag() { + return tag; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadGroupReference#name() + */ + @Override + public String name() { + if (fName != null) { + return fName; + } + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TGR_NAME, + this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fName = readString("name", replyData); //$NON-NLS-1$ + return fName; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadGroupReference#parent() + */ + @Override + public ThreadGroupReference parent() { + if (fParent != fgUnsetParent) { + return fParent; + } + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TGR_PARENT, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fParent = ThreadGroupReferenceImpl.read(this, replyData); + return fParent; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadGroupReference#resume() + */ + @Override + public void resume() { + Iterator iter = allThreads().iterator(); + while (iter.hasNext()) { + ThreadReference thr = iter.next(); + thr.resume(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadGroupReference#suspend() + */ + @Override + public void suspend() { + Iterator iter = allThreads().iterator(); + while (iter.hasNext()) { + ThreadReference thr = iter.next(); + thr.suspend(); + } + } + + /** + * Inner class used to return children info. + */ + private static class ChildrenInfo { + List childThreads; + List childThreadGroups; + } + + /** + * @return Returns a List containing each ThreadReference in this thread + * group. + */ + public ChildrenInfo childrenInfo() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TGR_CHILDREN, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + ChildrenInfo result = new ChildrenInfo(); + int nrThreads = readInt("nr threads", replyData); //$NON-NLS-1$ + result.childThreads = new ArrayList<>(nrThreads); + for (int i = 0; i < nrThreads; i++) { + result.childThreads.add(ThreadReferenceImpl.read(this, + replyData)); + } + int nrThreadGroups = readInt("nr thread groups", replyData); //$NON-NLS-1$ + result.childThreadGroups = new ArrayList<>(nrThreadGroups); + for (int i = 0; i < nrThreadGroups; i++) { + result.childThreadGroups.add(ThreadGroupReferenceImpl.read( + this, replyData)); + } + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadGroupReference#threadGroups() + */ + @Override + public List threadGroups() { + return childrenInfo().childThreadGroups; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadGroupReference#threads() + */ + @Override + public List threads() { + return childrenInfo().childThreads; + } + + /** + * @return Returns a List containing each ThreadGroupReference in this + * thread group and all of its subgroups. + */ + private List allThreads() { + ChildrenInfo info = childrenInfo(); + List result = info.childThreads; + Iterator iter = info.childThreadGroups.iterator(); + while (iter.hasNext()) { + ThreadGroupReferenceImpl tg = (ThreadGroupReferenceImpl) iter.next(); + result.addAll(tg.allThreads()); + } + return result; + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return name(); + } catch (Exception e) { + return fDescription; + } + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ThreadGroupReferenceImpl read(MirrorImpl target, + DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpThreadGroupID ID = new JdwpThreadGroupID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("threadGroupReference", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + + ThreadGroupReferenceImpl mirror = (ThreadGroupReferenceImpl) vmImpl + .getCachedMirror(ID); + if (mirror == null) { + mirror = new ThreadGroupReferenceImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + return mirror; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ThreadReferenceImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ThreadReferenceImpl.java new file mode 100644 index 0000000000..effb34640f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ThreadReferenceImpl.java @@ -0,0 +1,892 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdi.OpaqueFrameException; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdi.internal.jdwp.JdwpThreadID; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InternalException; +import com.sun.jdi.InvalidStackFrameException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.NativeMethodException; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.StackFrame; +import com.sun.jdi.ThreadGroupReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMCannotBeModifiedException; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; + +/** + * This class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ThreadReferenceImpl extends ObjectReferenceImpl implements ThreadReference, org.eclipse.jdi.hcr.ThreadReference { + /** ThreadStatus Constants. */ + public static final int JDWP_THREAD_STATUS_ZOMBIE = 0; + public static final int JDWP_THREAD_STATUS_RUNNING = 1; + public static final int JDWP_THREAD_STATUS_SLEEPING = 2; + public static final int JDWP_THREAD_STATUS_MONITOR = 3; + public static final int JDWP_THREAD_STATUS_WAIT = 4; + + /** SuspendStatus Constants. */ + public static final int SUSPEND_STATUS_SUSPENDED = 0x01; + + /** Mapping of command codes to strings. */ + private static Map fgThreadStatusMap = null; + + /** Map with Strings for flag bits. */ + private static String[] fgSuspendStatusStrings = null; + + /** JDWP Tag. */ + protected static final byte tag = JdwpID.THREAD_TAG; + + /** Is thread currently at a breakpoint? */ + private boolean fIsAtBreakpoint = false; + + /** + * The cached thread group. A thread's thread group cannot be changed. + */ + private ThreadGroupReferenceImpl fThreadGroup = null; + + // Whether a thread is a virtual thread or not is cached + private volatile boolean isVirtual; + private volatile boolean isVirtualCached; + + /** + * Creates new ThreadReferenceImpl. + */ + public ThreadReferenceImpl(VirtualMachineImpl vmImpl, JdwpThreadID threadID) { + super("ThreadReference", vmImpl, threadID); //$NON-NLS-1$ + } + + /** + * Sets at breakpoint flag. + */ + public void setIsAtBreakpoint() { + fIsAtBreakpoint = true; + } + + /** + * Reset flags that can be set when event occurs. + */ + public void resetEventFlags() { + fIsAtBreakpoint = false; + } + + /** + * @return Value tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return Returns an ObjectReference for the monitor, if any, for which + * this thread is currently waiting. + */ + @Override + public ObjectReference currentContendedMonitor() + throws IncompatibleThreadStateException { + if (!virtualMachine().canGetCurrentContendedMonitor()) { + throw new UnsupportedOperationException(); + } + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_CURRENT_CONTENDED_MONITOR, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_1); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + ObjectReference result = ObjectReferenceImpl.readObjectRefWithTag( + this, replyData); + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * @see com.sun.jdi.ThreadReference#forceEarlyReturn(com.sun.jdi.Value) + * @since 3.3 + */ + @Override + public void forceEarlyReturn(Value value) throws InvalidTypeException, + ClassNotLoadedException, IncompatibleThreadStateException { + if (!virtualMachineImpl().canBeModified()) { + throw new VMCannotBeModifiedException( + JDIMessages.ThreadReferenceImpl_vm_read_only); + } + initJdwpRequest(); + ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); + DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); + try { + write(this, dataOutStream); + if (value != null) { + ((ValueImpl) value).writeWithTag((ValueImpl) value, + dataOutStream); + } else { + ValueImpl.writeNullWithTag(this, dataOutStream); + } + JdwpReplyPacket reply = requestVM( + JdwpCommandPacket.TR_FORCE_EARLY_RETURN, byteOutStream); + switch (reply.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException( + JDIMessages.ThreadReferenceImpl_thread_object_invalid); + case JdwpReplyPacket.INVALID_OBJECT: + throw new ClassNotLoadedException( + JDIMessages.ThreadReferenceImpl_thread_or_value_unknown); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + case JdwpReplyPacket.THREAD_NOT_ALIVE: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_thread_not_suspended); + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ThreadReferenceImpl_no_force_early_return_on_threads); + case JdwpReplyPacket.OPAQUE_FRAME: + if (isVirtual()) { + throw new OpaqueFrameException(); + } + throw new NativeMethodException(JDIMessages.ThreadReferenceImpl_thread_cannot_force_native_method); + case JdwpReplyPacket.NO_MORE_FRAMES: + throw new InvalidStackFrameException( + JDIMessages.ThreadReferenceImpl_thread_no_stackframes); + case JdwpReplyPacket.TYPE_MISMATCH: + throw new InvalidTypeException( + JDIMessages.ThreadReferenceImpl_incapatible_return_type); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(reply.errorCode()); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the StackFrame at the given index in the thread's + * current call stack. + */ + @Override + public StackFrame frame(int index) throws IncompatibleThreadStateException { + return frames(index, 1).get(0); + } + + /** + * @see com.sun.jdi.ThreadReference#frameCount() + */ + @Override + public int frameCount() throws IncompatibleThreadStateException { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_FRAME_COUNT, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_1); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int result = readInt("frame count", replyData); //$NON-NLS-1$ + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#frames() + */ + @Override + public List frames() throws IncompatibleThreadStateException { + return frames(0, -1); + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#frames(int, int) + */ + @Override + public List frames(int start, int length) throws IndexOutOfBoundsException, + IncompatibleThreadStateException { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + writeInt(start, "start", outData); //$NON-NLS-1$ + writeInt(length, "length", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_FRAMES, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_1); + case JdwpReplyPacket.INVALID_INDEX: + throw new IndexOutOfBoundsException( + JDIMessages.ThreadReferenceImpl_Invalid_index_of_stack_frames_given_4); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + List frames = new ArrayList<>(nrOfElements); + for (int i = 0; i < nrOfElements; i++) { + StackFrameImpl frame = StackFrameImpl.readWithLocation(this, + this, replyData); + if (frame == null) { + continue; + } + frames.add(frame); + } + return frames; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#interrupt() + */ + @Override + public void interrupt() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + requestVM(JdwpCommandPacket.TR_INTERRUPT, this); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#isAtBreakpoint() + */ + @Override + public boolean isAtBreakpoint() { + return isSuspended() && fIsAtBreakpoint; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#isSuspended() + */ + @Override + public boolean isSuspended() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_STATUS, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + // remove the thread status reply + readInt("thread status", threadStatusMap(), replyData); //$NON-NLS-1$ + int suspendStatus = readInt( + "suspend status", suspendStatusStrings(), replyData); //$NON-NLS-1$ + boolean result = suspendStatus == SUSPEND_STATUS_SUSPENDED; + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return false; + } finally { + handledJdwpRequest(); + } + } + + /** + * isVirtual is a preview API of the Java platform. Programs can only use isVirtual when preview features are enabled. Preview features may be + * removed in a future release, or upgraded to permanent features of the Java platform. + * + * @return true if the thread is a virtual thread + * @since 3.20 + */ + public boolean isVirtual() { + if (isVirtualCached) { + return isVirtual; + } + boolean result = false; + boolean supportsVirtualThreads = virtualMachineImpl().mayCreateVirtualThreads(); + if (supportsVirtualThreads) { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TR_IS_VIRTUAL, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + result = readBoolean("isVirtual", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + return false; + } finally { + handledJdwpRequest(); + } + } + + isVirtual = result; + isVirtualCached = true; + return result; + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#name() + */ + @Override + public String name() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TR_NAME, + this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + return readString("name", replyData); //$NON-NLS-1$ + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#ownedMonitors() + */ + @Override + public List ownedMonitors() throws IncompatibleThreadStateException { + if (!virtualMachine().canGetOwnedMonitorInfo()) { + throw new UnsupportedOperationException(); + } + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_OWNED_MONITORS, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_5); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + int nrOfMonitors = readInt("nr of monitors", replyData); //$NON-NLS-1$ + List result = new ArrayList<>(nrOfMonitors); + for (int i = 0; i < nrOfMonitors; i++) { + result.add(ObjectReferenceImpl.readObjectRefWithTag(this, + replyData)); + } + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.ThreadReference#ownedMonitorsAndFrames() + */ + @Override + public List ownedMonitorsAndFrames() + throws IncompatibleThreadStateException { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_OWNED_MONITOR_STACK_DEPTH, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.ThreadReferenceImpl_thread_object_invalid); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_5); + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ThreadReferenceImpl_no_force_early_return_on_threads); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + int owned = readInt("owned monitors", replyData); //$NON-NLS-1$ + List result = new ArrayList<>(owned); + ObjectReference monitor = null; + int depth = -1; + for (int i = 0; i < owned; i++) { + monitor = ObjectReferenceImpl.readObjectRefWithTag(this, + replyData); + depth = readInt("stack depth", replyData); //$NON-NLS-1$ + result.add(new MonitorInfoImpl(this, depth, monitor, virtualMachineImpl())); + } + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Resumes this thread. + * + * @see com.sun.jdi.ThreadReference#resume() + */ + @Override + public void resume() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_RESUME, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + resetEventFlags(); + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the thread's status. + */ + @Override + public int status() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_STATUS, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.ABSENT_INFORMATION: + return THREAD_STATUS_UNKNOWN; + case JdwpReplyPacket.INVALID_THREAD: + return THREAD_STATUS_NOT_STARTED; + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int threadStatus = readInt( + "thread status", threadStatusMap(), replyData); //$NON-NLS-1$ + readInt("suspend status", suspendStatusStrings(), replyData); //$NON-NLS-1$ + switch (threadStatus) { + case JDWP_THREAD_STATUS_ZOMBIE: + return THREAD_STATUS_ZOMBIE; + case JDWP_THREAD_STATUS_RUNNING: + return THREAD_STATUS_RUNNING; + case JDWP_THREAD_STATUS_SLEEPING: + return THREAD_STATUS_SLEEPING; + case JDWP_THREAD_STATUS_MONITOR: + return THREAD_STATUS_MONITOR; + case JDWP_THREAD_STATUS_WAIT: + return THREAD_STATUS_WAIT; + case -1: // see bug 30816 + return THREAD_STATUS_UNKNOWN; + } + throw new InternalException( + JDIMessages.ThreadReferenceImpl_Unknown_thread_status_received___6 + + threadStatus); + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * Stops this thread with an asynchronous exception. + * + * @see com.sun.jdi.ThreadReference#stop(com.sun.jdi.ObjectReference) + */ + @Override + public void stop(ObjectReference throwable) throws InvalidTypeException { + checkVM(throwable); + ObjectReferenceImpl throwableImpl = (ObjectReferenceImpl) throwable; + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + throwableImpl.write(this, outData); + + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TR_STOP, + outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + case JdwpReplyPacket.INVALID_CLASS: + throw new InvalidTypeException( + JDIMessages.ThreadReferenceImpl_Stop_argument_not_an_instance_of_java_lang_Throwable_in_the_target_VM_7); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * Suspends this thread. + * + * @see com.sun.jdi.ThreadReference#suspend() + */ + @Override + public void suspend() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_SUSPEND, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns the number of pending suspends for this thread. + */ + @Override + public int suspendCount() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_SUSPEND_COUNT, this); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int result = readInt("suspend count", replyData); //$NON-NLS-1$ + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns this thread's thread group. + */ + @Override + public ThreadGroupReference threadGroup() { + if (fThreadGroup != null) { + return fThreadGroup; + } + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.TR_THREAD_GROUP, this); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fThreadGroup = ThreadGroupReferenceImpl.read(this, replyData); + return fThreadGroup; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Simulate the execution of a return instruction instead of executing the + * next byte code in a method. + * + * @return Returns whether any finally or synchronized blocks are enclosing + * the current instruction. + */ + @Override + public boolean doReturn(Value returnValue, + boolean triggerFinallyAndSynchronized) + throws org.eclipse.jdi.hcr.OperationRefusedException { + virtualMachineImpl().checkHCRSupported(); + ValueImpl valueImpl; + if (returnValue != null) { // null is used if no value is returned. + checkVM(returnValue); + valueImpl = (ValueImpl) returnValue; + } else { + try { + TypeImpl returnType = (TypeImpl) frame(0).location().method() + .returnType(); + valueImpl = (ValueImpl) returnType.createNullValue(); + } catch (IncompatibleThreadStateException e) { + throw new org.eclipse.jdi.hcr.OperationRefusedException( + e.toString()); + } catch (ClassNotLoadedException e) { + throw new org.eclipse.jdi.hcr.OperationRefusedException( + e.toString()); + } + } + + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + write(this, outData); + valueImpl.writeWithTag(this, outData); + writeBoolean(triggerFinallyAndSynchronized, + "trigger finaly+sync", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.HCR_DO_RETURN, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_THREAD: + throw new ObjectCollectedException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + boolean result = readBoolean("is enclosed", replyData); //$NON-NLS-1$ + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return false; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return NLS.bind(JDIMessages.ThreadReferenceImpl_8, + new String[] { type().toString(), name(), + getObjectID().toString() }); + } catch (ObjectCollectedException e) { + return JDIMessages.ThreadReferenceImpl__Garbage_Collected__ThreadReference__9 + + idString(); + } catch (Exception e) { + return fDescription; + } + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ThreadReferenceImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + JdwpThreadID ID = new JdwpThreadID(vmImpl); + ID.read(in); + if (target.fVerboseWriter != null) + { + target.fVerboseWriter.println("threadReference", ID.value()); //$NON-NLS-1$ + } + + if (ID.isNull()) { + return null; + } + + ThreadReferenceImpl mirror = (ThreadReferenceImpl) vmImpl + .getCachedMirror(ID); + if (mirror == null) { + mirror = new ThreadReferenceImpl(vmImpl, ID); + vmImpl.addCachedMirror(mirror); + } + return mirror; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgThreadStatusMap != null) { + return; + } + + Field[] fields = ThreadReferenceImpl.class.getDeclaredFields(); + fgThreadStatusMap = new HashMap<>(); + fgSuspendStatusStrings = new String[32]; // Int + + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + int value = field.getInt(null); + Integer intValue = Integer.valueOf(value); + + if (name.startsWith("JDWP_THREAD_STATUS_")) { //$NON-NLS-1$ + name = name.substring(19); + fgThreadStatusMap.put(intValue, name); + } else if (name.startsWith("SUSPEND_STATUS_")) { //$NON-NLS-1$ + name = name.substring(15); + for (int j = 0; j < fgSuspendStatusStrings.length; j++) { + if ((1 << j & value) != 0) { + fgSuspendStatusStrings[j] = name; + break; + } + } + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + public static Map threadStatusMap() { + getConstantMaps(); + return fgThreadStatusMap; + } + + /** + * @return Returns a map with string representations of tags. + */ + public static String[] suspendStatusStrings() { + getConstantMaps(); + return fgSuspendStatusStrings; + } + + /** + * @see ThreadReference#popFrames(StackFrame) + */ + @Override + public void popFrames(StackFrame frameToPop) + throws IncompatibleThreadStateException { + if (!isSuspended()) { + throw new IncompatibleThreadStateException(); + } + if (!virtualMachineImpl().canPopFrames()) { + throw new UnsupportedOperationException(); + } + + StackFrameImpl frame = (StackFrameImpl) frameToPop; + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + frame.writeWithThread(frame, outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.SF_POP_FRAME, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.OPAQUE_FRAME: + if (isVirtual()) { + throw new OpaqueFrameException(); + } + throw new NativeMethodException(); + case JdwpReplyPacket.INVALID_THREAD: + throw new InvalidStackFrameException(); + case JdwpReplyPacket.INVALID_FRAMEID: + throw new InvalidStackFrameException( + JDIMessages.ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_frame_id_was_invalid__The_thread_was_resumed__10); + case JdwpReplyPacket.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + JDIMessages.ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame__The_requested_stack_frame_is_not_suspended_11); + case JdwpReplyPacket.NO_MORE_FRAMES: + throw new InvalidStackFrameException( + JDIMessages.ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_requested_frame_was_the_last_frame_on_the_call_stack__The_requested_frame_was_the_last_frame_above_a_native_frame__12); + default: + defaultReplyErrorHandler(replyPacket.errorCode()); + } + } catch (IOException ioe) { + defaultIOExceptionHandler(ioe); + } finally { + handledJdwpRequest(); + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/TypeComponentImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/TypeComponentImpl.java new file mode 100644 index 0000000000..bef7fe2fb4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/TypeComponentImpl.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.ReferenceType; +import com.sun.jdi.TypeComponent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class TypeComponentImpl extends AccessibleImpl implements + TypeComponent { + /** Text representation of this type. */ + private String fName = null; + /** JNI-style signature for this type. */ + private String fSignature = null; + /** the generic signature for this type, java 1.5 */ + private final String fGenericSignature; + /** ReferenceType that holds field or method. */ + private final ReferenceTypeImpl fDeclaringType; + /** Modifier bits. */ + protected int fModifierBits; + + /** + * Creates new instance. + */ + public TypeComponentImpl(String description, VirtualMachineImpl vmImpl, + ReferenceTypeImpl declaringType, String name, String signature, + String genericSignature, int modifierBits) { + super(description, vmImpl); + fName = name; + fSignature = signature; + fGenericSignature = genericSignature; + fDeclaringType = declaringType; + fModifierBits = modifierBits; + } + + /** + * @return Returns modifier bits. + */ + @Override + public int modifiers() { + return fModifierBits; + } + + /** + * @return Returns the ReferenceTypeImpl in which this component was + * declared. + */ + public ReferenceTypeImpl referenceTypeImpl() { + return fDeclaringType; + } + + /** + * @return Returns the type in which this component was declared. + */ + @Override + public ReferenceType declaringType() { + return fDeclaringType; + } + + /** + * @return Returns true if type component is final. + */ + @Override + public boolean isFinal() { + return (fModifierBits & MODIFIER_ACC_FINAL) != 0; + } + + /** + * @return Returns true if type component is static. + */ + @Override + public boolean isStatic() { + return (fModifierBits & MODIFIER_ACC_STATIC) != 0; + } + + /** + * @return Returns true if type component is synthetic. + */ + @Override + public boolean isSynthetic() { + return (fModifierBits & (MODIFIER_SYNTHETIC | MODIFIER_ACC_SYNTHETIC)) != 0; + } + + /** + * @return Returns text representation of this type. + */ + @Override + public String name() { + return fName; + } + + /** + * @return JNI-style signature for this type. + */ + @Override + public String signature() { + return fSignature; + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + return fName; + } + + @Override + public String genericSignature() { + return fGenericSignature; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/TypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/TypeImpl.java new file mode 100644 index 0000000000..5cd3a4f6c2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/TypeImpl.java @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.ClassLoaderReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class TypeImpl extends AccessibleImpl implements Type { + /** Text representation of this type. */ + protected String fName = null; + /** JNI-style signature for this type. */ + protected String fSignature = null; + + /** + * Creates new instance, used for REFERENCE types. + */ + protected TypeImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * Creates new instance, used for PRIMITIVE types or VOID. + */ + protected TypeImpl(String description, VirtualMachineImpl vmImpl, + String name, String signature) { + super(description, vmImpl); + setName(name); + setSignature(signature); + } + + /** + * @return Returns new instance based on signature and (if it is a + * ReferenceType) classLoader. + * @throws ClassNotLoadedException + * when type is a ReferenceType and it has not been loaded by + * the specified class loader. + */ + public static TypeImpl create(VirtualMachineImpl vmImpl, String signature, + ClassLoaderReference classLoader) throws ClassNotLoadedException { + // For void values, a VoidType is always returned. + if (isVoidSignature(signature)) + return new VoidTypeImpl(vmImpl); + + // For primitive variables, an appropriate PrimitiveType is always + // returned. + if (isPrimitiveSignature(signature)) + return PrimitiveTypeImpl.create(vmImpl, signature); + + // For object variables, the appropriate ReferenceType is returned if it + // has + // been loaded through the enclosing type's class loader. + return ReferenceTypeImpl.create(vmImpl, signature, classLoader); + } + + /** + * Assigns name. + */ + public void setName(String name) { + fName = name; + } + + /** + * Assigns signature. + */ + public void setSignature(String signature) { + fSignature = signature; + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return name(); + } catch (ClassNotPreparedException e) { + return JDIMessages.TypeImpl__Unloaded_Type__1; + } catch (Exception e) { + return fDescription; + } + } + + /** + * @return Create a null value instance of the type. + */ + public abstract Value createNullValue(); + + /** + * @return Returns text representation of this type. + */ + @Override + public String name() { + return fName; + } + + /** + * @return JNI-style signature for this type. + */ + @Override + public String signature() { + return fSignature; + } + + /** + * @return Returns modifier bits. + */ + @Override + public abstract int modifiers(); + + /** + * Converts a class name to a JNI signature. + */ + public static String classNameToSignature(String qualifiedName) { + // L; : fully-qualified-class + /* + * JNI signature examples: int[][] -> [[I long[] -> [J java.lang.String + * -> Ljava/lang/String; java.lang.String[] -> [Ljava/lang/String; + */ + StringBuilder signature = new StringBuilder(); + + int firstBrace = qualifiedName.indexOf('['); + if (firstBrace < 0) { + // Not an array type. Must be class type. + signature.append('L'); + signature.append(qualifiedName.replace('.', '/')); + signature.append(';'); + return signature.toString(); + } + + int index = 0; + while ((index = (qualifiedName.indexOf('[', index) + 1)) > 0) { + signature.append('['); + } + + String name = qualifiedName.substring(0, firstBrace); + switch (name.charAt(0)) { + // Check for primitive array type + case 'b': + if (name.equals("byte")) { //$NON-NLS-1$ + signature.append('B'); + return signature.toString(); + } else if (name.equals("boolean")) { //$NON-NLS-1$ + signature.append('Z'); + return signature.toString(); + } + break; + case 'i': + if (name.equals("int")) { //$NON-NLS-1$ + signature.append('I'); + return signature.toString(); + } + break; + case 'd': + if (name.equals("double")) { //$NON-NLS-1$ + signature.append('D'); + return signature.toString(); + } + break; + case 's': + if (name.equals("short")) { //$NON-NLS-1$ + signature.append('S'); + return signature.toString(); + } + break; + case 'c': + if (name.equals("char")) { //$NON-NLS-1$ + signature.append('C'); + return signature.toString(); + } + break; + case 'l': + if (name.equals("long")) { //$NON-NLS-1$ + signature.append('J'); + return signature.toString(); + } + break; + case 'f': + if (name.equals("float")) { //$NON-NLS-1$ + signature.append('F'); + return signature.toString(); + } + break; + } + // Class type array + signature.append('L'); + signature.append(name.replace('.', '/')); + signature.append(';'); + return signature.toString(); + } + + /** + * Converts a JNI class signature to a name. + */ + public static String classSignatureToName(String signature) { + // L; : fully-qualified-class + return signature.substring(1, signature.length() - 1).replace('/', '.'); + } + + /** + * Converts a JNI array signature to a name. + */ + public static String arraySignatureToName(String signature) { + // [ : array of type + if (signature.indexOf('[') < 0) { + return signature; + } + StringBuilder name = new StringBuilder(); + String type = signature.substring(signature.lastIndexOf('[') + 1); + if (type.length() == 1 && isPrimitiveSignature(type)) { + name.append(getPrimitiveSignatureToName(type.charAt(0))); + } else { + name.append(classSignatureToName(type)); + } + int index = 0; + while ((index = (signature.indexOf('[', index) + 1)) > 0) { + name.append('[').append(']'); + } + return signatureToName(signature.substring(1)) + "[]"; //$NON-NLS-1$ + } + + /** + * @return Returns Type Name, converted from a JNI signature. + */ + public static String signatureToName(String signature) { + // See JNI 1.1 Specification, Table 3-2 Java VM Type Signatures. + String primitive = getPrimitiveSignatureToName(signature.charAt(0)); + if (primitive != null) { + return primitive; + } + switch (signature.charAt(0)) { + case 'V': + return "void"; //$NON-NLS-1$ + case 'L': + return classSignatureToName(signature); + case '[': + return arraySignatureToName(signature); + case '(': + throw new InternalError( + JDIMessages.TypeImpl_Can__t_convert_method_signature_to_name_2); + } + throw new InternalError(JDIMessages.TypeImpl_Invalid_signature____10 + + signature + JDIMessages.TypeImpl___11); // + } + + private static String getPrimitiveSignatureToName(char signature) { + switch (signature) { + case 'Z': + return "boolean"; //$NON-NLS-1$ + case 'B': + return "byte"; //$NON-NLS-1$ + case 'C': + return "char"; //$NON-NLS-1$ + case 'S': + return "short"; //$NON-NLS-1$ + case 'I': + return "int"; //$NON-NLS-1$ + case 'J': + return "long"; //$NON-NLS-1$ + case 'F': + return "float"; //$NON-NLS-1$ + case 'D': + return "double"; //$NON-NLS-1$ + default: + return null; + } + } + + /** + * @return Returns Jdwp Tag, converted from a JNI signature. + */ + public static byte signatureToTag(String signature) { + switch (signature.charAt(0)) { + case 'Z': + return BooleanValueImpl.tag; + case 'B': + return ByteValueImpl.tag; + case 'C': + return CharValueImpl.tag; + case 'S': + return ShortValueImpl.tag; + case 'I': + return IntegerValueImpl.tag; + case 'J': + return LongValueImpl.tag; + case 'F': + return FloatValueImpl.tag; + case 'D': + return DoubleValueImpl.tag; + case 'V': + return VoidValueImpl.tag; + case 'L': + return ObjectReferenceImpl.tag; + case '[': + return ArrayReferenceImpl.tag; + case '(': + throw new InternalError( + JDIMessages.TypeImpl_Can__t_covert_method_signature_to_tag___9 + + signature); + } + throw new InternalError(JDIMessages.TypeImpl_Invalid_signature____10 + + signature + JDIMessages.TypeImpl___11); // + } + + /** + * @return Returns true if signature is an primitive signature. + */ + public static boolean isPrimitiveSignature(String signature) { + switch (signature.charAt(0)) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + case 'J': + case 'F': + case 'D': + return true; + } + return false; + } + + /** + * @return Returns true if signature is void signature. + */ + public static boolean isVoidSignature(String signature) { + return (signature.charAt(0) == 'V'); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ValueCache.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ValueCache.java new file mode 100644 index 0000000000..df6b640b2a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ValueCache.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * This class is used to cache values. It uses soft references to store cached + * values. Once a value is garbage collected by the VM, the corresponding entry + * is removed from the cache on the next invocation of put() or get(). + * + * Note that WeakHashMap can't be used for this purpose because in WeakHashMap + * soft references are only used for the keys, and values may not have 'strong' + * references to keys otherwise they will never be garbage collected. + * + */ +public class ValueCache { + /** + * Map to store pairs, where Reference is a soft reference + * to an Object. + */ + private final Map> cacheTable = new Hashtable<>(); + /** + * Map to store pairs, to find the cacheTable-key of a + * garbage collected Reference. + */ + private final Map, Object> refTable = new Hashtable<>(); + + /** + * The reference-queue that is registered with the soft references. The + * garbage collector will enqueue soft references that are garbage + * collected. + */ + private final ReferenceQueue refQueue = new ReferenceQueue<>(); + + /** + * Clean up all entries from the table for which the values were garbage + * collected. + */ + private void cleanup() { + Reference ref; + while ((ref = refQueue.poll()) != null) { + Object key = refTable.get(ref); + if (key != null) + cacheTable.remove(key); + refTable.remove(ref); + } + } + + /** + * Put a new entry in the cache under the given key. + */ + public void put(Object key, Object value) { + cleanup(); + SoftReference ref = new SoftReference<>(value, refQueue); + cacheTable.put(key, ref); + refTable.put(ref, key); + } + + /** + * Get entry from the cache. + * + * @return Returns value that is cached under the given key, or null of one + * of the following is true: - The value has not been cached. - The + * value had been cached but is garbage collected. + */ + public Object get(Object key) { + cleanup(); + Object value = null; + SoftReference ref = cacheTable.get(key); + if (ref != null) { + value = ref.get(); + } + return value; + } + + /** + * Returns a Collection view of the values contained in this cache. + */ + public Collection values() { + cleanup(); + List returnValues = new ArrayList<>(); + synchronized (cacheTable) { + Iterator> iter = cacheTable.values().iterator(); + SoftReference ref; + Object value; + while (iter.hasNext()) { + ref = iter.next(); + value = ref.get(); + if (value != null) { + returnValues.add(value); + } + } + } + return returnValues; + } + + /** + * Returns a Collection view of the values contained in this cache that have + * the same runtime class as the given Class. + */ + public Collection valuesWithType(Class type) { + cleanup(); + List returnValues = new ArrayList<>(); + synchronized (cacheTable) { + Iterator> iter = cacheTable.values().iterator(); + SoftReference ref; + Object value; + while (iter.hasNext()) { + ref = iter.next(); + value = ref.get(); + if (value != null && value.getClass().equals(type)) { + returnValues.add(value); + } + } + } + return returnValues; + } + + /** + * Removes the key and its corresponding value from this cache. + * + * @return Returns The value to which the key had been mapped in this + * hashtable, or null if the key did not have a mapping. + */ + public Object remove(Object key) { + cleanup(); + Object value = null; + SoftReference ref = cacheTable.get(key); + if (ref != null) { + value = ref.get(); + refTable.remove(ref); + } + cacheTable.remove(key); + return value; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ValueImpl.java new file mode 100644 index 0000000000..ecc0caba3f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ValueImpl.java @@ -0,0 +1,354 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.jdwp.JdwpID; +import org.eclipse.jdi.internal.jdwp.JdwpObjectID; + +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.InternalException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.PrimitiveType; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; +import com.sun.jdi.Value; +import com.sun.jdi.VoidType; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class ValueImpl extends MirrorImpl implements Value { + /** + * Creates new ValueImpl. + */ + protected ValueImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * @return type of value. + */ + @Override + public abstract Type type(); + + /** + * @return type of value. + */ + public abstract byte getTag(); + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ValueImpl readWithTag(MirrorImpl target, DataInputStream in) + throws IOException { + byte tag = target.readByte("object tag", JdwpID.tagMap(), in); //$NON-NLS-1$ + return readWithoutTag(target, tag, in); + } + + /** + * @return Reads JDWP representation and returns new instance. + */ + public static ValueImpl readWithoutTag(MirrorImpl target, int type, + DataInputStream in) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + // See also ArrayReference Impl. + switch (type) { + case ArrayReferenceImpl.tag: + return ArrayReferenceImpl.read(target, in); + case ClassLoaderReferenceImpl.tag: + return ClassLoaderReferenceImpl.read(target, in); + case ClassObjectReferenceImpl.tag: + return ClassObjectReferenceImpl.read(target, in); + case StringReferenceImpl.tag: + return StringReferenceImpl.read(target, in); + case ObjectReferenceImpl.tag: + return ObjectReferenceImpl.readObjectRefWithoutTag(target, in); + case ThreadGroupReferenceImpl.tag: + return ThreadGroupReferenceImpl.read(target, in); + case ThreadReferenceImpl.tag: + return ThreadReferenceImpl.read(target, in); + case BooleanValueImpl.tag: + return BooleanValueImpl.read(target, in); + case ByteValueImpl.tag: + return ByteValueImpl.read(target, in); + case CharValueImpl.tag: + return CharValueImpl.read(target, in); + case DoubleValueImpl.tag: + return DoubleValueImpl.read(target, in); + case FloatValueImpl.tag: + return FloatValueImpl.read(target, in); + case IntegerValueImpl.tag: + return IntegerValueImpl.read(target, in); + case LongValueImpl.tag: + return LongValueImpl.read(target, in); + case ShortValueImpl.tag: + return ShortValueImpl.read(target, in); + case VoidValueImpl.tag: + return new VoidValueImpl(vmImpl); + case 0: + return null; + default: + throw new InternalException( + JDIMessages.ValueImpl_Invalid_Value_tag_encountered___1 + + type); + } + } + + /** + * Writes value with value tag. + */ + public void writeWithTag(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeByte(getTag(), "tag", JdwpID.tagMap(), out); //$NON-NLS-1$ + write(target, out); + } + + /** + * Writes value without value tag. + */ + public abstract void write(MirrorImpl target, DataOutputStream out) + throws IOException; + + /** + * Writes null value without value tag. + */ + public static void writeNull(MirrorImpl target, DataOutputStream out) + throws IOException { + JdwpObjectID nullID = new JdwpObjectID(target.virtualMachineImpl()); + nullID.write(out); + if (target.fVerboseWriter != null) { + target.fVerboseWriter.println("objectReference", nullID.value()); //$NON-NLS-1$ + } + } + + /** + * Writes null value with value tag. + */ + public static void writeNullWithTag(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeByte(ObjectReferenceImpl.tag, "tag", JdwpID.tagMap(), out); //$NON-NLS-1$ + writeNull(target, out); + } + + /** + * Check the type and the vm of each values, according to the associated + * type. For primitive values, convert the value for match the given type if + * needed. The two list must have the same size. + * + * @return the (converted) values. + * @see checkValue(Value, Type, VirtualMachineImpl) + */ + protected static List checkValues(List values, List types, + VirtualMachineImpl vm) throws InvalidTypeException { + List result = new ArrayList<>(values.size()); + Iterator iterValues = values.iterator(); + Iterator iterTypes = types.iterator(); + while (iterValues.hasNext()) { + Value value = iterValues.next(); + Type type = iterTypes.next(); + result.add(checkValue(value, type, vm)); + } + return result; + } + + /** + * Check the type and the vm of the given value. In case of primitive value, + * the value is converted if needed. + * + * @return the (converted) value. + * @throws InvalidTypeException + * if the given value is no assignment compatible with the given + * type. + * @see checkPrimitiveValue(PrimitiveValueImpl, PrimitiveTypeImpl, + * PrimitiveTypeImpl) + */ + public static ValueImpl checkValue(Value value, Type type, + VirtualMachineImpl vm) throws InvalidTypeException { + if (value == null) { + if (!(type instanceof PrimitiveType)) { + return null; + } + } else { + vm.checkVM(value); + TypeImpl valueType = (TypeImpl) value.type(); + if (valueType instanceof PrimitiveType + && type instanceof PrimitiveType) { + return checkPrimitiveValue((PrimitiveValueImpl) value, + (PrimitiveTypeImpl) valueType, (PrimitiveTypeImpl) type); + } + if (valueType instanceof ReferenceType + && type instanceof ReferenceType) { + checkReferenceType((ReferenceType) valueType, + (ReferenceType) type); + return (ValueImpl) value; + } + if (valueType instanceof VoidType && type instanceof VoidType) { + return (VoidValueImpl) value; + } + } + throw new InvalidTypeException( + MessageFormat + .format(JDIMessages.ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1, + new Object[] { + value != null ? value.type().name() + : "null", type.name() })); //$NON-NLS-1$ + } + + /** + */ + private static void checkReferenceType(ReferenceType valueType, + ReferenceType type) throws InvalidTypeException { + if (valueType instanceof ArrayType) { + if (type instanceof ArrayType) { + try { + Type valueComponentType = ((ArrayType) valueType) + .componentType(); + Type componentType = ((ArrayType) type).componentType(); + if (valueComponentType instanceof PrimitiveType) { + if (valueComponentType.equals(componentType)) { + return; + } + } else if (valueComponentType instanceof ReferenceType + && componentType instanceof ReferenceType) { + checkReferenceType((ReferenceType) valueComponentType, + (ReferenceType) componentType); + return; + } + } catch (ClassNotLoadedException e) { + // should not append + } + } else { + // an array can be assigned to an object + if (type.signature().equals("Ljava/lang/Object;")) { //$NON-NLS-1$ + return; + } + } + } else { + if (type instanceof ClassType) { + if (valueType instanceof ClassType) { + ClassType superClass = (ClassType) valueType; + while (superClass != null) { + if (superClass.equals(type)) { + return; + } + superClass = superClass.superclass(); + } + } else if (valueType instanceof InterfaceType) { + // an interface can be assigned to an object + if (type.signature().equals("Ljava/lang/Object;")) { //$NON-NLS-1$ + return; + } + } + } else if (type instanceof InterfaceType) { + if (valueType instanceof InterfaceType) { + if (checkInterfaceType((InterfaceType) valueType, + (InterfaceType) type)) { + return; + } + } else { + for (InterfaceType interfaceType : ((ClassType) valueType).allInterfaces()) { + if (checkInterfaceType(interfaceType, + (InterfaceType) type)) { + return; + } + } + } + } + } + + throw new InvalidTypeException( + MessageFormat + .format(JDIMessages.ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1, + new Object[] { valueType.name(), type.name() })); + } + + private static boolean checkInterfaceType(InterfaceType valueType, + InterfaceType type) { + if (valueType.equals(type)) { + return true; + } + for (InterfaceType interfaceType : valueType.superinterfaces()) { + if (checkInterfaceType(interfaceType, type)) { + return true; + } + } + return false; + } + + /** + * Check the type of the given value, and convert the value to the given + * type if needed (see Java Language Spec, section 5.2). + * + * @return the (converted) value. + * @throws InvalidTypeException + * if the given value is no assignment compatible with the given + * type. + */ + protected static ValueImpl checkPrimitiveValue(PrimitiveValueImpl value, + PrimitiveTypeImpl valueType, PrimitiveTypeImpl type) + throws InvalidTypeException { + char valueTypeSignature = valueType.signature().charAt(0); + char typeSignature = type.signature().charAt(0); + if (valueTypeSignature == typeSignature) { + return value; + } + VirtualMachineImpl vm = value.virtualMachineImpl(); + switch (typeSignature) { + case 'D': + if (valueTypeSignature != 'Z') { + return new DoubleValueImpl(vm, Double.valueOf(value.doubleValue())); + } + break; + case 'F': + if (valueTypeSignature != 'Z' && valueTypeSignature != 'D') { + return new FloatValueImpl(vm, Float.valueOf(value.floatValue())); + } + break; + case 'J': + if (valueTypeSignature != 'Z' && valueTypeSignature != 'D' + && valueTypeSignature != 'F') { + return new LongValueImpl(vm, Long.valueOf(value.longValue())); + } + break; + case 'I': + if (valueTypeSignature == 'B' || valueTypeSignature == 'C' + || valueTypeSignature == 'S') { + return new IntegerValueImpl(vm, Integer.valueOf(value.intValue())); + } + break; + case 'S': + if (valueTypeSignature == 'B') { + return new ShortValueImpl(vm, Short.valueOf(value.shortValue())); + } + break; + } + throw new InvalidTypeException( + MessageFormat + .format(JDIMessages.ValueImpl_Type_of_the_value_not_compatible_with_the_expected_type__1, + new Object[] { valueType.name(), type.name() })); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VerboseWriter.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VerboseWriter.java new file mode 100644 index 0000000000..071f8583b8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VerboseWriter.java @@ -0,0 +1,615 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +public class VerboseWriter { + /** Length of verbose description. */ + public static final int VERBOSE_DESCRIPTION_LENGTH = 21; + /** Number of hexadecimal verbose bytes per line. */ + public static final int VERBOSE_HEX_BYTES_PER_LINE = 16; + /** Width of hex dump. */ + public static final int VERBOSE_HEX_WIDTH = 16 * 3 + 2; + + /** + * Number extra verbose lines. These are caused by hex dumps that span more + * than one line. + */ + volatile int fExtraVerboseLines = 0; + + /** PrintWriter that is written to. */ + private final PrintWriter fOutput; + /** Buffer for output: one StringBuilder entry per line. */ + private final List fLineBuffer; + /** Position from where buffer is written to. */ + private volatile int fPosition; + /** True if the current line has not yet been written to. */ + private volatile boolean fNewLine = true; + + /** + * Creates new VerboseWriter that writes to the given PrintWriter. Output is + * buffered and previous entries in the buffer can be rewritten. + */ + public VerboseWriter(PrintWriter out) { + fOutput = out; + fLineBuffer = new Vector<>(); + fPosition = 0; + fLineBuffer.add(new StringBuffer()); + } + + /** + * Terminate the current line by writing the line separator string. If + * autoflush is set and there are extra vebose lines caused by printHex, + * these lines are also printed. + */ + public synchronized void println() { + while (fExtraVerboseLines > 0) { + fExtraVerboseLines--; + markLn(); + } + + markLn(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, byte value) { + printDescription(description); + printHex(value); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, short value) { + printDescription(description); + printHex(value); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, int value) { + printDescription(description); + printHex(value); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, long value) { + printDescription(description); + printHex(value); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, byte value, Map valueToString) { + printDescription(description); + printHex(value); + printValue(value, valueToString); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, short value, Map valueToString) { + printDescription(description); + printHex(value); + printValue(value, valueToString); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, int value, Map valueToString) { + printDescription(description); + printHex(value); + printValue(value, valueToString); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, byte value, String[] bitNames) { + printDescription(description); + printHex(value); + printValue(value, bitNames); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, short value, String[] bitNames) { + printDescription(description); + printHex(value); + printValue(value, bitNames); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, int value, String[] bitNames) { + printDescription(description); + printHex(value); + printValue(value, bitNames); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, String value) { + printDescription(description); + printHex(value); + print(value); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, boolean value) { + printDescription(description); + printHex(value); + print(Boolean.toString(value)); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, char value) { + printDescription(description); + printHex(value); + print(value); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, double value) { + printDescription(description); + printHex(value); + print(Double.toString(value)); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, float value) { + printDescription(description); + printHex(value); + print(Float.toString(value)); + println(); + } + + /** + * Prints verbose line. + */ + public synchronized void println(String description, byte[] value) { + printDescription(description); + printHex(value); + println(); + } + + /** + * Prints string with right size. + */ + public synchronized void printWidth(String str, int width) { + print(str); + int spaces = width - str.length(); + if (spaces > 0) { + for (int i = 0; i < spaces; i++) { + print(' '); + } + } + } + + /** + * Prints description string with right size plus its seperator spaces. + */ + public synchronized void printDescription(String str) { + printWidth(str, VERBOSE_DESCRIPTION_LENGTH); + } + + /** + * Prints hex substitution string with right size plus its seperator spaces. + */ + public synchronized void printHexSubstitution(String str) { + // Note that bytes also start with a space. + print(' '); + printWidth(str, VERBOSE_HEX_WIDTH - 1); + } + + /** + * Appends hex representation of given byte to an array. + */ + private static void appendHexByte(byte b, char[] buffer, int pos) { + int count = 2; + + int abspos = 3 * pos; + buffer[abspos] = ' '; + do { + int t = b & 15; + if (t > 9) { + t = t - 10 + 'a'; + } else { + t += '0'; + } + buffer[count-- + abspos] = (char) t; + b >>>= 4; + } while (count > 0); + } + + /** + * Appends remaining spaces to hex dump. + */ + private static void appendHexSpaces(char[] buffer, int pos) { + for (int i = 3 * pos; i <= VERBOSE_HEX_WIDTH - 3; i += 3) { + buffer[i] = ' '; + buffer[i + 1] = ' '; + buffer[i + 2] = ' '; + } + + // Two extra spaces as seperator + buffer[VERBOSE_HEX_WIDTH - 1] = ' '; + buffer[VERBOSE_HEX_WIDTH - 2] = ' '; + } + + /** + * Prints hex representation of a byte. + */ + public synchronized void printHex(byte b) { + char buffer[] = new char[VERBOSE_HEX_WIDTH]; + appendHexByte(b, buffer, 0); + appendHexSpaces(buffer, 1); + print(buffer); + } + + /** + * Prints hex representation of an int. + */ + public synchronized void printHex(short s) { + char buffer[] = new char[VERBOSE_HEX_WIDTH]; + for (int i = 1; i >= 0; i--) { + appendHexByte((byte) (s >>> i * 8), buffer, 1 - i); + } + appendHexSpaces(buffer, 2); + print(buffer); + } + + /** + * Prints hex representation of an int. + */ + public synchronized void printHex(int integer) { + char buffer[] = new char[VERBOSE_HEX_WIDTH]; + for (int i = 3; i >= 0; i--) { + appendHexByte((byte) (integer >>> i * 8), buffer, 3 - i); + } + appendHexSpaces(buffer, 4); + print(buffer); + } + + /** + * Prints hex representation of a long. + */ + public synchronized void printHex(long l) { + char buffer[] = new char[VERBOSE_HEX_WIDTH]; + for (int i = 7; i >= 0; i--) { + appendHexByte((byte) (l >>> i * 8), buffer, 7 - i); + } + appendHexSpaces(buffer, 8); + print(buffer); + } + + /** + * Prints hex representation of a long. + * @param b the boolean + */ + public synchronized void printHex(boolean b) { + printHexSubstitution(""); //$NON-NLS-1$ + } + + /** + * Prints hex representation of a long. + * @param c the char + */ + public synchronized void printHex(char c) { + printHexSubstitution(""); //$NON-NLS-1$ + } + + /** + * Prints hex representation of a long. + * @param d the double + */ + public synchronized void printHex(double d) { + printHexSubstitution(""); //$NON-NLS-1$ + } + + /** + * Prints hex representation of a long. + * @param f the float + */ + public synchronized void printHex(float f) { + printHexSubstitution(""); //$NON-NLS-1$ + } + + /** + * Prints hex representation of a String. + * @param str the string + */ + public synchronized void printHex(String str) { + printHexSubstitution(""); //$NON-NLS-1$ + } + + /** + * Prints hex representation of a byte array. Note that this can span more + * than one line, but is considered to be part of one 'verbose line'. + * Therefore, a println after a printHex can result in more than one line + * being printed to the PrintWriter. + */ + public synchronized void printHex(byte[] bytes) { + int startPosition = position(); + char linebuf[] = new char[VERBOSE_HEX_WIDTH]; + int extraLines = 0; + int byteOnLine = 0; + + for (byte b : bytes) { + if (byteOnLine == VERBOSE_HEX_BYTES_PER_LINE) { + appendHexSpaces(linebuf, VERBOSE_HEX_BYTES_PER_LINE); + if (extraLines++ > 0) { + printDescription(""); //$NON-NLS-1$ + } + print(linebuf); + markLn(); + byteOnLine = 0; + } + appendHexByte(b, linebuf, byteOnLine++); + } + appendHexSpaces(linebuf, byteOnLine); + if (extraLines > 0) { + printDescription(""); //$NON-NLS-1$ + } + + fExtraVerboseLines += extraLines; + print(linebuf); + if (extraLines > 0) { + gotoPosition(startPosition); + } + } + + /** + * Prints string representation of a value given a Map from values to + * strings. + */ + public synchronized void printValue(int value, Map valueToString) { + Integer val = Integer.valueOf(value); + if (valueToString == null) { + print(val.toString()); + return; + } + String result = valueToString.get(val); + if (result == null) { + print(val.toString() + JDIMessages.VerboseWriter___unknown_value__1); + } else { + print(result); + } + } + + /** + * Prints string representation of a value given a Vector with the names of + * the bits. + */ + public synchronized void printValue(byte value, String[] bitNames) { + printValue(value & 0xff, bitNames); + } + + /** + * Prints string representation of a value given a Vector with the names of + * the bits. + */ + public synchronized void printValue(short value, String[] bitNames) { + printValue(value & 0xffff, bitNames); + } + + /** + * Prints string representation of a value given a Vector with the names of + * the bits. + */ + public synchronized void printValue(int value, String[] bitNames) { + Integer val = Integer.valueOf(value); + if (bitNames == null) { + print(val.toString()); + return; + } + + boolean bitsSet = false; + + for (int i = 0; i < bitNames.length; i++) { + // Test if bit is set in value. + if ((1 << i & value) == 0) { + continue; + } + + // See if we have a desciption for the bit. + String bitString = bitNames[i]; + if (bitString == null) { + bitString = JDIMessages.VerboseWriter__unknown_bit__2; + } + + if (!bitsSet) { + print(bitString); + } else { + print(" & "); //$NON-NLS-1$ + print(bitString); + } + bitsSet = true; + } + + if (!bitsSet) { + print(JDIMessages.VerboseWriter__none__4); + } + } + + /** + * Checks if a new line is written to. If so, first erase any data on that + * line. Line is marked 'not new' after this command. + */ + private void checkForNewLine() { + if (fNewLine) { + getCurrentBuffer().setLength(0); + fNewLine = false; + } + } + + /** + * Print a String. + */ + public synchronized void print(String str) { + checkForNewLine(); + getCurrentBuffer().append(str); + } + + /** + * Print a Character. + */ + public synchronized void print(char c) { + checkForNewLine(); + getCurrentBuffer().append(c); + } + + private StringBuffer getCurrentBuffer() { + return fLineBuffer.get(nextPosition()); + } + + private int nextPosition() { + int pos = fPosition; + if (pos >= fLineBuffer.size()) { + pos = fLineBuffer.size() - 1; + } + if (pos < 0) { + pos = 0; + } + return pos; + } + + /** + * Print array of Characters. + */ + public synchronized void print(char[] c) { + checkForNewLine(); + getCurrentBuffer().append(c); + } + + /** + * Print a String and then terminate the line. + */ + public synchronized void println(String str) { + print(str); + println(); + } + + /** + * Flush buffer. If autoflush is off, this method is synchronized on the + * PrintWriter given in the constructor. + */ + public synchronized void flush() { + int bufSize = fLineBuffer.size(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + for (int i = 0; i < bufSize - 1; i++) { + pw.println(fLineBuffer.get(i)); + } + + // The last line should be printed without an extra newline + StringBuffer lastLine = fLineBuffer.get(bufSize - 1); + if (lastLine.length() > 0) { + pw.print(lastLine); + } + fLineBuffer.clear(); + fPosition = 0; + fLineBuffer.add(new StringBuffer()); + // sync on fOutput to avoid writing from multiple writer instances + synchronized (fOutput) { + fOutput.print(sw.toString()); + fOutput.flush(); + } + } + + public synchronized void printStackTrace(Throwable t) { + t.printStackTrace(fOutput); + } + + /** + * Go to the given position in the buffer. If the given position is smaller + * than the current position, subsequent print commands overwrite existing + * lines in the buffer. Else, new lines are added to the buffer. + */ + public synchronized void gotoPosition(int pos) { + int delta = pos - fPosition; + if (delta < 0) { + fPosition = pos; + } else { + while (delta-- > 0) { + println(); + } + } + } + + /** + * Prints given number of lines. + */ + public synchronized void printLines(int lines) { + gotoPosition(fPosition + lines); + } + + /** + * @return Returns current position in buffer. + */ + public int position() { + return fPosition; + } + + /** + * Terminate the current line by writing the line separator string, start at + * end of next line. + */ + public synchronized void markLn() { + if (++fPosition == fLineBuffer.size()) { + fLineBuffer.add(new StringBuffer()); + } + + fNewLine = true; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VirtualMachineImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VirtualMachineImpl.java new file mode 100644 index 0000000000..9a712df725 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VirtualMachineImpl.java @@ -0,0 +1,1616 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdi.Bootstrap; +import org.eclipse.jdi.internal.connect.PacketReceiveManager; +import org.eclipse.jdi.internal.connect.PacketSendManager; +import org.eclipse.jdi.internal.event.EventQueueImpl; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpObjectID; +import org.eclipse.jdi.internal.jdwp.JdwpReferenceTypeID; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdi.internal.request.EventRequestManagerImpl; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.BooleanValue; +import com.sun.jdi.ByteValue; +import com.sun.jdi.CharValue; +import com.sun.jdi.DoubleValue; +import com.sun.jdi.FloatValue; +import com.sun.jdi.IntegerValue; +import com.sun.jdi.LongValue; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ShortValue; +import com.sun.jdi.StringReference; +import com.sun.jdi.ThreadGroupReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.VoidValue; +import com.sun.jdi.connect.spi.Connection; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.request.EventRequestManager; + +/** + * This class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class VirtualMachineImpl extends MirrorImpl implements VirtualMachine, + org.eclipse.jdi.hcr.VirtualMachine, org.eclipse.jdi.VirtualMachine { + /** Result flags for Classes Have Changed command. */ + public static final byte HCR_RELOAD_SUCCESS = 0; + public static final byte HCR_RELOAD_FAILURE = 1; + public static final byte HCR_RELOAD_IGNORED = 2; + + /* Indexes in HCR capabilities list. */ + private static final int HCR_CAN_RELOAD_CLASSES = 0; + private static final int HCR_CAN_GET_CLASS_VERSION = 1; + private static final int HCR_CAN_DO_RETURN = 2; + private static final int HCR_CAN_REENTER_ON_EXIT = 3; + + protected static final String JAVA_STRATUM_NAME = "Java"; //$NON-NLS-1$ + + /** Timeout value for requests to VM if not overridden for a particular VM. */ + private int fRequestTimeout; + /** Mapping of command codes to strings. */ + + private static Map fgHCRResultMap = null; + + /** EventRequestManager that creates event objects on request. */ + private final EventRequestManagerImpl fEventReqMgr; + /** EventQueue that returns EventSets from the Virtual Manager. */ + private final EventQueueImpl fEventQueue; + + /** If a launching connector is used, we store the process. */ + private Process fLaunchedProcess; + + /** + * The following field contains cached Mirrors. Note that these are + * optional: their only purpose is to speed up the debugger by being able to + * use the stored results of JDWP calls. + */ + private final ValueCache fCachedReftypes = new ValueCache(); + private final ValueCache fCachedObjects = new ValueCache(); + + /** The following are the stored results of JDWP calls. */ + private String fVersionDescription = null; // Text information on the VM + // version. + private int fJdwpMajorVersion; + private int fJdwpMinorVersion; + private String fVMVersion; // Target VM JRE version, as in the java.version + // property. + private String fVMName; // Target VM name, as in the java.vm.name property. + private boolean fGotIDSizes = false; + private int fFieldIDSize; + private int fMethodIDSize; + private int fObjectIDSize; + private int fReferenceTypeIDSize; + private int fFrameIDSize; + + private boolean fGotCapabilities = false; + private boolean fCanWatchFieldModification; + private boolean fCanWatchFieldAccess; + private boolean fCanGetBytecodes; + private boolean fCanGetSyntheticAttribute; + private boolean fCanGetOwnedMonitorInfo; + private boolean fCanGetCurrentContendedMonitor; + private boolean fCanGetMonitorInfo; + private boolean fCanRedefineClasses; + private boolean fCanAddMethod; + private boolean fCanUnrestrictedlyRedefineClasses; + private boolean fCanPopFrames; + private boolean fCanUseInstanceFilters; + private boolean fCanGetSourceDebugExtension; + private boolean fCanRequestVMDeathEvent; + private boolean fCanSetDefaultStratum; + private boolean fCanGetInstanceInfo; + private boolean fCanGetConstantPool; + private boolean fCanUseSourceNameFilters; + private boolean fCanForceEarlyReturn; + private boolean fCanRequestMonitorEvents; + private boolean fCanGetMonitorFrameInfo; + private boolean[] fHcrCapabilities = null; + + /* + * singletons for primitive types + */ + private BooleanTypeImpl fBooleanType; + private ByteTypeImpl fByteType; + private CharTypeImpl fCharType; + private DoubleTypeImpl fDoubleType; + private FloatTypeImpl fFloatType; + private IntegerTypeImpl fIntegerType; + private LongTypeImpl fLongType; + private ShortTypeImpl fShortType; + + /** + * Disconnected flag + */ + private boolean fIsDisconnected = false; + + /** + * The name of the current default stratum. + */ + private String fDefaultStratum; + private final PacketReceiveManager fPacketReceiveManager; + private final PacketSendManager fPacketSendManager; + + /** + * Creates a new Virtual Machine. + */ + public VirtualMachineImpl(Connection connection) { + super("VirtualMachine"); //$NON-NLS-1$ + fEventReqMgr = new EventRequestManagerImpl(this); + fEventQueue = new EventQueueImpl(this); + fRequestTimeout = ((VirtualMachineManagerImpl) Bootstrap + .virtualMachineManager()).getGlobalRequestTimeout(); + + fPacketReceiveManager = new PacketReceiveManager(connection, this); + Thread receiveThread = new Thread(fPacketReceiveManager, + JDIMessages.VirtualMachineImpl_0); + receiveThread.setDaemon(true); + fPacketReceiveManager.setPartnerThread(receiveThread); + receiveThread.start(); + + fPacketSendManager = new PacketSendManager(connection); + Thread sendThread = new Thread(fPacketSendManager, + JDIMessages.VirtualMachineImpl_1); + sendThread.setDaemon(true); + fPacketReceiveManager.setPartnerThread(sendThread); + sendThread.start(); + } + + /** + * @return Returns size of JDWP ID. + */ + public final int fieldIDSize() { + return fFieldIDSize; + } + + /** + * @return Returns size of JDWP ID. + */ + public final int methodIDSize() { + return fMethodIDSize; + } + + /** + * @return Returns size of JDWP ID. + */ + public final int objectIDSize() { + return fObjectIDSize; + } + + /** + * @return Returns size of JDWP ID. + */ + public final int referenceTypeIDSize() { + return fReferenceTypeIDSize; + } + + /** + * @return Returns size of JDWP ID. + */ + public final int frameIDSize() { + return fFrameIDSize; + } + + /** + * @return Returns cached mirror object, or null if method is not in cache. + */ + public ReferenceTypeImpl getCachedMirror(JdwpReferenceTypeID ID) { + return (ReferenceTypeImpl) fCachedReftypes.get(ID); + } + + /** + * @return Returns cached mirror object, or null if method is not in cache. + */ + public ObjectReferenceImpl getCachedMirror(JdwpObjectID ID) { + return (ObjectReferenceImpl) fCachedObjects.get(ID); + } + + /** + * Adds mirror object to cache. + */ + public void addCachedMirror(ReferenceTypeImpl mirror) { + fCachedReftypes.put(mirror.getRefTypeID(), mirror); + // TBD: It is now yet possible to only ask for unload events for + // classes that we know of due to a limitation in the J9 VM. + // eventRequestManagerImpl().enableInternalClasUnloadEvent(mirror); + } + + /** + * Adds mirror object to cache. + */ + public void addCachedMirror(ObjectReferenceImpl mirror) { + fCachedObjects.put(mirror.getObjectID(), mirror); + } + + /** + * Flushes all stored Jdwp results. + */ + public void flushStoredJdwpResults() { + // All known classes also become invalid. + Iterator iter = fCachedReftypes.values().iterator(); + while (iter.hasNext()) { + ReferenceTypeImpl refType = (ReferenceTypeImpl) iter.next(); + refType.flushStoredJdwpResults(); + } + + fVersionDescription = null; + fGotIDSizes = false; + fHcrCapabilities = null; + } + + /* + * Removes a known class. A class/interface is known if we have ever + * received its ReferenceTypeID and we have not received an unload event for + * it. + */ + public final void removeKnownRefType(String signature) { + List refTypeList = classesBySignature(signature); + if (refTypeList.isEmpty()) { + return; + } + + // If we have only one known class for this signature, we known that + // this is the class + // to be removed. + if (refTypeList.size() == 1) { + ReferenceTypeImpl refType = (ReferenceTypeImpl) refTypeList.get(0); + refType.flushStoredJdwpResults(); + fCachedReftypes.remove(refType.getRefTypeID()); + return; + } + + // We have more than one known class for the signature, let's find the + // unloaded one(s). + Iterator iter = refTypeList.iterator(); + while (iter.hasNext()) { + ReferenceTypeImpl refType = (ReferenceTypeImpl) iter.next(); + boolean prepared = false; + try { + prepared = refType.isPrepared(); + } catch (ObjectCollectedException exception) { + // The type is unloaded. Fall through + } + if (!prepared) { + refType.flushStoredJdwpResults(); + iter.remove(); + fCachedReftypes.remove(refType.getRefTypeID()); + } + } + } + + /* + * @exception Throws UnsupportedOperationException if VM does not support J9 + * HCR. + */ + public void checkHCRSupported() throws UnsupportedOperationException { + if (!isHCRSupported()) { + throw new UnsupportedOperationException( + NLS.bind(JDIMessages.VirtualMachineImpl_Target_VM__0__does_not_support_Hot_Code_Replacement_1, new String[] { name() })); + } + } + + /* + * Returns whether J9 HCR is supported + */ + public boolean isHCRSupported() throws UnsupportedOperationException { + return name().equals("j9"); //$NON-NLS-1$ + } + + /* + * @return Returns Manager for receiving packets from the Virtual Machine. + */ + public final PacketReceiveManager packetReceiveManager() { + return fPacketReceiveManager; + } + + /* + * @return Returns Manager for sending packets to the Virtual Machine. + */ + public final PacketSendManager packetSendManager() { + /* + * Before we send out first bytes to the VM by JDI calls, we need some + * initial requests: - Get the sizes of the IDs (fieldID, method ID + * etc.) that the VM uses; - Request class prepare and unload events. We + * used these to cache classes/interfaces and map their signatures. + */ + if (!fGotIDSizes) { + getIDSizes(); + if (!fGotIDSizes) { // We can't do much without them. + disconnectVM(); + throw new VMDisconnectedException( + JDIMessages.VirtualMachineImpl_Failed_to_get_ID_sizes_2); + } + + // TBD: This call should be moved to addKnownRefType() when it can + // be made specific + // for a reference type. + eventRequestManagerImpl().enableInternalClasUnloadEvent(); + } + + return fPacketSendManager; + } + + /** + * Returns all loaded types (classes, interfaces, and array types). For each + * loaded type in the target VM a ReferenceType will be placed in the + * returned list. + */ + @Override + public List allClasses() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + boolean withGenericSignature = virtualMachineImpl() + .isJdwpVersionGreaterOrEqual(1, 5); + int jdwpCommand = withGenericSignature ? JdwpCommandPacket.VM_ALL_CLASSES_WITH_GENERIC + : JdwpCommandPacket.VM_ALL_CLASSES; + JdwpReplyPacket replyPacket = requestVM(jdwpCommand); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + List elements = new ArrayList<>(nrOfElements); + for (int i = 0; i < nrOfElements; i++) { + ReferenceTypeImpl elt = ReferenceTypeImpl + .readWithTypeTagAndSignature(this, + withGenericSignature, replyData); + if (elt == null) { + continue; + } + readInt("status", ReferenceTypeImpl.classStatusStrings(), replyData); //$NON-NLS-1$ + elements.add(elt); + } + return elements; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + + } + + /** + * @return Returns an iterator over all loaded classes. + */ + protected final Iterator allRefTypes() { + return allClasses().iterator(); + } + + /** + * @return Returns an iterator over all cached classes. + */ + protected final Iterator allCachedRefTypes() { + return fCachedReftypes.values().iterator(); + } + + /** + * Returns a list of the currently running threads. For each running thread + * in the target VM, a ThreadReference that mirrors it is placed in the + * list. + */ + @Override + public List allThreads() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_ALL_THREADS); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + List elements = new ArrayList<>(nrOfElements); + for (int i = 0; i < nrOfElements; i++) { + ThreadReferenceImpl elt = ThreadReferenceImpl.read(this, + replyData); + if (elt == null) { + continue; + } + elements.add(elt); + } + return elements; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Retrieve this VM's capabilities. + */ + public void getCapabilities() { + if (fGotCapabilities) { + return; + } + + int command = JdwpCommandPacket.VM_CAPABILITIES; + if (isJdwpVersionGreaterOrEqual(1, 4)) { + command = JdwpCommandPacket.VM_CAPABILITIES_NEW; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(command); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + fCanWatchFieldModification = readBoolean( + "watch field modification", replyData); //$NON-NLS-1$ + fCanWatchFieldAccess = readBoolean("watch field access", replyData); //$NON-NLS-1$ + fCanGetBytecodes = readBoolean("get bytecodes", replyData); //$NON-NLS-1$ + fCanGetSyntheticAttribute = readBoolean("synth. attr", replyData); //$NON-NLS-1$ + fCanGetOwnedMonitorInfo = readBoolean( + "owned monitor info", replyData); //$NON-NLS-1$ + fCanGetCurrentContendedMonitor = readBoolean( + "curr. contended monitor", replyData); //$NON-NLS-1$ + fCanGetMonitorInfo = readBoolean("monitor info", replyData); //$NON-NLS-1$ + if (command == JdwpCommandPacket.VM_CAPABILITIES_NEW) { + // extended capabilities + fCanRedefineClasses = readBoolean("redefine classes", replyData); //$NON-NLS-1$ + fCanAddMethod = readBoolean("add method", replyData); //$NON-NLS-1$ + fCanUnrestrictedlyRedefineClasses = readBoolean( + "unrestrictedly redefine classes", replyData); //$NON-NLS-1$ + fCanPopFrames = readBoolean("pop frames", replyData); //$NON-NLS-1$ + fCanUseInstanceFilters = readBoolean( + "use instance filters", replyData); //$NON-NLS-1$ + fCanGetSourceDebugExtension = readBoolean( + "get source debug extension", replyData); //$NON-NLS-1$ + fCanRequestVMDeathEvent = readBoolean( + "request vm death", replyData); //$NON-NLS-1$ + fCanSetDefaultStratum = readBoolean( + "set default stratum", replyData); //$NON-NLS-1$ + fCanGetInstanceInfo = readBoolean("instance info", replyData); //$NON-NLS-1$ + fCanRequestMonitorEvents = readBoolean( + "request monitor events", replyData); //$NON-NLS-1$ + fCanGetMonitorFrameInfo = readBoolean( + "monitor frame info", replyData); //$NON-NLS-1$ + fCanUseSourceNameFilters = readBoolean( + "source name filters", replyData); //$NON-NLS-1$ + fCanGetConstantPool = readBoolean("constant pool", replyData); //$NON-NLS-1$ + fCanForceEarlyReturn = readBoolean( + "force early return", replyData); //$NON-NLS-1$ + } else { + fCanRedefineClasses = false; + fCanAddMethod = false; + fCanUnrestrictedlyRedefineClasses = false; + fCanPopFrames = false; + fCanUseInstanceFilters = false; + fCanGetSourceDebugExtension = false; + fCanRequestVMDeathEvent = false; + fCanSetDefaultStratum = false; + fCanGetInstanceInfo = false; + fCanGetConstantPool = false; + fCanUseSourceNameFilters = false; + fCanForceEarlyReturn = false; + fCanRequestMonitorEvents = false; + fCanGetMonitorFrameInfo = false; + } + fGotCapabilities = true; + } catch (IOException e) { + fGotIDSizes = false; + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * @see com.sun.jdi.VirtualMachine#canForceEarlyReturn() + * @since 3.3 + */ + @Override + public boolean canForceEarlyReturn() { + getCapabilities(); + return fCanForceEarlyReturn; + } + + /** + * @return Returns true if this implementation supports the retrieval of a + * method's bytecodes. + */ + @Override + public boolean canGetBytecodes() { + getCapabilities(); + return fCanGetBytecodes; + } + + /** + * @return Returns true if this implementation supports the retrieval of the + * monitor for which a thread is currently waiting. + */ + @Override + public boolean canGetCurrentContendedMonitor() { + getCapabilities(); + return fCanGetCurrentContendedMonitor; + } + + /** + * @see com.sun.jdi.VirtualMachine#canGetInstanceInfo() + * @since 3.3 + */ + @Override + public boolean canGetInstanceInfo() { + getCapabilities(); + return fCanGetInstanceInfo; + } + + /** + * @see com.sun.jdi.VirtualMachine#canGetMethodReturnValues() + * @since 3.3 + */ + @Override + public boolean canGetMethodReturnValues() { + return isJdwpVersionGreaterOrEqual(1, 6); + } + + /** + * @return Returns true if this implementation supports the retrieval of the + * monitor information for an object. + */ + @Override + public boolean canGetMonitorInfo() { + getCapabilities(); + return fCanGetMonitorInfo; + } + + /** + * @see com.sun.jdi.VirtualMachine#canGetMonitorFrameInfo() + * @since 3.3 + */ + @Override + public boolean canGetMonitorFrameInfo() { + getCapabilities(); + return fCanGetMonitorFrameInfo; + } + + /** + * @return Returns true if this implementation supports the retrieval of the + * monitors owned by a thread. + */ + @Override + public boolean canGetOwnedMonitorInfo() { + getCapabilities(); + return fCanGetOwnedMonitorInfo; + } + + /** + * @return Returns true if this implementation supports the query of the + * synthetic attribute of a method or field. + */ + @Override + public boolean canGetSyntheticAttribute() { + getCapabilities(); + return fCanGetSyntheticAttribute; + } + + /** + * @see com.sun.jdi.VirtualMachine#canRequestMonitorEvents() + * @since 3.3 + */ + @Override + public boolean canRequestMonitorEvents() { + getCapabilities(); + return fCanRequestMonitorEvents; + } + + /** + * @return Returns true if this implementation supports watchpoints for + * field access. + */ + @Override + public boolean canWatchFieldAccess() { + getCapabilities(); + return fCanWatchFieldAccess; + } + + /** + * @return Returns true if this implementation supports watchpoints for + * field modification. + */ + @Override + public boolean canWatchFieldModification() { + getCapabilities(); + return fCanWatchFieldModification; + } + + /** + * @return Returns the loaded reference types that match a given signature. + */ + public List classesBySignature(String signature) { + // Note that this information should not be cached. + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeString(signature, "signature", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.VM_CLASSES_BY_SIGNATURE, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ + List elements = new ArrayList<>(nrOfElements); + for (int i = 0; i < nrOfElements; i++) { + ReferenceTypeImpl elt = ReferenceTypeImpl.readWithTypeTag(this, + replyData); + readInt("status", ReferenceTypeImpl.classStatusStrings(), replyData); //$NON-NLS-1$ + if (elt == null) { + continue; + } + elements.add(elt); + } + return elements; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#classesByName(java.lang.String) + */ + @Override + public List classesByName(String name) { + String signature = TypeImpl.classNameToSignature(name); + return classesBySignature(signature); + } + + /** + * Invalidates this virtual machine mirror. + */ + @Override + public void dispose() { + initJdwpRequest(); + try { + requestVM(JdwpCommandPacket.VM_DISPOSE); + disconnectVM(); + } catch (VMDisconnectedException e) { + // The VM can exit before we receive the reply. + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#eventQueue() + */ + @Override + public EventQueue eventQueue() { + return fEventQueue; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#eventRequestManager() + */ + @Override + public EventRequestManager eventRequestManager() { + return fEventReqMgr; + } + + /** + * @return Returns EventRequestManagerImpl that creates all event objects on + * request. + */ + public EventRequestManagerImpl eventRequestManagerImpl() { + return fEventReqMgr; + } + + /** + * Causes the mirrored VM to terminate with the given error code. + */ + @Override + public void exit(int exitCode) { + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeInt(exitCode, "exit code", outData); //$NON-NLS-1$ + requestVM(JdwpCommandPacket.VM_EXIT, outBytes); + disconnectVM(); + } catch (VMDisconnectedException e) { + // The VM can exit before we receive the reply. + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(byte) + */ + @Override + public ByteValue mirrorOf(byte value) { + return new ByteValueImpl(virtualMachineImpl(), Byte.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(char) + */ + @Override + public CharValue mirrorOf(char value) { + return new CharValueImpl(virtualMachineImpl(), Character.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(double) + */ + @Override + public DoubleValue mirrorOf(double value) { + return new DoubleValueImpl(virtualMachineImpl(), Double.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(float) + */ + @Override + public FloatValue mirrorOf(float value) { + return new FloatValueImpl(virtualMachineImpl(), Float.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(int) + */ + @Override + public IntegerValue mirrorOf(int value) { + return new IntegerValueImpl(virtualMachineImpl(), Integer.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(long) + */ + @Override + public LongValue mirrorOf(long value) { + return new LongValueImpl(virtualMachineImpl(), Long.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(short) + */ + @Override + public ShortValue mirrorOf(short value) { + return new ShortValueImpl(virtualMachineImpl(), Short.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(boolean) + */ + @Override + public BooleanValue mirrorOf(boolean value) { + return new BooleanValueImpl(virtualMachineImpl(), + Boolean.valueOf(value)); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOf(java.lang.String) + */ + @Override + public StringReference mirrorOf(String value) { + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeString(value, "string value", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.VM_CREATE_STRING, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + StringReference result = StringReferenceImpl.read(this, replyData); + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#mirrorOfVoid() + */ + @Override + public VoidValue mirrorOfVoid() { + return new VoidValueImpl(this); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#process() + */ + @Override + public Process process() { + return fLaunchedProcess; + } + + /** + * Sets Process object for this virtual machine if launched by a + * LaunchingConnector. + */ + public void setLaunchedProcess(Process proc) { + fLaunchedProcess = proc; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#resume() + */ + @Override + public void resume() { + initJdwpRequest(); + try { + resetThreadEventFlags(); + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_RESUME); + defaultReplyErrorHandler(replyPacket.errorCode()); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#setDebugTraceMode(int) + */ + @Override + public void setDebugTraceMode(int traceFlags) { + // We don't have trace info. + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#suspend() + */ + @Override + public void suspend() { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_SUSPEND); + defaultReplyErrorHandler(replyPacket.errorCode()); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#topLevelThreadGroups() + */ + @Override + public List topLevelThreadGroups() { + // Note that this information should not be cached. + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_TOP_LEVEL_THREAD_GROUPS); + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int nrGroups = readInt("nr of groups", replyData); //$NON-NLS-1$ + ArrayList result = new ArrayList<>(nrGroups); + for (int i = 0; i < nrGroups; i++) { + ThreadGroupReferenceImpl threadGroup = ThreadGroupReferenceImpl.read(this, replyData); + result.add(threadGroup); + } + return result; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#name() + */ + @Override + public String name() { + getVersionInfo(); + return fVMName; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#version() + */ + @Override + public String version() { + getVersionInfo(); + return fVMVersion; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#description() + */ + @Override + public String description() { + getVersionInfo(); + return fVersionDescription; + } + + /** + * Reset event flags of all threads. + */ + private void resetThreadEventFlags() { + Iterator iter = allThreads().iterator(); + ThreadReferenceImpl thread; + while (iter.hasNext()) { + thread = (ThreadReferenceImpl) iter.next(); + thread.resetEventFlags(); + } + } + + /** + * Request and fetch ID sizes of Virtual Machine. + */ + private void getIDSizes() { + if (fGotIDSizes) { + return; + } + + /* + * fGotIDSizes must first be assigned true to prevent an infinite loop + * because getIDSizes() calls requestVM which calls packetSendManager. + */ + fGotIDSizes = true; + + // We use a different mirror to avoid having verbose output mixed with + // the initiating command. + MirrorImpl mirror = new VoidValueImpl(this); + + mirror.initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = mirror + .requestVM(JdwpCommandPacket.VM_ID_SIZES); + mirror.defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + fFieldIDSize = mirror.readInt("field ID size", replyData); //$NON-NLS-1$ + fMethodIDSize = mirror.readInt("method ID size", replyData); //$NON-NLS-1$ + fObjectIDSize = mirror.readInt("object ID size", replyData); //$NON-NLS-1$ + fReferenceTypeIDSize = mirror.readInt("refType ID size", replyData); //$NON-NLS-1$ + fFrameIDSize = mirror.readInt("frame ID size", replyData); //$NON-NLS-1$ + } catch (IOException e) { + fGotIDSizes = false; + mirror.defaultIOExceptionHandler(e); + } finally { + mirror.handledJdwpRequest(); + } + } + + /** + * Retrieves version info of the VM. + */ + public void getVersionInfo() { + if (fVersionDescription != null) { + return; + } + + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.VM_VERSION); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + fVersionDescription = readString("version descr.", replyData); //$NON-NLS-1$ + fJdwpMajorVersion = readInt("major version", replyData); //$NON-NLS-1$ + fJdwpMinorVersion = readInt("minor version", replyData); //$NON-NLS-1$ + fVMVersion = readString("version", replyData); //$NON-NLS-1$ + fVMName = readString("name", replyData); //$NON-NLS-1$ + + if ((fVMName != null) && fVMName.equals("KVM")) { //$NON-NLS-1$ + // KVM requires class preparation events in order + // to resolve things correctly + eventRequestManagerImpl().enableInternalClassPrepareEvent(); + } + + } catch (IOException e) { + fVersionDescription = null; + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * Retrieves the HCR capabilities of the VM. + */ + public void getHCRCapabilities() { + if (fHcrCapabilities != null) { + return; + } + fHcrCapabilities = new boolean[HCR_CAN_REENTER_ON_EXIT + 1]; + + if (isHCRSupported()) { + initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.HCR_CAPABILITIES); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + fHcrCapabilities[HCR_CAN_RELOAD_CLASSES] = readBoolean( + "reload classes", replyData); //$NON-NLS-1$ + fHcrCapabilities[HCR_CAN_GET_CLASS_VERSION] = readBoolean( + "get class version", replyData); //$NON-NLS-1$ + fHcrCapabilities[HCR_CAN_DO_RETURN] = readBoolean( + "do return", replyData); //$NON-NLS-1$ + fHcrCapabilities[HCR_CAN_REENTER_ON_EXIT] = readBoolean( + "reenter on exit", replyData); //$NON-NLS-1$ + } catch (IOException e) { + fHcrCapabilities = null; + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } else { + for (int i = 0; i < fHcrCapabilities.length; i++) { + fHcrCapabilities[i] = false; + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.hcr.VirtualMachine#canReloadClasses() + */ + @Override + public boolean canReloadClasses() { + getHCRCapabilities(); + return fHcrCapabilities[HCR_CAN_RELOAD_CLASSES]; + } + + /** + * @return Returns Whether VM can get the version of a given class file. + */ + public boolean canGetClassFileVersion1() { + getHCRCapabilities(); + return fHcrCapabilities[HCR_CAN_GET_CLASS_VERSION]; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#canGetClassFileVersion() + */ + @Override + public boolean canGetClassFileVersion() { + return isJdwpVersionGreaterOrEqual(1, 6); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#canGetConstantPool() + */ + @Override + public boolean canGetConstantPool() { + getCapabilities(); + return fCanGetConstantPool; + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.hcr.VirtualMachine#canDoReturn() + */ + @Override + public boolean canDoReturn() { + getHCRCapabilities(); + return fHcrCapabilities[HCR_CAN_DO_RETURN]; + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.hcr.VirtualMachine#canReenterOnExit() + */ + @Override + public boolean canReenterOnExit() { + getHCRCapabilities(); + return fHcrCapabilities[HCR_CAN_REENTER_ON_EXIT]; + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.hcr.VirtualMachine#classesHaveChanged(java.lang.String[]) + */ + @Override + public int classesHaveChanged(String[] names) { + checkHCRSupported(); + // We convert the class/interface names to signatures. + String[] signatures = new String[names.length]; + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeInt(names.length, "length", outData); //$NON-NLS-1$ + for (int i = 0; i < names.length; i++) { + signatures[i] = TypeImpl.classNameToSignature(names[i]); + writeString(signatures[i], "signature", outData); //$NON-NLS-1$ + } + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.HCR_CLASSES_HAVE_CHANGED, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + + byte resultFlag = readByte("result", resultHCRMap(), replyData); //$NON-NLS-1$ + switch (resultFlag) { + case HCR_RELOAD_SUCCESS: + return RELOAD_SUCCESS; + case HCR_RELOAD_FAILURE: + return RELOAD_FAILURE; + case HCR_RELOAD_IGNORED: + return RELOAD_IGNORED; + } + throw new InternalError( + JDIMessages.VirtualMachineImpl_Invalid_result_flag_in_Classes_Have_Changed_response___3 + + resultFlag + JDIMessages.VirtualMachineImpl__4); // + } catch (IOException e) { + defaultIOExceptionHandler(e); + return 0; + } finally { + handledJdwpRequest(); + } + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + try { + return name(); + } catch (Exception e) { + return fDescription; + } + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgHCRResultMap != null) { + return; + } + + Field[] fields = VirtualMachineImpl.class.getDeclaredFields(); + fgHCRResultMap = new HashMap<>(); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + if (name.startsWith("HCR_RELOAD_")) { //$NON-NLS-1$ + Integer intValue = Integer.valueOf(field.getInt(null)); + name = name.substring(4); + fgHCRResultMap.put(intValue, name); + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + public static Map resultHCRMap() { + getConstantMaps(); + return fgHCRResultMap; + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.VirtualMachine#setRequestTimeout(int) + */ + @Override + public void setRequestTimeout(int timeout) { + fRequestTimeout = timeout; + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.VirtualMachine#getRequestTimeout() + */ + @Override + public int getRequestTimeout() { + return fRequestTimeout; + } + + /** + * Returns whether the JDWP version is greater than or equal to the + * specified major/minor version numbers. + * + * @return whether the JDWP version is greater than or equal to the + * specified major/minor version numbers + */ + public boolean isJdwpVersionGreaterOrEqual(int major, int minor) { + getVersionInfo(); + return (fJdwpMajorVersion > major) + || (fJdwpMajorVersion == major && fJdwpMinorVersion >= minor); + } + + @Override + public void redefineClasses(Map typesToBytes) { + if (!canRedefineClasses()) { + throw new UnsupportedOperationException(); + } + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeInt(typesToBytes.size(), "classes", outData); //$NON-NLS-1$ + + Set types = typesToBytes.keySet(); + Iterator iter = types.iterator(); + while (iter.hasNext()) { + ReferenceTypeImpl type = (ReferenceTypeImpl) iter.next(); + type.write(this, outData); + byte[] bytes = typesToBytes.get(type); + writeInt(bytes.length, "classfile", outData); //$NON-NLS-1$ + for (byte b : bytes) { + writeByte(b, "classByte", outData); //$NON-NLS-1$ + } + fCachedReftypes.remove(type.getRefTypeID()); // flush local + // cache of + // redefined + // types + } + + JdwpReplyPacket reply = requestVM( + JdwpCommandPacket.VM_REDEFINE_CLASSES, outBytes); + switch (reply.errorCode()) { + case JdwpReplyPacket.UNSUPPORTED_VERSION: + throw new UnsupportedClassVersionError(); + case JdwpReplyPacket.INVALID_CLASS_FORMAT: + throw new ClassFormatError(); + case JdwpReplyPacket.CIRCULAR_CLASS_DEFINITION: + throw new ClassCircularityError(); + case JdwpReplyPacket.FAILS_VERIFICATION: + throw new VerifyError(); + case JdwpReplyPacket.NAMES_DONT_MATCH: + throw new NoClassDefFoundError(); + case JdwpReplyPacket.ADD_METHOD_NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.VirtualMachineImpl_Add_method_not_implemented_1); + case JdwpReplyPacket.SCHEMA_CHANGE_NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.VirtualMachineImpl_Scheme_change_not_implemented_2); + case JdwpReplyPacket.HIERARCHY_CHANGE_NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.VirtualMachineImpl_Hierarchy_change_not_implemented_3); + case JdwpReplyPacket.DELETE_METHOD_NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.VirtualMachineImpl_Delete_method_not_implemented_4); + case JdwpReplyPacket.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.VirtualMachineImpl_Class_modifiers_change_not_implemented_5); + case JdwpReplyPacket.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.VirtualMachineImpl_Method_modifiers_change_not_implemented_6); + default: + defaultReplyErrorHandler(reply.errorCode()); + } + } catch (IOException ioe) { + defaultIOExceptionHandler(ioe); + return; + } finally { + handledJdwpRequest(); + } + } + + /* + * @see VirtualMachine#canRedefineClasses() + */ + @Override + public boolean canRedefineClasses() { + getCapabilities(); + return fCanRedefineClasses; + } + + /* + * @see VirtualMachine#canUseInstanceFilters() + */ + @Override + public boolean canUseInstanceFilters() { + getCapabilities(); + return fCanUseInstanceFilters; + } + + /* + * @see VirtualMachine#canAddMethod() + */ + @Override + public boolean canAddMethod() { + getCapabilities(); + return fCanAddMethod; + } + + /* + * @see VirtualMachine#canUnrestrictedlyRedefineClasses() + */ + @Override + public boolean canUnrestrictedlyRedefineClasses() { + getCapabilities(); + return fCanUnrestrictedlyRedefineClasses; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#canUseSourceNameFilters() + */ + @Override + public boolean canUseSourceNameFilters() { + getCapabilities(); + return fCanUseSourceNameFilters; + } + + /* + * @see VirtualMachine#canPopFrames() + */ + @Override + public boolean canPopFrames() { + getCapabilities(); + return fCanPopFrames; + } + + /* + * @see VirtualMachine#canGetSourceDebugExtension() + */ + @Override + public boolean canGetSourceDebugExtension() { + getCapabilities(); + return fCanGetSourceDebugExtension; + } + + /* + * @see VirtualMachine#canRequestVMDeathEvent() + */ + @Override + public boolean canRequestVMDeathEvent() { + getCapabilities(); + return fCanRequestVMDeathEvent; + } + + public boolean canSetDefaultStratum() { + getCapabilities(); + return fCanSetDefaultStratum; + } + + /* + * @see VirtualMachine#setDefaultStratum(String) + */ + @Override + public void setDefaultStratum(String stratum) { + fDefaultStratum = stratum; + + if (!canSetDefaultStratum()) { + // TODO: how to inform the user that the VM doesn't manage + // setDefaultStartum ? + return; + } + if (stratum == null) { + stratum = ""; //$NON-NLS-1$ + } + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeString(stratum, "stratum ID", outData); //$NON-NLS-1$ + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.VM_SET_DEFAULT_STRATUM, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#getDefaultStratum() + */ + @Override + public String getDefaultStratum() { + return fDefaultStratum; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachine#instanceCounts(java.util.List) + */ + @Override + public long[] instanceCounts(List refTypes) { + if (refTypes == null) { + throw new NullPointerException(JDIMessages.VirtualMachineImpl_2); + } + int size = refTypes.size(); + if (size == 0) { + if (isJdwpVersionGreaterOrEqual(1, 6)) { + return new long[0]; + } + throw new UnsupportedOperationException(JDIMessages.ReferenceTypeImpl_27); + } + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeInt(size, "size", outData); //$NON-NLS-1$ + for (int i = 0; i < size; i++) { + ((ReferenceTypeImpl) refTypes.get(i)).getRefTypeID().write( + outData); + } + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.VM_INSTANCE_COUNTS, outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.INVALID_CLASS: + case JdwpReplyPacket.INVALID_OBJECT: + throw new ObjectCollectedException( + JDIMessages.class_or_object_not_known); + case JdwpReplyPacket.ILLEGAL_ARGUMENT: + throw new IllegalArgumentException( + JDIMessages.VirtualMachineImpl_count_less_than_zero); + case JdwpReplyPacket.NOT_IMPLEMENTED: + throw new UnsupportedOperationException( + JDIMessages.ReferenceTypeImpl_27); + case JdwpReplyPacket.VM_DEAD: + throw new VMDisconnectedException(JDIMessages.vm_dead); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + DataInputStream replyData = replyPacket.dataInStream(); + int counts = readInt("counts", replyData); //$NON-NLS-1$ + if (counts != size) { + throw new InternalError(JDIMessages.VirtualMachineImpl_3); + } + long[] ret = new long[counts]; + for (int i = 0; i < counts; i++) { + ret[i] = readLong("ref count", replyData); //$NON-NLS-1$ + } + return ret; + } catch (IOException e) { + defaultIOExceptionHandler(e); + return null; + } finally { + handledJdwpRequest(); + } + } + + /** + * Returns whether this VM is disconnected. + * + * @return whether this VM is disconnected + */ + public boolean isDisconnected() { + return fIsDisconnected; + } + + /** + * Sets whether this VM is disconnected. + * + * @param disconected + * whether this VM is disconnected + */ + public synchronized void setDisconnected(boolean disconnected) { + fIsDisconnected = disconnected; + } + + /** + * Return the boolean type for this VM. + */ + protected BooleanTypeImpl getBooleanType() { + if (fBooleanType == null) { + fBooleanType = new BooleanTypeImpl(this); + } + return fBooleanType; + } + + /** + * Return the byte type for this VM. + */ + protected ByteTypeImpl getByteType() { + if (fByteType == null) { + fByteType = new ByteTypeImpl(this); + } + return fByteType; + } + + /** + * Return the char type for this VM. + */ + protected CharTypeImpl getCharType() { + if (fCharType == null) { + fCharType = new CharTypeImpl(this); + } + return fCharType; + } + + /** + * Return the double type for this VM. + */ + protected DoubleTypeImpl getDoubleType() { + if (fDoubleType == null) { + fDoubleType = new DoubleTypeImpl(this); + } + return fDoubleType; + } + + /** + * Return the float type for this VM. + */ + protected FloatTypeImpl getFloatType() { + if (fFloatType == null) { + fFloatType = new FloatTypeImpl(this); + } + return fFloatType; + } + + /** + * Return the integer type for this VM. + */ + protected IntegerTypeImpl getIntegerType() { + if (fIntegerType == null) { + fIntegerType = new IntegerTypeImpl(this); + } + return fIntegerType; + } + + /** + * Return the long type for this VM. + */ + protected LongTypeImpl getLongType() { + if (fLongType == null) { + fLongType = new LongTypeImpl(this); + } + return fLongType; + } + + /** + * Return the short type for this VM. + */ + protected ShortTypeImpl getShortType() { + if (fShortType == null) { + fShortType = new ShortTypeImpl(this); + } + return fShortType; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.VirtualMachine#canBeModified() + */ + @Override + public boolean canBeModified() { + return true; + } + + public boolean mayCreateVirtualThreads() { + return isJdwpVersionGreaterOrEqual(19, 0); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VirtualMachineManagerImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VirtualMachineManagerImpl.java new file mode 100644 index 0000000000..b2bee5a83e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VirtualMachineManagerImpl.java @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.jdi.internal.connect.SocketAttachingConnectorImpl; +import org.eclipse.jdi.internal.connect.SocketLaunchingConnectorImpl; +import org.eclipse.jdi.internal.connect.SocketListeningConnectorImpl; +import org.eclipse.jdi.internal.connect.SocketRawLaunchingConnectorImpl; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugOptions; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.VirtualMachineManager; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.ListeningConnector; +import com.sun.jdi.connect.spi.Connection; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + */ +public class VirtualMachineManagerImpl implements VirtualMachineManager { + /** Major interface version. */ + public static int MAJOR_INTERFACE_VERSION = 1; + /** Minor interface version. */ + public static int MINOR_INTERFACE_VERSION = 5; + /** + * PrintWriter where verbose info is written to, null if no verbose must be + * given. + */ + private PrintWriter fVerbosePrintWriter = null; + /** List of all VMs that are currently connected. */ + List fConnectedVMs = new ArrayList<>(); + + /** Name of verbose file. */ + private String fVerboseFile; + + /** + * Creates new VirtualMachineManagerImpl. + */ + public VirtualMachineManagerImpl() { + + getPreferences(); + + // See if verbose info must be given. + if (isVerboseTracingEnabled()) { + OutputStream out = null; + if (fVerboseFile != null && fVerboseFile.length() > 0) { + try { + out = new FileOutputStream(fVerboseFile); + } catch (IOException e) { + JDIDebugPlugin.logError(JDIMessages.VirtualMachineManagerImpl_Could_not_open_verbose_file___1 + + fVerboseFile + + JDIMessages.VirtualMachineManagerImpl_____2 + , e); // + } + } + if (out == null) { + fVerbosePrintWriter = new PrintWriter(new StringWriter()) { + @Override + public void flush() { + super.flush(); + StringWriter writer = new StringWriter(); + synchronized (lock) { + JDIDebugOptions.trace(JDIDebugOptions.DEBUG_JDI_VERBOSE_FLAG, this.out.toString(), null); + this.out = writer; + this.lock = writer; + } + } + }; + + } else { + fVerbosePrintWriter = new PrintWriter(out); + } + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#majorInterfaceVersion() + */ + @Override + public int majorInterfaceVersion() { + return MAJOR_INTERFACE_VERSION; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#minorInterfaceVersion() + */ + @Override + public int minorInterfaceVersion() { + return MINOR_INTERFACE_VERSION; + } + + public static boolean isVerboseTracingEnabled() { + return JDIDebugOptions.DEBUG_JDI_VEBOSE; + } + + static String getTracingFileName() { + return JDIDebugOptions.DEBUG_JDI_VEBOSE_FILE; + } + + /** + * Loads the user preferences from .options file + */ + private void getPreferences() { + if (isVerboseTracingEnabled()) { + fVerboseFile = getTracingFileName(); + } + } + + /** + * @return Returns Timeout value for requests to VM, if not overridden for + * the VM. This value is used to throw the exception + * TimeoutException in JDI calls. NOTE: This is not in compliance + * with the Sun's JDI. + */ + public int getGlobalRequestTimeout() { + try { + IPreferencesService srvc = Platform.getPreferencesService(); + if(srvc != null) { + return Platform.getPreferencesService().getInt( + JDIDebugModel.getPluginIdentifier(), + JDIDebugModel.PREF_REQUEST_TIMEOUT, + JDIDebugModel.DEF_REQUEST_TIMEOUT, + null); + } + } catch (NoClassDefFoundError e) { + } + // return the hard coded preference if the JDI debug plug-in does not + // exist + return JDIDebugModel.DEF_REQUEST_TIMEOUT; + } + + /** + * Adds a VM to the connected VM list. + */ + public void addConnectedVM(VirtualMachineImpl vm) { + fConnectedVMs.add(vm); + } + + /** + * Removes a VM from the connected VM list. + */ + public void removeConnectedVM(VirtualMachineImpl vm) { + fConnectedVMs.remove(vm); + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#connectedVirtualMachines() + */ + @Override + public List connectedVirtualMachines() { + return fConnectedVMs; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#allConnectors() + */ + @Override + public List allConnectors() { + List result = new ArrayList<>(attachingConnectors()); + result.addAll(launchingConnectors()); + result.addAll(listeningConnectors()); + return result; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#attachingConnectors() + */ + @Override + public List attachingConnectors() { + ArrayList list = new ArrayList<>(1); + list.add(new SocketAttachingConnectorImpl(this)); + return list; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#launchingConnectors() + */ + @Override + public List launchingConnectors() { + ArrayList list = new ArrayList<>(2); + list.add(new SocketLaunchingConnectorImpl(this)); + list.add(new SocketRawLaunchingConnectorImpl(this)); + return list; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#listeningConnectors() + */ + @Override + public List listeningConnectors() { + ArrayList list = new ArrayList<>(1); + list.add(new SocketListeningConnectorImpl(this)); + return list; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#defaultConnector() + */ + @Override + public LaunchingConnector defaultConnector() { + return new SocketLaunchingConnectorImpl(this); + } + + /** + * @return Returns PrintWriter to which verbose info must be written, or + * null if no verbose must be given. + */ + public PrintWriter verbosePrintWriter() { + return fVerbosePrintWriter; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#createVirtualMachine(com.sun.jdi.connect.spi.Connection) + */ + @Override + public VirtualMachine createVirtualMachine(Connection connection) throws IOException { + VirtualMachineImpl vmImpl = new VirtualMachineImpl(connection); + return vmImpl; + } + + /* (non-Javadoc) + * @see com.sun.jdi.VirtualMachineManager#createVirtualMachine(com.sun.jdi.connect.spi.Connection, java.lang.Process) + */ + @Override + public VirtualMachine createVirtualMachine(Connection connection, Process process) throws IOException { + VirtualMachineImpl vmImpl = new VirtualMachineImpl(connection); + vmImpl.setLaunchedProcess(process); + return vmImpl; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VoidTypeImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VoidTypeImpl.java new file mode 100644 index 0000000000..df77c6188a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VoidTypeImpl.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import com.sun.jdi.Value; +import com.sun.jdi.VoidType; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class VoidTypeImpl extends TypeImpl implements VoidType { + /** + * Creates new instance. + */ + public VoidTypeImpl(VirtualMachineImpl vmImpl) { + super("VoidType", vmImpl, "void", "V"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * @return Returns modifier bits. + */ + @Override + public int modifiers() { + throw new InternalError( + JDIMessages.VoidTypeImpl_A_VoidType_does_not_have_modifiers_1); + } + + /** + * @return Create a null value instance of the type. + */ + @Override + public Value createNullValue() { + return new VoidValueImpl(virtualMachineImpl()); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VoidValueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VoidValueImpl.java new file mode 100644 index 0000000000..634cf84ab6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/VoidValueImpl.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal; + +import java.io.DataOutputStream; + +import org.eclipse.jdi.internal.jdwp.JdwpID; + +import com.sun.jdi.Type; +import com.sun.jdi.VoidValue; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class VoidValueImpl extends ValueImpl implements VoidValue { + /** JDWP Tag. */ + public static final byte tag = JdwpID.VOID_TAG; + + /** + * Creates new instance. + */ + public VoidValueImpl(VirtualMachineImpl vmImpl) { + super("VoidValue", vmImpl); //$NON-NLS-1$ + } + + /** + * @return tag. + */ + @Override + public byte getTag() { + return tag; + } + + /** + * @return type of value. + */ + @Override + public Type type() { + return new VoidTypeImpl(virtualMachineImpl()); + } + + /** + * @return Returns true if two values are equal. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null && object.getClass().equals(this.getClass()); + } + + /** + * @return Returns a has code for this object. + * @see java.lang.Object#hashCode + */ + @Override + public int hashCode() { + return 0; + } + + /** + * Writes value without value tag. + */ + @Override + public void write(MirrorImpl target, DataOutputStream out) { + // Nothing to write. + } + + /** + * @return Returns description of Mirror object. + */ + @Override + public String toString() { + return "(void)"; //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java new file mode 100644 index 0000000000..f03c542b42 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + * Google Inc - add support for accepting multiple connections + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import org.eclipse.osgi.util.NLS; + +public class ConnectMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdi.internal.connect.ConnectMessages";//$NON-NLS-1$ + + public static String PacketReceiveManager_Got_IOException_from_Virtual_Machine_1; + public static String PacketReceiveManager_Got_IOException_from_Virtual_Machine_2; + public static String PacketSendManager_Got_IOException_from_Virtual_Machine_1; + public static String SocketAttachingConnectorImpl_Machine_name_to_which_to_attach_for_VM_connections_1; + public static String SocketAttachingConnectorImpl_Host_2; + public static String SocketAttachingConnectorImpl_Port_number_to_which_to_attach_for_VM_connections_3; + public static String SocketAttachingConnectorImpl_Port_4; + public static String SocketAttachingConnectorImpl_1; + public static String SocketAttachingConnectorImpl_2; + public static String SocketAttachingConnectorImpl_Attaches_by_socket_to_other_VMs_5; + public static String SocketAttachingConnectorImpl_Connection_argument_is_not_of_the_right_type_6; + public static String SocketAttachingConnectorImpl_Necessary_connection_argument_is_null_7; + public static String SocketAttachingConnectorImpl_Connection_argument_is_not_a_number_8; + public static String SocketLaunchingConnectorImpl_Home_directory_of_the_SDK_or_runtime_environment_used_to_launch_the_application_1; + public static String SocketLaunchingConnectorImpl_Home_2; + public static String SocketLaunchingConnectorImpl_Launched_VM_options_3; + public static String SocketLaunchingConnectorImpl_Options_4; + public static String SocketLaunchingConnectorImpl_Main_class_and_arguments__or_if__jar_is_an_option__the_main_jar_file_and_arguments_5; + public static String SocketLaunchingConnectorImpl_Main_6; + public static String SocketLaunchingConnectorImpl_All_threads_will_be_suspended_before_execution_of_main_7; + public static String SocketLaunchingConnectorImpl_Suspend_8; + public static String SocketLaunchingConnectorImpl_Character_used_to_combine_space_delimited_text_into_a_single_command_line_argument_9; + public static String SocketLaunchingConnectorImpl_Quote_10; + public static String SocketLaunchingConnectorImpl_Name_of_the_Java_VM_launcher_11; + public static String SocketLaunchingConnectorImpl_Launcher_12; + public static String SocketLaunchingConnectorImpl_Launches_target_using_Sun_Java_VM_command_line_and_attaches_to_it_13; + public static String SocketLaunchingConnectorImpl_Connection_argument_is_not_of_the_right_type_14; + public static String SocketLaunchingConnectorImpl_Necessary_connection_argument_is_null_15; + public static String SocketLaunchingConnectorImpl_Connection_argument_is_not_a_number_16; + public static String SocketLaunchingConnectorImpl_Include_virtual_threads_17; + public static String SocketLaunchingConnectorImpl_IncludeVirtualThreads_18; + public static String SocketListeningConnectorImpl_Port_number_at_which_to_listen_for_VM_connections_1; + public static String SocketListeningConnectorImpl_Port_2; + public static String SocketListeningConnectorImpl_Timeout_before_accept_returns_3; + public static String SocketListeningConnectorImpl_Timeout_4; + public static String SocketListeningConnectorImpl_Accepts_socket_connections_initiated_by_other_VMs_5; + public static String SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6; + public static String SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7; + public static String SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8; + public static String SocketListeningConnectorImpl_Limit; + + public static String SocketListeningConnectorImpl_Limit_incoming_connections; + + public static String SocketListeningConnectorImpl_ListeningConnector_Socket_Port; + public static String SocketRawLaunchingConnectorImpl_Raw_command_to_start_the_debugged_application_VM_1; + public static String SocketRawLaunchingConnectorImpl_Command_2; + public static String SocketRawLaunchingConnectorImpl_Address_from_which_to_listen_for_a_connection_after_the_raw_command_is_run_3; + public static String SocketRawLaunchingConnectorImpl_Address_4; + public static String SocketRawLaunchingConnectorImpl_Character_used_to_combine_space_delimited_text_into_a_single_command_line_argument_5; + public static String SocketRawLaunchingConnectorImpl_Quote_6; + public static String SocketRawLaunchingConnectorImpl_Launches_target_using_user_specified_command_line_and_attaches_to_it_7; + public static String SocketRawLaunchingConnectorImpl_Connection_argument_is_not_of_the_right_type_8; + public static String SocketRawLaunchingConnectorImpl_Necessary_connection_argument_is_null_9; + public static String SocketRawLaunchingConnectorImpl_Connection_argument_is_not_a_number_10; + public static String SocketLaunchingConnectorImpl_VM_did_not_connect_within_given_time___0__ms_1; + public static String PacketSendManager_Got__0__from_Virtual_Machine_1; + public static String PacketSendManager_Got__0__from_Virtual_Machine___1__1; + public static String PacketReceiveManager_Got__0__from_Virtual_Machine_1; + public static String PacketReceiveManager_Got__0__from_Virtual_Machine___1__1; + public static String PacketReceiveManager_0; + public static String SocketTransportService_0; + public static String SocketTransportService_1; + public static String SocketConnectionLabelSeparator; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, ConnectMessages.class); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties new file mode 100644 index 0000000000..4c5422b109 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties @@ -0,0 +1,84 @@ +############################################################################### +# Copyright (c) 2000, 2022 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +# Google Inc - add support for accepting multiple connections +# Microsoft Corporation - supports virtual threads +############################################################################### + +PacketReceiveManager_Got_IOException_from_Virtual_Machine_1=Got IOException from Virtual Machine +PacketReceiveManager_Got_IOException_from_Virtual_Machine_2=Got IOException from Virtual Machine +PacketSendManager_Got_IOException_from_Virtual_Machine_1=Got IOException from Virtual Machine +SocketAttachingConnectorImpl_Machine_name_to_which_to_attach_for_VM_connections_1=Machine name to which to attach for VM connections +#Separator for Remote Java application socket attach and listen arguments +SocketConnectionLabelSeparator=: +#For translation of separator ":" it should be consistent to the translated value of SocketConnectionLabelSeparator +SocketAttachingConnectorImpl_Host_2=&Host: +SocketAttachingConnectorImpl_Port_number_to_which_to_attach_for_VM_connections_3=Port number to which to attach for VM connections +#For translation of separator ":" it should be consistent to the translated value of SocketConnectionLabelSeparator +SocketAttachingConnectorImpl_Port_4=Po&rt: +SocketAttachingConnectorImpl_1=Connection Timeout +#For translation of separator ":" it should be consistent to the translated value of SocketConnectionLabelSeparator +SocketAttachingConnectorImpl_2=Connection Timeout: +SocketAttachingConnectorImpl_Attaches_by_socket_to_other_VMs_5=Attaches by socket to other VMs +SocketAttachingConnectorImpl_Connection_argument_is_not_of_the_right_type_6=Connection argument is not of the right type +SocketAttachingConnectorImpl_Necessary_connection_argument_is_null_7=Necessary connection argument is null +SocketAttachingConnectorImpl_Connection_argument_is_not_a_number_8=Connection argument is not a number +SocketLaunchingConnectorImpl_Home_directory_of_the_SDK_or_runtime_environment_used_to_launch_the_application_1=Home directory of the SDK or runtime environment used to launch the application +SocketLaunchingConnectorImpl_Home_2=Home: +SocketLaunchingConnectorImpl_Launched_VM_options_3=Launched VM options +SocketLaunchingConnectorImpl_Options_4=Options: +SocketLaunchingConnectorImpl_Main_class_and_arguments__or_if__jar_is_an_option__the_main_jar_file_and_arguments_5=Main class and arguments, or if -jar is an option, the main jar file and arguments +SocketLaunchingConnectorImpl_Main_6=Main: +SocketLaunchingConnectorImpl_All_threads_will_be_suspended_before_execution_of_main_7=All threads will be suspended before execution of main +SocketLaunchingConnectorImpl_Suspend_8=Suspend: +SocketLaunchingConnectorImpl_Character_used_to_combine_space_delimited_text_into_a_single_command_line_argument_9=Character used to combine space-delimited text into a single command line argument +SocketLaunchingConnectorImpl_Quote_10=Quote: +SocketLaunchingConnectorImpl_Name_of_the_Java_VM_launcher_11=Name of the Java VM launcher +SocketLaunchingConnectorImpl_Launcher_12=Launcher: +SocketLaunchingConnectorImpl_Launches_target_using_Sun_Java_VM_command_line_and_attaches_to_it_13=Launches target using Sun Java VM command line and attaches to it +SocketLaunchingConnectorImpl_Connection_argument_is_not_of_the_right_type_14=Connection argument is not of the right type +SocketLaunchingConnectorImpl_Necessary_connection_argument_is_null_15=Necessary connection argument is null +SocketLaunchingConnectorImpl_Connection_argument_is_not_a_number_16=Connection argument is not a number +SocketLaunchingConnectorImpl_Include_virtual_threads_17=List of all threads includes virtual threads as well as platform threads. Virtual threads are a preview feature of the Java platform. +SocketLaunchingConnectorImpl_IncludeVirtualThreads_18=Include Virtual Threads: +SocketListeningConnectorImpl_Port_number_at_which_to_listen_for_VM_connections_1=Port number at which to listen for VM connections +#For translation of separator ":" it should be consistent to the translated value of SocketConnectionLabelSeparator +SocketListeningConnectorImpl_Port_2=Po&rt: +SocketListeningConnectorImpl_Timeout_before_accept_returns_3=Timeout before accept returns +#For translation of separator ":" it should be consistent to the translated value of SocketConnectionLabelSeparator +SocketListeningConnectorImpl_Timeout_4=Timeout: +SocketListeningConnectorImpl_Accepts_socket_connections_initiated_by_other_VMs_5=Accepts socket connections initiated by other VMs +SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6=Connection argument is not of the right type +SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7=Necessary connection argument is null +SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8=Connection argument is not a number +#For translation of separator ":" it should be consistent to the translated value of SocketConnectionLabelSeparator +SocketListeningConnectorImpl_Limit=Connection &limit: +SocketListeningConnectorImpl_Limit_incoming_connections=Limit incoming connections (0 = no limit) +SocketListeningConnectorImpl_ListeningConnector_Socket_Port=ListeningConnector Socket Port= +SocketRawLaunchingConnectorImpl_Raw_command_to_start_the_debugged_application_VM_1=Raw command to start the debugged application VM +SocketRawLaunchingConnectorImpl_Command_2=Command: +SocketRawLaunchingConnectorImpl_Address_from_which_to_listen_for_a_connection_after_the_raw_command_is_run_3=Address from which to listen for a connection after the raw command is run +SocketRawLaunchingConnectorImpl_Address_4=Address: +SocketRawLaunchingConnectorImpl_Character_used_to_combine_space_delimited_text_into_a_single_command_line_argument_5=Character used to combine space-delimited text into a single command line argument +SocketRawLaunchingConnectorImpl_Quote_6=Quote: +SocketRawLaunchingConnectorImpl_Launches_target_using_user_specified_command_line_and_attaches_to_it_7=Launches target using user-specified command line and attaches to it +SocketRawLaunchingConnectorImpl_Connection_argument_is_not_of_the_right_type_8=Connection argument is not of the right type +SocketRawLaunchingConnectorImpl_Necessary_connection_argument_is_null_9=Necessary connection argument is null +SocketRawLaunchingConnectorImpl_Connection_argument_is_not_a_number_10=Connection argument is not a number +SocketLaunchingConnectorImpl_VM_did_not_connect_within_given_time___0__ms_1=VM did not connect within given time: {0} ms +PacketSendManager_Got__0__from_Virtual_Machine_1=Got {0} from Virtual Machine +PacketSendManager_Got__0__from_Virtual_Machine___1__1=Got {0} from Virtual Machine: {1} +PacketReceiveManager_Got__0__from_Virtual_Machine_1=Got {0} from Virtual Machine +PacketReceiveManager_Got__0__from_Virtual_Machine___1__1=Got {0} from Virtual Machine: {1} +PacketReceiveManager_0=Timeout occurred while waiting for packet {0}. +SocketTransportService_0=Attach Thread +SocketTransportService_1=Handshake Thread \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectorImpl.java new file mode 100644 index 0000000000..992255dd73 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectorImpl.java @@ -0,0 +1,385 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately + * from Eclipse + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.util.List; + +import org.eclipse.jdi.Bootstrap; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.VirtualMachineManagerImpl; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.Transport; +import com.sun.jdi.connect.spi.Connection; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class ConnectorImpl implements Connector { + /** Virtual machine manager that created this connector. */ + private final VirtualMachineManagerImpl fVirtualMachineManager; + + /** Transport that is used for communication. */ + protected Transport fTransport; + /** Virtual Machine that is connected. */ + protected VirtualMachineImpl fVirtualMachine; + + /** + * Creates a new Connector. + */ + public ConnectorImpl(VirtualMachineManagerImpl virtualMachineManager) { + fVirtualMachineManager = virtualMachineManager; + } + + /** + * @return Returns Virtual Machine Manager. + */ + public VirtualMachineManagerImpl virtualMachineManager() { + return fVirtualMachineManager; + } + + /** + * @return Returns Virtual Machine Manager. + */ + public VirtualMachineImpl virtualMachine() { + return fVirtualMachine; + } + + /** + * @return Returns a human-readable description of this connector and its + * purpose. + */ + @Override + public abstract String description(); + + /** + * @return Returns a short identifier for the connector. + */ + @Override + public abstract String name(); + + /** + * Assigns Transport. + */ + /* package */void setTransport(Transport transport) { + fTransport = transport; + } + + /** + * @return Returns the transport mechanism used by this connector to + * establish connections with a target VM. + */ + @Override + public Transport transport() { + return fTransport; + } + + /** + * Closes connection with Virtual Machine. + */ + /* package */synchronized void close() { + virtualMachineManager().removeConnectedVM(fVirtualMachine); + } + + /** + * @return Returns a connected Virtual Machine. + */ + protected VirtualMachine establishedConnection(Connection connection) + throws IOException { + fVirtualMachine = (VirtualMachineImpl) Bootstrap + .virtualMachineManager().createVirtualMachine(connection); + return fVirtualMachine; + } + + /** + * Argument class for arguments that are used to establish a connection. + */ + public abstract static class ArgumentImpl implements + com.sun.jdi.connect.Connector.Argument { + /** + * Serial version id. + */ + private static final long serialVersionUID = 8850533280769854833L; + + private final String fName; + private final String fDescription; + private final String fLabel; + private final boolean fMustSpecify; + + protected ArgumentImpl(String name, String description, String label, + boolean mustSpecify) { + fName = name; + fLabel = label; + fDescription = description; + fMustSpecify = mustSpecify; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#name() + */ + @Override + public String name() { + return fName; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#description() + */ + @Override + public String description() { + return fDescription; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#label() + */ + @Override + public String label() { + return fLabel; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#mustSpecify() + */ + @Override + public boolean mustSpecify() { + return fMustSpecify; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#value() + */ + @Override + public abstract String value(); + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#setValue(java.lang.String) + */ + @Override + public abstract void setValue(String value); + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.Argument#isValid(java.lang.String) + */ + @Override + public abstract boolean isValid(String value); + + @Override + public abstract String toString(); + } + + public static class StringArgumentImpl extends ArgumentImpl implements StringArgument { + private static final long serialVersionUID = 6009335074727417445L; + + private String fValue; + + protected StringArgumentImpl(String name, String description, + String label, boolean mustSpecify) { + super(name, description, label, mustSpecify); + } + + @Override + public String value() { + return fValue; + } + + @Override + public void setValue(String value) { + fValue = value; + } + + @Override + public boolean isValid(String value) { + return true; + } + + @Override + public String toString() { + return fValue; + } + + } + + public static class IntegerArgumentImpl extends ArgumentImpl implements IntegerArgument { + private static final long serialVersionUID = 6009335074727417445L; + private Integer fValue; + private final int fMin; + private final int fMax; + + protected IntegerArgumentImpl(String name, String description, + String label, boolean mustSpecify, int min, int max) { + super(name, description, label, mustSpecify); + fMin = min; + fMax = max; + } + + @Override + public String value() { + return (fValue == null) ? null : fValue.toString(); + } + + @Override + public void setValue(String value) { + fValue = Integer.valueOf(value); + } + + @Override + public boolean isValid(String value) { + Integer val; + try { + val = Integer.valueOf(value); + } catch (NumberFormatException e) { + return false; + } + return isValid(val.intValue()); + } + + @Override + public String toString() { + return value(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.IntegerArgument#intValue() + */ + @Override + public int intValue() { + return fValue.intValue(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.IntegerArgument#setValue(int) + */ + @Override + public void setValue(int value) { + fValue = Integer.valueOf(value); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.IntegerArgument#min() + */ + @Override + public int min() { + return fMin; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.IntegerArgument#max() + */ + @Override + public int max() { + return fMax; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.IntegerArgument#isValid(int) + */ + @Override + public boolean isValid(int value) { + return fMin <= value && value <= fMax; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.IntegerArgument#stringValueOf(int) + */ + @Override + public String stringValueOf(int value) { + return Integer.toString(value); + } + } + + public static class BooleanArgumentImpl extends ArgumentImpl implements BooleanArgument { + private static final long serialVersionUID = 6009335074727417445L; + private Boolean fValue; + + protected BooleanArgumentImpl(String name, String description, + String label, boolean mustSpecify) { + super(name, description, label, mustSpecify); + } + + @Override + public String value() { + return (fValue == null) ? null : fValue.toString(); + } + + @Override + public void setValue(String value) { + fValue = Boolean.valueOf(value); + } + + @Override + public boolean isValid(String value) { + return true; + } + + @Override + public String toString() { + return value(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.BooleanArgument#booleanValue() + */ + @Override + public boolean booleanValue() { + return fValue.booleanValue(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.BooleanArgument#setValue(boolean) + */ + @Override + public void setValue(boolean value) { + fValue = Boolean.valueOf(value); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.BooleanArgument#stringValueOf(boolean) + */ + @Override + public String stringValueOf(boolean value) { + return Boolean.toString(value); + } + } + + public class SelectedArgumentImpl extends StringArgumentImpl implements SelectedArgument { + private static final long serialVersionUID = 6009335074727417445L; + private final List fChoices; + + protected SelectedArgumentImpl(String name, String description, + String label, boolean mustSpecify, List choices) { + super(name, description, label, mustSpecify); + fChoices = choices; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector.SelectedArgument#choices() + */ + @Override + public List choices() { + return fChoices; + } + + @Override + public boolean isValid(String value) { + return fChoices.contains(value); + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketManager.java new file mode 100644 index 0000000000..06835a0b0d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketManager.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; + +import com.sun.jdi.connect.spi.Connection; + +/** + * This class implements threads that receive/send packets from/to the Virtual + * Machine. + * + */ +public abstract class PacketManager implements Runnable { + /** Connector that performs IO to Virtual Machine. */ + private final Connection fConnection; + /** + * Thread that handles the communication the other way (e.g. if we are + * sending, the receiving thread). + */ + private Thread fPartnerThread; + private IOException fDisconnectException; + + /** + * Creates new PacketManager. + */ + protected PacketManager(Connection connection) { + fConnection = connection; + } + + public Connection getConnection() { + return fConnection; + } + + /** + * Used to indicate that an IO exception occurred, closes connection to + * Virtual Machine. + * + * @param disconnectException + * the IOException that occurred + */ + public void disconnectVM(IOException disconnectException) { + fDisconnectException = disconnectException; + disconnectVM(); + } + + /** + * Closes connection to Virtual Machine. + */ + public void disconnectVM() { + try { + fConnection.close(); + } catch (IOException e) { + fDisconnectException = e; + } + // Interrupt the sending thread if we are the receiving thread and vice + // versa. + if (fPartnerThread != null) { + fPartnerThread.interrupt(); + } + } + + /** + * @return Returns whether an IO exception has occurred. + */ + public boolean VMIsDisconnected() { + return fConnection == null || !fConnection.isOpen(); + } + + /** + * Returns the IOException that caused this packet manager to disconnect or + * null if none. + */ + public IOException getDisconnectException() { + return fDisconnectException; + } + + /** + * Assigns thread of partner, to be notified if we have an IO exception. + */ + public void setPartnerThread(Thread thread) { + fPartnerThread = thread; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketReceiveManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketReceiveManager.java new file mode 100644 index 0000000000..7f1ff4ad97 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketReceiveManager.java @@ -0,0 +1,311 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.ListIterator; + +import org.eclipse.jdi.TimeoutException; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpPacket; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdt.internal.debug.core.JDIDebugOptions; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.connect.spi.Connection; + +/** + * This class implements a thread that receives packets from the Virtual + * Machine. + * + */ +public class PacketReceiveManager extends PacketManager { + + /** Generic timeout value for not blocking. */ + public static final int TIMEOUT_NOT_BLOCKING = 0; + + /** Generic timeout value for infinite timeout. */ + public static final int TIMEOUT_INFINITE = -1; + + /** List of Command packets received from Virtual Machine. */ + private final LinkedList fCommandPackets; + + /** List of Reply packets received from Virtual Machine. */ + private final LinkedList fReplyPackets; + + /** + * List of Packets that have timed out already. Maintained so that responses + * can be discarded if/when they are received. + */ + private final ArrayList fTimedOutPackets; + + private final VirtualMachineImpl fVM; + + /** + * Create a new thread that receives packets from the Virtual Machine. + */ + public PacketReceiveManager(Connection connection, VirtualMachineImpl vmImpl) { + super(connection); + fVM = vmImpl; + fCommandPackets = new LinkedList<>(); + fReplyPackets = new LinkedList<>(); + fTimedOutPackets = new ArrayList<>(); + } + + @Override + public void disconnectVM() { + super.disconnectVM(); + synchronized (fCommandPackets) { + fCommandPackets.notifyAll(); + } + synchronized (fReplyPackets) { + fReplyPackets.notifyAll(); + } + } + + /** + * Thread's run method. + */ + @Override + public void run() { + try { + while (!VMIsDisconnected()) { + // Read a packet from the input stream. + readAvailablePacket(); + } + } + // if the remote VM is interrupted, drop the connection and clean up, + // don't wait for it to happen on its own + catch (InterruptedIOException e) { + disconnectVM(e); + } catch (IOException e) { + disconnectVM(e); + } + } + + /** + * @return Returns a specified Command Packet from the Virtual Machine. + */ + public JdwpCommandPacket getCommand(int command, long timeToWait) + throws InterruptedException { + JdwpCommandPacket packet = null; + synchronized (fCommandPackets) { + long remainingTime = timeToWait; + long timeBeforeWait; + long waitedTime; + + // Wait until command is available. + while (!VMIsDisconnected() + && (packet = removeCommandPacket(command)) == null + && (timeToWait < 0 || remainingTime > 0)) { + timeBeforeWait = System.currentTimeMillis(); + waitForPacketAvailable(remainingTime, fCommandPackets); + waitedTime = System.currentTimeMillis() - timeBeforeWait; + remainingTime -= waitedTime; + } + } + // Check for an IO Exception. + if (VMIsDisconnected()) { + String message; + if (getDisconnectException() == null) { + message = ConnectMessages.PacketReceiveManager_Got_IOException_from_Virtual_Machine_1; + } else { + String exMessage = getDisconnectException().getMessage(); + if (exMessage == null) { + message = NLS.bind(ConnectMessages.PacketReceiveManager_Got__0__from_Virtual_Machine_1, + new String[] { getDisconnectException() + .getClass().getName() }); + } else { + message = NLS.bind(ConnectMessages.PacketReceiveManager_Got__0__from_Virtual_Machine___1__1, + new String[] { + getDisconnectException().getClass() + .getName(), exMessage }); + } + } + throw new VMDisconnectedException(message); + } + // Check for a timeout. + if (packet == null) { + throw new TimeoutException(); + } + return packet; + } + + /** + * @return Returns a specified Reply Packet from the Virtual Machine. + */ + public JdwpReplyPacket getReply(int id, long timeToWait) { + JdwpReplyPacket packet = null; + long remainingTime = timeToWait; + synchronized (fReplyPackets) { + final long timeBeforeWait = System.currentTimeMillis(); + // Wait until reply is available. + while (!VMIsDisconnected() && remainingTime > 0) { + packet = removeReplyPacket(id); + if (packet != null) { + break; + } + try { + waitForPacketAvailable(remainingTime, fReplyPackets); + } + // if the remote VM is interrupted DO NOT drop the connection - + // see bug 171075 + // just stop waiting for the reply and treat it as a timeout + catch (InterruptedException e) { + if (JDIDebugOptions.DEBUG) { + JDIDebugOptions.trace(null, "Interrupt observed while waiting for packet: " + id, e); //$NON-NLS-1$ + } + // Do not stop waiting on interrupt, this causes + // sporadic TimeoutException's without timeout + // break; + } + long waitedTime = System.currentTimeMillis() - timeBeforeWait; + remainingTime = timeToWait - waitedTime; + } + } + if (packet == null) { + synchronized (fReplyPackets) { + packet = removeReplyPacket(id); + } + } + // Check for an IO Exception. + if (VMIsDisconnected()) + throw new VMDisconnectedException( + ConnectMessages.PacketReceiveManager_Got_IOException_from_Virtual_Machine_2); + // Check for a timeout. + if (packet == null) { + synchronized (fTimedOutPackets) { + fTimedOutPackets.add(Integer.valueOf(id)); + } + throw new TimeoutException(NLS.bind( + ConnectMessages.PacketReceiveManager_0, new String[] { id + + "" })); //$NON-NLS-1$ + } + return packet; + } + + /** + * @return Returns a specified Reply Packet from the Virtual Machine. + */ + public JdwpReplyPacket getReply(JdwpCommandPacket commandPacket) { + return getReply(commandPacket.getId(), fVM.getRequestTimeout()); + } + + /** + * Wait for an available packet from the Virtual Machine. + */ + private void waitForPacketAvailable(long timeToWait, Object lock) + throws InterruptedException { + if (timeToWait == 0) + return; + else if (timeToWait < 0) + lock.wait(); + else + lock.wait(timeToWait); + } + + /** + * @return Returns and removes a specified command packet from the command + * packet list. + */ + private JdwpCommandPacket removeCommandPacket(int command) { + ListIterator iter = fCommandPackets.listIterator(); + while (iter.hasNext()) { + JdwpCommandPacket packet = iter.next(); + if (packet.getCommand() == command) { + iter.remove(); + return packet; + } + } + return null; + } + + /** + * @return Returns a specified reply packet from the reply packet list. + */ + private JdwpReplyPacket removeReplyPacket(int id) { + ListIterator iter = fReplyPackets.listIterator(); + while (iter.hasNext()) { + JdwpReplyPacket packet = iter.next(); + if (packet.getId() == id) { + iter.remove(); + return packet; + } + } + return null; + } + + /** + * Add a command packet to the command packet list. + */ + private void addCommandPacket(JdwpCommandPacket packet) { + if (isTimedOut(packet)) { + return; // already timed out. No need to keep this one + } + synchronized (fCommandPackets) { + fCommandPackets.add(packet); + fCommandPackets.notifyAll(); + } + } + + /** + * Returns whether the request for the given packet has already timed out. + * + * @param packet + * response packet + * @return whether the request for the given packet has already timed out + */ + private boolean isTimedOut(JdwpPacket packet) { + synchronized (fTimedOutPackets) { + if (fTimedOutPackets.isEmpty()) { + return false; + } + Integer id = Integer.valueOf(packet.getId()); + return fTimedOutPackets.remove(id); + } + } + + /** + * Add a reply packet to the reply packet list. + */ + private void addReplyPacket(JdwpReplyPacket packet) { + if (isTimedOut(packet)) { + return; // already timed out. No need to keep this one + } + synchronized (fReplyPackets) { + fReplyPackets.add(packet); + fReplyPackets.notifyAll(); + } + } + + /** + * Read a packet from the input stream and add it to the appropriate packet + * list. + */ + private void readAvailablePacket() throws IOException { + // Read a packet from the Input Stream. + byte[] bytes = getConnection().readPacket(); + JdwpPacket packet = JdwpPacket.build(bytes); + // Add packet to command or reply queue. + if (packet instanceof JdwpCommandPacket) + addCommandPacket((JdwpCommandPacket) packet); + else + addReplyPacket((JdwpReplyPacket) packet); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketSendManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketSendManager.java new file mode 100644 index 0000000000..002c66121c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/PacketSendManager.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.util.LinkedList; + +import org.eclipse.jdi.internal.jdwp.JdwpPacket; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.connect.spi.Connection; + +/** + * This class implements a thread that sends available packets to the Virtual + * Machine. + * + */ +public class PacketSendManager extends PacketManager { + /** List of packets to be sent to Virtual Machine */ + private final LinkedList fOutgoingPackets; + + /** + * Create a new thread that send packets to the Virtual Machine. + */ + public PacketSendManager(Connection connection) { + super(connection); + fOutgoingPackets = new LinkedList<>(); + } + + @Override + public void disconnectVM() { + super.disconnectVM(); + synchronized (fOutgoingPackets) { + fOutgoingPackets.notifyAll(); + } + } + + /** + * Thread's run method. + */ + @Override + public void run() { + while (!VMIsDisconnected()) { + try { + sendAvailablePackets(); + } + // in each case if the remote VM fails, or has been interrupted, + // disconnect and force a clean up, don't wait for it to happen + catch (InterruptedException e) { + disconnectVM(); + } catch (InterruptedIOException e) { + disconnectVM(e); + } catch (IOException e) { + disconnectVM(e); + } + } + } + + /** + * Add a packet to be sent to the Virtual Machine. + */ + public void sendPacket(JdwpPacket packet) { + if (VMIsDisconnected()) { + String message; + if (getDisconnectException() == null) { + message = ConnectMessages.PacketSendManager_Got_IOException_from_Virtual_Machine_1; + } else { + String exMessage = getDisconnectException().getMessage(); + if (exMessage == null) { + message = NLS.bind(ConnectMessages.PacketSendManager_Got__0__from_Virtual_Machine_1, + new String[] { getDisconnectException() + .getClass().getName() }); + } else { + message = NLS.bind(ConnectMessages.PacketSendManager_Got__0__from_Virtual_Machine___1__1, + new String[] { + getDisconnectException().getClass() + .getName(), exMessage }); + } + } + throw new VMDisconnectedException(message); + } + + synchronized (fOutgoingPackets) { + // Add packet to list of packets to send. + fOutgoingPackets.add(packet); + // Notify PacketSendThread that data is available. + fOutgoingPackets.notifyAll(); + } + } + + /** + * Send available packets to the Virtual Machine. + */ + private void sendAvailablePackets() throws InterruptedException, + IOException { + LinkedList packetsToSend = new LinkedList<>(); + synchronized (fOutgoingPackets) { + while (fOutgoingPackets.isEmpty()) { + fOutgoingPackets.wait(); + } + packetsToSend.addAll(fOutgoingPackets); + fOutgoingPackets.clear(); + } + + // Put available packets on Output Stream. + while (packetsToSend.size() > 0) { + // Note that only JdwpPackets are added to the list, so a + // ClassCastException can't occur. + JdwpPacket packet = packetsToSend.removeFirst(); + byte[] bytes = packet.getPacketAsBytes(); + getConnection().writePacket(bytes); + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java new file mode 100644 index 0000000000..f2f90a7a81 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketAttachingConnectorImpl.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdi.internal.VirtualMachineManagerImpl; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.spi.Connection; + +public class SocketAttachingConnectorImpl extends ConnectorImpl implements + AttachingConnector { + /** Host name to which is attached. */ + private String fHostname; + /** Port to which is attached. */ + private int fPort; + private int fTimeout; + + /** + * Creates new SocketAttachingConnectorImpl. + */ + public SocketAttachingConnectorImpl( + VirtualMachineManagerImpl virtualMachineManager) { + super(virtualMachineManager); + + // Create communication protocol specific transport. + SocketTransportImpl transport = new SocketTransportImpl(); + setTransport(transport); + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.Connector#defaultArguments() + */ + @Override + public Map defaultArguments() { + HashMap arguments = new HashMap<>(2); + + // Host name + StringArgumentImpl strArg = new StringArgumentImpl( + "hostname", ConnectMessages.SocketAttachingConnectorImpl_Machine_name_to_which_to_attach_for_VM_connections_1, ConnectMessages.SocketAttachingConnectorImpl_Host_2, false); //$NON-NLS-1$ + strArg.setValue("localhost"); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Port + IntegerArgumentImpl intArg = new IntegerArgumentImpl( + "port", ConnectMessages.SocketAttachingConnectorImpl_Port_number_to_which_to_attach_for_VM_connections_3, ConnectMessages.SocketAttachingConnectorImpl_Port_4, true, SocketTransportImpl.MIN_PORTNR, SocketTransportImpl.MAX_PORTNR); //$NON-NLS-1$ + arguments.put(intArg.name(), intArg); + + // Timeout + IntegerArgumentImpl timeoutArg = new IntegerArgumentImpl( + "timeout", ConnectMessages.SocketAttachingConnectorImpl_1, ConnectMessages.SocketAttachingConnectorImpl_2, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$ + timeoutArg.setValue(0); // by default wait forever + arguments.put(timeoutArg.name(), timeoutArg); + + return arguments; + } + + /** + * @return Returns a short identifier for the connector. + */ + @Override + public String name() { + return "com.sun.jdi.SocketAttach"; //$NON-NLS-1$ + } + + /** + * @return Returns a human-readable description of this connector and its + * purpose. + */ + @Override + public String description() { + return ConnectMessages.SocketAttachingConnectorImpl_Attaches_by_socket_to_other_VMs_5; + } + + /** + * Retrieves connection arguments. + */ + private void getConnectionArguments(Map connectionArgs) + throws IllegalConnectorArgumentsException { + String attribute = ""; //$NON-NLS-1$ + try { + attribute = "hostname"; //$NON-NLS-1$ + fHostname = ((Connector.StringArgument) connectionArgs + .get(attribute)).value(); + attribute = "port"; //$NON-NLS-1$ + fPort = ((Connector.IntegerArgument) connectionArgs.get(attribute)) + .intValue(); + attribute = "timeout"; //$NON-NLS-1$ + Object object = connectionArgs.get(attribute); + if (object != null) { + Connector.IntegerArgument timeoutArg = (IntegerArgument) object; + if (timeoutArg.value() != null) { + fTimeout = timeoutArg.intValue(); + } + } + } catch (ClassCastException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketAttachingConnectorImpl_Connection_argument_is_not_of_the_right_type_6, + attribute); + } catch (NullPointerException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketAttachingConnectorImpl_Necessary_connection_argument_is_null_7, + attribute); + } catch (NumberFormatException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketAttachingConnectorImpl_Connection_argument_is_not_a_number_8, + attribute); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.AttachingConnector#attach(java.util.Map) + */ + @Override + public VirtualMachine attach(Map connectionArgs) throws IOException, + IllegalConnectorArgumentsException { + getConnectionArguments(connectionArgs); + Connection connection = null; + try { + connection = ((SocketTransportImpl) fTransport).attach(fHostname, + fPort, fTimeout, 0); + } catch (IllegalArgumentException e) { + List args = new ArrayList<>(); + args.add("hostname"); //$NON-NLS-1$ + args.add("port"); //$NON-NLS-1$ + throw new IllegalConnectorArgumentsException(e.getMessage(), args); + } + return establishedConnection(connection); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java new file mode 100644 index 0000000000..cfe5cb6bb8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketConnection.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Google Inc - add support for accepting multiple connections + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import com.sun.jdi.connect.spi.ClosedConnectionException; +import com.sun.jdi.connect.spi.Connection; + +public class SocketConnection extends Connection { + + // for attaching connector + private Socket fSocket; + + private final InputStream fInput; + + private final OutputStream fOutput; + + SocketConnection(Socket socket, InputStream in, OutputStream out) { + fSocket = socket; + fInput = in; + fOutput = out; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.Connection#close() + */ + @Override + public synchronized void close() throws IOException { + if (fSocket == null) + return; + + fSocket.close(); + fSocket = null; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.Connection#isOpen() + */ + @Override + public synchronized boolean isOpen() { + return fSocket != null; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.Connection#readPacket() + */ + @Override + public byte[] readPacket() throws IOException { + DataInputStream stream; + synchronized (this) { + if (!isOpen()) { + throw new ClosedConnectionException(); + } + stream = new DataInputStream(fInput); + } + synchronized (stream) { + int packetLength = 0; + try { + packetLength = stream.readInt(); + } catch (IOException e) { + throw new ClosedConnectionException(); + } + + if (packetLength < 11) { + throw new IOException("JDWP Packet under 11 bytes"); //$NON-NLS-1$ + } + + byte[] packet = new byte[packetLength]; + packet[0] = (byte) ((packetLength >>> 24) & 0xFF); + packet[1] = (byte) ((packetLength >>> 16) & 0xFF); + packet[2] = (byte) ((packetLength >>> 8) & 0xFF); + packet[3] = (byte) ((packetLength >>> 0) & 0xFF); + + stream.readFully(packet, 4, packetLength - 4); + return packet; + } + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.Connection#writePacket(byte[]) + */ + @Override + public void writePacket(byte[] packet) throws IOException { + if (!isOpen()) { + throw new ClosedConnectionException(); + } + if (packet == null) { + throw new IllegalArgumentException( + "Invalid JDWP Packet, packet cannot be null"); //$NON-NLS-1$ + } + if (packet.length < 11) { + throw new IllegalArgumentException( + "Invalid JDWP Packet, must be at least 11 bytes. PacketSize:" + packet.length); //$NON-NLS-1$ + } + + int packetSize = getPacketLength(packet); + if (packetSize < 11) { + throw new IllegalArgumentException( + "Invalid JDWP Packet, must be at least 11 bytes. PacketSize:" + packetSize); //$NON-NLS-1$ + } + + if (packetSize > packet.length) { + throw new IllegalArgumentException( + "Invalid JDWP packet: Specified length is greater than actual length"); //$NON-NLS-1$ + } + + OutputStream stream = null; + synchronized (this) { + if (!isOpen()) { + throw new ClosedConnectionException(); + } + stream = fOutput; + } + + synchronized (stream) { + // packet.length can be > packetSize. Sending too much will cause + // errors on the other side + stream.write(packet, 0, packetSize); + } + } + + private int getPacketLength(byte[] packet) { + int len = 0; + if (packet.length >= 4) { + len = (((packet[0] & 0xFF) << 24) + ((packet[1] & 0xFF) << 16) + + ((packet[2] & 0xFF) << 8) + ((packet[3] & 0xFF) << 0)); + } + return len; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java new file mode 100644 index 0000000000..6669dac80d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately + * from Eclipse + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.File; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.ServerSocket; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.VirtualMachineManagerImpl; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.VMStartException; + +public class SocketLaunchingConnectorImpl extends ConnectorImpl implements + LaunchingConnector { + /** Time that a launched VM is given to connect to us. */ + private static final int ACCEPT_TIMEOUT = 10 * 1000; + + /** + * Home directory of the SDK or runtime environment used to launch the + * application. + */ + private String fHome; + /** Launched VM options. */ + private String fOptions; + /** + * Main class and arguments, or if -jar is an option, the main jar file and + * arguments. + */ + private String fMain; + /** All threads will be suspended before execution of main. */ + private boolean fSuspend; + /** Name of the Java VM launcher. */ + private String fLauncher; + /** + * List of all threads includes virtual threads as well as platform threads. + * Virtual threads are a preview feature of the Java platform. + * @since 3.20 + */ + private boolean fIncludeVirtualThreads; + + /** + * Creates new SocketAttachingConnectorImpl. + */ + public SocketLaunchingConnectorImpl( + VirtualMachineManagerImpl virtualMachineManager) { + super(virtualMachineManager); + + // Create communication protocol specific transport. + SocketTransportImpl transport = new SocketTransportImpl(); + setTransport(transport); + } + + /** + * @return Returns the default arguments. + */ + @Override + public Map defaultArguments() { + HashMap arguments = new HashMap<>(6); + + // Home + StringArgumentImpl strArg = new StringArgumentImpl( + "home", ConnectMessages.SocketLaunchingConnectorImpl_Home_directory_of_the_SDK_or_runtime_environment_used_to_launch_the_application_1, ConnectMessages.SocketLaunchingConnectorImpl_Home_2, false); //$NON-NLS-1$ + strArg.setValue(System.getProperty("java.home")); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Options + strArg = new StringArgumentImpl( + "options", ConnectMessages.SocketLaunchingConnectorImpl_Launched_VM_options_3, ConnectMessages.SocketLaunchingConnectorImpl_Options_4, false); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Main + strArg = new StringArgumentImpl( + "main", ConnectMessages.SocketLaunchingConnectorImpl_Main_class_and_arguments__or_if__jar_is_an_option__the_main_jar_file_and_arguments_5, ConnectMessages.SocketLaunchingConnectorImpl_Main_6, true); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Suspend + BooleanArgumentImpl boolArg = new BooleanArgumentImpl( + "suspend", ConnectMessages.SocketLaunchingConnectorImpl_All_threads_will_be_suspended_before_execution_of_main_7, ConnectMessages.SocketLaunchingConnectorImpl_Suspend_8, false); //$NON-NLS-1$ + boolArg.setValue(true); + arguments.put(boolArg.name(), boolArg); + + // Quote + strArg = new StringArgumentImpl( + "quote", ConnectMessages.SocketLaunchingConnectorImpl_Character_used_to_combine_space_delimited_text_into_a_single_command_line_argument_9, ConnectMessages.SocketLaunchingConnectorImpl_Quote_10, true); //$NON-NLS-1$ + strArg.setValue("\""); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Launcher + strArg = new StringArgumentImpl( + "vmexec", ConnectMessages.SocketLaunchingConnectorImpl_Name_of_the_Java_VM_launcher_11, ConnectMessages.SocketLaunchingConnectorImpl_Launcher_12, true); //$NON-NLS-1$ + strArg.setValue("java"); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Include Virtual Threads + BooleanArgumentImpl vthreadsArg = new BooleanArgumentImpl( + "includevirtualthreads", ConnectMessages.SocketLaunchingConnectorImpl_Include_virtual_threads_17, ConnectMessages.SocketLaunchingConnectorImpl_IncludeVirtualThreads_18, false); //$NON-NLS-1$ + vthreadsArg.setValue(false); + arguments.put(vthreadsArg.name(), vthreadsArg); + + return arguments; + } + + /** + * @return Returns a short identifier for the connector. + */ + @Override + public String name() { + return "com.sun.jdi.CommandLineLaunch"; //$NON-NLS-1$ + } + + /** + * @return Returns a human-readable description of this connector and its + * purpose. + */ + @Override + public String description() { + return ConnectMessages.SocketLaunchingConnectorImpl_Launches_target_using_Sun_Java_VM_command_line_and_attaches_to_it_13; + } + + /** + * Retrieves connection arguments. + */ + private void getConnectionArguments(Map connectionArgs) + throws IllegalConnectorArgumentsException { + String attribute = ""; //$NON-NLS-1$ + try { + attribute = "home"; //$NON-NLS-1$ + fHome = ((Connector.StringArgument) connectionArgs.get(attribute)) + .value(); + attribute = "options"; //$NON-NLS-1$ + fOptions = ((Connector.StringArgument) connectionArgs + .get(attribute)).value(); + attribute = "main"; //$NON-NLS-1$ + fMain = ((Connector.StringArgument) connectionArgs.get(attribute)) + .value(); + attribute = "suspend"; //$NON-NLS-1$ + fSuspend = ((Connector.BooleanArgument) connectionArgs + .get(attribute)).booleanValue(); + attribute = "quote"; //$NON-NLS-1$ + ((Connector.StringArgument) connectionArgs.get(attribute)).value(); + attribute = "vmexec"; //$NON-NLS-1$ + fLauncher = ((Connector.StringArgument) connectionArgs + .get(attribute)).value(); + attribute = "includevirtualthreads"; //$NON-NLS-1$ + fIncludeVirtualThreads = ((Connector.BooleanArgument) connectionArgs + .get(attribute)).booleanValue(); + } catch (ClassCastException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketLaunchingConnectorImpl_Connection_argument_is_not_of_the_right_type_14, + attribute); + } catch (NullPointerException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketLaunchingConnectorImpl_Necessary_connection_argument_is_null_15, + attribute); + } catch (NumberFormatException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketLaunchingConnectorImpl_Connection_argument_is_not_a_number_16, + attribute); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.LaunchingConnector#launch(java.util.Map) + */ + @Override + public VirtualMachine launch(Map connectionArgs) throws IOException, + IllegalConnectorArgumentsException, VMStartException { + getConnectionArguments(connectionArgs); + + // A listening connector is used that waits for a connection of the VM + // that is started up. + // Note that port number zero means that a free port is chosen. + SocketListeningConnectorImpl listenConnector = new SocketListeningConnectorImpl( + virtualMachineManager()); + Map args = listenConnector.defaultArguments(); + ((Connector.IntegerArgument) args.get("timeout")).setValue(ACCEPT_TIMEOUT); //$NON-NLS-1$ + String address = listenConnector.startListening(args); + + // String for Executable. + String execString = fHome + File.separatorChar + "bin" + File.separatorChar + fLauncher; //$NON-NLS-1$ + + // Add Debug options. + execString += " -Xdebug -Xnoagent -Djava.compiler=NONE"; //$NON-NLS-1$ + execString += " -Xrunjdwp:transport=dt_socket,address=" + address + ",server=n,suspend=" + (fSuspend ? "y" : "n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + if (fIncludeVirtualThreads) { // The default value is 'n', add it only when explicitly enabled. + execString += ",includevirtualthreads=y"; //$NON-NLS-1$ + } + + // Add User specified options. + if (fOptions != null) { + execString += " " + fOptions; //$NON-NLS-1$ + } + + // Add Main class. + execString += " " + fMain; //$NON-NLS-1$ + + // Start VM. + String[] cmdLine = DebugPlugin.parseArguments(execString); + Process proc = Runtime.getRuntime().exec(cmdLine); + + // The accept times out if the VM does not connect. + VirtualMachineImpl virtualMachine; + try { + virtualMachine = (VirtualMachineImpl) listenConnector.accept(args); + } catch (InterruptedIOException e) { + proc.destroy(); + String message = NLS.bind(ConnectMessages.SocketLaunchingConnectorImpl_VM_did_not_connect_within_given_time___0__ms_1, + new String[] { ((Connector.IntegerArgument) args + .get("timeout")).value() }); //$NON-NLS-1$ + throw new VMStartException(message, proc); + } + + virtualMachine.setLaunchedProcess(proc); + return virtualMachine; + } + + /** + * Returns a free port number on localhost, or -1 if unable to find a free + * port. + * + * @return a free port number on localhost, or -1 if unable to find a free + * port + * @since 3.2 + */ + public static int findFreePort() { + try (ServerSocket socket = new ServerSocket(0)) { + return socket.getLocalPort(); + } catch (IOException e) { + } + return -1; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java new file mode 100644 index 0000000000..136028129e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketListeningConnectorImpl.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately + * from Eclipse + * Google Inc - add support for accepting multiple connections + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdi.internal.VirtualMachineManagerImpl; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.ListeningConnector; + +public class SocketListeningConnectorImpl extends ConnectorImpl implements ListeningConnector { + /** Port to which is attached. */ + private int fPort; + /** Timeout before accept returns. */ + private int fTimeout; + + /** + * Creates new SocketAttachingConnectorImpl. + */ + public SocketListeningConnectorImpl( + VirtualMachineManagerImpl virtualMachineManager) { + super(virtualMachineManager); + + // Create communication protocol specific transport. + SocketTransportImpl transport = new SocketTransportImpl(); + setTransport(transport); + } + + /** + * @return Returns the default arguments. + */ + @Override + public Map defaultArguments() { + HashMap arguments = new HashMap<>(1); + + // Port + IntegerArgumentImpl intArg = new IntegerArgumentImpl( + "port", ConnectMessages.SocketListeningConnectorImpl_Port_number_at_which_to_listen_for_VM_connections_1, ConnectMessages.SocketListeningConnectorImpl_Port_2, true, SocketTransportImpl.MIN_PORTNR, SocketTransportImpl.MAX_PORTNR); //$NON-NLS-1$ + arguments.put(intArg.name(), intArg); + + // Timeout + intArg = new IntegerArgumentImpl( + "timeout", ConnectMessages.SocketListeningConnectorImpl_Timeout_before_accept_returns_3, ConnectMessages.SocketListeningConnectorImpl_Timeout_4, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$ + arguments.put(intArg.name(), intArg); + + // FIXME: connectionLimit is not actually used in this class, but in the higher-level controller, SocketListenConnector. + // But IntegerArgumentImpl is package restricted so we must put it here. + intArg = new IntegerArgumentImpl("connectionLimit", ConnectMessages.SocketListeningConnectorImpl_Limit_incoming_connections, ConnectMessages.SocketListeningConnectorImpl_Limit, false, 0, Integer.MAX_VALUE); //$NON-NLS-1$ + intArg.setValue(1); // mimics previous behaviour, allowing a single connection + arguments.put(intArg.name(), intArg); + + return arguments; + } + + /** + * @return Returns a short identifier for the connector. + */ + @Override + public String name() { + return "com.sun.jdi.SocketListen"; //$NON-NLS-1$ + } + + /** + * @return Returns a human-readable description of this connector and its + * purpose. + */ + @Override + public String description() { + return ConnectMessages.SocketListeningConnectorImpl_Accepts_socket_connections_initiated_by_other_VMs_5; + } + + /** + * Retrieves connection arguments. + */ + private void getConnectionArguments(Map connectionArgs) throws IllegalConnectorArgumentsException { + String attribute = "port"; //$NON-NLS-1$ + try { + // If listening port is not specified, use port 0 + IntegerArgument argument = (IntegerArgument) connectionArgs + .get(attribute); + if (argument != null && argument.value() != null) { + fPort = argument.intValue(); + } else { + fPort = 0; + } + // Note that timeout is not used in SUN's ListeningConnector, but is + // used by our + // LaunchingConnector. + attribute = "timeout"; //$NON-NLS-1$ + argument = (IntegerArgument) connectionArgs.get(attribute); + if (argument != null && argument.value() != null) { + fTimeout = argument.intValue(); + } else { + fTimeout = 0; + } + } catch (ClassCastException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6, + attribute); + } catch (NullPointerException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7, + attribute); + } catch (NumberFormatException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8, + attribute); + } + } + + /** + * Listens for one or more connections initiated by target VMs. + * + * @return Returns the address at which the connector is listening for a + * connection. + */ + @Override + public String startListening(Map connectionArgs) throws IOException, IllegalConnectorArgumentsException { + getConnectionArguments(connectionArgs); + String result = null; + try { + result = ((SocketTransportImpl) fTransport).startListening(fPort); + } catch (IllegalArgumentException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketListeningConnectorImpl_ListeningConnector_Socket_Port, + "port"); //$NON-NLS-1$ + } + return result; + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.ListeningConnector#stopListening(java.util.Map) + */ + @Override + public void stopListening(Map connectionArgs) throws IOException { + ((SocketTransportImpl) fTransport).stopListening(); + } + + /** + * Waits for a target VM to attach to this connector. + * + * @return Returns a connected Virtual Machine. + */ + @Override + public VirtualMachine accept(Map connectionArgs) throws IOException, IllegalConnectorArgumentsException { + getConnectionArguments(connectionArgs); + SocketConnection connection = (SocketConnection) ((SocketTransportImpl) fTransport) + .accept(fTimeout, 0); + return establishedConnection(connection); + } + + /** + * @return Returns whether this listening connector supports multiple + * connections for a single argument map. + */ + @Override + public boolean supportsMultipleConnections() { + return true; + } + + /** + * @return Returns port number that is listened to. + */ + public int listeningPort() { + return fPort; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketRawLaunchingConnectorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketRawLaunchingConnectorImpl.java new file mode 100644 index 0000000000..85954ade8f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketRawLaunchingConnectorImpl.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.VirtualMachineManagerImpl; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.VMStartException; + +public class SocketRawLaunchingConnectorImpl extends ConnectorImpl implements + LaunchingConnector { + /** Time that a launched VM is given to connect to us. */ + private static final int ACCEPT_TIMEOUT = 10000; + + /** Raw command to start the debugged application VM. */ + private String[] fCommand; + /** + * Address from which to listen for a connection after the raw command is + * run. + */ + private String fAddress; + + /** + * Creates new SocketAttachingConnectorImpl. + */ + public SocketRawLaunchingConnectorImpl( + VirtualMachineManagerImpl virtualMachineManager) { + super(virtualMachineManager); + + // Create communication protocol specific transport. + SocketTransportImpl transport = new SocketTransportImpl(); + setTransport(transport); + } + + /** + * @return Returns the default arguments. + */ + @Override + public Map defaultArguments() { + HashMap arguments = new HashMap<>(3); + + // Command + StringArgumentImpl strArg = new StringArgumentImpl( + "command", ConnectMessages.SocketRawLaunchingConnectorImpl_Raw_command_to_start_the_debugged_application_VM_1, ConnectMessages.SocketRawLaunchingConnectorImpl_Command_2, true); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Address + strArg = new StringArgumentImpl( + "address", ConnectMessages.SocketRawLaunchingConnectorImpl_Address_from_which_to_listen_for_a_connection_after_the_raw_command_is_run_3, ConnectMessages.SocketRawLaunchingConnectorImpl_Address_4, true); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + // Quote + strArg = new StringArgumentImpl( + "quote", ConnectMessages.SocketRawLaunchingConnectorImpl_Character_used_to_combine_space_delimited_text_into_a_single_command_line_argument_5, ConnectMessages.SocketRawLaunchingConnectorImpl_Quote_6, true); //$NON-NLS-1$ + strArg.setValue("\""); //$NON-NLS-1$ + arguments.put(strArg.name(), strArg); + + return arguments; + } + + /** + * @return Returns a short identifier for the connector. + */ + @Override + public String name() { + return "com.sun.jdi.RawCommandLineLaunch"; //$NON-NLS-1$ + } + + /** + * @return Returns a human-readable description of this connector and its + * purpose. + */ + @Override + public String description() { + return ConnectMessages.SocketRawLaunchingConnectorImpl_Launches_target_using_user_specified_command_line_and_attaches_to_it_7; + } + + /** + * Retrieves connection arguments. + */ + private void getConnectionArguments(Map connectionArgs) + throws IllegalConnectorArgumentsException { + String attribute = ""; //$NON-NLS-1$ + try { + attribute = "command"; //$NON-NLS-1$ + fCommand = DebugPlugin.parseArguments(((Connector.StringArgument) connectionArgs + .get(attribute)).value()); + attribute = "address"; //$NON-NLS-1$ + fAddress = ((Connector.StringArgument) connectionArgs + .get(attribute)).value(); + attribute = "quote"; //$NON-NLS-1$ + ((Connector.StringArgument) connectionArgs.get(attribute)).value(); + } catch (ClassCastException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketRawLaunchingConnectorImpl_Connection_argument_is_not_of_the_right_type_8, + attribute); + } catch (NullPointerException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketRawLaunchingConnectorImpl_Necessary_connection_argument_is_null_9, + attribute); + } catch (NumberFormatException e) { + throw new IllegalConnectorArgumentsException( + ConnectMessages.SocketRawLaunchingConnectorImpl_Connection_argument_is_not_a_number_10, + attribute); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.connect.LaunchingConnector#launch(java.util.Map) + */ + @Override + public VirtualMachine launch(Map connectionArgs) throws IOException, + IllegalConnectorArgumentsException, VMStartException { + getConnectionArguments(connectionArgs); + + // A listening connector is used that waits for a connection of the VM + // that is started up. + // Note that port number zero means that a free port is chosen. + SocketListeningConnectorImpl listenConnector = new SocketListeningConnectorImpl( + virtualMachineManager()); + Map args = listenConnector.defaultArguments(); + ((Connector.IntegerArgument) args.get("port")).setValue(fAddress); //$NON-NLS-1$ + ((Connector.IntegerArgument) args.get("timeout")).setValue(ACCEPT_TIMEOUT); //$NON-NLS-1$ + listenConnector.startListening(args); + + // Start VM. + Process proc = Runtime.getRuntime().exec(fCommand); + + // The accept times out it the VM does not connect. + VirtualMachineImpl virtualMachine; + try { + virtualMachine = (VirtualMachineImpl) listenConnector.accept(args); + } catch (InterruptedIOException e) { + proc.destroy(); + String message = NLS.bind(ConnectMessages.SocketLaunchingConnectorImpl_VM_did_not_connect_within_given_time___0__ms_1, + new String[] { ((Connector.IntegerArgument) args + .get("timeout")).value() }); //$NON-NLS-1$ + throw new VMStartException(message, proc); + } + + virtualMachine.setLaunchedProcess(proc); + return virtualMachine; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java new file mode 100644 index 0000000000..feffeebf9a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportImpl.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; + +import com.sun.jdi.connect.Transport; +import com.sun.jdi.connect.spi.Connection; +import com.sun.jdi.connect.spi.TransportService.ListenKey; + +public class SocketTransportImpl implements Transport { + public static final String TRANSPORT_NAME = "dt_socket"; //$NON-NLS-1$ + public static final int MIN_PORTNR = 0; + public static final int MAX_PORTNR = 65535; + + SocketTransportService service; + private ListenKey fListenKey; + + /** + * Constructs new SocketTransportImpl. + */ + public SocketTransportImpl() { + service = new SocketTransportService(); + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.Transport#name() + */ + @Override + public String name() { + return TRANSPORT_NAME; + } + + public Connection attach(String hostname, int port, long attachTimeout, + long handshakeTimeout) throws IOException { + return service.attach(hostname, port, attachTimeout, handshakeTimeout); + } + + public String startListening(int port) throws IOException { + fListenKey = service.startListening(port + ""); //$NON-NLS-1$ + return fListenKey.address(); + } + + public void stopListening() throws IOException { + service.stopListening(fListenKey); + } + + public Connection accept(long attachTimeout, long handshakeTimeout) + throws IOException { + return service.accept(fListenKey, attachTimeout, handshakeTimeout); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java new file mode 100644 index 0000000000..df0ac331d9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketTransportService.java @@ -0,0 +1,326 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Ivan Popov - Bug 184211: JDI connectors throw NullPointerException if used separately + * from Eclipse + * Google Inc - add support for accepting multiple connections + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.Arrays; + +import org.eclipse.jdi.TimeoutException; + +import com.sun.jdi.connect.TransportTimeoutException; +import com.sun.jdi.connect.spi.ClosedConnectionException; +import com.sun.jdi.connect.spi.Connection; +import com.sun.jdi.connect.spi.TransportService; + +public class SocketTransportService extends TransportService { + /** Handshake bytes used just after connecting VM. */ + private static final byte[] handshakeBytes = "JDWP-Handshake".getBytes(); //$NON-NLS-1$ + + private final Capabilities fCapabilities = new Capabilities() { + @Override + public boolean supportsAcceptTimeout() { + return true; + } + + @Override + public boolean supportsAttachTimeout() { + return true; + } + + @Override + public boolean supportsHandshakeTimeout() { + return true; + } + + @Override + public boolean supportsMultipleConnections() { + return false; + } + }; + + private static class SocketListenKey extends ListenKey { + private final String fAddress; + + SocketListenKey(String address) { + fAddress = address; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.TransportService.ListenKey#address() + */ + @Override + public String address() { + return fAddress; + } + } + + // for listening or accepting connectors + private ServerSocket fServerSocket; + + /* + * (non-Javadoc) + * + * @see + * com.sun.jdi.connect.spi.TransportService#accept(com.sun.jdi.connect.spi + * .TransportService.ListenKey, long, long) + */ + @Override + public Connection accept(ListenKey listenKey, long attachTimeout, + long handshakeTimeout) throws IOException { + if (attachTimeout > 0) { + if (attachTimeout > Integer.MAX_VALUE) { + attachTimeout = Integer.MAX_VALUE; // approx 25 days! + } + fServerSocket.setSoTimeout((int) attachTimeout); + } + Socket socket; + try { + socket = fServerSocket.accept(); + } catch (SocketTimeoutException e) { + throw new TransportTimeoutException(); + } + InputStream input = socket.getInputStream(); + OutputStream output = socket.getOutputStream(); + performHandshake(input, output, handshakeTimeout); + return new SocketConnection(socket, input, output); + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.TransportService#attach(java.lang.String, + * long, long) + */ + @Override + public Connection attach(String address, long attachTimeout, + long handshakeTimeout) throws IOException { + String[] strings = address.split(":"); //$NON-NLS-1$ + String host = "localhost"; //$NON-NLS-1$ + int port = 0; + if (strings.length == 2) { + host = strings[0]; + port = Integer.parseInt(strings[1]); + } else { + port = Integer.parseInt(strings[0]); + } + + return attach(host, port, attachTimeout, handshakeTimeout); + } + + public Connection attach(final String host, final int port, + long attachTimeout, final long handshakeTimeout) throws IOException { + if (attachTimeout > 0) { + if (attachTimeout > Integer.MAX_VALUE) { + attachTimeout = Integer.MAX_VALUE; // approx 25 days! + } + } + + final IOException[] ex = new IOException[1]; + final SocketConnection[] result = new SocketConnection[1]; + Thread attachThread = new Thread(new Runnable() { + @Override + public void run() { + try { + Socket socket = new Socket(host, port); + InputStream input = socket.getInputStream(); + OutputStream output = socket.getOutputStream(); + performHandshake(input, output, handshakeTimeout); + result[0] = new SocketConnection(socket, input, output); + } catch (IOException e) { + ex[0] = e; + } + } + }, ConnectMessages.SocketTransportService_0); + attachThread.setDaemon(true); + attachThread.start(); + try { + attachThread.join(attachTimeout); + if (attachThread.isAlive()) { + attachThread.interrupt(); + throw new TimeoutException(); + } + } catch (InterruptedException e) { + } + + if (ex[0] != null) { + throw ex[0]; + } + + return result[0]; + } + + void performHandshake(final InputStream in, final OutputStream out, + final long timeout) throws IOException { + final IOException[] ex = new IOException[1]; + final boolean[] handshakeCompleted = new boolean[1]; + + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + writeHandshake(out); + readHandshake(in); + handshakeCompleted[0] = true; + } catch (IOException e) { + ex[0] = e; + } + } + }, ConnectMessages.SocketTransportService_1); + t.setDaemon(true); + t.start(); + try { + t.join(timeout); + } catch (InterruptedException e1) { + } + + if (handshakeCompleted[0]) { + return; + } + + try { + in.close(); + out.close(); + } catch (IOException e) { + } + + if (ex[0] != null) { + throw ex[0]; + } + + throw new TransportTimeoutException(); + } + + private void readHandshake(InputStream input) throws IOException { + try { + DataInputStream in = new DataInputStream(input); + byte[] handshakeInput = new byte[handshakeBytes.length]; + in.readFully(handshakeInput); + if (!Arrays.equals(handshakeInput, handshakeBytes)) { + throw new IOException("Received invalid handshake"); //$NON-NLS-1$ + } + } catch (EOFException e) { + throw new ClosedConnectionException(); + } + } + + private void writeHandshake(OutputStream out) throws IOException { + out.write(handshakeBytes); + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.TransportService#capabilities() + */ + @Override + public Capabilities capabilities() { + return fCapabilities; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.TransportService#description() + */ + @Override + public String description() { + return "org.eclipse.jdt.debug: Socket Implementation of TransportService"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.TransportService#name() + */ + @Override + public String name() { + return "org.eclipse.jdt.debug_SocketTransportService"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.connect.spi.TransportService#startListening() + */ + @Override + public ListenKey startListening() throws IOException { + // not used by jdt debug. + return startListening(null); + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.jdi.connect.spi.TransportService#startListening(java.lang.String) + */ + @Override + public ListenKey startListening(String address) throws IOException { + String host = null; + int port = -1; + if (address != null) { + // jdt debugger will always specify an address in + // the form localhost:port + String[] strings = address.split(":"); //$NON-NLS-1$ + host = "localhost"; //$NON-NLS-1$ + if (strings.length == 2) { + host = strings[0]; + port = Integer.parseInt(strings[1]); + } else { + port = Integer.parseInt(strings[0]); + } + } + if (port == -1) { + throw new IOException("Unable to decode port from address: " + address); //$NON-NLS-1$ + } + if (host == null) { + host = "localhost"; //$NON-NLS-1$ + } + + fServerSocket = new ServerSocket(port); + port = fServerSocket.getLocalPort(); + ListenKey listenKey = new SocketListenKey(host + ":" + port); //$NON-NLS-1$ + return listenKey; + } + + /* + * (non-Javadoc) + * + * @see + * com.sun.jdi.connect.spi.TransportService#stopListening(com.sun.jdi.connect + * .spi.TransportService.ListenKey) + */ + @Override + public void stopListening(ListenKey arg1) throws IOException { + if (fServerSocket != null) { + try { + fServerSocket.close(); + } catch (IOException e) { + } + } + fServerSocket = null; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/TransportImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/TransportImpl.java new file mode 100644 index 0000000000..b4a575f149 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/TransportImpl.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.connect; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.sun.jdi.connect.Transport; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class TransportImpl implements Transport { + /** Name of Transport. */ + private final String fName; + + /** + * Constructs new SocketTransportImpl. + */ + public TransportImpl(String name) { + fName = name; + } + + /** + * @return Returns a short identifier for the transport. + */ + @Override + public String name() { + return fName; + } + + /** + * @return Returns true if we have an open connection. + */ + public abstract boolean isOpen(); + + /** + * Closes connection. + */ + public abstract void close(); + + /** + * @return Returns InputStream from Virtual Machine. + */ + public abstract InputStream getInputStream() throws IOException; + + /** + * @return Returns OutputStream to Virtual Machine. + */ + public abstract OutputStream getOutputStream() throws IOException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/AccessWatchpointEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/AccessWatchpointEventImpl.java new file mode 100644 index 0000000000..f1c041b870 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/AccessWatchpointEventImpl.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.AccessWatchpointEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class AccessWatchpointEventImpl extends WatchpointEventImpl implements + AccessWatchpointEvent { + /** JDWP Event Kind. */ + public static final byte EVENT_KIND = EVENT_FIELD_ACCESS; + + /** + * Creates new AccessWatchpointEventImpl. + * @param vmImpl the VM + * @param requestID the request ID + */ + protected AccessWatchpointEventImpl(VirtualMachineImpl vmImpl, + RequestID requestID) { + super("AccessWatchpointEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @param target the target + * @param requestID the request ID + * @param dataInStream the stream + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + * @throws IOException if the read fails + */ + public static WatchpointEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + AccessWatchpointEventImpl event = new AccessWatchpointEventImpl(vmImpl, + requestID); + event.readWatchpointEventFields(target, dataInStream); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/BreakpointEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/BreakpointEventImpl.java new file mode 100644 index 0000000000..ae480f2bab --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/BreakpointEventImpl.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.BreakpointEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class BreakpointEventImpl extends LocatableEventImpl implements + BreakpointEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_BREAKPOINT; + + /** + * Creates new BreakpointEventImpl. + * @param vmImpl the VM + * @param requestID the request ID + */ + private BreakpointEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("BreakpointEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @param target the target + * @param requestID the request ID + * @param dataInStream the stream + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + * @throws IOException if the read fails + */ + public static BreakpointEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + BreakpointEventImpl event = new BreakpointEventImpl(vmImpl, requestID); + event.readThreadAndLocation(target, dataInStream); + ((ThreadReferenceImpl) event.thread()).setIsAtBreakpoint(); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ClassPrepareEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ClassPrepareEventImpl.java new file mode 100644 index 0000000000..4f6429efba --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ClassPrepareEventImpl.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ReferenceTypeImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.ReferenceType; +import com.sun.jdi.event.ClassPrepareEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassPrepareEventImpl extends EventImpl implements + ClassPrepareEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_CLASS_PREPARE; + + /** Reference type for which this event was generated. */ + private ReferenceTypeImpl fReferenceType; + + /** + * Creates new BreakpointEventImpl. + */ + private ClassPrepareEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("ClassPrepareEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static ClassPrepareEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + ClassPrepareEventImpl event = new ClassPrepareEventImpl(vmImpl, + requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + event.fReferenceType = ReferenceTypeImpl.readWithTypeTagAndSignature( + target, false, dataInStream); + target.readInt( + "class status", ReferenceTypeImpl.classStatusStrings(), dataInStream); //$NON-NLS-1$ + return event; + } + + /** + * @return Returns the reference type for which this event was generated. + */ + @Override + public ReferenceType referenceType() { + return fReferenceType; + } + + /** + * @return Returns the JNI-style signature of the class that has been + * unloaded. + */ + public String classSignature() { + return referenceType().signature(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ClassUnloadEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ClassUnloadEventImpl.java new file mode 100644 index 0000000000..2dba7e3f04 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ClassUnloadEventImpl.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.TypeImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.ClassUnloadEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassUnloadEventImpl extends EventImpl implements ClassUnloadEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_CLASS_UNLOAD; + + /** Type signature. */ + private String fSignature; + + /** + * Creates new ClassUnloadEventImpl. + */ + private ClassUnloadEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("ClassUnloadEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static ClassUnloadEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + ClassUnloadEventImpl event = new ClassUnloadEventImpl(vmImpl, requestID); + event.fSignature = target.readString("signature", dataInStream); //$NON-NLS-1$ + // Remove the class from classes that are known by the application to be + // loaded in the VM. + vmImpl.removeKnownRefType(event.fSignature); + return event; + } + + /** + * @return Returns the name of the class that has been unloaded. + */ + @Override + public String className() { + return TypeImpl.signatureToName(fSignature); + } + + /** + * @return Returns the JNI-style signature of the class that has been + * unloaded. + */ + @Override + public String classSignature() { + return fSignature; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventImpl.java new file mode 100644 index 0000000000..f0887e854a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventImpl.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.ThreadReference; +import com.sun.jdi.event.Event; +import com.sun.jdi.request.EventRequest; + +/** + * This class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class EventImpl extends MirrorImpl implements Event { + /** Constants for EventKind. */ + public static final byte EVENT_SINGLE_STEP = 1; + public static final byte EVENT_BREAKPOINT = 2; + public static final byte EVENT_FRAME_POP = 3; + public static final byte EVENT_EXCEPTION = 4; + public static final byte EVENT_USER_DEFINED = 5; + public static final byte EVENT_THREAD_START = 6; + public static final byte EVENT_THREAD_END = 7; + public static final byte EVENT_CLASS_PREPARE = 8; + public static final byte EVENT_CLASS_UNLOAD = 9; + public static final byte EVENT_CLASS_LOAD = 10; + public static final byte EVENT_FIELD_ACCESS = 20; + public static final byte EVENT_FIELD_MODIFICATION = 21; + public static final byte EVENT_EXCEPTION_CATCH = 30; + public static final byte EVENT_METHOD_ENTRY = 40; + public static final byte EVENT_METHOD_EXIT = 41; + public static final byte EVENT_METHOD_EXIT_WITH_RETURN_VALUE = 42; + public static final byte EVENT_MONITOR_CONTENDED_ENTER = 43; + public static final byte EVENT_MONITOR_CONTENDED_ENTERED = 44; + public static final byte EVENT_MONITOR_WAIT = 45; + public static final byte EVENT_MONITOR_WAITED = 46; + public static final byte EVENT_VM_INIT = 90; + public static final byte EVENT_VM_DEATH = 99; + public static final byte EVENT_VM_DISCONNECTED = 100; // Never sent by + // across JDWP. + public static final byte EVENT_VM_START = EVENT_VM_INIT; + public static final byte EVENT_THREAD_DEATH = EVENT_THREAD_END; + + /** ThreadReference of thread that generated this event. */ + protected ThreadReferenceImpl fThreadRef; + + /** Mapping of command codes to strings. */ + private static HashMap fEventKindMap = null; + + /** Request ID of event. */ + private final RequestID fRequestID; + + /** The EventRequest that requested this event. */ + private EventRequest fRequest; + + /** + * Creates new EventImpl, only used by subclasses. + */ + protected EventImpl(String description, VirtualMachineImpl vmImpl, + RequestID requestID) { + super(description, vmImpl); + fRequestID = requestID; + } + + /** + * @return Returns ThreadReference of thread that generated this event. + */ + public ThreadReference thread() { + return fThreadRef; + } + + /** + * @return Returns requestID. + */ + public RequestID requestID() { + return fRequestID; + } + + /** + * @return Returns string representation. + */ + @Override + public String toString() { + return super.toString() + ": " + fRequestID; //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl. + */ + public static EventImpl read(MirrorImpl target, DataInputStream dataInStream) + throws IOException { + byte eventKind = target.readByte( + "event kind", eventKindMap(), dataInStream); //$NON-NLS-1$ + RequestID requestID = RequestID.read(target, dataInStream); + + // Create, read and return Event of eventKind. + EventImpl result; + switch (eventKind) { + case 0: + return null; + case AccessWatchpointEventImpl.EVENT_KIND: + result = AccessWatchpointEventImpl.read(target, requestID, + dataInStream); + break; + case BreakpointEventImpl.EVENT_KIND: + result = BreakpointEventImpl.read(target, requestID, dataInStream); + break; + case ClassPrepareEventImpl.EVENT_KIND: + result = ClassPrepareEventImpl + .read(target, requestID, dataInStream); + break; + case ClassUnloadEventImpl.EVENT_KIND: + result = ClassUnloadEventImpl.read(target, requestID, dataInStream); + break; + case ExceptionEventImpl.EVENT_KIND: + result = ExceptionEventImpl.read(target, requestID, dataInStream); + break; + case MethodEntryEventImpl.EVENT_KIND: + result = MethodEntryEventImpl.read(target, requestID, dataInStream); + break; + case MethodExitEventImpl.EVENT_KIND: + result = MethodExitEventImpl.read(target, requestID, dataInStream); + break; + case EVENT_METHOD_EXIT_WITH_RETURN_VALUE: + result = MethodExitEventImpl.readWithReturnValue(target, requestID, + dataInStream); + break; + case MonitorContendedEnteredEventImpl.EVENT_KIND: + result = MonitorContendedEnteredEventImpl.read(target, requestID, + dataInStream); + break; + case MonitorContendedEnterEventImpl.EVENT_KIND: + result = MonitorContendedEnterEventImpl.read(target, requestID, + dataInStream); + break; + case MonitorWaitedEventImpl.EVENT_KIND: + result = MonitorWaitedEventImpl.read(target, requestID, + dataInStream); + break; + case MonitorWaitEventImpl.EVENT_KIND: + result = MonitorWaitEventImpl.read(target, requestID, dataInStream); + break; + case ModificationWatchpointEventImpl.EVENT_KIND: + result = ModificationWatchpointEventImpl.read(target, requestID, + dataInStream); + break; + case StepEventImpl.EVENT_KIND: + result = StepEventImpl.read(target, requestID, dataInStream); + break; + case ThreadDeathEventImpl.EVENT_KIND: + result = ThreadDeathEventImpl.read(target, requestID, dataInStream); + break; + case ThreadStartEventImpl.EVENT_KIND: + result = ThreadStartEventImpl.read(target, requestID, dataInStream); + break; + case VMDeathEventImpl.EVENT_KIND: + result = VMDeathEventImpl.read(target, requestID, dataInStream); + break; + case VMDisconnectEventImpl.EVENT_KIND: + result = VMDisconnectEventImpl + .read(target, requestID, dataInStream); + break; + case VMStartEventImpl.EVENT_KIND: + result = VMStartEventImpl.read(target, requestID, dataInStream); + break; + default: + throw new IOException( + EventMessages.EventImpl_Read_invalid_EventKind___1 + + eventKind); + } + + // Find and store original request. + if (!requestID.isNull()) + result.fRequest = target.virtualMachineImpl().eventRequestManagerImpl().findRequest(result); + + return result; + } + + /** + * @return Returns EventRequest that caused this event to be generated by + * the Virtual Machine. + */ + @Override + public EventRequest request() { + return fRequest; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fEventKindMap != null) + return; + + java.lang.reflect.Field[] fields = EventImpl.class.getDeclaredFields(); + fEventKindMap = new HashMap<>(); + for (Field field : fields) { + if ((field.getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.FINAL) == 0) + continue; + + try { + String name = field.getName(); + Integer intValue = Integer.valueOf(field.getInt(null)); + + if (name.startsWith("EVENT_")) { //$NON-NLS-1$ + name = name.substring(6); + fEventKindMap.put(intValue, name); + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + public static Map eventKindMap() { + getConstantMaps(); + return fEventKindMap; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventIteratorImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventIteratorImpl.java new file mode 100644 index 0000000000..ef7bf4912a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventIteratorImpl.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.util.ListIterator; + +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventIterator; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class EventIteratorImpl implements EventIterator { + /** List iterator implementation of iterator. */ + private final ListIterator fIterator; + + /** + * Creates new EventIteratorImpl. + */ + public EventIteratorImpl(ListIterator iter) { + fIterator = iter; + } + + /** + * @return Returns next Event from EventSet. + */ + @Override + public Event nextEvent() { + return fIterator.next(); + } + + /** + * @see java.util.Iterator#hasNext() + */ + @Override + public boolean hasNext() { + return fIterator.hasNext(); + } + + /** + * @see java.util.Iterator#next() + */ + @Override + public Event next() { + return fIterator.next(); + } + + /** + * @see java.util.Iterator#remove() + * @exception UnsupportedOperationException + * always thrown since EventSets are unmodifiable. + */ + @Override + public void remove() { + throw new UnsupportedOperationException( + EventMessages.EventIteratorImpl_EventSets_are_unmodifiable_1); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventMessages.java new file mode 100644 index 0000000000..24ec75f29a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventMessages.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import org.eclipse.osgi.util.NLS; + +public class EventMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdi.internal.event.EventMessages";//$NON-NLS-1$ + + public static String EventImpl_Read_invalid_EventKind___1; + public static String EventIteratorImpl_EventSets_are_unmodifiable_1; + public static String EventSetImpl_Invalid_suspend_policy_encountered___1; + public static String EventSetImpl_EventSets_are_unmodifiable_3; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, EventMessages.class); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventMessages.properties new file mode 100644 index 0000000000..7e124ecab3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventMessages.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2000, 2007 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +EventImpl_Read_invalid_EventKind___1=Read invalid EventKind: +EventIteratorImpl_EventSets_are_unmodifiable_1=EventSets are unmodifiable +EventSetImpl_Invalid_suspend_policy_encountered___1=Invalid suspend policy encountered: +EventSetImpl_EventSets_are_unmodifiable_3=EventSets are unmodifiable diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventQueueImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventQueueImpl.java new file mode 100644 index 0000000000..a9046e72e2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventQueueImpl.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.IOException; + +import org.eclipse.jdi.TimeoutException; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.connect.PacketReceiveManager; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class EventQueueImpl extends MirrorImpl implements EventQueue { + /** Flag used to see if a VMDisconnectEvent has already been generated. */ + private boolean genereatedVMDisconnectEvent = false; + + /** + * Creates new EventQueueImpl. + */ + public EventQueueImpl(VirtualMachineImpl vmImpl) { + super("EventQueue", vmImpl); //$NON-NLS-1$ + } + + /* + * @return Returns next EventSet from Virtual Machine. + */ + @Override + public EventSet remove() throws InterruptedException { + return remove(PacketReceiveManager.TIMEOUT_INFINITE); + } + + /* + * @return Returns next EventSet from Virtual Machine, returns null if times + * out. + */ + @Override + public EventSet remove(long timeout) throws InterruptedException { + // Return a received EventSet or null if no EventSet is received in + // time. + // Note that handledJdwpEventSet() is not don in a 'finally' clause + // because + // it must also be done when an 'empty' set is read (i.e. a set composed + // of internal + // events only). + try { + // We remove elements from event sets that are generated from + // inside, therefore the set may become empty. + EventSetImpl set; + do { + JdwpCommandPacket packet = getCommandVM( + JdwpCommandPacket.E_COMPOSITE, timeout); + initJdwpEventSet(packet); + set = EventSetImpl.read(this, packet.dataInStream()); + handledJdwpEventSet(null); + } while (set.isEmpty()); + return set; + } catch (TimeoutException e) { + // Timeout in getCommand, JDI spec says return null. + handledJdwpEventSet(e); + return null; + } catch (IOException e) { + // This means the already received data is invalid. + handledJdwpEventSet(e); + defaultIOExceptionHandler(e); + return null; + } catch (VMDisconnectedException e) { + // JDI spec says that a VMDisconnectedException must always be + // preceeded by a VMDisconnectEvent. + handledJdwpEventSet(e); + if (!genereatedVMDisconnectEvent) { + genereatedVMDisconnectEvent = true; + return new EventSetImpl(virtualMachineImpl(), + new VMDisconnectEventImpl(virtualMachineImpl(), + RequestID.nullID)); + } + throw e; + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventSetImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventSetImpl.java new file mode 100644 index 0000000000..fc50dcd3e3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/EventSetImpl.java @@ -0,0 +1,323 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.EventRequestImpl; + +import com.sun.jdi.InternalException; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventIterator; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.EventRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class EventSetImpl extends MirrorImpl implements EventSet { + /** Set that is used to store events. */ + private List fEvents; + /** Which threads were suspended by this composite event. */ + private byte fSuspendPolicy; + + /** + * Creates new EventSetImpl. + */ + private EventSetImpl(VirtualMachineImpl vmImpl) { + super("EventSet", vmImpl); //$NON-NLS-1$ + } + + /** + * Creates new EventSetImpl with events in a given array. + */ + public EventSetImpl(VirtualMachineImpl vmImpl, EventImpl[] events) { + this(vmImpl); + fEvents = new ArrayList<>(events.length); + for (EventImpl event : events) + fEvents.add(event); + } + + /** + * Creates new EventSetImpl with given event. + */ + public EventSetImpl(VirtualMachineImpl vmImpl, EventImpl event) { + this(vmImpl); + fEvents = new ArrayList<>(1); + fEvents.add(event); + } + + /** + * @return Returns iterator over events. + */ + @Override + public EventIterator eventIterator() { + return new EventIteratorImpl(fEvents.listIterator()); + } + + /** + * @return Returns which threads were suspended by this composite event. + */ + @Override + public int suspendPolicy() { + switch (fSuspendPolicy) { + case EventRequestImpl.SUSPENDPOL_NONE_JDWP: + return EventRequest.SUSPEND_NONE; + case EventRequestImpl.SUSPENDPOL_EVENT_THREAD_JDWP: + return EventRequest.SUSPEND_EVENT_THREAD; + case EventRequestImpl.SUSPENDPOL_ALL_JDWP: + return EventRequest.SUSPEND_ALL; + default: + throw new InternalException( + EventMessages.EventSetImpl_Invalid_suspend_policy_encountered___1 + + fSuspendPolicy); + } + } + + /** + * Resumes threads that were suspended by this event set. + */ + @Override + public void resume() { + switch (fSuspendPolicy) { + case EventRequestImpl.SUSPENDPOL_NONE_JDWP: + break; + case EventRequestImpl.SUSPENDPOL_EVENT_THREAD_JDWP: + resumeThreads(); + break; + case EventRequestImpl.SUSPENDPOL_ALL_JDWP: + virtualMachineImpl().resume(); + break; + default: + throw new InternalException( + EventMessages.EventSetImpl_Invalid_suspend_policy_encountered___1 + + fSuspendPolicy); + } + } + + /** + * Resumes threads that were suspended by this event set. + */ + private void resumeThreads() { + if (fEvents.size() == 1) { + // Most event sets have only one event. + // Avoid expensive object creation. + ThreadReference ref = ((EventImpl)fEvents.get(0)).thread(); + if (ref != null) { + ref.resume(); + } else { + fEvents.get(0).virtualMachine().resume(); + } + return; + } + Iterator iter = fEvents.iterator(); + List resumedThreads = new ArrayList<>(fEvents.size()); + while (iter.hasNext()) { + EventImpl event = (EventImpl)iter.next(); + ThreadReference thread = event.thread(); + if (thread == null) { + event.virtualMachine().resume(); + return; + } + if (!resumedThreads.contains(thread)) { + resumedThreads.add(thread); + } + } + Iterator resumeIter = resumedThreads.iterator(); + while (resumeIter.hasNext()) { + resumeIter.next().resume(); + } + } + + /** + * @return Returns EventSetImpl that was read from InputStream. + */ + public static EventSetImpl read(MirrorImpl target, DataInputStream in) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + EventSetImpl eventSet = new EventSetImpl(vmImpl); + + // Read suspend policy. + eventSet.fSuspendPolicy = target.readByte( + "suspendPolicy", EventRequestImpl.suspendPolicyMap(), in); //$NON-NLS-1$ + // Read size. + int size = target.readInt("size", in); //$NON-NLS-1$ + // Create event list. + eventSet.fEvents = new ArrayList<>(size); + + while (size-- > 0) { + EventImpl event = EventImpl.read(target, in); + + // If event == null than it is an event that must not be given to + // the application. + // See ClassPrepareEvent. + if (event == null) + continue; + + EventRequestImpl request = (EventRequestImpl) event.request(); + + // Check if the request corresponding to the event was not generated + // from inside this JDI implementation. + if (request == null || !request.isGeneratedInside()) + eventSet.fEvents.add(event); + + } + return eventSet; + } + + /** + * @see java.util.Collection + */ + @Override + public boolean contains(Object event) { + return fEvents.contains(event); + } + + /* (non-Javadoc) + * @see java.util.Collection#containsAll(java.util.Collection) + */ + @Override + public boolean containsAll(Collection events) { + return fEvents.containsAll(events); + } + + /** + * @see java.util.Collection + */ + @Override + public boolean equals(Object object) { + return object != null && object.getClass().equals(this.getClass()) + && fEvents.equals(((EventSetImpl) object).fEvents); + } + + /** + * @see java.util.Collection + */ + @Override + public int hashCode() { + return fEvents.hashCode(); + } + + /** + * @see java.util.Collection + */ + @Override + public boolean isEmpty() { + return fEvents.isEmpty(); + } + + /** + * @see java.util.Collection#iterator() + */ + @Override + public Iterator iterator() { + return fEvents.iterator(); + } + + /** + * @see java.util.Collection#size() + */ + @Override + public int size() { + return fEvents.size(); + } + + /** + * @see java.util.Collection#toArray() + */ + @Override + public Object[] toArray() { + return fEvents.toArray(); + } + + /** + * @see java.util.Collection#clear() + * @exception UnsupportedOperationException + * always thrown since EventSets are unmodifiable. + */ + @Override + public void clear() { + throw new UnsupportedOperationException( + EventMessages.EventSetImpl_EventSets_are_unmodifiable_3); + } + + /** + * @see java.util.Collection#remove(Object) + * @exception UnsupportedOperationException + * always thrown since EventSets are unmodifiable. + */ + @Override + public boolean remove(Object arg1) { + throw new UnsupportedOperationException( + EventMessages.EventSetImpl_EventSets_are_unmodifiable_3); + } + + /** + * @see java.util.Collection#removeAll(Collection) + * @exception UnsupportedOperationException + * always thrown since EventSets are unmodifiable. + */ + @Override + public boolean removeAll(Collection arg1) { + throw new UnsupportedOperationException( + EventMessages.EventSetImpl_EventSets_are_unmodifiable_3); + } + + /** + * @see java.util.Collection#retainAll(Collection) + * @exception UnsupportedOperationException + * always thrown since EventSets are unmodifiable. + */ + @Override + public boolean retainAll(Collection arg1) { + throw new UnsupportedOperationException( + EventMessages.EventSetImpl_EventSets_are_unmodifiable_3); + } + + /* (non-Javadoc) + * @see java.util.Collection#toArray(T[]) + */ + @Override + public T[] toArray(T[] a) { + return fEvents.toArray(a); + } + + /* (non-Javadoc) + * @see java.util.Collection#add(java.lang.Object) + */ + @Override + public boolean add(Event o) { + throw new UnsupportedOperationException( + EventMessages.EventSetImpl_EventSets_are_unmodifiable_3); + } + + /* (non-Javadoc) + * @see java.util.Collection#addAll(java.util.Collection) + */ + @Override + public boolean addAll(Collection c) { + throw new UnsupportedOperationException( + EventMessages.EventSetImpl_EventSets_are_unmodifiable_3); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ExceptionEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ExceptionEventImpl.java new file mode 100644 index 0000000000..4266ef0e11 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ExceptionEventImpl.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.Location; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.event.ExceptionEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ExceptionEventImpl extends LocatableEventImpl implements + ExceptionEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_EXCEPTION; + + /** Thrown exception. */ + private ObjectReferenceImpl fException; + /** Location of catch, or 0 if not caught. */ + private LocationImpl fCatchLocation; + /** Whether garbage collection has been re-enabled for the exception. */ + private boolean fExceptionCollectionEnabled; + + /** + * Creates new ExceptionEventImpl. + */ + private ExceptionEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("ExceptionEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static ExceptionEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + ExceptionEventImpl event = new ExceptionEventImpl(vmImpl, requestID); + event.readThreadAndLocation(target, dataInStream); + event.fException = ObjectReferenceImpl.readObjectRefWithTag(target, + dataInStream); + event.fException.disableCollection(); + event.fExceptionCollectionEnabled = false; + event.fCatchLocation = LocationImpl.read(target, dataInStream); + return event; + } + + /** + * @return Returns the location where the exception will be caught. + */ + @Override + public Location catchLocation() { + return fCatchLocation; + } + + /** + * @return Returns the thrown exception object. + */ + @Override + public ObjectReference exception() { + return fException; + } + + /** + * Enables garbage collection for the exception in the event. GC for the exception is initially disabled, until the exception event is processed. + */ + public void enableExceptionGC() { + if (!fExceptionCollectionEnabled && fException != null) { + fException.enableCollection(); + fExceptionCollectionEnabled = true; + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/LocatableEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/LocatableEventImpl.java new file mode 100644 index 0000000000..eced013f21 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/LocatableEventImpl.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.Locatable; +import com.sun.jdi.Location; + +/** + * This class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class LocatableEventImpl extends EventImpl implements Locatable { + /** Location where event occurred. */ + protected LocationImpl fLocation; + + /** + * Creates new LocatableEventImpl, only used by subclasses. + */ + protected LocatableEventImpl(String description, VirtualMachineImpl vmImpl, + RequestID requestID) { + super(description, vmImpl, requestID); + } + + /** + * Reads Thread and Location. + */ + public void readThreadAndLocation(MirrorImpl target, + DataInputStream dataInStream) throws IOException { + fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + fLocation = LocationImpl.read(target, dataInStream); + } + + /** + * @return Returns Location where event occurred. + */ + @Override + public Location location() { + return fLocation; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MethodEntryEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MethodEntryEventImpl.java new file mode 100644 index 0000000000..3901f6157b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MethodEntryEventImpl.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.Method; +import com.sun.jdi.event.MethodEntryEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class MethodEntryEventImpl extends LocatableEventImpl implements + MethodEntryEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_METHOD_ENTRY; + + /** + * Creates new MethodEntryEventImpl. + */ + private MethodEntryEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("MethodEntryEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MethodEntryEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MethodEntryEventImpl event = new MethodEntryEventImpl(vmImpl, requestID); + event.readThreadAndLocation(target, dataInStream); + return event; + } + + /** + * @return Returns the method that was entered. + */ + @Override + public Method method() { + return fLocation.method(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MethodExitEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MethodExitEventImpl.java new file mode 100644 index 0000000000..6aa832a2dd --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MethodExitEventImpl.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ValueImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.Method; +import com.sun.jdi.Value; +import com.sun.jdi.event.MethodExitEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class MethodExitEventImpl extends LocatableEventImpl implements + MethodExitEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_METHOD_EXIT; + + /** return value for the method **/ + private Value fReturnValue = null; + + /** + * Creates new MethodExitEventImpl. + */ + private MethodExitEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("MethodExitEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MethodExitEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MethodExitEventImpl event = new MethodExitEventImpl(vmImpl, requestID); + event.readThreadAndLocation(target, dataInStream); + return event; + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MethodExitEventImpl readWithReturnValue(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MethodExitEventImpl event = new MethodExitEventImpl(vmImpl, requestID); + event.readThreadAndLocation(target, dataInStream); + event.fReturnValue = ValueImpl.readWithTag(target, dataInStream); + return event; + } + + /** + * @return Returns the method that was entered. + */ + @Override + public Method method() { + return fLocation.method(); + } + + /** + * @see com.sun.jdi.event.MethodExitEvent#returnValue() + * @since 3.3 + */ + @Override + public Value returnValue() { + return fReturnValue; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ModificationWatchpointEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ModificationWatchpointEventImpl.java new file mode 100644 index 0000000000..41842791dc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ModificationWatchpointEventImpl.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ValueImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.Value; +import com.sun.jdi.event.ModificationWatchpointEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ModificationWatchpointEventImpl extends WatchpointEventImpl + implements ModificationWatchpointEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_FIELD_MODIFICATION; + + /** Value to be assigned. */ + private ValueImpl fValueToBe; + + /** + * Creates new ModificationWatchpointEventImpl. + */ + private ModificationWatchpointEventImpl(VirtualMachineImpl vmImpl, + RequestID requestID) { + super("ModificationWatchpointEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static WatchpointEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + ModificationWatchpointEventImpl event = new ModificationWatchpointEventImpl( + vmImpl, requestID); + event.readWatchpointEventFields(target, dataInStream); + event.fValueToBe = ValueImpl.readWithTag(target, dataInStream); + return event; + } + + /** + * @return Returns value that will be assigned to the field when the + * instruction completes. + */ + @Override + public Value valueToBe() { + return fValueToBe; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorContendedEnterEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorContendedEnterEventImpl.java new file mode 100644 index 0000000000..02c5b27103 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorContendedEnterEventImpl.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.ObjectReference; +import com.sun.jdi.event.MonitorContendedEnterEvent; + +/** + * This class provides an implementation of MonitorContendedEnterEvent according + * to Sun's 1.6 specs + * + * @since 3.3 + */ +public class MonitorContendedEnterEventImpl extends LocatableEventImpl + implements MonitorContendedEnterEvent { + + /** event kind iod **/ + public static final byte EVENT_KIND = EVENT_MONITOR_CONTENDED_ENTER; + + /** the monitor information **/ + private ObjectReference fMonitor; + + /** Constructor **/ + private MonitorContendedEnterEventImpl(VirtualMachineImpl vmImpl, + RequestID requestID) { + super("MonitorContendedEnter", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MonitorContendedEnterEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MonitorContendedEnterEventImpl event = new MonitorContendedEnterEventImpl( + vmImpl, requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + event.fMonitor = ObjectReferenceImpl.readObjectRefWithTag(target, + dataInStream); + event.fLocation = LocationImpl.read(target, dataInStream); + return event; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.event.MonitorContendedEnterEvent#monitor() + */ + @Override + public ObjectReference monitor() { + return fMonitor; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorContendedEnteredEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorContendedEnteredEventImpl.java new file mode 100644 index 0000000000..ed85b77195 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorContendedEnteredEventImpl.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.ObjectReference; +import com.sun.jdi.event.MonitorContendedEnteredEvent; + +/** + * This class provides an implementation of MonitorContendedEnteredEvent + * according to Sun's 1.6 specs + * + * @since 3.3 + */ +public class MonitorContendedEnteredEventImpl extends LocatableEventImpl + implements MonitorContendedEnteredEvent { + + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_MONITOR_CONTENDED_ENTERED; + + /** the monitor information **/ + private ObjectReference fMonitor; + + /** Constructor **/ + private MonitorContendedEnteredEventImpl(VirtualMachineImpl vmImpl, + RequestID requestID) { + super("MonitorContendedEntered", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MonitorContendedEnteredEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MonitorContendedEnteredEventImpl event = new MonitorContendedEnteredEventImpl( + vmImpl, requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + event.fMonitor = ObjectReferenceImpl.readObjectRefWithTag(target, + dataInStream); + event.fLocation = LocationImpl.read(target, dataInStream); + return event; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.event.MonitorContendedEnteredEvent#monitor() + */ + @Override + public ObjectReference monitor() { + return fMonitor; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorWaitEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorWaitEventImpl.java new file mode 100644 index 0000000000..9d5826cb8e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorWaitEventImpl.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.ValueImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.LongValue; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.event.MonitorWaitEvent; + +public class MonitorWaitEventImpl extends LocatableEventImpl implements + MonitorWaitEvent { + + /** Jdwp event kind id **/ + public static final byte EVENT_KIND = EVENT_MONITOR_WAIT; + + /** howl ong the timeout is **/ + private long fTimeOut; + + /** the monitor reference **/ + private ObjectReference fMonitor; + + /** Constructor **/ + private MonitorWaitEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("MonitorWait", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MonitorWaitEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MonitorWaitEventImpl event = new MonitorWaitEventImpl(vmImpl, requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + event.fMonitor = ObjectReferenceImpl.readObjectRefWithTag(target, + dataInStream); + event.fLocation = LocationImpl.read(target, dataInStream); + event.fTimeOut = ((LongValue) ValueImpl.readWithTag(target, + dataInStream)).value(); + return event; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.event.MonitorWaitedEvent#monitor() + */ + @Override + public ObjectReference monitor() { + return fMonitor; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.event.MonitorWaitEvent#timeout() + */ + @Override + public long timeout() { + return fTimeOut; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorWaitedEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorWaitedEventImpl.java new file mode 100644 index 0000000000..896f2a1870 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/MonitorWaitedEventImpl.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.ValueImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.BooleanValue; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.event.MonitorWaitedEvent; + +/** + * This class provides an implementation of MonitorContendedEnterEvent according + * to Sun's 1.6 specs + * + * @since 3.3 + */ +public class MonitorWaitedEventImpl extends LocatableEventImpl implements + MonitorWaitedEvent { + + /** Jdwp event id **/ + public static final byte EVENT_KIND = EVENT_MONITOR_WAITED; + + /** if the wait timed out or not **/ + private boolean fTimedOut; + + /** the monitor reference **/ + private ObjectReference fMonitor; + + /** Constructor **/ + private MonitorWaitedEventImpl(VirtualMachineImpl vmImpl, + RequestID requestID) { + super("MonitorWaited", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static MonitorWaitedEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + MonitorWaitedEventImpl event = new MonitorWaitedEventImpl(vmImpl, + requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + event.fMonitor = ObjectReferenceImpl.readObjectRefWithTag(target, + dataInStream); + event.fLocation = LocationImpl.read(target, dataInStream); + event.fTimedOut = ((BooleanValue) ValueImpl.readWithTag(target, + dataInStream)).value(); + return event; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.event.MonitorWaitedEvent#monitor() + */ + @Override + public ObjectReference monitor() { + return fMonitor; + } + + /* + * (non-Javadoc) + * + * @see com.sun.jdi.event.MonitorWaitedEvent#timedout() + */ + @Override + public boolean timedout() { + return fTimedOut; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/StepEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/StepEventImpl.java new file mode 100644 index 0000000000..2613869dc6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/StepEventImpl.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.StepEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class StepEventImpl extends LocatableEventImpl implements StepEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_SINGLE_STEP; + + /** + * Creates new StepEventImpl. + */ + private StepEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("StepEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static StepEventImpl read(MirrorImpl target, RequestID requestID, + DataInputStream dataInStream) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + StepEventImpl event = new StepEventImpl(vmImpl, requestID); + event.readThreadAndLocation(target, dataInStream); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ThreadDeathEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ThreadDeathEventImpl.java new file mode 100644 index 0000000000..4e0b60af47 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ThreadDeathEventImpl.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.ThreadDeathEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ThreadDeathEventImpl extends EventImpl implements ThreadDeathEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_THREAD_DEATH; + + /** + * Creates new ThreadDeathEventImpl. + */ + private ThreadDeathEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("ThreadDeathEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static ThreadDeathEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + ThreadDeathEventImpl event = new ThreadDeathEventImpl(vmImpl, requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ThreadStartEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ThreadStartEventImpl.java new file mode 100644 index 0000000000..a922ae96f8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/ThreadStartEventImpl.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.ThreadStartEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ThreadStartEventImpl extends EventImpl implements ThreadStartEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_THREAD_START; + + /** + * Creates new ThreadDeathEventImpl. + */ + private ThreadStartEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("ThreadStartEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static ThreadStartEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) + throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + ThreadStartEventImpl event = new ThreadStartEventImpl(vmImpl, requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMDeathEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMDeathEventImpl.java new file mode 100644 index 0000000000..de139d92d4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMDeathEventImpl.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.VMDeathEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class VMDeathEventImpl extends EventImpl implements VMDeathEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_VM_DEATH; + + /** + * Creates new VMDeathEventImpl. + */ + public VMDeathEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("VMDeathEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * Creates, reads and returns new EventImpl, of which requestID has + * already been read. + * @param target + * @param requestID + * @param dataInStream + * @return + */ + public static VMDeathEventImpl read(MirrorImpl target, RequestID requestID, + DataInputStream dataInStream) { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + VMDeathEventImpl event = new VMDeathEventImpl(vmImpl, requestID); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMDisconnectEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMDisconnectEventImpl.java new file mode 100644 index 0000000000..e76346b14b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMDisconnectEventImpl.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.VMDisconnectEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class VMDisconnectEventImpl extends EventImpl implements + VMDisconnectEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_VM_DISCONNECTED; + + /** + * Creates new VMDisconnectEventImpl. + */ + public VMDisconnectEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("VMDisconnectEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * Creates, reads and returns new EventImpl, of which requestID has + * already been read. + * @param target + * @param requestID + * @param dataInStream + * @return the new event + */ + public static VMDisconnectEventImpl read(MirrorImpl target, + RequestID requestID, DataInputStream dataInStream) { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + VMDisconnectEventImpl event = new VMDisconnectEventImpl(vmImpl, + requestID); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMStartEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMStartEventImpl.java new file mode 100644 index 0000000000..670b0bb0cb --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/VMStartEventImpl.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.event.VMStartEvent; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class VMStartEventImpl extends EventImpl implements VMStartEvent { + /** Jdwp Event Kind. */ + public static final byte EVENT_KIND = EVENT_VM_START; + + /** + * Creates new VMStartEventImpl. + */ + private VMStartEventImpl(VirtualMachineImpl vmImpl, RequestID requestID) { + super("VMStartEvent", vmImpl, requestID); //$NON-NLS-1$ + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public static VMStartEventImpl read(MirrorImpl target, RequestID requestID, + DataInputStream dataInStream) throws IOException { + VirtualMachineImpl vmImpl = target.virtualMachineImpl(); + VMStartEventImpl event = new VMStartEventImpl(vmImpl, requestID); + event.fThreadRef = ThreadReferenceImpl.read(target, dataInStream); + return event; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/WatchpointEventImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/WatchpointEventImpl.java new file mode 100644 index 0000000000..24a6cd0fe6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/event/WatchpointEventImpl.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.event; + +import java.io.DataInputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.FieldImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.request.RequestID; + +import com.sun.jdi.Field; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.Value; +import com.sun.jdi.event.WatchpointEvent; + +/** + * This class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class WatchpointEventImpl extends LocatableEventImpl implements + WatchpointEvent { + /** The field that is about to be accessed/modified. */ + protected FieldImpl fField; + /** The object whose field is about to be accessed/modified. */ + protected ObjectReferenceImpl fObjectReference; + + /** + * Creates new WatchpointEventImpl. + */ + protected WatchpointEventImpl(String description, + VirtualMachineImpl vmImpl, RequestID requestID) { + super(description, vmImpl, requestID); + } + + /** + * @return Creates, reads and returns new EventImpl, of which requestID has + * already been read. + */ + public void readWatchpointEventFields(MirrorImpl target, + DataInputStream dataInStream) throws IOException { + readThreadAndLocation(target, dataInStream); + fField = FieldImpl.readWithReferenceTypeWithTag(target, dataInStream); + fObjectReference = ObjectReferenceImpl.readObjectRefWithTag(target, + dataInStream); + } + + /** + * Returns the field that is about to be accessed/modified. + */ + @Override + public Field field() { + return fField; + } + + /** + * Returns the object whose field is about to be accessed/modified. + */ + @Override + public ObjectReference object() { + return fObjectReference; + } + + /** + * Current value of the field. + */ + @Override + public Value valueCurrent() { + // Note: if field is static, fObjectReference will be null. + if (fObjectReference == null) + return fField.declaringType().getValue(fField); + return fObjectReference.getValue(fField); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JDWPMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JDWPMessages.java new file mode 100644 index 0000000000..67009abc8c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JDWPMessages.java @@ -0,0 +1,30 @@ +/********************************************************************** + * Copyright (c) 2000, 2005 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.osgi.util.NLS; + +public class JDWPMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdi.internal.jdwp.JDWPMessages";//$NON-NLS-1$ + + public static String JdwpString_Second_byte_input_does_not_match_UTF_Specification_1; + public static String JdwpString_Second_or_third_byte_input_does_not_mach_UTF_Specification_2; + public static String JdwpString_Input_does_not_match_UTF_Specification_3; + public static String JdwpString_str_is_null_4; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, JDWPMessages.class); + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JDWPMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JDWPMessages.properties new file mode 100644 index 0000000000..bd45d795fa --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JDWPMessages.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2000, 2005 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +JdwpString_Second_byte_input_does_not_match_UTF_Specification_1=Second byte input does not match UTF Specification +JdwpString_Second_or_third_byte_input_does_not_mach_UTF_Specification_2=Second or third byte input does not mach UTF Specification +JdwpString_Input_does_not_match_UTF_Specification_3=Input does not match UTF Specification +JdwpString_str_is_null_4=Parameter str is null diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpArrayID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpArrayID.java new file mode 100644 index 0000000000..868ba7df6f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpArrayID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpArrayID extends JdwpReferenceTypeID { + /** + * Creates new JdwpID. + */ + public JdwpArrayID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassID.java new file mode 100644 index 0000000000..048defcd02 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpClassID extends JdwpReferenceTypeID { + /** + * Creates new JdwpID. + */ + public JdwpClassID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassLoaderID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassLoaderID.java new file mode 100644 index 0000000000..8ede98e9bf --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassLoaderID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpClassLoaderID extends JdwpObjectID { + /** + * Creates new JdwpID. + */ + public JdwpClassLoaderID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassObjectID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassObjectID.java new file mode 100644 index 0000000000..e30aa35e31 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpClassObjectID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpClassObjectID extends JdwpObjectID { + /** + * Creates new JdwpID. + */ + public JdwpClassObjectID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpCommandPacket.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpCommandPacket.java new file mode 100644 index 0000000000..956d19bfcf --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpCommandPacket.java @@ -0,0 +1,641 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) + * packet declared by the JDWP specification. + * + */ +public class JdwpCommandPacket extends JdwpPacket { + /** Command Sets. */ + public static final int CSET_VIRTUAL_MACHINE = 1; + public static final int CSET_REFERENCE_TYPE = 2; + public static final int CSET_CLASS_TYPE = 3; + public static final int CSET_ARRAY_TYPE = 4; + public static final int CSET_INTERFACE_TYPE = 5; + public static final int CSET_METHOD = 6; + public static final int CSET_FIELD = 8; + public static final int CSET_OBJECT_REFERENCE = 9; + public static final int CSET_STRING_REFERENCE = 10; + public static final int CSET_THREAD_REFERENCE = 11; + public static final int CSET_THREAD_GROUP_REFERENCE = 12; + public static final int CSET_ARRAY_REFERENCE = 13; + public static final int CSET_CLASS_LOADER_REFERENCE = 14; + public static final int CSET_EVENT_REQUEST = 15; + public static final int CSET_STACK_FRAME = 16; + public static final int CSET_CLASS_OBJECT_REFERENCE = 17; + public static final int CSET_EVENT = 64; + public static final int CSET_HOT_CODE_REPLACEMENT = 128; + + /** Commands VirtualMachine. */ + public static final int VM_VERSION = 1 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CLASSES_BY_SIGNATURE = 2 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ALL_CLASSES = 3 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ALL_THREADS = 4 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_TOP_LEVEL_THREAD_GROUPS = 5 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_DISPOSE = 6 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ID_SIZES = 7 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_SUSPEND = 8 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_RESUME = 9 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_EXIT = 10 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CREATE_STRING = 11 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CAPABILITIES = 12 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CLASS_PATHS = 13 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_DISPOSE_OBJECTS = 14 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_HOLD_EVENTS = 15 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_RELEASE_EVENTS = 16 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CAPABILITIES_NEW = 17 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_REDEFINE_CLASSES = 18 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_SET_DEFAULT_STRATUM = 19 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ALL_CLASSES_WITH_GENERIC = 20 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_INSTANCE_COUNTS = 21 + (CSET_VIRTUAL_MACHINE << 8); + + /** Commands ReferenceType. */ + public static final int RT_SIGNATURE = 1 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_CLASS_LOADER = 2 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_MODIFIERS = 3 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_FIELDS = 4 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_METHODS = 5 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_GET_VALUES = 6 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_SOURCE_FILE = 7 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_NESTED_TYPES = 8 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_STATUS = 9 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_INTERFACES = 10 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_CLASS_OBJECT = 11 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_SOURCE_DEBUG_EXTENSION = 12 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_SIGNATURE_WITH_GENERIC = 13 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_FIELDS_WITH_GENERIC = 14 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_METHODS_WITH_GENERIC = 15 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_INSTANCES = 16 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_CLASS_VERSION = 17 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_CONSTANT_POOL = 18 + (CSET_REFERENCE_TYPE << 8); + + /** Commands ClassType. */ + public static final int CT_SUPERCLASS = 1 + (CSET_CLASS_TYPE << 8); + public static final int CT_SET_VALUES = 2 + (CSET_CLASS_TYPE << 8); + public static final int CT_INVOKE_METHOD = 3 + (CSET_CLASS_TYPE << 8); + public static final int CT_NEW_INSTANCE = 4 + (CSET_CLASS_TYPE << 8); + + /** Commands InterfaceType. */ + public static final int IT_INVOKE_METHOD = 1 + (CSET_INTERFACE_TYPE << 8); + + /** Commands ArrayType. */ + public static final int AT_NEW_INSTANCE = 1 + (CSET_ARRAY_TYPE << 8); + + /** Commands Method. */ + public static final int M_LINE_TABLE = 1 + (CSET_METHOD << 8); + public static final int M_VARIABLE_TABLE = 2 + (CSET_METHOD << 8); + public static final int M_BYTECODES = 3 + (CSET_METHOD << 8); + public static final int M_OBSOLETE = 4 + (CSET_METHOD << 8); + public static final int M_VARIABLE_TABLE_WITH_GENERIC = 5 + (CSET_METHOD << 8); + + /** Commands ObjectReference. */ + public static final int OR_REFERENCE_TYPE = 1 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_GET_VALUES = 2 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_SET_VALUES = 3 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_MONITOR_INFO = 5 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_INVOKE_METHOD = 6 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_DISABLE_COLLECTION = 7 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_ENABLE_COLLECTION = 8 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_IS_COLLECTED = 9 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_REFERRING_OBJECTS = 10 + (CSET_OBJECT_REFERENCE << 8); + + /** Commands StringReference. */ + public static final int SR_VALUE = 1 + (CSET_STRING_REFERENCE << 8); + + /** Commands ThreadReference. */ + public static final int TR_NAME = 1 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_SUSPEND = 2 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_RESUME = 3 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_STATUS = 4 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_THREAD_GROUP = 5 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_FRAMES = 6 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_FRAME_COUNT = 7 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_OWNED_MONITORS = 8 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_CURRENT_CONTENDED_MONITOR = 9 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_STOP = 10 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_INTERRUPT = 11 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_SUSPEND_COUNT = 12 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_OWNED_MONITOR_STACK_DEPTH = 13 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_FORCE_EARLY_RETURN = 14 + (CSET_THREAD_REFERENCE << 8); + /** + * IsVirtual is a preview API of the Java platform. Preview features may be removed in a future release, or upgraded to permanent features of the + * Java platform. Since JDWP version 19. + * + * @since 3.20 + */ + public static final int TR_IS_VIRTUAL = 15 + (CSET_THREAD_REFERENCE << 8); + + /** Commands ThreadGroupReference. */ + public static final int TGR_NAME = 1 + (CSET_THREAD_GROUP_REFERENCE << 8); + public static final int TGR_PARENT = 2 + (CSET_THREAD_GROUP_REFERENCE << 8); + public static final int TGR_CHILDREN = 3 + (CSET_THREAD_GROUP_REFERENCE << 8); + + /** Commands ArrayReference. */ + public static final int AR_LENGTH = 1 + (CSET_ARRAY_REFERENCE << 8); + public static final int AR_GET_VALUES = 2 + (CSET_ARRAY_REFERENCE << 8); + public static final int AR_SET_VALUES = 3 + (CSET_ARRAY_REFERENCE << 8); + + /** Commands ClassLoaderReference. */ + public static final int CLR_VISIBLE_CLASSES = 1 + (CSET_CLASS_LOADER_REFERENCE << 8); + + /** Commands EventRequest. */ + public static final int ER_SET = 1 + (CSET_EVENT_REQUEST << 8); + public static final int ER_CLEAR = 2 + (CSET_EVENT_REQUEST << 8); + public static final int ER_CLEAR_ALL_BREAKPOINTS = 3 + (CSET_EVENT_REQUEST << 8); + + /** Commands StackFrame. */ + public static final int SF_GET_VALUES = 1 + (CSET_STACK_FRAME << 8); + public static final int SF_SET_VALUES = 2 + (CSET_STACK_FRAME << 8); + public static final int SF_THIS_OBJECT = 3 + (CSET_STACK_FRAME << 8); + public static final int SF_POP_FRAME = 4 + (CSET_STACK_FRAME << 8); + + /** Commands ClassObjectReference. */ + public static final int COR_REFLECTED_TYPE = 1 + (CSET_CLASS_OBJECT_REFERENCE << 8); + + /** Commands Event. */ + public static final int E_COMPOSITE = 100 + (CSET_EVENT << 8); + + /** Commands Hot Code Replacement (OTI specific). */ + public static final int HCR_CLASSES_HAVE_CHANGED = 1 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_GET_CLASS_VERSION = 2 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_DO_RETURN = 3 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_REENTER_ON_EXIT = 4 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_CAPABILITIES = 5 + (CSET_HOT_CODE_REPLACEMENT << 8); + + /** Mapping of command codes to strings. */ + private static Map fgCommandMap = null; + + /** Next id to be assigned. */ + private static int fgNextId = 1; + /** + * Command, note that this field is 256 * JDWP CommandSet (unsigned) + JDWP + * Command. + */ + private int fCommand; + + /** + * Creates new JdwpCommandPacket. + */ + protected JdwpCommandPacket() { + } + + /** + * Creates new JdwpCommandPacket. + */ + public JdwpCommandPacket(int command) { + setCommand(command); + setId(getNewId()); + } + + /** + * @return Returns unique id for command packet. + */ + public static synchronized int getNewId() { + return fgNextId++; + } + + /** + * @return Returns JDWP command set of packet. + */ + public byte getCommandSet() { + return (byte) (fCommand >>> 8); + } + + /** + * @return Returns 256 * JDWP CommandSet (unsigned) + JDWP Command. + */ + public int getCommand() { + return fCommand; + } + + /** + * Assigns command (256 * JDWP CommandSet (unsigned) + JDWP Command) + */ + public void setCommand(int command) { + fCommand = command; + } + + /** + * Reads header fields that are specific for this type of packet. + */ + @Override + protected int readSpecificHeaderFields(byte[] bytes, int index) { + byte commandSet = bytes[index]; + fCommand = (bytes[index + 1] & 0xff) + (commandSet << 8); + return 2; + } + + /** + * Writes header fields that are specific for this type of packet. + */ + @Override + protected int writeSpecificHeaderFields(byte[] bytes, int index) + throws IOException { + bytes[index] = getCommandSet(); + bytes[index + 1] = (byte) fCommand; + return 2; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgCommandMap != null) { + return; + } + + Field[] fields = JdwpCommandPacket.class.getDeclaredFields(); + + // First get the set names. + Map setNames = new HashMap<>(fields.length); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + // If it is not a set, continue. + if (!name.startsWith("CSET_")) {//$NON-NLS-1$ + continue; + } + int value = field.getInt(null); + setNames.put(Integer.valueOf(value), removePrefix(name)); + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + + // Get the commands. + fgCommandMap = new HashMap<>(); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + + // If it is a set, continue. + if (name.startsWith("CSET_")) { //$NON-NLS-1$ + continue; + } + Integer val = (Integer) field.get(null); + int value = val.intValue(); + int set = value >>> 8; + String setName = setNames.get(Integer.valueOf(set)); + String entryName = setName + " - " + removePrefix(name); //$NON-NLS-1$ + + fgCommandMap.put(val, entryName); + + } catch (IllegalAccessException e) { + // Will not occur for own class. + } + } + } + + /** + * @return Returns a map with string representations of error codes. + */ + public static Map commandMap() { + getConstantMaps(); + return fgCommandMap; + } + + /** + * @return Returns string without XXX_ prefix. + */ + public static String removePrefix(String str) { + int i = str.indexOf('_'); + if (i < 0) { + return str; + } + return str.substring(i + 1); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append('['); + buffer.append(getId()); + buffer.append("] "); //$NON-NLS-1$ + switch (getCommand()) { + + /** Commands VirtualMachine. */ + case VM_VERSION: + buffer.append("VM_VERSION"); //$NON-NLS-1$ + break; + case VM_CLASSES_BY_SIGNATURE: + buffer.append("VM_CLASSES_BY_SIGNATURE"); //$NON-NLS-1$ + break; + case VM_ALL_CLASSES: + buffer.append("VM_ALL_CLASSES"); //$NON-NLS-1$ + break; + case VM_ALL_THREADS: + buffer.append("VM_ALL_THREADS"); //$NON-NLS-1$ + break; + case VM_TOP_LEVEL_THREAD_GROUPS: + buffer.append("VM_TOP_LEVEL_THREAD_GROUPS"); //$NON-NLS-1$ + break; + case VM_DISPOSE: + buffer.append("VM_DISPOSE"); //$NON-NLS-1$ + break; + case VM_ID_SIZES: + buffer.append("VM_ID_SIZES"); //$NON-NLS-1$ + break; + case VM_SUSPEND: + buffer.append("VM_SUSPEND"); //$NON-NLS-1$ + break; + case VM_RESUME: + buffer.append("VM_RESUME"); //$NON-NLS-1$ + break; + case VM_EXIT: + buffer.append("VM_EXIT"); //$NON-NLS-1$ + break; + case VM_CREATE_STRING: + buffer.append("VM_CREATE_STRING"); //$NON-NLS-1$ + break; + case VM_CAPABILITIES: + buffer.append("VM_CAPABILITIES"); //$NON-NLS-1$ + break; + case VM_CLASS_PATHS: + buffer.append("VM_CLASS_PATHS"); //$NON-NLS-1$ + break; + case VM_DISPOSE_OBJECTS: + buffer.append("VM_DISPOSE_OBJECTS"); //$NON-NLS-1$ + break; + case VM_HOLD_EVENTS: + buffer.append("VM_HOLD_EVENTS"); //$NON-NLS-1$ + break; + case VM_RELEASE_EVENTS: + buffer.append("VM_RELEASE_EVENTS"); //$NON-NLS-1$ + break; + case VM_CAPABILITIES_NEW: + buffer.append("VM_CAPABILITIES_NEW"); //$NON-NLS-1$ + break; + case VM_REDEFINE_CLASSES: + buffer.append("VM_REDEFINE_CLASSES"); //$NON-NLS-1$ + break; + case VM_SET_DEFAULT_STRATUM: + buffer.append("VM_SET_DEFAULT_STRATUM"); //$NON-NLS-1$ + break; + case VM_ALL_CLASSES_WITH_GENERIC: + buffer.append("VM_ALL_CLASSES_WITH_GENERIC"); //$NON-NLS-1$ + break; + + /** Commands ReferenceType. */ + case RT_SIGNATURE: + buffer.append("RT_SIGNATURE"); //$NON-NLS-1$ + break; + case RT_CLASS_LOADER: + buffer.append("RT_CLASS_LOADER"); //$NON-NLS-1$ + break; + case RT_MODIFIERS: + buffer.append("RT_MODIFIERS"); //$NON-NLS-1$ + break; + case RT_FIELDS: + buffer.append("RT_FIELDS"); //$NON-NLS-1$ + break; + case RT_METHODS: + buffer.append("RT_METHODS"); //$NON-NLS-1$ + break; + case RT_GET_VALUES: + buffer.append("RT_GET_VALUES"); //$NON-NLS-1$ + break; + case RT_SOURCE_FILE: + buffer.append("RT_SOURCE_FILE"); //$NON-NLS-1$ + break; + case RT_NESTED_TYPES: + buffer.append("RT_NESTED_TYPES"); //$NON-NLS-1$ + break; + case RT_STATUS: + buffer.append("RT_STATUS"); //$NON-NLS-1$ + break; + case RT_INTERFACES: + buffer.append("RT_INTERFACES"); //$NON-NLS-1$ + break; + case RT_CLASS_OBJECT: + buffer.append("RT_CLASS_OBJECT"); //$NON-NLS-1$ + break; + case RT_SOURCE_DEBUG_EXTENSION: + buffer.append("RT_SOURCE_DEBUG_EXTENSION"); //$NON-NLS-1$ + break; + case RT_SIGNATURE_WITH_GENERIC: + buffer.append("RT_SIGNATURE_WITH_GENERIC"); //$NON-NLS-1$ + break; + case RT_FIELDS_WITH_GENERIC: + buffer.append("RT_FIELDS_WITH_GENERIC"); //$NON-NLS-1$ + break; + case RT_METHODS_WITH_GENERIC: + buffer.append("RT_METHODS_WITH_GENERIC"); //$NON-NLS-1$ + break; + + /** Commands ClassType. */ + case CT_SUPERCLASS: + buffer.append("CT_SUPERCLASS"); //$NON-NLS-1$ + break; + case CT_SET_VALUES: + buffer.append("CT_SET_VALUES"); //$NON-NLS-1$ + break; + case CT_INVOKE_METHOD: + buffer.append("CT_INVOKE_METHOD"); //$NON-NLS-1$ + break; + case CT_NEW_INSTANCE: + buffer.append("CT_NEW_INSTANCE"); //$NON-NLS-1$ + break; + + /** Commands ArrayType. */ + case AT_NEW_INSTANCE: + buffer.append("AT_NEW_INSTANCE"); //$NON-NLS-1$ + break; + + /** Commands Method. */ + case M_LINE_TABLE: + buffer.append("M_LINE_TABLE"); //$NON-NLS-1$ + break; + case M_VARIABLE_TABLE: + buffer.append("M_VARIABLE_TABLE"); //$NON-NLS-1$ + break; + case M_BYTECODES: + buffer.append("M_BYTECODES"); //$NON-NLS-1$ + break; + case M_OBSOLETE: + buffer.append("M_OBSOLETE"); //$NON-NLS-1$ + break; + case M_VARIABLE_TABLE_WITH_GENERIC: + buffer.append("M_VARIABLE_TABLE_WITH_GENERIC"); //$NON-NLS-1$ + break; + + /** Commands ObjectReference. */ + case OR_REFERENCE_TYPE: + buffer.append("OR_REFERENCE_TYPE"); //$NON-NLS-1$ + break; + case OR_GET_VALUES: + buffer.append("OR_GET_VALUES"); //$NON-NLS-1$ + break; + case OR_SET_VALUES: + buffer.append("OR_SET_VALUES"); //$NON-NLS-1$ + break; + case OR_MONITOR_INFO: + buffer.append("OR_MONITOR_INFO"); //$NON-NLS-1$ + break; + case OR_INVOKE_METHOD: + buffer.append("OR_INVOKE_METHOD"); //$NON-NLS-1$ + break; + case OR_DISABLE_COLLECTION: + buffer.append("OR_DISABLE_COLLECTION"); //$NON-NLS-1$ + break; + case OR_ENABLE_COLLECTION: + buffer.append("OR_ENABLE_COLLECTION"); //$NON-NLS-1$ + break; + case OR_IS_COLLECTED: + buffer.append("OR_IS_COLLECTED"); //$NON-NLS-1$ + break; + + /** Commands StringReference. */ + case SR_VALUE: + buffer.append("SR_VALUE"); //$NON-NLS-1$ + break; + + /** Commands ThreadReference. */ + case TR_NAME: + buffer.append("TR_NAME"); //$NON-NLS-1$ + break; + case TR_SUSPEND: + buffer.append("TR_SUSPEND"); //$NON-NLS-1$ + break; + case TR_RESUME: + buffer.append("TR_RESUME"); //$NON-NLS-1$ + break; + case TR_STATUS: + buffer.append("TR_STATUS"); //$NON-NLS-1$ + break; + case TR_THREAD_GROUP: + buffer.append("TR_THREAD_GROUP"); //$NON-NLS-1$ + break; + case TR_FRAMES: + buffer.append("TR_FRAMES"); //$NON-NLS-1$ + break; + case TR_FRAME_COUNT: + buffer.append("TR_FRAME_COUNT"); //$NON-NLS-1$ + break; + case TR_OWNED_MONITORS: + buffer.append("TR_OWNED_MONITORS"); //$NON-NLS-1$ + break; + case TR_CURRENT_CONTENDED_MONITOR: + buffer.append("TR_CURRENT_CONTENDED_MONITOR"); //$NON-NLS-1$ + break; + case TR_STOP: + buffer.append("TR_STOP"); //$NON-NLS-1$ + break; + case TR_INTERRUPT: + buffer.append("TR_INTERRUPT"); //$NON-NLS-1$ + break; + case TR_SUSPEND_COUNT: + buffer.append("TR_SUSPEND_COUNT"); //$NON-NLS-1$ + break; + + /** Commands ThreadGroupReference. */ + case TGR_NAME: + buffer.append("TGR_NAME"); //$NON-NLS-1$ + break; + case TGR_PARENT: + buffer.append("TGR_PARENT"); //$NON-NLS-1$ + break; + case TGR_CHILDREN: + buffer.append("TGR_CHILDREN"); //$NON-NLS-1$ + break; + + /** Commands ArrayReference. */ + case AR_LENGTH: + buffer.append("AR_LENGTH"); //$NON-NLS-1$ + break; + case AR_GET_VALUES: + buffer.append("AR_GET_VALUES"); //$NON-NLS-1$ + break; + case AR_SET_VALUES: + buffer.append("AR_SET_VALUES"); //$NON-NLS-1$ + break; + + /** Commands ClassLoaderReference. */ + case CLR_VISIBLE_CLASSES: + buffer.append("CLR_VISIBLE_CLASSES"); //$NON-NLS-1$ + break; + + /** Commands EventRequest. */ + case ER_SET: + buffer.append("ER_SET"); //$NON-NLS-1$ + break; + case ER_CLEAR: + buffer.append("ER_CLEAR"); //$NON-NLS-1$ + break; + case ER_CLEAR_ALL_BREAKPOINTS: + buffer.append("ER_CLEAR_ALL_BREAKPOINTS"); //$NON-NLS-1$ + break; + + /** Commands StackFrame. */ + case SF_GET_VALUES: + buffer.append("SF_GET_VALUES"); //$NON-NLS-1$ + break; + case SF_SET_VALUES: + buffer.append("SF_SET_VALUES"); //$NON-NLS-1$ + break; + case SF_THIS_OBJECT: + buffer.append("SF_THIS_OBJECT"); //$NON-NLS-1$ + break; + case SF_POP_FRAME: + buffer.append("SF_POP_FRAME"); //$NON-NLS-1$ + break; + + /** Commands ClassObjectReference. */ + case COR_REFLECTED_TYPE: + buffer.append("COR_REFLECTED_TYPE"); //$NON-NLS-1$ + break; + + /** Commands Event. */ + case E_COMPOSITE: + buffer.append("E_COMPOSITE"); //$NON-NLS-1$ + break; + + default: + buffer.append("UNKNOWN COMMAND: "); //$NON-NLS-1$ + buffer.append(getCommand()); + break; + } + return buffer.toString(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpFieldID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpFieldID.java new file mode 100644 index 0000000000..c59031bfe9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpFieldID.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpFieldID extends JdwpID { + /** + * Creates new JdwpID. + */ + public JdwpFieldID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } + + /** + * @return Returns VM specific size of ID. + */ + @Override + public int getSize() { + return fVirtualMachine.fieldIDSize(); + } + + /** + * @return Returns true if ID is null. + */ + @Override + public boolean isNull() { + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpFrameID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpFrameID.java new file mode 100644 index 0000000000..f000ac9519 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpFrameID.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpFrameID extends JdwpID { + /** + * Creates new JdwpID. + */ + public JdwpFrameID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } + + /** + * @return Returns VM specific size of ID. + */ + @Override + public int getSize() { + return fVirtualMachine.frameIDSize(); + } + + /** + * @return Returns true if ID is null. + */ + @Override + public boolean isNull() { + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpID.java new file mode 100644 index 0000000000..55f1adc8c2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpID.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * From this class all Java Debug Wire Protocol (JDWP) IDs declared by the JDWP + * specification are derived. + * + */ +public abstract class JdwpID { + /** Tag Constants. */ + public static final byte NULL_TAG = 91; // Used for tagged null values. + public static final byte ARRAY_TAG = 91; // '[' - an array object (objectID + // size). + public static final byte BYTE_TAG = 66; // 'B' - a byte value (1 byte). + public static final byte CHAR_TAG = 67; // 'C' - a character value (2 + // bytes). + public static final byte OBJECT_TAG = 76; // 'L' - an object (objectID + // size). + public static final byte FLOAT_TAG = 70; // 'F' - a float value (4 bytes). + public static final byte DOUBLE_TAG = 68; // 'D' - a double value (8 bytes). + public static final byte INT_TAG = 73; // 'I' - an int value (4 bytes). + public static final byte LONG_TAG = 74; // 'J' - a long value (8 bytes). + public static final byte SHORT_TAG = 83; // 'S' - a short value (2 bytes). + public static final byte VOID_TAG = 86; // 'V' - a void value (no bytes). + public static final byte BOOLEAN_TAG = 90; // 'Z' - a boolean value (1 + // byte). + public static final byte STRING_TAG = 115; // 's' - a String object + // (objectID size). + public static final byte THREAD_TAG = 116; // 't' - a Thread object + // (objectID size). + public static final byte THREAD_GROUP_TAG = 103; // 'g' - a ThreadGroup + // object (objectID + // size). + public static final byte CLASS_LOADER_TAG = 108; // 'l' - a ClassLoader + // object (objectID + // size). + public static final byte CLASS_OBJECT_TAG = 99; // 'c' - a class object + // object (objectID size). + + /** TypeTag Constants. */ + public static final byte TYPE_TAG_CLASS = 1; // ReferenceType is a class. + public static final byte TYPE_TAG_INTERFACE = 2; // ReferenceType is an + // interface. + public static final byte TYPE_TAG_ARRAY = 3; // ReferenceType is an array. + + /** Mapping of command codes to strings. */ + private static HashMap fTagMap = null; + private static HashMap fTypeTagMap = null; + + /** Jdwp representation of null ID. */ + protected static final int VALUE_NULL = 0; + + /** The value of the ID */ + protected long fValue = VALUE_NULL; + /** + * The virtual machine of the mirror object that uses this ID (needed for ID + * sizes. + */ + protected VirtualMachineImpl fVirtualMachine; + + /** + * Creates new JdwpID. + */ + public JdwpID(VirtualMachineImpl vmImpl) { + fVirtualMachine = vmImpl; + } + + /** + * @return Returns true if two IDs refer to the same entity in the target + * VM. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object instanceof JdwpID && fValue == ((JdwpID) object).fValue; + } + + /** + * @return Returns a has code for this object. + * @see java.lang.Object#hashCode + */ + @Override + public int hashCode() { + return (int) fValue; + } + + /** + * @return Returns value of ID. + */ + public final long value() { + return fValue; + } + + /** + * @return Returns string representation. + */ + @Override + public String toString() { + return Long.toString(fValue); + } + + /** + * @return Returns VM specific size of ID. + */ + protected abstract int getSize(); + + /** + * @return Returns true if ID is null. + */ + public abstract boolean isNull(); + + /** + * Reads ID. + */ + public void read(DataInputStream inStream) throws IOException { + fValue = 0; + int size = getSize(); + for (int i = 0; i < size; i++) { + int b = inStream.readUnsignedByte(); // Note that the byte must be + // treated as unsigned. + fValue = fValue << 8 | b; + } + } + + /** + * Writes ID. + */ + public void write(DataOutputStream outStream) throws IOException { + int size = getSize(); + for (int i = size - 1; i >= 0; i--) { + byte b = (byte) (fValue >>> 8 * i); // Note that >>> must be used + // because fValue must be + // treated as unsigned. + outStream.write(b); + } + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fTagMap != null) { + return; + } + + java.lang.reflect.Field[] fields = JdwpID.class.getDeclaredFields(); + fTagMap = new HashMap<>(); + fTypeTagMap = new HashMap<>(); + for (Field field : fields) { + if ((field.getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + Integer intValue = Integer.valueOf(field.getInt(null)); + if (name.startsWith("TYPE_TAG_")) { //$NON-NLS-1$ + name = name.substring(9); + fTypeTagMap.put(intValue, name); + } else if (name.endsWith("_TAG")) { //$NON-NLS-1$ + fTagMap.put(intValue, name); + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + public static Map tagMap() { + getConstantMaps(); + return fTagMap; + } + + /** + * @return Returns a map with string representations of type tags. + */ + public static Map typeTagMap() { + getConstantMaps(); + return fTypeTagMap; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpInterfaceID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpInterfaceID.java new file mode 100644 index 0000000000..64618acf98 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpInterfaceID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpInterfaceID extends JdwpReferenceTypeID { + /** + * Creates new JdwpID. + */ + public JdwpInterfaceID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpMethodID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpMethodID.java new file mode 100644 index 0000000000..cce728dde3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpMethodID.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpMethodID extends JdwpID { + /** + * Creates new JdwpID. + */ + public JdwpMethodID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } + + /** + * @return Returns VM specific size of ID. + */ + @Override + public int getSize() { + return fVirtualMachine.methodIDSize(); + } + + /** + * @return Returns true if ID is null. + */ + @Override + public boolean isNull() { + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpObjectID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpObjectID.java new file mode 100644 index 0000000000..d6fc5527e1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpObjectID.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpObjectID extends JdwpID { + /** + * Creates new JdwpID. + */ + public JdwpObjectID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } + + /** + * @return Returns VM specific size of ID. + */ + @Override + public int getSize() { + return fVirtualMachine.objectIDSize(); + } + + /** + * @return Returns true if ID is null. + */ + @Override + public boolean isNull() { + return fValue == VALUE_NULL; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpPacket.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpPacket.java new file mode 100644 index 0000000000..86f504cfae --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpPacket.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) + * packet declared by the JDWP specification. + * + */ +public abstract class JdwpPacket { + /** General JDWP constants. */ + public static final byte FLAG_REPLY_PACKET = (byte) 0x80; + protected static final int MIN_PACKET_LENGTH = 11; + + /** Map with Strings for flag bits. */ + private static String[] fgFlagStrings = null; + + /** Header fields. */ + protected int fId = 0; + protected byte fFlags = 0; + protected byte[] fDataBuf = null; + + /** + * Set Id. + */ + /* package */void setId(int id) { + fId = id; + } + + /** + * @return Returns Id. + */ + public int getId() { + return fId; + } + + /** + * Set Flags. + */ + /* package */void setFlags(byte flags) { + fFlags = flags; + } + + /** + * @return Returns Flags. + */ + public byte getFlags() { + return fFlags; + } + + /** + * @return Returns total length of packet. + */ + public int getLength() { + return MIN_PACKET_LENGTH + getDataLength(); + } + + /** + * @return Returns length of data in packet. + */ + public int getDataLength() { + return fDataBuf == null ? 0 : fDataBuf.length; + } + + /** + * @return Returns data of packet. + */ + public byte[] data() { + return fDataBuf; + } + + /** + * @return Returns DataInputStream with reply data, or an empty stream if + * there is none. + */ + public DataInputStream dataInStream() { + if (fDataBuf != null) { + return new DataInputStream(new ByteArrayInputStream(fDataBuf)); + } + + return new DataInputStream(new ByteArrayInputStream(new byte[0])); + } + + /** + * Assigns data to packet. + */ + public void setData(byte[] data) { + fDataBuf = data; + } + + /** + * Reads header fields that are specific for a type of packet. + */ + protected abstract int readSpecificHeaderFields(byte[] bytes, int index) + throws IOException; + + /** + * Writes header fields that are specific for a type of packet. + */ + protected abstract int writeSpecificHeaderFields(byte[] bytes, int index) + throws IOException; + + /** + * Constructs a JdwpPacket from a byte[]. + */ + public static JdwpPacket build(byte[] bytes) throws IOException { + // length (int) + int a = (bytes[0] & 0xff) << 24; + int b = (bytes[1] & 0xff) << 16; + int c = (bytes[2] & 0xff) << 8; + int d = (bytes[3] & 0xff) << 0; + int packetLength = a + b + c + d; + + // id (int) + a = (bytes[4] & 0xff) << 24; + b = (bytes[5] & 0xff) << 16; + c = (bytes[6] & 0xff) << 8; + d = (bytes[7] & 0xff) << 0; + int id = a + b + c + d; + + // flags (byte) + byte flags = bytes[8]; + + // Determine type: command or reply. + JdwpPacket packet; + if ((flags & FLAG_REPLY_PACKET) != 0) + packet = new JdwpReplyPacket(); + else + packet = new JdwpCommandPacket(); + + // Assign generic header fields. + packet.setId(id); + packet.setFlags(flags); + + // Read specific header fields and data. + int index = 9; + index += packet.readSpecificHeaderFields(bytes, 9); + if (packetLength - MIN_PACKET_LENGTH > 0) { + packet.fDataBuf = new byte[packetLength - MIN_PACKET_LENGTH]; + System.arraycopy(bytes, index, packet.fDataBuf, 0, + packet.fDataBuf.length); + } + + return packet; + } + + public byte[] getPacketAsBytes() throws IOException { + int len = getLength(); + byte[] bytes = new byte[len]; + + // convert len to bytes + bytes[0] = (byte) (len >>> 24); + bytes[1] = (byte) (len >>> 16); + bytes[2] = (byte) (len >>> 8); + bytes[3] = (byte) (len >>> 0); + + // convert id to bytes + int id = getId(); + bytes[4] = (byte) (id >>> 24); + bytes[5] = (byte) (id >>> 16); + bytes[6] = (byte) (id >>> 8); + bytes[7] = (byte) (id >>> 0); + + // flags + bytes[8] = getFlags(); + + // convert specific header fields + int index = 9; + index += writeSpecificHeaderFields(bytes, index); + + if (index < len && fDataBuf != null) { + // copy data + System.arraycopy(fDataBuf, 0, bytes, index, fDataBuf.length); + } + return bytes; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgFlagStrings != null) { + return; + } + + Field[] fields = JdwpPacket.class.getDeclaredFields(); + fgFlagStrings = new String[8]; + + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + String name = field.getName(); + if (!name.startsWith("FLAG_")) {//$NON-NLS-1$ + continue; + } + + name = name.substring(5); + + try { + byte value = field.getByte(null); + + for (int j = 0; j < fgFlagStrings.length; j++) { + if ((1 << j & value) != 0) { + fgFlagStrings[j] = name; + break; + } + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are bytes. + } + } + } + + /** + * @return Returns a mapping with string representations of flags. + */ + public static String[] getFlagMap() { + getConstantMaps(); + return fgFlagStrings; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpReferenceTypeID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpReferenceTypeID.java new file mode 100644 index 0000000000..96254bb214 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpReferenceTypeID.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpReferenceTypeID extends JdwpID { + /** + * Creates new JdwpID. + */ + public JdwpReferenceTypeID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } + + /** + * @return Returns VM specific size of ID. + */ + @Override + public int getSize() { + return fVirtualMachine.referenceTypeIDSize(); + } + + /** + * @return Returns true if ID is null. + */ + @Override + public boolean isNull() { + return fValue == VALUE_NULL; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpReplyPacket.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpReplyPacket.java new file mode 100644 index 0000000000..8f19f0b97e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpReplyPacket.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) + * packet declared by the JDWP specification. + * + */ +public class JdwpReplyPacket extends JdwpPacket { + /** Error code constants. */ + public static final short NONE = 0; + public static final short INVALID_THREAD = 10; + public static final short INVALID_THREAD_GROUP = 11; + public static final short INVALID_PRIORITY = 12; + public static final short THREAD_NOT_SUSPENDED = 13; + public static final short THREAD_SUSPENDED = 14; + public static final short THREAD_NOT_ALIVE = 15; + public static final short INVALID_OBJECT = 20; + public static final short INVALID_CLASS = 21; + public static final short CLASS_NOT_PREPARED = 22; + public static final short INVALID_METHODID = 23; + public static final short INVALID_LOCATION = 24; + public static final short INVALID_FIELDID = 25; + public static final short INVALID_FRAMEID = 30; + public static final short NO_MORE_FRAMES = 31; + public static final short OPAQUE_FRAME = 32; + public static final short NOT_CURRENT_FRAME = 33; + public static final short TYPE_MISMATCH = 34; + public static final short INVALID_SLOT = 35; + public static final short DUPLICATE = 40; + public static final short NOT_FOUND = 41; + public static final short INVALID_MONITOR = 50; + public static final short NOT_MONITOR_OWNER = 51; + public static final short INTERRUPT = 52; + public static final short INVALID_CLASS_FORMAT = 60; + public static final short CIRCULAR_CLASS_DEFINITION = 61; + public static final short FAILS_VERIFICATION = 62; + public static final short ADD_METHOD_NOT_IMPLEMENTED = 63; + public static final short SCHEMA_CHANGE_NOT_IMPLEMENTED = 64; + public static final short INVALID_TYPESTATE = 65; + public static final short HIERARCHY_CHANGE_NOT_IMPLEMENTED = 66; + public static final short DELETE_METHOD_NOT_IMPLEMENTED = 67; + public static final short UNSUPPORTED_VERSION = 68; + public static final short NAMES_DONT_MATCH = 69; + public static final short CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED = 70; + public static final short METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED = 71; + public static final short NOT_IMPLEMENTED = 99; + public static final short NULL_POINTER = 100; + public static final short ABSENT_INFORMATION = 101; + public static final short INVALID_EVENT_TYPE = 102; + public static final short ILLEGAL_ARGUMENT = 103; + public static final short OUT_OF_MEMORY = 110; + public static final short ACCESS_DENIED = 111; + public static final short VM_DEAD = 112; + public static final short INTERNAL = 113; + public static final short UNATTACHED_THREAD = 115; + public static final short INVALID_TAG = 500; + public static final short ALREADY_INVOKING = 502; + public static final short INVALID_INDEX = 503; + public static final short INVALID_LENGTH = 504; + public static final short INVALID_STRING = 506; + public static final short INVALID_CLASS_LOADER = 507; + public static final short INVALID_ARRAY = 508; + public static final short TRANSPORT_LOAD = 509; + public static final short TRANSPORT_INIT = 510; + public static final short NATIVE_METHOD = 511; + public static final short INVALID_COUNT = 512; + public static final short HCR_OPERATION_REFUSED = 900; // HCR specific. + + /** Mapping of error codes to strings. */ + private static HashMap fErrorMap = null; + + /** JDWP Error code. */ + private short fErrorCode; + + /** + * Creates new JdwpReplyPacket. + */ + public JdwpReplyPacket() { + setFlags(FLAG_REPLY_PACKET); + } + + /** + * @return Returns JDWP Error code. + */ + public short errorCode() { + return fErrorCode; + } + + /** + * Assigns JDWP Error code. + */ + public void setErrorCode(short newValue) { + fErrorCode = newValue; + } + + /** + * Reads header fields that are specific for this type of packet. + */ + @Override + protected int readSpecificHeaderFields(byte[] bytes, int index) + throws IOException { + fErrorCode = (short) (((bytes[index] & 0xFF) << 8) + ((bytes[index + 1] & 0xFF) << 0)); + return 2; + } + + /** + * Writes header fields that are specific for this type of packet. + */ + @Override + protected int writeSpecificHeaderFields(byte[] bytes, int index) + throws IOException { + bytes[index] = (byte) ((fErrorCode >>> 8) & 0xFF); + bytes[index + 1] = (byte) ((fErrorCode >>> 0) & 0xFF); + return 2; + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fErrorMap != null) { + return; + } + + Field[] fields = JdwpReplyPacket.class.getDeclaredFields(); + fErrorMap = new HashMap<>(fields.length); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) + continue; + + try { + Integer intValue = Integer.valueOf(field.getInt(null)); + fErrorMap.put(intValue, field.getName()); + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of error codes. + */ + public static Map errorMap() { + getConstantMaps(); + return fErrorMap; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + buffer.append("["); //$NON-NLS-1$ + buffer.append(getId()); + buffer.append("] "); //$NON-NLS-1$ + buffer.append("(reply)"); //$NON-NLS-1$ + short ec = errorCode(); + if (ec != NONE) { + buffer.append(" ERROR CODE: "); //$NON-NLS-1$ + buffer.append(ec); + } + return buffer.toString(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpString.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpString.java new file mode 100644 index 0000000000..4f6b2fe465 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpString.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UTFDataFormatException; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpString { + /** + * Reads String from Jdwp stream. Read a UTF where length has 4 bytes, and + * not just 2. This code was based on the OTI Retysin source for readUTF. + */ + public static String read(DataInputStream in) throws IOException { + int utfSize = in.readInt(); + byte utfBytes[] = new byte[utfSize]; + in.readFully(utfBytes); + /* Guess at buffer size */ + StringBuilder strBuffer = new StringBuilder(utfSize / 3 * 2); + for (int i = 0; i < utfSize;) { + int a = utfBytes[i] & 0xFF; + if ((a >> 4) < 12) { + strBuffer.append((char) a); + i++; + } else { + int b = utfBytes[i + 1] & 0xFF; + if ((a >> 4) < 14) { + if ((b & 0xBF) == 0) { + throw new UTFDataFormatException( + JDWPMessages.JdwpString_Second_byte_input_does_not_match_UTF_Specification_1); + } + strBuffer.append((char) (((a & 0x1F) << 6) | (b & 0x3F))); + i += 2; + } else { + int c = utfBytes[i + 2] & 0xFF; + if ((a & 0xEF) > 0) { + if (((b & 0xBF) == 0) || ((c & 0xBF) == 0)) { + throw new UTFDataFormatException( + JDWPMessages.JdwpString_Second_or_third_byte_input_does_not_mach_UTF_Specification_2); + } + strBuffer.append((char) (((a & 0x0F) << 12) + | ((b & 0x3F) << 6) | (c & 0x3F))); + i += 3; + } else { + throw new UTFDataFormatException( + JDWPMessages.JdwpString_Input_does_not_match_UTF_Specification_3); + } + } + } + } + return strBuffer.toString(); + } + + /** + * Writes String to Jdwp stream. Write a UTF where length has 4 bytes, and + * not just 2. This code was based on OTI Retsin source for writeUTF. + */ + public static void write(String str, DataOutputStream out) + throws IOException { + if (str == null) + throw new NullPointerException( + JDWPMessages.JdwpString_str_is_null_4); + int utfCount = 0; + for (int i = 0; i < str.length(); i++) { + int charValue = str.charAt(i); + if (charValue > 0 && charValue <= 127) + utfCount += 1; + else if (charValue <= 2047) + utfCount += 2; + else + utfCount += 3; + } + byte utfBytes[] = new byte[utfCount]; + int utfIndex = 0; + for (int i = 0; i < str.length(); i++) { + int charValue = str.charAt(i); + if (charValue > 0 && charValue <= 127) + utfBytes[utfIndex++] = (byte) charValue; + else if (charValue <= 2047) { + utfBytes[utfIndex++] = (byte) (0xc0 | (0x1f & (charValue >> 6))); + utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & charValue)); + } else { + utfBytes[utfIndex++] = (byte) (0xe0 | (0x0f & (charValue >> 12))); + utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & (charValue >> 6))); + utfBytes[utfIndex++] = (byte) (0x80 | (0x3f & charValue)); + } + } + out.writeInt(utfCount); + if (utfCount > 0) + out.write(utfBytes); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpStringID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpStringID.java new file mode 100644 index 0000000000..57d05144a4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpStringID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpStringID extends JdwpObjectID { + /** + * Creates new JdwpID. + */ + public JdwpStringID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpThreadGroupID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpThreadGroupID.java new file mode 100644 index 0000000000..be7235b8ee --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpThreadGroupID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpThreadGroupID extends JdwpObjectID { + /** + * Creates new JdwpID. + */ + public JdwpThreadGroupID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpThreadID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpThreadID.java new file mode 100644 index 0000000000..492fa22db0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/jdwp/JdwpThreadID.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.jdwp; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) ID + * declared by the JDWP specification. + * + */ +public class JdwpThreadID extends JdwpObjectID { + /** + * Creates new JdwpID. + */ + public JdwpThreadID(VirtualMachineImpl vmImpl) { + super(vmImpl); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/AccessWatchpointRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/AccessWatchpointRequestImpl.java new file mode 100644 index 0000000000..5bdbe38eba --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/AccessWatchpointRequestImpl.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.AccessWatchpointEventImpl; + +import com.sun.jdi.request.AccessWatchpointRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class AccessWatchpointRequestImpl extends WatchpointRequestImpl + implements AccessWatchpointRequest { + /** + * Creates new AccessWatchpointRequest. + * @param vmImpl the VM + */ + public AccessWatchpointRequestImpl(VirtualMachineImpl vmImpl) { + super("AccessWatchpointRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return AccessWatchpointEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/BreakpointRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/BreakpointRequestImpl.java new file mode 100644 index 0000000000..77045922ed --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/BreakpointRequestImpl.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.BreakpointEventImpl; + +import com.sun.jdi.Locatable; +import com.sun.jdi.Location; +import com.sun.jdi.request.BreakpointRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class BreakpointRequestImpl extends EventRequestImpl implements + BreakpointRequest, Locatable { + /** + * Creates new BreakpointRequest. + * @param vmImpl the VM + */ + public BreakpointRequestImpl(VirtualMachineImpl vmImpl) { + super("BreakpointRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns location of Breakpoint Request. + */ + @Override + public Location location() { + return fLocationFilters.get(0); + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return BreakpointEventImpl.EVENT_KIND; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ClassPrepareRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ClassPrepareRequestImpl.java new file mode 100644 index 0000000000..3bd4f8f8f2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ClassPrepareRequestImpl.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.ClassPrepareEventImpl; + +import com.sun.jdi.request.ClassPrepareRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassPrepareRequestImpl extends EventRequestImpl implements + ClassPrepareRequest { + /** + * Creates new ClassPrepareRequest. + */ + public ClassPrepareRequestImpl(VirtualMachineImpl vmImpl) { + super("ClassPrepareRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return ClassPrepareEventImpl.EVENT_KIND; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ClassUnloadRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ClassUnloadRequestImpl.java new file mode 100644 index 0000000000..acc1d99a79 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ClassUnloadRequestImpl.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.ClassUnloadEventImpl; + +import com.sun.jdi.request.ClassUnloadRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ClassUnloadRequestImpl extends EventRequestImpl implements + ClassUnloadRequest { + /** + * Creates new ClassUnloadRequest. + */ + public ClassUnloadRequestImpl(VirtualMachineImpl vmImpl) { + super("ClassUnloadRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return ClassUnloadEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/EventRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/EventRequestImpl.java new file mode 100644 index 0000000000..dd11aee489 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/EventRequestImpl.java @@ -0,0 +1,880 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdi.internal.FieldImpl; +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ObjectReferenceImpl; +import org.eclipse.jdi.internal.ReferenceTypeImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.EventImpl; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +import com.sun.jdi.InternalException; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMMismatchException; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.InvalidRequestStateException; +import com.sun.jdi.request.StepRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class EventRequestImpl extends MirrorImpl implements + EventRequest { + /** Jdwp constants for StepRequests. */ + public static final byte STEP_SIZE_MIN_JDWP = 0; + public static final byte STEP_SIZE_LINE_JDWP = 1; + public static final byte STEP_DEPTH_INTO_JDWP = 0; + public static final byte STEP_DEPTH_OVER_JDWP = 1; + public static final byte STEP_DEPTH_OUT_JDWP = 2; + public static final byte STEP_DEPTH_REENTER_JDWP_HCR = 3; // OTI specific + // for Hot Code + // Replacement. + + /** Jdwp constants for SuspendPolicy. */ + public static final byte SUSPENDPOL_NONE_JDWP = 0; + public static final byte SUSPENDPOL_EVENT_THREAD_JDWP = 1; + public static final byte SUSPENDPOL_ALL_JDWP = 2; + + /** Constants for ModifierKind. */ + public static final byte MODIF_KIND_COUNT = 1; + public static final byte MODIF_KIND_CONDITIONAL = 2; + public static final byte MODIF_KIND_THREADONLY = 3; + public static final byte MODIF_KIND_CLASSONLY = 4; + public static final byte MODIF_KIND_CLASSMATCH = 5; + public static final byte MODIF_KIND_CLASSEXCLUDE = 6; + public static final byte MODIF_KIND_LOCATIONONLY = 7; + public static final byte MODIF_KIND_EXCEPTIONONLY = 8; + public static final byte MODIF_KIND_FIELDONLY = 9; + public static final byte MODIF_KIND_STEP = 10; + public static final byte MODIF_KIND_INSTANCE = 11; + public static final byte MODIF_KIND_SOURCE_NAME_FILTER = 12; + /** + * PlatformThreadsOnly is a preview API of the Java platform. Preview features may be removed in a future release, or upgraded to permanent + * features of the Java platform. Since JDWP version 19. For thread start and thread end events, restrict the events so they are only sent for + * platform threads. + * + * @since 3.20 + */ + public static final byte MODIF_KIND_PLATFORMTHREADSONLY = 13; + + /** Mapping of command codes to strings. */ + private static HashMap fStepSizeMap = null; + private static HashMap fStepDepthMap = null; + private static HashMap fSuspendPolicyMap = null; + private static HashMap fModifierKindMap = null; + + /** + * Flag that indicates the request was generated from inside of this JDI + * implementation. + */ + private boolean fGeneratedInside = false; + + /** User property map. */ + private HashMap fPropertyMap; + + /** + * RequestId of EventRequest, assigned by the reply data of the JDWP Event + * Reuqest Set command, null if request had not yet been enabled. + */ + protected RequestID fRequestID = null; + /** + * Determines the threads to suspend when the requested event occurs in the + * target VM. + */ + private byte fSuspendPolicy = SUSPEND_ALL; // Default is as specified by JDI + // spec. + + /** + * Modifiers. + */ + /** Count filters. */ + protected ArrayList fCountFilters; + + /** Thread filters. */ + protected ArrayList fThreadFilters = null; + + /** Class filters. */ + protected ArrayList fClassFilters = null; + + /** Class filters. */ + protected ArrayList fClassFilterRefs = null; + + /** Class Exclusion filters. */ + protected ArrayList fClassExclusionFilters = null; + + /** Location filters. */ + protected ArrayList fLocationFilters = null; + + /** Exception filters. */ + protected ArrayList fExceptionFilters = null; + + /** Field filters. */ + protected ArrayList fFieldFilters = null; + + /** Thread step filters. */ + protected ArrayList fThreadStepFilters = null; + + /** Instance filters. */ + protected ArrayList fInstanceFilters = null; + /** + * source name filters + * + * @since 3.3 + */ + protected ArrayList fSourceNameFilters = null; + + /** + * Platform threads filter + * + * @since 3.20 + */ + protected boolean fPlatformThreadsFilter = false; + + /** + * Creates new EventRequest. + */ + protected EventRequestImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * @return Returns string representation. + */ + @Override + public String toString() { + return super.toString() + + (fRequestID == null ? RequestMessages.EventRequestImpl___not_enabled__1 + : RequestMessages.EventRequestImpl____2 + fRequestID); // + } + + /** + * @return Returns the value of the property with the specified key. + */ + @Override + public Object getProperty(Object key) { + if (fPropertyMap == null) { + return null; + } + + return fPropertyMap.get(key); + } + + /** + * Add an arbitrary key/value "property" to this request. + */ + @Override + public void putProperty(Object key, Object value) { + if (fPropertyMap == null) { + fPropertyMap = new HashMap<>(); + } + + if (value == null) { + fPropertyMap.remove(key); + } else { + fPropertyMap.put(key, value); + } + } + + /** + * Sets the generated inside flag. Used for requests that are not generated + * by JDI requests from outside. + */ + public void setGeneratedInside() { + fGeneratedInside = true; + } + + /** + * @return Returns whether the event request was generated from inside of + * this JDI implementation. + */ + public final boolean isGeneratedInside() { + return fGeneratedInside; + } + + /** + * Disables event request. + */ + @Override + public synchronized void disable() { + if (!isEnabled()) { + return; + } + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeByte(eventKind(), + "event kind", EventImpl.eventKindMap(), outData); //$NON-NLS-1$ + fRequestID.write(this, outData); + + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.ER_CLEAR, + outBytes); + switch (replyPacket.errorCode()) { + case JdwpReplyPacket.NOT_FOUND: + throw new InvalidRequestStateException(); + } + defaultReplyErrorHandler(replyPacket.errorCode()); + + virtualMachineImpl().eventRequestManagerImpl() + .removeRequestIDMapping(this); + fRequestID = null; + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * Enables event request. + */ + @Override + public synchronized void enable() { + if (isEnabled()) { + return; + } + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeByte(eventKind(), + "event kind", EventImpl.eventKindMap(), outData); //$NON-NLS-1$ + writeByte( + suspendPolicyJDWP(), + "suspend policy", EventRequestImpl.suspendPolicyMap(), outData); //$NON-NLS-1$ + writeInt(modifierCount(), "modifiers", outData); //$NON-NLS-1$ + writeModifiers(outData); + + JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.ER_SET, + outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fRequestID = RequestID.read(this, replyData); + virtualMachineImpl().eventRequestManagerImpl().addRequestIDMapping(this); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } + + /** + * Clear all breakpoints (used by EventRequestManager). + */ + public static void clearAllBreakpoints(MirrorImpl mirror) { + mirror.initJdwpRequest(); + try { + JdwpReplyPacket replyPacket = mirror + .requestVM(JdwpCommandPacket.ER_CLEAR_ALL_BREAKPOINTS); + mirror.defaultReplyErrorHandler(replyPacket.errorCode()); + } finally { + mirror.handledJdwpRequest(); + } + } + + /** + * @return Returns whether event request is enabled. + */ + @Override + public synchronized final boolean isEnabled() { + return fRequestID != null; + } + + /** + * Disables or enables event request. + */ + @Override + public void setEnabled(boolean enable) { + if (enable) { + enable(); + } else { + disable(); + } + } + + /** + * @exception InvalidRequestStateException + * is thrown if this request is enabled. + */ + public void checkDisabled() throws InvalidRequestStateException { + if (isEnabled()) { + throw new InvalidRequestStateException(); + } + } + + /** + * Sets suspend policy. + */ + @Override + public void setSuspendPolicy(int suspendPolicy) { + fSuspendPolicy = (byte) suspendPolicy; + if (isEnabled()) { + disable(); + enable(); + } + } + + /** + * @return Returns suspend policy. + */ + @Override + public int suspendPolicy() { + return fSuspendPolicy; + } + + /** + * @return Returns requestID, or null if request ID is not (yet) assigned. + */ + public final RequestID requestID() { + return fRequestID; + } + + /** + * Sets countfilter. + */ + @Override + public void addCountFilter(int count) throws InvalidRequestStateException { + checkDisabled(); + if (fCountFilters == null) { + fCountFilters = new ArrayList<>(); + } + + fCountFilters.add(Integer.valueOf(count)); + } + + /** + * Restricts reported events to those in the given thread. + */ + public void addThreadFilter(ThreadReference threadFilter) + throws ObjectCollectedException, VMMismatchException, + InvalidRequestStateException { + checkVM(threadFilter); + checkDisabled(); + if (threadFilter.isCollected()) { + throw new ObjectCollectedException(); + } + if (fThreadFilters == null) { + fThreadFilters = new ArrayList<>(); + } + + fThreadFilters.add(threadFilter); + } + + /** + * Restricts the events generated by this request to the preparation of + * reference types whose name matches this restricted regular expression. + */ + public void addClassFilter(ReferenceType filter) + throws VMMismatchException, InvalidRequestStateException { + checkVM(filter); + checkDisabled(); + if (fClassFilterRefs == null) { + fClassFilterRefs = new ArrayList<>(); + } + + fClassFilterRefs.add(filter); + } + + /** + * Restricts the events generated by this request to be the preparation of + * the given reference type and any subtypes. + */ + public void addClassFilter(String filter) + throws InvalidRequestStateException { + checkDisabled(); + if (fClassFilters == null) { + fClassFilters = new ArrayList<>(); + } + + fClassFilters.add(filter); + } + + /** + * Restricts the events generated by this request to the preparation of + * reference types whose name does not match this restricted regular + * expression. + */ + public void addClassExclusionFilter(String filter) + throws InvalidRequestStateException { + checkDisabled(); + if (fClassExclusionFilters == null) { + fClassExclusionFilters = new ArrayList<>(); + } + + fClassExclusionFilters.add(filter); + } + + /** + * Restricts the events generated by this request to those that occur at the + * given location. + */ + public void addLocationFilter(LocationImpl location) + throws VMMismatchException { + checkDisabled(); + // Used in createBreakpointRequest. + checkVM(location); + if (fLocationFilters == null) { + fLocationFilters = new ArrayList<>(); + } + + fLocationFilters.add(location); + } + + /** + * Restricts reported exceptions by their class and whether they are caught + * or uncaught. + */ + public void addExceptionFilter(ReferenceTypeImpl refType, + boolean notifyCaught, boolean notifyUncaught) + throws VMMismatchException { + checkDisabled(); + // refType Null means report exceptions of all types. + if (refType != null) { + checkVM(refType); + } + + if (fExceptionFilters == null) { + fExceptionFilters = new ArrayList<>(); + } + + ExceptionFilter filter = new ExceptionFilter(); + filter.fException = refType; + filter.fNotifyCaught = notifyCaught; + filter.fNotifyUncaught = notifyUncaught; + fExceptionFilters.add(filter); + } + + /** + * Restricts reported events to those that occur for a given field. + */ + public void addFieldFilter(FieldImpl field) throws VMMismatchException { + checkDisabled(); + // Used in createXWatchpointRequest methods. + checkVM(field); + if (fFieldFilters == null) { + fFieldFilters = new ArrayList<>(); + } + + fFieldFilters.add(field); + } + + /** + * Restricts reported step events to those which satisfy depth and size + * constraints. + */ + public void addStepFilter(ThreadReferenceImpl thread, int size, int depth) + throws VMMismatchException { + checkDisabled(); + // Used in createStepRequest. + checkVM(thread); + + if (fThreadStepFilters == null) { + fThreadStepFilters = new ArrayList<>(); + } + + ThreadStepFilter filter = new ThreadStepFilter(); + filter.fThread = thread; + filter.fThreadStepSize = size; + filter.fThreadStepDepth = depth; + fThreadStepFilters.add(filter); + } + + /** + * Helper method which allows instance filters to be added + * + * @param instance + * the object ref instance to add to the listing + */ + public void addInstanceFilter(ObjectReference instance) { + checkDisabled(); + checkVM(instance); + if (fInstanceFilters == null) { + fInstanceFilters = new ArrayList<>(); + } + fInstanceFilters.add(instance); + } + + /** + * Adds a source name filter to the request. An exact match or pattern + * beginning OR ending in '*'. + * + * @param pattern + * source name pattern + * @since 3.3 + */ + public void addSourceNameFilter(String pattern) { + checkDisabled(); + if (fSourceNameFilters == null) { + fSourceNameFilters = new ArrayList<>(); + } + fSourceNameFilters.add(pattern); + } + + /** + * From here on JDWP functionality of EventRequest is implemented. + */ + + /** + * @return Returns JDWP constant for suspend policy. + */ + public byte suspendPolicyJDWP() { + switch (fSuspendPolicy) { + case SUSPEND_NONE: + return SUSPENDPOL_NONE_JDWP; + case SUSPEND_EVENT_THREAD: + return SUSPENDPOL_EVENT_THREAD_JDWP; + case SUSPEND_ALL: + return SUSPENDPOL_ALL_JDWP; + default: + throw new InternalException( + RequestMessages.EventRequestImpl_Invalid_suspend_policy_encountered___3 + + fSuspendPolicy); + } + } + + /** + * @return Returns JDWP constant for step size. + */ + public int threadStepSizeJDWP(int threadStepSize) { + switch (threadStepSize) { + case StepRequest.STEP_MIN: + return STEP_SIZE_MIN_JDWP; + case StepRequest.STEP_LINE: + return STEP_SIZE_LINE_JDWP; + default: + throw new InternalException( + RequestMessages.EventRequestImpl_Invalid_step_size_encountered___4 + + threadStepSize); + } + } + + /** + * @return Returns JDWP constant for step depth. + */ + public int threadStepDepthJDWP(int threadStepDepth) { + switch (threadStepDepth) { + case StepRequest.STEP_INTO: + return STEP_DEPTH_INTO_JDWP; + case StepRequest.STEP_OVER: + return STEP_DEPTH_OVER_JDWP; + case StepRequest.STEP_OUT: + return STEP_DEPTH_OUT_JDWP; + default: + throw new InternalException( + RequestMessages.EventRequestImpl_Invalid_step_depth_encountered___5 + + threadStepDepth); + } + } + + /** + * @return Returns JDWP EventKind. + */ + protected abstract byte eventKind(); + + /** + * @return Returns number of modifiers. + */ + protected int modifierCount() { + int count = 0; + + if (fCountFilters != null) { + count += fCountFilters.size(); + } + if (fThreadFilters != null) { + count += fThreadFilters.size(); + } + if (fClassFilterRefs != null) { + count += fClassFilterRefs.size(); + } + if (fClassFilters != null) { + count += fClassFilters.size(); + } + if (fClassExclusionFilters != null) { + count += fClassExclusionFilters.size(); + } + if (fLocationFilters != null) { + count += fLocationFilters.size(); + } + if (fExceptionFilters != null) { + count += fExceptionFilters.size(); + } + if (fFieldFilters != null) { + count += fFieldFilters.size(); + } + if (fThreadStepFilters != null) { + count += fThreadStepFilters.size(); + } + if (fInstanceFilters != null) { + count += fInstanceFilters.size(); + } + if (fSourceNameFilters != null) { + if (supportsSourceNameFilters()) { + count += fSourceNameFilters.size(); + } + } + if (fPlatformThreadsFilter && supportsPlatformThreadsFilter()) { + count++; + } + return count; + } + + /** + * Writes JDWP bytestream representation of modifiers. + */ + protected void writeModifiers(DataOutputStream outData) throws IOException { + // Note: for some reason the order of these modifiers matters when + // communicating with SUN's VM. + // It seems to expect them 'the wrong way around'. + if (fThreadStepFilters != null) { + for (ThreadStepFilter filter : fThreadStepFilters) { + writeByte(MODIF_KIND_STEP, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + filter.fThread.write(this, outData); + writeInt(threadStepSizeJDWP(filter.fThreadStepSize), + "step size", outData); //$NON-NLS-1$ + writeInt(threadStepDepthJDWP(filter.fThreadStepDepth), + "step depth", outData); //$NON-NLS-1$ + } + } + if (fFieldFilters != null) { + for (FieldImpl field : fFieldFilters) { + writeByte(MODIF_KIND_FIELDONLY, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + field.writeWithReferenceType(this, + outData); + } + } + if (fExceptionFilters != null) { + for (ExceptionFilter filter : fExceptionFilters) { + writeByte(MODIF_KIND_EXCEPTIONONLY, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + if (filter.fException != null) { + filter.fException.write(this, outData); + } else { + ReferenceTypeImpl.writeNull(this, outData); + } + + writeBoolean(filter.fNotifyCaught, "notify caught", outData); //$NON-NLS-1$ + writeBoolean(filter.fNotifyUncaught, "notify uncaught", outData); //$NON-NLS-1$ + } + } + if (fLocationFilters != null) { + for (LocationImpl locationFilter : fLocationFilters) { + writeByte(MODIF_KIND_LOCATIONONLY, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + locationFilter.write(this, outData); + } + } + if (fClassExclusionFilters != null) { + for (String classExclusionFilter : fClassExclusionFilters) { + writeByte(MODIF_KIND_CLASSEXCLUDE, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + writeString(classExclusionFilter, + "class excl. filter", outData); //$NON-NLS-1$ + } + } + if (fClassFilters != null) { + for (String classFilter : fClassFilters) { + writeByte(MODIF_KIND_CLASSMATCH, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + writeString(classFilter, + "class filter", outData); //$NON-NLS-1$ + } + } + if (fClassFilterRefs != null) { + for (ReferenceType classFilterRef : fClassFilterRefs) { + writeByte(MODIF_KIND_CLASSONLY, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + ((ReferenceTypeImpl) classFilterRef).write(this, + outData); + } + } + if (fThreadFilters != null) { + for (ThreadReference threadFilter : fThreadFilters) { + writeByte(MODIF_KIND_THREADONLY, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + ((ThreadReferenceImpl) threadFilter).write(this, + outData); + } + } + if (fCountFilters != null) { + for (Integer countFilter : fCountFilters) { + writeByte(MODIF_KIND_COUNT, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + writeInt(countFilter.intValue(), + "count filter", outData); //$NON-NLS-1$ + } + } + if (fInstanceFilters != null) { + for (ObjectReference instanceFilter : fInstanceFilters) { + writeByte(MODIF_KIND_INSTANCE, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + ((ObjectReferenceImpl) instanceFilter).write(this, + outData); + } + } + if (fSourceNameFilters != null) { + if (supportsSourceNameFilters()) { + for (String sourceNameFilter : fSourceNameFilters) { + writeByte(MODIF_KIND_SOURCE_NAME_FILTER, + "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + writeString(sourceNameFilter, + "modifier", outData); //$NON-NLS-1$ + } + } + } + if (fPlatformThreadsFilter && supportsPlatformThreadsFilter()) { + writeByte(MODIF_KIND_PLATFORMTHREADSONLY, "modifier", modifierKindMap(), outData); //$NON-NLS-1$ + } + } + + /** + * Returns whether JDWP supports platform threads filter (a 19 preview feature). + * + * @return whether JDWP supports platform threads filter + */ + private boolean supportsPlatformThreadsFilter() { + return ((VirtualMachineImpl) virtualMachine()).mayCreateVirtualThreads(); + } + + /** + * Returns whether JDWP supports source name filters (a 1.6 feature). + * + * @return whether JDWP supports source name filters + */ + private boolean supportsSourceNameFilters() { + return ((VirtualMachineImpl) virtualMachine()) + .isJdwpVersionGreaterOrEqual(1, 6); + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fStepSizeMap != null) { + return; + } + + fStepSizeMap = new HashMap<>(); + fStepDepthMap = new HashMap<>(); + fSuspendPolicyMap = new HashMap<>(); + fModifierKindMap = new HashMap<>(); + for (Field field : EventRequestImpl.class.getDeclaredFields()) { + if ((field.getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 + || (field.getModifiers() & java.lang.reflect.Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + Integer intValue = Integer.valueOf(field.getInt(null)); + if (name.startsWith("STEP_SIZE_")) { //$NON-NLS-1$ + name = name.substring(10); + fStepSizeMap.put(intValue, name); + } else if (name.startsWith("STEP_DEPTH_")) { //$NON-NLS-1$ + name = name.substring(11); + fStepDepthMap.put(intValue, name); + } else if (name.startsWith("SUSPENDPOL_")) { //$NON-NLS-1$ + name = name.substring(11); + fSuspendPolicyMap.put(intValue, name); + } else if (name.startsWith("MODIF_KIND_")) { //$NON-NLS-1$ + name = name.substring(11); + fModifierKindMap.put(intValue, name); + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of tags. + */ + public static Map stepSizeMap() { + getConstantMaps(); + return fStepSizeMap; + } + + /** + * @return Returns a map with string representations of tags. + */ + public static Map stepDepthMap() { + getConstantMaps(); + return fStepDepthMap; + } + + /** + * @return Returns a map with string representations of type tags. + */ + public static Map suspendPolicyMap() { + getConstantMaps(); + return fSuspendPolicyMap; + } + + /** + * @return Returns a map with string representations of type tags. + */ + public static Map modifierKindMap() { + getConstantMaps(); + return fModifierKindMap; + } + + static class ExceptionFilter { + /** + * If non-null, specifies that exceptions which are instances of + * fExceptionFilterRef will be reported. + */ + ReferenceTypeImpl fException = null; + /** If true, caught exceptions will be reported. */ + boolean fNotifyCaught = false; + /** If true, uncaught exceptions will be reported. */ + boolean fNotifyUncaught = false; + } + + static class ThreadStepFilter { + /** ThreadReference of thread in which to step. */ + protected ThreadReferenceImpl fThread = null; + /** Size of each step. */ + protected int fThreadStepSize; + /** Relative call stack limit. */ + protected int fThreadStepDepth; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/EventRequestManagerImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/EventRequestManagerImpl.java new file mode 100644 index 0000000000..ccc7034f11 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/EventRequestManagerImpl.java @@ -0,0 +1,682 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdi.internal.FieldImpl; +import org.eclipse.jdi.internal.LocationImpl; +import org.eclipse.jdi.internal.MirrorImpl; +import org.eclipse.jdi.internal.ReferenceTypeImpl; +import org.eclipse.jdi.internal.ThreadReferenceImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.AccessWatchpointEventImpl; +import org.eclipse.jdi.internal.event.BreakpointEventImpl; +import org.eclipse.jdi.internal.event.ClassPrepareEventImpl; +import org.eclipse.jdi.internal.event.ClassUnloadEventImpl; +import org.eclipse.jdi.internal.event.EventImpl; +import org.eclipse.jdi.internal.event.ExceptionEventImpl; +import org.eclipse.jdi.internal.event.MethodEntryEventImpl; +import org.eclipse.jdi.internal.event.MethodExitEventImpl; +import org.eclipse.jdi.internal.event.ModificationWatchpointEventImpl; +import org.eclipse.jdi.internal.event.MonitorContendedEnterEventImpl; +import org.eclipse.jdi.internal.event.MonitorContendedEnteredEventImpl; +import org.eclipse.jdi.internal.event.MonitorWaitEventImpl; +import org.eclipse.jdi.internal.event.MonitorWaitedEventImpl; +import org.eclipse.jdi.internal.event.StepEventImpl; +import org.eclipse.jdi.internal.event.ThreadDeathEventImpl; +import org.eclipse.jdi.internal.event.ThreadStartEventImpl; +import org.eclipse.jdi.internal.event.VMDeathEventImpl; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.Field; +import com.sun.jdi.Location; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMMismatchException; +import com.sun.jdi.request.AccessWatchpointRequest; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.ClassUnloadRequest; +import com.sun.jdi.request.DuplicateRequestException; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; +import com.sun.jdi.request.ExceptionRequest; +import com.sun.jdi.request.InvalidRequestStateException; +import com.sun.jdi.request.MethodEntryRequest; +import com.sun.jdi.request.MethodExitRequest; +import com.sun.jdi.request.ModificationWatchpointRequest; +import com.sun.jdi.request.MonitorContendedEnterRequest; +import com.sun.jdi.request.MonitorContendedEnteredRequest; +import com.sun.jdi.request.MonitorWaitRequest; +import com.sun.jdi.request.MonitorWaitedRequest; +import com.sun.jdi.request.StepRequest; +import com.sun.jdi.request.ThreadDeathRequest; +import com.sun.jdi.request.ThreadStartRequest; +import com.sun.jdi.request.VMDeathRequest; + +/** + * this class implements the corresponding interfaces + * declared by the JDI specification. See the com.sun.jdi package + * for more information. + */ +public class EventRequestManagerImpl extends MirrorImpl implements EventRequestManager, org.eclipse.jdi.hcr.EventRequestManager { + + private static class EventRequestType { + + private final ArrayList requests; + private final Hashtable enabledrequests; + + private EventRequestType() { + requests= new ArrayList<>(); + enabledrequests= new Hashtable<>(); + } + + public List getUnmodifiableList() { + return Collections.unmodifiableList(requests); + } + + public void clear() { + requests.clear(); + enabledrequests.clear(); + } + } + + private final EventRequestType ACCESS_WATCHPOINT_TYPE= new EventRequestType<>(); + private final EventRequestType BREAKPOINT_TYPE= new EventRequestType<>(); + private final EventRequestType CLASS_PREPARE_TYPE= new EventRequestType<>(); + private final EventRequestType CLASS_UNLOAD_TYPE= new EventRequestType<>(); + private final EventRequestType METHOD_ENTRY_TYPE= new EventRequestType<>(); + private final EventRequestType METHOD_EXIT_TYPE= new EventRequestType<>(); + private final EventRequestType EXCEPTION_TYPE= new EventRequestType<>(); + private final EventRequestType MODIFICATION_WATCHPOINT_TYPE= new EventRequestType<>(); + private final EventRequestType STEP_TYPE= new EventRequestType<>(); + private final EventRequestType THREAD_DEATH_TYPE= new EventRequestType<>(); + private final EventRequestType THREAD_START_TYPE= new EventRequestType<>(); + private final EventRequestType VM_DEATH_TYPE= new EventRequestType<>(); + private final EventRequestType MONITOR_CONTENDED_ENTERED_TYPE= new EventRequestType<>(); + private final EventRequestType MONITOR_CONTENDED_ENTER_TYPE= new EventRequestType<>(); + private final EventRequestType MONITOR_WAITED_TYPE= new EventRequestType<>(); + private final EventRequestType MONITOR_WAIT_TYPE= new EventRequestType<>(); + + /** + * Creates new EventRequestManager. + */ + public EventRequestManagerImpl(VirtualMachineImpl vmImpl) { + super("EventRequestManager", vmImpl); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createAccessWatchpointRequest(com.sun.jdi.Field) + */ + @Override + public AccessWatchpointRequest createAccessWatchpointRequest(Field field) { + FieldImpl fieldImpl = (FieldImpl)field; + AccessWatchpointRequestImpl req = new AccessWatchpointRequestImpl(virtualMachineImpl()); + req.addFieldFilter(fieldImpl); + ACCESS_WATCHPOINT_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createBreakpointRequest(com.sun.jdi.Location) + */ + @Override + public BreakpointRequest createBreakpointRequest(Location location) throws VMMismatchException { + LocationImpl locImpl = (LocationImpl)location; + BreakpointRequestImpl req = new BreakpointRequestImpl(virtualMachineImpl()); + req.addLocationFilter(locImpl); + BREAKPOINT_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createClassPrepareRequest() + */ + @Override + public ClassPrepareRequest createClassPrepareRequest() { + ClassPrepareRequestImpl req = new ClassPrepareRequestImpl(virtualMachineImpl()); + CLASS_PREPARE_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createClassUnloadRequest() + */ + @Override + public ClassUnloadRequest createClassUnloadRequest() { + ClassUnloadRequestImpl req = new ClassUnloadRequestImpl(virtualMachineImpl()); + CLASS_UNLOAD_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createExceptionRequest(com.sun.jdi.ReferenceType, boolean, boolean) + */ + @Override + public ExceptionRequest createExceptionRequest(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught) { + ReferenceTypeImpl refTypeImpl = (ReferenceTypeImpl)refType; + ExceptionRequestImpl req = new ExceptionRequestImpl(virtualMachineImpl()); + req.addExceptionFilter(refTypeImpl, notifyCaught, notifyUncaught); + EXCEPTION_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createMethodEntryRequest() + */ + @Override + public MethodEntryRequest createMethodEntryRequest() { + MethodEntryRequestImpl req = new MethodEntryRequestImpl(virtualMachineImpl()); + METHOD_ENTRY_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createMethodExitRequest() + */ + @Override + public MethodExitRequest createMethodExitRequest() { + MethodExitRequestImpl req = new MethodExitRequestImpl(virtualMachineImpl()); + METHOD_EXIT_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createMonitorContendedEnteredRequest() + */ + @Override + public MonitorContendedEnteredRequest createMonitorContendedEnteredRequest() { + MonitorContendedEnteredRequestImpl req = new MonitorContendedEnteredRequestImpl(virtualMachineImpl()); + MONITOR_CONTENDED_ENTERED_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createMonitorContendedEnterRequest() + */ + @Override + public MonitorContendedEnterRequest createMonitorContendedEnterRequest() { + MonitorContendedEnterRequestImpl req = new MonitorContendedEnterRequestImpl(virtualMachineImpl()); + MONITOR_CONTENDED_ENTER_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createMonitorWaitedRequest() + */ + @Override + public MonitorWaitedRequest createMonitorWaitedRequest() { + MonitorWaitedRequestImpl req = new MonitorWaitedRequestImpl(virtualMachineImpl()); + MONITOR_WAITED_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createMonitorWaitRequest() + */ + @Override + public MonitorWaitRequest createMonitorWaitRequest() { + MonitorWaitRequestImpl req = new MonitorWaitRequestImpl(virtualMachineImpl()); + MONITOR_WAIT_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createModificationWatchpointRequest(com.sun.jdi.Field) + */ + @Override + public ModificationWatchpointRequest createModificationWatchpointRequest(Field field) { + FieldImpl fieldImpl = (FieldImpl)field; + ModificationWatchpointRequestImpl req = new ModificationWatchpointRequestImpl(virtualMachineImpl()); + req.addFieldFilter(fieldImpl); + MODIFICATION_WATCHPOINT_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createStepRequest(com.sun.jdi.ThreadReference, int, int) + */ + @Override + public StepRequest createStepRequest(ThreadReference thread, int size, int depth) throws DuplicateRequestException, ObjectCollectedException { + ThreadReferenceImpl threadImpl = (ThreadReferenceImpl)thread; + StepRequestImpl req = new StepRequestImpl(virtualMachineImpl()); + req.addStepFilter(threadImpl, size, depth); + STEP_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createThreadDeathRequest() + */ + @Override + public ThreadDeathRequest createThreadDeathRequest() { + ThreadDeathRequestImpl req = new ThreadDeathRequestImpl(virtualMachineImpl()); + THREAD_DEATH_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#createThreadStartRequest() + */ + @Override + public ThreadStartRequest createThreadStartRequest() { + ThreadStartRequestImpl req = new ThreadStartRequestImpl(virtualMachineImpl()); + THREAD_START_TYPE.requests.add(req); + return req; + } + + /* + * @see EventRequestManager#createVMDeathRequest() + */ + @Override + public VMDeathRequest createVMDeathRequest() { + VMDeathRequestImpl req = new VMDeathRequestImpl(virtualMachineImpl()); + VM_DEATH_TYPE.requests.add(req); + return req; + } + + /* (non-Javadoc) + * @see org.eclipse.jdi.hcr.EventRequestManager#createReenterStepRequest(com.sun.jdi.ThreadReference) + */ + @Override + public org.eclipse.jdi.hcr.ReenterStepRequest createReenterStepRequest(ThreadReference thread) { + virtualMachineImpl().checkHCRSupported(); + ThreadReferenceImpl threadImpl = (ThreadReferenceImpl)thread; + ReenterStepRequestImpl req = new ReenterStepRequestImpl(virtualMachineImpl()); + // Note that the StepFilter is only used to specify the thread. + // The size is ignored and the depth will always be written as HCR_STEP_DEPTH_REENTER_JDWP. + req.addStepFilter(threadImpl, StepRequest.STEP_MIN, 0); + // Since this is a special case of a step request, we use the same request list. + STEP_TYPE.requests.add(req); + return req; + } + + /** + * Enables class prepare requests for all loaded classes. This is + * necessary for current versions of the KVM to function correctly. + * This method is only called when the remote VM is determined to be + * the KVM. + */ + public void enableInternalClassPrepareEvent() { + // Note that these requests are not stored in the set of outstanding requests because + // they must be invisible from outside. + ClassPrepareRequestImpl requestPrepare = + new ClassPrepareRequestImpl(virtualMachineImpl()); + requestPrepare.setGeneratedInside(); + requestPrepare.setSuspendPolicy(EventRequest.SUSPEND_NONE); + + requestPrepare.enable(); + } + + /** + * Creates ClassUnloadRequest for maintaining class information for within JDI. + * Needed to known when to flush the cache. + */ + public void enableInternalClasUnloadEvent(/* TBD: ReferenceTypeImpl refType*/) { + // Note that these requests are not stored in the set of outstanding requests because + // they must be invisible from outside. + ClassUnloadRequestImpl reqUnload = new ClassUnloadRequestImpl(virtualMachineImpl()); + reqUnload.setGeneratedInside(); + // TBD: It is now yet possible to only ask for unload events for + // classes that we know of due to a limitation in the J9 VM. + // reqUnload.addClassFilter(refType); + reqUnload.setSuspendPolicy(EventRequest.SUSPEND_NONE); + reqUnload.enable(); + } + + /** + * Checks if a steprequest is for the given thread is already enabled. + */ + boolean existsEnabledStepRequest(ThreadReferenceImpl threadImpl) { + Enumeration enumeration = STEP_TYPE.enabledrequests.elements(); + StepRequestImpl step; + while (enumeration.hasMoreElements()) { + step = (StepRequestImpl)enumeration.nextElement(); + if (step.thread() == threadImpl) + return true; + } + return false; + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#deleteAllBreakpoints() + */ + @Override + public void deleteAllBreakpoints() { + EventRequestImpl.clearAllBreakpoints(this); + BREAKPOINT_TYPE.clear(); + } + + /** + * Deletes an EventRequest. + */ + private void deleteEventRequest(EventRequestType type, EventRequestImpl req) throws VMMismatchException { + // Remove request from list of requests and from the mapping of requestIDs to requests. + checkVM(req); + type.requests.remove(req); + RequestID id = req.requestID(); + if(id != null) { + type.enabledrequests.remove(id); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#deleteEventRequest(com.sun.jdi.request.EventRequest) + */ + @Override + public void deleteEventRequest(EventRequest req) { + // Disable request, note that this also causes the event request to be removed from fEnabledRequests. + try { + req.disable(); + } catch (InvalidRequestStateException exception) { + // The event has already been removed from the VM. + } + if (req instanceof AccessWatchpointRequestImpl) { + deleteEventRequest(ACCESS_WATCHPOINT_TYPE, (AccessWatchpointRequestImpl) req); + } else if (req instanceof BreakpointRequestImpl) { + deleteEventRequest(BREAKPOINT_TYPE, (BreakpointRequestImpl)req); + } else if (req instanceof ClassPrepareRequestImpl) { + deleteEventRequest(CLASS_PREPARE_TYPE, (ClassPrepareRequestImpl)req); + } else if (req instanceof ClassUnloadRequestImpl) { + deleteEventRequest(CLASS_UNLOAD_TYPE, (ClassUnloadRequestImpl)req); + } else if (req instanceof ExceptionRequestImpl) { + deleteEventRequest(EXCEPTION_TYPE, (ExceptionRequestImpl)req); + } else if (req instanceof MethodEntryRequestImpl) { + deleteEventRequest(METHOD_ENTRY_TYPE, (MethodEntryRequestImpl)req); + } else if (req instanceof MethodExitRequestImpl) { + deleteEventRequest(METHOD_EXIT_TYPE, (MethodExitRequestImpl)req); + } else if (req instanceof ModificationWatchpointRequestImpl) { + deleteEventRequest(MODIFICATION_WATCHPOINT_TYPE, (ModificationWatchpointRequestImpl)req); + } else if (req instanceof StepRequestImpl) { + deleteEventRequest(STEP_TYPE, (StepRequestImpl)req); + } else if (req instanceof ThreadDeathRequestImpl) { + deleteEventRequest(THREAD_DEATH_TYPE, (ThreadDeathRequestImpl)req); + } else if (req instanceof ThreadStartRequestImpl) { + deleteEventRequest(THREAD_START_TYPE, (ThreadStartRequestImpl)req); + } else if(req instanceof MonitorContendedEnterRequestImpl) { + deleteEventRequest(MONITOR_CONTENDED_ENTER_TYPE, (MonitorContendedEnterRequestImpl)req); + } else if(req instanceof MonitorContendedEnteredRequestImpl) { + deleteEventRequest(MONITOR_CONTENDED_ENTERED_TYPE, (MonitorContendedEnteredRequestImpl)req); + } else if(req instanceof MonitorWaitRequestImpl) { + deleteEventRequest(MONITOR_WAIT_TYPE, (MonitorWaitRequestImpl)req); + } else if(req instanceof MonitorWaitedRequestImpl) { + deleteEventRequest(MONITOR_WAITED_TYPE, (MonitorWaitedRequestImpl)req); + } else { + throw new InternalError(NLS.bind(RequestMessages.EventRequestManagerImpl_EventRequest_type_of__0__is_unknown_1, new String[]{req.toString()})); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#deleteEventRequests(java.util.List) + */ + @Override + public void deleteEventRequests(List requests) throws VMMismatchException { + Iterator iter = requests.iterator(); + while(iter.hasNext()) { + Object obj = iter.next(); + deleteEventRequest((EventRequest)obj); + } + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#accessWatchpointRequests() + */ + @Override + public List accessWatchpointRequests() { + return ACCESS_WATCHPOINT_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#breakpointRequests() + */ + @Override + public List breakpointRequests() { + return BREAKPOINT_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#classPrepareRequests() + */ + @Override + public List classPrepareRequests() { + return CLASS_PREPARE_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#classUnloadRequests() + */ + @Override + public List classUnloadRequests() { + return CLASS_UNLOAD_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#exceptionRequests() + */ + @Override + public List exceptionRequests() { + return EXCEPTION_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#methodEntryRequests() + */ + @Override + public List methodEntryRequests() { + return METHOD_ENTRY_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#methodExitRequests() + */ + @Override + public List methodExitRequests() { + return METHOD_EXIT_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#modificationWatchpointRequests() + */ + @Override + public List modificationWatchpointRequests() { + return MODIFICATION_WATCHPOINT_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#stepRequests() + */ + @Override + public List stepRequests() { + return STEP_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#threadDeathRequests() + */ + @Override + public List threadDeathRequests() { + return THREAD_DEATH_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#threadStartRequests() + */ + @Override + public List threadStartRequests() { + return THREAD_START_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#vmDeathRequests() + */ + @Override + public List vmDeathRequests() { + return VM_DEATH_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#monitorContendedEnterRequests() + */ + @Override + public List monitorContendedEnterRequests() { + return MONITOR_CONTENDED_ENTER_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#monitorContendedEnteredRequests() + */ + @Override + public List monitorContendedEnteredRequests() { + return MONITOR_CONTENDED_ENTERED_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#monitorWaitRequests() + */ + @Override + public List monitorWaitRequests() { + return MONITOR_WAIT_TYPE.getUnmodifiableList(); + } + + /* (non-Javadoc) + * @see com.sun.jdi.request.EventRequestManager#monitorWaitedRequests() + */ + @Override + public List monitorWaitedRequests() { + return MONITOR_WAITED_TYPE.getUnmodifiableList(); + } + + public void removeRequestIDMapping(EventRequestImpl req) { + if (req instanceof AccessWatchpointRequestImpl) { + ACCESS_WATCHPOINT_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof BreakpointRequestImpl) { + BREAKPOINT_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof ClassPrepareRequestImpl) { + CLASS_PREPARE_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof ClassUnloadRequestImpl) { + CLASS_UNLOAD_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof ExceptionRequestImpl) { + EXCEPTION_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof MethodEntryRequestImpl) { + METHOD_ENTRY_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof MethodExitRequestImpl) { + METHOD_EXIT_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof ModificationWatchpointRequestImpl) { + MODIFICATION_WATCHPOINT_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof StepRequestImpl) { + STEP_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof ThreadDeathRequestImpl) { + THREAD_DEATH_TYPE.enabledrequests.remove(req.requestID()); + } else if (req instanceof ThreadStartRequestImpl) { + THREAD_START_TYPE.enabledrequests.remove(req.requestID()); + } else if(req instanceof MonitorContendedEnterRequestImpl) { + MONITOR_CONTENDED_ENTER_TYPE.enabledrequests.remove(req.requestID()); + } else if(req instanceof MonitorContendedEnteredRequestImpl) { + MONITOR_CONTENDED_ENTERED_TYPE.enabledrequests.remove(req.requestID()); + } else if(req instanceof MonitorWaitRequestImpl) { + MONITOR_WAIT_TYPE.enabledrequests.remove(req.requestID()); + } else if(req instanceof MonitorWaitedRequestImpl) { + MONITOR_WAITED_TYPE.enabledrequests.remove(req.requestID()); + } else if(req instanceof VMDeathRequestImpl) { + VM_DEATH_TYPE.enabledrequests.remove(req.requestID()); + } + } + + /** + * Maps a request ID to requests. + */ + public void addRequestIDMapping(EventRequestImpl req) { + if (req instanceof AccessWatchpointRequestImpl) { + ACCESS_WATCHPOINT_TYPE.enabledrequests.put(req.requestID(), (AccessWatchpointRequestImpl) req); + } else if (req instanceof BreakpointRequestImpl) { + BREAKPOINT_TYPE.enabledrequests.put(req.requestID(), (BreakpointRequestImpl)req); + } else if (req instanceof ClassPrepareRequestImpl) { + CLASS_PREPARE_TYPE.enabledrequests.put(req.requestID(), (ClassPrepareRequestImpl)req); + } else if (req instanceof ClassUnloadRequestImpl) { + CLASS_UNLOAD_TYPE.enabledrequests.put(req.requestID(), (ClassUnloadRequestImpl)req); + } else if (req instanceof ExceptionRequestImpl) { + EXCEPTION_TYPE.enabledrequests.put(req.requestID(), (ExceptionRequestImpl)req); + } else if (req instanceof MethodEntryRequestImpl) { + METHOD_ENTRY_TYPE.enabledrequests.put(req.requestID(), (MethodEntryRequestImpl)req); + } else if (req instanceof MethodExitRequestImpl) { + METHOD_EXIT_TYPE.enabledrequests.put(req.requestID(), (MethodExitRequestImpl)req); + } else if (req instanceof ModificationWatchpointRequestImpl) { + MODIFICATION_WATCHPOINT_TYPE.enabledrequests.put(req.requestID(), (ModificationWatchpointRequestImpl)req); + } else if (req instanceof StepRequestImpl) { + STEP_TYPE.enabledrequests.put(req.requestID(), (StepRequestImpl)req); + } else if (req instanceof ThreadDeathRequestImpl) { + THREAD_DEATH_TYPE.enabledrequests.put(req.requestID(), (ThreadDeathRequestImpl)req); + } else if (req instanceof ThreadStartRequestImpl) { + THREAD_START_TYPE.enabledrequests.put(req.requestID(), (ThreadStartRequestImpl)req); + } else if(req instanceof MonitorWaitRequestImpl) { + MONITOR_WAIT_TYPE.enabledrequests.put(req.requestID(), (MonitorWaitRequestImpl)req); + } else if(req instanceof MonitorWaitedRequestImpl) { + MONITOR_WAITED_TYPE.enabledrequests.put(req.requestID(), (MonitorWaitedRequestImpl)req); + } else if(req instanceof MonitorContendedEnterRequestImpl) { + MONITOR_CONTENDED_ENTER_TYPE.enabledrequests.put(req.requestID(), (MonitorContendedEnterRequestImpl)req); + } else if(req instanceof MonitorContendedEnteredRequestImpl) { + MONITOR_CONTENDED_ENTERED_TYPE.enabledrequests.put(req.requestID(), (MonitorContendedEnteredRequestImpl)req); + } else if(req instanceof VMDeathRequestImpl) { + VM_DEATH_TYPE.enabledrequests.put(req.requestID(), (VMDeathRequest) req); + } + } + + /** + * Find Request that matches event. + */ + public EventRequest findRequest(EventImpl event) { + if (event instanceof AccessWatchpointEventImpl) { + return ACCESS_WATCHPOINT_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof BreakpointEventImpl) { + return BREAKPOINT_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof ClassPrepareEventImpl) { + return CLASS_PREPARE_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof ClassUnloadEventImpl) { + return CLASS_UNLOAD_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof ExceptionEventImpl) { + return EXCEPTION_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof MethodEntryEventImpl) { + return METHOD_ENTRY_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof MethodExitEventImpl) { + return METHOD_EXIT_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof ModificationWatchpointEventImpl) { + return MODIFICATION_WATCHPOINT_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof StepEventImpl) { + return STEP_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof ThreadDeathEventImpl) { + return THREAD_DEATH_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof ThreadStartEventImpl) { + return THREAD_START_TYPE.enabledrequests.get(event.requestID()); + } else if (event instanceof VMDeathEventImpl) { + return VM_DEATH_TYPE.enabledrequests.get(event.requestID()); + } else if(event instanceof MonitorWaitEventImpl) { + return MONITOR_WAIT_TYPE.enabledrequests.get(event.requestID()); + } else if(event instanceof MonitorWaitedEventImpl) { + return MONITOR_WAITED_TYPE.enabledrequests.get(event.requestID()); + } else if(event instanceof MonitorContendedEnterEventImpl) { + return MONITOR_CONTENDED_ENTER_TYPE.enabledrequests.get(event.requestID()); + } else if(event instanceof MonitorContendedEnteredEventImpl) { + return MONITOR_CONTENDED_ENTERED_TYPE.enabledrequests.get(event.requestID()); + } + throw new InternalError(RequestMessages.EventRequestManagerImpl_Got_event_of_unknown_type_2); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ExceptionRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ExceptionRequestImpl.java new file mode 100644 index 0000000000..2d416706e3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ExceptionRequestImpl.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.ExceptionEventImpl; + +import com.sun.jdi.ReferenceType; +import com.sun.jdi.request.ExceptionRequest; + +/** + * This class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ExceptionRequestImpl extends EventRequestImpl implements + ExceptionRequest { + /** + * Creates new EventRequestManager. + */ + public ExceptionRequestImpl(VirtualMachineImpl vmImpl) { + super("ExceptionRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * Returns exception type for which exception events are requested. + */ + @Override + public ReferenceType exception() { + return fExceptionFilters.get(0).fException; + } + + /** + * @return Returns true if caught exceptions will be reported. + */ + @Override + public boolean notifyCaught() { + return fExceptionFilters.get(0).fNotifyCaught; + } + + /** + * @return Returns true if uncaught exceptions will be reported. + */ + @Override + public boolean notifyUncaught() { + return fExceptionFilters.get(0).fNotifyUncaught; + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return ExceptionEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MethodEntryRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MethodEntryRequestImpl.java new file mode 100644 index 0000000000..7cea9dfdf6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MethodEntryRequestImpl.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.MethodEntryEventImpl; + +import com.sun.jdi.request.MethodEntryRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class MethodEntryRequestImpl extends EventRequestImpl implements + MethodEntryRequest { + /** + * Creates new MethodEntryRequest. + */ + public MethodEntryRequestImpl(VirtualMachineImpl vmImpl) { + super("MethodEntryRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return MethodEntryEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MethodExitRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MethodExitRequestImpl.java new file mode 100644 index 0000000000..83bc86b657 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MethodExitRequestImpl.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.EventImpl; +import org.eclipse.jdi.internal.event.MethodExitEventImpl; + +import com.sun.jdi.request.MethodExitRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class MethodExitRequestImpl extends EventRequestImpl implements + MethodExitRequest { + /** + * Creates new MethodExitRequest. + */ + public MethodExitRequestImpl(VirtualMachineImpl vmImpl) { + super("MethodExitRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + if (virtualMachine().canGetMethodReturnValues()) { + return EventImpl.EVENT_METHOD_EXIT_WITH_RETURN_VALUE; + } + return MethodExitEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ModificationWatchpointRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ModificationWatchpointRequestImpl.java new file mode 100644 index 0000000000..b81f9ad012 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ModificationWatchpointRequestImpl.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.ModificationWatchpointEventImpl; + +import com.sun.jdi.request.ModificationWatchpointRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ModificationWatchpointRequestImpl extends WatchpointRequestImpl + implements ModificationWatchpointRequest { + /** + * Creates new ModificationWatchpointRequest. + */ + public ModificationWatchpointRequestImpl(VirtualMachineImpl vmImpl) { + super("ModificationWatchpointRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return ModificationWatchpointEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorContendedEnterRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorContendedEnterRequestImpl.java new file mode 100644 index 0000000000..95d938d4be --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorContendedEnterRequestImpl.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.MonitorContendedEnterEventImpl; + +import com.sun.jdi.request.MonitorContendedEnterRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + * @since 3.3 + */ +public class MonitorContendedEnterRequestImpl extends EventRequestImpl + implements MonitorContendedEnterRequest { + + /** + * Creates new MethodExitRequest. + */ + public MonitorContendedEnterRequestImpl(VirtualMachineImpl vmImpl) { + super("MonitorContendedEnterRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected byte eventKind() { + return MonitorContendedEnterEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorContendedEnteredRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorContendedEnteredRequestImpl.java new file mode 100644 index 0000000000..47a3a05bb8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorContendedEnteredRequestImpl.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.MonitorContendedEnteredEventImpl; + +import com.sun.jdi.request.MonitorContendedEnteredRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + * @since 3.3 + */ +public class MonitorContendedEnteredRequestImpl extends EventRequestImpl + implements MonitorContendedEnteredRequest { + + /** + * Creates new MethodExitRequest. + */ + public MonitorContendedEnteredRequestImpl(VirtualMachineImpl vmImpl) { + super("MonitorContendedEnteredRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return MonitorContendedEnteredEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorWaitRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorWaitRequestImpl.java new file mode 100644 index 0000000000..04ab520e40 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorWaitRequestImpl.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.MonitorWaitEventImpl; + +import com.sun.jdi.request.MonitorWaitRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + * @since 3.3 + */ +public class MonitorWaitRequestImpl extends EventRequestImpl implements + MonitorWaitRequest { + + public MonitorWaitRequestImpl(VirtualMachineImpl vmImpl) { + super("MonitorWaitRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected byte eventKind() { + return MonitorWaitEventImpl.EVENT_KIND; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorWaitedRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorWaitedRequestImpl.java new file mode 100644 index 0000000000..1a56db1da2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/MonitorWaitedRequestImpl.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.MonitorWaitedEventImpl; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + * @since 3.3 + */ +public class MonitorWaitedRequestImpl extends EventRequestImpl implements + com.sun.jdi.request.MonitorWaitedRequest { + + /** constructor **/ + public MonitorWaitedRequestImpl(VirtualMachineImpl vmImpl) { + super("MonitorWaitedRequestImpl", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected byte eventKind() { + return MonitorWaitedEventImpl.EVENT_KIND; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ReenterStepRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ReenterStepRequestImpl.java new file mode 100644 index 0000000000..f55275a5fa --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ReenterStepRequestImpl.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.EventImpl; +import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; + +/** + * this class implements the corresponding interfaces declared by the OTI Hot + * Code Replacement extentions of the JDI specification. + */ + +public class ReenterStepRequestImpl extends StepRequestImpl implements + org.eclipse.jdi.hcr.ReenterStepRequest { + /** + * Creates new ReenterStepRequestImpl. + */ + public ReenterStepRequestImpl(VirtualMachineImpl vmImpl) { + super("ReenterStepRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP constant for step depth. + */ + @Override + public int threadStepDepthJDWP(int threadStepDepth) { + return STEP_DEPTH_REENTER_JDWP_HCR; + } + + /** + * Enables event request. + */ + @Override + public void enable() { + if (isEnabled()) + return; + + initJdwpRequest(); + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + DataOutputStream outData = new DataOutputStream(outBytes); + writeByte(eventKind(), + "event kind", EventImpl.eventKindMap(), outData); // Always 01 for Step event. //$NON-NLS-1$ + writeByte(suspendPolicyJDWP(), "suspend policy", outData); //$NON-NLS-1$ + writeInt(modifierCount(), "modifiers", outData); //$NON-NLS-1$ + writeModifiers(outData); + + JdwpReplyPacket replyPacket = requestVM( + JdwpCommandPacket.HCR_REENTER_ON_EXIT, outBytes); + defaultReplyErrorHandler(replyPacket.errorCode()); + DataInputStream replyData = replyPacket.dataInStream(); + fRequestID = RequestID.read(this, replyData); + virtualMachineImpl().eventRequestManagerImpl().addRequestIDMapping( + this); + } catch (IOException e) { + defaultIOExceptionHandler(e); + } finally { + handledJdwpRequest(); + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestID.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestID.java new file mode 100644 index 0000000000..038c36588b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestID.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.jdi.internal.MirrorImpl; + +public class RequestID { + /** + * Null request ID, returned by Virtual Machine in events that were not + * requested. + */ + private static final int NULL_REQUEST_ID = 0; + public static final RequestID nullID = new RequestID(NULL_REQUEST_ID); + + /** Integer representation of request ID. */ + private final int fRequestID; + + /** + * Creates new request ID. + */ + private RequestID(int ID) { + fRequestID = ID; + } + + /** + * @return Returns whether the request ID is a NULL ID, which means that + * there is no corresponding request. + */ + public boolean isNull() { + return fRequestID == NULL_REQUEST_ID; + } + + /** + * @return Returns true if two RequestIDs are the same. + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object != null && object.getClass().equals(this.getClass()) + && fRequestID == ((RequestID) object).fRequestID; + } + + /** + * @return Returns a has code for this object. + * @see java.lang.Object#hashCode + */ + @Override + public int hashCode() { + return fRequestID; + } + + /** + * @return Returns string representation. + */ + @Override + public String toString() { + return Long.toString(fRequestID); + } + + /** + * Writes IDto stream. + */ + public void write(MirrorImpl target, DataOutputStream out) + throws IOException { + target.writeInt(fRequestID, "request ID", out); //$NON-NLS-1$ + } + + /** + * @return Returns a new request ID read from stream. + */ + public static RequestID read(MirrorImpl target, DataInputStream in) + throws IOException { + int result = target.readInt("request ID", in); //$NON-NLS-1$ + return new RequestID(result); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestMessages.java new file mode 100644 index 0000000000..c608c01a4c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestMessages.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.osgi.util.NLS; + +public class RequestMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdi.internal.request.RequestMessages";//$NON-NLS-1$ + + public static String EventRequestImpl___not_enabled__1; + public static String EventRequestImpl____2; + public static String EventRequestImpl_Invalid_suspend_policy_encountered___3; + public static String EventRequestImpl_Invalid_step_size_encountered___4; + public static String EventRequestImpl_Invalid_step_depth_encountered___5; + public static String EventRequestManagerImpl_EventRequest_type_of__0__is_unknown_1; + public static String EventRequestManagerImpl_Got_event_of_unknown_type_2; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, RequestMessages.class); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestMessages.properties new file mode 100644 index 0000000000..679c6c372d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/RequestMessages.properties @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2000, 2007 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +EventRequestImpl___not_enabled__1=\ (not enabled) +EventRequestImpl____2=: +EventRequestImpl_Invalid_suspend_policy_encountered___3=Invalid suspend policy encountered: +EventRequestImpl_Invalid_step_size_encountered___4=Invalid step size encountered: +EventRequestImpl_Invalid_step_depth_encountered___5=Invalid step depth encountered: +EventRequestManagerImpl_EventRequest_type_of__0__is_unknown_1=EventRequest type of {0} is unknown +EventRequestManagerImpl_Got_event_of_unknown_type_2=Got event of unknown type diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/StepRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/StepRequestImpl.java new file mode 100644 index 0000000000..0937d6ea3d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/StepRequestImpl.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.StepEventImpl; + +import com.sun.jdi.ThreadReference; +import com.sun.jdi.request.StepRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class StepRequestImpl extends EventRequestImpl implements StepRequest { + /** + * Creates new StepRequest. + */ + public StepRequestImpl(VirtualMachineImpl vmImpl) { + super("StepRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * Creates new StepRequest, used by subclasses. + */ + protected StepRequestImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * @return Returns the relative call stack limit. + */ + @Override + public int depth() { + return fThreadStepFilters.get(0).fThreadStepDepth; + } + + /** + * @return Returns the size of each step. + */ + @Override + public int size() { + return fThreadStepFilters.get(0).fThreadStepSize; + } + + /** + * @return Returns ThreadReference of thread in which to step. + */ + @Override + public ThreadReference thread() { + return fThreadStepFilters.get(0).fThread; + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return StepEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadDeathRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadDeathRequestImpl.java new file mode 100644 index 0000000000..8922e5e631 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadDeathRequestImpl.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.ThreadDeathEventImpl; + +import com.sun.jdi.request.ThreadDeathRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ThreadDeathRequestImpl extends ThreadLifecycleRequestImpl implements + ThreadDeathRequest { + /** + * Creates new ThreadDeathRequest. + */ + public ThreadDeathRequestImpl(VirtualMachineImpl vmImpl) { + super("ThreadDeathRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return ThreadDeathEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadLifecycleRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadLifecycleRequestImpl.java new file mode 100644 index 0000000000..8fa5290c97 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadLifecycleRequestImpl.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2022 Microsoft Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +public abstract class ThreadLifecycleRequestImpl extends EventRequestImpl { + + protected ThreadLifecycleRequestImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * For thread start and thread end events, restrict the events so they are only sent for platform threads. + * + * @since 3.20 + */ + public void addPlatformThreadsOnlyFilter() { + checkDisabled(); + fPlatformThreadsFilter = true; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadStartRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadStartRequestImpl.java new file mode 100644 index 0000000000..6ddb217abb --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/ThreadStartRequestImpl.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Microsoft Corporation - supports virtual threads + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.ThreadStartEventImpl; + +import com.sun.jdi.request.ThreadStartRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public class ThreadStartRequestImpl extends ThreadLifecycleRequestImpl implements + ThreadStartRequest { + /** + * Creates new ThreadStartRequest. + */ + public ThreadStartRequestImpl(VirtualMachineImpl vmImpl) { + super("ThreadStartRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return Returns JDWP EventKind. + */ + @Override + protected final byte eventKind() { + return ThreadStartEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/VMDeathRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/VMDeathRequestImpl.java new file mode 100644 index 0000000000..3d33faca60 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/VMDeathRequestImpl.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.event.VMDeathEventImpl; + +import com.sun.jdi.request.VMDeathRequest; + +public class VMDeathRequestImpl extends EventRequestImpl implements + VMDeathRequest { + + public VMDeathRequestImpl(VirtualMachineImpl vmImpl) { + super("VMDeathRequest", vmImpl); //$NON-NLS-1$ + } + + /** + * @return JDWP event kind + */ + @Override + protected byte eventKind() { + return VMDeathEventImpl.EVENT_KIND; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/WatchpointRequestImpl.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/WatchpointRequestImpl.java new file mode 100644 index 0000000000..80eb255b3f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/request/WatchpointRequestImpl.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.request; + +import org.eclipse.jdi.internal.VirtualMachineImpl; + +import com.sun.jdi.Field; +import com.sun.jdi.request.WatchpointRequest; + +/** + * this class implements the corresponding interfaces declared by the JDI + * specification. See the com.sun.jdi package for more information. + * + */ +public abstract class WatchpointRequestImpl extends EventRequestImpl implements + WatchpointRequest { + /** + * Creates new WatchpointRequest, only used by subclasses. + */ + public WatchpointRequestImpl(String description, VirtualMachineImpl vmImpl) { + super(description, vmImpl); + } + + /** + * @return Returns field for which Watchpoint requests is issued. + */ + @Override + public Field field() { + return fFieldFilters.get(0); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpCommandPacket.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpCommandPacket.java new file mode 100644 index 0000000000..79539ba46b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpCommandPacket.java @@ -0,0 +1,327 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) + * packet declared by the JDWP specification. + * + */ +public class JdwpCommandPacket extends JdwpPacket { + /** Command Sets. */ + public static final int CSET_VIRTUAL_MACHINE = 1; + public static final int CSET_REFERENCE_TYPE = 2; + public static final int CSET_CLASS_TYPE = 3; + public static final int CSET_ARRAY_TYPE = 4; + public static final int CSET_INTERFACE_TYPE = 5; + public static final int CSET_METHOD = 6; + public static final int CSET_FIELD = 8; + public static final int CSET_OBJECT_REFERENCE = 9; + public static final int CSET_STRING_REFERENCE = 10; + public static final int CSET_THREAD_REFERENCE = 11; + public static final int CSET_THREAD_GROUP_REFERENCE = 12; + public static final int CSET_ARRAY_REFERENCE = 13; + public static final int CSET_CLASS_LOADER_REFERENCE = 14; + public static final int CSET_EVENT_REQUEST = 15; + public static final int CSET_STACK_FRAME = 16; + public static final int CSET_CLASS_OBJECT_REFERENCE = 17; + public static final int CSET_EVENT = 64; + public static final int CSET_HOT_CODE_REPLACEMENT = 128; + + /** Commands VirtualMachine. */ + public static final int VM_VERSION = 1 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CLASSES_BY_SIGNATURE = 2 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ALL_CLASSES = 3 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ALL_THREADS = 4 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_TOP_LEVEL_THREAD_GROUPS = 5 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_DISPOSE = 6 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ID_SIZES = 7 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_SUSPEND = 8 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_RESUME = 9 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_EXIT = 10 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CREATE_STRING = 11 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CAPABILITIES = 12 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CLASS_PATHS = 13 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_DISPOSE_OBJECTS = 14 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_HOLD_EVENTS = 15 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_RELEASE_EVENTS = 16 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_CAPABILITIES_NEW = 17 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_REDEFINE_CLASSES = 18 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_SET_DEFAULT_STRATUM = 19 + (CSET_VIRTUAL_MACHINE << 8); + public static final int VM_ALL_CLASSES_WITH_GENERIC = 20 + (CSET_VIRTUAL_MACHINE << 8); + + /** Commands ReferenceType. */ + public static final int RT_SIGNATURE = 1 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_CLASS_LOADER = 2 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_MODIFIERS = 3 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_FIELDS = 4 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_METHODS = 5 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_GET_VALUES = 6 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_SOURCE_FILE = 7 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_NESTED_TYPES = 8 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_STATUS = 9 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_INTERFACES = 10 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_CLASS_OBJECT = 11 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_SOURCE_DEBUG_EXTENSION = 12 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_SIGNATURE_WITH_GENERIC = 13 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_FIELDS_WITH_GENERIC = 14 + (CSET_REFERENCE_TYPE << 8); + public static final int RT_METHODS_WITH_GENERIC = 15 + (CSET_REFERENCE_TYPE << 8); + + /** Commands ClassType. */ + public static final int CT_SUPERCLASS = 1 + (CSET_CLASS_TYPE << 8); + public static final int CT_SET_VALUES = 2 + (CSET_CLASS_TYPE << 8); + public static final int CT_INVOKE_METHOD = 3 + (CSET_CLASS_TYPE << 8); + public static final int CT_NEW_INSTANCE = 4 + (CSET_CLASS_TYPE << 8); + + /** Commands ArrayType. */ + public static final int AT_NEW_INSTANCE = 1 + (CSET_ARRAY_TYPE << 8); + + /** Commands Method. */ + public static final int M_LINE_TABLE = 1 + (CSET_METHOD << 8); + public static final int M_VARIABLE_TABLE = 2 + (CSET_METHOD << 8); + public static final int M_BYTECODES = 3 + (CSET_METHOD << 8); + public static final int M_IS_OBSOLETE = 4 + (CSET_METHOD << 8); + public static final int M_VARIABLE_TABLE_WITH_GENERIC = 5 + (CSET_METHOD << 8); + + /** Commands ObjectReference. */ + public static final int OR_REFERENCE_TYPE = 1 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_GET_VALUES = 2 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_SET_VALUES = 3 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_MONITOR_INFO = 5 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_INVOKE_METHOD = 6 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_DISABLE_COLLECTION = 7 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_ENABLE_COLLECTION = 8 + (CSET_OBJECT_REFERENCE << 8); + public static final int OR_IS_COLLECTED = 9 + (CSET_OBJECT_REFERENCE << 8); + + /** Commands StringReference. */ + public static final int SR_VALUE = 1 + (CSET_STRING_REFERENCE << 8); + + /** Commands ThreadReference. */ + public static final int TR_NAME = 1 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_SUSPEND = 2 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_RESUME = 3 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_STATUS = 4 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_THREAD_GROUP = 5 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_FRAMES = 6 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_FRAME_COUNT = 7 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_OWNED_MONITORS = 8 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_CURRENT_CONTENDED_MONITOR = 9 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_STOP = 10 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_INTERRUPT = 11 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_SUSPEND_COUNT = 12 + (CSET_THREAD_REFERENCE << 8); + public static final int TR_POP_TOP_FRAME = 13 + (CSET_THREAD_REFERENCE << 8); + + /** Commands ThreadGroupReference. */ + public static final int TGR_NAME = 1 + (CSET_THREAD_GROUP_REFERENCE << 8); + public static final int TGR_PARENT = 2 + (CSET_THREAD_GROUP_REFERENCE << 8); + public static final int TGR_CHILDREN = 3 + (CSET_THREAD_GROUP_REFERENCE << 8); + + /** Commands ArrayReference. */ + public static final int AR_LENGTH = 1 + (CSET_ARRAY_REFERENCE << 8); + public static final int AR_GET_VALUES = 2 + (CSET_ARRAY_REFERENCE << 8); + public static final int AR_SET_VALUES = 3 + (CSET_ARRAY_REFERENCE << 8); + + /** Commands ClassLoaderReference. */ + public static final int CLR_VISIBLE_CLASSES = 1 + (CSET_CLASS_LOADER_REFERENCE << 8); + + /** Commands EventRequest. */ + public static final int ER_SET = 1 + (CSET_EVENT_REQUEST << 8); + public static final int ER_CLEAR = 2 + (CSET_EVENT_REQUEST << 8); + public static final int ER_CLEAR_ALL_BREAKPOINTS = 3 + (CSET_EVENT_REQUEST << 8); + + /** Commands StackFrame. */ + public static final int SF_GET_VALUES = 1 + (CSET_STACK_FRAME << 8); + public static final int SF_SET_VALUES = 2 + (CSET_STACK_FRAME << 8); + public static final int SF_THIS_OBJECT = 3 + (CSET_STACK_FRAME << 8); + public static final int SF_POP_FRAME = 4 + (CSET_STACK_FRAME << 8); + + /** Commands ClassObjectReference. */ + public static final int COR_REFLECTED_TYPE = 1 + (CSET_CLASS_OBJECT_REFERENCE << 8); + + /** Commands Event. */ + public static final int E_COMPOSITE = 100 + (CSET_EVENT << 8); + + /** Commands Hot Code Replacement (OTI specific). */ + public static final int HCR_CLASSES_HAVE_CHANGED = 1 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_GET_CLASS_VERSION = 2 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_DO_RETURN = 3 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_REENTER_ON_EXIT = 4 + (CSET_HOT_CODE_REPLACEMENT << 8); + public static final int HCR_CAPABILITIES = 5 + (CSET_HOT_CODE_REPLACEMENT << 8); + + /** Mapping of command codes to strings. */ + private static Map fgCommandMap = null; + + /** Next id to be assigned. */ + private static int fgNextId = 1; + /** + * Command, note that this field is 256 * JDWP CommandSet (unsigned) + JDWP + * Command. + */ + private int fCommand; + + /** + * Creates new JdwpCommandPacket. + */ + protected JdwpCommandPacket() { + } + + /** + * Creates new JdwpCommandPacket. + */ + public JdwpCommandPacket(int command) { + setCommand(command); + setId(getNewId()); + } + + /** + * @return Returns unique id for command packet. + */ + public static synchronized int getNewId() { + return fgNextId++; + } + + /** + * @return Returns JDWP command set of packet. + */ + public byte getCommandSet() { + return (byte) (fCommand >>> 8); + } + + /** + * @return Returns 256 * JDWP CommandSet (unsigned) + JDWP Command. + */ + public int getCommand() { + return fCommand; + } + + /** + * Assigns command (256 * JDWP CommandSet (unsigned) + JDWP Command) + */ + public void setCommand(int command) { + fCommand = command; + } + + /** + * Reads header fields that are specific for this type of packet. + */ + @Override + protected void readSpecificHeaderFields(DataInputStream dataInStream) + throws IOException { + byte commandSet = dataInStream.readByte(); + fCommand = (dataInStream.readByte() & 0xff) + (commandSet << 8); + } + + /** + * Writes header fields that are specific for this type of packet. + */ + @Override + protected void writeSpecificHeaderFields(DataOutputStream dataOutStream) + throws IOException { + dataOutStream.writeByte(getCommandSet()); + dataOutStream.writeByte((byte) fCommand); + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgCommandMap != null) { + return; + } + + Field[] fields = JdwpCommandPacket.class.getDeclaredFields(); + + // First get the set names. + Map setNames = new HashMap<>(fields.length); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + // If it is not a set, continue. + if (!name.startsWith("CSET_")) {//$NON-NLS-1$ + continue; + } + int value = field.getInt(null); + setNames.put(Integer.valueOf(value), removePrefix(name)); + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + + // Get the commands. + fgCommandMap = new HashMap<>(); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + try { + String name = field.getName(); + + // If it is a set, continue. + if (name.startsWith("CSET_")) { //$NON-NLS-1$ + continue; + } + Integer val = (Integer) field.get(null); + int value = val.intValue(); + int set = value >>> 8; + String setName = setNames.get(Integer.valueOf(set)); + String entryName = setName + " - " + removePrefix(name); //$NON-NLS-1$ + + fgCommandMap.put(val, entryName); + + } catch (IllegalAccessException e) { + // Will not occur for own class. + } + } + } + + /** + * @return Returns a map with string representations of error codes. + */ + public static Map commandMap() { + getConstantMaps(); + return fgCommandMap; + } + + /** + * @return Returns string without XXX_ prefix. + */ + public static String removePrefix(String str) { + int i = str.indexOf('_'); + if (i < 0) { + return str; + } + return str.substring(i + 1); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpConversation.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpConversation.java new file mode 100644 index 0000000000..c556992be1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpConversation.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +import java.text.MessageFormat; + +public class JdwpConversation { + private final int fId; + private JdwpCommandPacket fCommand; + private JdwpReplyPacket fReply; + + JdwpConversation(int id) { + fId = id; + } + + void setCommand(JdwpCommandPacket command) { + if (fCommand != null) { + throw new IllegalArgumentException( + MessageFormat + .format("Attempt to overwrite command with {0}", new Object[] { command.toString() })); //$NON-NLS-1$ + } + fCommand = command; + } + + void setReply(JdwpReplyPacket reply) { + if (fReply != null) { + throw new IllegalArgumentException( + MessageFormat + .format("Attempt to overwrite reply with {0}", new Object[] { reply.toString() })); //$NON-NLS-1$ + } + fReply = reply; + } + + public JdwpCommandPacket getCommand() { + return fCommand; + } + + public JdwpReplyPacket getReply() { + return fReply; + } + + public int getId() { + return fId; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpPacket.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpPacket.java new file mode 100644 index 0000000000..bbdc16aa31 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpPacket.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) + * packet declared by the JDWP specification. + * + */ +public abstract class JdwpPacket { + /** General JDWP constants. */ + public static final byte FLAG_REPLY_PACKET = (byte) 0x80; + protected static final int MIN_PACKET_LENGTH = 11; + + /** Map with Strings for flag bits. */ + private static String[] fgFlagStrings = null; + + /** Header fields. */ + protected int fId = 0; + protected byte fFlags = 0; + protected byte[] fDataBuf = null; + + /** + * Set Id. + */ + /* package */void setId(int id) { + fId = id; + } + + /** + * @return Returns Id. + */ + public int getId() { + return fId; + } + + /** + * Set Flags. + */ + /* package */void setFlags(byte flags) { + fFlags = flags; + } + + /** + * @return Returns Flags. + */ + public byte getFlags() { + return fFlags; + } + + /** + * @return Returns total length of packet. + */ + public int getLength() { + return MIN_PACKET_LENGTH + getDataLength(); + } + + /** + * @return Returns length of data in packet. + */ + public int getDataLength() { + return fDataBuf == null ? 0 : fDataBuf.length; + } + + /** + * @return Returns data of packet. + */ + public byte[] data() { + return fDataBuf; + } + + /** + * @return Returns DataInputStream with reply data, or an empty stream if + * there is none. + */ + public DataInputStream dataInStream() { + if (fDataBuf != null) { + return new DataInputStream(new ByteArrayInputStream(fDataBuf)); + } + + return new DataInputStream(new ByteArrayInputStream(new byte[0])); + } + + /** + * Assigns data to packet. + */ + public void setData(byte[] data) { + fDataBuf = data; + } + + /** + * Reads header fields that are specific for a type of packet. + */ + protected abstract void readSpecificHeaderFields( + DataInputStream dataInStream) throws IOException; + + /** + * Writes header fields that are specific for a type of packet. + */ + protected abstract void writeSpecificHeaderFields( + DataOutputStream dataOutStream) throws IOException; + + /** + * Reads complete packet. + */ + public static JdwpPacket read(InputStream inStream) throws IOException { + DataInputStream dataInStream = new DataInputStream(inStream); + + // Read header. + int packetLength = dataInStream.readInt(); + int id = dataInStream.readInt(); + byte flags = dataInStream.readByte(); + + // Determine type: command or reply. + JdwpPacket packet; + if ((flags & FLAG_REPLY_PACKET) != 0) + packet = new JdwpReplyPacket(); + else + packet = new JdwpCommandPacket(); + + // Assign generic header fields. + packet.setId(id); + packet.setFlags(flags); + + // Read specific header fields and data. + packet.readSpecificHeaderFields(dataInStream); + if (packetLength - MIN_PACKET_LENGTH > 0) { + packet.fDataBuf = new byte[packetLength - MIN_PACKET_LENGTH]; + dataInStream.readFully(packet.fDataBuf); + } + + return packet; + } + + /** + * Writes complete packet. + */ + public void write(OutputStream outStream) throws IOException { + DataOutputStream dataOutStream = new DataOutputStream(outStream); + + writeHeader(dataOutStream); + writeData(dataOutStream); + } + + /** + * Writes header of packet. + */ + protected void writeHeader(DataOutputStream dataOutStream) + throws IOException { + dataOutStream.writeInt(getLength()); + dataOutStream.writeInt(getId()); + dataOutStream.writeByte(getFlags()); + writeSpecificHeaderFields(dataOutStream); + } + + /** + * Writes data of packet. + */ + protected void writeData(DataOutputStream dataOutStream) throws IOException { + if (fDataBuf != null) { + dataOutStream.write(fDataBuf); + } + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fgFlagStrings != null) { + return; + } + + Field[] fields = JdwpPacket.class.getDeclaredFields(); + fgFlagStrings = new String[8]; + + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) { + continue; + } + + String name = field.getName(); + if (!name.startsWith("FLAG_")) {//$NON-NLS-1$ + continue; + } + + name = name.substring(5); + + try { + byte value = field.getByte(null); + + for (int j = 0; j < fgFlagStrings.length; j++) { + if ((1 << j & value) != 0) { + fgFlagStrings[j] = name; + break; + } + } + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are bytes. + } + } + } + + /** + * @return Returns a mapping with string representations of flags. + */ + public static String[] getFlagMap() { + getConstantMaps(); + return fgFlagStrings; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpReplyPacket.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpReplyPacket.java new file mode 100644 index 0000000000..bbcecbdd8e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/JdwpReplyPacket.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +/** + * This class implements the corresponding Java Debug Wire Protocol (JDWP) + * packet declared by the JDWP specification. + * + */ +public class JdwpReplyPacket extends JdwpPacket { + /** Error code constants. */ + public static final short NONE = 0; + public static final short INVALID_THREAD = 10; + public static final short INVALID_THREAD_GROUP = 11; + public static final short INVALID_PRIORITY = 12; + public static final short THREAD_NOT_SUSPENDED = 13; + public static final short THREAD_SUSPENDED = 14; + public static final short INVALID_OBJECT = 20; + public static final short INVALID_CLASS = 21; + public static final short CLASS_NOT_PREPARED = 22; + public static final short INVALID_METHODID = 23; + public static final short INVALID_LOCATION = 24; + public static final short INVALID_FIELDID = 25; + public static final short INVALID_FRAMEID = 30; + public static final short NO_MORE_FRAMES = 31; + public static final short OPAQUE_FRAME = 32; + public static final short NOT_CURRENT_FRAME = 33; + public static final short TYPE_MISMATCH = 34; + public static final short INVALID_SLOT = 35; + public static final short DUPLICATE = 40; + public static final short NOT_FOUND = 41; + public static final short INVALID_MONITOR = 50; + public static final short NOT_MONITOR_OWNER = 51; + public static final short INTERRUPT = 52; + public static final short INVALID_CLASS_FORMAT = 60; + public static final short CIRCULAR_CLASS_DEFINITION = 61; + public static final short FAILS_VERIFICATION = 62; + public static final short ADD_METHOD_NOT_IMPLEMENTED = 63; + public static final short SCHEMA_CHANGE_NOT_IMPLEMENTED = 64; + public static final short INVALID_TYPESTATE = 65; + public static final short HIERARCHY_CHANGE_NOT_IMPLEMENTED = 66; + public static final short DELETE_METHOD_NOT_IMPLEMENTED = 67; + public static final short UNSUPPORTED_VERSION = 68; + public static final short NAMES_DONT_MATCH = 69; + public static final short CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED = 70; + public static final short METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED = 71; + public static final short NOT_IMPLEMENTED = 99; + public static final short NULL_POINTER = 100; + public static final short ABSENT_INFORMATION = 101; + public static final short INVALID_EVENT_TYPE = 102; + public static final short ILLEGAL_ARGUMENT = 103; + public static final short OUT_OF_MEMORY = 110; + public static final short ACCESS_DENIED = 111; + public static final short VM_DEAD = 112; + public static final short INTERNAL = 113; + public static final short UNATTACHED_THREAD = 115; + public static final short INVALID_TAG = 500; + public static final short ALREADY_INVOKING = 502; + public static final short INVALID_INDEX = 503; + public static final short INVALID_LENGTH = 504; + public static final short INVALID_STRING = 506; + public static final short INVALID_CLASS_LOADER = 507; + public static final short INVALID_ARRAY = 508; + public static final short TRANSPORT_LOAD = 509; + public static final short TRANSPORT_INIT = 510; + public static final short NATIVE_METHOD = 511; + public static final short INVALID_COUNT = 512; + public static final short HCR_OPERATION_REFUSED = 900; // HCR specific. + + /** Mapping of error codes to strings. */ + private static HashMap fErrorMap = null; + + /** JDWP Error code. */ + private short fErrorCode; + + /** + * Creates new JdwpReplyPacket. + */ + public JdwpReplyPacket() { + setFlags(FLAG_REPLY_PACKET); + } + + /** + * @return Returns JDWP Error code. + */ + public short errorCode() { + return fErrorCode; + } + + /** + * Assigns JDWP Error code. + */ + public void setErrorCode(short newValue) { + fErrorCode = newValue; + } + + /** + * Reads header fields that are specific for this type of packet. + */ + @Override + protected void readSpecificHeaderFields(DataInputStream dataInStream) + throws IOException { + fErrorCode = dataInStream.readShort(); + } + + /** + * Writes header fields that are specific for this type of packet. + */ + @Override + protected void writeSpecificHeaderFields(DataOutputStream dataOutStream) + throws IOException { + dataOutStream.writeShort(fErrorCode); + } + + /** + * Retrieves constant mappings. + */ + public static void getConstantMaps() { + if (fErrorMap != null) { + return; + } + + Field[] fields = JdwpReplyPacket.class.getDeclaredFields(); + fErrorMap = new HashMap<>(fields.length); + for (Field field : fields) { + if ((field.getModifiers() & Modifier.PUBLIC) == 0 + || (field.getModifiers() & Modifier.STATIC) == 0 + || (field.getModifiers() & Modifier.FINAL) == 0) + continue; + + try { + Integer intValue = Integer.valueOf(field.getInt(null)); + fErrorMap.put(intValue, field.getName()); + } catch (IllegalAccessException e) { + // Will not occur for own class. + } catch (IllegalArgumentException e) { + // Should not occur. + // We should take care that all public static final constants + // in this class are numbers that are convertible to int. + } + } + } + + /** + * @return Returns a map with string representations of error codes. + */ + public static Map errorMap() { + getConstantMaps(); + return fErrorMap; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/TcpipSpy.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/TcpipSpy.java new file mode 100644 index 0000000000..3af7fc095e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/TcpipSpy.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + + +/** + * This class can be used to spy all JDWP packets. It should be configured 'in + * between' the debugger application and the VM (or J9 debug proxy). Its + * parameters are: 1) The port number to which the debugger application + * connects; 2) The name of the host on which the VM or proxy waits for a JDWP + * connection; 3) The port number on which the VM or proxy waits for a JDWP + * connection; 4) The file where the trace is written to. + * + * Note that if this program is used for tracing JDWP activity of Leapfrog, the + * 'debug remote program' option must be used, and the J9 proxy must first be + * started up by hand on the port to which Leapfrog will connect. The J9 proxy + * that is started up by Leapfrog is not used and will return immediately. + */ +public class TcpipSpy extends Thread { + + private static final byte[] handshakeBytes = "JDWP-Handshake".getBytes(); //$NON-NLS-1$ + private final boolean fVMtoDebugger; + private final DataInputStream fDataIn; + private final DataOutputStream fDataOut; + + private static VerbosePacketStream out = new VerbosePacketStream(System.out); + private static Map fPackets = new HashMap<>(); + + private static int fFieldIDSize; + private static int fMethodIDSize; + private static int fObjectIDSize; + private static int fReferenceTypeIDSize; + private static int fFrameIDSize; + private static boolean fHasSizes; + + public TcpipSpy(boolean VMtoDebugger, InputStream in, OutputStream out) { + fVMtoDebugger = VMtoDebugger; + fDataIn = new DataInputStream(new BufferedInputStream(in)); + fDataOut = new DataOutputStream(new BufferedOutputStream(out)); + fHasSizes = false; + } + + public static void main(String[] args) { + int inPort = 0; + String serverHost = null; + int outPort = 0; + String outputFile = null; + try { + inPort = Integer.parseInt(args[0]); + serverHost = args[1]; + outPort = Integer.parseInt(args[2]); + if (args.length > 3) { + outputFile = args[3]; + } + } catch (Exception e) { + out.println("usage: TcpipSpy []"); //$NON-NLS-1$ + System.exit(-1); + } + + if (outputFile != null) { + File file = new File(outputFile); + out.println(MessageFormat + .format("Writing output to {0}", new Object[] { file.getAbsolutePath() })); //$NON-NLS-1$ + try { + out = new VerbosePacketStream(new BufferedOutputStream( + new FileOutputStream(file))); + } catch (FileNotFoundException e) { + out.println(MessageFormat + .format("Could not open {0}. Using stdout instead", new Object[] { file.getAbsolutePath() })); //$NON-NLS-1$ + } + } + out.println(); + try (ServerSocket serverSock = new ServerSocket(inPort); + Socket inSock = serverSock.accept(); + Socket outSock = new Socket(InetAddress.getByName(serverHost), + outPort);){ + new TcpipSpy(false, inSock.getInputStream(), + outSock.getOutputStream()).start(); + new TcpipSpy(true, outSock.getInputStream(), + inSock.getOutputStream()).start(); + } catch (Exception e) { + out.println(e); + } + } + + @Override + public void run() { + try { + // Skip handshake. + int handshakeLength; + + handshakeLength = handshakeBytes.length; + while (handshakeLength-- > 0) { + int b = fDataIn.read(); + fDataOut.write(b); + } + fDataOut.flush(); + + // Print all packages. + while (true) { + JdwpPacket p = JdwpPacket.read(fDataIn); + // we need to store conversation only for command send by the + // debugger, + // as there is no answer from the debugger to VM commands. + if (!(fVMtoDebugger && (p.getFlags() & JdwpPacket.FLAG_REPLY_PACKET) == 0)) { + store(p); + } + out.print(p, fVMtoDebugger); + out.flush(); + p.write(fDataOut); + fDataOut.flush(); + } + } catch (EOFException e) { + } catch (SocketException e) { + } catch (IOException e) { + out.println(MessageFormat.format( + "Caught exception: {0}", new Object[] { e.toString() })); //$NON-NLS-1$ + e.printStackTrace(out); + } finally { + try { + fDataIn.close(); + fDataOut.close(); + } catch (IOException e) { + } + out.flush(); + } + } + + public static JdwpCommandPacket getCommand(int id) { + JdwpConversation conversation = fPackets + .get(Integer.valueOf(id)); + if (conversation != null) { + return conversation.getCommand(); + } + return null; + } + + protected static void store(JdwpPacket packet) { + int id = packet.getId(); + JdwpConversation conversation = fPackets + .get(Integer.valueOf(id)); + if (conversation == null) { + conversation = new JdwpConversation(id); + fPackets.put(Integer.valueOf(id), conversation); + } + + if ((packet.getFlags() & JdwpPacket.FLAG_REPLY_PACKET) != 0) { + conversation.setReply((JdwpReplyPacket) packet); + } else { + conversation.setCommand((JdwpCommandPacket) packet); + } + } + + public static int getCommand(JdwpPacket packet) + throws UnableToParseDataException { + JdwpCommandPacket command = null; + if (packet instanceof JdwpCommandPacket) { + command = (JdwpCommandPacket) packet; + } else { + command = getCommand(packet.getId()); + if (command == null) { + throw new UnableToParseDataException( + "This packet is marked as reply, but there is no command with the same id.", null); //$NON-NLS-1$ + } + } + return command.getCommand(); + } + + public static boolean hasSizes() { + return fHasSizes; + } + + public static void setHasSizes(boolean value) { + fHasSizes = value; + } + + public static void setFieldIDSize(int fieldIDSize) { + fFieldIDSize = fieldIDSize; + } + + public static int getFieldIDSize() { + return fFieldIDSize; + } + + public static void setMethodIDSize(int methodIDSize) { + fMethodIDSize = methodIDSize; + } + + public static int getMethodIDSize() { + return fMethodIDSize; + } + + public static void setObjectIDSize(int objectIDSize) { + fObjectIDSize = objectIDSize; + } + + public static int getObjectIDSize() { + return fObjectIDSize; + } + + public static void setReferenceTypeIDSize(int referenceTypeIDSize) { + fReferenceTypeIDSize = referenceTypeIDSize; + } + + public static int getReferenceTypeIDSize() { + return fReferenceTypeIDSize; + } + + public static void setFrameIDSize(int frameIDSize) { + fFrameIDSize = frameIDSize; + } + + public static int getFrameIDSize() { + return fFrameIDSize; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/UnableToParseDataException.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/UnableToParseDataException.java new file mode 100644 index 0000000000..7290a3fbb8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/UnableToParseDataException.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +/** + * Exception throws when the spy have not enough information form correctly + * parse the data. + */ +public class UnableToParseDataException extends Exception { + + /** + * All serializable objects should have a stable serialVersionUID + */ + private static final long serialVersionUID = 1L; + + private final byte[] fRemainingData; + + public UnableToParseDataException(String message, byte[] remainingData) { + super(message); + fRemainingData = remainingData; + } + + public byte[] getRemainingData() { + return fRemainingData; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/VerbosePacketStream.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/VerbosePacketStream.java new file mode 100644 index 0000000000..6fa27e7ca2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/spy/VerbosePacketStream.java @@ -0,0 +1,2976 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Keith Seitz - Bug 165988 + *******************************************************************************/ +package org.eclipse.jdi.internal.spy; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UTFDataFormatException; +import java.text.MessageFormat; +import java.util.Arrays; + + +/** + * The VerbosePacketWriter is responsible for writing out + * JdwpPacket data in human readable form. + */ +public class VerbosePacketStream extends PrintStream { + /** Tag Constants. */ + // public static final byte NULL_TAG = 91; // Used for tagged null values. + public static final byte ARRAY_TAG = 91; // '[' - an array object (objectID + // size). + public static final byte BYTE_TAG = 66; // 'B' - a byte value (1 byte). + public static final byte CHAR_TAG = 67; // 'C' - a character value (2 + // bytes). + public static final byte OBJECT_TAG = 76; // 'L' - an object (objectID + // size). + public static final byte FLOAT_TAG = 70; // 'F' - a float value (4 bytes). + public static final byte DOUBLE_TAG = 68; // 'D' - a double value (8 bytes). + public static final byte INT_TAG = 73; // 'I' - an int value (4 bytes). + public static final byte LONG_TAG = 74; // 'J' - a long value (8 bytes). + public static final byte SHORT_TAG = 83; // 'S' - a short value (2 bytes). + public static final byte VOID_TAG = 86; // 'V' - a void value (no bytes). + public static final byte BOOLEAN_TAG = 90; // 'Z' - a boolean value (1 + // byte). + public static final byte STRING_TAG = 115; // 's' - a String object + // (objectID size). + public static final byte THREAD_TAG = 116; // 't' - a Thread object + // (objectID size). + public static final byte THREAD_GROUP_TAG = 103; // 'g' - a ThreadGroup + // object (objectID + // size). + public static final byte CLASS_LOADER_TAG = 108; // 'l' - a ClassLoader + // object (objectID + // size). + public static final byte CLASS_OBJECT_TAG = 99; // 'c' - a class object + // object (objectID size). + + /** TypeTag Constants. */ + public static final byte TYPE_TAG_CLASS = 1; // ReferenceType is a class. + public static final byte TYPE_TAG_INTERFACE = 2; // ReferenceType is an + // interface. + public static final byte TYPE_TAG_ARRAY = 3; // ReferenceType is an array. + + /** ClassStatus Constants. */ + public static final int JDWP_CLASS_STATUS_VERIFIED = 1; + public static final int JDWP_CLASS_STATUS_PREPARED = 2; + public static final int JDWP_CLASS_STATUS_INITIALIZED = 4; + public static final int JDWP_CLASS_STATUS_ERROR = 8; + + /** access_flags Constants */ + public static final int ACC_PUBLIC = 0x0001; + public static final int ACC_PRIVATE = 0x0002; + public static final int ACC_PROTECTED = 0x0004; + public static final int ACC_STATIC = 0x0008; + public static final int ACC_FINAL = 0x0010; + public static final int ACC_SUPER = 0x0020; + public static final int ACC_VOLATILE = 0x0040; + public static final int ACC_TRANSIENT = 0x0080; + public static final int ACC_NATIVE = 0x0100; + public static final int ACC_INTERFACE = 0x0200; + public static final int ACC_ABSTRACT = 0x0400; + public static final int ACC_STRICT = 0x0800; + public static final int ACC_ENUM = 0x0100; + public static final int ACC_VARARGS = 0x0080; + public static final int ACC_BRIDGE = 0x0040; + public static final int ACC_SYNTHETIC = 0x1000; + public static final int ACC_SYNCHRONIZED = 0x0020; + + public static final int ACC_EXT_SYNTHETIC = 0xf0000000; + + /** Invoke options constants */ + public static final int INVOKE_SINGLE_THREADED = 0x01; + public static final int INVOKE_NONVIRTUAL = 0x02; + + /** ThreadStatus Constants */ + public static final int THREAD_STATUS_ZOMBIE = 0; + public static final int THREAD_STATUS_RUNNING = 1; + public static final int THREAD_STATUS_SLEEPING = 2; + public static final int THREAD_STATUS_MONITOR = 3; + public static final int THREAD_STATUS_WAIT = 4; + + /** EventKind Constants */ + public static final int EVENTKIND_SINGLE_STEP = 1; + public static final int EVENTKIND_BREAKPOINT = 2; + public static final int EVENTKIND_FRAME_POP = 3; + public static final int EVENTKIND_EXCEPTION = 4; + public static final int EVENTKIND_USER_DEFINED = 5; + public static final int EVENTKIND_THREAD_START = 6; + public static final int EVENTKIND_THREAD_END = 7; + public static final int EVENTKIND_THREAD_DEATH = EVENTKIND_THREAD_END; + public static final int EVENTKIND_CLASS_PREPARE = 8; + public static final int EVENTKIND_CLASS_UNLOAD = 9; + public static final int EVENTKIND_CLASS_LOAD = 10; + public static final int EVENTKIND_FIELD_ACCESS = 20; + public static final int EVENTKIND_FIELD_MODIFICATION = 21; + public static final int EVENTKIND_EXCEPTION_CATCH = 30; + public static final int EVENTKIND_METHOD_ENTRY = 40; + public static final int EVENTKIND_METHOD_EXIT = 41; + public static final int EVENTKIND_VM_INIT = 90; + public static final int EVENTKIND_VM_START = EVENTKIND_VM_INIT; + public static final int EVENTKIND_VM_DEATH = 99; + public static final int EVENTKIND_VM_DISCONNECTED = 100; + + /** SuspendStatus Constants */ + public static final int SUSPEND_STATUS_SUSPENDED = 0x01; + + /** SuspendPolicy Constants */ + public static final int SUSPENDPOLICY_NONE = 0; + public static final int SUSPENDPOLICY_EVENT_THREAD = 1; + public static final int SUSPENDPOLICY_ALL = 2; + + /** StepDepth Constants */ + public static final int STEPDEPTH_INTO = 0; + public static final int STEPDEPTH_OVER = 1; + public static final int STEPDEPTH_OUT = 2; + + /** StepSize Constants */ + public static final int STEPSIZE_MIN = 0; + public static final int STEPSIZE_LINE = 1; + + private static final byte[] padding; + static { + padding = new byte[256]; + Arrays.fill(padding, (byte) ' '); + } + + private static final String shift = new String(padding, 0, 32); + + public VerbosePacketStream(OutputStream out) { + super(out); + } + + private static final byte[] zeros; + static { + zeros = new byte[16]; + Arrays.fill(zeros, (byte) '0'); + } + + public synchronized void print(JdwpPacket packet, boolean fromVM) + throws IOException { + try { + printHeader(packet, fromVM); + printData(packet); + println(); + } catch (UnableToParseDataException e) { + println("\n" + e.getMessage() + ':'); //$NON-NLS-1$ + printDescription("Remaining data:"); //$NON-NLS-1$ + byte[] data = e.getRemainingData(); + if (data == null) { + printHex(packet.data()); + } else { + printHex(e.getRemainingData()); + } + println(); + } + } + + protected void printHeader(JdwpPacket packet, boolean fromVM) + throws UnableToParseDataException { + if (fromVM) { + println("From VM"); //$NON-NLS-1$ + } else { + println("From Debugger"); //$NON-NLS-1$ + } + + printDescription("Packet ID:"); //$NON-NLS-1$ + printHex(packet.getId()); + println(); + + printDescription("Length:"); //$NON-NLS-1$ + print(packet.getLength()); + println(); + + printDescription("Flags:"); //$NON-NLS-1$ + byte flags = packet.getFlags(); + printHex(flags); + if ((flags & JdwpPacket.FLAG_REPLY_PACKET) != 0) { + print(MessageFormat + .format(" (REPLY to {0})", new Object[] { JdwpCommandPacket.commandMap().get(Integer.valueOf(TcpipSpy.getCommand(packet))) })); //$NON-NLS-1$ + } else { + print(" (COMMAND)"); //$NON-NLS-1$ + } + println(); + + printSpecificHeaderFields(packet); + } + + protected void printSpecificHeaderFields(JdwpPacket packet) { + if (packet instanceof JdwpReplyPacket) { + printError((JdwpReplyPacket) packet); + } else if (packet instanceof JdwpCommandPacket) { + printCommand((JdwpCommandPacket) packet); + } + } + + protected void printCommand(JdwpCommandPacket commandPacket) { + printDescription("Command set:"); //$NON-NLS-1$ + int commandAndSet = commandPacket.getCommand(); + byte set = (byte) (commandAndSet >> 8); + byte command = (byte) commandAndSet; + printHex(set); + printParanthetical(set); + println(); + printDescription("Command:"); //$NON-NLS-1$ + printHex(command); + printParanthetical(command); + print(" ("); //$NON-NLS-1$ + print(JdwpCommandPacket.commandMap().get(Integer.valueOf(commandAndSet))); + println(')'); + } + + protected void printError(JdwpReplyPacket reply) { + int error = reply.errorCode(); + + printDescription("Error:"); //$NON-NLS-1$ + printHex(error); + if (error != 0) { + print(" ("); //$NON-NLS-1$ + print(JdwpReplyPacket.errorMap().get(Integer.valueOf(error))); + print(')'); + } + println(); + } + + protected void printData(JdwpPacket packet) throws IOException, + UnableToParseDataException { + if ((packet.getFlags() & JdwpPacket.FLAG_REPLY_PACKET) != 0) { + printReplyData((JdwpReplyPacket) packet); + } else { + printCommandData((JdwpCommandPacket) packet); + } + } + + private void printCommandData(JdwpCommandPacket command) + throws IOException, UnableToParseDataException { + byte[] data = command.data(); + if (data == null) { + return; + } + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); + int commandId = command.getCommand(); + switch (commandId) { + /** Commands VirtualMachine. */ + case JdwpCommandPacket.VM_VERSION: + // no data + break; + case JdwpCommandPacket.VM_CLASSES_BY_SIGNATURE: + printVmClassesBySignatureCommand(in); + break; + case JdwpCommandPacket.VM_ALL_CLASSES: + // no data + break; + case JdwpCommandPacket.VM_ALL_THREADS: + // no data + break; + case JdwpCommandPacket.VM_TOP_LEVEL_THREAD_GROUPS: + // no data + break; + case JdwpCommandPacket.VM_DISPOSE: + // no data + break; + case JdwpCommandPacket.VM_ID_SIZES: + // no data + break; + case JdwpCommandPacket.VM_SUSPEND: + // no data + break; + case JdwpCommandPacket.VM_RESUME: + // no data + break; + case JdwpCommandPacket.VM_EXIT: + printVmExitCommand(in); + break; + case JdwpCommandPacket.VM_CREATE_STRING: + printVmCreateStringCommand(in); + break; + case JdwpCommandPacket.VM_CAPABILITIES: + // no data + break; + case JdwpCommandPacket.VM_CLASS_PATHS: + // no data + break; + case JdwpCommandPacket.VM_DISPOSE_OBJECTS: + printVmDisposeObjectsCommand(in); + break; + case JdwpCommandPacket.VM_HOLD_EVENTS: + // no data + break; + case JdwpCommandPacket.VM_RELEASE_EVENTS: + // no data + break; + case JdwpCommandPacket.VM_CAPABILITIES_NEW: + // no data + break; + case JdwpCommandPacket.VM_REDEFINE_CLASSES: + printVmRedefineClassCommand(in); + break; + case JdwpCommandPacket.VM_SET_DEFAULT_STRATUM: + printVmSetDefaultStratumCommand(in); + break; + case JdwpCommandPacket.VM_ALL_CLASSES_WITH_GENERIC: + // no data + break; + + /** Commands ReferenceType. */ + case JdwpCommandPacket.RT_SIGNATURE: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_CLASS_LOADER: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_MODIFIERS: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_FIELDS: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_METHODS: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_GET_VALUES: + printRtGetValuesCommand(in); + break; + case JdwpCommandPacket.RT_SOURCE_FILE: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_NESTED_TYPES: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_STATUS: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_INTERFACES: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_CLASS_OBJECT: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_SOURCE_DEBUG_EXTENSION: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_SIGNATURE_WITH_GENERIC: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_FIELDS_WITH_GENERIC: + printRtDefaultCommand(in); + break; + case JdwpCommandPacket.RT_METHODS_WITH_GENERIC: + printRtDefaultCommand(in); + break; + + /** Commands ClassType. */ + case JdwpCommandPacket.CT_SUPERCLASS: + printCtSuperclassCommand(in); + break; + case JdwpCommandPacket.CT_SET_VALUES: + printCtSetValuesCommand(in); + break; + case JdwpCommandPacket.CT_INVOKE_METHOD: + printCtInvokeMethodCommand(in); + break; + case JdwpCommandPacket.CT_NEW_INSTANCE: + printCtNewInstanceCommand(in); + break; + + /** Commands ArrayType. */ + case JdwpCommandPacket.AT_NEW_INSTANCE: + printAtNewInstanceCommand(in); + break; + + /** Commands Method. */ + case JdwpCommandPacket.M_LINE_TABLE: + printMDefaultCommand(in); + break; + case JdwpCommandPacket.M_VARIABLE_TABLE: + printMDefaultCommand(in); + break; + case JdwpCommandPacket.M_BYTECODES: + printMDefaultCommand(in); + break; + case JdwpCommandPacket.M_IS_OBSOLETE: + printMDefaultCommand(in); + break; + case JdwpCommandPacket.M_VARIABLE_TABLE_WITH_GENERIC: + printMDefaultCommand(in); + break; + + /** Commands ObjectReference. */ + case JdwpCommandPacket.OR_REFERENCE_TYPE: + printOrDefaultCommand(in); + break; + case JdwpCommandPacket.OR_GET_VALUES: + printOrGetValuesCommand(in); + break; + case JdwpCommandPacket.OR_SET_VALUES: + printOrSetValuesCommand(in); + break; + case JdwpCommandPacket.OR_MONITOR_INFO: + printOrDefaultCommand(in); + break; + case JdwpCommandPacket.OR_INVOKE_METHOD: + printOrInvokeMethodCommand(in); + break; + case JdwpCommandPacket.OR_DISABLE_COLLECTION: + printOrDefaultCommand(in); + break; + case JdwpCommandPacket.OR_ENABLE_COLLECTION: + printOrDefaultCommand(in); + break; + case JdwpCommandPacket.OR_IS_COLLECTED: + printOrDefaultCommand(in); + break; + + /** Commands StringReference. */ + case JdwpCommandPacket.SR_VALUE: + printSrValueCommand(in); + break; + + /** Commands ThreadReference. */ + case JdwpCommandPacket.TR_NAME: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_SUSPEND: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_RESUME: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_STATUS: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_THREAD_GROUP: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_FRAMES: + printTrFramesCommand(in); + break; + case JdwpCommandPacket.TR_FRAME_COUNT: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_OWNED_MONITORS: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_CURRENT_CONTENDED_MONITOR: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_STOP: + printTrStopCommand(in); + break; + case JdwpCommandPacket.TR_INTERRUPT: + printTrDefaultCommand(in); + break; + case JdwpCommandPacket.TR_SUSPEND_COUNT: + printTrDefaultCommand(in); + break; + /* + * no more in the jdwp spec case JdwpCommandPacket.TR_POP_TOP_FRAME: + * break; + */ + + /** Commands ThreadGroupReference. */ + case JdwpCommandPacket.TGR_NAME: + printTgrDefaultCommand(in); + break; + case JdwpCommandPacket.TGR_PARENT: + printTgrDefaultCommand(in); + break; + case JdwpCommandPacket.TGR_CHILDREN: + printTgrDefaultCommand(in); + break; + + /** Commands ArrayReference. */ + case JdwpCommandPacket.AR_LENGTH: + printArLengthCommand(in); + break; + case JdwpCommandPacket.AR_GET_VALUES: + printArGetValuesCommand(in); + break; + case JdwpCommandPacket.AR_SET_VALUES: + printArSetValuesCommand(in); + break; + + /** Commands ClassLoaderReference. */ + case JdwpCommandPacket.CLR_VISIBLE_CLASSES: + printClrVisibleClassesCommand(in); + break; + + /** Commands EventRequest. */ + case JdwpCommandPacket.ER_SET: + printErSetCommand(in); + break; + case JdwpCommandPacket.ER_CLEAR: + printErClearCommand(in); + break; + case JdwpCommandPacket.ER_CLEAR_ALL_BREAKPOINTS: + // no data + break; + + /** Commands StackFrame. */ + case JdwpCommandPacket.SF_GET_VALUES: + printSfGetValuesCommand(in); + break; + case JdwpCommandPacket.SF_SET_VALUES: + printSfSetValuesCommand(in); + break; + case JdwpCommandPacket.SF_THIS_OBJECT: + printSfDefaultCommand(in); + break; + case JdwpCommandPacket.SF_POP_FRAME: + printSfDefaultCommand(in); + break; + + /** Commands ClassObjectReference. */ + case JdwpCommandPacket.COR_REFLECTED_TYPE: + printCorReflectedTypeCommand(in); + break; + + /** Commands Event. */ + case JdwpCommandPacket.E_COMPOSITE: + printECompositeCommand(in); + break; + + /** Commands Hot Code Replacement (OTI specific). */ + case JdwpCommandPacket.HCR_CLASSES_HAVE_CHANGED: + case JdwpCommandPacket.HCR_GET_CLASS_VERSION: + case JdwpCommandPacket.HCR_DO_RETURN: + case JdwpCommandPacket.HCR_REENTER_ON_EXIT: + case JdwpCommandPacket.HCR_CAPABILITIES: + throw new UnableToParseDataException( + "NOT MANAGED COMMAND", remainderData(in)); //$NON-NLS-1$ + + default: + int cset = commandId >> 8; + int cmd = commandId & 0xFF; + println(MessageFormat + .format("Unknown command : {0} {1}", new Object[] { "" + cset, "" + cmd })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } + + private void printReplyData(JdwpReplyPacket reply) throws IOException, + UnableToParseDataException { + byte[] data = reply.data(); + if (data == null) { + return; + } + DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); + JdwpCommandPacket command = TcpipSpy.getCommand(reply.getId()); + int commandId = command.getCommand(); + switch (commandId) { + /** Commands VirtualMachine. */ + case JdwpCommandPacket.VM_VERSION: + printVmVersionReply(in); + break; + case JdwpCommandPacket.VM_CLASSES_BY_SIGNATURE: + printVmClassesBySignatureReply(in); + break; + case JdwpCommandPacket.VM_ALL_CLASSES: + printVmAllClassesReply(in); + break; + case JdwpCommandPacket.VM_ALL_THREADS: + printVmAllThreadsReply(in); + break; + case JdwpCommandPacket.VM_TOP_LEVEL_THREAD_GROUPS: + printVmTopLevelThreadGroupReply(in); + break; + case JdwpCommandPacket.VM_DISPOSE: + // no data + break; + case JdwpCommandPacket.VM_ID_SIZES: + printVmIdSizesReply(in); + break; + case JdwpCommandPacket.VM_SUSPEND: + // no data + break; + case JdwpCommandPacket.VM_RESUME: + // no data + break; + case JdwpCommandPacket.VM_EXIT: + // no data + break; + case JdwpCommandPacket.VM_CREATE_STRING: + printVmCreateStringReply(in); + break; + case JdwpCommandPacket.VM_CAPABILITIES: + printVmCapabilitiesReply(in); + break; + case JdwpCommandPacket.VM_CLASS_PATHS: + printVmClassPathsReply(in); + break; + case JdwpCommandPacket.VM_DISPOSE_OBJECTS: + // no data + break; + case JdwpCommandPacket.VM_HOLD_EVENTS: + // no data + break; + case JdwpCommandPacket.VM_RELEASE_EVENTS: + // no data + break; + case JdwpCommandPacket.VM_CAPABILITIES_NEW: + printVmCapabilitiesNewReply(in); + break; + case JdwpCommandPacket.VM_REDEFINE_CLASSES: + // no data + break; + case JdwpCommandPacket.VM_SET_DEFAULT_STRATUM: + // no data + break; + case JdwpCommandPacket.VM_ALL_CLASSES_WITH_GENERIC: + printVmAllClassesWithGenericReply(in); + break; + + /** Commands ReferenceType. */ + case JdwpCommandPacket.RT_SIGNATURE: + printRtSignatureReply(in); + break; + case JdwpCommandPacket.RT_CLASS_LOADER: + printRtClassLoaderReply(in); + break; + case JdwpCommandPacket.RT_MODIFIERS: + printRtModifiersReply(in); + break; + case JdwpCommandPacket.RT_FIELDS: + printRtFieldsReply(in); + break; + case JdwpCommandPacket.RT_METHODS: + printRtMethodsReply(in); + break; + case JdwpCommandPacket.RT_GET_VALUES: + printRtGetValuesReply(in); + break; + case JdwpCommandPacket.RT_SOURCE_FILE: + printRtSourceFileReply(in); + break; + case JdwpCommandPacket.RT_NESTED_TYPES: + printRtNestedTypesReply(in); + break; + case JdwpCommandPacket.RT_STATUS: + printRtStatusReply(in); + break; + case JdwpCommandPacket.RT_INTERFACES: + printRtInterfacesReply(in); + break; + case JdwpCommandPacket.RT_CLASS_OBJECT: + printRtClassObjectReply(in); + break; + case JdwpCommandPacket.RT_SOURCE_DEBUG_EXTENSION: + printRtSourceDebugExtensionReply(in); + break; + case JdwpCommandPacket.RT_SIGNATURE_WITH_GENERIC: + printRtSignatureWithGenericReply(in); + break; + case JdwpCommandPacket.RT_FIELDS_WITH_GENERIC: + printRtFieldsWithGenericReply(in); + break; + case JdwpCommandPacket.RT_METHODS_WITH_GENERIC: + printRtMethodsWithGenericReply(in); + break; + + /** Commands ClassType. */ + case JdwpCommandPacket.CT_SUPERCLASS: + printCtSuperclassReply(in); + break; + case JdwpCommandPacket.CT_SET_VALUES: + // no data + break; + case JdwpCommandPacket.CT_INVOKE_METHOD: + printCtInvokeMethodReply(in); + break; + case JdwpCommandPacket.CT_NEW_INSTANCE: + printCtNewInstanceReply(in); + break; + + /** Commands ArrayType. */ + case JdwpCommandPacket.AT_NEW_INSTANCE: + printAtNewInstanceReply(in); + break; + + /** Commands Method. */ + case JdwpCommandPacket.M_LINE_TABLE: + printMLineTableReply(in); + break; + case JdwpCommandPacket.M_VARIABLE_TABLE: + printMVariableTableReply(in); + break; + case JdwpCommandPacket.M_BYTECODES: + printMBytecodesReply(in); + break; + case JdwpCommandPacket.M_IS_OBSOLETE: + printMIsObsoleteReply(in); + break; + case JdwpCommandPacket.M_VARIABLE_TABLE_WITH_GENERIC: + printMVariableTableWithGenericReply(in); + break; + + /** Commands ObjectReference. */ + case JdwpCommandPacket.OR_REFERENCE_TYPE: + printOrReferenceTypeReply(in); + break; + case JdwpCommandPacket.OR_GET_VALUES: + printOrGetValuesReply(in); + break; + case JdwpCommandPacket.OR_SET_VALUES: + // no data + break; + case JdwpCommandPacket.OR_MONITOR_INFO: + printOrMonitorInfoReply(in); + break; + case JdwpCommandPacket.OR_INVOKE_METHOD: + printOrInvokeMethodReply(in); + break; + case JdwpCommandPacket.OR_DISABLE_COLLECTION: + // no data + break; + case JdwpCommandPacket.OR_ENABLE_COLLECTION: + // no data + break; + case JdwpCommandPacket.OR_IS_COLLECTED: + printOrIsCollectedReply(in); + break; + + /** Commands StringReference. */ + case JdwpCommandPacket.SR_VALUE: + printSrValueReply(in); + break; + + /** Commands ThreadReference. */ + case JdwpCommandPacket.TR_NAME: + printTrNameReply(in); + break; + case JdwpCommandPacket.TR_SUSPEND: + // no data + break; + case JdwpCommandPacket.TR_RESUME: + // no data + break; + case JdwpCommandPacket.TR_STATUS: + printTrStatusReply(in); + break; + case JdwpCommandPacket.TR_THREAD_GROUP: + printTrThreadGroupReply(in); + break; + case JdwpCommandPacket.TR_FRAMES: + printTrFramesReply(in); + break; + case JdwpCommandPacket.TR_FRAME_COUNT: + printTrFrameCountReply(in); + break; + case JdwpCommandPacket.TR_OWNED_MONITORS: + printTrOwnedMonitorsReply(in); + break; + case JdwpCommandPacket.TR_CURRENT_CONTENDED_MONITOR: + printTrCurrentContendedMonitorReply(in); + break; + case JdwpCommandPacket.TR_STOP: + // no data + break; + case JdwpCommandPacket.TR_INTERRUPT: + // no data + break; + case JdwpCommandPacket.TR_SUSPEND_COUNT: + printTrSuspendCountReply(in); + break; + /* + * no more in the jdwp spec case JdwpCommandPacket.TR_POP_TOP_FRAME: + * break; + */ + /** Commands ThreadGroupReference. */ + case JdwpCommandPacket.TGR_NAME: + printTgrNameReply(in); + break; + case JdwpCommandPacket.TGR_PARENT: + printTgrParentReply(in); + break; + case JdwpCommandPacket.TGR_CHILDREN: + printTgrChildrenReply(in); + break; + + /** Commands ArrayReference. */ + case JdwpCommandPacket.AR_LENGTH: + printArLengthReply(in); + break; + case JdwpCommandPacket.AR_GET_VALUES: + printArGetValuesReply(in); + break; + case JdwpCommandPacket.AR_SET_VALUES: + // no data + break; + + /** Commands ClassLoaderReference. */ + case JdwpCommandPacket.CLR_VISIBLE_CLASSES: + printClrVisibleClassesReply(in); + break; + + /** Commands EventRequest. */ + case JdwpCommandPacket.ER_SET: + printErSetReply(in); + break; + case JdwpCommandPacket.ER_CLEAR: + // no data + break; + case JdwpCommandPacket.ER_CLEAR_ALL_BREAKPOINTS: + // no data + break; + + /** Commands StackFrame. */ + case JdwpCommandPacket.SF_GET_VALUES: + printSfGetValuesReply(in); + break; + case JdwpCommandPacket.SF_SET_VALUES: + // no data + break; + case JdwpCommandPacket.SF_THIS_OBJECT: + printSfThisObjectReply(in); + break; + case JdwpCommandPacket.SF_POP_FRAME: + // no data + break; + + /** Commands ClassObjectReference. */ + case JdwpCommandPacket.COR_REFLECTED_TYPE: + printCorReflectedTypeReply(in); + break; + + /** Commands Event. */ + /* + * no reply case JdwpCommandPacket.E_COMPOSITE: break; + */ + + /** Commands Hot Code Replacement (OTI specific). */ + case JdwpCommandPacket.HCR_CLASSES_HAVE_CHANGED: + case JdwpCommandPacket.HCR_GET_CLASS_VERSION: + case JdwpCommandPacket.HCR_DO_RETURN: + case JdwpCommandPacket.HCR_REENTER_ON_EXIT: + case JdwpCommandPacket.HCR_CAPABILITIES: + throw new UnableToParseDataException( + "NOT MANAGED COMMAND", remainderData(in)); //$NON-NLS-1$ + + default: + int cset = commandId >> 8; + int cmd = commandId & 0xFF; + println(MessageFormat + .format("Unknown command : {0} {1}", new Object[] { "" + cset, "" + cmd })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } + + private void printRefTypeTag(byte refTypeTag) { + printDescription("Type tag:"); //$NON-NLS-1$ + printRefTypeTagValue(refTypeTag); + println(); + } + + private void printRefTypeTagValue(byte refTypeTag) { + printHex(refTypeTag); + print(" ("); //$NON-NLS-1$ + switch (refTypeTag) { + case TYPE_TAG_CLASS: + print("CLASS"); //$NON-NLS-1$ + break; + case TYPE_TAG_INTERFACE: + print("INTERFACE"); //$NON-NLS-1$ + break; + case TYPE_TAG_ARRAY: + print("ARRAY"); //$NON-NLS-1$ + break; + default: + print("unknown"); //$NON-NLS-1$ + } + print(')'); + } + + private void printClassStatus(int status) { + printDescription("Status:"); //$NON-NLS-1$ + printHex(status); + print(" ("); //$NON-NLS-1$ + boolean spaceNeeded = false; + if ((status & JDWP_CLASS_STATUS_VERIFIED) != 0) { + print("VERIFIED"); //$NON-NLS-1$ + spaceNeeded = true; + } + if ((status & JDWP_CLASS_STATUS_PREPARED) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PREPARED"); //$NON-NLS-1$ + } + if ((status & JDWP_CLASS_STATUS_INITIALIZED) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("INITIALIZED"); //$NON-NLS-1$ + } + if ((status & JDWP_CLASS_STATUS_ERROR) != 0) { + if (spaceNeeded) { + print(' '); + } + print("unknown"); //$NON-NLS-1$ + } + println(')'); + } + + private void printClassModifiers(int modifiers) { + printDescription("Modifiers:"); //$NON-NLS-1$ + printHex(modifiers); + print(" ("); //$NON-NLS-1$ + boolean spaceNeeded = false; + if ((modifiers & ACC_PUBLIC) != 0) { + print("PUBLIC"); //$NON-NLS-1$ + spaceNeeded = true; + } + if ((modifiers & ACC_PRIVATE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PRIVATE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_PROTECTED) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PROTECTED"); //$NON-NLS-1$ + } + if ((modifiers & ACC_STATIC) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("STATIC"); //$NON-NLS-1$ + } + if ((modifiers & ACC_FINAL) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("FINAL"); //$NON-NLS-1$ + } + if ((modifiers & ACC_SUPER) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("SUPER"); //$NON-NLS-1$ + } + if ((modifiers & ACC_INTERFACE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("INTERFACE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_ABSTRACT) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("ABSTRACT"); //$NON-NLS-1$ + } + if ((modifiers & (ACC_EXT_SYNTHETIC | ACC_SYNTHETIC)) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("SYNTHETIC"); //$NON-NLS-1$ + } + println(')'); + } + + private void printMethodModifiers(int modifiers) { + printDescription("Modifiers:"); //$NON-NLS-1$ + printHex(modifiers); + print(" ("); //$NON-NLS-1$ + boolean spaceNeeded = false; + if ((modifiers & ACC_PUBLIC) != 0) { + print("PUBLIC"); //$NON-NLS-1$ + spaceNeeded = true; + } + if ((modifiers & ACC_PRIVATE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PRIVATE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_PROTECTED) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PROTECTED"); //$NON-NLS-1$ + } + if ((modifiers & ACC_STATIC) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("STATIC"); //$NON-NLS-1$ + } + if ((modifiers & ACC_FINAL) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("FINAL"); //$NON-NLS-1$ + } + if ((modifiers & ACC_SYNCHRONIZED) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("SYNCHRONIZED"); //$NON-NLS-1$ + } + if ((modifiers & ACC_BRIDGE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("BRIDGE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_VARARGS) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("VARARGS"); //$NON-NLS-1$ + } + if ((modifiers & ACC_NATIVE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("NATIVE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_ABSTRACT) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("ABSTRACT"); //$NON-NLS-1$ + } + if ((modifiers & ACC_STRICT) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("STRICT"); //$NON-NLS-1$ + } + if ((modifiers & (ACC_EXT_SYNTHETIC | ACC_SYNTHETIC)) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("SYNTHETIC"); //$NON-NLS-1$ + } + println(')'); + } + + private void printFieldModifiers(int modifiers) { + printDescription("Modifiers:"); //$NON-NLS-1$ + printHex(modifiers); + print(" ("); //$NON-NLS-1$ + boolean spaceNeeded = false; + if ((modifiers & ACC_PUBLIC) != 0) { + print("PUBLIC"); //$NON-NLS-1$ + spaceNeeded = true; + } + if ((modifiers & ACC_PRIVATE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PRIVATE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_PROTECTED) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("PROTECTED"); //$NON-NLS-1$ + } + if ((modifiers & ACC_STATIC) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("STATIC"); //$NON-NLS-1$ + } + if ((modifiers & ACC_FINAL) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("FINAL"); //$NON-NLS-1$ + } + if ((modifiers & ACC_VOLATILE) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("VOLATILE"); //$NON-NLS-1$ + } + if ((modifiers & ACC_TRANSIENT) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("TRANSIENT"); //$NON-NLS-1$ + } + if ((modifiers & ACC_ENUM) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("ENUM"); //$NON-NLS-1$ + } + if ((modifiers & (ACC_EXT_SYNTHETIC | ACC_SYNTHETIC)) != 0) { + if (spaceNeeded) { + print(' '); + } else { + spaceNeeded = true; + } + print("SYNTHETIC"); //$NON-NLS-1$ + } + println(')'); + } + + private void printInvocationOptions(int invocationOptions) { + printDescription("Invocation Options:"); //$NON-NLS-1$ + printHex(invocationOptions); + print(" ("); //$NON-NLS-1$ + boolean spaceNeeded = false; + if ((invocationOptions & INVOKE_SINGLE_THREADED) != 0) { + print("SINGLE_THREADED"); //$NON-NLS-1$ + spaceNeeded = true; + } + if ((invocationOptions & INVOKE_NONVIRTUAL) != 0) { + if (spaceNeeded) { + print(' '); + } + print("NONVIRTUAL"); //$NON-NLS-1$ + } + println(')'); + } + + private void printThreadStatus(int threadStatus) { + printDescription("Thread status:"); //$NON-NLS-1$ + printHex(threadStatus); + print(" ("); //$NON-NLS-1$ + switch (threadStatus) { + case THREAD_STATUS_ZOMBIE: + print("ZOMBIE"); //$NON-NLS-1$ + break; + case THREAD_STATUS_RUNNING: + print("RUNNING"); //$NON-NLS-1$ + break; + case THREAD_STATUS_SLEEPING: + print("SLEEPING"); //$NON-NLS-1$ + break; + case THREAD_STATUS_MONITOR: + print("MONITOR"); //$NON-NLS-1$ + break; + case THREAD_STATUS_WAIT: + print("WAIT"); //$NON-NLS-1$ + break; + default: + print("unknown"); //$NON-NLS-1$ + break; + } + println(')'); + } + + private void printSuspendStatus(int suspendStatus) { + printDescription("Suspend status:"); //$NON-NLS-1$ + printHex(suspendStatus); + print(" ("); //$NON-NLS-1$ + if ((suspendStatus & SUSPEND_STATUS_SUSPENDED) != 0) { + print("SUSPENDED"); //$NON-NLS-1$ + } + println(')'); + } + + private void printEventKind(byte eventKind) { + printDescription("Event kind:"); //$NON-NLS-1$ + printHex(eventKind); + print(" ("); //$NON-NLS-1$ + switch (eventKind) { + case EVENTKIND_SINGLE_STEP: + print("SINGLE_STEP"); //$NON-NLS-1$ + break; + case EVENTKIND_BREAKPOINT: + print("BREAKPOINT"); //$NON-NLS-1$ + break; + case EVENTKIND_FRAME_POP: + print("FRAME_POP"); //$NON-NLS-1$ + break; + case EVENTKIND_EXCEPTION: + print("EXCEPTION"); //$NON-NLS-1$ + break; + case EVENTKIND_USER_DEFINED: + print("USER_DEFINED"); //$NON-NLS-1$ + break; + case EVENTKIND_THREAD_START: + print("THREAD_START"); //$NON-NLS-1$ + break; + case EVENTKIND_THREAD_END: + print("THREAD_END"); //$NON-NLS-1$ + break; + case EVENTKIND_CLASS_PREPARE: + print("CLASS_PREPARE"); //$NON-NLS-1$ + break; + case EVENTKIND_CLASS_UNLOAD: + print("CLASS_UNLOAD"); //$NON-NLS-1$ + break; + case EVENTKIND_CLASS_LOAD: + print("CLASS_LOAD"); //$NON-NLS-1$ + break; + case EVENTKIND_FIELD_ACCESS: + print("FIELD_ACCESS"); //$NON-NLS-1$ + break; + case EVENTKIND_FIELD_MODIFICATION: + print("FIELD_MODIFICATION"); //$NON-NLS-1$ + break; + case EVENTKIND_EXCEPTION_CATCH: + print("EXCEPTION_CATCH"); //$NON-NLS-1$ + break; + case EVENTKIND_METHOD_ENTRY: + print("METHOD_ENTRY"); //$NON-NLS-1$ + break; + case EVENTKIND_METHOD_EXIT: + print("METHOD_EXIT"); //$NON-NLS-1$ + break; + case EVENTKIND_VM_INIT: + print("VM_INIT"); //$NON-NLS-1$ + break; + case EVENTKIND_VM_DEATH: + print("VM_DEATH"); //$NON-NLS-1$ + break; + case EVENTKIND_VM_DISCONNECTED: + print("VM_DISCONNECTED"); //$NON-NLS-1$ + break; + default: + print("unknown"); //$NON-NLS-1$ + break; + } + println(')'); + } + + private void printSuspendPolicy(byte suspendPolicy) { + printDescription("Suspend policy:"); //$NON-NLS-1$ + printHex(suspendPolicy); + print(" ("); //$NON-NLS-1$ + switch (suspendPolicy) { + case SUSPENDPOLICY_NONE: + print("NONE"); //$NON-NLS-1$ + break; + case SUSPENDPOLICY_EVENT_THREAD: + print("EVENT_THREAD"); //$NON-NLS-1$ + break; + case SUSPENDPOLICY_ALL: + print("ALL"); //$NON-NLS-1$ + break; + default: + print("unknown"); //$NON-NLS-1$ + break; + } + println(')'); + } + + private void printStepDepth(int setDepth) { + printDescription("Step depth:"); //$NON-NLS-1$ + printHex(setDepth); + print(" ("); //$NON-NLS-1$ + switch (setDepth) { + case STEPDEPTH_INTO: + print("INTO"); //$NON-NLS-1$ + break; + case STEPDEPTH_OVER: + print("OVER"); //$NON-NLS-1$ + break; + case STEPDEPTH_OUT: + print("OUT"); //$NON-NLS-1$ + break; + default: + print("unknown"); //$NON-NLS-1$ + break; + } + println(')'); + } + + private void printStepSize(int setSize) { + printDescription("Step size:"); //$NON-NLS-1$ + printHex(setSize); + print(" ("); //$NON-NLS-1$ + switch (setSize) { + case STEPSIZE_MIN: + print("MIN"); //$NON-NLS-1$ + break; + case STEPSIZE_LINE: + print("LINE"); //$NON-NLS-1$ + break; + default: + print("unknown"); //$NON-NLS-1$ + break; + } + println(')'); + } + + private void printVmVersionReply(DataInputStream in) throws IOException { + String description = readString(in); + int jdwpMajor = in.readInt(); + int jdwpMinor = in.readInt(); + String vmVersion = readString(in); + String vmName = readString(in); + + println("VM Description:", description); //$NON-NLS-1$ + println("JDWP Major Version:", jdwpMajor); //$NON-NLS-1$ + println("JDWP Minor Version:", jdwpMinor); //$NON-NLS-1$ + println("VM Version:", vmVersion); //$NON-NLS-1$ + println("VM Name:", vmName); //$NON-NLS-1$ + } + + private void printVmClassesBySignatureCommand(DataInputStream in) + throws IOException { + String signature = readString(in); + println("Class signature:", signature); //$NON-NLS-1$ + } + + private void printVmClassesBySignatureReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int classesCount = in.readInt(); + println("Classes count:", classesCount); //$NON-NLS-1$ + for (int i = 0; i < classesCount; i++) { + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + int status = in.readInt(); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + printClassStatus(status); + } + } + + private void printVmAllClassesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int classesCount = in.readInt(); + println("Classes count:", classesCount); //$NON-NLS-1$ + for (int i = 0; i < classesCount; i++) { + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + String signature = readString(in); + int status = in.readInt(); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + println("Class signature:", signature); //$NON-NLS-1$ + printClassStatus(status); + } + } + + private void printVmAllThreadsReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int threadsCount = in.readInt(); + println("Threads count:", threadsCount); //$NON-NLS-1$ + for (int i = 0; i < threadsCount; i++) { + long threadId = readObjectID(in); + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + } + } + + private void printVmTopLevelThreadGroupReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int groupsCount = in.readInt(); + println("Threads count:", groupsCount); //$NON-NLS-1$ + for (int i = 0; i < groupsCount; i++) { + long threadGroupId = readObjectID(in); + printlnObjectId("Thread id:", threadGroupId); //$NON-NLS-1$ + } + } + + private void printVmIdSizesReply(DataInputStream in) throws IOException { + int fieldIDSize = in.readInt(); + int methodIDSize = in.readInt(); + int objectIDSize = in.readInt(); + int referenceTypeIDSize = in.readInt(); + int frameIDSize = in.readInt(); + println("Field ID size:", fieldIDSize); //$NON-NLS-1$ + println("Method ID size:", methodIDSize); //$NON-NLS-1$ + println("Object ID size:", objectIDSize); //$NON-NLS-1$ + println("Reference type ID size:", referenceTypeIDSize); //$NON-NLS-1$ + println("Frame ID size:", frameIDSize); //$NON-NLS-1$ + TcpipSpy.setFieldIDSize(fieldIDSize); + TcpipSpy.setMethodIDSize(methodIDSize); + TcpipSpy.setObjectIDSize(objectIDSize); + TcpipSpy.setReferenceTypeIDSize(referenceTypeIDSize); + TcpipSpy.setFrameIDSize(frameIDSize); + TcpipSpy.setHasSizes(true); + } + + private void printVmExitCommand(DataInputStream in) throws IOException { + int exitCode = in.readInt(); + println("Exit code:", exitCode); //$NON-NLS-1$ + } + + private void printVmCreateStringCommand(DataInputStream in) + throws IOException { + String string = readString(in); + println("String:", string); //$NON-NLS-1$ + } + + private void printVmCreateStringReply(DataInputStream in) + throws IOException, UnableToParseDataException { + long stringId = readObjectID(in); + printlnObjectId("String id:", stringId); //$NON-NLS-1$ + } + + private void printVmCapabilitiesReply(DataInputStream in) + throws IOException { + boolean canWatchFieldModification = in.readBoolean(); + boolean canWatchFieldAccess = in.readBoolean(); + boolean canGetBytecodes = in.readBoolean(); + boolean canGetSyntheticAttribute = in.readBoolean(); + boolean canGetOwnedMonitorInfo = in.readBoolean(); + boolean canGetCurrentContendedMonitor = in.readBoolean(); + boolean canGetMonitorInfo = in.readBoolean(); + println("Can watch field modification:", canWatchFieldModification); //$NON-NLS-1$ + println("can watch field access:", canWatchFieldAccess); //$NON-NLS-1$ + println("Can get bytecodes:", canGetBytecodes); //$NON-NLS-1$ + println("Can get synthetic attribute:", canGetSyntheticAttribute); //$NON-NLS-1$ + println("Can get owned monitor info:", canGetOwnedMonitorInfo); //$NON-NLS-1$ + println("Can get currently contended monitor:", canGetCurrentContendedMonitor); //$NON-NLS-1$ + println("Can get monitor info:", canGetMonitorInfo); //$NON-NLS-1$ + } + + private void printVmClassPathsReply(DataInputStream in) throws IOException { + String baseDir = readString(in); + println("Base directory:", baseDir); //$NON-NLS-1$ + int classpathCount = in.readInt(); + println("Classpaths count:", classpathCount); //$NON-NLS-1$ + for (int i = 0; i < classpathCount; i++) { + String path = readString(in); + println("Classpath:", path); //$NON-NLS-1$ + } + int bootclasspathCount = in.readInt(); + println("Bootclasspaths count:", bootclasspathCount); //$NON-NLS-1$ + for (int i = 0; i < bootclasspathCount; i++) { + String path = readString(in); + println("Bootclasspath:", path); //$NON-NLS-1$ + } + } + + private void printVmDisposeObjectsCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + int requestsCount = in.readInt(); + println("Requests Count:", requestsCount); //$NON-NLS-1$ + for (int i = 0; i < requestsCount; i++) { + long objectId = readObjectID(in); + int refsCounts = in.readInt(); + printlnObjectId("Object id:", objectId); //$NON-NLS-1$ + println("References count:", refsCounts); //$NON-NLS-1$ + } + } + + private void printVmCapabilitiesNewReply(DataInputStream in) + throws IOException { + printVmCapabilitiesReply(in); + boolean canRedefineClasses = in.readBoolean(); + boolean canAddMethod = in.readBoolean(); + boolean canUnrestrictedlyRedefineClasses = in.readBoolean(); + boolean canPopFrames = in.readBoolean(); + boolean canUseInstanceFilters = in.readBoolean(); + boolean canGetSourceDebugExtension = in.readBoolean(); + boolean canRequestVMDeathEvent = in.readBoolean(); + boolean canSetDefaultStratum = in.readBoolean(); + boolean reserved16 = in.readBoolean(); + boolean reserved17 = in.readBoolean(); + boolean reserved18 = in.readBoolean(); + boolean reserved19 = in.readBoolean(); + boolean reserved20 = in.readBoolean(); + boolean reserved21 = in.readBoolean(); + boolean reserved22 = in.readBoolean(); + boolean reserved23 = in.readBoolean(); + boolean reserved24 = in.readBoolean(); + boolean reserved25 = in.readBoolean(); + boolean reserved26 = in.readBoolean(); + boolean reserved27 = in.readBoolean(); + boolean reserved28 = in.readBoolean(); + boolean reserved29 = in.readBoolean(); + boolean reserved30 = in.readBoolean(); + boolean reserved31 = in.readBoolean(); + boolean reserved32 = in.readBoolean(); + println("Can redefine classes:", canRedefineClasses); //$NON-NLS-1$ + println("Can add method:", canAddMethod); //$NON-NLS-1$ + println("Can unrestrictedly rd. classes:", canUnrestrictedlyRedefineClasses); //$NON-NLS-1$ + println("Can pop frames:", canPopFrames); //$NON-NLS-1$ + println("Can use instance filters:", canUseInstanceFilters); //$NON-NLS-1$ + println("Can get source debug extension:", canGetSourceDebugExtension); //$NON-NLS-1$ + println("Can request VMDeath event:", canRequestVMDeathEvent); //$NON-NLS-1$ + println("Can set default stratum:", canSetDefaultStratum); //$NON-NLS-1$ + println("Reserved:", reserved16); //$NON-NLS-1$ + println("Reserved:", reserved17); //$NON-NLS-1$ + println("Reserved:", reserved18); //$NON-NLS-1$ + println("Reserved:", reserved19); //$NON-NLS-1$ + println("Reserved:", reserved20); //$NON-NLS-1$ + println("Reserved:", reserved21); //$NON-NLS-1$ + println("Reserved:", reserved22); //$NON-NLS-1$ + println("Reserved:", reserved23); //$NON-NLS-1$ + println("Reserved:", reserved24); //$NON-NLS-1$ + println("Reserved:", reserved25); //$NON-NLS-1$ + println("Reserved:", reserved26); //$NON-NLS-1$ + println("Reserved:", reserved27); //$NON-NLS-1$ + println("Reserved:", reserved28); //$NON-NLS-1$ + println("Reserved:", reserved29); //$NON-NLS-1$ + println("Reserved:", reserved30); //$NON-NLS-1$ + println("Reserved:", reserved31); //$NON-NLS-1$ + println("Reserved:", reserved32); //$NON-NLS-1$ + } + + private void printVmRedefineClassCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + int typesCount = in.readInt(); + println("Types count:", typesCount); //$NON-NLS-1$ + for (int i = 0; i < typesCount; i++) { + long typeId = readReferenceTypeID(in); + int classfileLength = in.readInt(); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + println("Classfile length:", classfileLength); //$NON-NLS-1$ + while ((classfileLength -= in.skipBytes(classfileLength)) != 0) { + } + printDescription("Class bytes:"); //$NON-NLS-1$ + println("skipped"); //$NON-NLS-1$ + } + } + + private void printVmSetDefaultStratumCommand(DataInputStream in) + throws IOException { + String stratumId = readString(in); + println("Stratum id:", stratumId); //$NON-NLS-1$ + } + + private void printVmAllClassesWithGenericReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int classesCount = in.readInt(); + println("Classes count:", classesCount); //$NON-NLS-1$ + for (int i = 0; i < classesCount; i++) { + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + String signature = readString(in); + String genericSignature = readString(in); + int status = in.readInt(); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + println("Class signature:", signature); //$NON-NLS-1$ + println("Generic class signature:", genericSignature); //$NON-NLS-1$ + printClassStatus(status); + } + } + + private void printRtDefaultCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long typeId = readReferenceTypeID(in); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + } + + private void printRtSignatureReply(DataInputStream in) throws IOException { + String signature = readString(in); + println("Signature:", signature); //$NON-NLS-1$ + } + + private void printRtClassLoaderReply(DataInputStream in) + throws IOException, UnableToParseDataException { + long classLoaderId = readObjectID(in); + printlnObjectId("ClassLoader id:", classLoaderId); //$NON-NLS-1$ + } + + private void printRtModifiersReply(DataInputStream in) throws IOException { + int modifiers = in.readInt(); + printClassModifiers(modifiers); + } + + private void printRtFieldsReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int fieldsCount = in.readInt(); + println("Fields count:", fieldsCount); //$NON-NLS-1$ + for (int i = 0; i < fieldsCount; i++) { + long fieldId = readFieldID(in); + String name = readString(in); + String signature = readString(in); + int modifiers = in.readInt(); + printlnFieldId("Field id:", fieldId); //$NON-NLS-1$ + println("Name:", name); //$NON-NLS-1$ + println("Signature:", signature); //$NON-NLS-1$ + printFieldModifiers(modifiers); + } + } + + private void printRtMethodsReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int methodsCount = in.readInt(); + println("Methods count:", methodsCount); //$NON-NLS-1$ + for (int i = 0; i < methodsCount; i++) { + long methodId = readMethodID(in); + String name = readString(in); + String signature = readString(in); + int modifiers = in.readInt(); + printlnMethodId("Method id:", methodId); //$NON-NLS-1$ + println("Name:", name); //$NON-NLS-1$ + println("Signature:", signature); //$NON-NLS-1$ + printMethodModifiers(modifiers); + } + } + + private void printRtGetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long typeId = readReferenceTypeID(in); + int fieldsCount = in.readInt(); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + println("Fields count:", fieldsCount); //$NON-NLS-1$ + for (int i = 0; i < fieldsCount; i++) { + long fieldId = readFieldID(in); + printlnFieldId("Field id:", fieldId); //$NON-NLS-1$ + } + } + + private void printRtGetValuesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int valuesCount = in.readInt(); + println("Values count:", valuesCount); //$NON-NLS-1$ + for (int i = 0; i < valuesCount; i++) { + readAndPrintlnTaggedValue("Value:", in); //$NON-NLS-1$ + } + } + + private void printRtSourceFileReply(DataInputStream in) throws IOException { + String sourceFile = readString(in); + println("Source file:", sourceFile); //$NON-NLS-1$ + } + + private void printRtNestedTypesReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int typesCount = in.readInt(); + println("Types count:", typesCount); //$NON-NLS-1$ + for (int i = 0; i < typesCount; i++) { + byte typeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + printRefTypeTag(typeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + } + } + + private void printRtStatusReply(DataInputStream in) throws IOException { + int status = in.readInt(); + printClassStatus(status); + } + + private void printRtInterfacesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int interfacesCount = in.readInt(); + println("Interfaces count:", interfacesCount); //$NON-NLS-1$ + for (int i = 0; i < interfacesCount; i++) { + long interfaceId = readReferenceTypeID(in); + printlnReferenceTypeId("Interface type id:", interfaceId); //$NON-NLS-1$ + } + } + + private void printRtClassObjectReply(DataInputStream in) + throws IOException, UnableToParseDataException { + long classObjectId = readObjectID(in); + printlnObjectId("Class object id:", classObjectId); //$NON-NLS-1$ + } + + private void printRtSourceDebugExtensionReply(DataInputStream in) + throws IOException { + String extension = readString(in); + println("Extension:", extension); //$NON-NLS-1$ + } + + private void printRtSignatureWithGenericReply(DataInputStream in) + throws IOException { + String signature = readString(in); + String genericSignature = readString(in); + println("Signature:", signature); //$NON-NLS-1$ + println("Generic signature:", genericSignature); //$NON-NLS-1$ + } + + private void printRtFieldsWithGenericReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int fieldsCount = in.readInt(); + println("Fields count:", fieldsCount); //$NON-NLS-1$ + for (int i = 0; i < fieldsCount; i++) { + long fieldId = readFieldID(in); + String name = readString(in); + String signature = readString(in); + String genericSignature = readString(in); + int modifiers = in.readInt(); + printlnFieldId("Field id:", fieldId); //$NON-NLS-1$ + println("Name:", name); //$NON-NLS-1$ + println("Signature:", signature); //$NON-NLS-1$ + println("Generic signature:", genericSignature); //$NON-NLS-1$ + printFieldModifiers(modifiers); + } + } + + private void printRtMethodsWithGenericReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int methodsCount = in.readInt(); + println("Methods count:", methodsCount); //$NON-NLS-1$ + for (int i = 0; i < methodsCount; i++) { + long methodId = readMethodID(in); + String name = readString(in); + String genericSignature = readString(in); + int modifiers = in.readInt(); + printlnMethodId("Method id:", methodId); //$NON-NLS-1$ + println("Name:", name); //$NON-NLS-1$ + // println(TcpIpSpyMessages.VerbosePacketStream_Signature__106, + // signature); + println("Generic signature:", genericSignature); //$NON-NLS-1$ + printMethodModifiers(modifiers); + } + } + + private void printCtSuperclassCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long classTypeId = readReferenceTypeID(in); + printlnReferenceTypeId("Class type id:", classTypeId); //$NON-NLS-1$ + } + + private void printCtSuperclassReply(DataInputStream in) throws IOException, + UnableToParseDataException { + long superclassTypeId = readReferenceTypeID(in); + printlnReferenceTypeId("Superclass type id:", superclassTypeId); //$NON-NLS-1$ + } + + private void printCtSetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long classTypeId = readReferenceTypeID(in); + int fieldsCount = in.readInt(); + printlnReferenceTypeId("Class type id:", classTypeId); //$NON-NLS-1$ + println("Fields count:", fieldsCount); //$NON-NLS-1$ + throw new UnableToParseDataException( + "List of values: NOT MANAGED", remainderData(in)); //$NON-NLS-1$ + } + + private void printCtInvokeMethodCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long classTypeId = readReferenceTypeID(in); + long threadId = readObjectID(in); + long methodId = readMethodID(in); + int argumentsCount = in.readInt(); + printlnReferenceTypeId("Class type id:", classTypeId); //$NON-NLS-1$ + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + printlnMethodId("Method id:", methodId); //$NON-NLS-1$ + println("Arguments count:", argumentsCount); //$NON-NLS-1$ + for (int i = 0; i < argumentsCount; i++) { + readAndPrintlnTaggedValue("Argument:", in); //$NON-NLS-1$ + } + int invocationOptions = in.readInt(); + printInvocationOptions(invocationOptions); + } + + private void printCtInvokeMethodReply(DataInputStream in) + throws IOException, UnableToParseDataException { + readAndPrintlnTaggedValue("Return value:", in); //$NON-NLS-1$ + byte signatureByte = in.readByte(); + long exception = readObjectID(in); + printlnTaggedObjectId("Exception object id:", exception, signatureByte); //$NON-NLS-1$ + } + + private void printCtNewInstanceCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + printCtInvokeMethodCommand(in); + } + + private void printCtNewInstanceReply(DataInputStream in) + throws IOException, UnableToParseDataException { + byte objectSignatureByte = in.readByte(); + long newObjectId = readObjectID(in); + byte exceptionSignatureByte = in.readByte(); + long exception = readObjectID(in); + printlnTaggedObjectId( + "New object id:", newObjectId, objectSignatureByte); //$NON-NLS-1$ + printlnTaggedObjectId( + "Exception object id:", exception, exceptionSignatureByte); //$NON-NLS-1$ + } + + private void printAtNewInstanceCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long arrayTypeId = readReferenceTypeID(in); + int length = in.readInt(); + printlnReferenceTypeId("Array type id:", arrayTypeId); //$NON-NLS-1$ + println("Length:", length); //$NON-NLS-1$ + } + + private void printAtNewInstanceReply(DataInputStream in) + throws IOException, UnableToParseDataException { + byte signatureByte = in.readByte(); + long newArrayId = readObjectID(in); + printlnTaggedObjectId("New array id:", newArrayId, signatureByte); //$NON-NLS-1$ + } + + private void printMDefaultCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long classTypeId = readReferenceTypeID(in); + long methodId = readMethodID(in); + printlnReferenceTypeId("Class type id:", classTypeId); //$NON-NLS-1$ + printlnMethodId("Method id:", methodId); //$NON-NLS-1$ + } + + private void printMLineTableReply(DataInputStream in) throws IOException { + long start = in.readLong(); + long end = in.readLong(); + int lines = in.readInt(); + println("Lowest valid code index:", start); //$NON-NLS-1$ + println("Highest valid code index:", end); //$NON-NLS-1$ + println("Number of lines:", lines); //$NON-NLS-1$ + for (int i = 0; i < lines; i++) { + long lineCodeIndex = in.readLong(); + int lineNumber = in.readInt(); + println("Line code Index:", lineCodeIndex); //$NON-NLS-1$ + println("Line number:", lineNumber); //$NON-NLS-1$ + } + } + + private void printMVariableTableReply(DataInputStream in) + throws IOException { + int slotsUsedByArgs = in.readInt(); + int variablesCount = in.readInt(); + println("Nb of slots used by all args:", slotsUsedByArgs); //$NON-NLS-1$ + println("Nb of variables:", variablesCount); //$NON-NLS-1$ + for (int i = 0; i < variablesCount; i++) { + long codeIndex = in.readLong(); + String name = readString(in); + String signature = readString(in); + int length = in.readInt(); + int slotId = in.readInt(); + println("First code index:", codeIndex); //$NON-NLS-1$ + println("Variable name:", name); //$NON-NLS-1$ + println("Variable type signature:", signature); //$NON-NLS-1$ + println("Code index length:", length); //$NON-NLS-1$ + println("Slot id:", slotId); //$NON-NLS-1$ + } + } + + private void printMBytecodesReply(DataInputStream in) throws IOException { + int bytes = in.readInt(); + println("Nb of bytes:", bytes); //$NON-NLS-1$ + while ((bytes -= in.skipBytes(bytes)) != 0) { + } + printDescription("Method bytes:"); //$NON-NLS-1$ + println("skipped"); //$NON-NLS-1$ + } + + private void printMIsObsoleteReply(DataInputStream in) throws IOException { + boolean isObsolete = in.readBoolean(); + println("Is obsolete:", isObsolete); //$NON-NLS-1$ + } + + private void printMVariableTableWithGenericReply(DataInputStream in) + throws IOException { + int slotsUsedByArgs = in.readInt(); + int variablesCount = in.readInt(); + println("Nb of slots used by all args:", slotsUsedByArgs); //$NON-NLS-1$ + println("Nb of variables:", variablesCount); //$NON-NLS-1$ + for (int i = 0; i < variablesCount; i++) { + long codeIndex = in.readLong(); + String name = readString(in); + String signature = readString(in); + String genericSignature = readString(in); + int length = in.readInt(); + int slotId = in.readInt(); + println("First code index:", codeIndex); //$NON-NLS-1$ + println("Variable name:", name); //$NON-NLS-1$ + println("Variable type signature:", signature); //$NON-NLS-1$ + println("Var. type generic signature:", genericSignature); //$NON-NLS-1$ + println("Code index length:", length); //$NON-NLS-1$ + println("Slot id:", slotId); //$NON-NLS-1$ + } + } + + private void printOrDefaultCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long objectId = readObjectID(in); + println("Object id:", objectId); //$NON-NLS-1$ + } + + private void printOrReferenceTypeReply(DataInputStream in) + throws IOException, UnableToParseDataException { + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + } + + private void printOrGetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long objectId = readObjectID(in); + int fieldsCount = in.readInt(); + println("Object id:", objectId); //$NON-NLS-1$ + println("Fields count:", fieldsCount); //$NON-NLS-1$ + for (int i = 0; i < fieldsCount; i++) { + long fieldId = readFieldID(in); + println("Field id:", fieldId); //$NON-NLS-1$ + } + } + + private void printOrGetValuesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int valuesCount = in.readInt(); + println("Values count:", valuesCount); //$NON-NLS-1$ + for (int i = 0; i < valuesCount; i++) { + readAndPrintlnTaggedValue("Value:", in); //$NON-NLS-1$ + } + } + + private void printOrSetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long objectId = readObjectID(in); + int fieldsCount = in.readInt(); + println("Object id:", objectId); //$NON-NLS-1$ + println("Fields count:", fieldsCount); //$NON-NLS-1$ + throw new UnableToParseDataException( + "List of values: NOT MANAGED", remainderData(in)); //$NON-NLS-1$ + } + + private void printOrMonitorInfoReply(DataInputStream in) + throws IOException, UnableToParseDataException { + long ownerThreadId = readObjectID(in); + int entryCount = in.readInt(); + int waiters = in.readInt(); + printlnObjectId("Owner thread id:", ownerThreadId); //$NON-NLS-1$ + println("Entry count:", entryCount); //$NON-NLS-1$ + println("Nb of waiters:", waiters); //$NON-NLS-1$ + long waiterThreadId; + for (int i = 0; i < waiters; i++) { + waiterThreadId = readObjectID(in); + printlnObjectId("Waiting thread id:", waiterThreadId); //$NON-NLS-1$ + } + } + + private void printOrInvokeMethodCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long objectId = readObjectID(in); + long threadId = readObjectID(in); + long classTypeId = readReferenceTypeID(in); + long methodId = readMethodID(in); + int argsCount = in.readInt(); + printlnObjectId("Object id:", objectId); //$NON-NLS-1$ + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + printlnReferenceTypeId("Class type id:", classTypeId); //$NON-NLS-1$ + printlnMethodId("Method id:", methodId); //$NON-NLS-1$ + println("Arguments count:", argsCount); //$NON-NLS-1$ + for (int i = 0; i < argsCount; i++) { + readAndPrintlnTaggedValue("Argument:", in); //$NON-NLS-1$ + } + int invocationOption = in.readInt(); + printInvocationOptions(invocationOption); + } + + private void printOrInvokeMethodReply(DataInputStream in) + throws IOException, UnableToParseDataException { + readAndPrintlnTaggedValue("Return value:", in); //$NON-NLS-1$ + byte signatureByte = in.readByte(); + long exception = readObjectID(in); + printlnTaggedObjectId("Exception object id:", exception, signatureByte); //$NON-NLS-1$ + } + + private void printOrIsCollectedReply(DataInputStream in) throws IOException { + boolean isCollected = in.readBoolean(); + println("Is collected:", isCollected); //$NON-NLS-1$ + } + + private void printSrValueCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long stringObjectId = readObjectID(in); + printlnObjectId("String object id:", stringObjectId); //$NON-NLS-1$ + } + + private void printSrValueReply(DataInputStream in) throws IOException { + String value = readString(in); + println("Value:", value); //$NON-NLS-1$ + } + + private void printTrDefaultCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long threadId = readObjectID(in); + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + } + + private void printTrNameReply(DataInputStream in) throws IOException { + String threadName = readString(in); + println("Name:", threadName); //$NON-NLS-1$ + } + + private void printTrStatusReply(DataInputStream in) throws IOException { + int threadStatus = in.readInt(); + int suspendStatus = in.readInt(); + printThreadStatus(threadStatus); + printSuspendStatus(suspendStatus); + } + + private void printTrThreadGroupReply(DataInputStream in) + throws IOException, UnableToParseDataException { + long threadGroupId = readObjectID(in); + printlnObjectId("Thread group id:", threadGroupId); //$NON-NLS-1$ + } + + private void printTrFramesCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long threadId = readObjectID(in); + int startFrame = in.readInt(); + int length = in.readInt(); + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + println("First frame:", startFrame); //$NON-NLS-1$ + println("Number of frame:", length); //$NON-NLS-1$ + } + + private void printTrFramesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int framesCount = in.readInt(); + println("Frames count:", framesCount); //$NON-NLS-1$ + for (int i = 0; i < framesCount; i++) { + long frameId = readFrameID(in); + printlnFrameId("Frame id:", frameId); //$NON-NLS-1$ + readAndPrintLocation(in); + } + } + + private void printTrFrameCountReply(DataInputStream in) throws IOException { + int framesCount = in.readInt(); + println("Frames count:", framesCount); //$NON-NLS-1$ + } + + private void printTrOwnedMonitorsReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int monitorsCount = in.readInt(); + println("Monitors count:", monitorsCount); //$NON-NLS-1$ + for (int i = 0; i < monitorsCount; i++) { + byte signatureByte = in.readByte(); + long monitorObjectId = readObjectID(in); + printlnTaggedObjectId( + "Monitor object id:", monitorObjectId, signatureByte); //$NON-NLS-1$ + } + } + + private void printTrCurrentContendedMonitorReply(DataInputStream in) + throws IOException, UnableToParseDataException { + byte signatureByte = in.readByte(); + long monitorObjectId = readObjectID(in); + printlnTaggedObjectId( + "Monitor object id:", monitorObjectId, signatureByte); //$NON-NLS-1$ + } + + private void printTrStopCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long threadId = readObjectID(in); + long exceptionObjectId = readObjectID(in); + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + printlnObjectId("Exception object id:", exceptionObjectId); //$NON-NLS-1$ + } + + private void printTrSuspendCountReply(DataInputStream in) + throws IOException { + int suspendCount = in.readInt(); + println("Suspend count:", suspendCount); //$NON-NLS-1$ + } + + private void printTgrDefaultCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long threadGroupId = readObjectID(in); + printlnObjectId("Thread group id:", threadGroupId); //$NON-NLS-1$ + } + + private void printTgrNameReply(DataInputStream in) throws IOException { + String name = readString(in); + println("Name:", name); //$NON-NLS-1$ + } + + private void printTgrParentReply(DataInputStream in) throws IOException, + UnableToParseDataException { + long parentThreadGroupId = readObjectID(in); + printlnObjectId("Parent thread group id:", parentThreadGroupId); //$NON-NLS-1$ + } + + private void printTgrChildrenReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int childThreadsCount = in.readInt(); + println("Child threads count:", childThreadsCount); //$NON-NLS-1$ + for (int i = 0; i < childThreadsCount; i++) { + long childThreadId = readObjectID(in); + printlnObjectId("Child thread id:", childThreadId); //$NON-NLS-1$ + } + int childGroupThreadsCount = in.readInt(); + println("Child group threads count:", childGroupThreadsCount); //$NON-NLS-1$ + for (int i = 0; i < childGroupThreadsCount; i++) { + long childGroupThreadId = readObjectID(in); + printlnObjectId("Child group thread id:", childGroupThreadId); //$NON-NLS-1$ + } + } + + private void printArLengthCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long arrayObjectId = readObjectID(in); + printlnObjectId("Array object id:", arrayObjectId); //$NON-NLS-1$ + } + + private void printArLengthReply(DataInputStream in) throws IOException { + int length = in.readInt(); + println("Length:", length); //$NON-NLS-1$ + } + + private void printArGetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long arrayObjectId = readObjectID(in); + int firstIndex = in.readInt(); + int length = in.readInt(); + printlnObjectId("Array object id:", arrayObjectId); //$NON-NLS-1$ + println("First index:", firstIndex); //$NON-NLS-1$ + println("Length:", length); //$NON-NLS-1$ + } + + private void printArGetValuesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + readAndPrintArrayRegion(in); + } + + private void printArSetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long arrayObjectId = readObjectID(in); + int firstIndex = in.readInt(); + int length = in.readInt(); + printlnObjectId("Array object id:", arrayObjectId); //$NON-NLS-1$ + println("First index:", firstIndex); //$NON-NLS-1$ + println("Length:", length); //$NON-NLS-1$ + throw new UnableToParseDataException( + "List of values: NOT MANAGED", remainderData(in)); //$NON-NLS-1$ + } + + private void printClrVisibleClassesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long classLoaderObjectId = readObjectID(in); + printlnObjectId("Class loader object id:", classLoaderObjectId); //$NON-NLS-1$ + } + + private void printClrVisibleClassesReply(DataInputStream in) + throws IOException, UnableToParseDataException { + int classesCount = in.readInt(); + println("Classes count:", classesCount); //$NON-NLS-1$ + for (int i = 0; i < classesCount; i++) { + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + } + } + + private void printErSetCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + byte eventKind = in.readByte(); + byte suspendPolicy = in.readByte(); + int modifiersCount = in.readInt(); + printEventKind(eventKind); + printSuspendPolicy(suspendPolicy); + println("Modifiers count:", modifiersCount); //$NON-NLS-1$ + for (int i = 0; i < modifiersCount; i++) { + byte modKind = in.readByte(); + printDescription("Modifier kind:"); //$NON-NLS-1$ + printHex(modKind); + switch (modKind) { + case 1: // count + println(" (Count)"); //$NON-NLS-1$ + int count = in.readInt(); + println("Count:", count); //$NON-NLS-1$ + break; + case 2: // conditional + println(" (Conditional)"); //$NON-NLS-1$ + int exprId = in.readInt(); + println("Expression id:", exprId); //$NON-NLS-1$ + break; + case 3: // thread only + println(" (ThreadOnly)"); //$NON-NLS-1$ + long threadId = readObjectID(in); + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + break; + case 4: // class only + println(" (ClassOnly)"); //$NON-NLS-1$ + long classId = readReferenceTypeID(in); + printlnReferenceTypeId("Class type id:", classId); //$NON-NLS-1$ + break; + case 5: // class match + println(" (ClassMatch)"); //$NON-NLS-1$ + String classPatern = readString(in); + println("Class pattern:", classPatern); //$NON-NLS-1$ + break; + case 6: // class exclude + println(" (ClassExclude)"); //$NON-NLS-1$ + classPatern = readString(in); + println("Class pattern:", classPatern); //$NON-NLS-1$ + break; + case 7: // location only + println(" (LocationOnly)"); //$NON-NLS-1$ + readAndPrintLocation(in); + break; + case 8: // exception only + println(" (ExceptionOnly)"); //$NON-NLS-1$ + long typeId = readReferenceTypeID(in); + boolean caught = in.readBoolean(); + boolean uncaught = in.readBoolean(); + printlnReferenceTypeId("Exception type id:", typeId); //$NON-NLS-1$ + println("Caught:", caught); //$NON-NLS-1$ + println("Uncaught:", uncaught); //$NON-NLS-1$ + break; + case 9: // field only + println(" (FieldOnly)"); //$NON-NLS-1$ + long declaringTypeId = readReferenceTypeID(in); + long fieldId = readFieldID(in); + printlnReferenceTypeId("Declaring type id:", declaringTypeId); //$NON-NLS-1$ + printlnFieldId("Field id:", fieldId); //$NON-NLS-1$ + break; + case 10: // step + println(" (Step)"); //$NON-NLS-1$ + threadId = readObjectID(in); + int stepSize = in.readInt(); + int stepDepth = in.readInt(); + printlnObjectId("Thread id:", threadId); //$NON-NLS-1$ + printStepSize(stepSize); + printStepDepth(stepDepth); + break; + case 11: // instance only + println(" (InstanceOnly)"); //$NON-NLS-1$ + long objectId = readObjectID(in); + printlnObjectId("Object id:", objectId); //$NON-NLS-1$ + break; + } + } + } + + private void printErSetReply(DataInputStream in) throws IOException { + int requestId = in.readInt(); + println("Request id:", requestId); //$NON-NLS-1$ + } + + private void printErClearCommand(DataInputStream in) throws IOException { + byte eventKind = in.readByte(); + int requestId = in.readInt(); + printEventKind(eventKind); + println("Request id:", requestId); //$NON-NLS-1$ + } + + private void printSfDefaultCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + long threadId = readObjectID(in); + long frameId = readFrameID(in); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + printlnFrameId("Frame id:", frameId); //$NON-NLS-1$ + } + + private void printSfGetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long threadId = readObjectID(in); + long frameId = readFrameID(in); + int slotsCount = in.readInt(); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + printlnFrameId("Frame id:", frameId); //$NON-NLS-1$ + println("Slots count:", slotsCount); //$NON-NLS-1$ + for (int i = 0; i < slotsCount; i++) { + int slotIndex = in.readInt(); + byte signatureTag = in.readByte(); + println("Slot index:", slotIndex); //$NON-NLS-1$ + printDescription("Signature tag:"); //$NON-NLS-1$ + printSignatureByte(signatureTag, true); + println(); + } + } + + private void printSfGetValuesReply(DataInputStream in) throws IOException, + UnableToParseDataException { + int valuesCount = in.readInt(); + println("Values count:", valuesCount); //$NON-NLS-1$ + for (int i = 0; i < valuesCount; i++) { + readAndPrintlnTaggedValue("Value:", in); //$NON-NLS-1$ + } + } + + private void printSfSetValuesCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long threadId = readObjectID(in); + long frameId = readFrameID(in); + int slotsCount = in.readInt(); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + printlnFrameId("Frame id:", frameId); //$NON-NLS-1$ + println("Slots count:", slotsCount); //$NON-NLS-1$ + for (int i = 0; i < slotsCount; i++) { + int slotIndex = in.readInt(); + println("Slot index:", slotIndex); //$NON-NLS-1$ + readAndPrintlnTaggedValue("Values:", in); //$NON-NLS-1$ + } + } + + private void printSfThisObjectReply(DataInputStream in) throws IOException, + UnableToParseDataException { + byte signatureByte = in.readByte(); + long objectId = readObjectID(in); + printlnTaggedObjectId("'this' object id:", objectId, signatureByte); //$NON-NLS-1$ + } + + private void printCorReflectedTypeCommand(DataInputStream in) + throws IOException, UnableToParseDataException { + long classObjectId = readObjectID(in); + printlnObjectId("Class object id:", classObjectId); //$NON-NLS-1$ + } + + private void printCorReflectedTypeReply(DataInputStream in) + throws IOException, UnableToParseDataException { + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + } + + private void printECompositeCommand(DataInputStream in) throws IOException, + UnableToParseDataException { + byte suspendPolicy = in.readByte(); + int eventsCount = in.readInt(); + printSuspendPolicy(suspendPolicy); + println("Events count:", eventsCount); //$NON-NLS-1$ + for (int i = 0; i < eventsCount; i++) { + byte eventKind = in.readByte(); + int requestId = in.readInt(); + printEventKind(eventKind); + println("Request id:", requestId); //$NON-NLS-1$ + switch (eventKind) { + case EVENTKIND_VM_START: + long threadId = readObjectID(in); + printlnObjectId("Initial thread object id:", threadId); //$NON-NLS-1$ + break; + case EVENTKIND_SINGLE_STEP: + case EVENTKIND_BREAKPOINT: + case EVENTKIND_METHOD_ENTRY: + case EVENTKIND_METHOD_EXIT: + threadId = readObjectID(in); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + readAndPrintLocation(in); + break; + case EVENTKIND_EXCEPTION: + threadId = readObjectID(in); + readAndPrintLocation(in); + byte signatureByte = in.readByte(); + long objectId = readObjectID(in); + printlnTaggedObjectId( + "Exception object id:", objectId, signatureByte); //$NON-NLS-1$ + readAndPrintLocation(in); + break; + case EVENTKIND_THREAD_START: + case EVENTKIND_THREAD_DEATH: + threadId = readObjectID(in); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + break; + case EVENTKIND_CLASS_PREPARE: + threadId = readObjectID(in); + byte refTypeTag = in.readByte(); + long typeId = readReferenceTypeID(in); + String typeSignature = readString(in); + int status = in.readInt(); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + println("Type signature:", typeSignature); //$NON-NLS-1$ + println("Status:", status); //$NON-NLS-1$ + break; + case EVENTKIND_CLASS_UNLOAD: + typeSignature = readString(in); + println("Type signature:", typeSignature); //$NON-NLS-1$ + break; + case EVENTKIND_FIELD_ACCESS: + threadId = readObjectID(in); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + readAndPrintLocation(in); + refTypeTag = in.readByte(); + typeId = readReferenceTypeID(in); + long fieldId = readFieldID(in); + signatureByte = in.readByte(); + objectId = readObjectID(in); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + printlnFieldId("Field id:", fieldId); //$NON-NLS-1$ + printlnTaggedObjectId("Object id:", objectId, signatureByte); //$NON-NLS-1$ + break; + case EVENTKIND_FIELD_MODIFICATION: + threadId = readObjectID(in); + printlnObjectId("Thread object id:", threadId); //$NON-NLS-1$ + readAndPrintLocation(in); + refTypeTag = in.readByte(); + typeId = readReferenceTypeID(in); + fieldId = readFieldID(in); + signatureByte = in.readByte(); + objectId = readObjectID(in); + printRefTypeTag(refTypeTag); + printlnReferenceTypeId("Type id:", typeId); //$NON-NLS-1$ + printlnFieldId("Field id:", fieldId); //$NON-NLS-1$ + printlnTaggedObjectId("Object id:", objectId, signatureByte); //$NON-NLS-1$ + readAndPrintlnTaggedValue("Value:", in); //$NON-NLS-1$ + break; + case EVENTKIND_VM_DEATH: + break; + } + } + } + + /** + * Reads String from Jdwp stream. Read a UTF where length has 4 bytes, and + * not just 2. This code was based on the OTI Retysin source for readUTF. + */ + private static String readString(DataInputStream in) throws IOException { + int utfSize = in.readInt(); + byte utfBytes[] = new byte[utfSize]; + in.readFully(utfBytes); + /* Guess at buffer size */ + StringBuilder strBuffer = new StringBuilder(utfSize / 3 * 2); + for (int i = 0; i < utfSize;) { + int a = utfBytes[i] & 0xFF; + if ((a >> 4) < 12) { + strBuffer.append((char) a); + i++; + } else { + int b = utfBytes[i + 1] & 0xFF; + if ((a >> 4) < 14) { + if ((b & 0xBF) == 0) { + throw new UTFDataFormatException( + "Second byte input does not match UTF Specification"); //$NON-NLS-1$ + } + strBuffer.append((char) (((a & 0x1F) << 6) | (b & 0x3F))); + i += 2; + } else { + int c = utfBytes[i + 2] & 0xFF; + if ((a & 0xEF) > 0) { + if (((b & 0xBF) == 0) || ((c & 0xBF) == 0)) { + throw new UTFDataFormatException( + "Second or third byte input does not mach UTF Specification_"); //$NON-NLS-1$ + } + strBuffer.append((char) (((a & 0x0F) << 12) + | ((b & 0x3F) << 6) | (c & 0x3F))); + i += 3; + } else { + throw new UTFDataFormatException( + "Input does not match UTF Specification"); //$NON-NLS-1$ + } + } + } + } + return strBuffer.toString(); + } + + private byte[] remainderData(DataInputStream in) throws IOException { + byte[] buffer = new byte[100]; + byte[] res = new byte[0], newRes; + int resLength = 0, length; + while ((length = in.read(buffer)) != -1) { + newRes = new byte[resLength + length]; + System.arraycopy(res, 0, newRes, 0, resLength); + System.arraycopy(buffer, 0, newRes, resLength, length); + res = newRes; + resLength += length; + } + return res; + } + + private long readObjectID(DataInputStream in) throws IOException, + UnableToParseDataException { + if (!TcpipSpy.hasSizes()) { + throw new UnableToParseDataException( + "Unable to parse remaining data", remainderData(in)); //$NON-NLS-1$ + } + return readID(in, TcpipSpy.getObjectIDSize()); + } + + private long readReferenceTypeID(DataInputStream in) throws IOException, + UnableToParseDataException { + if (!TcpipSpy.hasSizes()) { + throw new UnableToParseDataException( + "Unable to parse remaining data", remainderData(in)); //$NON-NLS-1$ + } + return readID(in, TcpipSpy.getReferenceTypeIDSize()); + } + + private long readFieldID(DataInputStream in) throws IOException, + UnableToParseDataException { + if (!TcpipSpy.hasSizes()) { + throw new UnableToParseDataException( + "Unable to parse remaining data", remainderData(in)); //$NON-NLS-1$ + } + return readID(in, TcpipSpy.getFieldIDSize()); + } + + private long readMethodID(DataInputStream in) throws IOException, + UnableToParseDataException { + if (!TcpipSpy.hasSizes()) { + throw new UnableToParseDataException( + "Unable to parse remaining data", remainderData(in)); //$NON-NLS-1$ + } + return readID(in, TcpipSpy.getMethodIDSize()); + } + + private long readFrameID(DataInputStream in) throws IOException, + UnableToParseDataException { + if (!TcpipSpy.hasSizes()) { + throw new UnableToParseDataException( + "Unable to parse remaining data", remainderData(in)); //$NON-NLS-1$ + } + return readID(in, TcpipSpy.getFrameIDSize()); + } + + private long readID(DataInputStream in, int size) throws IOException { + long id = 0; + for (int i = 0; i < size; i++) { + int b = in.readUnsignedByte(); // Note that the byte must be treated + // as unsigned. + id = id << 8 | b; + } + return id; + } + + private void readAndPrintlnTaggedValue(String description, + DataInputStream in) throws IOException, UnableToParseDataException { + byte tag = in.readByte(); + readAndPrintlnUntaggedValue(description, in, tag, true); + } + + private void readAndPrintlnUntaggedValue(String description, + DataInputStream in, byte tag, boolean printTagValue) + throws IOException, UnableToParseDataException { + printDescription(description); + int size; + boolean isId = false; + switch (tag) { + case VOID_TAG: + printSignatureByte(tag, printTagValue); + println(); + return; + case BOOLEAN_TAG: + if (printTagValue) { + printSignatureByte(tag, true); + print(' '); + println(in.readBoolean()); + } else { + println(in.readBoolean()); + print(' '); + printSignatureByte(tag, false); + } + return; + case BYTE_TAG: + size = 1; + break; + case CHAR_TAG: + case SHORT_TAG: + size = 2; + break; + case INT_TAG: + case FLOAT_TAG: + size = 4; + break; + case DOUBLE_TAG: + case LONG_TAG: + size = 8; + break; + case ARRAY_TAG: + case OBJECT_TAG: + case STRING_TAG: + case THREAD_TAG: + case THREAD_GROUP_TAG: + case CLASS_LOADER_TAG: + case CLASS_OBJECT_TAG: + if (!TcpipSpy.hasSizes()) { + throw new UnableToParseDataException( + "Unable to parse remaining data", remainderData(in)); //$NON-NLS-1$ + } + size = TcpipSpy.getObjectIDSize(); + isId = true; + break; + default: + size = 0; + break; + } + + long value = readID(in, size); + if (printTagValue) { + printSignatureByte(tag, true); + print(' '); + } + printHex(value, size); + if (isId) { + printParanthetical(value); + } else { + switch (tag) { + case BYTE_TAG: + printParanthetical((byte) value); + break; + case CHAR_TAG: + printParanthetical((char) value); + break; + case SHORT_TAG: + printParanthetical((short) value); + break; + case INT_TAG: + printParanthetical((int) value); + break; + case FLOAT_TAG: + printParanthetical(Float.intBitsToFloat((int) value)); + break; + case DOUBLE_TAG: + printParanthetical(Double.longBitsToDouble(value)); + break; + case LONG_TAG: + printParanthetical(value); + break; + } + } + if (!printTagValue) { + print(' '); + printSignatureByte(tag, false); + } + println(); + } + + private void printSignatureByte(byte signatureByte, boolean printValue) { + String type; + switch (signatureByte) { + case VOID_TAG: + type = "void"; //$NON-NLS-1$ + break; + case BOOLEAN_TAG: + type = "boolean"; //$NON-NLS-1$ + break; + case BYTE_TAG: + type = "byte"; //$NON-NLS-1$ + break; + case CHAR_TAG: + type = "char"; //$NON-NLS-1$ + break; + case SHORT_TAG: + type = "short"; //$NON-NLS-1$ + break; + case INT_TAG: + type = "int"; //$NON-NLS-1$ + break; + case FLOAT_TAG: + type = "float"; //$NON-NLS-1$ + break; + case DOUBLE_TAG: + type = "double"; //$NON-NLS-1$ + break; + case LONG_TAG: + type = "long"; //$NON-NLS-1$ + break; + case ARRAY_TAG: + type = "array id"; //$NON-NLS-1$ + break; + case OBJECT_TAG: + type = "object id"; //$NON-NLS-1$ + break; + case STRING_TAG: + type = "string id"; //$NON-NLS-1$ + break; + case THREAD_TAG: + type = "thread id"; //$NON-NLS-1$ + break; + case THREAD_GROUP_TAG: + type = "thread group id"; //$NON-NLS-1$ + break; + case CLASS_LOADER_TAG: + type = "class loader id"; //$NON-NLS-1$ + break; + case CLASS_OBJECT_TAG: + type = "class object id"; //$NON-NLS-1$ + break; + default: + type = "unknown"; //$NON-NLS-1$ + break; + } + if (printValue) { + printHex(signatureByte); + print(" ("); //$NON-NLS-1$ + print(signatureByte); + print(" - "); //$NON-NLS-1$ + } else { + print(" ("); //$NON-NLS-1$ + } + print(type + ')'); + } + + private void readAndPrintLocation(DataInputStream in) throws IOException, + UnableToParseDataException { + byte typeTag = in.readByte(); + long classId = readReferenceTypeID(in); + long methodId = readMethodID(in); + long index = in.readLong(); + printlnReferenceTypeIdWithTypeTag( + "Location: class id:", classId, typeTag); //$NON-NLS-1$ + printlnMethodId(" method id:", methodId); //$NON-NLS-1$ + println(" index:", index); //$NON-NLS-1$ + } + + private void readAndPrintArrayRegion(DataInputStream in) + throws IOException, UnableToParseDataException { + byte signatureByte = in.readByte(); + int valuesCount = in.readInt(); + printDescription("Signature byte:"); //$NON-NLS-1$ + printSignatureByte(signatureByte, true); + println(); + println("Values count:", valuesCount); //$NON-NLS-1$ + switch (signatureByte) { + case ARRAY_TAG: + case OBJECT_TAG: + case STRING_TAG: + case THREAD_TAG: + case THREAD_GROUP_TAG: + case CLASS_LOADER_TAG: + case CLASS_OBJECT_TAG: + for (int i = 0; i < valuesCount; i++) { + readAndPrintlnTaggedValue("Value", in); //$NON-NLS-1$ + } + break; + default: + for (int i = 0; i < valuesCount; i++) { + readAndPrintlnUntaggedValue("Value", in, signatureByte, false); //$NON-NLS-1$ + } + break; + } + } + + protected void println(String description, int value) { + printDescription(description); + printHex(value); + printParanthetical(value); + println(); + } + + protected void println(String description, long value) { + printDescription(description); + printHex(value); + printParanthetical(value); + println(); + } + + protected void println(String description, String value) { + printDescription(description); + print('\"'); + StringBuilder val = new StringBuilder(); + int pos = 0, lastPos = 0; + while ((pos = value.indexOf('\n', lastPos)) != -1) { + pos++; + val.append(value.substring(lastPos, pos)); + val.append(shift); + lastPos = pos; + } + val.append(value.substring(lastPos, value.length())); + print(val); + println('"'); + } + + protected void println(String description, boolean value) { + printDescription(description); + println(value); + } + + protected void printlnReferenceTypeId(String description, long value) { + println(description, value, TcpipSpy.getReferenceTypeIDSize()); + } + + protected void printlnReferenceTypeIdWithTypeTag(String description, + long value, byte typeTag) { + printDescription(description); + printRefTypeTagValue(typeTag); + print(" - "); //$NON-NLS-1$ + printHex(value, TcpipSpy.getReferenceTypeIDSize()); + printParanthetical(value); + println(); + } + + protected void printlnObjectId(String description, long value) { + printDescription(description); + printHex(value, TcpipSpy.getObjectIDSize()); + if (value == 0) { + println(" (NULL)"); //$NON-NLS-1$ + } else { + printParanthetical(value); + println(); + } + } + + protected void printlnTaggedObjectId(String description, long value, + byte signatureByte) { + printDescription(description); + printSignatureByte(signatureByte, true); + print(' '); + printHex(value, TcpipSpy.getReferenceTypeIDSize()); + if (value == 0) { + println(" (NULL)"); //$NON-NLS-1$ + } else { + printParanthetical(value); + println(); + } + } + + protected void printlnFieldId(String description, long value) { + println(description, value, TcpipSpy.getFieldIDSize()); + } + + protected void printlnMethodId(String description, long value) { + println(description, value, TcpipSpy.getMethodIDSize()); + } + + protected void printlnFrameId(String description, long value) { + println(description, value, TcpipSpy.getFrameIDSize()); + } + + protected void println(String description, long value, int size) { + printDescription(description); + printHex(value, size); + printParanthetical(value); + println(); + } + + protected void printDescription(String description) { + // current max length = 36 (+2 pad) + int width = 38 - description.length(); + print(description); + write(padding, 0, width); + } + + protected void printHexString(String hex, int width) { + width -= hex.length(); + print("0x"); //$NON-NLS-1$ + write(zeros, 0, width); + print(hex); + } + + protected void printHex(long l, int byteNumber) { + printHexString(Long.toHexString(l).toUpperCase(), byteNumber * 2); + } + + protected void printHex(byte b) { + printHexString(Integer.toHexString(b & 0xFF).toUpperCase(), 2); + } + + protected void printHex(int i) { + printHexString(Integer.toHexString(i).toUpperCase(), 8); + } + + protected void printHex(long l) { + printHexString(Long.toHexString(l).toUpperCase(), 16); + } + + protected void printHex(byte[] b) { + if (b == null) { + println("NULL"); //$NON-NLS-1$ + return; + } + int i, length; + for (i = 0, length = b.length; i < length; i++) { + String hexa = Integer.toHexString(b[i]).toUpperCase(); + if (hexa.length() == 1) { + print('0'); + } + print(hexa); + if ((i % 32) == 0 && i != 0) { + println(); + print(shift); + } else { + print(' '); + } + } + println(); + } + + protected void printParanthetical(byte i) { + print(" ("); //$NON-NLS-1$ + print(i); + print(')'); + } + + protected void printParanthetical(char i) { + print(" ("); //$NON-NLS-1$ + print(i); + print(')'); + } + + protected void printParanthetical(short i) { + print(" ("); //$NON-NLS-1$ + print(i); + print(')'); + } + + protected void printParanthetical(int i) { + print(" ("); //$NON-NLS-1$ + print(i); + print(')'); + } + + protected void printParanthetical(long l) { + print(" ("); //$NON-NLS-1$ + print(l); + print(')'); + } + + protected void printParanthetical(float f) { + print(" ("); //$NON-NLS-1$ + print(f); + print(')'); + } + + protected void printParanthetical(double d) { + print(" ("); //$NON-NLS-1$ + print(d); + print(')'); + } + + protected void printParanthetical(String s) { + print(" ("); //$NON-NLS-1$ + print(s); + print(')'); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IEvaluationRunnable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IEvaluationRunnable.java new file mode 100644 index 0000000000..697ed0ed41 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IEvaluationRunnable.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; + +/** + * A runnable that represents one logical evaluation to be run in a target + * thread. + *

      + * Clients are intended to implement this interface. + *

      + * + * @see org.eclipse.jdt.debug.core.IJavaThread#runEvaluation(IEvaluationRunnable, + * IProgressMonitor, int, boolean) + * @since 2.0 + */ +public interface IEvaluationRunnable { + + /** + * Runs this evaluation in the specified thread, reporting progress to the + * given progress monitor. + * + * @param thread + * the thread in which to run the evaluation + * @param monitor + * progress monitor (may be null) + * @exception DebugException + * if an exception occurs during the evaluation + */ + public abstract void run(IJavaThread thread, IProgressMonitor monitor) + throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaArray.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaArray.java new file mode 100644 index 0000000000..ffb2618338 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaArray.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IIndexedValue; + +/** + * A value referencing an array on a target VM. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface IJavaArray extends IJavaObject, IIndexedValue { + + /** + * Returns the values contained in this array. + * + * @return the values contained in this array + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public IJavaValue[] getValues() throws DebugException; + + /** + * Returns the value at the given index in this array. + * + * @param index + * the index of the value to return + * @return the value at the given index + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @exception java.lang.IndexOutOfBoundsException + * if the index is not within the bounds of this array. + */ + public IJavaValue getValue(int index) throws DebugException; + + /** + * Returns the length of this array. + * + * @return the length of this array + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + */ + public int getLength() throws DebugException; + + /** + * Sets the value at the given index to the specified value. + * + * @param index + * the index at which to assign a new value + * @param value + * the new value + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • The given value is not compatible with the type of + * this array
      • + *
      + * @exception java.lang.IndexOutOfBoundsException + * if the index is not within the bounds of this array. + */ + public void setValue(int index, IJavaValue value) throws DebugException; + + /** + * Replaces values in this array. If the given replacement values length is + * less that the length of this array, only the number of values in the + * given array are replaced. If the given replacement values length is + * longer than the length of this array, values in positions greater than + * the length of this array are ignored. + * + * @param values + * replacement values + * @exception DebugException + * if an exception occurs replacing values + * @since 3.4 + */ + public void setValues(IJavaValue[] values) throws DebugException; + + /** + * Replaces a range of values in this array. + * + * @param offset + * offset in this array to start replacing values at + * @param length + * the number of values to replace in this array + * @param values + * replacement values + * @param startOffset + * the first offset where values are copied from the given + * replacement values + * @exception DebugException + * if an exception occurs replacing values or if the given + * offsets and length are not within the range of this array + * or the replacement values + * @since 3.4 + */ + public void setValues(int offset, int length, IJavaValue[] values, + int startOffset) throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaArrayType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaArrayType.java new file mode 100644 index 0000000000..ab3df57589 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaArrayType.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * The type of an array on a Java debug target. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface IJavaArrayType extends IJavaReferenceType { + + /** + * Returns a new instance of an array of this type, with the specified + * length. + * + * @param size + * the length of the new array + * @return a new array of the specified length + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public IJavaArray newInstance(int size) throws DebugException; + + /** + * Returns the type of the elements in this array. + * + * @return type + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The exception's + * status code contains the underlying exception responsible + * for the failure.
      • + *
      + */ + public IJavaType getComponentType() throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java new file mode 100644 index 0000000000..1d3131a913 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpoint.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.ITriggerPoint; + +/** + * A breakpoint specific to the Java debug model. A Java breakpoint supports: + *
        + *
      • a hit count
      • + *
      • a suspend policy that determines if the entire VM or a single thread is + * suspended when hit
      • + *
      • a thread filter to restrict a breakpoint to a specific thread within a VM + *
      • + *
      • an installed property that indicates a breakpoint was successfully + * installed in a VM
      • + *
      + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaBreakpoint extends IBreakpoint, ITriggerPoint { + + /** + * Suspend policy constant indicating a breakpoint will suspend the target + * VM when hit. + */ + public static final int SUSPEND_VM = 1; + + /** + * Default suspend policy constant indicating a breakpoint will suspend only + * the thread in which it occurred. + */ + public static final int SUSPEND_THREAD = 2; + + /** + * Returns whether this breakpoint is installed in at least one debug + * target. + * + * @return whether this breakpoint is installed + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + */ + public boolean isInstalled() throws CoreException; + + /** + * Returns the fully qualified name of the type this breakpoint is located + * in, or null if this breakpoint is not located in a specific + * type - for example, a pattern breakpoint. + * + * @return the fully qualified name of the type this breakpoint is located + * in, or null + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getTypeName() throws CoreException; + + /** + * Returns this breakpoint's hit count or, -1 if this breakpoint does not + * have a hit count. + * + * @return this breakpoint's hit count, or -1 + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public int getHitCount() throws CoreException; + + /** + * Sets the hit count attribute of this breakpoint. If this breakpoint is + * currently disabled and the hit count is set greater than -1, this + * breakpoint is automatically enabled. + * + * @param count + * the new hit count + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setHitCount(int count) throws CoreException; + + /** + * Sets whether all threads in the target VM will be suspended when this + * breakpoint is hit. When SUSPEND_VM the target VM is + * suspended, and when SUSPEND_THREAD only the thread in which + * this breakpoint occurred is suspended. + * + * @param suspendPolicy + * one of SUSPEND_VM or SUSPEND_THREAD + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setSuspendPolicy(int suspendPolicy) throws CoreException; + + /** + * Returns the suspend policy used by this breakpoint, one of + * SUSPEND_VM or SUSPEND_THREAD. + * + * @return one of SUSPEND_VM or SUSPEND_THREAD + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public int getSuspendPolicy() throws CoreException; + + /** + * Restricts this breakpoint to suspend only in the given thread when + * encountered in the given thread's target. A breakpoint can only be + * restricted to one thread per target. Any previous thread filter for the + * same target is lost. A thread filter is not persisted across workbench + * invocations. + * + * @param thread + * the thread to add the filter to + * + * @exception CoreException + * if unable to set the thread filter + */ + public void setThreadFilter(IJavaThread thread) throws CoreException; + + /** + * Removes this breakpoint's thread filter in the given target, if any. Has + * no effect if this breakpoint does not have a filter in the given target. + * + * @param target + * the target whose thread filter will be removed + * @exception CoreException + * if unable to remove the thread filter + */ + public void removeThreadFilter(IJavaDebugTarget target) + throws CoreException; + + /** + * Returns the thread in the given target in which this breakpoint is + * enabled or null if this breakpoint is enabled in all threads + * in the given target. + * + * @param target + * the debug target + * + * @return the thread in the given target that this breakpoint is enabled + * for + * @exception CoreException + * if unable to determine this breakpoint's thread filter + */ + public IJavaThread getThreadFilter(IJavaDebugTarget target) + throws CoreException; + + /** + * Returns all thread filters set on this breakpoint. + * + * @return the threads that this breakpoint is restricted to + * @exception CoreException + * if unable to determine this breakpoint's thread filters + */ + public IJavaThread[] getThreadFilters() throws CoreException; + + /** + * Adds the given object to the list of objects in which this breakpoint is + * restricted to suspend execution. Has no effect if the object has already + * been added. Note that clients should first ensure that a breakpoint + * supports instance filters. + *

      + * Note: This implementation will add more than one filter. However, if + * there is more than one instance filter for a debug target, the breakpoint + * will never be hit in that target, as the current context cannot be two + * different instances at the same time. + *

      + * + * @param object + * instance filter to add + * @exception CoreException + * if unable to add the given instance filter + * @since 2.1 + */ + public void addInstanceFilter(IJavaObject object) throws CoreException; + + /** + * Removes the given object from the list of objects in which this + * breakpoint is restricted to suspend execution. Has no effect if the + * object has not yet been added as an instance filter. + * + * @param object + * instance filter to remove + * @exception CoreException + * if unable to remove the given instance filter + * @since 2.1 + */ + public void removeInstanceFilter(IJavaObject object) throws CoreException; + + /** + * Returns whether this breakpoints supports instance filters. + * + * @return whether this breakpoints supports instance filters + * @since 3.0 + */ + public boolean supportsInstanceFilters(); + + /** + * Returns the current set of active instance filters. + * + * @return the current set of active instance filters. + * @exception CoreException + * if unable to retrieve the list + * @since 2.1 + */ + public IJavaObject[] getInstanceFilters() throws CoreException; + + /** + * Returns whether this breakpoints supports thread filters. + * + * @return whether this breakpoints supports thread filters + * @since 3.0 + */ + public boolean supportsThreadFilters(); + + /** + * Returns a collection of identifiers of breakpoint listener extensions + * registered for this breakpoint, possibly empty. + * + * @return breakpoint listener extension identifiers registered on this + * breakpoint + * @throws CoreException + * if unable to retrieve the collection + * @since 3.5 + */ + public String[] getBreakpointListeners() throws CoreException; + + /** + * Adds the breakpoint listener extension with specified identifier to this + * breakpoint. Has no effect if an identical listener is already registered. + * + * @param identifier + * breakpoint listener extension identifier + * @throws CoreException + * if unable to add the listener + * @since 3.5 + */ + public void addBreakpointListener(String identifier) throws CoreException; + + /** + * Removes the breakpoint listener extension with the specified identifier + * from this breakpoint and returns whether the listener was removed. + * + * @param identifier + * breakpoint listener extension identifier + * @return whether the listener was removed + * @throws CoreException + * if an error occurs removing the listener + * @since 3.5 + */ + public boolean removeBreakpointListener(String identifier) + throws CoreException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpointListener.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpointListener.java new file mode 100644 index 0000000000..6935c70221 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaBreakpointListener.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.dom.Message; + +/** + * Provides event and error notification for Java breakpoints. Listeners + * register with the JDIDebugModel. + *

      + * Since 3.5, clients can also register breakpoint listeners using the + * org.eclipse.jdt.debug.breakpointListeners extension point. A + * listener can be contributed to receive notifications from all Java + * breakpoints or receive notifications about specific breakpoints by + * programmatically registering the extension with a breakpoint. + *

      + *

      + * Clients are intended to implement this interface. + *

      + * + * @since 2.0 + * @see JDIDebugModel + * @see IJavaBreakpoint + */ +public interface IJavaBreakpointListener { + + /** + * Return code in response to a "breakpoint hit" notification, indicating a + * vote to suspend the associated thread. + * + * @since 3.0 + */ + public static int SUSPEND = 0x0001; + /** + * Return code in response to a "breakpoint hit" notification, indicating a + * vote to not suspend (i.e. resume) the associated thread. + * + * @since 3.0 + */ + public static int DONT_SUSPEND = 0x0002; + /** + * Return code in response to an "installing" notification, indicating a + * vote to install the associated breakpoint. + * + * @since 3.0 + */ + public static int INSTALL = 0x0001; + /** + * Return code in response to an "installing" notification, indicating a + * vote to not install the associated breakpoint. + * + * @since 3.0 + */ + public static int DONT_INSTALL = 0x0002; + /** + * Return code indicating that this listener should not be considered in a + * vote to suspend a thread or install a breakpoint. + * + * @since 3.0 + */ + public static int DONT_CARE = 0x0004; + + /** + * Notification that the given breakpoint is about to be added to the + * specified target. This message is sent before the breakpoint is actually + * added to the debut target (i.e. this is a pre-notification). + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + */ + public void addingBreakpoint(IJavaDebugTarget target, + IJavaBreakpoint breakpoint); + + /** + * Notification that the given breakpoint is about to be installed in the + * specified target, in the specified type. Allows this listener to vote to + * determine if the given breakpoint should be installed in the specified + * type and target. If at least one listener votes to INSTALL, + * the breakpoint will be installed. If there are no votes to install the + * breakpoint, there must be at least one DONT_INSTALL vote to + * cancel the installation. If all listeners vote DONT_CARE, + * the breakpoint will be installed by default. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + * @param type + * the type (class or interface) the breakpoint is about to be + * installed in or null if the given breakpoint is + * not installed in a specific type (one of + * IJavaClassType, IJavaInterfaceType, + * or IJavaArrayType) + * @return whether the the breakpoint should be installed in the given type + * and target, or whether this listener doesn't care - one of + * INSTALL, DONT_INSTALL, or + * DONT_CARE + * @since 3.0 + */ + public int installingBreakpoint(IJavaDebugTarget target, + IJavaBreakpoint breakpoint, IJavaType type); + + /** + * Notification that the given breakpoint has been installed in the + * specified target. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + */ + public void breakpointInstalled(IJavaDebugTarget target, + IJavaBreakpoint breakpoint); + + /** + * Notification that the given breakpoint has been hit in the specified + * thread. Allows this listener to vote to determine if the given thread + * should be suspended in response to the breakpoint. If at least one + * listener votes to SUSPEND, the thread will suspend. If there + * are no votes to suspend the thread, there must be at least one + * DONT_SUSPEND vote to avoid the suspension (resume). If all + * listeners vote DONT_CARE, the thread will suspend by + * default. + *

      + * The thread the breakpoint has been encountered in is now suspended. + * Listeners may query thread state and perform evaluations. All subsequent + * breakpoints in this thread will be ignored until voting has completed. + *

      + * + * @param thread + * Java thread + * @param breakpoint + * Java breakpoint + * @return whether the thread should suspend or whether this listener + * doesn't care - one of SUSPEND, + * DONT_SUSPEND, or DONT_CARE + * @since 3.0 + */ + public int breakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint); + + /** + * Notification that the given breakpoint has been removed from the + * specified target. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + */ + public void breakpointRemoved(IJavaDebugTarget target, + IJavaBreakpoint breakpoint); + + /** + * Notification that the given breakpoint had runtime errors in its + * conditional expression. + * + * @param breakpoint + * the breakpoint + * @param exception + * the debug exception that occurred evaluating the breakpoint's + * condition + */ + public void breakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, + DebugException exception); + + /** + * Notification that the given breakpoint has compilation errors in its + * conditional expression. + * + * @param breakpoint + * the breakpoint + * @param errors + * the compilation errors in the breakpoint's condition + */ + public void breakpointHasCompilationErrors(IJavaLineBreakpoint breakpoint, + Message[] errors); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassObject.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassObject.java new file mode 100644 index 0000000000..1bd5cc8a6e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassObject.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +/** + * An object referencing an instance of java.lang.Class on a target + * VM. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface IJavaClassObject extends IJavaObject { + + /** + * Returns the type associated with instances of this class. + * + * @return the type associated with instances of this class + */ + IJavaType getInstanceType(); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassPrepareBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassPrepareBreakpoint.java new file mode 100644 index 0000000000..e9a6a624ff --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassPrepareBreakpoint.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; + +/** + * A breakpoint that suspends execution when a class is prepared in a target VM. + * + * @since 3.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaClassPrepareBreakpoint extends IJavaBreakpoint { + + /** + * Constant indicating a class prepare breakpoint is associated with a class + * type. + */ + public static final int TYPE_CLASS = 0; + /** + * Constant indicating a class prepare breakpoint is associated with an + * interface type. + */ + public static final int TYPE_INTERFACE = 1; + + /** + * Returns a constant indicating what kind of type this breakpoint is + * associated with. + * + * @return one of TYPE_CLASS or TYPE_INTERFACE + * @throws CoreException + * if unable to retrieve the attribute + */ + public int getMemberType() throws CoreException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassType.java new file mode 100644 index 0000000000..c0a3991f65 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaClassType.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * The class of an object on a Java debug target. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaClassType extends IJavaReferenceType { + + /** + * Returns a new instance of this class by invoking the constructor with the + * given signature and arguments in the specified thread. The given thread + * is resumed to perform this method invocation and suspends in its original + * location when this method invocation is complete. This method does not + * return until the method invocation is complete. Resuming the specified + * thread can result in breakpoints being hit, infinite loops, and deadlock. + * + * @param signature + * the JNI style signature of the method to be invoked + * @param args + * the arguments of the constructor, which can be + * null or empty if there are none + * @param thread + * the thread in which to invoke the constructor + * @return the result of invoking the constructor + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This type does not implement the specified constructor + *
      • + *
      • An exception occurs while invoking the specified + * constructor
      • + *
      • The given thread is already performing a message send, + * (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
      • + *
      • The given thread is not currently suspended (status + * code IJavaThread.ERR_THREAD_NOT_SUSPENDED)
      • + *
      • The given thread was explicitly suspended (status code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
      • + *
      + */ + public IJavaObject newInstance(String signature, IJavaValue[] args, + IJavaThread thread) throws DebugException; + + /** + * Returns the result of sending the specified message to this class with + * the given arguments in the specified thread (invokes a static method on + * this type). The given thread is resumed to perform this method invocation + * and suspends in its original location when this method invocation is + * complete. This method does not return until the method invocation is + * complete. Resuming the specified thread can result in breakpoints being + * hit, infinite loops, and deadlock. + * + * @param selector + * the selector of the method to be invoked + * @param signature + * the JNI style signature of the method to be invoked + * @param args + * the arguments of the method, which can be null or + * empty if there are none + * @param thread + * the thread in which to invoke the method + * @return the result of invoking the method + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This object does not implement the specified method
      • + *
      • An exception occurs while invoking the specified + * method
      • + *
      • The given thread is already performing a message send, + * (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
      • + *
      • The given thread is not currently suspended (status + * code IJavaThread.ERR_THREAD_NOT_SUSPENDED)
      • + *
      • The given thread was explicitly suspended (status code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
      • + *
      + */ + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread) throws DebugException; + + /** + * Returns the superclass of this class type, or null if no + * such class exists. + * + * @return the superclass of this class type, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public IJavaClassType getSuperclass() throws DebugException; + + /** + * Returns the interface objects associated with the interfaces this class + * directly implements. Only those interfaces declared in the + * implements clause for this class are included. + * + * @return the interface objects associated with the interfaces this class + * directly implements + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.0 + */ + public IJavaInterfaceType[] getInterfaces() throws DebugException; + + /** + * Returns the interface objects associated with all interfaces + * this class implements, directly or indirectly. + * + * @return the interface objects associated with the interfaces this class + * directly implements, directly or indirectly + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.0 + */ + public IJavaInterfaceType[] getAllInterfaces() throws DebugException; + + /** + * Returns whether this type is declared as a type safe enumeration. + * + * @return true if this type is a type safe enumeration, + * false otherwise. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.1 + */ + public boolean isEnum() throws DebugException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java new file mode 100644 index 0000000000..df65d0d7a5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java @@ -0,0 +1,583 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Moller - enhancement 254677 - filter getters/setters + * Codenza Software Development Inc. - Darin Wright - bug 330987 + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IStepFilters; + +/** + * A Java virtual machine. + * + * @see IDebugTarget + * @see org.eclipse.core.runtime.IAdaptable + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ + +public interface IJavaDebugTarget extends IDebugTarget, IStepFilters { + /** + * Searches for and returns a variable with the given name, or + * null if unable to resolve a variable with the name. + *

      + * Variable lookup works only when a debug target has one or more threads + * suspended. Lookup is performed in each suspended thread, returning the + * first successful match, or null if no match if found. If + * this debug target has no suspended threads, null is + * returned. + *

      + * + * @param variableName + * name of the variable + * @return a variable with the given name, or null if none + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public abstract IJavaVariable findVariable(String variableName) + throws DebugException; + + /** + * Returns the types loaded in this debug target with the given fully + * qualified name, or null of no type with the given name is + * loaded. + * + * @param name + * fully qualified name of type, for example + * java.lang.String + * @return the types with the given name, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public abstract IJavaType[] getJavaTypes(String name) throws DebugException; + + /** + * Returns a value from this target that corresponds to the given boolean. + * The returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a boolean from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(boolean value); + + /** + * Returns a value from this target that corresponds to the given byte. The + * returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a byte from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(byte value); + + /** + * Returns a value from this target that corresponds to the given char. The + * returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a char from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(char value); + + /** + * Returns a value from this target that corresponds to the given double. + * The returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a double from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(double value); + + /** + * Returns a value from this target that corresponds to the given float. The + * returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a float from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(float value); + + /** + * Returns a value from this target that corresponds to the given int. The + * returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * an int from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(int value); + + /** + * Returns a value from this target that corresponds to the given long. The + * returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a long from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(long value); + + /** + * Returns a value from this target that corresponds to the given short. The + * returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a short from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(short value); + + /** + * Returns a value from this target that corresponds to the given string. + * The returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @param value + * a string from which to create a value + * @return a corresponding value from this target + */ + public abstract IJavaValue newValue(String value); + + /** + * Returns a value from this target that corresponds to null. + * The returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @return a value corresponding to null + */ + public abstract IJavaValue nullValue(); + + /** + * Returns a value from this target that corresponds to void. + * The returned value can be used for setting and comparing against a value + * retrieved from this debug target. + * + * @return a value corresponding to void + */ + public abstract IJavaValue voidValue(); + + /** + * Returns whether any of the threads associated with this debug target are running code in the VM that is out of synch with the code in the + * workspace. + * + * @return whether this debug target is out of synch with the workspace. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + */ + public abstract boolean isOutOfSynch() throws DebugException; + + /** + * Returns whether any of the threads associated with this debug target may be running code in the VM that is out of synch with the code in the + * workspace. + * + * @return whether this debug target may be out of synch with the workspace. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + */ + public abstract boolean mayBeOutOfSynch() throws DebugException; + + /** + * Returns whether this target supports hot code replace. + * + * @return whether this target supports hot code replace + */ + public boolean supportsHotCodeReplace(); + + /** + * Returns whether this target is currently performing a hot code replace. + * + * @return whether this target is currently performing a hot code replace + * @since 2.1 + */ + public boolean isPerformingHotCodeReplace(); + + /** + * Returns whether this target supports instance breakpoints. + * + * @return whether this target supports instance breakpoints + * @since 2.1 + */ + public boolean supportsInstanceBreakpoints(); + + /** + * Returns whether synthetic methods are filtered when stepping, if step + * filters are enabled. + * + * @return whether synthetic methods are filtered when stepping + */ + public abstract boolean isFilterSynthetics(); + + /** + * Sets whether synthetic methods are filtered when stepping. + * + * @param filter + * whether to synthetic methods are filtered when stepping + */ + public abstract void setFilterSynthetics(boolean filter); + + /** + * Returns whether simple getters are filtered when stepping. + * + * @return true, if simple getters should be filtered when stepping + * @since 3.7 + */ + public abstract boolean isFilterGetters(); + + /** + * Sets whether simple getters are filtered when stepping. + * + * @param filter + * whether to filter simple getters when stepping + * @since 3.7 + */ + public abstract void setFilterGetters(boolean filter); + + /** + * Returns whether simple setters are filtered when stepping. + * + * @return true, if simple setters should be filtered when stepping + * @since 3.7 + */ + public abstract boolean isFilterSetters(); + + /** + * Sets whether simple setters are filtered when stepping. + * + * @param filter + * whether to filter simple setters when stepping + * @since 3.7 + */ + public abstract void setFilterSetters(boolean filter); + + /** + * Returns whether static initializers are filtered when stepping, if step + * filters are enabled. + * + * @return whether static initializers are filtered when stepping + */ + public abstract boolean isFilterStaticInitializers(); + + /** + * Sets whether to filter static initializers when stepping. + * + * @param filter + * whether to filter static initializers when stepping + */ + public abstract void setFilterStaticInitializers(boolean filter); + + /** + * Returns whether constructors are filtered when stepping, if step filters + * are enabled. + * + * @return whether constructors are filtered when stepping + */ + public abstract boolean isFilterConstructors(); + + /** + * Sets whether to filter constructors when stepping. + * + * @param filter + * whether to filter constructors when stepping + */ + public abstract void setFilterConstructors(boolean filter); + + /** + * Returns the list of active step filters in this target. The list is a + * collection of Strings. Each string is the fully qualified name/pattern of + * a type/package to filter when stepping. For example + * java.lang.* or java.lang.String. + * + * @return the list of active step filters, or null + */ + public abstract String[] getStepFilters(); + + /** + * Sets the list of active step filters in this target. The list is a + * collection of Strings. Each string is the fully qualified name/pattern of + * a type/package to filter when stepping. For example + * java.lang.* or java.lang.String. + * + * @param list + * active step filters, or null + */ + public abstract void setStepFilters(String[] list); + + /** + * Sets whether a step that lands in a filtered location should continue + * through to an un-filtered location, or return to where the step + * originated. + * + * @param thru + * whether to step thru a filtered location or return to location + * where step originated + * @since 3.5 + */ + public void setStepThruFilters(boolean thru); + + /** + * Returns whether a step that lands in a filtered location should proceed + * through to an un-filtered location or return to the location where a step + * originated. + * + * @return whether a step that lands in a filtered location should proceed + * through to an un-filtered location or return to the location + * where a step originated + * @since 3.5 + */ + public boolean isStepThruFilters(); + + /** + * Returns whether this debug target supports a request timeout - a maximum + * time for a JDI request to receive a response. This option is only + * supported by the Eclipse JDI implementation. + * + * @return whether this debug target supports a request timeout + */ + public boolean supportsRequestTimeout(); + + /** + * Sets the timeout value for JDI requests in milliseconds. Has no effect if + * this target does not support a request timeout. + * + * @param timeout + * the communication timeout, in milliseconds + */ + public void setRequestTimeout(int timeout); + + /** + * Returns the timeout value for JDI requests in milliseconds, or -1 if not + * supported. + * + * @return timeout value, in milliseconds, or -1 if not supported + */ + public int getRequestTimeout(); + + /** + * Returns whether this target supports providing monitor information. + * + * @return whether this target supports providing monitor information. + * @since 2.1 + */ + public boolean supportsMonitorInformation(); + + /** + * Returns whether this target supports access watchpoints. + * + * @return whether this target supports access watchpoints + * @since 3.0 + */ + public boolean supportsAccessWatchpoints(); + + /** + * Returns whether this target supports modification watchpoints. + * + * @return whether this target supports modification watchpoints + * @since 3.0 + */ + public boolean supportsModificationWatchpoints(); + + /** + * Set the default stratum used in this debug target. + * + * @param stratum + * the new default stratum, or null to indicate + * per-class default stratum + * @since 3.0 + */ + public void setDefaultStratum(String stratum); + + /** + * Return the default stratum used in this the target, or null + * to indicate a per-class default stratum. + * + * @return the default stratum, or null to indicate a per-class + * default stratum + * @see #setDefaultStratum(String) + * @since 3.0 + */ + public String getDefaultStratum(); + + /** + * Returns the top level thread groups in this target. Top level thread + * groups do not have a parent. + * + * @return top level thread groups + * @throws DebugException + * if an exception occurs + * @since 3.2 + */ + public IJavaThreadGroup[] getRootThreadGroups() throws DebugException; + + /** + * Returns all thread groups in this target. + * + * @return all thread groups in this target + * @throws DebugException + * if an exception occurs + * @since 3.2 + */ + public IJavaThreadGroup[] getAllThreadGroups() throws DebugException; + + /** + * Returns whether this VM supports instance and reference retrieval for + * types and objects. + * + * @return whether this VM supports instance and reference retrieval for + * types and objects + * @since 3.3 + */ + public boolean supportsInstanceRetrieval(); + + /** + * Returns whether this VM supports the ability to force an early return + * from methods. + * + * @return whether this VM can force an early return from methods + * @since 3.3 + * @see IJavaThread + */ + public boolean supportsForceReturn(); + + /** + * Returns whether this VM supports the ability to enable and disable + * garbage collection of individual objects. + * + * @return whether this VM supports the ability to enable and disable + * garbage collection of individual objects + * @see IJavaObject + * @since 3.4 + */ + public boolean supportsSelectiveGarbageCollection(); + + /** + * Returns the name of the underlying virtual machine as defined by the + * system property java.vm.name. + * + * @return virtual machine name + * @exception DebugException + * if retrieving the name fails + * @since 3.4 + */ + public String getVMName() throws DebugException; + + /** + * Returns the version of the underlying virtual machine as defined by the + * system property java.version. + * + * @return java.version system property + * @exception DebugException + * if retrieving the version property fails + * @since 3.4 + */ + public String getVersion() throws DebugException; + + /** + * Refreshes the state of the Java debug model elements (client) with the + * current state of the debug target. + *

      + * For example, a {@link IJavaThread} may currently have a suspended state, + * but was somehow resumed on the target. Calling this method will causes + * all threads to update their state based on the current state of the + * target. Elements will fire debug events associated with any state + * changes. For example, a thread would fire a resume event if it discovered + * it was in a running state when it thought it was suspended. + *

      + * + * @throws DebugException + * if an exception occurs + * @since 3.6 + */ + public void refreshState() throws DebugException; + + /** + * Sends a JDWP command to the back end and returns the JDWP reply packet as + * bytes. This method creates an appropriate command header and packet id, + * before sending to the back end. + * + * @param commandSet + * command set identifier as defined by JDWP + * @param commandId + * command identifier as defined by JDWP + * @param data + * any bytes required for the command that follow the command + * header or null for commands that have no data + * @return raw reply packet as bytes defined by JDWP + * @exception DebugException + * if an error occurs sending the packet or receiving the + * reply + * @since 3.6 + */ + public byte[] sendCommand(byte commandSet, byte commandId, byte[] data) + throws DebugException; + + /** + * Adds the given listener to this target for hot code replace + * notifications. Has no effect if an identical listener is already + * registered. + *

      + * When a hot code replace listener is added to a specific target, general + * hot code replace notifications via {@link JDIDebugModel} are not reported + * for that target. This allows a target to override general/default hot + * code replace listeners/handlers. + *

      + * + * @param listener + * hot code replace listener + * @since 3.6 + */ + public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener); + + /** + * Removes the given listener from this target. Has no effect if an + * identical listener is not already registered. + * + * @param listener + * hot code replace listener + * @since 3.6 + */ + public void removeHotCodeReplaceListener( + IJavaHotCodeReplaceListener listener); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaExceptionBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaExceptionBreakpoint.java new file mode 100644 index 0000000000..93c19c2d00 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaExceptionBreakpoint.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; + +/** + * A breakpoint that suspends execution when a corresponding exception is thrown + * in a target VM. An exception breakpoint can be configured to suspend + * execution when the corresponding exception is thrown in a caught or uncaught + * location. As well, the location can be filtered inclusively or exclusively by + * type name patterns. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaExceptionBreakpoint extends IJavaBreakpoint { + /** + * Sets the inclusion filters that will define the scope for the associated + * exception. Filters are a collection of strings of type name prefixes. + * Default packages should be specified as the empty string. + * + * @param filters + * the array of filters to apply + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + * @since 2.1 + */ + public void setInclusionFilters(String[] filters) throws CoreException; + + /** + * Returns the inclusive filters that define the scope for the associated + * exception. Filters are a collection of strings of type name prefixes. + * + * @return the array of defined inclusive filters + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + * @since 2.1 + */ + public String[] getInclusionFilters() throws CoreException; + + /** + * Returns whether this breakpoint suspends execution when the associated + * exception is thrown in a caught location (in a try/catch statement). + * + * @return true if this is a caught exception breakpoint + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public boolean isCaught() throws CoreException; + + /** + * Returns whether this breakpoint suspends execution when the associated + * exception is thrown in an uncaught location (not caught by a try/catch + * statement). + * + * @return true if this is an uncaught exception breakpoint. + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public boolean isUncaught() throws CoreException; + + /** + * Sets whether this breakpoint suspends execution when the associated + * exception is thrown in a caught location (in a try/catch statement). + * + * @param caught + * whether or not this breakpoint suspends execution when the + * associated exception is thrown in a caught location + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setCaught(boolean caught) throws CoreException; + + /** + * Sets whether this breakpoint suspends execution when the associated + * exception is thrown in an uncaught location. + * + * @param uncaught + * whether or not this breakpoint suspends execution when the + * associated exception is thrown in an uncaught location + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setUncaught(boolean uncaught) throws CoreException; + + /** + * Returns whether the exception associated with this breakpoint is a + * checked exception (compiler detected). + * + * @return true if the exception associated with this + * breakpoint is a checked exception + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public boolean isChecked() throws CoreException; + + /** + * Returns the fully qualified type name of the exception that last caused + * this breakpoint to suspend, of null if this breakpoint has + * not caused a thread to suspend. Note that this name may be a sub type of + * the exception that this breakpoint is associated with. + * + * @return fully qualified exception name or null + */ + public String getExceptionTypeName(); + + /** + * Sets the filters that will define the scope for the associated exception. + * Filters are a collection of strings of type name prefixes. Default + * packages should be specified as the empty string. + * + * @param filters + * the array of filters to apply + * @param inclusive + * whether or not to apply the filters as inclusive or exclusive + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + * @deprecated Exception breakpoints can have a mixed set of filters. Use + * setInclusiveFilters(String[] filters) or + * setExclusiveFilters(String[] filters) + */ + @Deprecated + public void setFilters(String[] filters, boolean inclusive) + throws CoreException; + + /** + * Sets the exclusion filters that will define the scope for the associated + * exception. Filters are a collection of strings of type name prefixes. + * Default packages should be specified as the empty string. + * + * @param filters + * the array of filters to apply + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + * @since 2.1 + */ + public void setExclusionFilters(String[] filters) throws CoreException; + + /** + * Returns the filters that define the scope for the associated exception. + * Filters are a collection of strings of type name prefixes. + * + * @return the array of defined filters + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + * @deprecated Use getExclusionFilters() or getInclusionFilters() + */ + @Deprecated + public String[] getFilters() throws CoreException; + + /** + * Returns the exclusive filters that define the scope for the associated + * exception. Filters are a collection of strings of type name prefixes. + * + * @return the array of defined inclusive filters + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + * @since 2.1 + */ + public String[] getExclusionFilters() throws CoreException; + + /** + * Returns whether any inclusive filters have been applied. + * + * @return true if the inclusive filters have been applied + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + * @deprecated Exception breakpoints can have a mixed set of filters and + * this method is maintained strictly for API backwards + * compatibility + */ + @Deprecated + public boolean isInclusiveFiltered() throws CoreException; + + /** + * Constants for telling the debugger for each exception breakpoint how to handle multiple occurrences of the same exception instance, which can + * happen via re-throwing or multiple finally clauses in the call stack. + * + * @since 3.14 + * @see IJavaExceptionBreakpoint#getSuspendOnRecurrenceStrategy() + * @see IJavaExceptionBreakpoint#setSuspendOnRecurrenceStrategy(SuspendOnRecurrenceStrategy) + */ + enum SuspendOnRecurrenceStrategy { + /** + * Signals that this setting has not yet been configured for a given breakpoint + */ + RECURRENCE_UNCONFIGURED, + /** + * Signals that the exception breakpoint should always cause suspending. + */ + SUSPEND_ALWAYS, + /** + * Signals that the breakpoint should not cause suspending more than once. This does not influence the way how the debugger reacts to uncaught + * exceptions. + */ + SKIP_RECURRENCES + } + + /** + * Define this breakpoint's {@link SuspendOnRecurrenceStrategy strategy} for suspending on recurrences of the same exception instance. + * + * @param strategy + * the new strategy + * + * @throws CoreException + * if accessing the breakpoint's marker failed + * @since 3.14 + * @see #getSuspendOnRecurrenceStrategy() + */ + void setSuspendOnRecurrenceStrategy(SuspendOnRecurrenceStrategy strategy) throws CoreException; + + /** + * Answer this breakpoint's {@link SuspendOnRecurrenceStrategy strategy} for suspending on recurrences of the same exception instance. + * + * @return the strategy + * + * @throws CoreException + * if accessing the breakpoint's marker failed + * @since 3.14 + * @see #setSuspendOnRecurrenceStrategy(SuspendOnRecurrenceStrategy) + */ + SuspendOnRecurrenceStrategy getSuspendOnRecurrenceStrategy() throws CoreException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaFieldVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaFieldVariable.java new file mode 100644 index 0000000000..af5dfb5f36 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaFieldVariable.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * A variable that contains the value of an instance or class variable. + * + * @see org.eclipse.debug.core.model.IVariable + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaFieldVariable extends IJavaVariable { + + /** + * Returns whether this variable is declared as transient. + * + * @return whether this variable has been declared as transient + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isTransient() throws DebugException; + + /** + * Returns whether this variable is declared as volatile. + * + * @return whether this variable has been declared as volatile + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isVolatile() throws DebugException; + + /** + * Returns the type that declares this variable. + * + * @return the type that declares this variable + */ + public IJavaType getDeclaringType(); + + /** + * Returns the object that contains this field variable, or + * null if no object contains this field variable (static field + * variable). + * + * @return the object that contains this field variable + * @since 3.0 + */ + public IJavaObject getReceiver(); + + /** + * Returns the type that contains this field variable. + * + * @return the type that contains this field variable + * @since 3.0 + */ + public IJavaReferenceType getReceivingType(); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaHotCodeReplaceListener.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaHotCodeReplaceListener.java new file mode 100644 index 0000000000..c3ec75154c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaHotCodeReplaceListener.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * Notification of hot code replace failure and success. As resources are + * modified in the workspace, targets that support hot code replace are updated + * with new class files. + *

      + * Clients may implement this interface + *

      + * + * @since 2.0 + */ +public interface IJavaHotCodeReplaceListener { + + /** + * Notification that a hot code replace attempt failed in the given target. + * + * @param target + * the target in which the hot code replace failed + * @param exception + * the exception generated by the hot code replace failure, or + * null if the hot code replace failed because the + * target VM does not support hot code replace + */ + public void hotCodeReplaceFailed(IJavaDebugTarget target, + DebugException exception); + + /** + * Notification that a hot code replace attempt succeeded in the given + * target. + * + * @param target + * the target in which the hot code replace succeeded + */ + public void hotCodeReplaceSucceeded(IJavaDebugTarget target); + + /** + * Notification that obsolete methods remain on the stack in one or more + * threads in the given target after a hot code replace. + * + * @param target + * the target in which obsolete methods remain after a hot code + * replace + */ + public void obsoleteMethods(IJavaDebugTarget target); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaInterfaceType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaInterfaceType.java new file mode 100644 index 0000000000..b89091b9c0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaInterfaceType.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * An interface an object implements on a Java debug target. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaInterfaceType extends IJavaReferenceType { + + /** + * Returns the class objects associated with the implementors of this + * interface type. Returns an empty array if there are none. + * + * @return the class objects associated with the implementors of this + * interface type + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.0 + */ + public IJavaClassType[] getImplementors() throws DebugException; + + /** + * Returns the interface objects associated with the sub-interfaces of this + * interface type. Returns an empty array if there are none. The + * sub-interfaces are those interfaces that directly extend this interface, + * that is, those interfaces that declared this interface in their + * extends clause. + * + * @return the interface objects associated with the sub-interfaces of this + * interface type + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.0 + */ + public IJavaInterfaceType[] getSubInterfaces() throws DebugException; + + /** + * Returns the interface objects associated with the super-interfaces of + * this interface type. Returns an empty array if there are none. The + * super-interfaces are those interfaces that are directly extended by this + * interface, that is, those interfaces that this interface declared to be + * extended. + * + * @return the interface objects associated with the super-interfaces of + * this interface type + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.0 + */ + public IJavaInterfaceType[] getSuperInterfaces() throws DebugException; + + /** + * Returns the result of sending the specified message to this class with + * the given arguments in the specified thread (invokes a static method on + * this type). The given thread is resumed to perform this method invocation + * and suspends in its original location when this method invocation is + * complete. This method does not return until the method invocation is + * complete. Resuming the specified thread can result in breakpoints being + * hit, infinite loops, and deadlock. + * + * @param selector + * the selector of the method to be invoked + * @param signature + * the JNI style signature of the method to be invoked + * @param args + * the arguments of the method, which can be null or + * empty if there are none + * @param thread + * the thread in which to invoke the method + * @return the result of invoking the method + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This object does not implement the specified method
      • + *
      • An exception occurs while invoking the specified + * method
      • + *
      • The given thread is already performing a message send, + * (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
      • + *
      • The given thread is not currently suspended (status + * code IJavaThread.ERR_THREAD_NOT_SUSPENDED)
      • + *
      • The given thread was explicitly suspended (status code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
      • + *
      + * + * @since 3.10 + */ + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread) throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaLineBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaLineBreakpoint.java new file mode 100644 index 0000000000..c1039b410c --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaLineBreakpoint.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.ILineBreakpoint; + +/** + * A breakpoint that suspends execution when a particular line of code is + * reached. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaLineBreakpoint extends IJavaBreakpoint, ILineBreakpoint { + + /** + * Returns whether this breakpoint supports a conditional expression. + * Conditional breakpoints only suspend when their associated condition + * evaluates to true. + * + * @return whether this breakpoint supports a condition + */ + public boolean supportsCondition(); + + /** + * Returns the conditional expression associated with this breakpoint, or + * null if this breakpoint does not have a condition. + * + * @return this breakpoint's conditional expression, or null + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + */ + public String getCondition() throws CoreException; + + /** + * Sets the condition associated with this breakpoint. When the condition is + * enabled, this breakpoint will only suspend execution when the given + * condition evaluates to true. Setting the condition to + * null or an empty string removes the condition. + *

      + * If this breakpoint does not support conditions, setting the condition has + * no effect. + *

      + * + * @param condition + * conditional expression + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setCondition(String condition) throws CoreException; + + /** + * Returns whether the condition on this breakpoint is enabled. + * + * @return whether this breakpoint's condition is enabled + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + */ + public boolean isConditionEnabled() throws CoreException; + + /** + * Sets the enabled state of this breakpoint's condition to the given state. + * When enabled, this breakpoint will only suspend when its condition + * evaluates to true. When disabled, this breakpoint will suspend as it + * would with no condition defined. + * + * @param enabled + * the enabled state of the condition + * + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setConditionEnabled(boolean enabled) throws CoreException; + + /** + * Returns whether the breakpoint suspends when the value of the condition + * is true or when the value of the condition changes. + * + * @return true if this breakpoint suspends when the value of + * the condition is true, false if this + * breakpoint suspends when the value of the condition changes. + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + * @since 2.1 + */ + public boolean isConditionSuspendOnTrue() throws CoreException; + + /** + * Set the suspend state of this breakpoint's condition. If the value is + * true, the breakpoint will stop when the value of the + * condition is true. If the value is false, the + * breakpoint will stop when the value of the condition changes. + * + * @param suspendOnTrue + * if the condition should suspend when true + * + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + * @since 2.1 + */ + public void setConditionSuspendOnTrue(boolean suspendOnTrue) + throws CoreException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaMethodBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaMethodBreakpoint.java new file mode 100644 index 0000000000..20d2384f97 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaMethodBreakpoint.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.IDebugTarget; + +/** + * A method breakpoint suspends execution when a method is entered or exited. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaMethodBreakpoint extends IJavaLineBreakpoint { + + /** + * Returns the name of the method(s) this breakpoint suspends execution in, + * or null if this breakpoint does not suspend execution based + * on method name. + * + * @return the name of the method(s) this breakpoint suspends execution in, + * or null if this breakpoint does not suspend + * execution based on method name + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getMethodName() throws CoreException; + + /** + * Returns the signature of the method(s) this breakpoint suspends execution + * in, or null if this breakpoint does not suspend execution + * based on method signature. + * + * @return the signature of the method(s) this breakpoint suspends execution + * in, or null if this breakpoint does not suspend + * execution based on method signature + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getMethodSignature() throws CoreException; + + /** + * Returns the pattern specifying the fully qualified name of type(s) this + * breakpoint suspends execution in. Patterns are limited to exact matches + * and patterns that begin or end with '*'. + * + * @return the pattern specifying the fully qualified name of type(s) this + * breakpoint suspends execution in + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + * @see IJavaBreakpoint#getTypeName() + */ + @Override + public String getTypeName() throws CoreException; + + /** + * Returns whether this breakpoint causes execution to suspend on entry to + * methods. + * + * @return whether this breakpoint causes execution to suspend on entry to + * methods + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public boolean isEntry() throws CoreException; + + /** + * Returns whether this breakpoint causes execution to suspend on exit of + * methods. + * + * @return whether this breakpoint causes execution to suspend on exit of + * methods + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public boolean isExit() throws CoreException; + + /** + * Sets whether this breakpoint causes execution to suspend on entry to + * methods. + * + * @param entry + * whether this breakpoint causes execution to suspend on entry + * to methods + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setEntry(boolean entry) throws CoreException; + + /** + * Sets whether this breakpoint causes execution to suspend on exit of + * methods. + * + * @param exit + * whether this breakpoint causes execution to suspend on exit of + * methods + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setExit(boolean exit) throws CoreException; + + /** + * Sets whether this breakpoint causes execution to suspend only on + * entry/exit of native methods. + * + * @param nativeOnly + * whether this breakpoint causes execution to suspend only on + * entry/exit of native methods + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + */ + public void setNativeOnly(boolean nativeOnly) throws CoreException; + + /** + * Returns whether this breakpoint causes execution to suspend only on + * entry/exit of native methods. + * + * @return whether this breakpoint causes execution to suspend only on + * entry/exit of native methods + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + */ + public boolean isNativeOnly() throws CoreException; + + /** + * Returns whether this breakpoint last suspended in the given target due to + * a method entry (true) or exit (false). + * + * @param target + * the debug target + * + * @return true if this breakpoint last suspended the given + * target due to a method entry; false if this + * breakpoint last suspended in the given target due to a method + * exit or if this breakpoint hasn't suspended the given target. + */ + public boolean isEntrySuspend(IDebugTarget target); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaMethodEntryBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaMethodEntryBreakpoint.java new file mode 100644 index 0000000000..0daf05a685 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaMethodEntryBreakpoint.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; + +/** + * A method entry breakpoint suspends execution on the first executable line of + * a method when entered. Entry breakpoints can only be installed in methods + * that have executable code (i.e. do not work in native methods). + *

      + * This breakpoint provides a subset of the function provided by + * IJavaMethodBreakpoint - i.e. break on enter. The implementation + * of this breakpoint is more efficient than the general method breakpoint, as + * the implementation is based on line breakpoints and does not require method + * enter/exit tracing in the target VM. + *

      + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaMethodEntryBreakpoint extends IJavaLineBreakpoint { + + /** + * Returns the name of the method this breakpoint suspends execution in. + * + * @return the name of the method this breakpoint suspends execution in + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getMethodName() throws CoreException; + + /** + * Returns the signature of the method this breakpoint suspends execution + * in. + * + * @return the signature of the method this breakpoint suspends execution in + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getMethodSignature() throws CoreException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaModifiers.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaModifiers.java new file mode 100644 index 0000000000..0df3fb7cd4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaModifiers.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * Modifiers common to Java debug elements that have associated Java member + * declarations. For example, the method associated with a stack frame, or the + * field associated with a variable. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaModifiers { + + /** + * Returns whether the associated Java construct is declared as public. + * + * @return whether the associated Java construct is declared as public + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isPublic() throws DebugException; + + /** + * Returns whether the associated Java construct is declared as private. + * + * @return whether the associated Java construct is declared as private + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isPrivate() throws DebugException; + + /** + * Returns whether the associated Java construct is declared as protected. + * + * @return whether the associated Java construct is declared as protected + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isProtected() throws DebugException; + + /** + * Returns whether the associated Java construct is declared with no + * protection modifier (package private protection). + * + * @return whether the associated Java construct is declared as package + * private + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isPackagePrivate() throws DebugException; + + /** + * Returns whether the associated Java construct is declared as final. + * + * @return whether the associated Java construct is declared as final + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isFinal() throws DebugException; + + /** + * Returns whether the associated Java construct is declared as static. + * + * @return whether the associated Java construct is declared as static + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isStatic() throws DebugException; + + /** + * Returns whether the associated Java construct is synthetic. Synthetic + * members are generated by the compiler and are not present in source code. + * + * @return whether the associated Java construct is synthetic + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public boolean isSynthetic() throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaObject.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaObject.java new file mode 100644 index 0000000000..532663c6c3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaObject.java @@ -0,0 +1,258 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * A value referencing an object on a target VM. + * + * @see IJavaValue + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaObject extends IJavaValue { + + /** + * Returns the result of sending the specified message to this object with + * the given arguments in the specified thread. The given thread is resumed + * to perform the method invocation. The thread will suspend in its original + * location when the method invocation is complete. This method does not + * return until the method invocation is complete. Invoking a method in the + * target VM can result in breakpoints being hit, infinite loops, and + * deadlock. + * + * @param selector + * the selector of the method to be invoked + * @param signature + * the JNI style signature of the method to be invoked + * @param args + * the arguments of the method, which can be null or + * empty if there are none + * @param thread + * the thread in which to invoke the method + * @param superSend + * true if the method lookup should begin in this + * object's superclass + * @return the result of invoking the method + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This object does not implement the specified method
      • + *
      • An exception occurs while invoking the specified + * method
      • + *
      • The given thread is already performing a message send, + * (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
      • + *
      • The given thread is not currently suspended (status + * code IJavaThread.ERR_THREAD_NOT_SUSPENDED)
      • + *
      • The given thread was explicitly suspended (status code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
      • + *
      + */ + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, boolean superSend) + throws DebugException; + + /** + * Returns the result of sending the specified message on the specified + * declaring type to this object with the given arguments in the specified + * thread. The given thread is resumed to perform the method invocation. The + * thread will suspend in its original location when the method invocation + * is complete. This method does not return until the method invocation is + * complete. Invoking a method in the target VM can result in breakpoints + * being hit, infinite loops, and deadlock. + * + * @param selector + * the selector of the method to be invoked + * @param signature + * the JNI style signature of the method to be invoked + * @param args + * the arguments of the method, which can be null or + * empty if there are none + * @param thread + * the thread in which to invoke the method + * @param typeSignature + * the signature of the type in which the method is defined or + * null if the method should be invoked normally + * using polymorphism + * @return the result of invoking the method + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This object does not implement the specified method
      • + *
      • An exception occurs while invoking the specified + * method
      • + *
      • The given thread is already performing a message send, + * (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
      • + *
      • The given thread is not currently suspended (status + * code IJavaThread.ERR_THREAD_NOT_SUSPENDED)
      • + *
      • The given thread was explicitly suspended (status code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
      • + *
      + * @since 2.0.1 + */ + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, String typeSignature) + throws DebugException; + + /** + * Returns a variable representing the field in this object with the given name, or null if there is no field with the given name, or + * the name is ambiguous. + * + * @param name + * field name + * @param superField + * whether or not to get the field in the superclass of this objects. + * @return the variable representing the field, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + */ + public IJavaFieldVariable getField(String name, boolean superField) + throws DebugException; + + /** + * Returns a variable representing the field in this object with the given name declared in the type with the given signature, or + * null if there is no field with the given name, or the name is ambiguous. + * + * @param name + * field name + * @param typeSignature + * the signature of the type in which the field is defined + * @return the variable representing the field, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + */ + public IJavaFieldVariable getField(String name, String typeSignature) + throws DebugException; + + /** + * Returns the threads waiting for the monitor associated to this object, or + * null if no thread is waiting for the monitor. + * + * @return the thread waiting for the monitor, or null. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • The VM is not able to retrieve the monitor information + *
      • + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.1 + */ + public IJavaThread[] getWaitingThreads() throws DebugException; + + /** + * Returns the threads which owns for the monitor associated to this object, + * or null if no thread owns the monitor. + * + * @return the thread which owns the monitor, or null. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • The VM is not able to retrieve the monitor information + *
      • + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 3.1 + */ + public IJavaThread getOwningThread() throws DebugException; + + /** + * Returns objects that directly reference this object. + * + * @param max + * the maximum number of references to retrieve or 0 for all + * references + * @return objects that directly reference this object + * @throws DebugException + * if the request fails + * @since 3.3 + */ + public IJavaObject[] getReferringObjects(long max) throws DebugException; + + /** + * Permits this object to be garbage collected. Has no effect if this VM + * does not support enabling/disabling of garbage collection of specific + * objects. + * + * @throws DebugException + * if request fails + * @see IJavaDebugTarget + * @since 3.4 + */ + public void enableCollection() throws DebugException; + + /** + * Prevents this object from being garbage collected. Has no effect if this + * VM does not support enabling/disabling of garbage collection of specific + * objects. + * + * @throws DebugException + * if request fails + * @see IJavaDebugTarget + * @since 3.4 + */ + public void disableCollection() throws DebugException; + + /** + * Returns the unique id for this object. + * + * @return unique id or -1 if this value is null + * @throws DebugException + * if the request fails + * @since 3.4 + */ + public long getUniqueId() throws DebugException; + + /** + * Returns the user assigned label for this object. + * + * @since 3.19 + * @throws DebugException + * if the request fails + * @return the label, or null if there isn't any. + */ + public String getLabel() throws DebugException; + + /** + * Sets the label for this object. If the newLabel is null or empty string, then it removes the previous assignment. + * + * @since 3.19 + * @throws DebugException + * if the request fails + */ + void setLabel(String newLabel) throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaPatternBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaPatternBreakpoint.java new file mode 100644 index 0000000000..5384424760 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaPatternBreakpoint.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; + +/** + * A line breakpoint installed in types associated with a specific source file + * (based on source file name debug attribute) and whose fully qualified name + * matches a specified pattern. + * + * @since 2.0 + * @deprecated use IJavaStratumLineBreakpoint instead + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +@Deprecated +public interface IJavaPatternBreakpoint extends IJavaLineBreakpoint { + + /** + * Returns the type name pattern this breakpoint uses to identify types in + * which to install itself. + * + * @return the type name pattern this breakpoint uses to identify types in + * which to install itself + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getPattern() throws CoreException; + + /** + * Returns the source file name in which this breakpoint is set. When this + * breakpoint specifies a source file name, this breakpoint is only + * installed in types whose source file name debug attribute match this + * value. + * + * @return the source file name in which this breakpoint is set + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getSourceName() throws CoreException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaPrimitiveValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaPrimitiveValue.java new file mode 100644 index 0000000000..481718a4d4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaPrimitiveValue.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +/** + * A primitive value on a Java debug target. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaPrimitiveValue extends IJavaValue { + + /** + * Returns this value as a boolean. + * + * @return this value as a boolean + */ + public boolean getBooleanValue(); + + /** + * Returns this value as a byte + * + * @return this value as a byte + */ + public byte getByteValue(); + + /** + * Returns this value as a char + * + * @return this value as a char + */ + public char getCharValue(); + + /** + * Returns this value as a double + * + * @return this value as a double + */ + public double getDoubleValue(); + + /** + * Returns this value as a float + * + * @return this value as a float + */ + public float getFloatValue(); + + /** + * Returns this value as an int + * + * @return this value as an int + */ + public int getIntValue(); + + /** + * Returns this value as a long + * + * @return this value as a long + */ + public long getLongValue(); + + /** + * Returns this value as a short + * + * @return this value as a short + */ + public short getShortValue(); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaReferenceType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaReferenceType.java new file mode 100644 index 0000000000..debabdf6c7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaReferenceType.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; + +/** + * Represents the type of an object in a virtual machine - including classes, + * interfaces and array types. + * + * @since 3.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaReferenceType extends IJavaType { + + /** + * Returns a variable representing the static field in this type with the + * given name, or null if there is no field with the given + * name, or the name is ambiguous. + * + * @param name + * field name + * @return the variable representing the static field, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public IJavaFieldVariable getField(String name) throws DebugException; + + /** + * Returns the class object associated with this type. + * + * @return the class object associated with this type + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public IJavaClassObject getClassObject() throws DebugException; + + /** + * Returns a collection of strata available for this type. + * + * @return a collection of strata available for this type + * @throws DebugException + * if unable to retrieve available strata + */ + public String[] getAvailableStrata() throws DebugException; + + /** + * Returns the default stratum for this type. + * + * @return the default stratum for this type + * @throws DebugException + * if unable to retrieve the default stratum + */ + public String getDefaultStratum() throws DebugException; + + /** + * Returns a collection of the names of the fields declared in this type. + * + * @return a collection of the names of the field declared in this type + * @throws DebugException + * if unable to retrieve declared field names + */ + public String[] getDeclaredFieldNames() throws DebugException; + + /** + * Returns a collection of the names of all of the fields declared in this + * type, all of its super classes, implemented interfaces and super + * interfaces. + * + * @return a collection of the names of all of the fields declared in this + * type, all of its super classes, implemented interfaces and super + * interfaces + * @throws DebugException + * if unable to retrieve field names + */ + public String[] getAllFieldNames() throws DebugException; + + /** + * Returns the class loader object that loaded the class corresponding to + * this type, or null if this type was loaded by the bootstrap + * loader. + * + * @return the class loader object that loaded the class corresponding to + * this type or null + * @throws DebugException + * if unable to get the class loader + * @since 3.1 + */ + public IJavaObject getClassLoaderObject() throws DebugException; + + /** + * Returns the generic signature as defined in the JVM specification for this type. Returns null if this type is not a generic type. + * + * @return signature, or null if generic signature not available + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + * @since 3.1 + */ + public String getGenericSignature() throws DebugException; + + /** + * Returns the unqualified name of the source file corresponding to this + * type, or null if source name debug attribute is not present. + * The source name returned is based on this target's default stratum. + * + * @return unqualified source file name or null + * @throws DebugException + * if an exception occurs retrieving the source name + * @since 3.2 + */ + public String getSourceName() throws DebugException; + + /** + * Returns the unqualified names of the source files corresponding to this + * type in the specified stratum, or null if the source name + * debug attribute is not present. + * + * @param stratum + * stratum identifier or null to use this type's + * default stratum + * @return unqualified source file names or null + * @throws DebugException + * if an exception occurs retrieving the source name + * @since 3.2 + */ + public String[] getSourceNames(String stratum) throws DebugException; + + /** + * Returns the qualified names of the source files corresponding to this + * type in the specified stratum, or null if the source name + * debug attribute is not present. + * + * @param stratum + * stratum identifier or null to use this type's + * default stratum + * @return qualified source file names or null + * @throws DebugException + * if an exception occurs retrieving the source name + * @since 3.2 + */ + public String[] getSourcePaths(String stratum) throws DebugException; + + /** + * Retrieves and returns instances of this reference type. + * + * @param max + * the maximum number of instances to retrieve or 0 to retrieve + * all instances + * @return instances of this reference type + * @throws DebugException + * on failure + * @since 3.3 + */ + public IJavaObject[] getInstances(long max) throws DebugException; + + /** + * Returns the number of instances of this type currently allocated in the + * target virtual machine, or -1 if instance counts are not supported by the + * target. + * + * @return number of instances of this type, or -1 if unsupported + * @throws DebugException + * on failure + * @since 3.6 + */ + public long getInstanceCount() throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaStackFrame.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaStackFrame.java new file mode 100644 index 0000000000..a77f2e3ebf --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaStackFrame.java @@ -0,0 +1,536 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDropToFrame; +import org.eclipse.debug.core.model.IFilteredStep; +import org.eclipse.debug.core.model.IStackFrame; + +/** + * A stack frame in a thread on a Java virtual machine. + *

      + * Since 3.1, IJavaStackFrame also implements + * {@link org.eclipse.debug.core.model.IDropToFrame}. + *

      + * + * @see org.eclipse.debug.core.model.IStackFrame + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +@SuppressWarnings("deprecation") +public interface IJavaStackFrame extends IStackFrame, IJavaModifiers, + IFilteredStep, IDropToFrame { + + /** + * Status code indicating a stack frame is invalid. A stack frame becomes + * invalid when the thread containing the stack frame resumes. A stack frame + * may or may not be valid if the thread subsequently suspends, depending on + * the location where the thread suspends. + * + * @since 3.1 + */ + public static final int ERR_INVALID_STACK_FRAME = 130; + + /** + * Returns whether this stack frame currently supports the drop to frame + * operation. Note that not all VMs support the operation. + * + * @return whether this stack frame currently supports drop to frame + * @deprecated since 3.1, IJavaStackFrame extends + * org.eclipse.debug.core.IDropToFrame which defines + * canDropToFrame(). Use this method instead. + */ + @Deprecated + boolean supportsDropToFrame(); + + /** + * Returns whether the method associated with this stack frame is a + * constructor. + * + * @return whether this stack frame is associated with a constructor + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public boolean isConstructor() throws DebugException; + + /** + * Returns whether the method associated with this stack frame has been + * declared as native. + * + * @return whether this stack frame has been declared as native + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public boolean isNative() throws DebugException; + + /** + * Returns whether the method associated with this stack frame is a static + * initializer. + * + * @return whether this stack frame is a static initializer + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public boolean isStaticInitializer() throws DebugException; + + /** + * Returns whether the method associated with this stack frame has been + * declared as synchronized. + * + * @return whether this stack frame has been declared as synchronized + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public boolean isSynchronized() throws DebugException; + + /** + * Returns whether the method associated with this stack frame is running + * code in the VM that is out of synch with the code in the workspace. + * + * @return whether this stack frame is out of synch with the workspace. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 2.0 + */ + public boolean isOutOfSynch() throws DebugException; + + /** + * Returns whether the method associated with this stack frame is obsolete, + * that is, it is running old byte codes that have been replaced in the VM. + * This can occur when a hot code replace succeeds but the VM is unable to + * pop a call to an affected method from the call stack. + * + * @return whether this stack frame's method is obsolete + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 2.0 + */ + public boolean isObsolete() throws DebugException; + + /** + * Returns the fully qualified name of the type that declares the method + * associated with this stack frame. + * + * @return declaring type name + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public String getDeclaringTypeName() throws DebugException; + + /** + * Returns the fully qualified name of the type that is the receiving object + * associated with this stack frame + * + * @return receiving type name + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public String getReceivingTypeName() throws DebugException; + + /** + * Returns the JNI signature for the method this stack frame is associated + * with. + * + * @return signature + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public String getSignature() throws DebugException; + + /** + * Returns a list of fully qualified type names of the arguments for the + * method associated with this stack frame. + * + * @return argument type names, or an empty list if this method has no + * arguments + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public List getArgumentTypeNames() throws DebugException; + + /** + * Returns the name of the method associated with this stack frame + * + * @return method name + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public String getMethodName() throws DebugException; + + /** + * Returns the local, static, or "this" variable with the given name, or + * null if unable to resolve a variable with the name. + * + * @param variableName + * the name of the variable to search for + * @return a variable, or null if none + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public IJavaVariable findVariable(String variableName) + throws DebugException; + + /** + * Returns the line number of the instruction pointer in this stack frame + * that corresponds to the line in the associated source element in the + * specified stratum, or -1 if line number information is + * unavailable. + * + * @param stratum + * the stratum to use. + * @return line number of instruction pointer in this stack frame, or + * -1 if line number information is unavailable + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the debug target. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * + * @since 3.0 + */ + public int getLineNumber(String stratum) throws DebugException; + + /** + * Returns the source name debug attribute associated with the declaring + * type of this stack frame, or null if the source name debug + * attribute not present. + * + * @return source name debug attribute, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public String getSourceName() throws DebugException; + + /** + * Returns the source name debug attribute associated with the declaring + * type of this stack frame in the specified stratum, or null + * if the source name debug attribute not present. + * + * @param stratum + * the stratum to use. + * @return source name debug attribute, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * + * @since 3.0 + */ + public String getSourceName(String stratum) throws DebugException; + + /** + * Returns the source path debug attribute associated with this stack frame + * in the specified stratum, or null if the source path is not + * known. + * + * @param stratum + * the stratum to use. + * @return source path debug attribute, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 3.0 + */ + public String getSourcePath(String stratum) throws DebugException; + + /** + * Returns the source path debug attribute associated with this stack frame, + * or null if the source path is not known. + * + * @return source path debug attribute, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 3.0 + */ + public String getSourcePath() throws DebugException; + + /** + * Returns a collection of local variables that are visible at the current + * point of execution in this stack frame. The list includes arguments. + * + * @return collection of locals and arguments + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 2.0 + */ + public IJavaVariable[] getLocalVariables() throws DebugException; + + /** + * Returns a reference to the receiver of the method associated with this + * stack frame, or null if this stack frame represents a static + * method. + * + * @return 'this' object, or null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + */ + public IJavaObject getThis() throws DebugException; + + /** + * Returns the class in which this stack frame's method is declared. + * + * @return the class in which this stack frame's method is declared + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 2.0 + * @deprecated Use getReferenceType() instead, as a method is + * not restricted to occur in a class. An interface may contain + * a synthetic class initializer methods. Since 3.1, this method + * throws a DebugException when a stack frame's + * method is contained in an interface. + */ + @Deprecated + public IJavaClassType getDeclaringType() throws DebugException; + + /** + * Returns the type in which this stack frame's method is declared. + * + * @return the type in which this stack frame's method is declared + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 3.1 + */ + public IJavaReferenceType getReferenceType() throws DebugException; + + /** + * Returns whether local variable information was available when local + * variables were retrieved from the target for this frame. Returns + * true if locals have never been retrieved. This data is + * available after the fact, since variable retrieval is expensive. + * + * @return whether local variable information was available when variables + * were retrieved from the target. Returns true if + * locals have never been retrieved + * + * @since 2.0 + */ + public boolean wereLocalsAvailable(); + + /** + * Returns whether the method associated with this stack frame accepts a + * variable number of arguments. + * + * @return true if the method associated with this stack frame + * accepts a variable number of arguments, false + * otherwise. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • This stack frame is no longer valid. That is, the + * thread containing this stack frame has since been resumed. + *
      • + *
      + * @since 3.1 + */ + public boolean isVarArgs() throws DebugException; + + /** + * Returns whether this frame currently supports a force return operation. + * That is, can this method force a return before it reaches a return + * statement. Not all VMs support this feature. + *

      + * Force return is only available when a thread is suspended. + *

      + * + * @return whether force return can be performed currently + * @since 3.3 + */ + public boolean canForceReturn(); + + /** + * Steps out of this frame's method returning the given value. No further + * instructions in the method are executed but locks acquired by entering + * synchronized blocks are released. The following conditions must be + * satisfied: + *
        + *
      • This frame must be suspended in a non-native method.
      • + *
      • The return value must be assignment compatible with this frame's + * method's return type. Use a void value when a method return type is void + * (see IJavaDebugTarget.voidValue()).
      • + *
      + * + * @param value + * return value that must be assignment compatible with this + * frame's method's return value + * @throws DebugException + * if the operation fails + * @since 3.3 + */ + public void forceReturn(IJavaValue value) throws DebugException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaStratumLineBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaStratumLineBreakpoint.java new file mode 100644 index 0000000000..11a8032389 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaStratumLineBreakpoint.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2003, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; + +/** + * A line breakpoint identified by its source file name and/or path, and stratum + * that it is relative to. + * + * @since 3.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaStratumLineBreakpoint extends IJavaLineBreakpoint { + + /** + * Returns the type name pattern this breakpoint uses to identify types in + * which to install itself. Patterns may begin or end with '*'. Will not + * return null. In the case that a stratum breakpoint was + * created with a null pattern, "*" is returned. + *

      + * Multiple patterns can be specified in this breakpoint by delimiting the + * patterns with a comma - e.g. "x.y.z,a.b.c". + *

      + * + * @return the type name patterns this breakpoint uses to identify types in + * which to install itself. + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getPattern() throws CoreException; + + /** + * Returns the simple name of the source file in which this breakpoint is + * set, or null. When this breakpoint specifies a source file + * name, this breakpoint is only installed in types whose source file name + * debug attribute matches this value, relative to this breakpoint's + * stratum. + * + * @return the source file name in which this breakpoint is set, or + * null + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getSourceName() throws CoreException; + + /** + * Returns the stratum that this breakpoint's source name, source path, and + * line number are relative to, or null if this breakpoint is + * relative to a type's default stratum. + * + * @return the stratum that this breakpoint's source name, source path, and + * line number are relative to, or null + * @throws CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getStratum() throws CoreException; + + /** + * Returns the qualified source file path in which this breakpoint is set, + * or null. When specified, this breakpoint is only installed + * in types whose source file path debug attribute matches this value, + * relative to this breakpoint's stratum. + * + * @return the qualified source file path in which this breakpoint is set, + * or null + * @throws CoreException + * if unable to get the source path + */ + public String getSourcePath() throws CoreException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaTargetPatternBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaTargetPatternBreakpoint.java new file mode 100644 index 0000000000..8624d7fb71 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaTargetPatternBreakpoint.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; + +/** + * A line breakpoint installed in types associated with a specific source file + * (based on source file name debug attribute) and whose fully qualified name + * matches a specified pattern per target. The {target, type name pattern} pairs + * are not persisted with this breakpoint, as targets are transient. Clients + * that use this type of breakpoint are intended to be breakpoint listeners that + * set a pattern per target as each breakpoint is added to a target. + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpointListener + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaTargetPatternBreakpoint extends IJavaLineBreakpoint { + + /** + * Returns the type name pattern this breakpoint uses to identify types in + * which to install itself in the given target + * + * @param target + * debug target + * @return the type name pattern this breakpoint uses to identify types in + * which to install itself in the given target + */ + public String getPattern(IJavaDebugTarget target); + + /** + * Sets the type name pattern this breakpoint uses to identify types in + * which to install itself in the given target + * + * @param target + * debug target + * @param pattern + * type name pattern + * @exception CoreException + * if changing the pattern for this breakpoint fails + */ + public void setPattern(IJavaDebugTarget target, String pattern) + throws CoreException; + + /** + * Returns the source file name in which this breakpoint is set. When this + * breakpoint specifies a source file name, this breakpoint is only + * installed in types whose source file name debug attribute match this + * value. + * + * @return the source file name in which this breakpoint is set + * @exception CoreException + * if unable to access the property from this breakpoint's + * underlying marker + */ + public String getSourceName() throws CoreException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java new file mode 100644 index 0000000000..90d15b5c6a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IFilteredStep; +import org.eclipse.debug.core.model.IThread; + +/** + * A thread in a Java virtual machine. + * + * @see org.eclipse.debug.core.model.IThread + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +@SuppressWarnings("deprecation") +public interface IJavaThread extends IThread, IFilteredStep { + + /** + * Status code indicating a request failed because a thread was not + * suspended. + */ + public static final int ERR_THREAD_NOT_SUSPENDED = 100; + + /** + * Status code indicating a request to perform a message send failed because + * a thread was already performing a message send. + * + * @see IJavaObject#sendMessage(String, String, IJavaValue[], IJavaThread, + * boolean) + * @see IJavaClassType#sendMessage(String, String, IJavaValue[], + * IJavaThread) + * @see IJavaClassType#newInstance(String, IJavaValue[], IJavaThread) + */ + public static final int ERR_NESTED_METHOD_INVOCATION = 101; + + /** + * Status code indicating a request to perform a message send failed because + * a thread was not suspended by a step or breakpoint event. When a thread + * is suspended explicitly via the suspend() method, it is not + * able to perform method invocations (this is a JDI limitation). + * + * @see IJavaObject#sendMessage(String, String, IJavaValue[], IJavaThread, + * boolean) + * @see IJavaClassType#sendMessage(String, String, IJavaValue[], + * IJavaThread) + * @see IJavaClassType#newInstance(String, IJavaValue[], IJavaThread) + */ + public static final int ERR_INCOMPATIBLE_THREAD_STATE = 102; + + /** + * Returns whether this thread is a system thread. + * + * @return whether this thread is a system thread + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + boolean isSystemThread() throws DebugException; + + /** + * Returns whether any of the stack frames associated with this thread are running code in the VM that is out of synch with the code in the + * workspace. + * + * @return whether this thread is out of synch with the workspace. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + * @since 2.0 + */ + boolean isOutOfSynch() throws DebugException; + + /** + * Returns whether this thread may be running code in the VM that is out of synch with the code in the workspace. + * + * @return whether this thread may be out of synch with the workspace. + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The DebugException's status code contains the underlying exception responsible for the + * failure.
      • + *
      + * @since 2.0 + */ + boolean mayBeOutOfSynch() throws DebugException; + + /** + * Returns whether this thread is currently performing an evaluation. + * + * @return whether this thread is currently performing an evaluation + * @since 2.0 + */ + boolean isPerformingEvaluation(); + + /** + * Returns the name of the thread group this thread belongs to, or + * null if none. + * + * @return thread group name, or null if none + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + String getThreadGroupName() throws DebugException; + + /** + * Returns a variable with the given name, or null if unable to + * resolve a variable with the name, or if this thread is not currently + * suspended. + *

      + * Variable lookup works only when a thread is suspended. Lookup is + * performed in all stack frames, in a top-down order, returning the first + * successful match, or null if no match is found. + *

      + * + * @param variableName + * the name of the variable to search for + * @return a variable, or null if none + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + IJavaVariable findVariable(String variableName) throws DebugException; + + /** + * Invokes the given evaluation with the specified progress monitor. This + * thread fires a resume event when the evaluation begins, and a suspend + * event when the evaluation completes or throws an exception. The events + * are given a detail as specified by evaluationDetail (one of + * DebugEvent.EVALUATION or + * DebugEvent.EVALUATION_IMPLICIT). + *

      + * Since 3.5, the org.eclipse.jdt.debug.breakpointListeners + * extension point supports evaluation execution during a listener call + * back. Suspend and resume events are not fired during listener call backs. + * Unspecified model specific events are fired. + *

      + * + * @param evaluation + * the evaluation to perform + * @param monitor + * progress monitor (may be null + * @param evaluationDetail + * one of DebugEvent.EVALUATION or + * DebugEvent.EVALUATION_IMPLICIT + * @param hitBreakpoints + * whether or not breakpoints should be honored in this thread + * during the evaluation. If false, breakpoints hit + * in this thread during the evaluation will be ignored. + * @exception DebugException + * if an exception occurs performing the evaluation + * @since 2.0 + */ + public void runEvaluation(IEvaluationRunnable evaluation, + IProgressMonitor monitor, int evaluationDetail, + boolean hitBreakpoints) throws DebugException; + + /** + * Queues the given runnable with the list of runnables associated with this + * thread. Runnables are executed asynchronously in a separate thread. This + * method should be used to execute any code which performs an operation + * like a method invocation. + * + * @param runnable + * the runnable to execute. + * @since 2.1 + */ + public void queueRunnable(Runnable runnable); + + /** + * Attempts to terminate the currently executing + * IEvaluationRunnable in this thread, if any. + * + * Evaluations may be composed of a series of instructions. Terminating an + * evaluation means stopping the evaluation after the current instruction + * completes. A single instruction (such as a method invocation) cannot be + * interrupted. + * + * @exception DebugException + * if an exception occurs while terminating the evaluation. + * @since 2.1 + */ + public void terminateEvaluation() throws DebugException; + + /** + * Returns whether the currently executing IEvaluationRunnable + * supports termination. An IEvaluationRunnable supports termination if it + * implements ITerminate + * + * @return whether the current evaluation supports termination + * @since 2.1 + */ + public boolean canTerminateEvaluation(); + + /** + * Returns a Java object for the monitor for which this thread is currently + * waiting or null. + * + * @return IJavaObject the contended monitor object or null if + * this thread is not waiting on a monitor. + * @exception DebugException + * if an exception occurs while retrieving the contended + * monitor. + * @since 2.1 + */ + public IJavaObject getContendedMonitor() throws DebugException; + + /** + * Returns the monitors owned by this thread or null if this + * thread owns no monitors. + * + * @return the owned monitors + * @exception DebugException + * if an exception occurs while retrieving the owned monitors + * of this thread. + * @since 2.1 + */ + public IJavaObject[] getOwnedMonitors() throws DebugException; + + /** + * Returns whether this threads owns at least one monitor. + * + * @return boolean whether this thread owns a monitor + * @exception DebugException + * if an exception occurs determining if there are owned + * monitors. + * @since 2.1 + */ + public boolean hasOwnedMonitors() throws DebugException; + + /** + * Request to stops this thread with the given exception.
      + * The result will be the same as calling java.lang.Thread#stop(java.lang.Throwable).
      + * If the thread is suspended when the method is called, the thread must be resumed to complete the action.
      + * + * exception must represent an exception. + * + * @param exception + * the exception to throw. + * @exception DebugException + * if the request fails + * @since 3.0 + * @see java.lang.Thread#stop() + */ + public void stop(IJavaObject exception) throws DebugException; + + /** + * Returns the thread group this thread belongs to or null if + * none. + * + * @return thread group or null + * @throws DebugException + * if the thread group cannot be computed + * @since 3.2 + */ + public IJavaThreadGroup getThreadGroup() throws DebugException; + + /** + * Returns whether this thread is a daemon thread. + * + * @return whether this thread is a daemon thread + * @throws DebugException + * if an exception occurs while determining status + * @since 3.3 + */ + public boolean isDaemon() throws DebugException; + + /** + * Returns the number of frames in this thread. + * + * @return number of stack frames + * @throws DebugException + * if an exception occurs while retrieving the count + * @since 3.3 + */ + public int getFrameCount() throws DebugException; + + /** + * Returns the object reference associated with this thread. + * + * @return thread object reference + * @throws DebugException + * if unable to retrieve an object reference + * @since 3.6 + */ + public IJavaObject getThreadObject() throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThreadGroup.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThreadGroup.java new file mode 100644 index 0000000000..34e1885c96 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThreadGroup.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugElement; + +/** + * Represents a thread group in the target VM. + * + * @since 3.2 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaThreadGroup extends IDebugElement { + + /** + * Returns the threads in this thread group. Does not include threads in + * subgroups. + * + * @return threads in this group + * @throws DebugException + * if the request fails + */ + public IJavaThread[] getThreads() throws DebugException; + + /** + * Returns whether this group contains any threads. + * + * @return whether this group contains any threads + * @throws DebugException + * if the request fails + */ + public boolean hasThreads() throws DebugException; + + /** + * Returns the thread group this thread group is contained in or + * null if none. + * + * @return parent thread group or null + * @throws DebugException + * if the request fails + */ + public IJavaThreadGroup getThreadGroup() throws DebugException; + + /** + * Returns whether this thread group contains subgroups. + * + * @return whether this thread group contains subgroups + * @throws DebugException + * if the request fails + */ + public boolean hasThreadGroups() throws DebugException; + + /** + * Returns immediate thread groups contained in this thread. Does not + * include subgroups of immediate groups. + * + * @return thread groups contained in this group + * @throws DebugException + * if the request fails + */ + public IJavaThreadGroup[] getThreadGroups() throws DebugException; + + /** + * Returns the name of this thread group. + * + * @return thread group name + * @throws DebugException + * if the request fails + */ + public String getName() throws DebugException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaType.java new file mode 100644 index 0000000000..269def19b8 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaType.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugElement; + +/** + * The type of a value on a Java debug target - a primitive data type, class, + * interface, or array. + *

      + * Since 3.2, an IJavaType is also a debug element + *

      + * + * @see IJavaValue + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaType extends IDebugElement { + /** + * Returns the JNI-style signature for this type. + * + * @return signature + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public String getSignature() throws DebugException; + + /** + * Returns the name of this type. For example, + * "java.lang.String". + * + * @return the name of this type + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + */ + public String getName() throws DebugException; +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaValue.java new file mode 100644 index 0000000000..07f5adec96 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaValue.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; + +/** + * An object, primitive data type, or array, on a Java virtual machine. + * + * @see org.eclipse.debug.core.model.IValue + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaValue extends IValue { + /** + * Returns the JNI-style signature for the type of this value, or + * null if the value is null. + * + * @return signature, or null if signature is null + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • The type associated with the signature is not yet + * loaded
      • + *
      + */ + public String getSignature() throws DebugException; + + /** + * Returns the generic signature as defined in the JVM specification for the + * type of this value. Returns null if the value is + * null, or if the type of this value is not a generic type. + * + * @return signature, or null if generic signature not + * available + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • The type associated with the signature is not yet + * loaded
      • + *
      + * @since 3.1 + */ + public String getGenericSignature() throws DebugException; + + /** + * Returns the type of this value, or null if this value + * represents the null value + * + * @return the type of this value, or null if this value + * represents the null value + * @throws DebugException + * if the request fails + * + * @since 2.0 + */ + public IJavaType getJavaType() throws DebugException; + + /** + * Returns whether this value represents null. + * + * @return whether this value represents null + * @since 3.5 + */ + public boolean isNull(); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaVariable.java new file mode 100644 index 0000000000..1e68855cfa --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaVariable.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; + +/** + * A local variable, field slot, or receiver (this) in a Java virtual machine. + * + * @see org.eclipse.debug.core.model.IVariable + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaVariable extends IVariable, IJavaModifiers { + + /** + * Returns the JNI-style signature for the declared type of this variable, + * or null if the type associated with the signature is not yet + * loaded in the target VM. + * + * @return signature, or null if not accessible + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • The type associated with the signature is not yet + * loaded
      • + *
      + */ + public String getSignature() throws DebugException; + + /** + * Returns the generic signature as defined in the JVM specification for the + * declared type of this variable, or null if the type + * associated with the signature is not yet loaded in the target VM. Returns + * the same value as #getSignature() if the declared type of this variable + * is not a generic type. + * + * @return generic signature, or null if not accessible + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • The type associated with the signature is not yet + * loaded
      • + *
      + * @since 3.1 + */ + public String getGenericSignature() throws DebugException; + + /** + * Returns the declared type of this variable. + * + * @return the declared type of this variable + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      • The type associated with the signature is not yet + * loaded
      • + *
      + * @since 2.0 + */ + public IJavaType getJavaType() throws DebugException; + + /** + * Returns whether this variable is local. + * + * @return whether this variable is a local variable + * @exception DebugException + * if this method fails. Reasons include: + *
        + *
      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
      • + *
      + * @since 2.1 + */ + public boolean isLocal() throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaWatchpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaWatchpoint.java new file mode 100644 index 0000000000..f7e215f6ca --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaWatchpoint.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IWatchpoint; + +/** + * A breakpoint on a field. If a watchpoint is an access watchpoint, it will + * suspend execution when its field is accessed. If a watchpoint is a + * modification watchpoint, it will suspend execution when its field is + * modified. + *

      + * Since 3.1, IJavaWatchpoint also implements + * {@link org.eclipse.debug.core.model.IWatchpoint}. + *

      + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface IJavaWatchpoint extends IJavaLineBreakpoint, IWatchpoint { + /** + * Returns the name of the field associated with this watchpoint + * + * @return field the name of the field on which this watchpoint is installed + * @exception CoreException + * if unable to access the property on this breakpoint's + * underlying marker + */ + public String getFieldName() throws CoreException; + + /** + * Returns whether this breakpoint last suspended in this target due to an + * access (true) or modification (false). + * + * @param target + * the debug target + * + * @return true if this watchpoint last suspended the given + * target due to a field access; false if this + * watchpoint last suspended the given target due to a modification + * access or if this watchpoint hasn't suspended the given target. + */ + public boolean isAccessSuspend(IDebugTarget target); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java new file mode 100644 index 0000000000..3837547ec5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java @@ -0,0 +1,1022 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.debug.core; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaClassPrepareBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaExceptionBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaMethodBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaMethodEntryBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaPatternBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaStratumLineBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaTargetPatternBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaWatchpoint; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.osgi.service.prefs.BackingStoreException; + +import com.sun.jdi.VirtualMachine; + +/** + * Provides utility methods for creating debug targets and breakpoints specific + * to the JDI debug model. + *

      + * To provide access to behavior and information specific to the JDI debug + * model, a set of interfaces are defined which extend the base set of debug + * element interfaces. For example, IJavaStackFrame is declared to + * extend IStackFrame, and provides methods specific to this debug + * model. The specialized interfaces are also available as adapters from the + * debug elements generated from this model. + *

      + *

      + * This class provides static utility methods only. + *

      + * + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + */ +@SuppressWarnings("deprecation") +public class JDIDebugModel { + + /** + * Preference key for default JDI request timeout value. + */ + public static final String PREF_REQUEST_TIMEOUT = getPluginIdentifier() + + ".PREF_REQUEST_TIMEOUT"; //$NON-NLS-1$ + + /** + * Preference key for specifying if hot code replace should be performed + * when a replacement class file contains compilation errors. + */ + public static final String PREF_HCR_WITH_COMPILATION_ERRORS = getPluginIdentifier() + + ".PREF_HCR_WITH_COMPILATION_ERRORS"; //$NON-NLS-1$ + + /** + * The default JDI request timeout when no preference is set. + */ + public static final int DEF_REQUEST_TIMEOUT = 3000; + + /** + * Boolean preference controlling whether breakpoints are hit during an + * evaluation operation. If true, breakpoints will be hit as usual during + * evaluations. If false, the breakpoint manager will be automatically + * disabled during evaluations. + * + * @since 3.0 + */ + public static final String PREF_SUSPEND_FOR_BREAKPOINTS_DURING_EVALUATION = getPluginIdentifier() + + ".suspend_for_breakpoints_during_evaluation"; //$NON-NLS-1$ + + /** + * Boolean preference controlling whether to not install (filter) breakpoints for types existing multiple times + * in source projects and not related to the current debug session. + * @since 3.10 + */ + public static final String PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES = getPluginIdentifier() + + ".do_not_install_breakpoints_from_unrelated_sources"; //$NON-NLS-1$ + + /** + * Preference key for specifying if the value returned or thrown should be displayed as variable after a "step return" or "step over" (if + * supported by the vm) + * @since 3.11 + */ + public static final String PREF_SHOW_STEP_RESULT = getPluginIdentifier() + + ".PREF_SHOW_STEP_RESULT"; //$NON-NLS-1$ + + /** + * Preference key for specifying if PREF_SHOW_STEP_RESULT is respected for remote debugging. + * + * @since 3.15 + */ + public static final String PREF_SHOW_STEP_RESULT_REMOTE = getPluginIdentifier() + ".PREF_SHOW_STEP_RESULT_REMOTE"; //$NON-NLS-1$ + + /** + * Preference key for specifying if the timeout (in ms) after which the return method result of a step operation is not observed any longer (0 + * means no timeout, a negative value means: simulate a timeout condition). + * + * @since 3.12 + */ + public static final String PREF_SHOW_STEP_TIMEOUT = getPluginIdentifier() + ".PREF_SHOW_STEP_TIMEOUT"; //$NON-NLS-1$ + + /** + * The default value for {@link #PREF_SHOW_STEP_TIMEOUT} timeout when no preference is set. + * + * @since 3.12 + */ + public static final int DEF_SHOW_STEP_TIMEOUT = 7000; + + /** + * The preference key for the behavior of exception breakpoint hits recurring for the same exception instance. + * + * @see org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint.SuspendOnRecurrenceStrategy + * + * @since 3.14 + */ + public static final String PREF_SUSPEND_ON_RECURRENCE_STRATEGY = getPluginIdentifier() + ".PREF_SUSPEND_ON_RECURRENCE_STRATEGY"; //$NON-NLS-1$ + + /** + * Launch attribute, use ILaunch.setAttribute to set it to "true", to disable hot code replace for an individual launch. + * + * @since 3.17 + */ + public static final String DISABLE_HCR_LAUNCH_ATTRIBUTE = getPluginIdentifier() + ".disable.hcr"; //$NON-NLS-1$ + + /** + * Not to be instantiated. + */ + private JDIDebugModel() { + super(); + } + + /** + * Creates and returns a debug target for the given VM, with the specified + * name, and associates the debug target with the given process for console + * I/O. The allow terminate flag specifies whether the debug target will + * support termination (ITerminate). The allow disconnect flag + * specifies whether the debug target will support disconnection ( + * IDisconnect). Launching the actual VM is a client + * responsibility. By default, the target VM will be resumed on startup. The + * debug target is added to the given launch. + * + * @param launch + * the launch the new debug target will be contained in + * @param vm + * the VM to create a debug target for + * @param name + * the name to associate with the VM, which will be returned from + * IDebugTarget.getName. If null the + * name will be retrieved from the underlying VM. + * @param process + * the process to associate with the debug target, which will be + * returned from IDebugTarget.getProcess + * @param allowTerminate + * whether the target will support termination + * @param allowDisconnect + * whether the target will support disconnection + * @return a debug target + * @see org.eclipse.debug.core.model.ITerminate + * @see org.eclipse.debug.core.model.IDisconnect + * @since 2.0 + */ + public static IDebugTarget newDebugTarget(ILaunch launch, + VirtualMachine vm, String name, IProcess process, + boolean allowTerminate, boolean allowDisconnect) { + return newDebugTarget(launch, vm, name, process, allowTerminate, + allowDisconnect, true); + } + + /** + * Creates and returns a debug target for the given VM, with the specified + * name, and associates the debug target with the given process for console + * I/O. The allow terminate flag specifies whether the debug target will + * support termination (ITerminate). The allow disconnect flag + * specifies whether the debug target will support disconnection ( + * IDisconnect). The resume flag specifies if the target VM + * should be resumed on startup (has no effect if the VM was already running + * when the connection to the VM was established). Launching the actual VM + * is a client responsibility. The debug target is added to the given + * launch. + * + * @param launch + * the launch the new debug target will be contained in + * @param vm + * the VM to create a debug target for + * @param name + * the name to associate with the VM, which will be returned from + * IDebugTarget.getName. If null the + * name will be retrieved from the underlying VM. + * @param process + * the process to associate with the debug target, which will be + * returned from IDebugTarget.getProcess + * @param allowTerminate + * whether the target will support termination + * @param allowDisconnect + * whether the target will support disconnection + * @param resume + * whether the target is to be resumed on startup. Has no effect + * if the target was already running when the connection to the + * VM was established. + * @return a debug target + * @see org.eclipse.debug.core.model.ITerminate + * @see org.eclipse.debug.core.model.IDisconnect + * @since 2.0 + */ + public static IDebugTarget newDebugTarget(final ILaunch launch, + final VirtualMachine vm, final String name, final IProcess process, + final boolean allowTerminate, final boolean allowDisconnect, + final boolean resume) { + final IJavaDebugTarget[] target = new IJavaDebugTarget[1]; + IWorkspaceRunnable r = m -> target[0] = new JDIDebugTarget(launch, vm, name, + allowTerminate, allowDisconnect, process, resume); + try { + ResourcesPlugin.getWorkspace().run(r, null, 0, null); + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + return target[0]; + } + + /** + * Returns the identifier for the JDI debug model plug-in + * + * @return plug-in identifier + */ + public static String getPluginIdentifier() { + return JDIDebugPlugin.getUniqueIdentifier(); + } + + /** + * Registers the given listener for hot code replace notifications. Has no + * effect if an identical listener is already registered. + *

      + * Note that since 3.6, if an {@link IJavaDebugTarget} has hot code replace + * listeners registered with it directly, listeners registered with this + * class are not notified of hot code replace events for that target. This + * allows a target to have custom hot code replace notification behavior. + *

      + * + * @param listener + * hot code replace listener + * @see IJavaHotCodeReplaceListener + * @see IJavaDebugTarget#addHotCodeReplaceListener(IJavaHotCodeReplaceListener) + * @since 2.0 + */ + public static void addHotCodeReplaceListener( + IJavaHotCodeReplaceListener listener) { + JDIDebugPlugin.getDefault().addHotCodeReplaceListener(listener); + } + + /** + * Unregisters the given listener for hot code replace notifications. Has no + * effect if an identical listener is not already registered. + * + * @param listener + * hot code replace listener + * @see IJavaHotCodeReplaceListener + * @since 2.0 + */ + public static void removeHotCodeReplaceListener( + IJavaHotCodeReplaceListener listener) { + JDIDebugPlugin.getDefault().removeHotCodeReplaceListener(listener); + } + + /** + * Registers the given listener for breakpoint notifications. Has no effect + * if an identical listener is already registered. + * + * @param listener + * breakpoint listener + * @see IJavaBreakpointListener + * @since 2.0 + */ + public static void addJavaBreakpointListener( + IJavaBreakpointListener listener) { + JDIDebugPlugin.getDefault().addJavaBreakpointListener(listener); + } + + /** + * Unregisters the given listener for breakpoint notifications. Has no + * effect if an identical listener is not already registered. + * + * @param listener + * breakpoint listener + * @see IJavaBreakpointListener + * @since 2.0 + */ + public static void removeJavaBreakpointListener( + IJavaBreakpointListener listener) { + JDIDebugPlugin.getDefault().removeJavaBreakpointListener(listener); + } + + /** + * Creates and returns a line breakpoint in the type with the given name, at + * the given line number. The marker associated with the breakpoint will be + * created on the specified resource. If a character range within the line + * is known, it may be specified by charStart/charEnd. If hitCount is > 0, + * the breakpoint will suspend execution when it is "hit" the specified + * number of times. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param typeName + * the fully qualified name of the type the breakpoint is to be + * installed in. If the breakpoint is to be installed in an inner + * type, it is sufficient to provide the name of the top level + * enclosing type. If an inner class name is specified, it should + * be formatted as the associated class file name (i.e. with + * $). For example, + * example.SomeClass$InnerType, could be specified, + * but example.SomeClass is sufficient. + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file in which the + * breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a line breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @since 2.0 + */ + public static IJavaLineBreakpoint createLineBreakpoint(IResource resource, + String typeName, int lineNumber, int charStart, int charEnd, + int hitCount, boolean register, Map attributes) + throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaLineBreakpoint(resource, typeName, lineNumber, + charStart, charEnd, hitCount, register, attributes); + } + + /** + * Creates and returns a pattern breakpoint for the given resource at the + * given line number, which is installed in all classes whose fully + * qualified name matches the given pattern. If hitCount > 0, the breakpoint + * will suspend execution when it is "hit" the specified number of times. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param sourceName + * the name of the source file in which the breakpoint is set, or + * null. When specified, the pattern breakpoint will + * install itself in classes that have a source file name debug + * attribute that matches this value, and satisfies the class + * name pattern. + * @param pattern + * the class name pattern in which the pattern breakpoint should + * be installed. The pattern breakpoint will install itself in + * every class which matches the pattern. + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file in which the + * breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a pattern breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @deprecated use createStratumBreakpoint instead + */ + @Deprecated + public static IJavaPatternBreakpoint createPatternBreakpoint( + IResource resource, String sourceName, String pattern, + int lineNumber, int charStart, int charEnd, int hitCount, + boolean register, Map attributes) throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaPatternBreakpoint(resource, sourceName, pattern, + lineNumber, charStart, charEnd, hitCount, register, attributes); + } + + /** + * Creates and returns a line breakpoint identified by its source file name + * and/or path, and stratum that it is relative to. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param stratum + * the stratum in which the source name, source path and line + * number are relative, or null. If + * null or if the specified stratum is not defined + * for a type, the source name, source path and line number are + * relative to the type's default stratum. + * @param sourceName + * the simple name of the source file in which the breakpoint is + * set, or null. The breakpoint will install itself + * in classes that have a source file name debug attribute that + * matches this value in the specified stratum, and satisfies the + * class name pattern and source path attribute. When + * null, the source file name debug attribute is not + * considered. + * @param sourcePath + * the qualified source file name in which the breakpoint is set, + * or null. The breakpoint will install itself in + * classes that have a source file path in the specified stratum + * that matches this value, and satisfies the class name pattern + * and source name attribute. When null, the source + * path attribute is not considered. + * @param classNamePattern + * the class name pattern to which the breakpoint should be + * restricted, or null. The breakpoint will install + * itself in each type that matches this class name pattern, with + * a satisfying source name and source path. Patterns may begin + * or end with '*', which matches 0 or more characters. A pattern + * that does not contain a '*' is equivalent to a pattern ending + * in '*'. Specifying null, or an empty string is + * the equivalent to "*". Multiple patterns can be specified by + * delimiting the patterns with a comma - e.g. "x.y.z,a.b.c". + * When multiple patterns are specified, The breakpoint will + * install itself in each of the types that match any of the + * specified class pattern, with a satisfying source name and + * source path. + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file (stratum) in + * which the breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a stratum breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @since 3.0 + */ + public static IJavaStratumLineBreakpoint createStratumBreakpoint( + IResource resource, String stratum, String sourceName, + String sourcePath, String classNamePattern, int lineNumber, + int charStart, int charEnd, int hitCount, boolean register, + Map attributes) throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaStratumLineBreakpoint(resource, stratum, sourceName, + sourcePath, classNamePattern, lineNumber, charStart, charEnd, + hitCount, register, attributes); + } + + /** + * Creates and returns a target pattern breakpoint for the given resource at + * the given line number. Clients must set the class name pattern per target + * for this type of breakpoint. If hitCount > 0, the breakpoint will suspend + * execution when it is "hit" the specified number of times. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param sourceName + * the name of the source file in which the breakpoint is set, or + * null. When specified, the pattern breakpoint will + * install itself in classes that have a source file name debug + * attribute that matches this value, and satisfies the class + * name pattern. + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file in which the + * breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a target pattern breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + */ + public static IJavaTargetPatternBreakpoint createTargetPatternBreakpoint( + IResource resource, String sourceName, int lineNumber, + int charStart, int charEnd, int hitCount, boolean register, + Map attributes) throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaTargetPatternBreakpoint(resource, sourceName, + lineNumber, charStart, charEnd, hitCount, register, attributes); + } + + /** + * Creates and returns an exception breakpoint for an exception with the + * given name. The marker associated with the breakpoint will be created on + * the specified resource. Caught and uncaught specify where the exception + * should cause thread suspensions - that is, in caught and/or uncaught + * locations. Checked indicates if the given exception is a checked + * exception. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param exceptionName + * the fully qualified name of the exception for which to create + * the breakpoint + * @param caught + * whether to suspend in caught locations + * @param uncaught + * whether to suspend in uncaught locations + * @param checked + * whether the exception is a checked exception (i.e. compiler + * detected) + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation or + * null if none. + * @return an exception breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @since 2.0 + */ + public static IJavaExceptionBreakpoint createExceptionBreakpoint( + IResource resource, String exceptionName, boolean caught, + boolean uncaught, boolean checked, boolean register, Map attributes) + throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaExceptionBreakpoint(resource, exceptionName, caught, + uncaught, checked, register, attributes); + } + + /** + * Creates and returns a watchpoint on a field with the given name in a type + * with the given name. The marker associated with the breakpoint will be + * created on the specified resource. If hitCount > 0, the breakpoint will + * suspend execution when it is "hit" the specified number of times. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param typeName + * the fully qualified name of the type the breakpoint is to be + * installed in. If the breakpoint is to be installed in an inner + * type, it is sufficient to provide the name of the top level + * enclosing type. If an inner class name is specified, it should + * be formatted as the associated class file name (i.e. with + * $). For example, + * example.SomeClass$InnerType, could be specified, + * but example.SomeClass is sufficient. + * @param fieldName + * the name of the field on which to suspend (on access or + * modification) + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file in which the + * breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a watchpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The + * CoreException's status contains the underlying exception + * responsible for the failure.
      • + *
      + * @since 2.0 + */ + public static IJavaWatchpoint createWatchpoint(IResource resource, + String typeName, String fieldName, int lineNumber, int charStart, + int charEnd, int hitCount, boolean register, Map attributes) + throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaWatchpoint(resource, typeName, fieldName, lineNumber, + charStart, charEnd, hitCount, register, attributes); + } + + /** + * Creates and returns a method breakpoint with the specified criteria. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param typePattern + * the pattern specifying the fully qualified name of type(s) + * this breakpoint suspends execution in. Patterns are limited to + * exact matches and patterns that begin or end with '*'. + * @param methodName + * the name of the method(s) this breakpoint suspends execution + * in, or null if this breakpoint does not suspend + * execution based on method name + * @param methodSignature + * the signature of the method(s) this breakpoint suspends + * execution in, or null if this breakpoint does not + * suspend execution based on method signature + * @param entry + * whether this breakpoint causes execution to suspend on entry + * of methods + * @param exit + * whether this breakpoint causes execution to suspend on exit of + * methods + * @param nativeOnly + * whether this breakpoint causes execution to suspend on + * entry/exit of native methods only + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file in which the + * breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a method breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @since 2.0 + */ + public static IJavaMethodBreakpoint createMethodBreakpoint( + IResource resource, String typePattern, String methodName, + String methodSignature, boolean entry, boolean exit, + boolean nativeOnly, int lineNumber, int charStart, int charEnd, + int hitCount, boolean register, Map attributes) + throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaMethodBreakpoint(resource, typePattern, methodName, + methodSignature, entry, exit, nativeOnly, lineNumber, + charStart, charEnd, hitCount, register, attributes); + } + + /** + * Creates and returns a method entry breakpoint with the specified + * criteria. A method entry breakpoint will only be installed for methods + * that have executable code (i.e. will not work for native methods). + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param typeName + * the fully qualified name of type this breakpoint suspends + * execution in. + * @param methodName + * the name of the method this breakpoint suspends execution in + * @param methodSignature + * the signature of the method this breakpoint suspends execution + * in + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file in which the + * breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a method entry breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @since 2.0 + */ + public static IJavaMethodEntryBreakpoint createMethodEntryBreakpoint( + IResource resource, String typeName, String methodName, + String methodSignature, int lineNumber, int charStart, int charEnd, + int hitCount, boolean register, Map attributes) + throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaMethodEntryBreakpoint(resource, typeName, methodName, + methodSignature, lineNumber, charStart, charEnd, hitCount, + register, attributes); + } + + /** + * Returns a Java line breakpoint that is already registered with the + * breakpoint manager for a type with the given name at the given line + * number. + * + * @param typeName + * fully qualified type name + * @param lineNumber + * line number + * @return a Java line breakpoint that is already registered with the + * breakpoint manager for a type with the given name at the given + * line number or null if no such breakpoint is + * registered + * @exception CoreException + * if unable to retrieve the associated marker attributes + * (line number). + */ + public static IJavaLineBreakpoint lineBreakpointExists(String typeName, + int lineNumber) throws CoreException { + String modelId = getPluginIdentifier(); + String markerType = JavaLineBreakpoint.getMarkerType(); + IBreakpointManager manager = DebugPlugin.getDefault() + .getBreakpointManager(); + for (IBreakpoint bp : manager.getBreakpoints(modelId)) { + if (!(bp instanceof IJavaLineBreakpoint)) { + continue; + } + IJavaLineBreakpoint breakpoint = (IJavaLineBreakpoint) bp; + IMarker marker = breakpoint.getMarker(); + if (marker != null && marker.exists() + && marker.getType().equals(markerType)) { + String breakpointTypeName = breakpoint.getTypeName(); + if (JavaDebugUtils.typeNamesEqual(breakpointTypeName, typeName) || (breakpointTypeName != null && breakpointTypeName.startsWith(typeName + '$'))) { + if (breakpoint.getLineNumber() == lineNumber) { + return breakpoint; + } + } + } + } + return null; + } + + /** + * Returns a Java line breakpoint that is already registered with the + * breakpoint manager for a type with the given name at the given line + * number in the given resource. + * + * @param resource + * the resource + * @param typeName + * fully qualified type name + * @param lineNumber + * line number + * @return a Java line breakpoint that is already registered with the + * breakpoint manager for a type with the given name at the given + * line number or null if no such breakpoint is + * registered + * @exception CoreException + * if unable to retrieve the associated marker attributes + * (line number). + * @since 3.1 + */ + public static IJavaLineBreakpoint lineBreakpointExists(IResource resource, + String typeName, int lineNumber) throws CoreException { + String modelId = getPluginIdentifier(); + String markerType = JavaLineBreakpoint.getMarkerType(); + IBreakpointManager manager = DebugPlugin.getDefault() + .getBreakpointManager(); + for (IBreakpoint bp : manager.getBreakpoints(modelId)) { + if (!(bp instanceof IJavaLineBreakpoint)) { + continue; + } + IJavaLineBreakpoint breakpoint = (IJavaLineBreakpoint) bp; + IMarker marker = breakpoint.getMarker(); + if (marker != null && marker.exists() + && marker.getType().equals(markerType)) { + String breakpointTypeName = breakpoint.getTypeName(); + if ((JavaDebugUtils.typeNamesEqual(breakpointTypeName, typeName) || (breakpointTypeName != null && breakpointTypeName.startsWith(typeName + '$'))) + && breakpoint.getLineNumber() == lineNumber + && resource.equals(marker.getResource())) { + return breakpoint; + } + } + } + return null; + } + + /** + * Returns the preference store for this plug-in or null if the store is not available.
      + *
      + * The Preferences class has been deprecated and clients should directly be using the InstanceScope node for JDIDebugPlugin rather than this + * convenience method.
      + *
      + * For example: + * + *
      +	 * IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
      +	 * if(node != null) {
      +	 * 	...
      +	 * }
      +	 * 
      + * + * @return the preference store for this plug-in + * @since 2.0 + * @deprecated the {@link Preferences} class has been deprecated, use the {@link IEclipsePreferences} accessors instead + */ + @Deprecated + public static Preferences getPreferences() { + JDIDebugPlugin deflt = JDIDebugPlugin.getDefault(); + if (deflt != null) { + return deflt.getPluginPreferences(); + } + return null; + } + + /** + * Saves the preference store for this plug-in. + *

      + * The Preferences class has been deprecated and clients should directly be using the + * InstanceScope node for JDIDebugPlugin rather than this convenience method. + *

      + * For example: + *
      +	 * IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
      +	 * if(node != null) {
      +	 * 	try {
      +	 * 		node.flush();
      +	 * 	} catch (BackingStoreException e) {
      +	 * 		log(e);
      +	 * 	}
      +	 * }
      +	 * 
      + * @since 2.0 + * @deprecated the {@link Preferences} class has been deprecated, use the {@link IEclipsePreferences} accessors instead + */ + @Deprecated + public static void savePreferences() { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(node != null) { + try { + node.flush(); + } catch (BackingStoreException bse) { + JDIDebugPlugin.log(bse); + } + } + } + + /** + * Creates and returns a class prepare breakpoint for a type with the given + * name. The marker associated with the breakpoint will be created on the + * specified resource. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param typeName + * the fully qualified name of the type for which to create the + * breakpoint + * @param memberType + * one of TYPE_CLASS or TYPE_INTERFACE + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation or + * null if none. + * @return a class prepare breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
        + *
      • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
      • + *
      + * @since 3.0 + */ + public static IJavaClassPrepareBreakpoint createClassPrepareBreakpoint( + IResource resource, String typeName, int memberType, int charStart, + int charEnd, boolean register, Map attributes) throws CoreException { + if (attributes == null) { + attributes = new HashMap<>(10); + } + return new JavaClassPrepareBreakpoint(resource, typeName, memberType, + charStart, charEnd, register, attributes); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/package.html b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/package.html new file mode 100644 index 0000000000..8c4b555cdf --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/package.html @@ -0,0 +1,22 @@ + + + + + +Java Debug Model + + + + +Provides an implementation of a debug model based on JPDA (Java Platform Debug Architecture). + +

      Package Specification

      + +

      This package provides a set of classes and interfaces that implement a debug + model based on JPDA/JDI (Java Debug Interface). It provides a set of interfaces + that extend the base set of debug element interfaces to provide access to Java + specific attributes and behavior. This model defines and provides utilities + for creating line breakpoints, method entry breakpoints, exception breakpoints, + and field watchpoints.

      + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java new file mode 100644 index 0000000000..544b006325 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java @@ -0,0 +1,448 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.jdi.internal.event.ExceptionEventImpl; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventIterator; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.ThreadDeathEvent; +import com.sun.jdi.event.VMDeathEvent; +import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.event.VMStartEvent; +import com.sun.jdi.request.EventRequest; + +/** + * Dispatches events generated by an underlying VM. There is one event + * dispatcher per JDI debug target. + *

      + * Event listeners register with a debug target to handle specific event + * requests. A debug target forwards event listeners and requests to its event + * dispatcher. As events are received from the underlying VM, those listeners + * that registered to handle the specific events are notified. + *

      + *

      + * Events are processed in event sets. It is possible that one event can trigger + * more than one event request to be processed. In such cases all event requests + * triggered by that one event are processed, and each event listener votes on + * whether the thread in which the event occurred should be resumed. A thread is + * only resumed in if all event handlers agree that the thread should be + * resumed. + *

      + */ + +public class EventDispatcher implements Runnable { + /** + * The debug target this event dispatcher belongs to. + */ + private final JDIDebugTarget fTarget; + /** + * Whether this dispatcher is shutdown. + */ + private volatile boolean fShutdown; + /** + * Table of event listeners. Table is a mapping of EventRequest + * to IJDIEventListener. + */ + private final HashMap fEventHandlers; + + /** + * Queue of debug model events to fire, created when processing events on + * the target VM. Keyed by event sets, processed independently. + */ + private final Map> fSetToQueue = new HashMap<>(); + + /** + * Constructs a new event dispatcher listening for events originating from + * the specified debug target's underlying VM. + * + * @param target + * the target this event dispatcher belongs to + */ + public EventDispatcher(JDIDebugTarget target) { + fEventHandlers = new HashMap<>(10); + fTarget = target; + fShutdown = false; + } + + /** + * Dispatch the given event set. + * + * @param eventSet + * events to dispatch + */ + private void dispatch(EventSet eventSet) { + if (isShutdown()) { + return; + } + if (JDIDebugOptions.DEBUG_JDI_EVENTS) { + EventIterator eventIter = eventSet.eventIterator(); + StringBuilder buf = new StringBuilder("JDI Event Set: {\n"); //$NON-NLS-1$ + while (eventIter.hasNext()) { + buf.append(eventIter.next()); + if (eventIter.hasNext()) { + buf.append(", "); //$NON-NLS-1$ + } + } + buf.append("}\n"); //$NON-NLS-1$ + JDIDebugOptions.trace(buf.toString()); + } + EventIterator iter = eventSet.eventIterator(); + IJDIEventListener[] listeners = new IJDIEventListener[eventSet.size()]; + boolean vote = false; + boolean resume = true; + int index = -1; + List deferredEvents = null; + while (iter.hasNext()) { + index++; + if (isShutdown()) { + return; + } + Event event = iter.nextEvent(); + if (event == null) { + continue; + } + // Dispatch events to registered listeners, if any + IJDIEventListener listener = fEventHandlers.get(event.request()); + listeners[index] = listener; + if (listener != null) { + if (listener instanceof IJavaLineBreakpoint) { + // Event dispatch to conditional breakpoints is deferred + // until after + // other listeners vote. + try { + if (((IJavaLineBreakpoint) listener).isConditionEnabled()) { + if (deferredEvents == null) { + deferredEvents = new ArrayList<>(5); + } + deferredEvents.add(event); + continue; + } + } catch (CoreException exception) { + JDIDebugPlugin.log(exception); + } + } + vote = true; + try { + try { + resume = listener.handleEvent(event, fTarget, !resume, eventSet) && resume; + } finally { + enableGCForExceptionEvent(event); + } + } catch (Throwable t) { + logHandleEventError(listener, event, t); + } + continue; + } + + // Dispatch VM start/end events + if (event instanceof VMDeathEvent) { + fTarget.handleVMDeath((VMDeathEvent) event); + shutdown(); // stop listening for events + } else if (event instanceof VMDisconnectEvent) { + fTarget.handleVMDisconnect((VMDisconnectEvent) event); + shutdown(); // stop listening for events + } else if (event instanceof VMStartEvent) { + fTarget.handleVMStart((VMStartEvent) event); + } else { + // not handled + } + } + + // process deferred conditional breakpoint events + if (deferredEvents != null) { + Iterator deferredIter = deferredEvents.iterator(); + while (deferredIter.hasNext()) { + if (isShutdown()) { + return; + } + Event event = deferredIter.next(); + if (event == null) { + continue; + } + // Dispatch events to registered listeners, if any + IJDIEventListener listener = fEventHandlers + .get(event.request()); + if (listener != null) { + vote = true; + try { + resume = listener.handleEvent(event, fTarget, !resume, eventSet) && resume; + } catch (Throwable t) { + logHandleEventError(listener, event, t); + } finally { + enableGCForExceptionEvent(event); + } + continue; + } + } + } + + List threadDeathRunnables = new ArrayList<>(); + + // notify handlers of the end result + index = -1; + iter = eventSet.eventIterator(); + while (iter.hasNext()) { + index++; + Event event = iter.nextEvent(); + // notify registered listener, if any + IJDIEventListener listener = listeners[index]; + if (listener != null) { + if (event instanceof ThreadDeathEvent) { + final boolean res = resume; + threadDeathRunnables.add(() -> listener.eventSetComplete(event, fTarget, !res, eventSet)); + } else { + listener.eventSetComplete(event, fTarget, !resume, eventSet); + } + } + } + + // fire queued DEBUG events + fireEvents(eventSet); + + // Queue runnables which will remove terminated threads once other queued events are proceeded + threadDeathRunnables.forEach(runnable -> DebugPlugin.getDefault().asyncExec(runnable)); + + if (vote && resume) { + try { + eventSet.resume(); + } catch (VMDisconnectedException e) { + } catch (RuntimeException e) { + try { + fTarget.targetRequestFailed( + JDIDebugMessages.EventDispatcher_0, e); + } catch (DebugException de) { + JDIDebugPlugin.log(de); + } + } + } + } + + private boolean requiresExpressionEvaluation(EventSet eventSet) { + EventIterator iter = eventSet.eventIterator(); + while (iter.hasNext()) { + Event event = iter.nextEvent(); + if (event == null) { + continue; + } + IJDIEventListener listener = fEventHandlers.get(event.request()); + if (listener instanceof IJavaLineBreakpoint) { + try { + if (((IJavaLineBreakpoint) listener).isConditionEnabled()) { + return true; + } + } + catch (CoreException e) { + return true; // assume the worst + } + } + } + return false; + } + + /** @noreference public for test purposes */ + public abstract class AbstractDispatchJob extends Job { + protected AbstractDispatchJob(String name) { + super(name); + } + + @Override + public boolean belongsTo(Object family) { + return family == EventDispatcher.class || family == EventDispatcher.this; + } + + @Override + public String toString() { + try { + return super.toString() + " for [" + fTarget.getName() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + catch (DebugException e) { + return super.toString(); + } + } + } + + /** + * Continuously reads events that are coming from the event queue, until + * this event dispatcher is shutdown. A debug target starts a thread on this + * method on startup. + * + * @see #shutdown() + */ + @Override + public void run() { + VirtualMachine vm = fTarget.getVM(); + if (vm != null) { + EventQueue q = vm.eventQueue(); + while (!isShutdown()) { + try { + EventSet eventSet; + try { + // Get the next event set. + eventSet = q.remove(1000); + } catch (VMDisconnectedException e) { + break; + } + + if (eventSet != null) { + if (!requiresExpressionEvaluation(eventSet)) { + dispatch(eventSet); + } else { + // 269231 always evaluate expressions in a separate job to avoid deadlocks + Job job = new AbstractDispatchJob("JDI Expression Evaluation Event Dispatch") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + dispatch(eventSet); + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + } + } catch (InterruptedException e) { + break; + } + } + } + } + + /** + * Shutdown this event dispatcher - i.e. causes this event dispatcher to + * stop reading and dispatching events from the event queue. The thread + * associated with this runnable will exit. + */ + public void shutdown() { + fShutdown = true; + Job.getJobManager().cancel(this); + } + + /** + * Returns whether this event dispatcher has been shutdown. + * + * @return whether this event dispatcher has been shutdown + */ + private boolean isShutdown() { + return fShutdown; + } + + /** + * Registers the given listener for with the given event request. When an + * event is received from the underlying VM, that is associated with the + * given event request, the listener will be notified. + * + * @param listener + * the listener to register + * @param request + * the event request associated with events the listener is + * interested in + */ + public void addJDIEventListener(IJDIEventListener listener, + EventRequest request) { + fEventHandlers.put(request, listener); + } + + /** + * De-registers the given listener and event request. The listener will no + * longer be notified of events associated with the request. Listeners are + * responsible for deleting the associated event request if required. + * + * @param listener + * the listener to de-register + * @param request + * the event request to de-register + */ + public void removeJDIEventListener(IJDIEventListener listener, EventRequest request) { + fEventHandlers.remove(request); + } + + /** + * Adds the given event to the queue of debug events to fire when done + * dispatching events from the given event set. + * + * @param event + * the event to queue + * @param set + * event set the event is associated with + */ + public void queue(DebugEvent event, EventSet set) { + synchronized (fSetToQueue) { + List list = fSetToQueue.get(set); + if (list == null) { + list = new ArrayList<>(5); + fSetToQueue.put(set, list); + } + list.add(event); + } + } + + /** + * Fires debug events in the event queue associated with the given event + * set, and clears the queue. + * @param set the set to fire events for + */ + private void fireEvents(EventSet set) { + DebugPlugin plugin = DebugPlugin.getDefault(); + if (plugin != null) { // check that not in the process of shutting down + List list = null; + synchronized (fSetToQueue) { + list = fSetToQueue.remove(set); + } + if (list != null) { + DebugEvent[] events = list.toArray(new DebugEvent[list.size()]); + plugin.fireDebugEventSet(events); + } + } + } + + private void enableGCForExceptionEvent(Event event) { + if (event instanceof ExceptionEventImpl) { + try { + if (fTarget.isAvailable()) { + ((ExceptionEventImpl) event).enableExceptionGC(); + } + } catch (VMDisconnectedException e) { + if (fTarget.isAvailable()) { + JDIDebugPlugin.logError("Failed to enable GC for event: " + event, e); //$NON-NLS-1$ + } + } catch (Throwable t) { + JDIDebugPlugin.logError("Failed to enable GC for event: " + event, t); //$NON-NLS-1$ + } + } + } + + private static void logHandleEventError(IJDIEventListener listener, Event event, Throwable t) { + JDIDebugPlugin.logError("Exception occurred while notifying listener: " + listener + ", with event: " + event, t); //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/HeapWalkingManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/HeapWalkingManager.java new file mode 100644 index 0000000000..b3e8b5feb5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/HeapWalkingManager.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.osgi.service.prefs.BackingStoreException; + +/** + * Controls preferences related to heap walking so that they are available in + * java debug model code, but can be updated through the UI. + * + * @since 3.3 + */ +public class HeapWalkingManager { + + private static HeapWalkingManager fgSingleton; + + /** + * Constructor. Intended to be called by getDefault() + */ + protected HeapWalkingManager() { + } + + /** + * Returns whether the given parent object is a debug element with a debug + * target that supports retrieval of instance and reference information from + * the VM. + * + * @param object + * the object to test, can be null + * @return whether the given object has a debug target that supports heap + * walking + */ + public static boolean supportsHeapWalking(Object object) { + if (object instanceof IDebugElement) { + IDebugTarget target = ((IDebugElement) object).getDebugTarget(); + if (target instanceof IJavaDebugTarget) { + return ((IJavaDebugTarget) target).supportsInstanceRetrieval(); + } else if (target != null) { + Object adapter = target.getAdapter(IJavaDebugTarget.class); + if (adapter instanceof IJavaDebugTarget) { + return ((IJavaDebugTarget) adapter).supportsInstanceRetrieval(); + } + } + } + return false; + } + + /** + * @return the default singleton instance of the manager + */ + public static HeapWalkingManager getDefault() { + if (fgSingleton == null) { + fgSingleton = new HeapWalkingManager(); + } + return fgSingleton; + } + + /** + * @return preference dictating whether to display references as variables + * in variables view. + */ + public boolean isShowReferenceInVarView() { + return Platform.getPreferencesService().getBoolean( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.PREF_SHOW_REFERENCES_IN_VAR_VIEW, + false, + null); + } + + /** + * @return preference dictating the maximum number of references that should + * be displayed to the user + */ + public int getAllReferencesMaxCount() { + return Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.PREF_ALL_REFERENCES_MAX_COUNT, + 100, + null); + } + + /** + * @return preference dictating the maximum number of instances that should + * be displayed to the user + */ + public int getAllInstancesMaxCount() { + return Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.PREF_ALL_INSTANCES_MAX_COUNT, + 100, + null); + } + + /** + * Stores the passed vale in the preference store + * + * @param value + * whether to display references as variables in the variables + * view + */ + public void setShowReferenceInVarView(boolean value) { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(node != null) { + node.putBoolean(JDIDebugPlugin.PREF_SHOW_REFERENCES_IN_VAR_VIEW, value); + try { + node.flush(); + } catch (BackingStoreException e) { + JDIDebugPlugin.log(e); + } + } + } + + /** + * Stores the passed value in the preference store + * + * @param max + * the maximum number of references that should be displayed to + * the user + */ + public void setAllReferencesMaxCount(int max) { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(node != null) { + node.putInt(JDIDebugPlugin.PREF_ALL_REFERENCES_MAX_COUNT, max); + try { + node.flush(); + } catch (BackingStoreException e) { + JDIDebugPlugin.log(e); + } + } + } + + /** + * Stores the passed value in the preference store + * + * @param max + * the maximum number of instances that should be displayed to + * the user + */ + public void setAllInstancesMaxCount(int max) { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(node != null) { + node.putInt(JDIDebugPlugin.PREF_ALL_INSTANCES_MAX_COUNT, max); + try { + node.flush(); + } catch (BackingStoreException e) { + JDIDebugPlugin.log(e); + } + } + } + + /** + * Resets the preferences controlled by this manager to their default + * settings + */ + public void resetToDefaultSettings() { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(node != null) { + node.putBoolean(JDIDebugPlugin.PREF_SHOW_REFERENCES_IN_VAR_VIEW, false); + node.putInt(JDIDebugPlugin.PREF_ALL_REFERENCES_MAX_COUNT, 100); + node.putInt(JDIDebugPlugin.PREF_ALL_INSTANCES_MAX_COUNT, 100); + try { + node.flush(); + } catch (BackingStoreException e) { + JDIDebugPlugin.log(e); + } + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java new file mode 100644 index 0000000000..b1f6c45bc6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.EventRequest; + +/** + * A jdi event listener is notified of events associated with a specific jdi + * event request. A listener registers/deregisters event requests with a debug + * target. + * + * @see JDIDebugTarget#addJDIEventListener(IJDIEventListener, EventRequest) + * @see JDIDebugTarget#removeJDIEventListener(IJDIEventListener, EventRequest) + */ + +public interface IJDIEventListener { + /** + * Handles the given event that this listener has registered for and returns + * whether the thread in which the event occurred should be resumed. All + * event handlers for the events in an event set are given a chance to vote + * on whether the thread should be resumed. If all agree, the thread is + * resumed by the event dispatcher. If any event handler returns + * false the thread in which the event originated is left in a + * suspended state. + *

      + * Event listeners are provided with the current state of the suspend vote. + * For example, this could allow a conditional breakpoint to not bother + * running its evaluation since the vote is already to suspend (if it + * coincides with a step end). + *

      + * + * @param event + * the event to handle + * @param target + * the debug target in which the event occurred + * @param suspendVote + * whether the current vote among event listeners is to suspend + * @param eventSet + * the event set the event is contained in + * @return whether the thread in which the event occurred should be resumed + */ + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet); + + /** + * Notification that all event handlers for an event set have handled their + * associated events and whether the event set will suspend. + * + * @param event + * event the listener was registered for/handled + * @param target + * target in which the event occurred + * @param suspend + * whether the event will cause the event thread to suspend + * @param eventSet + * the event set the event is contained in + */ + public void eventSetComplete(Event event, JDIDebugTarget target, + boolean suspend, EventSet eventSet); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugMessages.java new file mode 100644 index 0000000000..5f54baf82d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugMessages.java @@ -0,0 +1,27 @@ +/********************************************************************** + * Copyright (c) 2004, 2005 IBM Corporation and others.s + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.osgi.util.NLS; + +public class JDIDebugMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.core.JDIDebugMessages";//$NON-NLS-1$ + + public static String EventDispatcher_0; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, JDIDebugMessages.class); + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugMessages.properties new file mode 100644 index 0000000000..018e130aef --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugMessages.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2004, 2005 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +EventDispatcher_0=Exception occurred while resuming event set after event dispatch. diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugOptions.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugOptions.java new file mode 100644 index 0000000000..db077776c2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugOptions.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2009, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Hashtable; + +import org.eclipse.osgi.service.debug.DebugOptions; +import org.eclipse.osgi.service.debug.DebugOptionsListener; +import org.eclipse.osgi.service.debug.DebugTrace; +import org.osgi.framework.BundleContext; + +/** + * Debug flags in options file. + * + * @since 3.5 + */ +public class JDIDebugOptions implements DebugOptionsListener { + + public static final String DEBUG_AST_EVALUATIONS_CALLING_THREADS_FLAG = "org.eclipse.jdt.debug/debug/astEvaluations/callingThreads"; //$NON-NLS-1$ + public static final String DEBUG_AST_EVALUATIONS_FLAG = "org.eclipse.jdt.debug/debug/astEvaluations"; //$NON-NLS-1$ + public static final String DEBUG_JDI_REQUEST_TIMES_FLAG = "org.eclipse.jdt.debug/debug/jdiRequestTimes"; //$NON-NLS-1$ + public static final String DEBUG_JDI_EVENTS_FLAG = "org.eclipse.jdt.debug/debug/jdiEvents"; //$NON-NLS-1$ + public static final String DEBUG_FLAG = "org.eclipse.jdt.debug/debug"; //$NON-NLS-1$ + public static final String DEBUG_JDI_VERBOSE_FLAG = "org.eclipse.jdt.debug/debug/jdi/verbose"; //$NON-NLS-1$ + public static final String DEBUG_JDI_VERBOSE_FILE = "org.eclipse.jdt.debug/debug/jdi/verbose/file"; //$NON-NLS-1$ + + public static boolean DEBUG = false; + public static boolean DEBUG_JDI_EVENTS = false; + public static boolean DEBUG_JDI_REQUEST_TIMES = false; + public static boolean DEBUG_AST_EVAL = false; + public static boolean DEBUG_AST_EVAL_THREAD_TRACE = false; + public static boolean DEBUG_JDI_VEBOSE; + public static String DEBUG_JDI_VEBOSE_FILE; + + /** + * The {@link DebugTrace} object to print to OSGi tracing + * @since 3.8 + */ + private static DebugTrace fgDebugTrace; + + /** + * Constructor + */ + public JDIDebugOptions(BundleContext context) { + Hashtable props = new Hashtable<>(2); + props.put(org.eclipse.osgi.service.debug.DebugOptions.LISTENER_SYMBOLICNAME, JDIDebugPlugin.getUniqueIdentifier()); + context.registerService(DebugOptionsListener.class.getName(), this, props); + } + + // used to format debug messages + public static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(ZoneId.systemDefault()); //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.osgi.service.debug.DebugOptionsListener#optionsChanged(org.eclipse.osgi.service.debug.DebugOptions) + */ + @Override + public void optionsChanged(DebugOptions options) { + fgDebugTrace = options.newDebugTrace(JDIDebugPlugin.getUniqueIdentifier()); + DEBUG = options.getBooleanOption(DEBUG_FLAG, false); + DEBUG_JDI_EVENTS = DEBUG && options.getBooleanOption(DEBUG_JDI_EVENTS_FLAG, false); + DEBUG_JDI_REQUEST_TIMES = DEBUG && options.getBooleanOption(DEBUG_JDI_REQUEST_TIMES_FLAG, false); + DEBUG_AST_EVAL = DEBUG && options.getBooleanOption(DEBUG_AST_EVALUATIONS_FLAG, false); + DEBUG_AST_EVAL_THREAD_TRACE = DEBUG && options.getBooleanOption(DEBUG_AST_EVALUATIONS_CALLING_THREADS_FLAG, false); + DEBUG_JDI_VEBOSE = DEBUG && options.getBooleanOption(DEBUG_JDI_VERBOSE_FLAG, false); + if (DEBUG && DEBUG_JDI_VEBOSE) { + DEBUG_JDI_VEBOSE_FILE = options.getOption(DEBUG_JDI_VERBOSE_FILE); + } + } + + /** + * Prints the given message to the OSGi tracing (if started) + * @param option the option or null + * @param message the message to print or null + * @param throwable the {@link Throwable} or null + * @since 3.8 + */ + public static void trace(String option, String message, Throwable throwable) { + if(fgDebugTrace != null) { + fgDebugTrace.trace(option, message, throwable); + } + } + + /** + * Prints the given message to the OSGi tracing (if enabled) + * + * @param message the message or null + * @since 3.8 + */ + public static void trace(String message) { + trace(null, message, null); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java new file mode 100644 index 0000000000..dc24b2f0b0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java @@ -0,0 +1,819 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.core.resources.ISaveContext; +import org.eclipse.core.resources.ISaveParticipant; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.jdi.Bootstrap; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.IJavaBreakpointListener; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; +import org.eclipse.jdt.internal.debug.core.breakpoints.BreakpointListenerManager; +import org.eclipse.jdt.internal.debug.core.hcr.JavaHotCodeReplaceManager; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.osgi.framework.BundleContext; +import org.osgi.service.prefs.BackingStoreException; + +import com.sun.jdi.VirtualMachineManager; + +/** + * The plug-in class for the JDI Debug Model plug-in. + */ +public class JDIDebugPlugin extends Plugin implements IEclipsePreferences.IPreferenceChangeListener { + + /** + * Boolean preference controlling if hot code replace is enabled. + * + * @since 3.11 + */ + public static final String PREF_ENABLE_HCR = JDIDebugPlugin + .getUniqueIdentifier() + ".enable_hcr"; //$NON-NLS-1$ + + /** + * integer preference controlling if we should, by default, suspend the VM + * instead of the thread + * + * @since 3.2 + */ + public static final String PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY = JDIDebugPlugin + .getUniqueIdentifier() + ".default_breakpoint_suspend_policy"; //$NON-NLS-1$ + + /** + * integer preference controlling which default suspend option to set on new + * watchpoints + * + * @since 3.3.1 + */ + public static final String PREF_DEFAULT_WATCHPOINT_SUSPEND_POLICY = JDIDebugPlugin + .getUniqueIdentifier() + "default_watchpoint_suspend_policy"; //$NON-NLS-1$ + + /** + * Boolean preference controlling if references should be displayed as + * variables in the variables and expressions view + * + * @since 3.3 + */ + public static final String PREF_SHOW_REFERENCES_IN_VAR_VIEW = JDIDebugPlugin + .getUniqueIdentifier() + ".show_references_in_var_view"; //$NON-NLS-1$ + + /** + * Integer preference determining the maximum number of references that + * should be returned to the user when displaying reference information + * + * @since 3.3 + */ + public static final String PREF_ALL_REFERENCES_MAX_COUNT = JDIDebugPlugin + .getUniqueIdentifier() + "._all_references_max_count"; //$NON-NLS-1$ + + /** + * Integer preference determining the maximum number of instances that + * should be returned to the user when displaying instance information + * + * @since 3.3 + */ + public static final String PREF_ALL_INSTANCES_MAX_COUNT = JDIDebugPlugin + .getUniqueIdentifier() + ".all_instances_max_count"; //$NON-NLS-1$ + + /** + * Boolean preference controlling if advanced sourcelookup is enabled. + * + * @since 3.11 + */ + public static final String PREF_ENABLE_ADVANCED_SOURCELOOKUP = JDIDebugPlugin + .getUniqueIdentifier() + ".enable_advanced_sourcelookup"; //$NON-NLS-1$ + + /** + * Extension point for java logical structures. + * + * @since 3.1 + */ + public static final String EXTENSION_POINT_JAVA_LOGICAL_STRUCTURES = "javaLogicalStructures"; //$NON-NLS-1$ + + /** + * Extension point for java breakpoint action delegates. + * + * @since 3.5 + */ + public static final String EXTENSION_POINT_JAVA_BREAKPOINT_LISTENERS = "breakpointListeners"; //$NON-NLS-1$ + + /** + * Status code indicating an unexpected error. + */ + public static final int ERROR = 120; + + /** + * Status code indicating an unexpected internal error. Internal errors + * should never be displayed to the user in dialogs or status text. Internal + * error messages are not translated. + */ + public static final int INTERNAL_ERROR = 125; + + private static JDIDebugPlugin fgPlugin; + + /** + * Breakpoint listener list. + */ + private ListenerList fBreakpointListeners = null; + + /** + * Breakpoint notification types + */ + private static final int ADDING = 1; + private static final int INSTALLED = 2; + private static final int REMOVED = 3; + private static final int COMPILATION_ERRORS = 4; + private static final int RUNTIME_EXCEPTION = 5; + + /** + * Whether this plug-in is in trace mode. Extra messages are logged in trace + * mode. + */ + private final boolean fTrace = false; + + /** + * Detected (speculated) JDI interface version + */ + private static int[] fJDIVersion = null; + + /** + * Status code used by the debug model to retrieve a thread to use for + * evaluations, via a status handler. A status handler is contributed by the + * Java debug UI. When not present, the debug model uses any suspended + * thread. + * + * @since 3.0 + */ + public static final int INFO_EVALUATION_THREAD = 110; + + /** + * Associated status to retrieve a thread. + */ + public static final IStatus STATUS_GET_EVALUATION_THREAD = new Status( + IStatus.INFO, getUniqueIdentifier(), INFO_EVALUATION_THREAD, + "Provides thread context for an evaluation", null); //$NON-NLS-1$ + + /** + * Status code used by the debug model to retrieve a frame to use for + * evaluations, via a status handler. A status handler is contributed by the + * Java debug UI. When not present, the debug model uses any suspended + * thread. + * + * @since 3.0 + */ + public static final int INFO_EVALUATION_STACK_FRAME = 111; + + /** + * Associated status to retrieve a stack frame. + */ + public static IStatus STATUS_GET_EVALUATION_FRAME = new Status( + IStatus.INFO, getUniqueIdentifier(), INFO_EVALUATION_STACK_FRAME, + "Provides thread context for an evaluation", null); //$NON-NLS-1$ + + /** + * Manages breakpoint listener extensions + */ + private BreakpointListenerManager fJavaBreakpointManager; + + /** + * Returns whether the debug UI plug-in is in trace mode. + * + * @return whether the debug UI plug-in is in trace mode + */ + public boolean isTraceMode() { + return fTrace; + } + + /** + * Logs the given message if in trace mode. + * + * @param message the string to log + */ + public static void logTraceMessage(String message) { + if (getDefault().isTraceMode()) { + IStatus s = new Status(IStatus.WARNING, + JDIDebugPlugin.getUniqueIdentifier(), INTERNAL_ERROR, + message, null); + getDefault().getLog().log(s); + } + } + + /** + * Return the singleton instance of the JDI Debug Model plug-in. + * + * @return the singleton instance of JDIDebugPlugin + */ + public static JDIDebugPlugin getDefault() { + return fgPlugin; + } + + /** + * Convenience method which returns the unique identifier of this plug-in. + *

      + * Value is: org.eclipse.jdt.debug + * @return the unique id of the JDT debug core plug-in + */ + public static String getUniqueIdentifier() { + return "org.eclipse.jdt.debug"; //$NON-NLS-1$ + } + + /** + * Returns the detected version of JDI support. This is intended to + * distinguish between clients that support JDI 1.4 methods like hot code + * replace. + * + * @return an array of version numbers, major followed by minor + * @since 2.1 + */ + public static int[] getJDIVersion() { + if (fJDIVersion == null) { + fJDIVersion = new int[2]; + VirtualMachineManager mgr = Bootstrap.virtualMachineManager(); + fJDIVersion[0] = mgr.majorInterfaceVersion(); + fJDIVersion[1] = mgr.minorInterfaceVersion(); + } + return fJDIVersion; + } + + /** + * Returns if the JDI version being used is greater than or equal to the + * given version (major, minor). + * + * @param version the array of version number identifiers to compare + * @return boolean + */ + public static boolean isJdiVersionGreaterThanOrEqual(int[] version) { + int[] runningVersion = getJDIVersion(); + return runningVersion[0] > version[0] || (runningVersion[0] == version[0] && runningVersion[1] >= version[1]); + } + + public JDIDebugPlugin() { + super(); + fgPlugin = this; + } + + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + new JDIDebugOptions(context); + ResourcesPlugin.getWorkspace().addSaveParticipant(getUniqueIdentifier(), + new ISaveParticipant() { + @Override + public void doneSaving(ISaveContext c) { + } + + @Override + public void prepareToSave(ISaveContext c) + throws CoreException { + } + + @Override + public void rollback(ISaveContext c) { + } + + @Override + public void saving(ISaveContext c) throws CoreException { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(getUniqueIdentifier()); + if(node != null) { + try { + node.flush(); + } catch (BackingStoreException bse) { + log(bse); + } + } + } + }); + JavaHotCodeReplaceManager.getDefault().startup(); + fBreakpointListeners = new ListenerList<>(); + fJavaBreakpointManager = new BreakpointListenerManager(); + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(getUniqueIdentifier()); + if(node != null) { + node.addPreferenceChangeListener(this); + } + } + + /** + * Adds the given hot code replace listener to the collection of listeners + * that will be notified by the hot code replace manager in this plug-in. + * @param listener the listener to add + */ + public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) { + JavaHotCodeReplaceManager.getDefault().addHotCodeReplaceListener(listener); + } + + /** + * Removes the given hot code replace listener from the collection of + * listeners that will be notified by the hot code replace manager in this + * plug-in. + * @param listener the listener to remove + */ + public void removeHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) { + JavaHotCodeReplaceManager.getDefault().removeHotCodeReplaceListener(listener); + } + + /** + * Shutdown the HCR manager and the Java debug targets. + * + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + * @see org.eclipse.core.runtime.Plugin#shutdown() + */ + @Override + public void stop(BundleContext context) throws Exception { + try { + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(getUniqueIdentifier()); + if(node != null) { + node.removePreferenceChangeListener(this); + } + JavaHotCodeReplaceManager.getDefault().shutdown(); + ILaunchManager launchManager = DebugPlugin.getDefault() + .getLaunchManager(); + IDebugTarget[] targets = launchManager.getDebugTargets(); + for (IDebugTarget target : targets) { + if (target instanceof JDIDebugTarget) { + ((JDIDebugTarget) target).shutdown(); + } + } + fBreakpointListeners = null; + ResourcesPlugin.getWorkspace().removeSaveParticipant(getUniqueIdentifier()); + } finally { + fgPlugin = null; + super.stop(context); + } + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) + */ + @Override + public void preferenceChange(PreferenceChangeEvent event) { + if (event.getKey().equals(JDIDebugModel.PREF_REQUEST_TIMEOUT)) { + int value = Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_REQUEST_TIMEOUT, + JDIDebugModel.DEF_REQUEST_TIMEOUT, + null); + IDebugTarget[] targets = DebugPlugin.getDefault().getLaunchManager().getDebugTargets(); + for (IDebugTarget target : targets) { + if (target instanceof IJavaDebugTarget) { + ((IJavaDebugTarget) target).setRequestTimeout(value); + } + } + } + } + + /** + * Logs the specified {@link Throwable} with this plug-in's log. + * + * @param t {@link Throwable} to log + */ + public static void logError(String message, Throwable t) { + Throwable top = t; + if (t instanceof CoreException) { + CoreException de = (CoreException) t; + IStatus status = de.getStatus(); + if (status.getException() != null) { + top = status.getException(); + } + } + // this message is intentionally not internationalized, as an exception + // may be due to the resource bundle itself + log(new Status(IStatus.ERROR, getUniqueIdentifier(), INTERNAL_ERROR, + message, top)); + } + + /** + * Logs the specified {@link Throwable} with this plug-in's log. + * + * @param t + * {@link Throwable} to log + */ + public static void log(Throwable t) { + logError("Internal error logged from JDI Debug: ", t); //$NON-NLS-1$ + } + + /** + * Logs the specified status with this plug-in's log. + * + * @param status + * status to log + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * @param breakpoint the breakpoint with problems + * @param errors the error set to notify about + * @see IJavaBreakpointListener#breakpointHasRuntimeException(IJavaLineBreakpoint, + * DebugException) + */ + public void fireBreakpointHasCompilationErrors(IJavaLineBreakpoint breakpoint, Message[] errors) { + getBreakpointNotifier().notify(null, breakpoint, COMPILATION_ERRORS, errors, null); + } + + /** + * @param breakpoint the breakpoint with problems + * @param exception the exception to notify about + * @see IJavaBreakpointListener#breakpointHasCompilationErrors(IJavaLineBreakpoint, Message[]) + */ + public void fireBreakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, DebugException exception) { + getBreakpointNotifier().notify(null, breakpoint, RUNTIME_EXCEPTION, null, exception); + } + + /** + * Adds the given breakpoint listener to the JDI debug model. + * + * @param listener + * breakpoint listener + */ + public void addJavaBreakpointListener(IJavaBreakpointListener listener) { + fBreakpointListeners.add(listener); + } + + /** + * Removes the given breakpoint listener from the JDI debug model. + * + * @param listener + * breakpoint listener + */ + public void removeJavaBreakpointListener(IJavaBreakpointListener listener) { + fBreakpointListeners.remove(listener); + } + + /** + * Notifies listeners that the given breakpoint is about to be added. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + */ + public void fireBreakpointAdding(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + getBreakpointNotifier().notify(target, breakpoint, ADDING, null, null); + } + + /** + * Notifies listeners that the given breakpoint has been installed. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + */ + public void fireBreakpointInstalled(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + getBreakpointNotifier().notify(target, breakpoint, INSTALLED, null, + null); + } + + /** + * Notifies listeners that the given breakpoint has been removed. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + */ + public void fireBreakpointRemoved(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + getBreakpointNotifier().notify(target, breakpoint, REMOVED, null, null); + } + + /** + * Notifies listeners that the given breakpoint has been hit. Returns + * whether the thread should suspend. + * + * @param thread the current thread context + * @param breakpoint Java breakpoint + * @return if the thread should suspend + */ + public boolean fireBreakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) { + return getHitNotifier().notifyHit(thread, breakpoint); + } + + /** + * Notifies listeners that the given breakpoint is about to be installed in + * the given type. Returns whether the breakpoint should be installed. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + * @param type + * the type the breakpoint is about to be installed in + * @return whether the breakpoint should be installed + */ + public boolean fireInstalling(IJavaDebugTarget target, + IJavaBreakpoint breakpoint, IJavaType type) { + return getInstallingNotifier().notifyInstalling(target, breakpoint, + type); + } + + private BreakpointNotifier getBreakpointNotifier() { + return new BreakpointNotifier(); + } + + abstract class AbstractNotifier implements ISafeRunnable { + + private IJavaBreakpoint fBreakpoint; + private IJavaBreakpointListener fListener; + + /** + * Iterates through listeners calling this notifier's safe runnable. + * @param breakpoint the breakpoint to notify about + */ + protected void notifyListeners(IJavaBreakpoint breakpoint) { + fBreakpoint = breakpoint; + String[] ids = null; + try { + ids = breakpoint.getBreakpointListeners(); + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + // breakpoint specific listener extensions + if (ids != null && ids.length > 0) { + for (String id : ids) { + fListener = fJavaBreakpointManager + .getBreakpointListener(id); + if (fListener != null) { + SafeRunner.run(this); + } + } + } + // global listener extensions + IJavaBreakpointListener[] global = fJavaBreakpointManager + .getGlobalListeners(); + if (global.length > 0) { + for (IJavaBreakpointListener element : global) { + fListener = element; + SafeRunner.run(this); + } + } + // programmatic global listeners + for (IJavaBreakpointListener listener : fBreakpointListeners) { + fListener = listener; + SafeRunner.run(this); + } + fBreakpoint = null; + fListener = null; + } + + /** + * Returns the breakpoint for which notification is proceeding or + * null if not in notification. + * + * @return breakpoint or null + */ + protected IJavaBreakpoint getBreakpoint() { + return fBreakpoint; + } + + /** + * Returns the listener for which notification is proceeding or + * null if not in notification loop. + * + * @return breakpoint listener or null + */ + protected IJavaBreakpointListener getListener() { + return fListener; + } + } + + class BreakpointNotifier extends AbstractNotifier { + + private IJavaDebugTarget fTarget; + private int fKind; + private Message[] fErrors; + private DebugException fException; + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) + */ + @Override + public void handleException(Throwable exception) { + } + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + @Override + public void run() throws Exception { + switch (fKind) { + case ADDING: + getListener().addingBreakpoint(fTarget, getBreakpoint()); + break; + case INSTALLED: + getListener().breakpointInstalled(fTarget, getBreakpoint()); + break; + case REMOVED: + getListener().breakpointRemoved(fTarget, getBreakpoint()); + break; + case COMPILATION_ERRORS: + getListener().breakpointHasCompilationErrors( + (IJavaLineBreakpoint) getBreakpoint(), fErrors); + break; + case RUNTIME_EXCEPTION: + getListener().breakpointHasRuntimeException( + (IJavaLineBreakpoint) getBreakpoint(), fException); + break; + } + } + + /** + * Notifies listeners of the given addition, install, or remove. + * + * @param target + * debug target + * @param breakpoint + * the associated breakpoint + * @param kind + * one of ADDED, REMOVED, INSTALLED + * @param errors + * associated errors, or null if none + * @param exception + * associated exception, or null if none + */ + public void notify(IJavaDebugTarget target, IJavaBreakpoint breakpoint, + int kind, Message[] errors, DebugException exception) { + fTarget = target; + fKind = kind; + fErrors = errors; + fException = exception; + notifyListeners(breakpoint); + fTarget = null; + fErrors = null; + fException = null; + } + } + + private InstallingNotifier getInstallingNotifier() { + return new InstallingNotifier(); + } + + class InstallingNotifier extends AbstractNotifier { + + private IJavaDebugTarget fTarget; + private IJavaType fType; + private int fInstall; + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) + */ + @Override + public void handleException(Throwable exception) { + } + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + @Override + public void run() throws Exception { + fInstall = fInstall + | getListener().installingBreakpoint(fTarget, + getBreakpoint(), fType); + } + + private void dispose() { + fTarget = null; + fType = null; + } + + /** + * Notifies listeners that the given breakpoint is about to be installed + * in the given type. Returns whether the breakpoint should be + * installed. + * + * @param target + * Java debug target + * @param breakpoint + * Java breakpoint + * @param type + * the type the breakpoint is about to be installed in + * @return whether the breakpoint should be installed + */ + public boolean notifyInstalling(IJavaDebugTarget target, + IJavaBreakpoint breakpoint, IJavaType type) { + fTarget = target; + fType = type; + fInstall = IJavaBreakpointListener.DONT_CARE; + notifyListeners(breakpoint); + dispose(); + // install if any listener voted to install, or if no one voted to + // not install + return (fInstall & IJavaBreakpointListener.INSTALL) > 0 + || (fInstall & IJavaBreakpointListener.DONT_INSTALL) == 0; + } + } + + private HitNotifier getHitNotifier() { + return new HitNotifier(); + } + + class HitNotifier extends AbstractNotifier { + + private IJavaThread fThread; + private int fSuspend; + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) + */ + @Override + public void handleException(Throwable exception) { + } + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + @Override + public void run() throws Exception { + if (fThread instanceof JDIThread) { + if (((JDIThread) fThread).hasClientRequestedSuspend()) { + // abort notification to breakpoint listeners if a client + // suspend + // request is received + fSuspend = fSuspend | IJavaBreakpointListener.SUSPEND; + return; + } + } + fSuspend = fSuspend + | getListener().breakpointHit(fThread, getBreakpoint()); + } + + /** + * Notifies listeners that the given breakpoint has been hit. Returns + * whether the thread should suspend. + * + * @param thread + * thread in which the breakpoint was hit + * @param breakpoint + * Java breakpoint + * @return whether the thread should suspend + */ + public boolean notifyHit(IJavaThread thread, IJavaBreakpoint breakpoint) { + fThread = thread; + fSuspend = IJavaBreakpointListener.DONT_CARE; + notifyListeners(breakpoint); + fThread = null; + // Suspend if any listener voted to suspend or no one voted + // "don't suspend" + return (fSuspend & IJavaBreakpointListener.SUSPEND) > 0 + || (fSuspend & IJavaBreakpointListener.DONT_SUSPEND) == 0; + } + } + + /** + * Returns an evaluation engine for the given project in the given debug + * target or null if target does not have a IJavaDebugTarget + * that is a JDIDebugTarget implementation. + * + * @param project java project + * @param target the debug target + * @return evaluation engine or null + */ + public IAstEvaluationEngine getEvaluationEngine(IJavaProject project, + IJavaDebugTarget target) { + // get adapter for those that wrapper us + IJavaDebugTarget javaTarget = target + .getAdapter(IJavaDebugTarget.class); + if (javaTarget instanceof JDIDebugTarget) { + return ((JDIDebugTarget) javaTarget).getEvaluationEngine(project); + } + return null; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java new file mode 100644 index 0000000000..e2a3e767c6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.JDIDebugModel; + +public class JDIDebugPluginPreferenceInitializer extends + AbstractPreferenceInitializer { + + public JDIDebugPluginPreferenceInitializer() { + super(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer# + * initializeDefaultPreferences() + */ + @Override + public void initializeDefaultPreferences() { + IEclipsePreferences node = DefaultScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + node.putBoolean(JDIDebugPlugin.PREF_ENABLE_HCR, true); + node.putInt(JDIDebugModel.PREF_REQUEST_TIMEOUT, JDIDebugModel.DEF_REQUEST_TIMEOUT); + node.putBoolean(JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, true); + node.putBoolean(JDIDebugModel.PREF_SUSPEND_FOR_BREAKPOINTS_DURING_EVALUATION, true); + node.putInt(JDIDebugPlugin.PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY, IJavaBreakpoint.SUSPEND_THREAD); + // 0 is the first index, meaning both access and modification + node.putInt(JDIDebugPlugin.PREF_DEFAULT_WATCHPOINT_SUSPEND_POLICY, 0); + node.putBoolean(JDIDebugPlugin.PREF_SHOW_REFERENCES_IN_VAR_VIEW, false); + node.putInt(JDIDebugPlugin.PREF_ALL_REFERENCES_MAX_COUNT, 100); + node.putInt(JDIDebugPlugin.PREF_ALL_INSTANCES_MAX_COUNT, 100); + node.putBoolean(JDIDebugModel.PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES, true); + node.putBoolean(JDIDebugModel.PREF_SHOW_STEP_RESULT, true); + node.putBoolean(JDIDebugModel.PREF_SHOW_STEP_RESULT_REMOTE, false); + node.putInt(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT); + node.putBoolean(JDIDebugPlugin.PREF_ENABLE_ADVANCED_SOURCELOOKUP, true); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaDebugPropertyTester.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaDebugPropertyTester.java new file mode 100644 index 0000000000..fbe2b104cc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaDebugPropertyTester.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import org.eclipse.core.expressions.PropertyTester; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.jdt.debug.core.IJavaStackFrame; + +/** + * Tests properties for java debug elements + */ +public class JavaDebugPropertyTester extends PropertyTester { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.expressions.IPropertyTester#test(java.lang.Object, + * java.lang.String, java.lang.Object[], java.lang.Object) + */ + @Override + public boolean test(Object receiver, String property, Object[] args, + Object expectedValue) { + if (property.equals("isMultiStrata")) { //$NON-NLS-1$ + if (receiver instanceof IStackFrame) { + IJavaStackFrame frame = ((IStackFrame) receiver) + .getAdapter(IJavaStackFrame.class); + if (frame != null) { + try { + return frame.getReferenceType().getAvailableStrata().length > 1; + } catch (DebugException e) { + } + } + } + } + return false; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaDebugUtils.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaDebugUtils.java new file mode 100644 index 0000000000..38e55d78b7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JavaDebugUtils.java @@ -0,0 +1,517 @@ +/******************************************************************************* + * Copyright (c) 2005, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IOrdinaryClassFile; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; + +import com.sun.jdi.VMDisconnectedException; + +/** + * A Utilities class. + * + * @since 3.2 + */ +public class JavaDebugUtils { + + // The value must match org.eclipse.jdi.internal.VirtualMachineImpl#JAVA_STRATUM_NAME} + public static final String JAVA_STRATUM = "Java"; //$NON-NLS-1$ + + /** + * Resolves and returns a type from the Java model that corresponds to the + * declaring type of the given stack frame, or null if none. + * + * @param frame + * frame to resolve declaring type for + * @return corresponding Java model type or null + * @exception CoreException + * if an exception occurs during the resolution + * @since 3.2 + */ + public static IType resolveDeclaringType(IJavaStackFrame frame) + throws CoreException { + IJavaElement javaElement = resolveJavaElement(frame, frame.getLaunch()); + if (javaElement != null) { + return resolveType(frame.getDeclaringTypeName(), javaElement); + } + return null; + } + + /** + * Resolves and returns a type from the Java model that corresponds to the + * type of the given value, or null if none. + * + * @param value + * value to resolve type for + * @return corresponding Java model type or null + * @exception CoreException + * if an exception occurs during the resolution + */ + public static IType resolveType(IJavaValue value) throws CoreException { + IJavaElement javaElement = resolveJavaElement(value, value.getLaunch()); + if (javaElement != null) { + return resolveType(value.getJavaType().getName(), javaElement); + } + return null; + } + + /** + * Resolves and returns the Java model type associated with the given Java + * debug type, or null if none. + * + * @param type + * Java debug model type + * @return Java model type or null + * @throws CoreException if resolving the type fails + */ + public static IType resolveType(IJavaType type) throws CoreException { + IJavaElement element = resolveJavaElement(type, type.getLaunch()); + if (element != null) { + return resolveType(type.getName(), element); + } + return null; + } + + /** + * Returns the source name associated with the given object, or + * null if none. + * + * @param object + * an object with an IJavaStackFrame adapter, an + * IJavaValue or an IJavaType + * @return the source name associated with the given object, or + * null if none + * @exception CoreException + * if unable to retrieve the source name + */ + public static String getSourceName(Object object) throws CoreException { + if (object instanceof String) { + // assume it's a file name + return (String) object; + } + IJavaStackFrame frame = null; + if (object instanceof IAdaptable) { + frame = ((IAdaptable) object) + .getAdapter(IJavaStackFrame.class); + } + String typeName = null; + try { + if (frame != null) { + if (frame.isObsolete()) { + return null; + } + String sourceName = frame.getSourcePath(); + // TODO: this may break fix to bug 21518 + if (sourceName == null) { + // no debug attributes, guess at source name + typeName = frame.getDeclaringTypeName(); + } else { + return sourceName; + } + } else { + if (object instanceof IJavaValue) { + // look at its type + object = ((IJavaValue) object).getJavaType(); + } + if (object instanceof IJavaReferenceType) { + IJavaReferenceType refType = (IJavaReferenceType) object; + IJavaDebugTarget target = ((IJavaDebugTarget) refType.getDebugTarget()); + String[] sourcePaths = refType.getSourcePaths(target.getDefaultStratum()); + if (sourcePaths != null && sourcePaths.length > 0) { + return sourcePaths[0]; + } + } + if (object instanceof IJavaType) { + typeName = ((IJavaType) object).getName(); + } + } + } catch (DebugException e) { + int code = e.getStatus().getCode(); + if (code == IJavaThread.ERR_THREAD_NOT_SUSPENDED + || code == IJavaStackFrame.ERR_INVALID_STACK_FRAME + || e.getStatus().getException() instanceof VMDisconnectedException) { + return null; + } + throw e; + } + if (typeName != null) { + return generateSourceName(typeName); + } + return null; + } + + /** + * Generates and returns a source file path based on a qualified type name. + * For example, when java.lang.String is provided, the returned + * source name is java/lang/String.java. + * + * @param qualifiedTypeName + * fully qualified type name that may contain inner types denoted + * with $ character + * @return a source file path corresponding to the type name + */ + public static String generateSourceName(String qualifiedTypeName) { + int index = qualifiedTypeName.lastIndexOf('.'); + if (index < 0) { + index = 0; + } + qualifiedTypeName = qualifiedTypeName.replace('.', File.separatorChar); + index = qualifiedTypeName.indexOf('$'); + if (index >= 0) { + qualifiedTypeName = qualifiedTypeName.substring(0, index); + } + if (qualifiedTypeName.length() == 0) { + // likely a proxy class (see bug 40815) + qualifiedTypeName = null; + } else { + qualifiedTypeName = qualifiedTypeName + ".java"; //$NON-NLS-1$ + } + return qualifiedTypeName; + } + + /** + * Resolves the type corresponding to the given name contained in the given + * top-level Java element (class file, compilation unit, or type). + * + * @param qualifiedName + * fully qualified type name + * @param javaElement + * java element containing the type + * @return type + */ + private static IType resolveType(final String qualifiedName, + IJavaElement javaElement) { + IType type = null; + String[] typeNames = getNestedTypeNames(qualifiedName); + if (javaElement instanceof IOrdinaryClassFile) { + type = ((IOrdinaryClassFile) javaElement).getType(); + } else if (javaElement instanceof ICompilationUnit) { + type = ((ICompilationUnit) javaElement).getType(typeNames[0]); + } else if (javaElement instanceof IType) { + type = (IType) javaElement; + } + if (type != null) { + for (int i = 1; i < typeNames.length; i++) { + String innerTypeName = typeNames[i]; + + class ResultException extends RuntimeException { + private static final long serialVersionUID = 1L; + private final IType fResult; + + public ResultException(IType result) { + fResult = result; + } + } + if (innerTypeName.length() > 0) { + try { + Integer.parseInt(innerTypeName.substring(0, 1)); // throws NFE if not an integer + // perform expensive lookup for anonymous types: + ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); + parser.setResolveBindings(true); + parser.setSource(type.getTypeRoot()); + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + cu.accept(new ASTVisitor(false) { + @Override + public boolean visit(AnonymousClassDeclaration node) { + ITypeBinding binding = node.resolveBinding(); + if (binding == null) { + return false; + } + if (qualifiedName.equals(binding.getBinaryName())) { + throw new ResultException((IType) binding.getJavaElement()); + } + return true; + } + + @Override + public boolean visit(TypeDeclaration node) { + ITypeBinding binding = node.resolveBinding(); + if (binding == null) { + return false; + } + if (qualifiedName.equals(binding.getBinaryName())) { + throw new ResultException((IType) binding.getJavaElement()); + } + return true; + } + }); + return type; // return enclosing type if exact type not + // found + } catch (NumberFormatException e) { + // normal nested type, continue + } catch (IllegalStateException e) { + return type; // binary class without source + } catch (ResultException e) { + return e.fResult; + } + } + type = type.getType(innerTypeName); + } + } + return type; + } + + /** + * Returns the Java element corresponding to the given object or + * null if none, in the context of the given launch. + * + * @param launch + * provides source locator + * @param object + * object to resolve Java model element for + * @return corresponding Java element or null + * @throws CoreException if an exception occurs + */ + public static IJavaElement resolveJavaElement(Object object, ILaunch launch) throws CoreException { + Object sourceElement = resolveSourceElement(object, launch); + IJavaElement javaElement = getJavaElement(sourceElement); + if (javaElement == null) { + // fallback if default stratum does not provide a Java element + sourceElement = resolveSourceElement(object, JAVA_STRATUM, launch); + javaElement = getJavaElement(sourceElement); + } + return javaElement; + } + + /** + * Returns the {@link IJavaElement} associated with the given source element + * or null if none. + * + * @param sourceElement + * a java element, object that adapts to a java element, or a + * resource + * @return corresponding {@link IJavaElement} or null + * @since 3.4.0 + */ + public static IJavaElement getJavaElement(Object sourceElement) { + IJavaElement javaElement = null; + if (sourceElement instanceof IJavaElement) { + javaElement = (IJavaElement) sourceElement; + } else if (sourceElement instanceof IAdaptable) { + javaElement = ((IAdaptable) sourceElement).getAdapter(IJavaElement.class); + } + if (javaElement == null && sourceElement instanceof IResource) { + javaElement = JavaCore.create((IResource) sourceElement); + } + if (javaElement == null) { + return null; + } + if (!javaElement.exists()) { + return null; + } + return javaElement; + } + + /** + * Returns the source element corresponding to the given object or null if none, in the context of the given launch. + * + * @param launch + * provides source locator + * @param object + * object to resolve source element for + * @return corresponding source element or null + * @throws CoreException + * if an exception occurs + */ + public static Object resolveSourceElement(Object object, ILaunch launch) throws CoreException { + return resolveSourceElement(object, null, launch); + } + + /** + * Returns the source element corresponding to the given object in the given stratum or null if none, in the context of the given + * launch. + * + * @param launch + * provides source locator + * @param object + * object to resolve source element for + * @param stratum + * the stratum to use + * @return corresponding source element or null + * @throws CoreException + * if an exception occurs + */ + public static Object resolveSourceElement(Object object, String stratum, ILaunch launch) throws CoreException { + ISourceLocator sourceLocator = launch.getSourceLocator(); + if (stratum != null && object instanceof IDebugElement) { + IDebugTarget debugTarget = ((IDebugElement) object).getDebugTarget(); + if (debugTarget instanceof IJavaDebugTarget) { + IJavaDebugTarget javaDebugTarget = (IJavaDebugTarget) debugTarget; + String def = javaDebugTarget.getDefaultStratum(); + try { + javaDebugTarget.setDefaultStratum(stratum); + return doSourceLookup(object, sourceLocator); + } + finally { + javaDebugTarget.setDefaultStratum(def); + } + } + } + return doSourceLookup(object, sourceLocator); + } + + private static Object doSourceLookup(Object object, ISourceLocator sourceLocator) { + if (sourceLocator instanceof ISourceLookupDirector) { + ISourceLookupDirector director = (ISourceLookupDirector) sourceLocator; + return director.getSourceElement(object); + } + return null; + } + + /** + * Resolves the {@link IJavaProject} within the context of the given {@link IJavaStackFrame} + * + * @param frame + * @return the {@link IJavaProject} or null + * @since 3.8.0 + */ + public static IJavaProject resolveJavaProject(IJavaStackFrame frame) { + ILaunch launch = frame.getLaunch(); + if(launch != null) { + try { + Object sourceElement = resolveSourceElement(frame, launch); + IJavaElement element = getJavaElement(sourceElement); + if (element == null) { + Object sourceElement1 = resolveSourceElement(frame, JAVA_STRATUM, launch); + if (sourceElement1 != null){ + sourceElement = sourceElement1; + element = getJavaElement(sourceElement); + } + } + if(element != null) { + return element.getJavaProject(); + } + // If Source element is not a Java element + if (sourceElement instanceof IResource) { + IJavaProject project = JavaCore.create(((IResource) sourceElement).getProject()); + if (project.exists()) { + return project; + } + } + } + catch(CoreException ce) { + //do nothing, return null + } + } + return null; + } + + /** + * Returns an array of simple type names that are part of the given type's + * qualified name. For example, if the given name is x.y.A$B, + * an array with ["A", "B"] is returned. + * + * @param typeName + * fully qualified type name + * @return array of nested type names + */ + private static String[] getNestedTypeNames(String typeName) { + int index = typeName.lastIndexOf('.'); + if (index >= 0) { + typeName = typeName.substring(index + 1); + } + index = typeName.indexOf('$'); + List list = new ArrayList<>(1); + while (index >= 0) { + list.add(typeName.substring(0, index)); + typeName = typeName.substring(index + 1); + index = typeName.indexOf('$'); + } + list.add(typeName); + return list.toArray(new String[list.size()]); + } + + /** + * Returns the class file or compilation unit containing the given fully + * qualified name in the specified project. All registered java like file + * extensions are considered. + * + * @param qualifiedTypeName + * fully qualified type name + * @param project + * project to search in + * @return class file or compilation unit or null + * @throws CoreException if an exception occurs + */ + public static IJavaElement findElement(String qualifiedTypeName, IJavaProject project) throws CoreException { + String[] javaLikeExtensions = JavaCore.getJavaLikeExtensions(); + String path = qualifiedTypeName; + int pos = path.indexOf('$'); + if (pos != -1) { + path = path.substring(0, pos); + } + path = path.replace('.', IPath.SEPARATOR); + path += "."; //$NON-NLS-1$ + for (String ext : javaLikeExtensions) { + IJavaElement element = project.findElement(new Path(path + ext)); + if (element != null) { + return element; + } + } + return null; + } + + /** + * Returns if the type names are equal, where being equals means: + *
        + *
      • The names are non-null and equal
      • + *
      • The names are both null
      • + *
      + * + * @param name1 + * The first name + * @param name2 + * The second name + * @return If the type names are equal + * @since 3.8.100 + */ + public static boolean typeNamesEqual(String name1, String name2) { + if (name1 == null) { + return name2 == null; + } + return name1.equals(name2); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/BreakpointListenerManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/BreakpointListenerManager.java new file mode 100644 index 0000000000..6d35a779c7 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/BreakpointListenerManager.java @@ -0,0 +1,287 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.IJavaBreakpointListener; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +/** + * Manages breakpoint listener extensions. + * + * @since 3.5 + */ +public class BreakpointListenerManager { + + /** + * Map java breakpoint listeners by id + */ + private static Map fgJavaBreakpointListenersMap; + + /** + * Global listeners + */ + private static IJavaBreakpointListener[] fgGlobalListeners; + + private static final String VALUE_GLOBAL = "*"; //$NON-NLS-1$ + private static final String ATTR_ID = "id"; //$NON-NLS-1$ + private static final String ATTR_CLASS = "class"; //$NON-NLS-1$ + private static final String ATTR_FILTER = "filter"; //$NON-NLS-1$ + + /** + * Proxy to a breakpoint listener + */ + private class JavaBreakpointListenerProxy implements + IJavaBreakpointListener { + + private final IConfigurationElement fConfigElement; + private IJavaBreakpointListener fDelegate; + + public JavaBreakpointListenerProxy(IConfigurationElement element) { + fConfigElement = element; + } + + /** + * Returns the underlying delegate or null if none/error + * + * @return breakpoint listener extension + */ + private synchronized IJavaBreakpointListener getDelegate() { + if (fDelegate == null) { + try { + fDelegate = (IJavaBreakpointListener) fConfigElement + .createExecutableExtension(ATTR_CLASS); + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + } + + return fDelegate; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpointListener#addingBreakpoint + * (org.eclipse.jdt.debug.core.IJavaDebugTarget, + * org.eclipse.jdt.debug.core.IJavaBreakpoint) + */ + @Override + public void addingBreakpoint(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + delegate.addingBreakpoint(target, breakpoint); + } + } + + /** + * Whether this listener is for all breakpoints. + * + * @return whether for all breakpoints + */ + boolean isGlobal() { + String filter = fConfigElement.getAttribute(ATTR_FILTER); + if (filter != null && filter.equals(VALUE_GLOBAL)) { + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpointListener# + * breakpointHasCompilationErrors + * (org.eclipse.jdt.debug.core.IJavaLineBreakpoint, + * org.eclipse.jdt.core.dom.Message[]) + */ + @Override + public void breakpointHasCompilationErrors( + IJavaLineBreakpoint breakpoint, Message[] errors) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + delegate.breakpointHasCompilationErrors(breakpoint, errors); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpointListener# + * breakpointHasRuntimeException + * (org.eclipse.jdt.debug.core.IJavaLineBreakpoint, + * org.eclipse.debug.core.DebugException) + */ + @Override + public void breakpointHasRuntimeException( + IJavaLineBreakpoint breakpoint, DebugException exception) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + delegate.breakpointHasRuntimeException(breakpoint, exception); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpointListener#breakpointHit( + * org.eclipse.jdt.debug.core.IJavaThread, + * org.eclipse.jdt.debug.core.IJavaBreakpoint) + */ + @Override + public int breakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + return delegate.breakpointHit(thread, breakpoint); + } + return IJavaBreakpointListener.DONT_CARE; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpointListener#breakpointInstalled + * (org.eclipse.jdt.debug.core.IJavaDebugTarget, + * org.eclipse.jdt.debug.core.IJavaBreakpoint) + */ + @Override + public void breakpointInstalled(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + delegate.breakpointInstalled(target, breakpoint); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpointListener#breakpointRemoved + * (org.eclipse.jdt.debug.core.IJavaDebugTarget, + * org.eclipse.jdt.debug.core.IJavaBreakpoint) + */ + @Override + public void breakpointRemoved(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + delegate.breakpointRemoved(target, breakpoint); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpointListener#installingBreakpoint + * (org.eclipse.jdt.debug.core.IJavaDebugTarget, + * org.eclipse.jdt.debug.core.IJavaBreakpoint, + * org.eclipse.jdt.debug.core.IJavaType) + */ + @Override + public int installingBreakpoint(IJavaDebugTarget target, + IJavaBreakpoint breakpoint, IJavaType type) { + IJavaBreakpointListener delegate = getDelegate(); + if (delegate != null) { + return delegate.installingBreakpoint(target, breakpoint, type); + } + return IJavaBreakpointListener.DONT_CARE; + } + + } + + /** + * Load extensions. + */ + private synchronized void init() { + if (fgJavaBreakpointListenersMap == null) { + fgJavaBreakpointListenersMap = new HashMap<>(); + List global = new ArrayList<>(); + IExtensionPoint extensionPoint = Platform + .getExtensionRegistry() + .getExtensionPoint( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.EXTENSION_POINT_JAVA_BREAKPOINT_LISTENERS); + IConfigurationElement[] actionDelegateElements = extensionPoint + .getConfigurationElements(); + for (IConfigurationElement actionDelegateElement : actionDelegateElements) { + try { + String id = actionDelegateElement.getAttribute(ATTR_ID); + if (id == null) + throw new CoreException( + new Status(IStatus.ERROR, JDIDebugPlugin + .getUniqueIdentifier(), + "Java breakpoint listener requires an identifier attribute.")); //$NON-NLS-1$ + JavaBreakpointListenerProxy listener = new JavaBreakpointListenerProxy( + actionDelegateElement); + fgJavaBreakpointListenersMap.put(id, listener); + if (listener.isGlobal()) { + global.add(listener); + } + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + } + fgGlobalListeners = global + .toArray(new IJavaBreakpointListener[global.size()]); + } + } + + /** + * Returns the listener registered with the given identifier or + * null if none. + * + * @param id + * extension identifier + * @return breakpoint listener or null + */ + public IJavaBreakpointListener getBreakpointListener(String id) { + init(); + return fgJavaBreakpointListenersMap.get(id); + } + + /** + * Returns breakpoint listener extensions registered to listen for changes + * to all breakpoints. + * + * @return global listeners + */ + public IJavaBreakpointListener[] getGlobalListeners() { + init(); + return fgGlobalListeners; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ConditionalBreakpointHandler.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ConditionalBreakpointHandler.java new file mode 100644 index 0000000000..91656805d6 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ConditionalBreakpointHandler.java @@ -0,0 +1,347 @@ +/******************************************************************************* + * Copyright (c) 2009, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.text.MessageFormat; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.IJavaBreakpointListener; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; +import org.eclipse.jdt.debug.eval.ICompiledExpression; +import org.eclipse.jdt.debug.eval.IEvaluationListener; +import org.eclipse.jdt.debug.eval.IEvaluationResult; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDINullValue; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; + +import com.sun.jdi.VMDisconnectedException; + +/** + * Breakpoint listener to handle breakpoint conditions. + * + * @since 3.5 + */ +public class ConditionalBreakpointHandler implements IJavaBreakpointListener { + + /** + * Whether the condition had compile or runtime errors + */ + private boolean fHasErrors = false; + + /** + * Listens for evaluation completion for condition evaluation. If an + * evaluation evaluates true or has an error, this breakpoint + * will suspend the thread in which the breakpoint was hit. If the + * evaluation returns false, the thread is resumed. + */ + class EvaluationListener implements IEvaluationListener { + + /** + * Lock for synchronizing evaluation + */ + private final Object fLock = new Object(); + + /** + * The breakpoint that was hit + */ + private final JavaLineBreakpoint fBreakpoint; + + /** + * Result of the vote + */ + private int fVote; + + EvaluationListener(JavaLineBreakpoint breakpoint) { + fBreakpoint = breakpoint; + } + + @Override + public void evaluationComplete(IEvaluationResult result) { + fVote = determineVote(result); + synchronized (fLock) { + fLock.notifyAll(); + } + } + + /** + * Processes the result to determine whether to suspend or resume. + * + * @param result + * evaluation result + * @return vote + */ + private int determineVote(IEvaluationResult result) { + if (result.isTerminated()) { + // indicates the user terminated the evaluation + return SUSPEND; + } + JDIThread thread = (JDIThread) result.getThread(); + if (result.hasErrors()) { + DebugException exception = result.getException(); + if (exception == null) { + return DONT_SUSPEND; + } + Throwable wrappedException = exception.getStatus() + .getException(); + if (wrappedException instanceof VMDisconnectedException) { + // VM terminated/disconnected during evaluation + return DONT_SUSPEND; + } + fireConditionHasRuntimeErrors(fBreakpoint, exception); + return SUSPEND; + } + try { + IValue value = result.getValue(); + if (fBreakpoint.isConditionSuspendOnTrue()) { + if (value instanceof IJavaPrimitiveValue) { + // Suspend when the condition evaluates true + IJavaPrimitiveValue javaValue = (IJavaPrimitiveValue) value; + if (javaValue.getJavaType().getName() + .equals("boolean")) { //$NON-NLS-1$ + if (javaValue.getBooleanValue()) { + return SUSPEND; + } + return DONT_SUSPEND; + } + } + if ((value instanceof JDIValue) && !(value instanceof JDINullValue)) { + JDIValue jdiValue = (JDIValue)value; + // Suspend if return is Boolean(true) else don't suspend (no error dialog) + if (jdiValue.getJavaType().getName().equals("java.lang.Boolean")) {//$NON-NLS-1$ + IJavaPrimitiveValue javaValue = (IJavaPrimitiveValue) ((IJavaObject) jdiValue).getField("value", false).getValue(); //$NON-NLS-1$ + if (javaValue.getBooleanValue()) { + return SUSPEND; + } + return DONT_SUSPEND; + } + return DONT_SUSPEND; + } + IStatus status = new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + MessageFormat.format(JDIDebugBreakpointMessages.ConditionalBreakpointHandler_1, value.getReferenceTypeName())); + // result was not JDIValue + fireConditionHasRuntimeErrors(fBreakpoint, new DebugException(status)); + return SUSPEND; + } + IDebugTarget debugTarget = thread.getDebugTarget(); + IValue lastValue = fBreakpoint + .setCurrentConditionValue(debugTarget, value); + if (!value.equals(lastValue)) { + return SUSPEND; + } + return DONT_SUSPEND; + } catch (DebugException e) { + // Suspend when an error occurs + JDIDebugPlugin.log(e); + return SUSPEND; + } + } + + /** + * Result of the conditional expression evaluation - to resume or not + * resume, that is the question. + * + * @return vote result + */ + int getVote() { + return fVote; + } + + /** + * Returns the lock object to synchronize this evaluation. + * + * @return lock object + */ + Object getLock() { + return fLock; + } + } + + @Override + public void addingBreakpoint(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + } + + @Override + public void breakpointHasCompilationErrors(IJavaLineBreakpoint breakpoint, + Message[] errors) { + } + + @Override + public void breakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, + DebugException exception) { + } + + @Override + public int breakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) { + if (breakpoint instanceof IJavaLineBreakpoint) { + JavaLineBreakpoint lineBreakpoint = (JavaLineBreakpoint) breakpoint; + try { + final String condition = lineBreakpoint.getCondition(); + if (condition == null) { + return SUSPEND; + } + EvaluationListener listener = new EvaluationListener( + lineBreakpoint); + IJavaStackFrame frame = (IJavaStackFrame) thread + .getTopStackFrame(); + IJavaProject project = lineBreakpoint.getJavaProject(frame); + if (project == null) { + fireConditionHasErrors( + lineBreakpoint, + new Message[] { new Message( + JDIDebugBreakpointMessages.JavaLineBreakpoint_Unable_to_compile_conditional_breakpoint___missing_Java_project_context__1, + -1) }); + return SUSPEND; + } + IJavaDebugTarget target = (IJavaDebugTarget) thread + .getDebugTarget(); + IAstEvaluationEngine engine = getEvaluationEngine(target, + project); + if (engine == null) { + // If no engine is available, suspend + return SUSPEND; + } + ICompiledExpression expression = lineBreakpoint + .getExpression(thread); + if (expression == null) { + expression = engine.getCompiledExpression(condition, frame); + lineBreakpoint.setExpression(thread, expression); + } + if (expression.hasErrors()) { + fireConditionHasErrors(lineBreakpoint, + getMessages(expression)); + return SUSPEND; + } + Object lock = listener.getLock(); + synchronized (lock) { + engine.evaluateExpression(expression, frame, listener, + DebugEvent.EVALUATION_IMPLICIT, false); + // TODO: timeout? + try { + lock.wait(); + } catch (InterruptedException e) { + fireConditionHasRuntimeErrors( + lineBreakpoint, + new DebugException( + new Status( + IStatus.ERROR, + JDIDebugPlugin + .getUniqueIdentifier(), + JDIDebugBreakpointMessages.ConditionalBreakpointHandler_0, + e))); + return SUSPEND; + } + } + return listener.getVote(); + } catch (CoreException e) { + DebugException de = null; + if (e instanceof DebugException) { + de = (DebugException) e; + } else { + de = new DebugException(e.getStatus()); + } + fireConditionHasRuntimeErrors(lineBreakpoint, de); + } + } + return SUSPEND; + } + + @Override + public void breakpointInstalled(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + } + + @Override + public void breakpointRemoved(IJavaDebugTarget target, + IJavaBreakpoint breakpoint) { + } + + @Override + public int installingBreakpoint(IJavaDebugTarget target, + IJavaBreakpoint breakpoint, IJavaType type) { + return 0; + } + + /** + * Returns an evaluation engine for evaluating this breakpoint's condition + * in the given target and project context. + * @param vm the VM to get an evaluation engine for + * @param project the project context + * @return a new {@link IAstEvaluationEngine} + */ + private IAstEvaluationEngine getEvaluationEngine(IJavaDebugTarget vm, IJavaProject project) { + return ((JDIDebugTarget) vm).getEvaluationEngine(project); + } + + private void fireConditionHasRuntimeErrors(IJavaLineBreakpoint breakpoint, DebugException exception) { + fHasErrors = true; + JDIDebugPlugin.getDefault().fireBreakpointHasRuntimeException(breakpoint, exception); + } + + /** + * Notifies listeners that a conditional breakpoint expression has been + * compiled that contains errors + * @param breakpoint the breakpoint that has errors in its condition + * @param messages the error messages + */ + private void fireConditionHasErrors(IJavaLineBreakpoint breakpoint, Message[] messages) { + fHasErrors = true; + JDIDebugPlugin.getDefault().fireBreakpointHasCompilationErrors(breakpoint, messages); + } + + /** + * Convert an array of String to an array of + * Message. + * @param expression the expression to get messages from + * @return the array of {@link Message}s from the expression + */ + private Message[] getMessages(ICompiledExpression expression) { + String[] errorMessages = expression.getErrorMessages(); + Message[] messages = new Message[errorMessages.length]; + for (int i = 0; i < messages.length; i++) { + messages[i] = new Message(errorMessages[i], -1); + } + return messages; + } + + /** + * Returns whether errors were encountered when evaluating the condition + * (compilation or runtime). + * + * @return whether errors were encountered when evaluating the condition + */ + public boolean hasErrors() { + return fHasErrors; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java new file mode 100644 index 0000000000..0013374dfc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.LambdaExpression; + +public class FirstLambdaLocationLocator extends ASTVisitor { + private int fNodeLength = -1; + private int fNodeOffset = -1; + private int fLineOffset = -1; + private int fLineEndPosition = -1; + private String fLambdaMethodName; + private String fLambdaMethodSignature; + private boolean fLocationFound = false; + + public FirstLambdaLocationLocator(int lineOffset, int lineEndPosition) { + fLineOffset = lineOffset; + fLineEndPosition = lineEndPosition; + } + + /** + * Return of the name of the lambda method where the valid location is. + */ + public String getLambdaMethodName() { + return fLambdaMethodName; + } + + /** + * Return of the signature of the lambda method where the valid location is. + * The signature is computed to be compatible with the final lambda method with + * method arguments and outer local variables. + */ + public String getfLambdaMethodSignature() { + return fLambdaMethodSignature; + } + + public int getNodeLength() { + return fNodeLength; + } + + public int getNodeOffset() { + return fNodeOffset; + } + + @Override + public boolean visit(LambdaExpression node) { + if (fLocationFound) { + return false; + } + if (node.getStartPosition() < fLineOffset || node.getStartPosition() > fLineEndPosition) { + return false; + } + fNodeLength = node.getLength(); + fNodeOffset = node.getStartPosition(); + IMethodBinding methodBinding = node.resolveMethodBinding(); + if (methodBinding != null) { + fLambdaMethodName = LambdaLocationLocatorHelper.toMethodName(methodBinding); + fLambdaMethodSignature = LambdaLocationLocatorHelper.toMethodSignature(methodBinding); + fLocationFound = true; + } + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JDIDebugBreakpointMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JDIDebugBreakpointMessages.java new file mode 100644 index 0000000000..18c15c786a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JDIDebugBreakpointMessages.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import org.eclipse.osgi.util.NLS; + +public class JDIDebugBreakpointMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.core.breakpoints.JDIDebugBreakpointMessages";//$NON-NLS-1$ + + public static String ConditionalBreakpointHandler_0; + + public static String ConditionalBreakpointHandler_1; + + public static String JavaBreakpoint___Hit_Count___0___1; + public static String JavaBreakpoint_Exception; + public static String JavaPatternBreakpoint_0; + public static String JavaBreakpoint__suspend_policy__thread__1; + public static String JavaBreakpoint__suspend_policy__VM__2; + + public static String JavaLineBreakpoint___Condition___0___2; + public static String JavaLineBreakpoint_Unable_to_compile_conditional_breakpoint___missing_Java_project_context__1; + public static String JavaLineBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1; + public static String JavaLineBreakpoint___line___0___1; + public static String JavaLineBreakpoint_Absent_Line_Number_Information_1; + + public static String JavaPatternBreakpoint_exception_source_name; + public static String JavaPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1; + + public static String JavaWatchpoint_no_access_watchpoints; + public static String JavaWatchpoint_no_modification_watchpoints; + public static String JavaWatchpoint_Unable_to_create_breakpoint_request___VM_disconnected__1; + + public static String JavaExceptionBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1; + + public static String JavaMethodBreakpoint_0; + + public static String JavaMethodBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1; + + public static String JavaTargetPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1; + + public static String JavaClassPrepareBreakpoint_2; + public static String JavaClassPrepareBreakpoint_3; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, JDIDebugBreakpointMessages.class); + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JDIDebugBreakpointMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JDIDebugBreakpointMessages.properties new file mode 100644 index 0000000000..38fecffc80 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JDIDebugBreakpointMessages.properties @@ -0,0 +1,44 @@ +############################################################################### +# Copyright (c) 2000, 2010 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +ConditionalBreakpointHandler_0=Conditional breakpoint evaluation interrupted +ConditionalBreakpointHandler_1=Result of breakpoint conditional expression was not a boolean: {0} +JavaBreakpoint___Hit_Count___0___1=\ [hit count: {0}] +JavaBreakpoint_Exception=Exception occurred while updating breakpoint. +JavaPatternBreakpoint_0=Breakpoint installation failed +JavaBreakpoint__suspend_policy__thread__1=[suspend policy: thread] +JavaBreakpoint__suspend_policy__VM__2=[suspend policy: VM] + +JavaLineBreakpoint___Condition___0___2=\ [condition: {0}] +JavaLineBreakpoint_Unable_to_compile_conditional_breakpoint___missing_Java_project_context__1=Unable to compile conditional breakpoint - missing Java project context. +JavaLineBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1=Unable to create breakpoint request - VM disconnected. +JavaLineBreakpoint___line___0___1=\ [line: {0}] +JavaLineBreakpoint_Absent_Line_Number_Information_1=Absent Line Number Information + +JavaPatternBreakpoint_exception_source_name={0} occurred while determining source name debug attribute for {1} +JavaPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1=Unable to add breakpoint - VM disconnected. + +JavaWatchpoint_no_access_watchpoints=VM does not support access watchpoints. +JavaWatchpoint_no_modification_watchpoints=VM does not support modification watchpoints. +JavaWatchpoint_Unable_to_create_breakpoint_request___VM_disconnected__1=Unable to create breakpoint request - VM disconnected. + +JavaExceptionBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1=Unable to create breakpoint request - VM disconnected. + +JavaMethodBreakpoint_0=Unable to restore type name pattern on method breakpoint +JavaMethodBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1=Unable to create breakpoint request - VM disconnected. + +JavaTargetPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1=Unable to add breakpoint - VM disconnected. + +JavaClassPrepareBreakpoint_2=Class prepare breakpoint does not support instance filters +JavaClassPrepareBreakpoint_3=Class prepare breakpoint does not support thread filters diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java new file mode 100644 index 0000000000..42c16435fb --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpoint.java @@ -0,0 +1,1501 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.model.Breakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.IJavaBreakpointListener; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.IJDIEventListener; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.eclipse.jdt.internal.debug.core.model.JDIType; + +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.LocatableEvent; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; + +public abstract class JavaBreakpoint extends Breakpoint implements IJavaBreakpoint, IJDIEventListener, IDebugEventSetListener { + + /** + * Breakpoint attribute storing the expired value (value + * "org.eclipse.jdt.debug.core.expired"). This attribute is + * stored as a boolean. Once a hit count has been reached, a + * breakpoint is considered to be "expired". + */ + protected static final String EXPIRED = "org.eclipse.jdt.debug.core.expired"; //$NON-NLS-1$ + /** + * Breakpoint attribute storing a breakpoint's hit count value (value + * "org.eclipse.jdt.debug.core.hitCount"). This attribute is + * stored as an int. + */ + protected static final String HIT_COUNT = "org.eclipse.jdt.debug.core.hitCount"; //$NON-NLS-1$ + /** + * Breakpoint attribute storing the number of debug targets a breakpoint is + * installed in (value + * "org.eclipse.jdt.debug.core.installCount"). This attribute + * is a int. + */ + protected static final String INSTALL_COUNT = "org.eclipse.jdt.debug.core.installCount"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the fully qualified name of the type this + * breakpoint is located in. (value + * "org.eclipse.jdt.debug.core.typeName"). This attribute is a + * String. + */ + protected static final String TYPE_NAME = "org.eclipse.jdt.debug.core.typeName"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing suspend policy code for this breakpoint. + * (value "org.eclipse.jdt.debug.core.suspendPolicy). This + * attribute is an int corresponding to + * IJavaBreakpoint.SUSPEND_VM or + * IJavaBreakpoint.SUSPEND_THREAD. + */ + protected static final String SUSPEND_POLICY = "org.eclipse.jdt.debug.core.suspendPolicy"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing a comma delimited list of extension + * identifiers of breakpoint listeners. The listeners will be notified in + * the order specified in the list. + * + * @since 3.5 + */ + public static final String BREAKPOINT_LISTENERS = JDIDebugPlugin.EXTENSION_POINT_JAVA_BREAKPOINT_LISTENERS; + /** + * Breakpoint attribute storing the expired value of trigger point (value + * "org.eclipse.jdt.debug.core.expiredTriggerPoint"). This attribute is + * stored as a boolean. Once a trigger point is hit, a + * breakpoint is considered to be "expired" as trigger point for the session. + * + * @since 3.11 + */ + public static final String EXPIRED_TRIGGER_POINT = "org.eclipse.jdt.debug.core.expiredTriggerPoint"; //$NON-NLS-1$ + + /** + * Stores the collection of requests that this breakpoint has installed in + * debug targets. key: a debug target value: the requests this breakpoint + * has installed in that target + */ + protected HashMap> fRequestsByTarget; + + /** + * The list of threads (ThreadReference objects) in which this breakpoint + * will suspend, associated with the target in which each thread exists + * (JDIDebugTarget). key: targets the debug targets (IJavaDebugTarget) + * value: thread the filtered thread (IJavaThread) in the given target + */ + protected Map fFilteredThreadsByTarget; + + /** + * Stores the type name that this breakpoint was last installed in. When a + * breakpoint is created, the TYPE_NAME attribute assigned to it is that of + * its top level enclosing type. When installed, the type may actually be an + * inner type. We need to keep track of the type type the breakpoint was + * installed in, in case we need to re-install the breakpoint for HCR (i.e. + * in case an inner type is HCR'd). + */ + protected String fInstalledTypeName = null; + + /** + * List of targets in which this breakpoint is installed. Used to prevent + * firing of more than one install notification when a breakpoint's requests + * are re-created. + */ + protected Set fInstalledTargets = null; + + /** + * List of active instance filters for this breakpoint (list of + * IJavaObject). + */ + protected List fInstanceFilters = null; + + /** + * List of breakpoint listener identifiers corresponding to breakpoint + * listener extensions. Listeners are cached with the breakpoint object such + * that they can be notified when a breakpoint is removed. + */ + private List fBreakpointListenerIds = null; + + /** + * Empty instance filters array. + */ + protected static final IJavaObject[] fgEmptyInstanceFilters = new IJavaObject[0]; + + /** + * Property identifier for a breakpoint object on an event request + */ + public static final String JAVA_BREAKPOINT_PROPERTY = "org.eclipse.jdt.debug.breakpoint"; //$NON-NLS-1$ + + /** + * JavaBreakpoint attributes + */ + protected static final String[] fgExpiredEnabledAttributes = new String[] { + EXPIRED, ENABLED }; + + public JavaBreakpoint() { + fRequestsByTarget = new HashMap<>(1); + fFilteredThreadsByTarget = new HashMap<>(1); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IBreakpoint#getModelIdentifier() + */ + @Override + public String getModelIdentifier() { + return JDIDebugModel.getPluginIdentifier(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.Breakpoint#setMarker(org.eclipse.core.resources + * .IMarker) + */ + @Override + public void setMarker(IMarker marker) throws CoreException { + super.setMarker(marker); + configureAtStartup(); + } + + /** + * Add this breakpoint to the breakpoint manager, or sets it as + * unregistered. + */ + protected void register(boolean register) throws CoreException { + DebugPlugin plugin = DebugPlugin.getDefault(); + if (plugin != null && register) { + plugin.getBreakpointManager().addBreakpoint(this); + } else { + setRegistered(false); + } + } + + /** + * Add the given event request to the given debug target. If the request is + * the breakpoint request associated with this breakpoint, increment the + * install count. + */ + protected void registerRequest(EventRequest request, JDIDebugTarget target) + throws CoreException { + if (request == null) { + return; + } + List reqs = getRequests(target); + if (reqs.isEmpty()) { + fRequestsByTarget.put(target, reqs); + } + reqs.add(request); + target.addJDIEventListener(this, request); + // update the install attribute on the breakpoint + if (!(request instanceof ClassPrepareRequest)) { + incrementInstallCount(); + // notification + fireInstalled(target); + } + } + + /** + * Returns a String corresponding to the reference type name to the top + * enclosing type in which this breakpoint is located or null + * if no reference type could be found. + */ + protected String getEnclosingReferenceTypeName() throws CoreException { + String name = getTypeName(); + if (name != null) { + int index = name.indexOf('$'); + if (index == -1) { + return name; + } + return name.substring(0, index); + } + return null; + } + + /** + * Returns the requests that this breakpoint has installed in the given + * target. + */ + protected ArrayList getRequests(JDIDebugTarget target) { + ArrayList list = (ArrayList) fRequestsByTarget.get(target); + if (list == null) { + list = new ArrayList<>(2); + } + return list; + } + + /** + * Remove the given request from the given target. If the request is the + * breakpoint request associated with this breakpoint, decrement the install + * count. + */ + protected void deregisterRequest(EventRequest request, JDIDebugTarget target) + throws CoreException { + target.removeJDIEventListener(this, request); + // A request may be getting de-registered because the breakpoint has + // been deleted. It may be that this occurred because of a marker + // deletion. + // Don't try updating the marker (decrementing the install count) if + // it no longer exists. + if (!(request instanceof ClassPrepareRequest) && getMarker().exists()) { + decrementInstallCount(); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.IJDIEventListener#handleEvent(com + * .sun.jdi.event.Event, + * org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet) { + if (event instanceof ClassPrepareEvent) { + return handleClassPrepareEvent((ClassPrepareEvent) event, target, + suspendVote); + } + ThreadReference threadRef = ((LocatableEvent) event).thread(); + JDIThread thread = target.findThread(threadRef); + if (thread == null) { + thread = target.findThread(threadRef); + } + if (thread == null || thread.isIgnoringBreakpoints()) { + return true; + } + return handleBreakpointEvent(event, thread, suspendVote); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.IJDIEventListener#eventSetComplete + * (com.sun.jdi.event.Event, + * org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, boolean) + */ + @Override + public void eventSetComplete(Event event, JDIDebugTarget target, + boolean suspend, EventSet eventSet) { + ThreadReference threadRef = null; + if (event instanceof ClassPrepareEvent) { + threadRef = ((ClassPrepareEvent) event).thread(); + } else if (event instanceof LocatableEvent) { + threadRef = ((LocatableEvent) event).thread(); + } + if (threadRef == null) { + return; + } + JDIThread thread = target.findThread(threadRef); + if (thread == null || thread.isIgnoringBreakpoints()) { + return; + } + if (event instanceof ClassPrepareEvent) { + classPrepareComplete(event, thread, suspend, eventSet); + } else { + thread.completeBreakpointHandling(this, suspend, true, eventSet); + } + } + + /** + * Call-back that the class prepare event has completed + * @param event the event + * @param thread the thread that sent the event + * @param suspend if the the thread was suspended + * @param eventSet the event set context + */ + protected void classPrepareComplete(Event event, JDIThread thread, boolean suspend, EventSet eventSet) { + // resume the thread if this is a class load event to install a deferred + // breakpoint (and the vote is to resume) + if (thread != null && !suspend) { + thread.resumedFromClassPrepare(); + } + } + + /** + * Handle the given class prepare event, which was generated by the class + * prepare event installed in the given target by this breakpoint. + * + * If the class which has been loaded is a class in which this breakpoint + * should install, create a breakpoint request for that class. + * @param event the event + * @param target the target + * @param suspendVote the current suspend vote + * @return is the thread should suspend or not + */ + public boolean handleClassPrepareEvent(ClassPrepareEvent event, JDIDebugTarget target, boolean suspendVote) { + try { + if (!installableReferenceType(event.referenceType(), target)) { + // Don't install this breakpoint in an + // inappropriate type + return true; + } + createRequest(target, event.referenceType()); + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + return true; + } + + /** + * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget) + * + * Handle the given event, which was generated by the breakpoint + * request installed in the given target by this breakpoint. + */ + public boolean handleBreakpointEvent(Event event, JDIThread thread, + boolean suspendVote) { + expireHitCount(event); + disableTriggerPoint(event); + return !suspend(thread, suspendVote); // Resume if suspend fails + } + + /** + * Delegates to the given thread to suspend, and returns whether the thread + * suspended It is possible that the thread will not suspend as directed by + * a Java breakpoint listener. + * + * @see IJavaBreakpointListener#breakpointHit(IJavaThread, IJavaBreakpoint) + */ + protected boolean suspend(JDIThread thread, boolean suspendVote) { + return thread.handleSuspendForBreakpoint(this, suspendVote); + } + + /** + * Returns whether the given reference type is appropriate for this + * breakpoint to be installed in the given target. Query registered + * breakpoint listeners. + */ + protected boolean installableReferenceType(ReferenceType type, + JDIDebugTarget target) throws CoreException { + String installableType = getTypeName(); + if (installableType == null ) { + return false; + } + String queriedType = type.name(); + if( queriedType == null) { + return false; + } + int index = queriedType.indexOf('<'); + if (index != -1) { + queriedType = queriedType.substring(0, index); + } + if (installableType.equals(queriedType)) { + return queryInstallListeners(target, type); + } + index = queriedType.indexOf('$', 0); + if (index == -1) { + return false; + } + if (installableType.regionMatches(0, queriedType, 0, index)) { + return queryInstallListeners(target, type); + } + return false; + } + + /** + * Called when a breakpoint event is encountered. Expires the hit count in + * the event's request and updates the marker. + * + * @param event + * the event whose request should have its hit count expired or + * null to only update the breakpoint marker. + */ + protected void expireHitCount(Event event) { + Integer requestCount = null; + EventRequest request = null; + if (event != null) { + request = event.request(); + requestCount = (Integer) request.getProperty(HIT_COUNT); + } + if (requestCount != null) { + if (request != null) { + request.putProperty(EXPIRED, Boolean.TRUE); + } + try { + setAttributes(fgExpiredEnabledAttributes, new Object[] { + Boolean.TRUE, Boolean.FALSE }); + // make a note that we auto-disabled this breakpoint. + } catch (CoreException ce) { + JDIDebugPlugin.log(ce); + } + } + } + + protected void disableTriggerPoint(@SuppressWarnings("unused") Event event) { + try{ + if (isTriggerPoint() && isEnabled()) { + if (this instanceof JavaLineBreakpoint) { + JavaLineBreakpoint lbp = (JavaLineBreakpoint) this; + if (lbp.hasCondition()) { + return; + } + } + DebugPlugin.getDefault().getBreakpointManager().enableTriggerPoints(null, false); + // make a note that we auto-disabled the trigger point for this breakpoint. + // we re enable it at cleanup of JDITarget + } + }catch (CoreException ce) { + JDIDebugPlugin.log(ce); + } + + } + + /** + * Returns whether this breakpoint should be "skipped". Breakpoints are + * skipped if the breakpoint manager is disabled and the breakpoint is + * registered with the manager + * + * @return whether this breakpoint should be skipped + */ + public boolean shouldSkipBreakpoint() throws CoreException { + DebugPlugin plugin = DebugPlugin.getDefault(); + return plugin != null && isRegistered() + && !plugin.getBreakpointManager().isEnabled(); + } + + /** + * Attempts to create a breakpoint request for this breakpoint in the given + * reference type in the given target. + * + * @return Whether a request was created + */ + protected boolean createRequest(JDIDebugTarget target, ReferenceType type) + throws CoreException { + if (shouldSkipBreakpoint()) { + return false; + } + EventRequest[] requests = newRequests(target, type); + if (requests == null) { + return false; + } + fInstalledTypeName = type.name(); + for (EventRequest request : requests) { + registerRequest(request, target); + } + return true; + } + + /** + * Configure a breakpoint request with common properties: + *
        + *
      • JAVA_BREAKPOINT_PROPERTY
      • + *
      • HIT_COUNT
      • + *
      • EXPIRED
      • + *
      + * and sets the suspend policy of the request to suspend the event thread. + */ + protected void configureRequest(EventRequest request, JDIDebugTarget target) + throws CoreException { + request.setSuspendPolicy(getJDISuspendPolicy()); + request.putProperty(JAVA_BREAKPOINT_PROPERTY, this); + configureRequestThreadFilter(request, target); + configureRequestHitCount(request); + configureInstanceFilters(request, target); + // Important: only enable a request after it has been configured + updateEnabledState(request, target); + } + + /** + * Adds an instance filter to the given request. Since the implementation is + * request specific, subclasses must override. + * + * @param request + * @param object + * instance filter + */ + protected abstract void addInstanceFilter(EventRequest request, + ObjectReference object); + + /** + * Configure the thread filter property of the given request. + */ + protected void configureRequestThreadFilter(EventRequest request, + JDIDebugTarget target) { + IJavaThread thread = fFilteredThreadsByTarget.get(target); + if (thread == null || (!(thread instanceof JDIThread))) { + return; + } + setRequestThreadFilter(request, + ((JDIThread) thread).getUnderlyingThread()); + } + + /** + * Configure the given request's hit count + */ + protected void configureRequestHitCount(EventRequest request) + throws CoreException { + int hitCount = getHitCount(); + if (hitCount > 0) { + request.addCountFilter(hitCount); + request.putProperty(HIT_COUNT, Integer.valueOf(hitCount)); + } + } + + protected void configureInstanceFilters(EventRequest request, + JDIDebugTarget target) { + if (fInstanceFilters != null && !fInstanceFilters.isEmpty()) { + Iterator iter = fInstanceFilters.iterator(); + while (iter.hasNext()) { + IJavaObject object = iter.next(); + if (object.getDebugTarget().equals(target)) { + addInstanceFilter(request, + ((JDIObjectValue) object).getUnderlyingObject()); + } + } + } + } + + /** + * Creates, installs, and returns all event requests for this breakpoint in + * the given reference type and and target. + * + * @return the event requests created or null if creation + * failed + */ + protected abstract EventRequest[] newRequests(JDIDebugTarget target, + ReferenceType type) throws CoreException; + + /** + * Add this breakpoint to the given target. After it has been added to the + * given target, this breakpoint will suspend execution of that target as + * appropriate. + */ + public void addToTarget(JDIDebugTarget target) throws CoreException { + fireAdding(target); + createRequests(target); + } + + /** + * Creates event requests for the given target + */ + protected void createRequests(JDIDebugTarget target) throws CoreException { + if (target.isTerminated() || shouldSkipBreakpoint()) { + return; + } + String referenceTypeName = getTypeName(); + String enclosingTypeName = getEnclosingReferenceTypeName(); + if (referenceTypeName == null || enclosingTypeName == null) { + return; + } + // create request to listen to class loads + if (referenceTypeName.indexOf('$') == -1) { + registerRequest( + target.createClassPrepareRequest(enclosingTypeName), target); + // register to ensure we hear about local and anonymous inner + // classes + registerRequest( + target.createClassPrepareRequest(enclosingTypeName + "$*"), target); //$NON-NLS-1$ + } else { + registerRequest( + target.createClassPrepareRequest(referenceTypeName), target); + // register to ensure we hear about local and anonymous inner + // classes + registerRequest(target.createClassPrepareRequest(enclosingTypeName + + "$*", referenceTypeName), target); //$NON-NLS-1$ + } + + // create breakpoint requests for each class currently loaded + List classes = target.jdiClassesByName(referenceTypeName); + if (classes.isEmpty() && enclosingTypeName.equals(referenceTypeName)) { + return; + } + + boolean success = false; + Iterator iter = classes.iterator(); + while (iter.hasNext()) { + ReferenceType type = iter.next(); + if (createRequest(target, type)) { + success = true; + } + } + + if (!success) { + addToTargetForLocalType(target, enclosingTypeName); + } + } + + /** + * Local types (types defined in methods) are handled specially due to the + * different types that the local type is associated with as well as the + * performance problems of using ReferenceType#nestedTypes. From the Java + * model perspective a local type is defined within a method of a type. + * Therefore the type of a breakpoint placed in a local type is the type + * that encloses the method where the local type was defined. The local type + * is enclosed within the top level type according to the VM. So if "normal" + * attempts to create a request when a breakpoint is being added to a target + * fail, we must be dealing with a local type and therefore resort to + * looking up all of the nested types of the top level enclosing type. + * + * @param target the target + * @param enclosingTypeName the type name of the enclosing type + * @throws CoreException if something bad happens + */ + protected void addToTargetForLocalType(JDIDebugTarget target, String enclosingTypeName) throws CoreException { + List classes = target.jdiClassesByName(enclosingTypeName); + for(ReferenceType type : classes) { + for(ReferenceType nestedType : type.nestedTypes()) { + if (createRequest(target, nestedType)) { + break; + } + } + } + } + + /** + * Returns the JDI suspend policy that corresponds to this breakpoint's + * suspend policy + * + * @return the JDI suspend policy that corresponds to this breakpoint's + * suspend policy + * @exception CoreException + * if unable to access this breakpoint's suspend policy + * setting + */ + protected int getJDISuspendPolicy() throws CoreException { + int breakpointPolicy = getSuspendPolicy(); + if (breakpointPolicy == IJavaBreakpoint.SUSPEND_THREAD) { + return EventRequest.SUSPEND_EVENT_THREAD; + } + return EventRequest.SUSPEND_ALL; + } + + /** + * returns the default suspend policy based on the pref setting on the + * Java-Debug pref page + * + * @return the default suspend policy + * @since 3.2 + */ + protected int getDefaultSuspendPolicy() { + return Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY, + IJavaBreakpoint.SUSPEND_THREAD, + null); + } + + /** + * Returns whether the hitCount of this breakpoint is equal to the hitCount + * of the associated request. + */ + protected boolean hasHitCountChanged(EventRequest request) + throws CoreException { + int hitCount = getHitCount(); + Integer requestCount = (Integer) request.getProperty(HIT_COUNT); + int oldCount = -1; + if (requestCount != null) { + oldCount = requestCount.intValue(); + } + return hitCount != oldCount; + } + + /** + * Removes this breakpoint from the given target. + */ + public void removeFromTarget(final JDIDebugTarget target) + throws CoreException { + removeRequests(target); + Object removed = fFilteredThreadsByTarget.remove(target); + boolean changed = removed != null; + boolean markerExists = markerExists(); + if (!markerExists || (markerExists && getInstallCount() == 0)) { + fInstalledTypeName = null; + } + + // remove instance filters + if (fInstanceFilters != null && !fInstanceFilters.isEmpty()) { + for (int i = 0; i < fInstanceFilters.size(); i++) { + IJavaObject object = fInstanceFilters.get(i); + if (object.getDebugTarget().equals(target)) { + fInstanceFilters.remove(i); + changed = true; + } + } + } + + // fire change notification if required + if (changed) { + fireChanged(); + } + + // notification + fireRemoved(target); + } + + /** + * Remove all requests that this breakpoint has installed in the given debug + * target. + */ + protected void removeRequests(final JDIDebugTarget target) throws CoreException { + // removing was previously done is a workspace runnable, but that is + // not possible since it can be a resource callback (marker deletion) + // that causes a breakpoint to be removed + ArrayList requests = new ArrayList<>(getRequests(target)); + // Iterate over a copy of the requests since this list of requests + // can be changed in other threads which would cause an + // ConcurrentModificationException + Iterator iter = requests.iterator(); + EventRequest req; + while (iter.hasNext()) { + req = iter.next(); + try { + if (target.isAvailable() && !isExpired(req)) { + EventRequestManager manager = target + .getEventRequestManager(); + if (manager != null) { + manager.deleteEventRequest(req); // disable & remove + } + } + } catch (VMDisconnectedException e) { + if (target.isAvailable()) { + JDIDebugPlugin.log(e); + } + } catch (RuntimeException e) { + target.internalError(e); + } finally { + deregisterRequest(req, target); + } + } + fRequestsByTarget.remove(target); + } + + /** + * Update the enabled state of the given request in the given target, which + * is associated with this breakpoint. Set the enabled state of the request + * to the enabled state of this breakpoint. + */ + protected void updateEnabledState(EventRequest request, + JDIDebugTarget target) throws CoreException { + internalUpdateEnabledState(request, isEnabled(), target); + } + + /** + * Set the enabled state of the given request to the given value, also + * taking into account instance filters. + */ + protected void internalUpdateEnabledState(EventRequest request, + boolean enabled, JDIDebugTarget target) { + if (request.isEnabled() != enabled) { + // change the enabled state + try { + // if the request has expired, do not disable. + // BreakpointRequests that have expired cannot be deleted. + if (!isExpired(request)) { + request.setEnabled(enabled); + } + } catch (VMDisconnectedException e) { + } catch (RuntimeException e) { + target.internalError(e); + } + } + } + + /** + * Returns whether this breakpoint has expired. + */ + public boolean isExpired() throws CoreException { + return ensureMarker().getAttribute(EXPIRED, false); + } + + /** + * Returns whether the given request is expired + */ + protected boolean isExpired(EventRequest request) { + Boolean requestExpired = (Boolean) request.getProperty(EXPIRED); + if (requestExpired == null) { + return false; + } + return requestExpired.booleanValue(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#isInstalled() + */ + @Override + public boolean isInstalled() throws CoreException { + return ensureMarker().getAttribute(INSTALL_COUNT, 0) > 0; + } + + /** + * Increments the install count of this breakpoint + */ + protected void incrementInstallCount() throws CoreException { + int count = getInstallCount(); + setAttribute(INSTALL_COUNT, count + 1); + } + + /** + * Returns the INSTALL_COUNT attribute of this breakpoint or 0 + * if the attribute is not set. + */ + public int getInstallCount() throws CoreException { + return ensureMarker().getAttribute(INSTALL_COUNT, 0); + } + + /** + * Returns whether this trigger breakpoint has expired. + */ + public boolean isTriggerPointExpired() throws CoreException { + return ensureMarker().getAttribute(EXPIRED_TRIGGER_POINT, false); + } + + /** + * Decrements the install count of this breakpoint. + */ + protected void decrementInstallCount() throws CoreException { + int count = getInstallCount(); + if (count > 0) { + setAttribute(INSTALL_COUNT, count - 1); + } + if (count == 1) { + if (isExpired()) { + // if breakpoint was auto-disabled, re-enable it + setAttributes(fgExpiredEnabledAttributes, new Object[] { + Boolean.FALSE, Boolean.TRUE }); + } + } + } + + /** + * Sets the type name in which to install this breakpoint. + */ + protected void setTypeName(String typeName) throws CoreException { + setAttribute(TYPE_NAME, typeName); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getTypeName() + */ + @Override + public String getTypeName() throws CoreException { + if (fInstalledTypeName == null) { + return ensureMarker().getAttribute(TYPE_NAME, null); + } + return fInstalledTypeName; + } + + /** + * Resets the install count attribute on this breakpoint's marker to "0". + * Resets the expired attribute on all breakpoint markers to + * false. Resets the enabled attribute on the breakpoint marker + * to true. If a workbench crashes, the attributes could have + * been persisted in an incorrect state. + */ + private void configureAtStartup() throws CoreException { + List attributes = null; + List values = new ArrayList<>(3); + if (isInstalled()) { + attributes = new ArrayList<>(3); + attributes.add(INSTALL_COUNT); + values.add(Integer.valueOf(0)); + } + if (isExpired()) { + if (attributes == null) { + attributes = new ArrayList<>(3); + } + // if breakpoint was auto-disabled, re-enable it + attributes.add(EXPIRED); + values.add(Boolean.FALSE); + attributes.add(ENABLED); + values.add(Boolean.TRUE); + } + if (attributes != null) { + String[] strAttributes = new String[attributes.size()]; + setAttributes(attributes.toArray(strAttributes), values.toArray()); + } + String[] listeners = readBreakpointListeners(); + if (listeners.length > 0) { + fBreakpointListenerIds = new ArrayList<>(); + for (String listener : listeners) { + fBreakpointListenerIds.add(listener); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getHitCount() + */ + @Override + public int getHitCount() throws CoreException { + return ensureMarker().getAttribute(HIT_COUNT, -1); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#setHitCount(int) + */ + @Override + public void setHitCount(int count) throws CoreException { + if (getHitCount() != count) { + if (!isEnabled() && count > -1) { + setAttributes(new String[] { ENABLED, HIT_COUNT, EXPIRED }, + new Object[] { Boolean.TRUE, Integer.valueOf(count), + Boolean.FALSE }); + } else { + setAttributes(new String[] { HIT_COUNT, EXPIRED }, + new Object[] { Integer.valueOf(count), Boolean.FALSE }); + } + recreate(); + } + } + + protected String getMarkerMessage(int hitCount, int suspendPolicy) { + StringBuilder buff = new StringBuilder(); + if (hitCount > 0) { + buff.append(MessageFormat + .format(JDIDebugBreakpointMessages.JavaBreakpoint___Hit_Count___0___1, + new Object[] { Integer.toString(hitCount) })); + buff.append(' '); + } + String suspendPolicyString; + if (suspendPolicy == IJavaBreakpoint.SUSPEND_THREAD) { + suspendPolicyString = JDIDebugBreakpointMessages.JavaBreakpoint__suspend_policy__thread__1; + } else { + suspendPolicyString = JDIDebugBreakpointMessages.JavaBreakpoint__suspend_policy__VM__2; + } + + buff.append(suspendPolicyString); + return buff.toString(); + } + + /** + * Sets whether this breakpoint's hit count has expired. + */ + public void setExpired(boolean expired) throws CoreException { + setAttribute(EXPIRED, expired); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getSuspendPolicy() + */ + @Override + public int getSuspendPolicy() throws CoreException { + return ensureMarker().getAttribute(SUSPEND_POLICY, + IJavaBreakpoint.SUSPEND_THREAD); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#setSuspendPolicy(int) + */ + @Override + public void setSuspendPolicy(int suspendPolicy) throws CoreException { + if (getSuspendPolicy() != suspendPolicy) { + setAttribute(SUSPEND_POLICY, suspendPolicy); + recreate(); + } + } + + /** + * Notifies listeners this breakpoint is to be added to the given target. + * + * @param target + * debug target + */ + protected void fireAdding(IJavaDebugTarget target) { + JDIDebugPlugin plugin = JDIDebugPlugin.getDefault(); + if (plugin != null) { + plugin.fireBreakpointAdding(target, this); + } + } + + /** + * Notifies listeners this breakpoint has been removed from the given + * target. + * + * @param target + * debug target + */ + protected void fireRemoved(IJavaDebugTarget target) { + JDIDebugPlugin plugin = JDIDebugPlugin.getDefault(); + if (plugin != null) { + plugin.fireBreakpointRemoved(target, this); + setInstalledIn(target, false); + } + } + + /** + * Notifies listeners this breakpoint has been installed in the given + * target. + * + * @param target + * debug target + */ + protected void fireInstalled(IJavaDebugTarget target) { + JDIDebugPlugin plugin = JDIDebugPlugin.getDefault(); + if (plugin != null && !isInstalledIn(target)) { + plugin.fireBreakpointInstalled(target, this); + setInstalledIn(target, true); + } + } + + /** + * Returns whether this breakpoint is installed in the given target. + * + * @param target + * @return whether this breakpoint is installed in the given target + */ + protected boolean isInstalledIn(IJavaDebugTarget target) { + return fInstalledTargets != null && fInstalledTargets.contains(target); + } + + /** + * Sets this breakpoint as installed in the given target + * + * @param target + * @param installed + * whether installed + */ + protected void setInstalledIn(IJavaDebugTarget target, boolean installed) { + if (installed) { + if (fInstalledTargets == null) { + fInstalledTargets = new HashSet<>(); + } + fInstalledTargets.add(target); + } else { + if (fInstalledTargets != null) { + fInstalledTargets.remove(target); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#setThreadFilter(org.eclipse + * .jdt.debug.core.IJavaThread) + */ + @Override + public void setThreadFilter(IJavaThread thread) throws CoreException { + if (!(thread.getDebugTarget() instanceof JDIDebugTarget) + || !(thread instanceof JDIThread)) { + return; + } + JDIDebugTarget target = (JDIDebugTarget) thread.getDebugTarget(); + if (thread != fFilteredThreadsByTarget.put(target, thread)) { + // recreate the breakpoint only if it is not the same thread + + // Other breakpoints set attributes on the underlying + // marker and the marker changes are eventually + // propagated to the target. The target then asks the + // breakpoint to update its request. Since thread filters + // are transient properties, they are not set on + // the marker. Thus we must update the request + // here. + recreate(target); + fireChanged(); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse + * .debug.core.DebugEvent[]) + */ + @Override + public void handleDebugEvents(DebugEvent[] events) { + for (DebugEvent event : events) { + if (event.getKind() == DebugEvent.TERMINATE) { + Object source = event.getSource(); + if (!(source instanceof JDIThread)) { + return; + } + try { + cleanupForThreadTermination((JDIThread) source); + } catch (VMDisconnectedException exception) { + // Thread death often occurs at shutdown. + // A VMDisconnectedException trying to + // update the breakpoint request is + // acceptable. + } + } + } + } + + /** + * Removes cached information relevant to this thread which has terminated. + * + * Remove thread filters for terminated threads + * + * Subclasses may override but need to call super. + */ + protected void cleanupForThreadTermination(JDIThread thread) { + JDIDebugTarget target = (JDIDebugTarget) thread.getDebugTarget(); + try { + if (thread == getThreadFilter(target)) { + removeThreadFilter(target); + } + } catch (CoreException exception) { + JDIDebugPlugin.log(exception); + } + } + + /** + * EventRequest does not support thread filters, so they can't be set + * generically here. However, each of the breakpoint subclasses of + * EventRequest do support thread filters. So subclasses can set thread + * filters on their specific request type. + */ + protected abstract void setRequestThreadFilter(EventRequest request, + ThreadReference thread); + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#getThreadFilter(org.eclipse + * .jdt.debug.core.IJavaDebugTarget) + */ + @Override + public IJavaThread getThreadFilter(IJavaDebugTarget target) { + return fFilteredThreadsByTarget.get(target); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getThreadFilters() + */ + @Override + public IJavaThread[] getThreadFilters() { + IJavaThread[] threads = null; + Collection values = fFilteredThreadsByTarget.values(); + threads = new IJavaThread[values.size()]; + values.toArray(threads); + return threads; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#removeThreadFilter(org.eclipse + * .jdt.debug.core.IJavaDebugTarget) + */ + @Override + public void removeThreadFilter(IJavaDebugTarget javaTarget) + throws CoreException { + if (!(javaTarget instanceof JDIDebugTarget)) { + return; + } + JDIDebugTarget target = (JDIDebugTarget) javaTarget; + if (fFilteredThreadsByTarget.remove(target) != null) { + recreate(target); + fireChanged(); + } + } + + /** + * Returns whether this breakpoint should be installed in the given + * reference type in the given target according to registered breakpoint + * listeners. + * + * @param target + * debug target + * @param type + * reference type or null if this breakpoint is not + * installed in a specific type + */ + protected boolean queryInstallListeners(JDIDebugTarget target, + ReferenceType type) { + JDIDebugPlugin plugin = JDIDebugPlugin.getDefault(); + if (plugin != null) { + IJavaType jt = null; + if (type != null) { + jt = JDIType.createType(target, type); + } + return plugin.fireInstalling(target, this, jt); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#addInstanceFilter(org.eclipse + * .jdt.debug.core.IJavaObject) + */ + @Override + public void addInstanceFilter(IJavaObject object) throws CoreException { + if (fInstanceFilters == null) { + fInstanceFilters = new ArrayList<>(); + } + if (!fInstanceFilters.contains(object)) { + fInstanceFilters.add(object); + recreate((JDIDebugTarget) object.getDebugTarget()); + fireChanged(); + } + } + + /** + * Change notification when there are no marker changes. If the marker does + * not exist, do not fire a change notification (the marker may not exist if + * the associated project was closed). + */ + protected void fireChanged() { + DebugPlugin plugin = DebugPlugin.getDefault(); + if (plugin != null && markerExists()) { + plugin.getBreakpointManager().fireBreakpointChanged(this); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getInstanceFilters() + */ + @Override + public IJavaObject[] getInstanceFilters() { + if (fInstanceFilters == null || fInstanceFilters.isEmpty()) { + return fgEmptyInstanceFilters; + } + return fInstanceFilters + .toArray(new IJavaObject[fInstanceFilters.size()]); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#removeInstanceFilter(org.eclipse + * .jdt.debug.core.IJavaObject) + */ + @Override + public void removeInstanceFilter(IJavaObject object) throws CoreException { + if (fInstanceFilters == null) { + return; + } + if (fInstanceFilters.remove(object)) { + recreate((JDIDebugTarget) object.getDebugTarget()); + fireChanged(); + } + } + + /** + * An attribute of this breakpoint has changed - recreate event requests in + * all targets. + */ + protected void recreate() throws CoreException { + DebugPlugin plugin = DebugPlugin.getDefault(); + if (plugin != null) { + IDebugTarget[] targets = plugin.getLaunchManager() + .getDebugTargets(); + for (IDebugTarget target : targets) { + MultiStatus multiStatus = new MultiStatus( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.ERROR, + JDIDebugBreakpointMessages.JavaBreakpoint_Exception, + null); + IJavaDebugTarget jdiTarget = target + .getAdapter(IJavaDebugTarget.class); + if (jdiTarget instanceof JDIDebugTarget) { + try { + recreate((JDIDebugTarget) jdiTarget); + } catch (CoreException e) { + multiStatus.add(e.getStatus()); + } + } + if (!multiStatus.isOK()) { + throw new CoreException(multiStatus); + } + } + } + } + + /** + * Recreate this breakpoint in the given target, as long as the target + * already contains this breakpoint. + * + * @param target + * the target in which to re-create the breakpoint + */ + protected void recreate(JDIDebugTarget target) throws CoreException { + if (target.isAvailable() && target.getBreakpoints().contains(this)) { + removeRequests(target); + createRequests(target); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.Breakpoint#setEnabled(boolean) + */ + @Override + public void setEnabled(boolean enabled) throws CoreException { + super.setEnabled(enabled); + recreate(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#supportsInstanceFilters() + */ + @Override + public boolean supportsInstanceFilters() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#supportsThreadFilters() + */ + @Override + public boolean supportsThreadFilters() { + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#addBreakpointListener(java + * .lang.String) + */ + @Override + public synchronized void addBreakpointListener(String identifier) + throws CoreException { + if (fBreakpointListenerIds == null) { + fBreakpointListenerIds = new ArrayList<>(); + } + if (!fBreakpointListenerIds.contains(identifier)) { + fBreakpointListenerIds.add(identifier); + writeBreakpointListeners(); + } + } + + /** + * Writes the current breakpoint listener collection to the underlying + * marker. + * + * @throws CoreException + */ + private void writeBreakpointListeners() throws CoreException { + StringBuilder buf = new StringBuilder(); + Iterator iterator = fBreakpointListenerIds.iterator(); + while (iterator.hasNext()) { + buf.append(iterator.next()); + if (iterator.hasNext()) { + buf.append(","); //$NON-NLS-1$ + } + } + setAttribute(BREAKPOINT_LISTENERS, buf.toString()); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#removeBreakpointListener(java + * .lang.String) + */ + @Override + public synchronized boolean removeBreakpointListener(String identifier) + throws CoreException { + if (fBreakpointListenerIds != null) { + if (fBreakpointListenerIds.remove(identifier)) { + writeBreakpointListeners(); + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getBreakpointListeners() + */ + @Override + public synchronized String[] getBreakpointListeners() throws CoreException { + // use the cache in case the underlying marker has been deleted + if (fBreakpointListenerIds == null) { + return new String[0]; + } + return fBreakpointListenerIds + .toArray(new String[fBreakpointListenerIds.size()]); + } + + /** + * Reads breakpoint listeners from the underlying marker. + * + * @return breakpoint listener identifiers stored in this breakpoint's + * marker + * @throws CoreException + * if no marker + */ + private String[] readBreakpointListeners() throws CoreException { + String value = ensureMarker().getAttribute(BREAKPOINT_LISTENERS, + (String) null); + if (value == null) { + return new String[0]; + } + return value.split(","); //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpointImportParticipant.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpointImportParticipant.java new file mode 100644 index 0000000000..9b48c2bfa9 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaBreakpointImportParticipant.java @@ -0,0 +1,800 @@ +/******************************************************************************* + * Copyright (c) 2008, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IBreakpointImportParticipant; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; +import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.EnumDeclaration; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.debug.core.IJavaWatchpoint; + +/** + * Default implementation covering the import of all platform Java breakpoints + * + * @since 3.5 + */ +public class JavaBreakpointImportParticipant implements + IBreakpointImportParticipant { + + // keep the last resource/timestamp with CU for optimization + IResource lastResourceVerified = null; + long lastResourceVerifiedTimeStamp = -1; + CompilationUnit lastCompilationUnit = null; + + class BreakpointVerifier extends ASTVisitor { + static final int TYPE = 0; + static final int METHOD = 1; + static final int FIELD = 2; + + String fTypename = null; + String fName = null; + String fSignature = null; + IBreakpoint fBreakpoint = null; + CompilationUnit fUnit = null; + Stack fTypeNameStack = null; + + /** + * Constructor + * + * @param breakpoint + * @param unit + */ + public BreakpointVerifier(IBreakpoint breakpoint, CompilationUnit unit) { + fTypename = getBreakpointTypeName(breakpoint); + fName = getMemberName(breakpoint); + fSignature = getMemberSignature(breakpoint); + fBreakpoint = breakpoint; + fUnit = unit; + fTypeNameStack = new Stack<>(); + } + + /** + * Returns the value of the {@link JavaBreakpoint#TYPE_NAME} attribute + * from the breakpoint or null + * + * @param breakpoint + * @return the value of the type name attribute + */ + String getBreakpointTypeName(IBreakpoint breakpoint) { + return breakpoint.getMarker().getAttribute( + JavaBreakpoint.TYPE_NAME, null); + } + + /** + * Returns the name of the member from the breakpoint attributes. The + * name will be one of (1) {@link JavaWatchpoint#FIELD_NAME}, if the + * breakpoint is a watchpoint, or (2) + * {@link JavaMethodBreakpoint#METHOD_NAME} if the breakpoint is a + * method or method entry breakpoint (3) null if there is + * no member name + * + * @param breakpoint + * @return the member name or null + */ + String getMemberName(IBreakpoint breakpoint) { + if (breakpoint instanceof IJavaWatchpoint) { + return breakpoint.getMarker().getAttribute( + JavaWatchpoint.FIELD_NAME, null); + } + return breakpoint.getMarker().getAttribute( + JavaMethodBreakpoint.METHOD_NAME, null); + } + + /** + * Returns the signature of the member, defined with the + * {@link JavaMethodBreakpoint#METHOD_SIGNATURE} attribute, or + * null + * + * @param breakpoint + * @return the signature of the member or null + */ + String getMemberSignature(IBreakpoint breakpoint) { + return breakpoint.getMarker().getAttribute( + JavaMethodBreakpoint.METHOD_SIGNATURE, null); + } + + /** + * Returns the fully qualified name of the enclosing type for the given + * node + * + * @param node + * @return the fully qualified name of the enclosing type + */ + private String getTypeName(ASTNode node) { + return getTypeName(node, new StringBuilder()); + } + + /** + * Constructs the qualified name of the enclosing parent type + * + * @param node + * the node to get the parent name for + * @param buffer + * the buffer to write the name into + * @return the fully qualified name of the parent + */ + private String getTypeName(ASTNode node, StringBuilder buffer) { + switch (node.getNodeType()) { + case ASTNode.COMPILATION_UNIT: { + CompilationUnit unit = (CompilationUnit) node; + PackageDeclaration packageDeclaration = unit.getPackage(); + if (packageDeclaration != null) { + buffer.insert(0, '.'); + buffer.insert(0, packageDeclaration.getName() + .getFullyQualifiedName()); + } + return String.valueOf(buffer); + } + default: { + if (node instanceof AbstractTypeDeclaration) { + AbstractTypeDeclaration typeDeclaration = (AbstractTypeDeclaration) node; + ITypeBinding binding = typeDeclaration.resolveBinding(); + if (binding != null) { + return binding.getBinaryName(); + } + if (typeDeclaration.isPackageMemberTypeDeclaration()) { + buffer.insert(0, typeDeclaration.getName() + .getIdentifier()); + } else { + buffer.insert(0, typeDeclaration.getName() + .getFullyQualifiedName()); + buffer.insert(0, '$'); + } + } + } + } + return getTypeName(node.getParent(), buffer); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration) + */ + @Override + public boolean visit(TypeDeclaration node) { + return doTypeVisit(node); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.TypeDeclaration) + */ + @Override + public void endVisit(TypeDeclaration node) { + doEndTypeVisit(); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration) + */ + @Override + public boolean visit(EnumDeclaration node) { + return doTypeVisit(node); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.EnumDeclaration) + */ + @Override + public void endVisit(EnumDeclaration node) { + doEndTypeVisit(); + } + + /** + * Cleans up after a type visit has ended + */ + private void doEndTypeVisit() { + if (!fTypeNameStack.isEmpty()) { + fTypeNameStack.pop(); + } + } + + /** + * Visits the type node and return if children should be visited + * + * @param node + * @return true if child nodes should be visited false otherwise + */ + private boolean doTypeVisit(AbstractTypeDeclaration node) { + SimpleName name = node.getName(); + String typename = getTypeName(node); + fTypeNameStack.push(typename); + if (!fTypename.startsWith(typename)) { + // we are examining the wrong type stop and process other types + return false; + } + if (fBreakpoint instanceof JavaClassPrepareBreakpoint + && name != null && typename.equals(fTypename)) { + int charstart = name.getStartPosition(); + IMarker marker = fBreakpoint.getMarker(); + try { + marker.setAttribute(IMarker.CHAR_START, charstart); + marker.setAttribute(IMarker.CHAR_END, + charstart + name.getLength()); + } catch (CoreException ce) { + } + // found the node we were looking for, do not visit children + return false; + } + return fTypename.indexOf('$') > -1 || name != null; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration) + */ + @Override + public boolean visit(FieldDeclaration node) { + if (!fTypename.equals(fTypeNameStack.peek())) { + return false; + } + List fragments = node.fragments(); + SimpleName name = null; + IMarker marker = fBreakpoint.getMarker(); + int currentstart = marker.getAttribute(IMarker.CHAR_START, -1); + for (VariableDeclarationFragment fragment : fragments) { + name = fragment.getName(); + if (name != null && name.getFullyQualifiedName().equals(fName)) { + // found field update the charstart / charend + int charstart = name.getStartPosition(); + if (currentstart != charstart) { + try { + marker.setAttribute(IMarker.CHAR_START, charstart); + marker.setAttribute(IMarker.CHAR_END, charstart + + name.getLength()); + } catch (CoreException ce) { + } + } + } + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration) + */ + @Override + public boolean visit(MethodDeclaration node) { + if (fTypeNameStack.isEmpty()) { + return false; + } + SimpleName name = node.getName(); + String typename = fTypeNameStack.peek(); + if (!fTypename.equals(typename) && !fTypename.startsWith(typename)) { + return false; + } + if (name != null && name.getFullyQualifiedName().equals(fName)) { + String sig = getMethodSignatureFromNode(node); + if (sig != null) { + sig = sig.replaceAll("\\.", "/"); //$NON-NLS-1$ //$NON-NLS-2$ + if (sig.equals(fSignature)) { + IMarker marker = fBreakpoint.getMarker(); + int currentstart = marker.getAttribute( + IMarker.CHAR_START, -1); + int charstart = name.getStartPosition(); + if (currentstart != charstart) { + try { + marker.setAttribute(IMarker.CHAR_START, + charstart); + marker.setAttribute(IMarker.CHAR_END, charstart + + name.getLength()); + } catch (CoreException ce) { + } + } + } + } + } + // visit children in the event we have a class load breakpoint on a + // local type + return fBreakpoint instanceof JavaClassPrepareBreakpoint; + } + + /** + * Creates a method signature from a specified {@link MethodDeclaration} + * + * @param node + * @return the signature for the given method node or null + */ + private String getMethodSignatureFromNode(MethodDeclaration node) { + Assert.isNotNull(node); + List params = node.parameters(); + List rparams = getParametersTypeNames(params); + if (rparams.size() == params.size()) { + if (!node.isConstructor()) { + Type returnType = node.getReturnType2(); + if (returnType != null) { + String rtype = getTypeSignature(returnType); + if (rtype != null) { + return Signature + .createMethodSignature( + rparams + .toArray(new String[rparams + .size()]), rtype); + } + } + } else { + StringBuilder buffer = new StringBuilder(); + buffer.append(""); //$NON-NLS-1$ + collectSyntheticParam(node, rparams); + buffer.append(Signature.createMethodSignature( + rparams.toArray(new String[rparams + .size()]), Signature.SIG_VOID)); + return buffer.toString(); + } + } + return null; + } + + /** + * Returns the listing of the signatures of the parameters passed in + * + * @param rawparams + * @return a listing of signatures for the specified parameters + */ + private List getParametersTypeNames(List rawparams) { + List rparams = new ArrayList<>(rawparams.size()); + String pname = null; + for (SingleVariableDeclaration param : rawparams) { + pname = getTypeSignature(param.getType()); + if (pname != null) { + rparams.add(pname); + } + } + return rparams; + } + + /** + * Processes the signature for the given {@link Type} + * + * @param type + * the type to process + * @return the signature for the type or null if one could + * not be derived + */ + private String getTypeSignature(Type type) { + ITypeBinding binding = type.resolveBinding(); + if (binding == null) { + return null; + } + switch (type.getNodeType()) { + case ASTNode.PRIMITIVE_TYPE: + case ASTNode.QUALIFIED_TYPE: + case ASTNode.SIMPLE_TYPE: { + return Signature.createTypeSignature( + binding.getQualifiedName(), true); + } + case ASTNode.ARRAY_TYPE: { + ArrayType a = (ArrayType) type; + return Signature + .createArraySignature( + getTypeSignature(a.getElementType()), + a.getDimensions()); + } + case ASTNode.PARAMETERIZED_TYPE: { + // we don't need to care about the other scoping types only the + // base type + return getTypeSignature(((ParameterizedType) type).getType()); + } + } + return null; + } + + /** + * Collects the synthetic parameter of the fully qualified name of the + * enclosing context for a constructor of an inner type + * + * @param method + * the constructor declaration + * @param rparams + * the listing of parameters to add to + */ + private void collectSyntheticParam(final MethodDeclaration method, + List rparams) { + Assert.isNotNull(method); + if (isInTopLevelType(method)) { + return; + } + ASTNode parent = method.getParent(); + StringBuilder name = new StringBuilder(); + while (parent != null) { + parent = parent.getParent(); + if (parent instanceof AbstractTypeDeclaration) { + AbstractTypeDeclaration type = (AbstractTypeDeclaration) parent; + name.insert(0, type.getName().getFullyQualifiedName()); + if (type.isMemberTypeDeclaration()) { + name.insert(0, '$'); + } + continue; + } + if (parent instanceof CompilationUnit) { + CompilationUnit cunit = (CompilationUnit) parent; + PackageDeclaration pdec = cunit.getPackage(); + if (pdec != null) { + name.insert(0, '.'); + name.insert(0, cunit.getPackage().getName() + .getFullyQualifiedName()); + } + } + } + name.insert(0, "L"); //$NON-NLS-1$ + name.append(';'); + if (name.length() > 2) { + rparams.add(0, name.toString()); + } + } + + /** + * Determines if the given {@link MethodDeclaration} is present in a top + * level type + * + * @param method + * @return + */ + private boolean isInTopLevelType(final MethodDeclaration method) { + TypeDeclaration type = (TypeDeclaration) method.getParent(); + return type != null && type.isPackageMemberTypeDeclaration(); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IBreakpointImportParticipant#matches(java + * .util.Map, org.eclipse.debug.core.model.IBreakpoint) + */ + @Override + public boolean matches(Map attributes, IBreakpoint breakpoint) + throws CoreException { + if (attributes == null || breakpoint == null) { + return false; + } + String type = (String) attributes.get("type"); //$NON-NLS-1$ + if (type == null) { + return false; + } + if (!breakpoint.getMarker().getType().equals(type)) { + return false; + } + if (breakpoint instanceof JavaClassPrepareBreakpoint) { + return matchesClassBreakpoint(attributes, + (JavaClassPrepareBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaExceptionBreakpoint) { + return matchesExceptionBreakpoint(attributes, + (JavaExceptionBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaMethodBreakpoint) { + return matchesMethodBreakpoint(attributes, + (JavaMethodBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaMethodEntryBreakpoint) { + return matchesMethodEntryBreakpoint(attributes, + (JavaMethodEntryBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaWatchpoint) { + return matchesWatchpoint(attributes, (JavaWatchpoint) breakpoint); + } + if (breakpoint instanceof JavaStratumLineBreakpoint) { + return matchesStratumLineBreakpoint(attributes, + (JavaStratumLineBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaPatternBreakpoint) { + return matchesPatternBreakpoint(attributes, + (JavaPatternBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaTargetPatternBreakpoint) { + return matchesTargetPatternBreakpoint(attributes, + (JavaTargetPatternBreakpoint) breakpoint); + } + if (breakpoint instanceof JavaLineBreakpoint) { + return matchesLineBreakpoint(attributes, + (JavaLineBreakpoint) breakpoint); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IBreakpointImportParticipant#verify(org. + * eclipse.debug.core.model.IBreakpoint) + */ + @Override + public void verify(IBreakpoint breakpoint) throws CoreException { + IResource resource = breakpoint.getMarker().getResource(); + CompilationUnit unit = null; + if (resource != null && resource.getType() == IResource.FILE) { + if (resource.equals(lastResourceVerified)) { + if (resource.getModificationStamp() == lastResourceVerifiedTimeStamp) { + unit = lastCompilationUnit; + } + } + if (unit == null) { + ICompilationUnit cunit = JavaCore.createCompilationUnitFrom((IFile) resource); + if (cunit != null) { + ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); + parser.setSource(cunit); + parser.setResolveBindings(true); + unit = (CompilationUnit) parser.createAST(new NullProgressMonitor()); + } + } + } + if (unit != null) { + lastResourceVerified = resource; + lastCompilationUnit = unit; + lastResourceVerifiedTimeStamp = lastResourceVerified.getModificationStamp(); + if (breakpoint instanceof JavaClassPrepareBreakpoint + || breakpoint instanceof JavaWatchpoint + || breakpoint instanceof JavaMethodEntryBreakpoint + || breakpoint instanceof JavaMethodBreakpoint) { + unit.accept(new BreakpointVerifier(breakpoint, unit)); + } else if (breakpoint instanceof JavaLineBreakpoint) { + JavaLineBreakpoint bp = (JavaLineBreakpoint) breakpoint; + // line breakpoint use the ValidBreakpointLocationLocator to + // (re)place it + int currentline = bp.getLineNumber(); + ValidBreakpointLocationLocator locator = new ValidBreakpointLocationLocator( + unit, currentline, true, true); + unit.accept(locator); + int newline = locator.getLineLocation(); + if (locator.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LINE) { + if (currentline != newline) { + if (locator.getFullyQualifiedTypeName() == null) { + throw new CoreException(Status.CANCEL_STATUS); + } + bp.getMarker().setAttribute(JavaBreakpoint.TYPE_NAME, + locator.getFullyQualifiedTypeName()); + bp.getMarker().setAttribute(IMarker.LINE_NUMBER, + newline); + int length = bp.getCharEnd() - bp.getCharStart(); + int pos = unit.getPosition(newline, 1); + bp.getMarker().setAttribute(IMarker.CHAR_START, pos); + bp.getMarker().setAttribute(IMarker.CHAR_END, + pos + length); + } + } else { + // the line breakpoint will not be a line breakpoint anymore + // get rid of it + throw new CoreException(Status.CANCEL_STATUS); + } + } + } + } + + /** + * Compares two attributes in a null safe way + * + * @param attr1 + * the first attribute + * @param attr2 + * the second attribute + * @return true if the attributes are equal, false otherwise. If both + * attributes are null they are considered to be equal + */ + private boolean attributesEqual(Object attr1, Object attr2) { + if (attr1 == null) { + return attr2 == null; + } + if (attr2 == null) { + return false; + } + return attr1.equals(attr2); + } + + /** + * Returns if the given map of attributes matches the given line breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesLineBreakpoint(Map attributes, + JavaLineBreakpoint breakpoint) throws CoreException { + Integer line = (Integer) attributes.get(IMarker.LINE_NUMBER); + return breakpoint.getLineNumber() == (line == null ? -1 : line.intValue()) + && attributesEqual(breakpoint.getTypeName(), attributes.get(JavaBreakpoint.TYPE_NAME)); + } + + /** + * Returns if the given map of attributes matches the given class prepare + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesClassBreakpoint(Map attributes, + JavaClassPrepareBreakpoint breakpoint) throws CoreException { + Integer type = (Integer) attributes + .get(JavaClassPrepareBreakpoint.MEMBER_TYPE); + return attributesEqual(breakpoint.getTypeName(), + attributes.get(JavaBreakpoint.TYPE_NAME)) + && breakpoint.getMemberType() == (type == null ? -1 : type + .intValue()); + } + + /** + * Returns if the given map of attributes matches the given exception + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesExceptionBreakpoint(Map attributes, + JavaExceptionBreakpoint breakpoint) throws CoreException { + return attributesEqual(breakpoint.getTypeName(), + attributes.get(JavaBreakpoint.TYPE_NAME)); + + } + + /** + * Returns if the given map of attributes matches the given method + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesMethodBreakpoint(Map attributes, + JavaMethodBreakpoint breakpoint) throws CoreException { + return attributesEqual(breakpoint.getTypeName(), + attributes.get(JavaBreakpoint.TYPE_NAME)) + && attributesEqual(breakpoint.getMethodName(), + attributes.get(JavaMethodBreakpoint.METHOD_NAME)) + && attributesEqual(breakpoint.getMethodSignature(), + attributes.get(JavaMethodBreakpoint.METHOD_SIGNATURE)); + } + + /** + * Returns if the given map of attributes matches the given method entry + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesMethodEntryBreakpoint(Map attributes, + JavaMethodEntryBreakpoint breakpoint) throws CoreException { + return attributesEqual(breakpoint.getTypeName(), + attributes.get(JavaBreakpoint.TYPE_NAME)) + && attributesEqual(breakpoint.getMethodName(), + attributes.get(JavaMethodBreakpoint.METHOD_NAME)) + && attributesEqual(breakpoint.getMethodSignature(), + attributes.get(JavaMethodBreakpoint.METHOD_SIGNATURE)); + } + + /** + * Returns if the given map of attributes matches the given watchpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the watchpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesWatchpoint(Map attributes, JavaWatchpoint watchpoint) + throws CoreException { + return watchpoint.getFieldName().equals( + attributes.get(JavaWatchpoint.FIELD_NAME)) + && attributesEqual(watchpoint.getTypeName(), + attributes.get(JavaBreakpoint.TYPE_NAME)); + } + + /** + * Returns if the given map of attributes matches the given stratum line + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesStratumLineBreakpoint(Map attributes, + JavaStratumLineBreakpoint breakpoint) throws CoreException { + Integer line = (Integer) attributes.get(IMarker.LINE_NUMBER); + return breakpoint.getLineNumber() == (line == null ? -1 : line + .intValue()) + && attributesEqual(breakpoint.getSourceName(), + attributes.get(JavaLineBreakpoint.SOURCE_NAME)) + && attributesEqual(breakpoint.getStratum(), + attributes.get(JavaStratumLineBreakpoint.STRATUM)) + && attributesEqual(breakpoint.getSourcePath(), + attributes.get(JavaStratumLineBreakpoint.SOURCE_PATH)); + } + + /** + * Returns if the given map of attributes matches the given pattern + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesPatternBreakpoint(Map attributes, + JavaPatternBreakpoint breakpoint) throws CoreException { + Integer line = (Integer) attributes.get(IMarker.LINE_NUMBER); + return breakpoint.getLineNumber() == (line == null ? -1 : line + .intValue()) + && attributesEqual(breakpoint.getSourceName(), + attributes.get(JavaLineBreakpoint.SOURCE_NAME)) && + // TDOD comparing pattern too restrictive?? + breakpoint.getPattern().equals( + attributes.get(JavaPatternBreakpoint.PATTERN)); + } + + /** + * Returns if the given map of attributes matches the given target pattern + * breakpoint + * + * @param attributes + * @param breakpoint + * @return true if the attributes match the breakpoints' attributes, false + * otherwise + * @throws CoreException + */ + private boolean matchesTargetPatternBreakpoint(Map attributes, + JavaTargetPatternBreakpoint breakpoint) throws CoreException { + Integer line = (Integer) attributes.get(IMarker.LINE_NUMBER); + return breakpoint.getLineNumber() == (line == null ? -1 : line + .intValue()) + && attributesEqual(breakpoint.getTypeName(), + attributes.get(JavaBreakpoint.TYPE_NAME)) + && attributesEqual(breakpoint.getSourceName(), + attributes.get(JavaLineBreakpoint.SOURCE_NAME)); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java new file mode 100644 index 0000000000..b81e674fb2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2000, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.Map; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.jdt.debug.core.IJavaClassPrepareBreakpoint; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; + +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.EventRequest; + +/** + * Class prepare breakpoint. + * + * @since 3.0 + */ +public class JavaClassPrepareBreakpoint extends JavaBreakpoint implements + IJavaClassPrepareBreakpoint { + + public static final String JAVA_CLASS_PREPARE_BREAKPOINT = "org.eclipse.jdt.debug.javaClassPrepareBreakpointMarker"; //$NON-NLS-1$ + + /** + * Class prepare breakpoint attribute storing the type of member this + * breakpoint is associated with (value + * "org.eclipse.jdt.debug.core.memberType"), encoded as an + * integer. + */ + protected static final String MEMBER_TYPE = "org.eclipse.jdt.debug.core.memberType"; //$NON-NLS-1$ + + private Pattern pattern = null; + + /** + * Creates and returns a Java class prepare breakpoint for the given type. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param typeName + * the fully qualified name of the type for which to create the + * breakpoint + * @param memberType + * one of TYPE_CLASS or TYPE_INTERFACE + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param add + * whether to add this breakpoint to the breakpoint manager + * @return a Java class prepare breakpoint + * @exception DebugException + * if unable to create the associated marker due to a lower + * level exception. + */ + public JavaClassPrepareBreakpoint(final IResource resource, + final String typeName, final int memberType, final int charStart, + final int charEnd, final boolean add, final Map attributes) + throws DebugException { + IWorkspaceRunnable wr = monitor -> { + // add attributes + attributes.put(IBreakpoint.ID, getModelIdentifier()); + attributes.put(IMarker.CHAR_START, Integer.valueOf(charStart)); + attributes.put(IMarker.CHAR_END, Integer.valueOf(charEnd)); + attributes.put(TYPE_NAME, typeName); + attributes.put(MEMBER_TYPE, Integer.valueOf(memberType)); + attributes.put(ENABLED, Boolean.TRUE); + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + + // create the marker + setMarker(resource.createMarker(JAVA_CLASS_PREPARE_BREAKPOINT, attributes)); + + register(add); + }; + run(getMarkerRule(resource), wr); + } + + public JavaClassPrepareBreakpoint() { + } + + /** + * Creates event requests for the given target + */ + @Override + protected void createRequests(JDIDebugTarget target) throws CoreException { + if (target.isTerminated() || shouldSkipBreakpoint()) { + return; + } + String referenceTypeName = getTypeName(); + if (referenceTypeName == null) { + return; + } + + ClassPrepareRequest request = target.createClassPrepareRequest( + referenceTypeName, null, false); + configureRequestHitCount(request); + updateEnabledState(request, target); + registerRequest(request, target); + // TODO: do we show anything for types already loaded? + incrementInstallCount(); + } + + /** + * Remove the given request from the given target. If the request is the + * breakpoint request associated with this breakpoint, decrement the install + * count. + */ + @Override + protected void deregisterRequest(EventRequest request, JDIDebugTarget target) + throws CoreException { + target.removeJDIEventListener(this, request); + // A request may be getting deregistered because the breakpoint has + // been deleted. It may be that this occurred because of a marker + // deletion. + // Don't try updating the marker (decrementing the install count) if + // it no longer exists. + if (getMarker().exists()) { + decrementInstallCount(); + } + } + + /* + * (non-Javadoc) + * + * Not supported for class prepare breakpoints. + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * addInstanceFilter(com.sun.jdi.request.EventRequest, + * com.sun.jdi.ObjectReference) + */ + @Override + protected void addInstanceFilter(EventRequest request, + ObjectReference object) { + } + + /* + * (non-Javadoc) + * + * This method not used for class prepare breakpoints. + * + * @see + * org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#newRequest + * (org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, + * com.sun.jdi.ReferenceType) + */ + @Override + protected EventRequest[] newRequests(JDIDebugTarget target, + ReferenceType type) throws CoreException { + return null; + } + + /* + * (non-Javadoc) + * + * Not supported for class prepare breakpoints. + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * setRequestThreadFilter(com.sun.jdi.request.EventRequest, + * com.sun.jdi.ThreadReference) + */ + @Override + protected void setRequestThreadFilter(EventRequest request, + ThreadReference thread) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * handleClassPrepareEvent(com.sun.jdi.event.ClassPrepareEvent, + * org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + public boolean handleClassPrepareEvent(ClassPrepareEvent event, + JDIDebugTarget target, boolean suspendVote) { + try { + if (pattern == null){ + String typeName = ".*";//$NON-NLS-1$ + String breakpointName = ensureMarker().getAttribute(TYPE_NAME, null); + typeName = typeName + breakpointName.replaceAll("\\.", "\\\\."); //$NON-NLS-1$//$NON-NLS-2$ + typeName = typeName.replaceAll("\\$", "\\\\\\$"); //$NON-NLS-1$//$NON-NLS-2$ + typeName = typeName.concat(".*"); //$NON-NLS-1$ + pattern = Pattern.compile(typeName); + } + if (isEnabled() && pattern.matcher(event.referenceType().name()).find()){ + ThreadReference threadRef = event.thread(); + JDIThread thread = target.findThread(threadRef); + if (thread == null || thread.isIgnoringBreakpoints()) { + return true; + } + fInstalledTypeName = event.referenceType().name(); + return handleBreakpointEvent(event, thread, suspendVote); + } + } catch (CoreException e) { + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * classPrepareComplete(com.sun.jdi.event.Event, + * org.eclipse.jdt.internal.debug.core.model.JDIThread, boolean) + */ + @Override + protected void classPrepareComplete(Event event, JDIThread thread, + boolean suspend, EventSet eventSet) { + thread.completeBreakpointHandling(this, suspend, true, eventSet); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaClassPrepareBreakpoint#getMemberType() + */ + @Override + public int getMemberType() throws CoreException { + return ensureMarker().getAttribute(MEMBER_TYPE, + IJavaClassPrepareBreakpoint.TYPE_CLASS); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#supportsInstanceFilters() + */ + @Override + public boolean supportsInstanceFilters() { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#addInstanceFilter(org.eclipse + * .jdt.debug.core.IJavaObject) + */ + @Override + public void addInstanceFilter(IJavaObject object) throws CoreException { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + JDIDebugBreakpointMessages.JavaClassPrepareBreakpoint_2, null)); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaBreakpoint#setThreadFilter(org.eclipse + * .jdt.debug.core.IJavaThread) + */ + @Override + public void setThreadFilter(IJavaThread thread) throws CoreException { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, + JDIDebugBreakpointMessages.JavaClassPrepareBreakpoint_3, null)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#supportsThreadFilters() + */ + @Override + public boolean supportsThreadFilters() { + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java new file mode 100644 index 0000000000..f0fdb4283e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaExceptionBreakpoint.java @@ -0,0 +1,817 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; +import org.eclipse.jdt.internal.debug.core.model.MethodResult; +import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType; +import org.eclipse.osgi.util.NLS; + +import com.sun.jdi.ClassType; +import com.sun.jdi.Location; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.ExceptionEvent; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; +import com.sun.jdi.request.ExceptionRequest; + +public class JavaExceptionBreakpoint extends JavaBreakpoint implements + IJavaExceptionBreakpoint { + + public static final String JAVA_EXCEPTION_BREAKPOINT = "org.eclipse.jdt.debug.javaExceptionBreakpointMarker"; //$NON-NLS-1$ + + /** + * Exception breakpoint attribute storing the suspend on caught value (value + * "org.eclipse.jdt.debug.core.caught"). This attribute is + * stored as a boolean. When this attribute is + * true, a caught exception of the associated type will cause + * execution to suspend . + */ + protected static final String CAUGHT = "org.eclipse.jdt.debug.core.caught"; //$NON-NLS-1$ + /** + * Exception breakpoint attribute storing the suspend on uncaught value + * (value "org.eclipse.jdt.debug.core.uncaught"). This + * attribute is stored as a boolean. When this attribute is + * true, an uncaught exception of the associated type will + * cause execution to suspend. + */ + protected static final String UNCAUGHT = "org.eclipse.jdt.debug.core.uncaught"; //$NON-NLS-1$ + /** + * Exception breakpoint attribute storing the checked value (value + * "org.eclipse.jdt.debug.core.checked"). This attribute is + * stored as a boolean, indicating whether an exception is a + * checked exception. + */ + protected static final String CHECKED = "org.eclipse.jdt.debug.core.checked"; //$NON-NLS-1$ + + /** + * Exception breakpoint attribute storing the String value (value + * "org.eclipse.jdt.debug.core.filters"). This attribute is + * stored as a String, a comma delimited list of class filters. + * The filters are applied as inclusion or exclusion depending on + * INCLUSIVE_FILTERS. + */ + protected static final String INCLUSION_FILTERS = "org.eclipse.jdt.debug.core.inclusion_filters"; //$NON-NLS-1$ + + /** + * Exception breakpoint attribute storing the String value (value + * "org.eclipse.jdt.debug.core.filters"). This attribute is + * stored as a String, a comma delimited list of class filters. + * The filters are applied as inclusion or exclusion depending on + * INCLUSIVE_FILTERS. + */ + protected static final String EXCLUSION_FILTERS = "org.eclipse.jdt.debug.core.exclusion_filters"; //$NON-NLS-1$ + /** + * Allows the user to specify whether we should suspend if subclasses of the + * specified exception are thrown/caught + * + * @since 3.2 + */ + protected static final String SUSPEND_ON_SUBCLASSES = "org.eclipse.jdt.debug.core.suspend_on_subclasses"; //$NON-NLS-1$ + + /** + * Allows the user to specify that each exception instance matching this breakpoint should suspend only once, i.e., re-throws and finally clauses + * will not again suspend on an exception instance that had already caused a suspend. + * + * @since 3.14 + */ + protected static final String SUSPEND_ON_RECURRENCE = "org.eclipse.jdt.debug.core.suspend_on_recurrence"; //$NON-NLS-1$ + + /** + * Name of the exception that was actually hit (could be a sub-type of the + * type that is being caught). + */ + protected String fExceptionName = null; + + /** + * The current set of inclusion class filters. + */ + protected String[] fInclusionClassFilters = null; + + /** + * The current set of inclusion class filters. + */ + protected String[] fExclusionClassFilters = null; + + private ObjectReference fLastException; + private JDIDebugTarget fLastTarget; + + public JavaExceptionBreakpoint() { + } + + /** + * Creates and returns an exception breakpoint for the given (throwable) + * type. Caught and uncaught specify where the exception should cause thread + * suspensions - that is, in caught and/or uncaught locations. Checked + * indicates if the given exception is a checked exception. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param exceptionName + * the fully qualified name of the exception for which to create + * the breakpoint + * @param caught + * whether to suspend in caught locations + * @param uncaught + * whether to suspend in uncaught locations + * @param checked + * whether the exception is a checked exception + * @param add + * whether to add this breakpoint to the breakpoint manager + * @return a Java exception breakpoint + * @exception DebugException + * if unable to create the associated marker due to a lower + * level exception. + */ + public JavaExceptionBreakpoint(final IResource resource, + final String exceptionName, final boolean caught, + final boolean uncaught, final boolean checked, final boolean add, + final Map attributes) throws DebugException { + IWorkspaceRunnable wr = monitor -> { + // add attributes + attributes.put(IBreakpoint.ID, getModelIdentifier()); + attributes.put(TYPE_NAME, exceptionName); + attributes.put(ENABLED, Boolean.TRUE); + attributes.put(CAUGHT, Boolean.valueOf(caught)); + attributes.put(UNCAUGHT, Boolean.valueOf(uncaught)); + attributes.put(CHECKED, Boolean.valueOf(checked)); + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + + // create the marker + setMarker(resource.createMarker(JAVA_EXCEPTION_BREAKPOINT, attributes)); + + register(add); + }; + run(getMarkerRule(resource), wr); + } + + /** + * Creates a request in the given target to suspend when the given exception + * type is thrown. The request is returned installed, configured, and + * enabled as appropriate for this breakpoint. + */ + @Override + protected EventRequest[] newRequests(JDIDebugTarget target, + ReferenceType type) throws CoreException { + if (!isCaught() && !isUncaught()) { + return null; + } + ExceptionRequest request = null; + EventRequestManager manager = target.getEventRequestManager(); + if (manager == null) { + target.requestFailed( + JDIDebugBreakpointMessages.JavaExceptionBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1, + new VMDisconnectedException()); + return null; + } + + try { + request = manager.createExceptionRequest(type, isCaught(), + isUncaught()); + configureRequest(request, target); + } catch (VMDisconnectedException e) { + if (target.isAvailable()) { + JDIDebugPlugin.log(e); + } + return null; + } catch (RuntimeException e) { + target.internalError(e); + return null; + } + return new EventRequest[] { request }; + } + + /** + * Enable this exception breakpoint. + * + * If the exception breakpoint is not catching caught or uncaught, turn both + * modes on. If this isn't done, the resulting state (enabled with caught + * and uncaught both disabled) is ambiguous. + */ + @Override + public void setEnabled(boolean enabled) throws CoreException { + if (enabled) { + if (!(isCaught() || isUncaught())) { + setAttributes(new String[] { CAUGHT, UNCAUGHT }, new Object[] { + Boolean.TRUE, Boolean.TRUE }); + } + } + super.setEnabled(enabled); + } + + /** + * Sets the values for whether this breakpoint will suspend execution when + * the associated exception is thrown and caught or not caught. + */ + protected void setCaughtAndUncaught(boolean caught, boolean uncaught) + throws CoreException { + Object[] values = new Object[] { Boolean.valueOf(caught), + Boolean.valueOf(uncaught) }; + String[] attributes = new String[] { CAUGHT, UNCAUGHT }; + setAttributes(attributes, values); + } + + /** + * @see IJavaExceptionBreakpoint#isCaught() + */ + @Override + public boolean isCaught() throws CoreException { + return ensureMarker().getAttribute(CAUGHT, false); + } + + /** + * @see IJavaExceptionBreakpoint#setCaught(boolean) + */ + @Override + public void setCaught(boolean caught) throws CoreException { + if (caught == isCaught()) { + return; + } + setAttribute(CAUGHT, caught); + if (caught && !isEnabled()) { + setEnabled(true); + } else if (!(caught || isUncaught())) { + setEnabled(false); + } + recreate(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#setSuspendOnSubclasses + * (boolean) + */ + public void setSuspendOnSubclasses(boolean suspend) throws CoreException { + if (suspend != isSuspendOnSubclasses()) { + setAttribute(SUSPEND_ON_SUBCLASSES, suspend); + recreate(); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#isSuspendOnSubclasses + * () + */ + public boolean isSuspendOnSubclasses() throws CoreException { + return ensureMarker().getAttribute(SUSPEND_ON_SUBCLASSES, false); + } + + /** + * @see IJavaExceptionBreakpoint#isUncaught() + */ + @Override + public boolean isUncaught() throws CoreException { + return ensureMarker().getAttribute(UNCAUGHT, false); + } + + /** + * @see IJavaExceptionBreakpoint#setUncaught(boolean) + */ + @Override + public void setUncaught(boolean uncaught) throws CoreException { + if (uncaught == isUncaught()) { + return; + } + setAttribute(UNCAUGHT, uncaught); + if (uncaught && !isEnabled()) { + setEnabled(true); + } else if (!(uncaught || isCaught())) { + setEnabled(false); + } + recreate(); + } + + @Override + public SuspendOnRecurrenceStrategy getSuspendOnRecurrenceStrategy() throws CoreException { + SuspendOnRecurrenceStrategy defaultStrategy = getWorkspaceSuspendOnRecurrenceStrategy(); + int valueIndex = ensureMarker().getAttribute(SUSPEND_ON_RECURRENCE, defaultStrategy.ordinal()); + return SuspendOnRecurrenceStrategy.values()[valueIndex]; + } + + @Override + public void setSuspendOnRecurrenceStrategy(SuspendOnRecurrenceStrategy strategy) throws CoreException { + setAttribute(SUSPEND_ON_RECURRENCE, strategy.ordinal()); + // don't re-create, the change only affects the debugger, not the target + } + + /** + * @see IJavaExceptionBreakpoint#isChecked() + */ + @Override + public boolean isChecked() throws CoreException { + return ensureMarker().getAttribute(CHECKED, false); + } + + /** + * @see JavaBreakpoint#setRequestThreadFilter(EventRequest) + */ + @Override + protected void setRequestThreadFilter(EventRequest request, + ThreadReference thread) { + ((ExceptionRequest) request).addThreadFilter(thread); + } + + /** + * @see JavaBreakpoint#handleBreakpointEvent(Event, JDIDebugTarget, + * JDIThread) Decides how to handle an exception being thrown + * + * @return true if we do not want to suspend false otherwise + */ + @Override + public boolean handleBreakpointEvent(Event event, JDIThread thread, + boolean suspendVote) { + boolean result = handleBreakpointEventInternal(event, thread, suspendVote); + if (!result) { + if (event instanceof ExceptionEvent) { + // about to suspend, store result + ExceptionEvent exceptionEvent = (ExceptionEvent) event; + thread.setMethodResult(new MethodResult(exceptionEvent.location().method(), -1, exceptionEvent.exception(), ResultType.throwing)); + } + } + return result; + } + + private boolean handleBreakpointEventInternal(Event event, JDIThread thread, boolean suspendVote) { + if (event instanceof ExceptionEvent) { + ObjectReference ex = ((ExceptionEvent) event).exception(); + fLastTarget = thread.getJavaDebugTarget(); + fLastException = ex; + String name = null; + try { + name = ex.type().name(); + if (!name.equals(getTypeName())) { + if (!isSuspendOnSubclasses() + & isSubclass((ClassType) ex.type(), getTypeName())) { + return true; + } + } + } catch (VMDisconnectedException e) { + return true; + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } catch (RuntimeException e) { + try { + thread.targetRequestFailed(e.getMessage(), e); + } catch (DebugException de) { + JDIDebugPlugin.log(e); + return false; + } + } + setExceptionName(name); + disableTriggerPoint(event); + IBreakpoint[] allBreakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(); + for (IBreakpoint iBreakpoint : allBreakpoints) { + if (iBreakpoint instanceof JavaExceptionBreakpoint) { + JavaExceptionBreakpoint jExceptionBreakpoint = (JavaExceptionBreakpoint)iBreakpoint; + try { + //This Java Exception breakpoint is the breakpoint created for catching compilation and Uncaught exception in JavaDebugOptionsManagaer initialization + // This does not have scope defined + if (jExceptionBreakpoint.getTypeName().equals(name)) { + if (jExceptionBreakpoint.getExclusionClassFilters().length >= 1 + || jExceptionBreakpoint.getInclusionClassFilters().length >= 1 + || filtersIncludeDefaultPackage(jExceptionBreakpoint.fInclusionClassFilters) + || filtersIncludeDefaultPackage(jExceptionBreakpoint.fExclusionClassFilters)) { + Location location = ((ExceptionEvent) event).location(); + String typeName = location.declaringType().name(); + boolean defaultPackage = typeName.indexOf('.') == -1; + boolean included = true; + String[] filters = jExceptionBreakpoint.getInclusionClassFilters(); + if (filters.length > 0) { + included = matchesFilters(filters, typeName, defaultPackage); + } + boolean excluded = false; + filters = jExceptionBreakpoint.getExclusionClassFilters(); + if (filters.length > 0) { + excluded = matchesFilters(filters, typeName, defaultPackage); + } + if (included && !excluded) { + return !suspend(thread, suspendVote); + } + return true; + } + } + } + catch (CoreException e) { + e.printStackTrace(); + } + } + } + + return !suspend(thread, suspendVote); + } + return true; + } + + /** + * Returns whether the given class type is a subclass of the classes with the + * given name. + * + * @param type + * the class type reference + * @return true if the specified the class type is a subclass of the class + * with the given name + * @since 3.2 + */ + private boolean isSubclass(ClassType type, String typeName) { + type = type.superclass(); + while (type != null) { + if (type.name().equals(typeName)) { + return true; + } + type = type.superclass(); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#setInstalledIn + * (org.eclipse.jdt.debug.core.IJavaDebugTarget, boolean) + */ + @Override + protected void setInstalledIn(IJavaDebugTarget target, boolean installed) { + fLastException = null; + fLastTarget = null; + super.setInstalledIn(target, installed); + } + + /** + * Determines of the filters for this exception include the default package + * or not + * + * @param filters + * the list of filters to inspect + * @return true if any one of the specified filters include the default + * package + */ + protected boolean filtersIncludeDefaultPackage(String[] filters) { + for (String filter : filters) { + if (filter.length() == 0 || (filter.indexOf('.') == -1)) { + return true; + } + } + return false; + } + + /** + * Returns whether the given type is in the given filter set. + * + * @param filters + * the filter set + * @param typeName + * fully qualified type name + * @param defaultPackage + * whether the type name is in the default package + * @return boolean + */ + protected boolean matchesFilters(String[] filters, String typeName, + boolean defaultPackage) { + for (String filter2 : filters) { + String filter = filter2; + if (defaultPackage && filter.length() == 0) { + return true; + } + + filter = filter.replaceAll("\\.", "\\\\."); //$NON-NLS-1$//$NON-NLS-2$ + filter = filter.replaceAll("\\*", "\\.\\*"); //$NON-NLS-1$//$NON-NLS-2$ + Pattern pattern = Pattern.compile(filter); + if (pattern.matcher(typeName).find()) { + return true; + } + } + return false; + } + + /** + * Sets the name of the exception that was last hit + * + * @param name + * fully qualified exception name + */ + protected void setExceptionName(String name) { + fExceptionName = name; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#getExceptionTypeName + * () + */ + @Override + public String getExceptionTypeName() { + return fExceptionName; + } + + /** + * @see IJavaExceptionBreakpoint#getFilters() + * @deprecated + */ + @Override + @Deprecated + public String[] getFilters() { + String[] iFilters = getInclusionFilters(); + String[] eFilters = getExclusionFilters(); + String[] filters = new String[iFilters.length + eFilters.length]; + System.arraycopy(iFilters, 0, filters, 0, iFilters.length); + System.arraycopy(eFilters, 0, filters, iFilters.length, eFilters.length); + return filters; + } + + /** + * @see IJavaExceptionBreakpoint#setFilters(String[], boolean) + * @deprecated + */ + @Override + @Deprecated + public void setFilters(String[] filters, boolean inclusive) + throws CoreException { + if (inclusive) { + setInclusionFilters(filters); + } else { + setExclusionFilters(filters); + } + recreate(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * configureRequest(com.sun.jdi.request.EventRequest, + * org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + protected void configureRequest(EventRequest eRequest, JDIDebugTarget target) + throws CoreException { + String[] iFilters = getInclusionClassFilters(); + String[] eFilters = getExclusionClassFilters(); + + ExceptionRequest request = (ExceptionRequest) eRequest; + + if (iFilters.length == 1) { + if (eFilters.length == 0) { + request.addClassFilter(iFilters[0]); + } + } else if (eFilters.length == 1) { + if (iFilters.length == 0) { + request.addClassExclusionFilter(eFilters[0]); + } + } + + super.configureRequest(eRequest, target); + } + + /** + * Serializes the array of Strings into one comma separated String. Removes + * duplicates. + */ + protected String serializeList(String[] list) { + if (list == null) { + return ""; //$NON-NLS-1$ + } + Set set = new HashSet<>(list.length); + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < list.length; i++) { + if (i > 0 && i < list.length) { + buffer.append(','); + } + String pattern = list[i]; + if (!set.contains(pattern)) { + if (pattern.length() == 0) { + // serialize the default package + pattern = "."; //$NON-NLS-1$ + } + buffer.append(pattern); + set.add(pattern); + } + } + return buffer.toString(); + } + + /** + * Parses the comma separated String into an array of Strings + */ + protected String[] parseList(String listString) { + List list = new ArrayList<>(10); + StringTokenizer tokenizer = new StringTokenizer(listString, ","); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (token.equals(".")) { //$NON-NLS-1$ + // serialized form for the default package + // @see serializeList(String[]) + token = ""; //$NON-NLS-1$ + } + list.add(token); + } + return list.toArray(new String[list.size()]); + } + + /** + * @see IJavaExceptionBreakpoint#isInclusiveFiltered() + * @deprecated + */ + @Override + @Deprecated + public boolean isInclusiveFiltered() throws CoreException { + return ensureMarker().getAttribute(INCLUSION_FILTERS, "").length() > 0; //$NON-NLS-1$ + } + + protected String[] getInclusionClassFilters() { + if (fInclusionClassFilters == null) { + try { + fInclusionClassFilters = parseList(ensureMarker().getAttribute( + INCLUSION_FILTERS, "")); //$NON-NLS-1$ + } catch (CoreException ce) { + fInclusionClassFilters = new String[] {}; + } + } + return fInclusionClassFilters; + } + + protected void setInclusionClassFilters(String[] filters) { + fInclusionClassFilters = filters; + } + + protected String[] getExclusionClassFilters() { + if (fExclusionClassFilters == null) { + try { + fExclusionClassFilters = parseList(ensureMarker().getAttribute( + EXCLUSION_FILTERS, "")); //$NON-NLS-1$ + } catch (CoreException ce) { + fExclusionClassFilters = new String[] {}; + } + } + return fExclusionClassFilters; + } + + protected void setExclusionClassFilters(String[] filters) { + fExclusionClassFilters = filters; + } + + /** + * @see JavaBreakpoint#installableReferenceType(ReferenceType, + * JDIDebugTarget) + */ + @Override + protected boolean installableReferenceType(ReferenceType type, + JDIDebugTarget target) throws CoreException { + String installableType = getTypeName(); + String queriedType = type.name(); + if (installableType == null || queriedType == null) { + return false; + } + if (installableType.equals(queriedType)) { + return queryInstallListeners(target, type); + } + + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#getExclusionFilters() + */ + @Override + public String[] getExclusionFilters() { + return getExclusionClassFilters(); + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#getInclusionFilters() + */ + @Override + public String[] getInclusionFilters() { + return getInclusionClassFilters(); + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#setExclusionFilters(String[]) + */ + @Override + public void setExclusionFilters(String[] filters) throws CoreException { + String serializedFilters = serializeList(filters); + + if (serializedFilters.equals(ensureMarker().getAttribute( + EXCLUSION_FILTERS, ""))) { //$NON-NLS-1$ + // no change + return; + } + + setExclusionClassFilters(filters); + + setAttribute(EXCLUSION_FILTERS, serializedFilters); + recreate(); + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint#setInclusionFilters(String[]) + */ + @Override + public void setInclusionFilters(String[] filters) throws CoreException { + String serializedFilters = serializeList(filters); + + if (serializedFilters.equals(ensureMarker().getAttribute( + INCLUSION_FILTERS, ""))) { //$NON-NLS-1$ + // no change + return; + } + + setInclusionClassFilters(filters); + + setAttribute(INCLUSION_FILTERS, serializedFilters); + recreate(); + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addInstanceFilter(EventRequest, + * ObjectReference) + */ + @Override + protected void addInstanceFilter(EventRequest request, + ObjectReference object) { + if (request instanceof ExceptionRequest) { + ((ExceptionRequest) request).addInstanceFilter(object); + } + } + + /** + * Returns the last exception object that was encountered by this exception + * + * TODO: make API in future release. + * + * @return + */ + public IJavaObject getLastException() { + if (fLastException != null) { + return (IJavaObject) JDIValue.createValue(fLastTarget, + fLastException); + } + return null; + } + + private static SuspendOnRecurrenceStrategy getWorkspaceSuspendOnRecurrenceStrategy() { + SuspendOnRecurrenceStrategy strategy = SuspendOnRecurrenceStrategy.RECURRENCE_UNCONFIGURED; + IPreferencesService preferencesService = Platform.getPreferencesService(); + if (preferencesService != null) { + String preferenceName = JDIDebugModel.PREF_SUSPEND_ON_RECURRENCE_STRATEGY; + String strategyPreference = preferencesService.getString(JDIDebugModel.getPluginIdentifier(), JDIDebugModel.PREF_SUSPEND_ON_RECURRENCE_STRATEGY, SuspendOnRecurrenceStrategy.RECURRENCE_UNCONFIGURED.name(), null); + try { + strategy = SuspendOnRecurrenceStrategy.valueOf(strategyPreference); + } catch (IllegalArgumentException e) { + String message = NLS.bind("Value \"{0}\" of preference \"{1}\" is illegal.", strategyPreference, preferenceName); //$NON-NLS-1$ + IStatus status = new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), message, e); + JDIDebugPlugin.log(status); + } + } + return strategy; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java new file mode 100644 index 0000000000..4f0d98e36f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java @@ -0,0 +1,683 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Igor Fedorenko - Bug 368212 - JavaLineBreakpoint.computeJavaProject does not let ISourceLocator evaluate the stackFrame + * Jesper Møller - Bug 422016 - [1.8] Having reference expressions or lambdas in file triggers warning for missing line numbers + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdi.internal.AccessibleImpl; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.eval.ICompiledExpression; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.NativeMethodException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.Event; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; + +public class JavaLineBreakpoint extends JavaBreakpoint implements + IJavaLineBreakpoint { + + /** + * Breakpoint attribute storing a breakpoint's conditional expression (value + * "org.eclipse.jdt.debug.core.condition"). This attribute is + * stored as a String. + */ + protected static final String CONDITION = "org.eclipse.jdt.debug.core.condition"; //$NON-NLS-1$ + /** + * Breakpoint attribute storing a breakpoint's condition enabled state + * (value "org.eclipse.jdt.debug.core.conditionEnabled"). This + * attribute is stored as an boolean. + */ + protected static final String CONDITION_ENABLED = "org.eclipse.jdt.debug.core.conditionEnabled"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing a breakpoint's condition suspend policy + * (value " org.eclipse.jdt.debug.core.conditionSuspendOnTrue" + * ). This attribute is stored as an boolean. + */ + protected static final String CONDITION_SUSPEND_ON_TRUE = "org.eclipse.jdt.debug.core.conditionSuspendOnTrue"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing a breakpoint's source file name (debug + * attribute) (value "org.eclipse.jdt.debug.core.sourceName"). + * This attribute is stored as a String. + */ + protected static final String SOURCE_NAME = "org.eclipse.jdt.debug.core.sourceName"; //$NON-NLS-1$ + + public static final String JAVA_LINE_BREAKPOINT = "org.eclipse.jdt.debug.javaLineBreakpointMarker"; //$NON-NLS-1$ + + /** + * Maps suspended threads to the suspend event that suspended them + */ + private final Map fSuspendEvents = new HashMap<>(); + /** + * The map of cached compiled expressions (ICompiledExpression) for this + * breakpoint, keyed by thread. This value must be cleared every time the + * breakpoint is added to a target. + */ + private final Map fCompiledExpressions = new HashMap<>(); + + /** + * Cache of projects for stack frames to avoid repetitive project resolution + * on conditional breakpoints. + */ + private final Map fProjectsByFrame = new HashMap<>(); + + /** + * The map of the result value of the condition (IValue) for this + * breakpoint, keyed by debug target. + */ + private final Map fConditionValues = new HashMap<>(); + + /** + * Status code indicating that a request to create a breakpoint in a type + * with no line number attributes has occurred. + */ + public static final int NO_LINE_NUMBERS = 162; + + public JavaLineBreakpoint() { + } + + /** + * @see JDIDebugModel#createLineBreakpoint(IResource, String, int, int, int, + * int, boolean, Map) + */ + public JavaLineBreakpoint(IResource resource, String typeName, + int lineNumber, int charStart, int charEnd, int hitCount, + boolean add, Map attributes) throws DebugException { + this(resource, typeName, lineNumber, charStart, charEnd, hitCount, add, + attributes, JAVA_LINE_BREAKPOINT); + } + + protected JavaLineBreakpoint(final IResource resource, + final String typeName, final int lineNumber, final int charStart, + final int charEnd, final int hitCount, final boolean add, + final Map attributes, final String markerType) + throws DebugException { + IWorkspaceRunnable wr = monitor -> { + + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addTypeNameAndHitCount(attributes, typeName, hitCount); + // set attributes + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // create the marker + setMarker(resource.createMarker(markerType, attributes)); + + // add to breakpoint manager if requested + register(add); + }; + run(getMarkerRule(resource), wr); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addToTarget + * (org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + public void addToTarget(JDIDebugTarget target) throws CoreException { + clearCachedExpressionFor(target); + super.addToTarget(target); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * removeFromTarget + * (org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + public void removeFromTarget(JDIDebugTarget target) throws CoreException { + clearCachedExpressionFor(target); + clearCachedSuspendEvents(target); + fConditionValues.remove(target); + super.removeFromTarget(target); + } + + /** + * Removes all suspend events which are currently being cached for threads + * in the given target. + */ + protected void clearCachedSuspendEvents(JDIDebugTarget target) { + removeCachedThreads(fSuspendEvents, target); + } + + private void removeCachedThreads(Map map, JDIDebugTarget target) { + Set threads = map.keySet(); + List threadsToRemove = new ArrayList<>(); + Iterator iter = threads.iterator(); + JDIThread thread; + while (iter.hasNext()) { + thread = (JDIThread) iter.next(); + if (thread.getDebugTarget() == target) { + threadsToRemove.add(thread); + } + } + iter = threadsToRemove.iterator(); + while (iter.hasNext()) { + map.remove(iter.next()); + } + } + + /** + * Removes all compiled expressions which are currently being cached for + * threads in the given target. + */ + protected void clearCachedExpressionFor(JDIDebugTarget target) { + removeCachedThreads(fCompiledExpressions, target); + + // clean up cached projects for stack frames + synchronized (fProjectsByFrame) { + Set frames = fProjectsByFrame.keySet(); + List framesToRemove = new ArrayList<>(); + Iterator iter = frames.iterator(); + JDIStackFrame frame; + while (iter.hasNext()) { + frame = (JDIStackFrame) iter.next(); + if (frame.getDebugTarget() == target) { + framesToRemove.add(frame); + } + } + iter = framesToRemove.iterator(); + while (iter.hasNext()) { + fProjectsByFrame.remove(iter.next()); + } + } + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ILineBreakpoint#getLineNumber() + */ + @Override + public int getLineNumber() throws CoreException { + return ensureMarker().getAttribute(IMarker.LINE_NUMBER, -1); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ILineBreakpoint#getCharStart() + */ + @Override + public int getCharStart() throws CoreException { + return ensureMarker().getAttribute(IMarker.CHAR_START, -1); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.ILineBreakpoint#getCharEnd() + */ + @Override + public int getCharEnd() throws CoreException { + return ensureMarker().getAttribute(IMarker.CHAR_END, -1); + } + + /** + * Returns the type of marker associated with Java line breakpoints + */ + public static String getMarkerType() { + return JAVA_LINE_BREAKPOINT; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#newRequest + * (org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, + * com.sun.jdi.ReferenceType) + */ + @Override + protected EventRequest[] newRequests(JDIDebugTarget target, + ReferenceType type) throws CoreException { + int lineNumber = getLineNumber(); + List locations = determineLocations(lineNumber, type, target); + if (locations == null || locations.isEmpty()) { + // could be an inner type not yet loaded, or line information not + // available + return null; + } + locations = filterLocations(locations); + if (locations.isEmpty()) { + return null; + } + EventRequest[] requests = new EventRequest[locations.size()]; + int i = 0; + for(Location location : locations) { + requests[i] = createLineBreakpointRequest(location, target); + i++; + } + return requests; + } + + /** + * Filter out locations which shouldn't be used for breakpoint creation (like lambda methods) + * + * @return non null list with filtered locations + */ + protected List filterLocations(List locations) { + if (locations.size() <= 1) { + return locations; + } + + // JVM has multiple breakpoint locations for this line. + // Bug 543385: in case we have no condition, we can allow to stop at every location. + // Bug 541110: In case we have condition, it will most likely fail due the wrong context + // if evaluated in a lambda where the condition arguments couldn't be resolved. + if (!hasCondition()) { + return locations; + } + List result = new ArrayList<>(); + for (Location location : locations) { + Method method = location.method(); + if (!method.isSynthetic()) { + result.add(location); + } + } + // this is just a best guess: all locations are synthetic, so we peek the first one + if (result.isEmpty()) { + result.add(locations.get(0)); + } + return result; + } + + /** + * Creates, installs, and returns a line breakpoint request at the given location for this breakpoint. + */ + protected BreakpointRequest createLineBreakpointRequest(Location location, + JDIDebugTarget target) throws CoreException { + BreakpointRequest request = null; + EventRequestManager manager = target.getEventRequestManager(); + if (manager != null) { + try { + request = manager.createBreakpointRequest(location); + configureRequest(request, target); + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return null; + } + JDIDebugPlugin.log(e); + } catch (RuntimeException e) { + target.internalError(e); + return null; + } + return request; + } + target.requestFailed( + JDIDebugBreakpointMessages.JavaLineBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1, + new VMDisconnectedException()); + return null; + } + + /** + * @see JavaBreakpoint#setRequestThreadFilter(EventRequest) + */ + @Override + protected void setRequestThreadFilter(EventRequest request, + ThreadReference thread) { + ((BreakpointRequest) request).addThreadFilter(thread); + } + + /** + * Returns a list of locations of the given line number in the given type. + * Returns null if locations cannot be determined. + */ + protected List determineLocations(int lineNumber, ReferenceType type, + JDIDebugTarget target) { + List locations = null; + try { + locations = type.locationsOfLine(JavaDebugUtils.JAVA_STRATUM, null, lineNumber); + } catch (AbsentInformationException aie) { + if (((type.modifiers() & (AccessibleImpl.MODIFIER_ACC_SYNTHETIC | AccessibleImpl.MODIFIER_SYNTHETIC)) != 0)||(type instanceof InterfaceType)) { + return null; + } + + IStatus status = new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + NO_LINE_NUMBERS, + JDIDebugBreakpointMessages.JavaLineBreakpoint_Absent_Line_Number_Information_1, + null); + IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler( + status); + if (handler != null) { + try { + handler.handleStatus(status, type); + } catch (CoreException e) { + } + } + return null; + } catch (NativeMethodException e) { + return null; + } catch (VMDisconnectedException e) { + return null; + } catch (ClassNotPreparedException e) { + // could be a nested type that is not yet loaded + return null; + } catch (RuntimeException e) { + // not able to retrieve line information + target.internalError(e); + return null; + } + return locations; + } + + /** + * Adds the standard attributes of a line breakpoint to the given attribute + * map. The standard attributes are: + *
        + *
      1. IBreakpoint.ID
      2. + *
      3. IBreakpoint.ENABLED
      4. + *
      5. IMarker.LINE_NUMBER
      6. + *
      7. IMarker.CHAR_START
      8. + *
      9. IMarker.CHAR_END
      10. + *
      + * + */ + public void addLineBreakpointAttributes(Map attributes, + String modelIdentifier, boolean enabled, int lineNumber, + int charStart, int charEnd) { + attributes.put(IBreakpoint.ID, modelIdentifier); + attributes.put(IBreakpoint.ENABLED, Boolean.valueOf(enabled)); + attributes.put(IMarker.LINE_NUMBER, Integer.valueOf(lineNumber)); + attributes.put(IMarker.CHAR_START, Integer.valueOf(charStart)); + attributes.put(IMarker.CHAR_END, Integer.valueOf(charEnd)); + } + + /** + * Adds type name and hit count attributes to the given map. + * + * If hitCount > 0, adds the HIT_COUNT attribute + * to the given breakpoint, and resets the EXPIRED attribute to + * false (since, if the hit count is changed, the breakpoint should no + * longer be expired). + */ + public void addTypeNameAndHitCount(Map attributes, String typeName, + int hitCount) { + attributes.put(TYPE_NAME, typeName); + if (hitCount > 0) { + attributes.put(HIT_COUNT, Integer.valueOf(hitCount)); + attributes.put(EXPIRED, Boolean.FALSE); + } + } + + /** + * Returns whether this breakpoint has an enabled condition + */ + public boolean hasCondition() { + try { + String condition = getCondition(); + return isConditionEnabled() && condition != null + && (condition.length() > 0); + } catch (CoreException exception) { + JDIDebugPlugin.log(exception); + return false; + } + } + + /** + * Suspends the given thread for the given breakpoint event. Returns whether + * the thread suspends. + */ + protected boolean suspendForEvent(Event event, JDIThread thread, + boolean suspendVote) { + expireHitCount(event); + disableTriggerPoint(event); + return suspend(thread, suspendVote); + } + + protected IJavaProject getJavaProject(IJavaStackFrame stackFrame) { + synchronized (fProjectsByFrame) { + IJavaProject project = fProjectsByFrame.get(stackFrame); + if (project == null) { + project = JavaDebugUtils.resolveJavaProject(stackFrame); + if (project != null) { + fProjectsByFrame.put(stackFrame, project); + } + } + return project; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#supportsCondition() + */ + @Override + public boolean supportsCondition() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#getCondition() + */ + @Override + public String getCondition() throws CoreException { + return ensureMarker().getAttribute(CONDITION, null); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setCondition(java.lang + * .String) + */ + @Override + public void setCondition(String condition) throws CoreException { + // Clear the cached compiled expressions + fCompiledExpressions.clear(); + fConditionValues.clear(); + fSuspendEvents.clear(); + if (condition != null && condition.trim().length() == 0) { + condition = null; + } + setAttributes(new String[] { CONDITION }, new Object[] { condition }); + recreate(); + } + + protected String getMarkerMessage(boolean conditionEnabled, + String condition, int hitCount, int suspendPolicy, int lineNumber) { + StringBuilder message = new StringBuilder(super.getMarkerMessage( + hitCount, suspendPolicy)); + if (lineNumber != -1) { + message.append(MessageFormat + .format(JDIDebugBreakpointMessages.JavaLineBreakpoint___line___0___1, + new Object[] { Integer.toString(lineNumber) })); + } + if (conditionEnabled && condition != null) { + message.append(MessageFormat + .format(JDIDebugBreakpointMessages.JavaLineBreakpoint___Condition___0___2, + new Object[] { condition })); + } + + return message.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#isConditionEnabled() + */ + @Override + public boolean isConditionEnabled() throws CoreException { + return ensureMarker().getAttribute(CONDITION_ENABLED, false); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setConditionEnabled(boolean + * ) + */ + @Override + public void setConditionEnabled(boolean conditionEnabled) + throws CoreException { + setAttributes(new String[] { CONDITION_ENABLED }, + new Object[] { Boolean.valueOf(conditionEnabled) }); + recreate(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * cleanupForThreadTermination + * (org.eclipse.jdt.internal.debug.core.model.JDIThread) + */ + @Override + protected void cleanupForThreadTermination(JDIThread thread) { + fSuspendEvents.remove(thread); + fCompiledExpressions.remove(thread); + super.cleanupForThreadTermination(thread); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * addInstanceFilter(com.sun.jdi.request.EventRequest, + * com.sun.jdi.ObjectReference) + */ + @Override + protected void addInstanceFilter(EventRequest request, + ObjectReference object) { + if (request instanceof BreakpointRequest) { + ((BreakpointRequest) request).addInstanceFilter(object); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaLineBreakpoint#isConditionSuspendOnTrue() + */ + @Override + public boolean isConditionSuspendOnTrue() throws DebugException { + return ensureMarker().getAttribute(CONDITION_SUSPEND_ON_TRUE, true); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaLineBreakpoint#setConditionSuspendOnTrue + * (boolean) + */ + @Override + public void setConditionSuspendOnTrue(boolean suspendOnTrue) + throws CoreException { + if (isConditionSuspendOnTrue() != suspendOnTrue) { + setAttributes(new String[] { CONDITION_SUSPEND_ON_TRUE }, + new Object[] { Boolean.valueOf(suspendOnTrue) }); + fConditionValues.clear(); + recreate(); + } + } + + /** + * Returns existing compiled expression for the given thread or + * null. + * + * @param thread + * thread the breakpoint was hit in + * @return compiled expression or null + */ + protected ICompiledExpression getExpression(IJavaThread thread) { + return fCompiledExpressions.get(thread); + } + + /** + * Sets the compiled expression for a thread. + * + * @param thread + * thread the breakpoint was hit in + * @param expression + * associated compiled expression + */ + protected void setExpression(IJavaThread thread, + ICompiledExpression expression) { + fCompiledExpressions.put(thread, expression); + } + + /** + * Sets the current result value of the conditional expression evaluation + * for this breakpoint in the given target, and returns the previous value + * or null if none + * + * @param target + * debug target + * @param value + * current expression value + * @return previous value or null + */ + protected IValue setCurrentConditionValue(IDebugTarget target, IValue value) { + IValue prev = fConditionValues.get(target); + fConditionValues.put(target, value); + return prev; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java new file mode 100644 index 0000000000..28e7b8ed6b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java @@ -0,0 +1,786 @@ +/******************************************************************************* + * Copyright (c) 2000, 2020 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.eclipse.jdt.internal.debug.core.model.LambdaUtils; +import org.eclipse.jdt.internal.debug.core.model.MethodResult; +import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType; + +import com.sun.jdi.ClassType; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.LocatableEvent; +import com.sun.jdi.event.MethodEntryEvent; +import com.sun.jdi.event.MethodExitEvent; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; +import com.sun.jdi.request.MethodEntryRequest; +import com.sun.jdi.request.MethodExitRequest; + +public class JavaMethodBreakpoint extends JavaLineBreakpoint implements + IJavaMethodBreakpoint { + + public static final String JAVA_METHOD_BREAKPOINT = "org.eclipse.jdt.debug.javaMethodBreakpointMarker"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the name of the method in which a breakpoint + * is contained. (value "org.eclipse.jdt.debug.core.methodName" + * ). This attribute is a String. + */ + protected static final String METHOD_NAME = "org.eclipse.jdt.debug.core.methodName"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the signature of the method in which a + * breakpoint is contained. (value + * "org.eclipse.jdt.debug.core.methodSignature"). This + * attribute is a String. + */ + protected static final String METHOD_SIGNATURE = "org.eclipse.jdt.debug.core.methodSignature"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing whether this breakpoint is an entry + * breakpoint. (value "org.eclipse.jdt.debug.core.entry"). This + * attribute is a boolean. + */ + protected static final String ENTRY = "org.eclipse.jdt.debug.core.entry"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing whether this breakpoint is an exit + * breakpoint. (value "org.eclipse.jdt.debug.core.exit"). This + * attribute is a boolean. + */ + protected static final String EXIT = "org.eclipse.jdt.debug.core.exit"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing whether this breakpoint only applies to + * native methods. (value "org.eclipse.jdt.debug.core.native"). + * This attribute is a boolean. + */ + protected static final String NATIVE = "org.eclipse.jdt.debug.core.native"; //$NON-NLS-1$ + + /** + * Cache of method name attribute + */ + private String fMethodName = null; + + /** + * Cache of method signature attribute + */ + private String fMethodSignature = null; + + /** + * Flag indicating that this breakpoint last suspended execution due to a + * method entry + */ + protected static final Integer ENTRY_EVENT = Integer.valueOf(0); + + /** + * Flag indicating that this breakpoint last suspended execution due to a + * method exit + */ + protected static final Integer EXIT_EVENT = Integer.valueOf(1); + + /** + * Maps each debug target that is suspended for this breakpoint to reason + * that this breakpoint suspended it. Reasons include: + *
        + *
      1. Method entry (value ENTRY_EVENT)
      2. + *
      3. Method exit (value EXIT_EVENT)
      4. + *
      + */ + private final Map fLastEventTypes = new HashMap<>(10); + + /** + * Used to match type names + */ + private Pattern fPattern; + + /** + * Cache of whether this breakpoint uses a type name pattern + */ + private Boolean fUsesTypePattern = null; + + /** + * Constructs a new method breakpoint + */ + public JavaMethodBreakpoint() { + } + + public JavaMethodBreakpoint(final IResource resource, + final String typePattern, final String methodName, + final String methodSignature, final boolean entry, + final boolean exit, final boolean nativeOnly, final int lineNumber, + final int charStart, final int charEnd, final int hitCount, + final boolean register, final Map attributes) throws CoreException { + IWorkspaceRunnable wr = monitor -> { + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addMethodNameAndSignature(attributes, methodName, + methodSignature); + addTypeNameAndHitCount(attributes, typePattern, hitCount); + attributes.put(ENTRY, Boolean.valueOf(entry)); + attributes.put(EXIT, Boolean.valueOf(exit)); + attributes.put(NATIVE, Boolean.valueOf(nativeOnly)); + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // create the marker + setMarker(resource.createMarker(JAVA_METHOD_BREAKPOINT, attributes)); + register(register); + }; + run(getMarkerRule(resource), wr); + if (typePattern != null) { + String type = convertToRegularExpression(typePattern); + fPattern = Pattern.compile(type); + } + } + + /** + * Creates and installs an entry and exit requests in the given type name, + * configuring the requests as appropriate for this breakpoint. The requests + * are then enabled based on whether this breakpoint is an entry breakpoint, + * exit breakpoint, or both. Finally, the requests are registered with the + * given target. + */ + protected void createRequest(JDIDebugTarget target, String typePattern) + throws CoreException { + MethodEntryRequest entryRequest = createMethodEntryRequest(target, + typePattern); + MethodExitRequest exitRequest = createMethodExitRequest(target, + typePattern); + + registerRequest(entryRequest, target); + registerRequest(exitRequest, target); + } + + /** + * Returns a new method entry request for this breakpoint's criteria + * + * @param the + * target in which to create the request + * @param type + * the type on which to create the request + * @return method entry request + * @exception CoreException + * if an exception occurs accessing this breakpoint's + * underlying marker + */ + protected MethodEntryRequest createMethodEntryRequest( + JDIDebugTarget target, String typePattern) throws CoreException { + return (MethodEntryRequest) createMethodRequest(target, typePattern, + true); + } + + /** + * Returns a new method exit request for this breakpoint's criteria + * + * @param target + * the target in which to create the request + * @param type + * the type on which to create the request + * @return method exit request + * @exception CoreException + * if an exception occurs accessing this breakpoint's + * underlying marker + */ + protected MethodExitRequest createMethodExitRequest(JDIDebugTarget target, + String typePattern) throws CoreException { + return (MethodExitRequest) createMethodRequest(target, typePattern, + false); + } + + /** + * Returns a new method entry request for this breakpoint's criteria + * + * @param the + * target in which to create the request + * @param type + * the type on which to create the request + * @return method entry request + * @exception CoreException + * if an exception occurs accessing this breakpoint's + * underlying marker + */ + protected EventRequest createMethodEntryRequest(JDIDebugTarget target, + ReferenceType type) throws CoreException { + return createMethodRequest(target, type, true); + } + + /** + * Returns a new method exit request for the given reference type + * + * @param target + * the target in which to create the request + * @param type + * the type on which to create the request + * @return method exit request + * @exception CoreException + * if an exception occurs accessing this breakpoint's + * underlying marker + */ + protected EventRequest createMethodExitRequest(JDIDebugTarget target, + ReferenceType type) throws CoreException { + return createMethodRequest(target, type, false); + } + + /** + * @see JavaMethodBreakpoint#createMethodEntryRequest(JDIDebugTarget, + * ReferenceType) or + * JavaMethodBreakpoint#createMethodExitRequest(JDIDebugTarget, + * ReferenceType) + * + * Returns a MethodEntryRequest or + * BreakpointRequest if entry is true, a + * MethodExitRequest if entry is false. + * + * @param target + * the debug target in which to create the request + * @param classFilter + * a filter which specifies the scope of the method request. This + * parameter must be either a String or a + * ReferenceType + * @param entry + * whether or not the request will be a method entry request. If + * false, the request will be a method exit request. + */ + private EventRequest createMethodRequest(JDIDebugTarget target, + Object classFilter, boolean entry) throws CoreException { + EventRequest request = null; + EventRequestManager manager = target.getEventRequestManager(); + if (manager != null) { + try { + if (entry) { + if (classFilter instanceof ClassType && getMethodName() != null + && getMethodSignature() != null) { + // use a line breakpoint if possible for better performance + ClassType clazz = (ClassType) classFilter; + if (clazz.name().equals(getTypeName())) { + // only use line breakpoint when there is an exact match + Method method = clazz.concreteMethodByName( + getMethodName(), getMethodSignature()); + if (method != null && !method.isNative()) { + Location location = method.location(); + if (location != null && location.codeIndex() != -1) { + request = manager + .createBreakpointRequest(location); + } + } + } + } + if (request == null) { + request = manager.createMethodEntryRequest(); + if (classFilter instanceof String) { + ((MethodEntryRequest) request) + .addClassFilter((String) classFilter); + } else if (classFilter instanceof ReferenceType) { + ((MethodEntryRequest) request) + .addClassFilter((ReferenceType) classFilter); + } + } + } else { + request = manager.createMethodExitRequest(); + if (classFilter instanceof String) { + ((MethodExitRequest) request) + .addClassFilter((String) classFilter); + } else if (classFilter instanceof ReferenceType) { + ((MethodExitRequest) request) + .addClassFilter((ReferenceType) classFilter); + } + } + configureRequest(request, target); + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return null; + } + JDIDebugPlugin.log(e); + } catch (RuntimeException e) { + target.internalError(e); + } + return request; + } + target.requestFailed( + JDIDebugBreakpointMessages.JavaMethodBreakpoint_Unable_to_create_breakpoint_request___VM_disconnected__1, + new VMDisconnectedException()); + return null; + } + + /** + * @see JavaBreakpoint#setRequestThreadFilter(EventRequest) + */ + @Override + protected void setRequestThreadFilter(EventRequest request, + ThreadReference thread) { + if (request instanceof MethodEntryRequest) { + ((MethodEntryRequest) request).addThreadFilter(thread); + } else if (request instanceof MethodExitRequest) { + ((MethodExitRequest) request).addThreadFilter(thread); + } else if (request instanceof BreakpointRequest) { + ((BreakpointRequest) request).addThreadFilter(thread); + } + } + + /** + * Configure the given request's hit count. Since method entry/exit requests + * do not support hit counts, we simulate a hit count by manually updating a + * counter stored on the request. + */ + @Override + protected void configureRequestHitCount(EventRequest request) + throws CoreException { + if (request instanceof BreakpointRequest) { + super.configureRequestHitCount(request); + } else { + int hitCount = getHitCount(); + if (hitCount > 0) { + request.putProperty(HIT_COUNT, Integer.valueOf(hitCount)); + } + } + } + + /** + * @see JavaBreakpoint#updateEnabledState(EventRequest, JDIDebugTarget) + */ + @Override + protected void updateEnabledState(EventRequest request, + JDIDebugTarget target) throws CoreException { + boolean enabled = isEnabled(); + if (request instanceof MethodEntryRequest + || request instanceof BreakpointRequest) { + enabled = enabled && isEntry(); + } else if (request instanceof MethodExitRequest) { + enabled = enabled && isExit(); + } + + if (enabled != request.isEnabled()) { + internalUpdateEnabledState(request, enabled, target); + } + } + + /** + * Adds the method name and signature attributes to the given attribute map, + * and initializes the local cache of method name and signature. + */ + private void addMethodNameAndSignature(Map attributes, String methodName, + String methodSignature) { + if (methodName != null) { + attributes.put(METHOD_NAME, methodName); + } + if (methodSignature != null) { + attributes.put(METHOD_SIGNATURE, methodSignature); + } + fMethodName = methodName; + fMethodSignature = methodSignature; + } + + /** + * @see IJavaMethodBreakpoint#isEntrySuspend(IDebugTarget) + */ + @Override + public boolean isEntrySuspend(IDebugTarget target) { + Integer lastEventType = fLastEventTypes.get(target); + if (lastEventType == null) { + return false; + } + return lastEventType.equals(ENTRY_EVENT); + } + + /** + * @see JavaBreakpoint#handleBreakpointEvent(Event, JDIDebugTarget, + * JDIThread) + */ + @Override + public boolean handleBreakpointEvent(Event event, JDIThread thread, + boolean suspendVote) { + if (event instanceof MethodEntryEvent) { + MethodEntryEvent entryEvent = (MethodEntryEvent) event; + fLastEventTypes.put(thread.getDebugTarget(), ENTRY_EVENT); + //inActivateTriggerPoint(event); + return handleMethodEvent(entryEvent, entryEvent.method(), thread, + suspendVote); + } else if (event instanceof MethodExitEvent) { + MethodExitEvent exitEvent = (MethodExitEvent) event; + fLastEventTypes.put(thread.getDebugTarget(), EXIT_EVENT); + //inActivateTriggerPoint(event); + boolean result = handleMethodEvent(exitEvent, exitEvent.method(), thread, + suspendVote); + if (!result) { + // about to suspend, store result + thread.setMethodResult(new MethodResult(exitEvent.method(), -1, exitEvent.returnValue(), ResultType.returning)); + } + return result; + } else if (event instanceof BreakpointEvent) { + fLastEventTypes.put(thread.getDebugTarget(), ENTRY_EVENT); + return super.handleBreakpointEvent(event, thread, suspendVote); + } + return true; + } + + /** + * Method entry/exit events are fired each time any method is invoked in a + * class in which a method entry/exit breakpoint has been installed. When a + * method entry/exit event is received by this breakpoint, ensure that the + * event has been fired by a method invocation that this breakpoint is + * interested in. If it is not, do nothing. + */ + protected boolean handleMethodEvent(LocatableEvent event, Method method, + JDIThread thread, boolean suspendVote) { + try { + if (isNativeOnly()) { + if (!method.isNative()) { + return true; + } + } + + if (getMethodName() != null && !LambdaUtils.isLambdaMethod(method)) { + if (!method.name().equals(getMethodName())) { + return true; + } + } + + if (getMethodSignature() != null) { + String sig = method.signature(); + if (sig.indexOf('$') > -1) { + sig = sig.replace('$', '.'); + } + if (!sig.equals(getMethodSignature())) { + return true; + } + } + + if (fPattern != null) { + if (!fPattern.matcher(method.declaringType().name()).find()) { + return true; + } + } + + // simulate hit count + Integer count = (Integer) event.request().getProperty(HIT_COUNT); + if (count != null && handleHitCount(event, count)) { + return true; + } + // no hit count + return !suspendForEvent(event, thread, suspendVote); // Resume if + // suspend + // fails + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + return true; + } + + /** + * Method breakpoints simulate hit count. When a method event is received, + * decrement the hit count property on the request and suspend if the hit + * count reaches 0. + */ + private boolean handleHitCount(LocatableEvent event, Integer count) { + // decrement count and suspend if 0 + int hitCount = count.intValue(); + if (hitCount > 0) { + hitCount--; + count = Integer.valueOf(hitCount); + event.request().putProperty(HIT_COUNT, count); + if (hitCount == 0) { + // the count has reached 0, breakpoint hit + expireHitCount(event); + disableTriggerPoint(event); + return false; + } + // count still > 0, keep running + return true; + } + // hit count expired, keep running + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaMethodEntryBreakpoint#getMethodName() + */ + @Override + public String getMethodName() { + return fMethodName; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaMethodEntryBreakpoint#getMethodSignature + * () + */ + @Override + public String getMethodSignature() { + return fMethodSignature; + } + + /** + * @see IJavaMethodBreakpoint#isEntry() + */ + @Override + public boolean isEntry() throws CoreException { + return ensureMarker().getAttribute(ENTRY, false); + } + + /** + * @see IJavaMethodBreakpoint#isExit() + */ + @Override + public boolean isExit() throws CoreException { + return ensureMarker().getAttribute(EXIT, false); + } + + /** + * @see IJavaMethodBreakpoint#isNative() + */ + @Override + public boolean isNativeOnly() throws CoreException { + return ensureMarker().getAttribute(NATIVE, false); + } + + /** + * @see IJavaMethodBreakpoint#setEntry(boolean) + */ + @Override + public void setEntry(boolean entry) throws CoreException { + if (isEntry() != entry) { + setAttribute(ENTRY, entry); + if (entry && !isEnabled()) { + setEnabled(true); + } else if (!(entry || isExit())) { + setEnabled(false); + } + recreate(); + } + } + + /** + * @see IJavaMethodBreakpoint#setExit(boolean) + */ + @Override + public void setExit(boolean exit) throws CoreException { + if (isExit() != exit) { + setAttribute(EXIT, exit); + if (exit && !isEnabled()) { + setEnabled(true); + } else if (!(exit || isEntry())) { + setEnabled(false); + } + recreate(); + } + } + + /** + * @see IJavaMethodBreakpoint#setNativeOnly(boolean) + */ + @Override + public void setNativeOnly(boolean nativeOnly) throws CoreException { + if (isNativeOnly() != nativeOnly) { + setAttribute(NATIVE, nativeOnly); + recreate(); + } + } + + /** + * Initialize cache of attributes + * + * @see org.eclipse.debug.core.model.IBreakpoint#setMarker(IMarker) + */ + @Override + public void setMarker(IMarker marker) throws CoreException { + super.setMarker(marker); + fMethodName = marker.getAttribute(METHOD_NAME, null); + fMethodSignature = marker.getAttribute(METHOD_SIGNATURE, null); + String typePattern = marker.getAttribute(TYPE_NAME, ""); //$NON-NLS-1$ + if (typePattern != null) { + try { + fPattern = Pattern + .compile(convertToRegularExpression(typePattern)); + } catch (PatternSyntaxException e) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + JDIDebugBreakpointMessages.JavaMethodBreakpoint_0, e)); + } + } + } + + /** + * converts the specified string to one which has been formated to our needs + * + * @param stringMatcherPattern + * the initial pattern + * @return the modified pattern + */ + private String convertToRegularExpression(String stringMatcherPattern) { + String regex = stringMatcherPattern.replaceAll("\\.", "\\\\."); //$NON-NLS-1$//$NON-NLS-2$ + regex = regex.replaceAll("\\*", "\\.\\*"); //$NON-NLS-1$//$NON-NLS-2$ + regex = regex.replaceAll("\\$", "\\\\\\$"); //$NON-NLS-1$ //$NON-NLS-2$ + return regex; + } + + /** + * If this breakpoint is not entry or exit enabled, set the default (entry) + * + * @see org.eclipse.debug.core.model.IBreakpoint#setEnabled(boolean) + */ + @Override + public void setEnabled(boolean enabled) throws CoreException { + if (enabled) { + if (!(isEntry() || isExit())) { + setDefaultEntryAndExit(); + } + } + super.setEnabled(enabled); + } + + /** + * Sets the default entry and exit attributes of the method breakpoint The + * default values are: + *
        + *
      • entry = true + *
      • exit = false + *
          + */ + protected void setDefaultEntryAndExit() throws CoreException { + Object[] values = new Object[] { Boolean.TRUE, Boolean.FALSE }; + String[] attributes = new String[] { ENTRY, EXIT }; + setAttributes(attributes, values); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaLineBreakpoint#supportsCondition() + */ + @Override + public boolean supportsCondition() { + return true; + } + + /** + * @see JavaBreakpoint#addToTarget(JDIDebugTarget) + */ + @Override + public void addToTarget(JDIDebugTarget target) throws CoreException { + if (usesTypePattern()) { + // pre-notification + fireAdding(target); + + String referenceTypeNamePattern = getTypeName(); + if (referenceTypeNamePattern == null) { + return; + } + + createRequest(target, referenceTypeNamePattern); + } else { + super.addToTarget(target); + } + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#removeFromTarget(JDIDebugTarget) + */ + @Override + public void removeFromTarget(JDIDebugTarget target) throws CoreException { + fLastEventTypes.remove(target); + super.removeFromTarget(target); + } + + /** + * Returns whether this breakpoint uses type name pattern matching. + * + * @return whether this breakpoint uses type name pattern matching + */ + protected boolean usesTypePattern() throws CoreException { + if (fUsesTypePattern == null) { + String name = getTypeName(); + fUsesTypePattern = Boolean.valueOf(name != null + && (name.startsWith("*") || name.endsWith("*"))); //$NON-NLS-1$ //$NON-NLS-2$ + } + return fUsesTypePattern.booleanValue(); + } + + /** + * Used when this breakpoint is for a specific type (i.e. not using type + * name pattern matching). + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#createRequest(JDIDebugTarget, + * ReferenceType) + */ + @Override + protected boolean createRequest(JDIDebugTarget target, ReferenceType type) + throws CoreException { + if (!type.name().equals(getTypeName()) || shouldSkipBreakpoint()) { + // do not create requests for inner/outer types if this is for a + // specific type + return false; + } + EventRequest entryRequest = createMethodEntryRequest(target, type); + EventRequest exitRequest = createMethodExitRequest(target, type); + + registerRequest(entryRequest, target); + registerRequest(exitRequest, target); + return true; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#setTypeName(String) + */ + @Override + protected void setTypeName(String typeName) throws CoreException { + fUsesTypePattern = null; + super.setTypeName(typeName); + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addInstanceFilter(EventRequest, + * ObjectReference) + */ + @Override + protected void addInstanceFilter(EventRequest request, + ObjectReference object) { + if (request instanceof MethodEntryRequest) { + ((MethodEntryRequest) request).addInstanceFilter(object); + } else if (request instanceof MethodExitRequest) { + ((MethodExitRequest) request).addInstanceFilter(object); + } else { + super.addInstanceFilter(request, object); + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodEntryBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodEntryBreakpoint.java new file mode 100644 index 0000000000..d4fdea0c6e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodEntryBreakpoint.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.Map; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.debug.core.IJavaMethodEntryBreakpoint; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.ClassType; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.request.BreakpointRequest; +import com.sun.jdi.request.EventRequest; + +/** + * A line breakpoint at the first executable location in a specific method. + */ + +public class JavaMethodEntryBreakpoint extends JavaLineBreakpoint implements + IJavaMethodEntryBreakpoint { + + protected static final String JAVA_METHOD_ENTRY_BREAKPOINT = "org.eclipse.jdt.debug.javaMethodEntryBreakpointMarker"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the name of the method in which a breakpoint + * is contained. (value "org.eclipse.jdt.debug.core.methodName" + * ). This attribute is a String. + */ + private static final String METHOD_NAME = "org.eclipse.jdt.debug.core.methodName"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the signature of the method in which a + * breakpoint is contained. (value + * "org.eclipse.jdt.debug.core.methodSignature"). This + * attribute is a String. + */ + private static final String METHOD_SIGNATURE = "org.eclipse.jdt.debug.core.methodSignature"; //$NON-NLS-1$ + + /** + * Cache of method name attribute + */ + private String fMethodName = null; + + /** + * Cache of method signature attribute + */ + private String fMethodSignature = null; + + /** + * Constructs a new method breakpoint + */ + public JavaMethodEntryBreakpoint() { + } + + public JavaMethodEntryBreakpoint(final IResource resource, + final String typeName, final String methodName, + final String methodSignature, final int lineNumber, + final int charStart, final int charEnd, final int hitCount, + final boolean register, final Map attributes) throws CoreException { + IWorkspaceRunnable wr = monitor -> { + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addMethodNameAndSignature(attributes, methodName, + methodSignature); + addTypeNameAndHitCount(attributes, typeName, hitCount); + // set attributes + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // create the marker + setMarker(resource.createMarker(JAVA_METHOD_ENTRY_BREAKPOINT, attributes)); + + register(register); + }; + run(getMarkerRule(resource), wr); + } + + /** + * Adds the method name and signature attributes to the given attribute map, + * and initializes the local cache of method name and signature. + */ + private void addMethodNameAndSignature(Map attributes, String methodName, + String methodSignature) { + if (methodName != null) { + attributes.put(METHOD_NAME, methodName); + } + if (methodSignature != null) { + attributes.put(METHOD_SIGNATURE, methodSignature); + } + fMethodName = methodName; + fMethodSignature = methodSignature; + } + + /** + * @see IJavaMethodEntryBreakpoint#getMethodName() + */ + @Override + public String getMethodName() { + return fMethodName; + } + + /** + * @see IJavaMethodEntryBreakpoint#getMethodSignature() + */ + @Override + public String getMethodSignature() { + return fMethodSignature; + } + + /** + * Initialize cache of attributes + * + * @see IBreakpoint#setMarker(IMarker) + */ + @Override + public void setMarker(IMarker marker) throws CoreException { + super.setMarker(marker); + fMethodName = marker.getAttribute(METHOD_NAME, null); + fMethodSignature = marker.getAttribute(METHOD_SIGNATURE, null); + } + + /** + * @see IJavaLineBreakpoint#supportsCondition() + */ + @Override + public boolean supportsCondition() { + return false; + } + + /** + * @see JavaBreakpoint#newRequests(JDIDebugTarget, ReferenceType) + */ + @Override + protected EventRequest[] newRequests(JDIDebugTarget target, + ReferenceType type) throws CoreException { + try { + if (type instanceof ClassType) { + ClassType clazz = (ClassType) type; + Method method = clazz.concreteMethodByName(getMethodName(), + getMethodSignature()); + if (method == null) { + return null; + } + Location location = method.location(); + if (location == null || location.codeIndex() == -1) { + return null; + } + BreakpointRequest req = type.virtualMachine() + .eventRequestManager() + .createBreakpointRequest(location); + configureRequest(req, target); + return new EventRequest[] { req }; + } + return null; + } catch (RuntimeException e) { + target.internalError(e); + return null; + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java new file mode 100644 index 0000000000..2c1096e2d4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaPatternBreakpoint; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; + +@SuppressWarnings("deprecation") +public class JavaPatternBreakpoint extends JavaLineBreakpoint implements + IJavaPatternBreakpoint { + + private static final String PATTERN_BREAKPOINT = "org.eclipse.jdt.debug.javaPatternBreakpointMarker"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the pattern identifier of the source file in + * which a breakpoint is created (value + * "org.eclipse.jdt.debug.core.pattern"). This attribute is a + * String. + */ + protected static final String PATTERN = "org.eclipse.jdt.debug.core.pattern"; //$NON-NLS-1$ + + public JavaPatternBreakpoint() { + } + + /** + * @see JDIDebugModel#createPatternBreakpoint(IResource, String, int, int, + * int, int, boolean, Map) + */ + public JavaPatternBreakpoint(IResource resource, String sourceName, + String pattern, int lineNumber, int charStart, int charEnd, + int hitCount, boolean add, Map attributes) throws DebugException { + this(resource, sourceName, pattern, lineNumber, charStart, charEnd, + hitCount, add, attributes, PATTERN_BREAKPOINT); + } + + public JavaPatternBreakpoint(final IResource resource, + final String sourceName, final String pattern, + final int lineNumber, final int charStart, final int charEnd, + final int hitCount, final boolean add, final Map attributes, + final String markerType) throws DebugException { + IWorkspaceRunnable wr = monitor -> { + + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addPatternAndHitCount(attributes, sourceName, pattern, hitCount); + // set attributes + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // create the marker + setMarker(resource.createMarker(markerType, attributes)); + + register(add); + }; + run(getMarkerRule(resource), wr); + } + + /** + * @see JavaBreakpoint#getReferenceTypeName() + */ + protected String getReferenceTypeName() { + String name = ""; //$NON-NLS-1$ + try { + name = getPattern(); + } catch (CoreException ce) { + JDIDebugPlugin.log(ce); + } + return name; + } + + /** + * @see JavaBreakpoint#installableReferenceType(ReferenceType) + */ + @Override + protected boolean installableReferenceType(ReferenceType type, + JDIDebugTarget target) throws CoreException { + // if the source name attribute is specified, check for a match with the + // debug attribute (if available) + if (getSourceName() != null) { + String sourceName = null; + try { + sourceName = type.sourceName(); + } catch (AbsentInformationException e) { + // unable to compare + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return false; + } + target.targetRequestFailed( + MessageFormat.format(JDIDebugBreakpointMessages.JavaPatternBreakpoint_exception_source_name, e.toString(), type.name()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return false; + } catch (RuntimeException e) { + target.targetRequestFailed( + MessageFormat.format(JDIDebugBreakpointMessages.JavaPatternBreakpoint_exception_source_name, e.toString(), type.name()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return false; + } + + // if the debug attribute matches the source name, attempt + // installation + if (sourceName != null) { + if (!getSourceName().equalsIgnoreCase(sourceName)) { + return false; + } + } + } + + String pattern = getPattern(); + String queriedType = type.name(); + if (pattern == null || queriedType == null) { + return false; + } + if (queriedType.startsWith(pattern)) { + // query registered listeners to see if this pattern breakpoint + // should + // be installed in the given target + return queryInstallListeners(target, type); + } + return false; + } + + /** + * Adds the class name pattern and hit count attributes to the given map. + */ + protected void addPatternAndHitCount(Map attributes, String sourceName, + String pattern, int hitCount) { + attributes.put(PATTERN, pattern); + if (sourceName != null) { + attributes.put(SOURCE_NAME, sourceName); + } + if (hitCount > 0) { + attributes.put(HIT_COUNT, Integer.valueOf(hitCount)); + attributes.put(EXPIRED, Boolean.FALSE); + } + } + + /** + * @see IJavaPatternBreakpoint#getPattern() + */ + @Override + public String getPattern() throws CoreException { + return (String) ensureMarker().getAttribute(PATTERN); + } + + /** + * @see IJavaPatternBreakpoint#getSourceName() + */ + @Override + public String getSourceName() throws CoreException { + return (String) ensureMarker().getAttribute(SOURCE_NAME); + } + + @Override + protected void createRequests(JDIDebugTarget target) throws CoreException { + if (target.isTerminated() || shouldSkipBreakpoint()) { + return; + } + String referenceTypeName = getReferenceTypeName(); + if (referenceTypeName == null) { + return; + } + + String classPrepareTypeName = referenceTypeName; + // create request to listen to class loads + // name may only be partially resolved + if (!referenceTypeName.endsWith("*")) { //$NON-NLS-1$ + classPrepareTypeName = classPrepareTypeName + '*'; + } + registerRequest(target.createClassPrepareRequest(classPrepareTypeName), + target); + + // create breakpoint requests for each class currently loaded + VirtualMachine vm = target.getVM(); + if (vm == null) { + target.requestFailed( + JDIDebugBreakpointMessages.JavaPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1, + new VMDisconnectedException()); + } + List classes = null; + try { + classes = vm.allClasses(); + } catch (RuntimeException e) { + target.targetRequestFailed( + JDIDebugBreakpointMessages.JavaPatternBreakpoint_0, e); + } + if (classes != null) { + Iterator iter = classes.iterator(); + String typeName = null; + ReferenceType type = null; + while (iter.hasNext()) { + type = iter.next(); + typeName = type.name(); + if (typeName != null && typeName.startsWith(referenceTypeName)) { + createRequest(target, type); + } + } + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java new file mode 100644 index 0000000000..0aacd40316 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java @@ -0,0 +1,467 @@ +/******************************************************************************* + * Copyright (c) 2003, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassNotPreparedException; +import com.sun.jdi.Location; +import com.sun.jdi.NativeMethodException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; + +/** + * A line breakpoint identified by its source file name and/or path, and stratum + * that it is relative to. + * + * @since 3.0 + */ +public class JavaStratumLineBreakpoint extends JavaLineBreakpoint implements + IJavaStratumLineBreakpoint { + private static final String PATTERN = "org.eclipse.jdt.debug.pattern"; //$NON-NLS-1$ + protected static final String STRATUM = "org.eclipse.jdt.debug.stratum"; //$NON-NLS-1$ + protected static final String SOURCE_PATH = "org.eclipse.jdt.debug.source_path"; //$NON-NLS-1$ + private static final String STRATUM_BREAKPOINT = "org.eclipse.jdt.debug.javaStratumLineBreakpointMarker"; //$NON-NLS-1$ + private String[] fTypeNamePatterns; + // corresponds to type name patterns with beginning/trailing '*' removed + private String[] fSuffix; + private String[] fPrefix; + + public JavaStratumLineBreakpoint() { + } + + /** + * Creates and returns a line breakpoint identified by its source file name + * and/or path, and stratum that it is relative to. + * + * @param resource + * the resource on which to create the associated breakpoint + * marker + * @param stratum + * the stratum in which the source name, source path and line + * number are relative, or null. If + * null or if the specified stratum is not defined + * for a type, the source name, source path and line number are + * relative to the type's default stratum. + * @param sourceName + * the simple name of the source file in which the breakpoint is + * set, or null. The breakpoint will install itself + * in classes that have a source file name debug attribute that + * matches this value in the specified stratum, and satisfies the + * class name pattern and source path attribute. When + * null, the source file name debug attribute is not + * considered. + * @param sourcePath + * the qualified source file name in which the breakpoint is set, + * or null. The breakpoint will install itself in + * classes that have a source file path in the specified stratum + * that matches this value, and satisfies the class name pattern + * and source name attribute. When null, the source + * path attribute is not considered. + * @param classNamePattern + * the class name pattern to which the breakpoint should be + * restricted, or null. The breakpoint will install + * itself in each type that matches this class name pattern, with + * a satisfying source name and source path. Patterns may begin + * or end with '*', which matches 0 or more characters. A pattern + * that does not contain a '*' is equivalent to a pattern ending + * in '*'. Specifying null, or an empty string is + * the equivalent to "*". + * @param lineNumber + * the lineNumber on which the breakpoint is set - line numbers + * are 1 based, associated with the source file (stratum) in + * which the breakpoint is set + * @param charStart + * the first character index associated with the breakpoint, or + * -1 if unspecified, in the source file in which the breakpoint + * is set + * @param charEnd + * the last character index associated with the breakpoint, or -1 + * if unspecified, in the source file in which the breakpoint is + * set + * @param hitCount + * the number of times the breakpoint will be hit before + * suspending execution - 0 if it should always suspend + * @param register + * whether to add this breakpoint to the breakpoint manager + * @param attributes + * a map of client defined attributes that should be assigned to + * the underlying breakpoint marker on creation, or + * null if none. + * @return a stratum breakpoint + * @exception CoreException + * If this method fails. Reasons include: + *
            + *
          • Failure creating underlying marker. The exception's + * status contains the underlying exception responsible for + * the failure.
          • + *
          + * @since 3.0 + */ + public JavaStratumLineBreakpoint(IResource resource, String stratum, + String sourceName, String sourcePath, String classNamePattern, + int lineNumber, int charStart, int charEnd, int hitCount, + boolean register, Map attributes) throws DebugException { + this(resource, stratum, sourceName, sourcePath, classNamePattern, + lineNumber, charStart, charEnd, hitCount, register, attributes, + STRATUM_BREAKPOINT); + } + + protected JavaStratumLineBreakpoint(final IResource resource, + final String stratum, final String sourceName, + final String sourcePath, final String classNamePattern, + final int lineNumber, final int charStart, final int charEnd, + final int hitCount, final boolean register, final Map attributes, + final String markerType) throws DebugException { + IWorkspaceRunnable wr = monitor -> { + + // modify pattern + String pattern = classNamePattern; + if (pattern != null && pattern.length() == 0) { + pattern = null; + } + + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addStratumPatternAndHitCount(attributes, stratum, sourceName, + sourcePath, pattern, hitCount); + // set attributes + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // create the marker + setMarker(resource.createMarker(markerType, attributes)); + + register(register); + }; + run(getMarkerRule(resource), wr); + } + + /** + * Adds the class name pattern and hit count attributes to the given map. + */ + protected void addStratumPatternAndHitCount(Map attributes, String stratum, + String sourceName, String sourcePath, String pattern, int hitCount) { + attributes.put(PATTERN, pattern); + attributes.put(STRATUM, stratum); + if (sourceName != null) { + attributes.put(SOURCE_NAME, sourceName); + } + if (sourcePath != null) { + attributes.put(SOURCE_PATH, sourcePath); + } + if (hitCount > 0) { + attributes.put(HIT_COUNT, Integer.valueOf(hitCount)); + attributes.put(EXPIRED, Boolean.FALSE); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * installableReferenceType(com.sun.jdi.ReferenceType, + * org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + protected boolean installableReferenceType(ReferenceType type, + JDIDebugTarget target) throws CoreException { + + // check the type name. + String typeName = type.name(); + if (!validType(typeName)) { + return false; + } + String stratum = getStratum(); + // check the source name. + String bpSourceName = getSourceName(); + if (bpSourceName != null) { + List sourceNames; + try { + sourceNames = type.sourceNames(stratum); + } catch (AbsentInformationException e1) { + return false; + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return false; + } + throw e; + } + if (!containsMatch(sourceNames, bpSourceName)) { + return false; + } + } + + String bpSourcePath = getSourcePath(); + if (bpSourcePath != null) { + // check that source paths match + List sourcePaths; + try { + sourcePaths = type.sourcePaths(stratum); + } catch (AbsentInformationException e1) { + return false; + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return false; + } + throw e; + } + if (!containsMatch(sourcePaths, bpSourcePath)) { + return false; + } + } + return queryInstallListeners(target, type); + } + + private boolean containsMatch(List strings, String key) { + for (String string : strings) { + if (string.equals(key)) { + return true; + } + } + return false; + } + + /** + * @param typeName + * @return + */ + private boolean validType(String typeName) throws CoreException { + + String[] patterns = getTypeNamePatterns(); + for (int i = 0; i < patterns.length; i++) { + if (fSuffix[i] != null) { + // pattern starting with '*' + if (fSuffix[i].length() == 0) { + return true; + } + if (typeName.endsWith(fSuffix[i])) { + return true; + } + } else if (fPrefix[i] != null) { + if (typeName.startsWith(fPrefix[i])) { + return true; + } + } else { + if (typeName.startsWith(patterns[i])) { + return true; + } + } + } + + // return false if we cannot find a type name to match + return false; + } + + /** + * Returns a list of locations for the given line number in the given type. + * Returns null if a location cannot be determined. + */ + @Override + protected List determineLocations(int lineNumber, ReferenceType type, + JDIDebugTarget target) { + List locations; + String sourcePath; + try { + locations = type.locationsOfLine(getStratum(), getSourceName(), + lineNumber); + sourcePath = getSourcePath(); + } catch (AbsentInformationException aie) { + IStatus status = new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + NO_LINE_NUMBERS, + JDIDebugBreakpointMessages.JavaLineBreakpoint_Absent_Line_Number_Information_1, + null); + IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler( + status); + if (handler != null) { + try { + handler.handleStatus(status, type); + } catch (CoreException e) { + } + } + return null; + } catch (NativeMethodException e) { + return null; + } catch (VMDisconnectedException e) { + return null; + } catch (ClassNotPreparedException e) { + // could be a nested type that is not yet loaded + return null; + } catch (RuntimeException e) { + // not able to retrieve line info + target.internalError(e); + return null; + } catch (CoreException e) { + // not able to retrieve line info + JDIDebugPlugin.log(e); + return null; + } + + if (sourcePath == null) { + if (locations.size() > 0) { + return locations; + } + } else { + for(Location location : locations) { + try { + if (!sourcePath.equals(location.sourcePath())) { + locations.remove(location); + } + } catch (AbsentInformationException e1) { + // nothing to do; + } + } + if (locations.size() > 0) { + return locations; + } + } + + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint#getPattern() + */ + @Override + public String getPattern() throws CoreException { + return ensureMarker().getAttribute(PATTERN, "*"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint#getSourceName() + */ + @Override + public String getSourceName() throws CoreException { + return (String) ensureMarker().getAttribute(SOURCE_NAME); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint#getStratum() + */ + @Override + public String getStratum() throws CoreException { + return (String) ensureMarker().getAttribute(STRATUM); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint#getSourcePath() + */ + @Override + public String getSourcePath() throws CoreException { + return (String) ensureMarker().getAttribute(SOURCE_PATH); + } + + @Override + protected void createRequests(JDIDebugTarget target) throws CoreException { + if (target.isTerminated() || shouldSkipBreakpoint()) { + return; + } + + String[] patterns = null; + try { + patterns = getTypeNamePatterns(); + } catch (CoreException e1) { + JDIDebugPlugin.log(e1); + return; + } + + String sourceName = getSourceName(); + for (String classPrepareTypeName : patterns) { + // create request to listen to class loads + // name may only be partially resolved + registerRequest(target.createClassPrepareRequest( + classPrepareTypeName, null, true, sourceName), target); + } + + // create breakpoint requests for each class currently loaded + VirtualMachine vm = target.getVM(); + if (vm == null) { + target.requestFailed( + JDIDebugBreakpointMessages.JavaPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1, + new VMDisconnectedException()); + } + List classes = null; + try { + classes = vm.allClasses(); + } catch (RuntimeException e) { + target.targetRequestFailed( + JDIDebugBreakpointMessages.JavaPatternBreakpoint_0, e); + } + if (classes != null) { + Iterator iter = classes.iterator(); + while (iter.hasNext()) { + ReferenceType type = iter.next(); + if (installableReferenceType(type, target)) { + createRequest(target, type); + } + } + } + } + + public synchronized String[] getTypeNamePatterns() throws CoreException { + if (fTypeNamePatterns != null) { + return fTypeNamePatterns; + } + + String patterns = getPattern(); + + // delimit by "," + fTypeNamePatterns = patterns.split(","); //$NON-NLS-1$ + fSuffix = new String[fTypeNamePatterns.length]; + fPrefix = new String[fTypeNamePatterns.length]; + for (int i = 0; i < fTypeNamePatterns.length; i++) { + fTypeNamePatterns[i] = fTypeNamePatterns[i].trim(); + String pattern = fTypeNamePatterns[i]; + if (pattern.charAt(0) == '*') { + if (pattern.length() > 1) { + fSuffix[i] = pattern.substring(1); + } else { + fSuffix[i] = ""; //$NON-NLS-1$ + } + } else if (pattern.charAt(pattern.length() - 1) == '*') { + fPrefix[i] = pattern.substring(0, pattern.length() - 1); + } + } + + return fTypeNamePatterns; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java new file mode 100644 index 0000000000..e54161500d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaTargetPatternBreakpoint; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; + +public class JavaTargetPatternBreakpoint extends JavaLineBreakpoint implements + IJavaTargetPatternBreakpoint { + + private static final String TARGET_PATTERN_BREAKPOINT = "org.eclipse.jdt.debug.javaTargetPatternBreakpointMarker"; //$NON-NLS-1$ + + /** + * Table of targets to patterns + */ + private HashMap fPatterns; + + public JavaTargetPatternBreakpoint() { + } + + /** + * @see JDIDebugModel#createTargetPatternBreakpoint(IResource, String, int, + * int, int, int, boolean, Map) + */ + public JavaTargetPatternBreakpoint(IResource resource, String sourceName, + int lineNumber, int charStart, int charEnd, int hitCount, + boolean add, Map attributes) throws DebugException { + this(resource, sourceName, lineNumber, charStart, charEnd, hitCount, + add, attributes, TARGET_PATTERN_BREAKPOINT); + } + + public JavaTargetPatternBreakpoint(final IResource resource, + final String sourceName, final int lineNumber, final int charStart, + final int charEnd, final int hitCount, final boolean add, + final Map attributes, final String markerType) + throws DebugException { + IWorkspaceRunnable wr = monitor -> { + + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addSourceNameAndHitCount(attributes, sourceName, hitCount); + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // create the marker + setMarker(resource.createMarker(markerType, attributes)); + + register(add); + }; + run(getMarkerRule(resource), wr); + } + + /** + * Creates the event requests to: + *
            + *
          • Listen to class loads related to the breakpoint
          • + *
          • Respond to the breakpoint being hit
          • + *
          + */ + @Override + public void addToTarget(JDIDebugTarget target) throws CoreException { + + // pre-notification + fireAdding(target); + + String referenceTypeName = getPattern(target); + if (referenceTypeName == null) { + return; + } + + String classPrepareTypeName = referenceTypeName; + // create request to listen to class loads + // name may only be partially resolved + if (!referenceTypeName.endsWith("*")) { //$NON-NLS-1$ + classPrepareTypeName = classPrepareTypeName + '*'; + } + registerRequest(target.createClassPrepareRequest(classPrepareTypeName), + target); + + // create breakpoint requests for each class currently loaded + VirtualMachine vm = target.getVM(); + if (vm != null) { + List classes = vm.allClasses(); + if (classes != null) { + String typeName = null; + for(ReferenceType type : classes) { + typeName = type.name(); + if (typeName != null && typeName.startsWith(referenceTypeName)) { + createRequest(target, type); + } + } + } + } else { + target.requestFailed( + JDIDebugBreakpointMessages.JavaTargetPatternBreakpoint_Unable_to_add_breakpoint___VM_disconnected__1, + new VMDisconnectedException()); + } + } + + /** + * @see JavaBreakpoint#getReferenceTypeName() + */ + protected String getReferenceTypeName() { + String name = "*"; //$NON-NLS-1$ + try { + name = getSourceName(); + } catch (CoreException ce) { + JDIDebugPlugin.log(ce); + } + return name; + } + + /** + * @see JavaBreakpoint#installableReferenceType(ReferenceType) + */ + @Override + protected boolean installableReferenceType(ReferenceType type, + JDIDebugTarget target) throws CoreException { + // if the source name attribute is specified, check for a match with the + // debug attribute (if available) + if (getSourceName() != null) { + String sourceName = null; + try { + sourceName = type.sourceName(); + } catch (AbsentInformationException e) { + // unable to compare + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return false; + } + target.targetRequestFailed( + MessageFormat.format( + JDIDebugBreakpointMessages.JavaPatternBreakpoint_exception_source_name, + e.toString(), + type.name()), + e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return false; + } catch (RuntimeException e) { + target.targetRequestFailed( + MessageFormat.format( + JDIDebugBreakpointMessages.JavaPatternBreakpoint_exception_source_name, + e.toString(), + type.name()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return false; + } + + // if the debug attribute matches the source name, attempt + // installion + if (sourceName != null) { + if (!getSourceName().equalsIgnoreCase(sourceName)) { + return false; + } + } + } + + String pattern = getPattern(target); + String queriedType = type.name(); + if (pattern == null || queriedType == null) { + return false; + } + if (queriedType.startsWith(pattern)) { + // query registered listeners to see if this pattern breakpoint + // should + // be installed in the given target + return queryInstallListeners(target, type); + } + return false; + } + + /** + * Adds the source name and hit count attributes to the given map. + */ + protected void addSourceNameAndHitCount(Map attributes, String sourceName, + int hitCount) { + if (sourceName != null) { + attributes.put(SOURCE_NAME, sourceName); + } + if (hitCount > 0) { + attributes.put(HIT_COUNT, Integer.valueOf(hitCount)); + attributes.put(EXPIRED, Boolean.FALSE); + } + } + + /** + * @see IJavaTargetPatternBreakpoint#getPattern(IJavaDebugTarget) + */ + @Override + public String getPattern(IJavaDebugTarget target) { + if (fPatterns != null) { + return fPatterns.get(target); + } + return null; + } + + /** + * @see IJavaTargetPatternBreakpoint#setPattern(IJavaDebugTarget, String) + */ + @Override + public void setPattern(IJavaDebugTarget target, String pattern) + throws CoreException { + if (fPatterns == null) { + fPatterns = new HashMap<>(2); + } + // if pattern is changing then remove and re-add + String oldPattern = getPattern(target); + fPatterns.put(target, pattern); + if (oldPattern != null && !oldPattern.equals(pattern)) { + recreate((JDIDebugTarget) target); + fireChanged(); + } + } + + /** + * @see IJavaTargetPatternBreakpoint#getSourceName() + */ + @Override + public String getSourceName() throws CoreException { + return (String) ensureMarker().getAttribute(SOURCE_NAME); + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#removeFromTarget(JDIDebugTarget) + */ + @Override + public void removeFromTarget(JDIDebugTarget target) throws CoreException { + fPatterns.remove(target); + super.removeFromTarget(target); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java new file mode 100644 index 0000000000..054d1b48bc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java @@ -0,0 +1,592 @@ +/******************************************************************************* + * Copyright (c) 2000, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; +import org.eclipse.jdt.debug.core.IJavaWatchpoint; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; + +import com.sun.jdi.Field; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.event.AccessWatchpointEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.ModificationWatchpointEvent; +import com.sun.jdi.request.AccessWatchpointRequest; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; +import com.sun.jdi.request.ModificationWatchpointRequest; +import com.sun.jdi.request.WatchpointRequest; + +public class JavaWatchpoint extends JavaLineBreakpoint implements + IJavaWatchpoint { + + public static final String JAVA_WATCHPOINT = "org.eclipse.jdt.debug.javaWatchpointMarker"; //$NON-NLS-1$ + /** + * Watchpoint attribute storing the access value (value + * "org.eclipse.jdt.debug.core.access"). This attribute is + * stored as a boolean, indicating whether a watchpoint is an + * access watchpoint. + */ + protected static final String ACCESS = "org.eclipse.jdt.debug.core.access"; //$NON-NLS-1$ + /** + * Watchpoint attribute storing the modification value (value + * "org.eclipse.jdt.debug.core.modification"). This attribute + * is stored as a boolean, indicating whether a watchpoint is a + * modification watchpoint. + */ + protected static final String MODIFICATION = "org.eclipse.jdt.debug.core.modification"; //$NON-NLS-1$ + /** + * Watchpoint attribute storing the auto_disabled value (value + * "org.eclipse.jdt.debug.core.auto_disabled"). This attribute + * is stored as a boolean, indicating whether a watchpoint has + * been auto-disabled (as opposed to being disabled explicitly by the user) + */ + protected static final String AUTO_DISABLED = "org.eclipse.jdt.debug.core.auto_disabled"; //$NON-NLS-1$ + + /** + * Breakpoint attribute storing the name of the field on which a breakpoint + * is set. (value "org.eclipse.jdt.debug.core.fieldName"). This + * attribute is a String. + */ + protected static final String FIELD_NAME = "org.eclipse.jdt.debug.core.fieldName"; //$NON-NLS-1$ + /** + * Flag indicating that this breakpoint last suspended execution due to a + * field access + */ + protected static final Integer ACCESS_EVENT = Integer.valueOf(0); + /** + * Flag indicating that this breakpoint last suspended execution due to a + * field modification + */ + protected static final Integer MODIFICATION_EVENT = Integer.valueOf(1); + /** + * Maps each debug target that is suspended for this breakpoint to reason + * that this breakpoint suspended it. Reasons include: + *
            + *
          1. Field access (value ACCESS_EVENT)
          2. + *
          3. Field modification (value MODIFICATION_EVENT)
          4. + *
          + */ + private final HashMap fLastEventTypes = new HashMap<>(10); + + public JavaWatchpoint() { + } + + /** + * @see JDIDebugModel#createWatchpoint(IResource, String, String, int, int, + * int, int, boolean, Map) + */ + public JavaWatchpoint(final IResource resource, final String typeName, + final String fieldName, final int lineNumber, final int charStart, + final int charEnd, final int hitCount, final boolean add, + final Map attributes) throws DebugException { + IWorkspaceRunnable wr = monitor -> { + // add attributes + addLineBreakpointAttributes(attributes, getModelIdentifier(), + true, lineNumber, charStart, charEnd); + addTypeNameAndHitCount(attributes, typeName, hitCount); + attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy())); + // configure the field handle + addFieldName(attributes, fieldName); + // configure the access and modification flags to defaults + addDefaultAccessAndModification(attributes); + + setMarker(resource.createMarker(JAVA_WATCHPOINT, attributes)); + + register(add); + }; + run(getMarkerRule(resource), wr); + } + + /** + * @see JavaBreakpoint#createRequest(JDIDebugTarget, ReferenceType) + * + * Creates and installs an access and modification watchpoint request + * in the given reference type, configuring the requests as appropriate + * for this watchpoint. The requests are then enabled based on whether + * this watchpoint is an access watchpoint, modification watchpoint, or + * both. Finally, the requests are registered with the given target. + */ + @Override + protected boolean createRequest(JDIDebugTarget target, ReferenceType type) + throws CoreException { + if (shouldSkipBreakpoint()) { + return false; + } + Field field = null; + + field = type.fieldByName(getFieldName()); + if (field == null) { + // error + return false; + } + AccessWatchpointRequest accessRequest = null; + ModificationWatchpointRequest modificationRequest = null; + if (target.supportsAccessWatchpoints()) { + accessRequest = createAccessWatchpoint(target, field); + registerRequest(accessRequest, target); + } else { + notSupported(JDIDebugBreakpointMessages.JavaWatchpoint_no_access_watchpoints); + } + if (target.supportsModificationWatchpoints()) { + modificationRequest = createModificationWatchpoint(target, field); + if (modificationRequest == null) { + return false; + } + registerRequest(modificationRequest, target); + return true; + } + notSupported(JDIDebugBreakpointMessages.JavaWatchpoint_no_modification_watchpoints); + return false; + } + + /** + * @see JavaBreakpoint#setRequestThreadFilter(EventRequest) + */ + @Override + protected void setRequestThreadFilter(EventRequest request, + ThreadReference thread) { + ((WatchpointRequest) request).addThreadFilter(thread); + } + + /** + * Either access or modification watchpoints are not supported. Throw an + * appropriate exception. + * + * @param message + * the message that states that access or modification + * watchpoints are not supported + */ + protected void notSupported(String message) throws DebugException { + throw new DebugException(new Status(IStatus.ERROR, + DebugPlugin.getUniqueIdentifier(), + DebugException.NOT_SUPPORTED, message, null)); // + } + + /** + * Create an access watchpoint for the given breakpoint and associated field + */ + protected AccessWatchpointRequest createAccessWatchpoint( + JDIDebugTarget target, Field field) throws CoreException { + return (AccessWatchpointRequest) createWatchpoint(target, field, true); + } + + /** + * Create a modification watchpoint for the given breakpoint and associated + * field + */ + protected ModificationWatchpointRequest createModificationWatchpoint( + JDIDebugTarget target, Field field) throws CoreException { + return (ModificationWatchpointRequest) createWatchpoint(target, field, + false); + } + + /** + * Create a watchpoint for the given breakpoint and associated field. + * + * @param target + * the target in which the request will be installed + * @param field + * the field on which the request will be set + * @param access + * true if an access watchpoint will be created. + * false if a modification watchpoint will be + * created. + * + * @return an WatchpointRequest (AccessWatchpointRequest if access is + * true; ModificationWatchpointRequest if access is + * false). + */ + protected WatchpointRequest createWatchpoint(JDIDebugTarget target, + Field field, boolean access) throws CoreException { + WatchpointRequest request = null; + EventRequestManager manager = target.getEventRequestManager(); + if (manager == null) { + target.requestFailed( + JDIDebugBreakpointMessages.JavaWatchpoint_Unable_to_create_breakpoint_request___VM_disconnected__1, + new VMDisconnectedException()); + } + try { + if (access) { + request = manager.createAccessWatchpointRequest(field); + } else { + request = manager.createModificationWatchpointRequest(field); + } + configureRequest(request, target); + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return null; + } + target.internalError(e); + return null; + } catch (RuntimeException e) { + target.internalError(e); + return null; + } + return request; + } + + /** + * @see JavaBreakpoint#recreateRequest(EventRequest, JDIDebugTarget) + */ + protected EventRequest recreateRequest(EventRequest request, + JDIDebugTarget target) throws CoreException { + try { + Field field = ((WatchpointRequest) request).field(); + if (request instanceof AccessWatchpointRequest) { + request = createAccessWatchpoint(target, field); + } else if (request instanceof ModificationWatchpointRequest) { + request = createModificationWatchpoint(target, field); + } + } catch (VMDisconnectedException e) { + if (!target.isAvailable()) { + return request; + } + target.internalError(e); + return request; + } catch (RuntimeException e) { + target.internalError(e); + } + return request; + } + + /** + * @see IBreakpoint#setEnabled(boolean) + * + * If the watchpoint is not watching access or modification, set the + * default values. If this isn't done, the resulting state (enabled + * with access and modification both disabled) is ambiguous. + */ + @Override + public void setEnabled(boolean enabled) throws CoreException { + if (enabled) { + if (!(isAccess() || isModification())) { + setDefaultAccessAndModification(); + } + } + super.setEnabled(enabled); + } + + /** + * @see org.eclipse.debug.core.model.IWatchpoint#isAccess() + */ + @Override + public boolean isAccess() throws CoreException { + return ensureMarker().getAttribute(ACCESS, false); + } + + /** + * Sets whether this breakpoint will suspend execution when its associated + * field is accessed. If true and this watchpoint is disabled, this + * watchpoint is automatically enabled. If both access and modification are + * false, this watchpoint is automatically disabled. + * + * @param access + * whether to suspend on field access + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + * @see org.eclipse.debug.core.model.IWatchpoint#setAccess(boolean) + */ + @Override + public void setAccess(boolean access) throws CoreException { + if (access == isAccess()) { + return; + } + setAttribute(ACCESS, access); + if (access && !isEnabled()) { + setEnabled(true); + } else if (!(access || isModification())) { + setEnabled(false); + } + recreate(); + } + + /** + * @see org.eclipse.debug.core.model.IWatchpoint#isModification() + */ + @Override + public boolean isModification() throws CoreException { + return ensureMarker().getAttribute(MODIFICATION, false); + } + + /** + * Sets whether this breakpoint will suspend execution when its associated + * field is modified. If true and this watchpoint is disabled, this + * watchpoint is automatically enabled. If both access and modification are + * false, this watchpoint is automatically disabled. + * + * @param modification + * whether to suspend on field modification + * @exception CoreException + * if unable to set the property on this breakpoint's + * underlying marker + * @see org.eclipse.debug.core.model.IWatchpoint#setModification(boolean) + */ + @Override + public void setModification(boolean modification) throws CoreException { + if (modification == isModification()) { + return; + } + setAttribute(MODIFICATION, modification); + if (modification && !isEnabled()) { + setEnabled(true); + } else if (!(modification || isAccess())) { + setEnabled(false); + } + recreate(); + } + + /** + * Sets the default access and modification attributes of the watchpoint. + * The default values are: + *
            + *
          • access = false + *
          • modification = true + *
              + */ + protected void setDefaultAccessAndModification() throws CoreException { + boolean[] def = getDefaultAccessAndModificationValues(); + Object[] values = new Object[def.length]; + for (int i = 0; i < def.length; i++) { + values[i] = Boolean.valueOf(def[i]); + } + String[] attributes = new String[] { ACCESS, MODIFICATION }; + setAttributes(attributes, values); + } + + /** + * Returns the default access and modification suspend option for a new + * watchpoint based on the user preference settings The return array will + * only ever contain two values, where the possibilities are: + *
                + *
              • {true, true} - both access and modification are enabled
              • + *
              • {true, false} - access is enabled and modification is + * disabled
              • + *
              • {false, true} -access is disabled and modification is + * enabled
              • + *
              + * The default returned array is {true, true} + * + * @return an array of two boolean values representing the default access + * and modification settings + * + * @since 3.3.1 + */ + protected boolean[] getDefaultAccessAndModificationValues() { + int value = Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.PREF_DEFAULT_WATCHPOINT_SUSPEND_POLICY, + 0, + null); + switch (value) { + case 0: { + return new boolean[] { true, true }; + } + case 1: { + return new boolean[] { true, false }; + } + case 2: { + return new boolean[] { false, true }; + } + default: { + return new boolean[] { true, true }; + } + } + } + + /** + * Adds the default access and modification attributes of the watchpoint to + * the given map + *
                + *
              • access = true + *
              • modification = true + *
              • auto disabled = false + *
                  + */ + protected void addDefaultAccessAndModification(Map attributes) { + boolean[] values = getDefaultAccessAndModificationValues(); + attributes.put(ACCESS, (values[0] ? Boolean.TRUE : Boolean.FALSE)); + attributes + .put(MODIFICATION, (values[1] ? Boolean.TRUE : Boolean.FALSE)); + attributes.put(AUTO_DISABLED, Boolean.FALSE); + } + + /** + * Adds the field name to the given attribute map + */ + protected void addFieldName(Map attributes, String fieldName) { + attributes.put(FIELD_NAME, fieldName); + } + + /** + * @see IJavaWatchpoint#getFieldName() + */ + @Override + public String getFieldName() throws CoreException { + return ensureMarker().getAttribute(FIELD_NAME, null); + } + + /** + * Store the type of the event, then handle it as specified in the + * superclass. This is useful for correctly generating the thread text when + * asked (assumes thread text is requested after the event is passed to this + * breakpoint. + * + * Also, @see JavaBreakpoint#handleEvent(Event, JDIDebugTarget) + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet) { + if (event instanceof AccessWatchpointEvent) { + fLastEventTypes.put(target, ACCESS_EVENT); + } else if (event instanceof ModificationWatchpointEvent) { + fLastEventTypes.put(target, MODIFICATION_EVENT); + } + return super.handleEvent(event, target, suspendVote, eventSet); + } + + /** + * @see JavaBreakpoint#updateEnabledState(EventRequest, JDIDebugTarget) + */ + @Override + protected void updateEnabledState(EventRequest request, + JDIDebugTarget target) throws CoreException { + boolean enabled = isEnabled(); + if (request instanceof AccessWatchpointRequest) { + if (isAccess()) { + if (enabled != request.isEnabled()) { + internalUpdateEnabledState(request, enabled, target); + } + } else { + if (request.isEnabled()) { + internalUpdateEnabledState(request, false, target); + } + } + } + if (request instanceof ModificationWatchpointRequest) { + if (isModification()) { + if (enabled != request.isEnabled()) { + internalUpdateEnabledState(request, enabled, target); + } + } else { + if (request.isEnabled()) { + internalUpdateEnabledState(request, false, target); + } + } + } + } + + /** + * @see IJavaWatchpoint#isAccessSuspend(IDebugTarget) + */ + @Override + public boolean isAccessSuspend(IDebugTarget target) { + Integer lastEventType = fLastEventTypes.get(target); + if (lastEventType == null) { + return false; + } + return lastEventType.equals(ACCESS_EVENT); + } + + /** + * @see IJavaLineBreakpoint#supportsCondition() + */ + @Override + public boolean supportsCondition() { + return true; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#removeFromTarget(JDIDebugTarget) + */ + @Override + public void removeFromTarget(JDIDebugTarget target) throws CoreException { + fLastEventTypes.remove(target); + super.removeFromTarget(target); + } + + /** + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint#addInstanceFilter(EventRequest, + * ObjectReference) + */ + @Override + protected void addInstanceFilter(EventRequest request, + ObjectReference object) { + if (request instanceof WatchpointRequest) { + ((WatchpointRequest) request).addInstanceFilter(object); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IWatchpoint#supportsAccess() + */ + @Override + public boolean supportsAccess() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IWatchpoint#supportsModification() + */ + @Override + public boolean supportsModification() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint# + * installableReferenceType(com.sun.jdi.ReferenceType, + * org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget) + */ + @Override + protected boolean installableReferenceType(ReferenceType type, + JDIDebugTarget target) throws CoreException { + String installableType = getTypeName(); + String queriedType = type.name(); + if (installableType == null || queriedType == null) { + return false; + } + if (installableType.equals(queriedType)) { + return queryInstallListeners(target, type); + } + + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/LambdaLocationLocatorHelper.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/LambdaLocationLocatorHelper.java new file mode 100644 index 0000000000..4d8b54236e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/LambdaLocationLocatorHelper.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2022 Gayan Perera and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Gayan Perera - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; + +public final class LambdaLocationLocatorHelper { + + private LambdaLocationLocatorHelper() { + } + + /** + * Return of the signature of the lambda method. The signature is computed to + * be compatible with the final lambda method with method arguments and outer + * local variables in debugger. + */ + public static String toMethodSignature(IMethodBinding methodBinding) { + StringBuilder builder = new StringBuilder(); + builder.append('('); + if (methodBinding.getParameterTypes().length > 0 || methodBinding.getSyntheticOuterLocals().length > 0) { + builder.append(Stream.of(methodBinding.getSyntheticOuterLocals()) + .map(b -> Signature.createTypeSignature(qualifiedName(b.getType()), true)) + .collect(Collectors.joining())); + + builder.append(Stream.of(methodBinding.getParameterTypes()) + .map(b -> Signature.createTypeSignature(qualifiedName(b), true)) + .collect(Collectors.joining())); + } + builder.append(')'); + builder.append(Signature.createTypeSignature(qualifiedName(methodBinding.getReturnType()), true)); + return builder.toString(); + } + + /** + * Return the lambda method name from the given method binding. + */ + public static String toMethodName(IMethodBinding methodBinding) { + String key = methodBinding.getKey(); + return key.substring(key.indexOf('.') + 1, key.indexOf('(')); + } + + private static String qualifiedName(ITypeBinding binding) { + return binding.getQualifiedName().replace('.', '/'); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java new file mode 100644 index 0000000000..095cc79056 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java @@ -0,0 +1,1614 @@ +/******************************************************************************* + * Copyright (c) 2003, 2023 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.breakpoints; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.ArrayAccess; +import org.eclipse.jdt.core.dom.ArrayCreation; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.AssertStatement; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BlockComment; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.CastExpression; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.CharacterLiteral; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ConditionalExpression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EmptyStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.EnumConstantDeclaration; +import org.eclipse.jdt.core.dom.EnumDeclaration; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IBinding; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.InstanceofExpression; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.LabeledStatement; +import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.core.dom.LineComment; +import org.eclipse.jdt.core.dom.MarkerAnnotation; +import org.eclipse.jdt.core.dom.MemberRef; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.MethodRef; +import org.eclipse.jdt.core.dom.MethodRefParameter; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.NullLiteral; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.ParenthesizedExpression; +import org.eclipse.jdt.core.dom.PostfixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression.Operator; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.QualifiedType; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SwitchCase; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.TagElement; +import org.eclipse.jdt.core.dom.TextBlock; +import org.eclipse.jdt.core.dom.TextElement; +import org.eclipse.jdt.core.dom.ThisExpression; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.TypeLiteral; +import org.eclipse.jdt.core.dom.TypeParameter; +import org.eclipse.jdt.core.dom.UnionType; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.core.dom.WildcardType; + +/** + * Compute a valid location where to put a breakpoint from an JDOM + * CompilationUnit. The result is the first valid location with a line number + * greater or equals than the given position. + */ +public class ValidBreakpointLocationLocator extends ASTVisitor { + + public static final int LOCATION_NOT_FOUND = 0; + public static final int LOCATION_LINE = 1; + public static final int LOCATION_METHOD = 2; + public static final int LOCATION_FIELD = 3; + public static final int LOCATION_LAMBDA_METHOD = 4; + + + private final CompilationUnit fCompilationUnit; + private final int fLineNumber; + private final boolean fBindingsResolved; + private boolean fNeedBindings = false; + private final boolean fBestMatch; + + private int fLocationType; + private boolean fLocationFound; + private boolean fLambdaVisited; + private String fLambdaMethodName; + private String fLambdaMethodSignature; + private String fTypeName; + private int fLineLocation; + private int fMemberOffset; + private int fNodeLength; + private List fLabels; + private final int fInputOffset; + private final int fInputLength; + + /** + * @param compilationUnit + * the JDOM CompilationUnit of the source code. + * @param lineNumber + * the line number in the source code where to put the + * breakpoint. + * @param bestMatch + * if true look for the best match, otherwise look + * only for a valid line + */ + public ValidBreakpointLocationLocator(CompilationUnit compilationUnit, + int lineNumber, boolean bindingsResolved, boolean bestMatch) { + fCompilationUnit = compilationUnit; + fLineNumber = lineNumber; + fBindingsResolved = bindingsResolved; + fBestMatch = bestMatch; + fLocationFound = false; + fInputOffset = -1; + fInputLength = -1; + } + + /** + * @param compilationUnit + * the JDOM CompilationUnit of the source code. + * @param lineNumber + * the line number in the source code where to put the breakpoint. + * @param bestMatch + * if true look for the best match, otherwise look only for a valid line + * @param offset + * selection offset on which breakpoints should be toggled + * @param end + * selection end on which breakpoints should be toggled + */ + public ValidBreakpointLocationLocator(CompilationUnit compilationUnit, int lineNumber, boolean bindingsResolved, boolean bestMatch, int offset, int end) { + fCompilationUnit = compilationUnit; + fLineNumber = lineNumber; + fBindingsResolved = bindingsResolved; + fBestMatch = bestMatch; + fLocationFound = false; + fInputOffset = offset; + fInputLength = end; + } + + /** + * Returns whether binding information would be helpful in validating a + * breakpoint location. If this locator makes a pass of the tree and + * determines that binding information would be helpful but was not + * available, this method returns true. + * + * @return whether binding information would be helpful in validating a + * breakpoint location + */ + public boolean isBindingsRequired() { + return fNeedBindings; + } + + /** + * Return the type of the valid location found + * + * @return one of LOCATION_NOT_FOUND, LOCATION_LINE, LOCATION_METHOD or + * LOCATION_FIELD + */ + public int getLocationType() { + return fLocationType; + } + + /** + * Return of the type where the valid location is. + */ + public String getFullyQualifiedTypeName() { + return fTypeName; + } + + /** + * Return of the name of the lambda method where the valid location is. + */ + public String getLambdaMethodName() { + return fLambdaMethodName; + } + + /** + * Return of the signature of the lambda method where the valid location is. + * The signature is computed to be compatible with the final lambda method with + * method arguments and outer local variables. + */ + public String getfLambdaMethodSignature() { + return fLambdaMethodSignature; + } + + /** + * Return the line number of the computed valid location + */ + public int getLineLocation() { + if (fLocationType == LOCATION_NOT_FOUND || fLocationType == LOCATION_METHOD) { + return -1; + } + return fLineLocation; + } + + /** + * Return the offset of the member which is the valid location, if the + * location type is LOCATION_METHOD or LOCATION_FIELD. + */ + public int getMemberOffset() { + return fMemberOffset; + } + + public int getNodeLength() { + return fNodeLength; + } + + public CompilationUnit getCompilationUnit() { + return fCompilationUnit; + } + /** + * Compute the name of the type which contains this node.
                  + *
                  + * Delegates to the old method of computing the type name if bindings are + * not available. + * + * @see #computeTypeName0(ASTNode) + * @since 3.6 + */ + private String computeTypeName(ASTNode node) { + AbstractTypeDeclaration type = null; + while (!(node instanceof CompilationUnit)) { + if (node instanceof AbstractTypeDeclaration) { + type = (AbstractTypeDeclaration) node; + break; + } + node = node.getParent(); + } + if (type != null) { + ITypeBinding binding = type.resolveBinding(); + if (binding != null) { + return binding.getBinaryName(); + } + } + return computeTypeName0(node); + } + + /** + * Fall back to compute the type name if bindings are not resolved + * + * @param node + * @return the computed type name + */ + String computeTypeName0(ASTNode node) { + String typeName = null; + while (!(node instanceof CompilationUnit)) { + if (node instanceof AbstractTypeDeclaration) { + String identifier = ((AbstractTypeDeclaration) node).getName() + .getIdentifier(); + if (typeName == null) { + typeName = identifier; + } else { + typeName = identifier + "$" + typeName; //$NON-NLS-1$ + } + } + node = node.getParent(); + } + PackageDeclaration packageDecl = ((CompilationUnit) node).getPackage(); + String packageIdentifier = ""; //$NON-NLS-1$ + if (packageDecl != null) { + Name packageName = packageDecl.getName(); + while (packageName.isQualifiedName()) { + QualifiedName qualifiedName = (QualifiedName) packageName; + packageIdentifier = qualifiedName.getName().getIdentifier() + + "." + packageIdentifier; //$NON-NLS-1$ + packageName = qualifiedName.getQualifier(); + } + packageIdentifier = ((SimpleName) packageName).getIdentifier() + + "." + packageIdentifier; //$NON-NLS-1$ + } + return packageIdentifier + typeName; + } + + /** + * Return true if this node children may contain a valid + * location for the breakpoint. + * + * @param node + * the node. + * @param isCode + * true indicated that the first line of the given node always + * contains some executable code, even if split in multiple + * lines. + */ + private boolean visit(ASTNode node, boolean isCode) { + int startPosition = node.getStartPosition(); + int startLine = lineNumber(startPosition); + int endLine = lineNumber(startPosition + node.getLength() - 1); + int inputEndLine = fInputOffset != -1 ? lineNumber(fInputOffset) : -1; + + // if we already found a correct location + // no need to check the element inside if the line number doesn't match. + // if line numbers match we still need to visit the whole expression in this line + // to make sure we have any lambda's we were looking for which we didn't visited yet. + if (fLambdaVisited || (fLocationFound && fLineNumber != startLine)) { + return false; + } + // if the position is not in this part of the code + // no need to check the element inside. + if (endLine < fLineNumber) { + return false; + } + // if the first line of this node always represents some executable code + // and the + // breakpoint is requested on this line or on a previous line, this is a + // valid + // location + // Need to check also that this Node is within the input boundary - applicable for Record + if (isCode && (fLineNumber <= startLine) && (inputEndLine == -1 || startLine <= inputEndLine)) { + fLineLocation = startLine; + fLocationFound = true; + fLocationType = LOCATION_LINE; + fTypeName = computeTypeName(node); + return false; + } + return true; + } + + private boolean isReplacedByConstantValue(Expression node) { + switch (node.getNodeType()) { + // literals are constant + case ASTNode.BOOLEAN_LITERAL: + case ASTNode.CHARACTER_LITERAL: + case ASTNode.NUMBER_LITERAL: + case ASTNode.STRING_LITERAL: + case ASTNode.TEXT_BLOCK: + return true; + case ASTNode.SIMPLE_NAME: + case ASTNode.QUALIFIED_NAME: + return isReplacedByConstantValue((Name) node); + case ASTNode.FIELD_ACCESS: + return isReplacedByConstantValue((FieldAccess) node); + case ASTNode.SUPER_FIELD_ACCESS: + return isReplacedByConstantValue((SuperFieldAccess) node); + case ASTNode.INFIX_EXPRESSION: + return isReplacedByConstantValue((InfixExpression) node); + case ASTNode.PREFIX_EXPRESSION: + return isReplacedByConstantValue((PrefixExpression) node); + case ASTNode.CAST_EXPRESSION: + return isReplacedByConstantValue(((CastExpression) node) + .getExpression()); + default: + return false; + } + } + + private boolean isReplacedByConstantValue(InfixExpression node) { + // if all operands are constant value, the expression is replaced by a + // constant value + if (!(isReplacedByConstantValue(node.getLeftOperand()) && isReplacedByConstantValue(node + .getRightOperand()))) { + return false; + } + if (node.hasExtendedOperands()) { + for (Iterator iter = node.extendedOperands().iterator(); iter.hasNext();) { + if (!isReplacedByConstantValue(iter.next())) { + return false; + } + } + } + return true; + } + + private boolean isReplacedByConstantValue(PrefixExpression node) { + // for '-', '+', '~' and '!', if the operand is a constant value, + // the expression is replaced by a constant value + Operator operator = node.getOperator(); + if (operator != PrefixExpression.Operator.INCREMENT + && operator != PrefixExpression.Operator.DECREMENT) { + return isReplacedByConstantValue(node.getOperand()); + } + return false; + } + + private boolean isReplacedByConstantValue(Name node) { + if (!fBindingsResolved) { + fNeedBindings = true; + return false; + } + // if node is a variable with a constant value (static final field) + IBinding binding = node.resolveBinding(); + if (binding != null && binding.getKind() == IBinding.VARIABLE) { + return ((IVariableBinding) binding).getConstantValue() != null; + } + return false; + } + + private boolean isReplacedByConstantValue(FieldAccess node) { + if (!fBindingsResolved) { + fNeedBindings = true; + return false; + } + // if the node is 'this.', and the field is static final + Expression expression = node.getExpression(); + IVariableBinding binding = node.resolveFieldBinding(); + if (binding != null + && expression.getNodeType() == ASTNode.THIS_EXPRESSION) { + return binding.getConstantValue() != null; + } + return false; + } + + private boolean isReplacedByConstantValue(SuperFieldAccess node) { + if (!fBindingsResolved) { + fNeedBindings = true; + return false; + } + // if the field is static final + IVariableBinding binding = node.resolveFieldBinding(); + if (binding != null) { + return binding.getConstantValue() != null; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * AnnotationTypeDeclaration) + */ + @Override + public boolean visit(AnnotationTypeDeclaration node) { + if (visit(node, false)) { + List decls = node.bodyDeclarations(); + for(BodyDeclaration decl : decls) { + decl.accept(this); + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * AnnotationTypeMemberDeclaration) + */ + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnonymousClassDeclaration) + */ + @Override + public boolean visit(AnonymousClassDeclaration node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayAccess) + */ + @Override + public boolean visit(ArrayAccess node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayCreation) + */ + @Override + public boolean visit(ArrayCreation node) { + return visit(node, node.getInitializer() == null); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayInitializer) + */ + @Override + public boolean visit(ArrayInitializer node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ArrayType) + */ + @Override + public boolean visit(ArrayType node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AssertStatement) + */ + @Override + public boolean visit(AssertStatement node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Assignment) + */ + @Override + public boolean visit(Assignment node) { + if (visit(node, false)) { + // if the left hand side represent a local variable, or a static + // field + // and the breakpoint was requested on a line before the line where + // starts the assignment, set the location to be the first executable + // instruction of the right hand side, as it will be the first part + // of + // this assignment to be executed + Expression leftHandSide = node.getLeftHandSide(); + if (leftHandSide instanceof Name) { + int startLine = lineNumber(node.getStartPosition()); + if (fLineNumber < startLine) { + if (fBindingsResolved) { + IVariableBinding binding = (IVariableBinding) ((Name) leftHandSide) + .resolveBinding(); + if (binding != null + && (!binding.isField() || Modifier + .isStatic(binding.getModifiers()))) { + node.getRightHandSide().accept(this); + } + } else { + fNeedBindings = true; + } + } + } + return true; + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Block) + */ + @Override + public boolean visit(Block node) { + if (visit(node, false)) { + if (node.statements().isEmpty() + && node.getParent().getNodeType() == ASTNode.METHOD_DECLARATION) { + // in case of an empty method, set the breakpoint on the last + // line of the empty block. + fLineLocation = lineNumber(node.getStartPosition() + + node.getLength() - 1); + fLocationFound = true; + fLocationType = LOCATION_LINE; + fTypeName = computeTypeName(node); + return false; + } + return true; + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * BlockComment) + */ + @Override + public boolean visit(BlockComment node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BooleanLiteral) + */ + @Override + public boolean visit(BooleanLiteral node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BreakStatement) + */ + @Override + public boolean visit(BreakStatement node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CastExpression) + */ + @Override + public boolean visit(CastExpression node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CatchClause) + */ + @Override + public boolean visit(CatchClause node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CharacterLiteral) + */ + @Override + public boolean visit(CharacterLiteral node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ClassInstanceCreation) + */ + @Override + public boolean visit(ClassInstanceCreation node) { + if (visit(node, false)) { + List arguments = node.arguments(); + for (ASTNode astNode : arguments) { + if (astNode instanceof LambdaExpression) { + astNode.accept(this); + return false; + } + } + } + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CompilationUnit) + */ + @Override + public boolean visit(CompilationUnit node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConditionalExpression) + */ + @Override + public boolean visit(ConditionalExpression node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ConstructorInvocation) + */ + @Override + public boolean visit(ConstructorInvocation node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ContinueStatement) + */ + @Override + public boolean visit(ContinueStatement node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.DoStatement) + */ + @Override + public boolean visit(DoStatement node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EmptyStatement) + */ + @Override + public boolean visit(EmptyStatement node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnhancedForStatement) + */ + @Override + public boolean visit(EnhancedForStatement node) { + if (visit(node, false)) { + node.getExpression().accept(this); + node.getBody().accept(this); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnumConstantDeclaration) + */ + @Override + public boolean visit(EnumConstantDeclaration node) { + if (visit(node, false)) { + List arguments = node.arguments(); + for(Expression exp : arguments) { + exp.accept(this); + } + AnonymousClassDeclaration decl = node.getAnonymousClassDeclaration(); + if (decl != null) { + decl.accept(this); + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * EnumDeclaration) + */ + @Override + public boolean visit(EnumDeclaration node) { + if (visit(node, false)) { + List enumConstants = node.enumConstants(); + for(EnumConstantDeclaration econst : enumConstants) { + econst.accept(this); + } + List decls = node.bodyDeclarations(); + for(BodyDeclaration body : decls) { + body.accept(this); + } + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ExpressionStatement) + */ + @Override + public boolean visit(ExpressionStatement node) { + if (fLocationFound && fLambdaVisited) { + return false; + } + if (visit(node, false)) { + if (node.getExpression() instanceof MethodInvocation) { + node.getExpression().accept(this); + return false; + } + } + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldAccess) + */ + @Override + public boolean visit(FieldAccess node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration) + */ + @Override + public boolean visit(FieldDeclaration node) { + if (visit(node, false)) { + if (fBestMatch) { + // check if the line contains a single field declaration. + List fragments = node.fragments(); + if (fragments.size() == 1) { + VariableDeclarationFragment fragment = fragments.get(0); + Expression init = fragment.getInitializer(); + int offset = fragment.getName().getStartPosition(); + int line = lineNumber(offset); + if(Flags.isFinal(node.getModifiers())) { + if(init != null) { + if (line == fLineNumber) { + if (isReplacedByConstantValue(init)) { + fLocationType = LOCATION_LINE; + } else { + fLocationType = LOCATION_FIELD; + } + fMemberOffset = offset; + fLineLocation = line; + fLocationFound = true; + fTypeName = computeTypeName(node); + return false; + } + } + else { + if (line == fLineNumber) { + fMemberOffset = offset; + fLineLocation = line; + fLocationType = LOCATION_FIELD; + fLocationFound = true; + fTypeName = computeTypeName(node); + return false; + } + return false; + } + } + else { + // check if the breakpoint is to be set on the line which + // contains the name of the field + if (line == fLineNumber) { + fMemberOffset = offset; + fLineLocation = line; + fLocationType = LOCATION_FIELD; + fLocationFound = true; + return false; + } + } + } + } + // visit only the variable declaration fragments, not the variable + // names. + List fragments = node.fragments(); + for(VariableDeclarationFragment frag : fragments) { + frag.accept(this); + if(fLocationFound) { + break; + } + } + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ForStatement) + */ + @Override + public boolean visit(ForStatement node) { + // in case on a "for(;;)", the breakpoint can be set on the first token + // of the node. + return visit(node, + node.initializers().isEmpty() && node.getExpression() == null + && node.updaters().isEmpty()); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.IfStatement) + */ + @Override + public boolean visit(IfStatement node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ImportDeclaration) + */ + @Override + public boolean visit(ImportDeclaration node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InfixExpression) + */ + @Override + public boolean visit(InfixExpression node) { + // if the breakpoint is to be set on a constant operand, the breakpoint + // needs to be + // set on the first constant operand after the previous non-constant + // operand + // (or the beginning of the expression, if there is no non-constant + // operand before). + // ex: foo() + // previous non-constant operand + // 1 + // breakpoint set here + // 2 // breakpoint asked to be set here + if (visit(node, false)) { + Expression leftOperand = node.getLeftOperand(); + Expression firstConstant = null; + if (visit(leftOperand, false)) { + leftOperand.accept(this); + return false; + } + if (isReplacedByConstantValue(leftOperand)) { + firstConstant = leftOperand; + } + Expression rightOperand = node.getRightOperand(); + if (visit(rightOperand, false)) { + if (firstConstant == null + || !isReplacedByConstantValue(rightOperand)) { + rightOperand.accept(this); + return false; + } + } else { + if (isReplacedByConstantValue(rightOperand)) { + if (firstConstant == null) { + firstConstant = rightOperand; + } + } else { + firstConstant = null; + } + List extendedOperands = node.extendedOperands(); + for(Expression exp : extendedOperands) { + if (visit(exp, false)) { + if (firstConstant == null || !isReplacedByConstantValue(exp)) { + exp.accept(this); + return false; + } + break; + } + if (isReplacedByConstantValue(exp)) { + if (firstConstant == null) { + firstConstant = exp; + } + } else { + firstConstant = null; + } + } + } + if (firstConstant != null) { + fLineLocation = lineNumber(firstConstant.getStartPosition()); + fLocationFound = true; + fLocationType = LOCATION_LINE; + fTypeName = computeTypeName(firstConstant); + } + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Initializer) + */ + @Override + public boolean visit(Initializer node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.InstanceofExpression) + */ + @Override + public boolean visit(InstanceofExpression node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Javadoc) + */ + @Override + public boolean visit(Javadoc node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.LabeledStatement) + */ + @Override + public boolean visit(LabeledStatement node) { + nestLabel(node.getLabel().getFullyQualifiedName()); + return visit(node, false); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom + * .LabeledStatement) + */ + @Override + public void endVisit(LabeledStatement node) { + popLabel(); + super.endVisit(node); + } + + private String getLabel() { + if (fLabels == null || fLabels.isEmpty()) { + return null; + } + return fLabels.get(fLabels.size() - 1); + } + + private void nestLabel(String label) { + if (fLabels == null) { + fLabels = new ArrayList<>(); + } + fLabels.add(label); + } + + private void popLabel() { + if (fLabels == null || fLabels.isEmpty()) { + return; + } + fLabels.remove(fLabels.size() - 1); + } + + @Override + public boolean visit(LambdaExpression node) { + fMemberOffset = node.getStartPosition(); + fNodeLength = node.getLength(); + if (fInputOffset != -1 && fInputLength > 0 && fInputOffset >= fMemberOffset && fInputOffset + fInputLength <= fMemberOffset + fNodeLength) { + IMethodBinding methodBinding = node.resolveMethodBinding(); + if (methodBinding != null) { + fLambdaVisited = true; + fLocationType = LOCATION_LAMBDA_METHOD; + fLambdaMethodName = LambdaLocationLocatorHelper.toMethodName(methodBinding); + fLambdaMethodSignature = LambdaLocationLocatorHelper.toMethodSignature(methodBinding); + fLocationFound = true; + return false; + } + } else if (fLocationType != LOCATION_LAMBDA_METHOD) { + fLocationType = LOCATION_LINE; + fTypeName = computeTypeName(node); + int startLine = lineNumber(fMemberOffset); + if (fLineNumber <= startLine) { + if (fInputOffset != -1) { + fLineLocation = lineNumber(fInputOffset); + } else { + fLineLocation = startLine; + } + } else { + // visit the body + ASTNode body = node.getBody(); + if (body instanceof Block) { // body is null for abstract methods + fLocationFound = false; + Block block1 = (Block) body; + if (visit(block1)) { + for (Object object : block1.statements()) { + if (object instanceof ASTNode) { + ASTNode node1 = (ASTNode) object; + node1.accept(this); + } + + } + } + } else if (body instanceof LambdaExpression) { + body.accept(this); + } else if (body instanceof MethodInvocation) { + body.accept(this); + } + } + return false; + } + return visit(node, true); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * LineComment) + */ + @Override + public boolean visit(LineComment node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MarkerAnnotation) + */ + @Override + public boolean visit(MarkerAnnotation node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef + * ) + */ + @Override + public boolean visit(MemberRef node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MemberValuePair) + */ + @Override + public boolean visit(MemberValuePair node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration) + */ + @Override + public boolean visit(MethodDeclaration node) { + if (visit(node, false)) { + if (fBestMatch) { + // check if we are on the line which contains the method name + int nameOffset = node.getName().getStartPosition(); + if (lineNumber(nameOffset) == fLineNumber) { + if (node.getParent() instanceof AnonymousClassDeclaration){ + fLocationType = LOCATION_NOT_FOUND; + fLocationFound = true; + return false; + } + fMemberOffset = nameOffset; + fLocationType = LOCATION_METHOD; + fLocationFound = true; + return false; + } + } + // visit only the body + Block body = node.getBody(); + if (body != null) { // body is null for abstract methods + body.accept(this); + } + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodInvocation) + */ + @Override + public boolean visit(MethodInvocation node) { + if (fLocationFound && fLambdaVisited) { + return false; + } + if (visit(node, false)) { + Expression expression = node.getExpression(); + if (expression instanceof ClassInstanceCreation || expression instanceof MethodInvocation) { + expression.accept(this); + } + if (fLocationFound) { + return false; + } + List arguments = node.arguments(); + for (ASTNode astNode : arguments) { + // arguments needs to be accepted to handle stream operation where the lambda debug point + // is expected on a lambda expression which is a parameter on a nested method invocation like + // strings.stream().collect(Collectors.toMap(s -> s.substring(0), s -> s)) + astNode.accept(this); + if (astNode instanceof LambdaExpression && fLambdaVisited) { + return false; + } + } + + } + return visit(node, true); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef + * ) + */ + @Override + public boolean visit(MethodRef node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MethodRefParameter) + */ + @Override + public boolean visit(MethodRefParameter node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier + * ) + */ + @Override + public boolean visit(Modifier node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * NormalAnnotation) + */ + @Override + public boolean visit(NormalAnnotation node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NullLiteral) + */ + @Override + public boolean visit(NullLiteral node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NumberLiteral) + */ + @Override + public boolean visit(NumberLiteral node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PackageDeclaration) + */ + @Override + public boolean visit(PackageDeclaration node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * ParameterizedType) + */ + @Override + public boolean visit(ParameterizedType node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ParenthesizedExpression) + */ + @Override + public boolean visit(ParenthesizedExpression node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PostfixExpression) + */ + @Override + public boolean visit(PostfixExpression node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PrefixExpression) + */ + @Override + public boolean visit(PrefixExpression node) { + if (visit(node, false)) { + if (isReplacedByConstantValue(node)) { + fLineLocation = lineNumber(node.getStartPosition()); + fLocationFound = true; + fLocationType = LOCATION_LINE; + fTypeName = computeTypeName(node); + return false; + } + return true; + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.PrimitiveType) + */ + @Override + public boolean visit(PrimitiveType node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedName) + */ + @Override + public boolean visit(QualifiedName node) { + visit(node, true); + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * QualifiedType) + */ + @Override + public boolean visit(QualifiedType node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ReturnStatement) + */ + @Override + public boolean visit(ReturnStatement node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SimpleName) + */ + @Override + public boolean visit(SimpleName node) { + // the name is only code if its not the current label (if any) + return visit(node, !node.getFullyQualifiedName().equals(getLabel())); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SimpleType) + */ + @Override + public boolean visit(SimpleType node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * SingleMemberAnnotation) + */ + @Override + public boolean visit(SingleMemberAnnotation node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleVariableDeclaration) + */ + @Override + public boolean visit(SingleVariableDeclaration node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.StringLiteral) + */ + @Override + public boolean visit(StringLiteral node) { + return visit(node, true); + } + + @Override + public boolean visit(TextBlock node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperConstructorInvocation) + */ + @Override + public boolean visit(SuperConstructorInvocation node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperFieldAccess) + */ + @Override + public boolean visit(SuperFieldAccess node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SuperMethodInvocation) + */ + @Override + public boolean visit(SuperMethodInvocation node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SwitchCase) + */ + @Override + public boolean visit(SwitchCase node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SwitchStatement) + */ + @Override + public boolean visit(SwitchStatement node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SynchronizedStatement) + */ + @Override + public boolean visit(SynchronizedStatement node) { + return visit(node, false); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement + * ) + */ + @Override + public boolean visit(TagElement node) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * TextElement) + */ + @Override + public boolean visit(TextElement node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThisExpression) + */ + @Override + public boolean visit(ThisExpression node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ThrowStatement) + */ + @Override + public boolean visit(ThrowStatement node) { + return visit(node, true); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TryStatement) + */ + @Override + public boolean visit(TryStatement node) { + return visit(node, false); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.UnionType + * ) + */ + @Override + public boolean visit(UnionType node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration) + */ + @Override + public boolean visit(TypeDeclaration node) { + if (visit(node, false)) { + // visit only the elements of the type declaration + List bodyDeclaration = node.bodyDeclarations(); + for(BodyDeclaration body : bodyDeclaration) { + body.accept(this); + } + } + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclarationStatement) + */ + @Override + public boolean visit(TypeDeclarationStatement node) { + return visit(node, false); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * TypeParameter) + */ + @Override + public boolean visit(TypeParameter node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeLiteral) + */ + @Override + public boolean visit(TypeLiteral node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationExpression) + */ + @Override + public boolean visit(VariableDeclarationExpression node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment) + */ + @Override + public boolean visit(VariableDeclarationFragment node) { + Expression initializer = node.getInitializer(); + if (visit(node, false)) { + int offset = node.getName().getStartPosition(); + int line = lineNumber(offset); + if (initializer != null) { + if (fLineNumber == line) { + fLineLocation = line; + fLocationFound = true; + fLocationType = LOCATION_LINE; + fTypeName = computeTypeName(node); + if (initializer instanceof MethodInvocation || initializer instanceof LambdaExpression) { + initializer.accept(this); + } + return false; + } + initializer.accept(this); + } else { + // the variable has no initializer + // check if the breakpoint is to be set on the line which + // contains the name of the field + if (line == fLineNumber) { + fMemberOffset = offset; + fLineLocation = line; + fLocationType = LOCATION_FIELD; + fTypeName = computeTypeName(node); + fLocationFound = true; + return false; + } + } + } + return false; + } + + private int lineNumber(int offset) { + int lineNumber = fCompilationUnit.getLineNumber(offset); + return lineNumber < 1 ? 1 : lineNumber; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * WildcardType) + */ + @Override + public boolean visit(WildcardType node) { + return false; + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationStatement) + */ + @Override + public boolean visit(VariableDeclarationStatement node) { + return visit(node, false); + } + + /** + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WhileStatement) + */ + @Override + public boolean visit(WhileStatement node) { + return visit(node, false); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/CompilationUnitDelta.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/CompilationUnitDelta.java new file mode 100644 index 0000000000..974060d75d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/CompilationUnitDelta.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2000, 2013 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Yevgen Kogan - Bug 403475 - Hot Code Replace drops too much frames in some cases + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.hcr; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFileState; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTMatcher; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MethodDeclaration; + +/** + * A CompilationUnitDelta represents the source code changes + * between a CU in the workspace and the same CU at some point in the past (from + * the local history). + *

                  + * This functionality is used in the context of Hot Code Replace to determine + * which stack frames are affected (and need to be dropped) by a class reload in + * the Java VM. + *

                  + * Typically a CompilationUnitDelta object is generated for a CU + * when the associated class is replaced in the VM. + */ +public class CompilationUnitDelta { + + /** + * AST of the current source code + */ + private CompilationUnit fCurrentAst; + /** + * AST of the previous source code + */ + private CompilationUnit fPrevAst; + + /** + * AST parser + */ + private ASTParser fParser = null; + + /** + * AST matcher + */ + private ASTMatcher fMatcher = null; + + private boolean fHasHistory = false; + + /** + * Creates a new + * CompilationUnitDelta object that calculates and stores + * the changes of the given CU since some point in time. + */ + public CompilationUnitDelta(ICompilationUnit cu, long timestamp) + throws CoreException { + + if (cu.isWorkingCopy()) { + cu = cu.getPrimary(); + } + + // find underlying file + IFile file = (IFile) cu.getUnderlyingResource(); + + // get available editions + IFileState[] states = file.getHistory(null); + if (states == null || states.length <= 0) { + return; + } + fHasHistory = true; + + IFileState found = null; + // find edition just before the given time stamp + for (IFileState state : states) { + long d = state.getModificationTime(); + if (d < timestamp) { + found = state; + break; + } + } + + if (found == null) { + found = states[states.length - 1]; + } + + InputStream oldContents = null; + InputStream newContents = null; + try { + oldContents = found.getContents(); + newContents = file.getContents(); + } catch (CoreException ex) { + return; + } + + fPrevAst = parse(oldContents, cu); + fCurrentAst = parse(newContents, cu); + } + + /** + * Returns true + *

                    + *
                  • if the source of the given member has been changed, or + *
                  • if the element has been deleted, or + *
                  • if the element has been newly created + *
                  + * after the initial timestamp. + */ + public boolean hasChanged(String className, String methodName, String signature) { + if (!fHasHistory) { + return false; // optimistic: we have no history, so assume that + // member hasn't changed + } + if (fPrevAst == null || fCurrentAst == null) { + return true; // pessimistic: unable to build parse trees + } + MethodSearchVisitor visitor = new MethodSearchVisitor(); + MethodDeclaration prev = findMethod(fPrevAst, visitor, className, methodName, + signature); + if (prev != null) { + MethodDeclaration curr = findMethod(fCurrentAst, visitor, className, methodName, signature); + if (curr != null) { + return !getMatcher().match(prev, curr); + } + } + return true; + } + + private MethodDeclaration findMethod(CompilationUnit cu, + MethodSearchVisitor visitor, String className, String name, String signature) { + visitor.setTargetMethod(className, name, signature); + cu.accept(visitor); + return visitor.getMatch(); + } + + // ---- private stuff + // ---------------------------------------------------------------- + + /** + * Parses the given input stream and returns a tree of JavaNodes or a null + * in case of failure. + */ + private CompilationUnit parse(InputStream input, ICompilationUnit cu) { + char[] buffer = readString(input); + if (buffer != null) { + if (fParser == null) { + fParser = ASTParser.newParser(AST.getJLSLatest()); + } + fParser.setSource(buffer); + fParser.setProject(cu.getJavaProject()); + fParser.setResolveBindings(true); + fParser.setKind(ASTParser.K_COMPILATION_UNIT); + fParser.setUnitName(cu.getElementName()); + return (CompilationUnit) fParser.createAST(null); + } + return null; + } + + /** + * Returns an AST matcher + * + * @return AST matcher + */ + private ASTMatcher getMatcher() { + if (fMatcher == null) { + fMatcher = new ASTMatcher(); + } + return fMatcher; + } + + /** + * Returns null if an error occurred. + */ + private char[] readString(InputStream is) { + if (is == null) { + return null; + } + BufferedReader reader = null; + try { + StringBuilder buffer = new StringBuilder(); + char[] part = new char[2048]; + int read = 0; + reader = new BufferedReader(new InputStreamReader(is, + ResourcesPlugin.getEncoding())); + + while ((read = reader.read(part)) != -1) { + buffer.append(part, 0, read); + } + + char[] b = new char[buffer.length()]; + buffer.getChars(0, b.length, b, 0); + return b; + + } catch (IOException ex) { + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ex) { + } + } + } + return null; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JDIDebugHCRMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JDIDebugHCRMessages.java new file mode 100644 index 0000000000..fce97a5c42 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JDIDebugHCRMessages.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.hcr; + +import org.eclipse.osgi.util.NLS; + +public class JDIDebugHCRMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.core.hcr.JDIDebugHCRMessages";//$NON-NLS-1$ + public static String JavaHotCodeReplaceManager_Drop_to_frame_not_supported; + public static String JavaHotCodeReplaceManager_does_not_support_hcr; + public static String JavaHotCodeReplaceManager_exception_replacing_types; + public static String JavaHotCodeReplaceManager_hcr_failed; + public static String JavaHotCodeReplaceManager_hcr_ignored; + public static String JavaHotCodeReplaceManager_hcr_unsupported_redefinition; + public static String JavaHotCodeReplaceManager_hcr_unsupported_operation; + public static String JavaHotCodeReplaceManager_hcr_bad_bytes; + public static String JavaHotCodeReplaceManager_hcr_verify_error; + public static String JavaHotCodeReplaceManager_hcr_unsupported_class_version; + public static String JavaHotCodeReplaceManager_hcr_class_format_error; + public static String JavaHotCodeReplaceManager_hcr_class_circularity_error; + public static String JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__1; + public static String JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__2; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, JDIDebugHCRMessages.class); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JDIDebugHCRMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JDIDebugHCRMessages.properties new file mode 100644 index 0000000000..c9e4b8d2f3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JDIDebugHCRMessages.properties @@ -0,0 +1,27 @@ +############################################################################### +# Copyright (c) 2000, 2006 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +JavaHotCodeReplaceManager_Drop_to_frame_not_supported=Drop to frame not supported. +JavaHotCodeReplaceManager_does_not_support_hcr=VM does not support hot code replace. +JavaHotCodeReplaceManager_exception_replacing_types={0} occurred replacing types in VM. +JavaHotCodeReplaceManager_hcr_failed=Hot code replace failed - VM may be inconsistent +JavaHotCodeReplaceManager_hcr_ignored=Hot code replace ignored. +JavaHotCodeReplaceManager_hcr_unsupported_redefinition=Hot code replace failed - VM unable to perform requested redefinition +JavaHotCodeReplaceManager_hcr_unsupported_operation=Hot code replace failed - {0} +JavaHotCodeReplaceManager_hcr_bad_bytes=Hot code replace failed - new classfile name does not match reference type name +JavaHotCodeReplaceManager_hcr_verify_error=Hot code replace failed - verifier detected internal inconsistency or security problem +JavaHotCodeReplaceManager_hcr_unsupported_class_version=Hot code replace failed - class version number not supported by VM +JavaHotCodeReplaceManager_hcr_class_format_error=Hot code replace failed - class is not valid +JavaHotCodeReplaceManager_hcr_class_circularity_error=Hot code replace failed - circularity detected while initializing a class +JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__1=Hot code replace failed - VM disconnected. +JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__2=Hot code replace failed - VM disconnected. diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java new file mode 100644 index 0000000000..f93be200ee --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java @@ -0,0 +1,1447 @@ +/******************************************************************************* + * Copyright (c) 2000, 2016 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Yevgen Kogan - Bug 403475 - Hot Code Replace drops too much frames in some cases + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.hcr; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchListener; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaModelMarker; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.util.IClassFileReader; +import org.eclipse.jdt.core.util.ISourceAttribute; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.core.util.Util; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; + +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; + +/** + * The hot code replace manager listens for changes to class files and notifies + * running debug targets of the changes. + *

                  + * Currently, replacing .jar files has no effect on running targets. + */ +public class JavaHotCodeReplaceManager implements IResourceChangeListener, + ILaunchListener, IDebugEventSetListener { + /** + * Singleton + */ + private static JavaHotCodeReplaceManager fgInstance = null; + /** + * The class file extension + */ + private static final String CLASS_FILE_EXTENSION = "class"; //$NON-NLS-1$ + + /** + * The list of IJavaHotCodeReplaceListeners which this hot code + * replace manager will notify about hot code replace attempts. + */ + private ListenerList fHotCodeReplaceListeners = new ListenerList<>(); + + /** + * The lists of hot swap targets which support HCR and those which don't + */ + private final ArrayList fHotSwapTargets = new ArrayList<>(1); + private final ArrayList fNoHotSwapTargets = new ArrayList<>(1); + + /** + * A mapping of the last time projects were built. + *

                    + *
                  1. key: project (IProject)
                  2. + *
                  3. value: build date (ProjectBuildTime)
                  4. + *
                  + */ + private final Map fProjectBuildTimes = new HashMap<>(); + private static Date fStartupDate = new Date(); + + /** + * Cache of compilation unit deltas renewed on each HCR attempt. + */ + private final Map fDeltaCache = new HashMap<>(); + + /** + * Utility object used for tracking build times of projects. The HCR manager + * receives notification of builds AFTER the build has occurred but BEFORE + * the classfile resource changed deltas are fired. Thus, when the current + * build time is set, we need to hang onto the last build time so that we + * can use the last build time for comparing changes to compilation units + * (for smart drop to frame). + */ + class ProjectBuildTime { + private Date fCurrentDate = new Date(); + private Date fPreviousDate = new Date(); + + public void setCurrentBuildDate(Date date) { + fPreviousDate = fCurrentDate; + fCurrentDate = date; + } + + public void setLastBuildDate(Date date) { + fPreviousDate = date; + if (fPreviousDate.getTime() > fCurrentDate.getTime()) { + // If the previous date is set later than the current + // date, move the current date up to the previous. + fCurrentDate = fPreviousDate; + } + } + + /** + * Returns the last build time + */ + public Date getLastBuildDate() { + return fPreviousDate; + } + } + + /** + * Visitor for resource deltas. + */ + protected ChangedClassFilesVisitor fClassfileVisitor = new ChangedClassFilesVisitor(); + + /** + * Creates a new HCR manager + */ + private JavaHotCodeReplaceManager() { + } + + /** + * Returns the singleton HCR manager + */ + public static synchronized JavaHotCodeReplaceManager getDefault() { + if (fgInstance == null) { + fgInstance = new JavaHotCodeReplaceManager(); + } + return fgInstance; + } + + /** + * Registers this HCR manager as a resource change listener. This method is + * called by the JDI debug model plug-in on startup. + */ + public void startup() { + DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); + DebugPlugin.getDefault().addDebugEventListener(this); + } + + /** + * unregisters this HCR manager as a resource change listener. Removes all + * hot code replace listeners. This method is called by the JDI debug model + * plug-in on shutdown. + */ + public void shutdown() { + DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); + DebugPlugin.getDefault().removeDebugEventListener(this); + getWorkspace().removeResourceChangeListener(this); + fHotCodeReplaceListeners = new ListenerList<>(); + synchronized (this) { + fHotSwapTargets.clear(); + fNoHotSwapTargets.clear(); + } + } + + /** + * Returns the workspace. + */ + protected IWorkspace getWorkspace() { + return ResourcesPlugin.getWorkspace(); + } + + /** + * Returns the launch manager. + */ + protected ILaunchManager getLaunchManager() { + return DebugPlugin.getDefault().getLaunchManager(); + } + + /** + * @see IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) + */ + @Override + public void resourceChanged(IResourceChangeEvent event) { + List projects = getBuiltProjects(event); + if (!projects.isEmpty()) { + updateProjectBuildTime(projects); + } + synchronized (this) { + if (fHotSwapTargets.isEmpty() && fNoHotSwapTargets.isEmpty()) { + // If there are no targets to notify, only update the build + // times. + return; + } + } + ChangedClassFilesVisitor visitor = getChangedClassFiles(event); + if (visitor != null) { + List resources = visitor.getChangedClassFiles(); + List names = visitor.getQualifiedNamesList(); + if (!resources.isEmpty()) { + notifyTargets(resources, names); + } + } + } + + /** + * Returns all projects which this event says may have been built. + */ + protected List getBuiltProjects(IResourceChangeEvent event) { + IResourceDelta delta = event.getDelta(); + if (event.getType() != IResourceChangeEvent.POST_BUILD || delta == null + || event.getBuildKind() == 0) { + return Collections.EMPTY_LIST; + } + if (event.getBuildKind() == IncrementalProjectBuilder.AUTO_BUILD + && !ResourcesPlugin.getWorkspace().isAutoBuilding()) { + // If this is an auto build and the workspace is not autobuilding, + // no projects will actually be compiled. + return Collections.EMPTY_LIST; + } + Object source = event.getSource(); + if (source instanceof IProject) { + List list = new ArrayList<>(); + list.add((IProject) source); + return list; + } else if (source instanceof IWorkspace) { + IProject[] allProjects = ((IWorkspace) source).getRoot() + .getProjects(); + return Arrays.asList(allProjects); + } + return Collections.EMPTY_LIST; + } + + /** + * If the given event contains a build notification, update the last build + * time of the corresponding project + */ + private void updateProjectBuildTime(List projects) { + Date currentDate = new Date(); + ProjectBuildTime buildTime = null; + for(IProject project : projects) { + buildTime = fProjectBuildTimes.get(project); + if (buildTime == null) { + buildTime = new ProjectBuildTime(); + fProjectBuildTimes.put(project, buildTime); + } + buildTime.setCurrentBuildDate(currentDate); + } + } + + /** + * Returns the last known build time for the given project. If no build time + * is known for the given project, the last known build time for the project + * is set to the hot code replace manager's startup time. + */ + protected long getLastProjectBuildTime(IProject project) { + ProjectBuildTime time = fProjectBuildTimes + .get(project); + if (time == null) { + time = new ProjectBuildTime(); + time.setLastBuildDate(fStartupDate); + fProjectBuildTimes.put(project, time); + } + return time.getLastBuildDate().getTime(); + } + + /** + * Notifies the targets of the changed types + */ + private void notifyTargets(final List resources, final List qualifiedNames) { + final List hotSwapTargets = getHotSwapTargets(); + final List noHotSwapTargets = getNoHotSwapTargets(); + if (!hotSwapTargets.isEmpty()) { + Runnable runnable = () -> doHotCodeReplace(hotSwapTargets, resources, qualifiedNames); + DebugPlugin.getDefault().asyncExec(runnable); + } + if (!noHotSwapTargets.isEmpty()) { + Runnable runnable = () -> notifyUnsupportedHCR(noHotSwapTargets, resources, + qualifiedNames); + DebugPlugin.getDefault().asyncExec(runnable); + } + } + + /** + * Notify the given targets that HCR failed for classes with the given fully + * qualified names. + */ + protected void notifyUnsupportedHCR(List targets, List resources, + List qualifiedNames) { + Iterator iter = targets.iterator(); + JDIDebugTarget target = null; + while (iter.hasNext()) { + target = iter.next(); + if (target.isAvailable()) { + // Make a local copy of the resources/names to swap so we can + // filter + // unloaded types on a per-target basis. + List resourcesToReplace = new ArrayList<>(resources); + List qualifiedNamesToReplace = new ArrayList<>(qualifiedNames); + target.filterNotLoadedTypes(resourcesToReplace, qualifiedNamesToReplace); + + if (!qualifiedNamesToReplace.isEmpty()) { + // Don't notify if the changed types aren't loaded. + fireHCRFailed(target, null); + notifyFailedHCR(target, qualifiedNamesToReplace); + } + } else { + // Targets should be unregistered when they terminate, + // but this is a fall-back. + deregisterTarget(target); + } + } + } + + protected void notifyFailedHCR(JDIDebugTarget target, List qualifiedNames) { + if (target.isAvailable()) { + target.addOutOfSynchTypes(qualifiedNames); + target.fireChangeEvent(DebugEvent.STATE); + } + } + + /** + * Returns the currently registered debug targets that support hot code + * replace. + */ + protected synchronized List getHotSwapTargets() { + return new ArrayList<>(fHotSwapTargets); + } + + /** + * Returns the currently registered debug targets that do not support hot + * code replace. + */ + protected synchronized List getNoHotSwapTargets() { + return new ArrayList<>(fNoHotSwapTargets); + } + + /** + * Perform a hot code replace with the given resources. For a JDK 1.4 + * compliant VM this involves: + *
                    + *
                  1. Popping all frames from all thread stacks which will be affected by + * reloading the given resources
                  2. + *
                  3. Telling the VirtualMachine to redefine the affected classes
                  4. + *
                  5. Performing a step-into operation on all threads which were affected + * by the class redefinition. This returns execution to the first (deepest) + * affected method on the stack
                  6. + *
                  + * For a J9 compliant VM this involves: + *
                    + *
                  1. Telling the VirtualMachine to redefine the affected classes
                  2. + *
                  3. Popping all frames from all thread stacks which were affected by + * reloading the given resources and then performing a step-into operation + * on all threads which were affected by the class redefinition.
                  4. + *
                  + * + * @param targets + * the targets in which to perform HCR + * @param resources + * the resources which correspond to the changed classes + */ + private void doHotCodeReplace(List targets, List resources, + List qualifiedNames) { + + // Check whether hot code replace is enabled + if (!Platform.getPreferencesService().getBoolean( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.PREF_ENABLE_HCR, + true, + null)) { + return; // disabled + } + + MultiStatus ms = new MultiStatus( + JDIDebugPlugin.getUniqueIdentifier(), + DebugException.TARGET_REQUEST_FAILED, + "At least one target failed to drop to frame after successful hot code replace.", null); //$NON-NLS-1$ + Iterator iter = targets.iterator(); + while (iter.hasNext()) { + JDIDebugTarget target = iter.next(); + if (!target.isAvailable()) { + deregisterTarget(target); + continue; + } + if (!isHCREnabled(target)) { + continue; + } + // Make a local copy of the resources/names to swap so we can filter + // unloaded types on a per-target basis. + List resourcesToReplace = new ArrayList<>(resources); + List qualifiedNamesToReplace = new ArrayList<>(qualifiedNames); + + // Make sure we only try to replace types from related projects + target.filterUnrelatedResources(resourcesToReplace, qualifiedNamesToReplace); + if (qualifiedNamesToReplace.isEmpty()) { + // If none of the changed types are related to our target, do nothing. + continue; + } + + target.filterNotLoadedTypes(resourcesToReplace, qualifiedNamesToReplace); + if (qualifiedNamesToReplace.isEmpty()) { + // If none of the changed types are loaded, do nothing. + continue; + } + + List poppedThreads = new ArrayList<>(); + target.setIsPerformingHotCodeReplace(true); + try { + boolean framesPopped = false; + if (target.canPopFrames()) { + // JDK 1.4 drop to frame support: + // JDK 1.4 spec is faulty around methods that have + // been rendered obsolete after class redefinition. + // Thus, pop the frames that contain affected methods + // *before* the class redefinition to avoid problems. + try { + attemptPopFrames(target, resourcesToReplace, + qualifiedNamesToReplace, poppedThreads); + framesPopped = true; // No exception occurred + } catch (DebugException de) { + if (shouldLogHCRException(de)) { + ms.merge(de.getStatus()); + } + } + } + target.removeOutOfSynchTypes(qualifiedNamesToReplace); + if (target.supportsJDKHotCodeReplace()) { + redefineTypesJDK(target, resourcesToReplace, + qualifiedNamesToReplace); + } else if (target.supportsJ9HotCodeReplace()) { + redefineTypesJ9(target, qualifiedNamesToReplace); + } + if (containsObsoleteMethods(target)) { + fireObsoleteMethods(target); + } + try { + if (target.canPopFrames() && framesPopped) { + // Second half of JDK 1.4 drop to frame support: + // All affected frames have been popped and the classes + // have been reloaded. Step into the first changed + // frame of each affected thread. + // must re-set 'is doing HCR' to be able to step + target.setIsPerformingHotCodeReplace(false); + attemptStepIn(poppedThreads); + } else { + // J9 drop to frame support: + // After redefining classes, drop to frame + attemptDropToFrame(target, resourcesToReplace, + qualifiedNamesToReplace); + } + } catch (DebugException de) { + if (shouldLogHCRException(de)) { + ms.merge(de.getStatus()); + } + } + fireHCRSucceeded(target); + } catch (DebugException de) { + // target update failed + fireHCRFailed(target, de); + } + // also re-set 'is doing HCR' here in case HCR failed + target.setIsPerformingHotCodeReplace(false); + target.fireChangeEvent(DebugEvent.CONTENT); + } + if (!ms.isOK()) { + JDIDebugPlugin.log(ms); + } + fDeltaCache.clear(); + } + + private boolean isHCREnabled(JDIDebugTarget target) { + ILaunch l = target.getLaunch(); + if (l != null) { + boolean disabledByLaunch = "true".equals(l.getAttribute(JDIDebugModel.DISABLE_HCR_LAUNCH_ATTRIBUTE)); //$NON-NLS-1$ + return !disabledByLaunch; + } + return false; + } + + /** + * Returns whether the given exception, which occurred during HCR, should be + * logged. We anticipate that we can get IncompatibleThreadStateExceptions + * if the user happens to resume a thread at just the right moment. Since + * this has no ill effects for HCR, we don't log these exceptions. + */ + private boolean shouldLogHCRException(DebugException exception) { + return !(exception.getStatus().getException() instanceof IncompatibleThreadStateException + || exception.getStatus().getCode() == IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE || exception + .getStatus().getCode() == IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } + + /** + * Replaces the given types in the given J9 debug target. A fully qualified + * name of each type must be supplied. + * + * Breakpoints are reinstalled automatically when the new types are loaded. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                    + *
                  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                  • + *
                  • The target VM was unable to reload a type due to a + * shape change
                  • + *
                  + */ + private void redefineTypesJ9(JDIDebugTarget target, List qualifiedNames) + throws DebugException { + String[] typeNames = qualifiedNames + .toArray(new String[qualifiedNames.size()]); + if (target.supportsJ9HotCodeReplace()) { + target.setHCROccurred(true); + org.eclipse.jdi.hcr.VirtualMachine vm = (org.eclipse.jdi.hcr.VirtualMachine) target + .getVM(); + if (vm == null) { + target.requestFailed( + JDIDebugHCRMessages.JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__1, + new VMDisconnectedException()); + } + int result = org.eclipse.jdi.hcr.VirtualMachine.RELOAD_FAILURE; + try { + result = vm.classesHaveChanged(typeNames); + } catch (RuntimeException e) { + target.targetRequestFailed( + MessageFormat.format(JDIDebugHCRMessages.JavaHotCodeReplaceManager_exception_replacing_types, e.toString()), + e); + } + switch (result) { + case org.eclipse.jdi.hcr.VirtualMachine.RELOAD_SUCCESS: + break; + case org.eclipse.jdi.hcr.VirtualMachine.RELOAD_IGNORED: + target.targetRequestFailed( + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_ignored, + null); + break; + case org.eclipse.jdi.hcr.VirtualMachine.RELOAD_FAILURE: + target.targetRequestFailed( + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_failed, + null); + target.addOutOfSynchTypes(qualifiedNames); + break; + } + } else { + target.notSupported(JDIDebugHCRMessages.JavaHotCodeReplaceManager_does_not_support_hcr); + target.addOutOfSynchTypes(qualifiedNames); + } + } + + /** + * Replaces the given types in the given JDK-compliant debug target. + * + * This method is to be used for JDK hot code replace. + */ + private void redefineTypesJDK(JDIDebugTarget target, List resources, + List qualifiedNames) throws DebugException { + if (target.supportsJDKHotCodeReplace()) { + target.setHCROccurred(true); + Map typesToBytes = getTypesToBytes(target, resources, + qualifiedNames); + try { + VirtualMachine vm = target.getVM(); + if (vm == null) { + target.requestFailed( + JDIDebugHCRMessages.JavaHotCodeReplaceManager_Hot_code_replace_failed___VM_disconnected__2, + new VMDisconnectedException()); + } + vm.redefineClasses(typesToBytes); + } catch (UnsupportedOperationException exception) { + String detail = exception.getMessage(); + if (detail != null) { + redefineTypesFailedJDK( + target, + qualifiedNames, + MessageFormat.format( + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_unsupported_operation, + detail), + exception); + } else { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_unsupported_redefinition, + exception); + } + } catch (NoClassDefFoundError exception) { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_bad_bytes, + exception); + } catch (VerifyError exception) { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_verify_error, + exception); + } catch (UnsupportedClassVersionError exception) { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_unsupported_class_version, + exception); + } catch (ClassFormatError exception) { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_class_format_error, + exception); + } catch (ClassCircularityError exception) { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_class_circularity_error, + exception); + } catch (RuntimeException exception) { + redefineTypesFailedJDK( + target, + qualifiedNames, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_hcr_failed, + exception); + } + target.reinstallBreakpointsIn(resources, qualifiedNames); + } else { + target.notSupported(JDIDebugHCRMessages.JavaHotCodeReplaceManager_does_not_support_hcr); + } + } + + /** + * Error handling for JDK hot code replace. + * + * The given exception occurred when redefinition was attempted for the + * given types. + */ + private void redefineTypesFailedJDK(JDIDebugTarget target, + List qualifiedNames, String message, Throwable exception) + throws DebugException { + target.addOutOfSynchTypes(qualifiedNames); + target.jdiRequestFailed(message, exception); + } + + /** + * Returns a mapping of class files to the bytes that make up those class + * files. + * + * @param target + * the debug target to query + * @param resources + * the classfiles + * @param qualifiedNames + * the fully qualified type names corresponding to the + * classfiles. The typeNames correspond to the resources on a + * one-to-one basis. + * @return a mapping of class files to bytes key: class file value: the + * bytes which make up that classfile + */ + private Map getTypesToBytes(JDIDebugTarget target, List resources, + List qualifiedNames) { + Map typesToBytes = new HashMap<>(resources.size()); + Iterator resourceIter = resources.iterator(); + Iterator nameIter = qualifiedNames.iterator(); + IResource resource; + String name; + while (resourceIter.hasNext()) { + resource = resourceIter.next(); + name = nameIter.next(); + List classes = target.jdiClassesByName(name); + byte[] bytes = null; + try { + bytes = Util.getResourceContentsAsByteArray((IFile) resource); + } catch (JavaModelException jme) { + continue; + } + for(ReferenceType type : classes) { + typesToBytes.put(type, bytes); + } + } + return typesToBytes; + } + + /** + * Return the listeners to notify for the given target. Target specific + * listeners take precedence over generic listeners registered with the + * debug model plug-in. + * + * @param target + * Java debug target + * @return hot code replace listeners + */ + private ListenerList getHotCodeReplaceListeners(IJavaDebugTarget target) { + ListenerList listeners = null; + if (target instanceof JDIDebugTarget) { + listeners = ((JDIDebugTarget) target).getHotCodeReplaceListeners(); + } + if (listeners == null || listeners.size() == 0) { + listeners = fHotCodeReplaceListeners; + } + return listeners; + } + + /** + * Notifies listeners that a hot code replace attempt succeeded + */ + private void fireHCRSucceeded(IJavaDebugTarget target) { + ListenerList listeners = getHotCodeReplaceListeners(target); + for (IJavaHotCodeReplaceListener listener : listeners) { + listener.hotCodeReplaceSucceeded(target); + } + } + + /** + * Notifies listeners that a hot code replace attempt failed with the given + * exception + */ + private void fireHCRFailed(JDIDebugTarget target, DebugException exception) { + ListenerList listeners = getHotCodeReplaceListeners(target); + for (IJavaHotCodeReplaceListener listener : listeners) { + listener.hotCodeReplaceFailed(target, exception); + } + } + + /** + * Notifies listeners that obsolete methods remain on the stack + */ + private void fireObsoleteMethods(JDIDebugTarget target) { + ListenerList listeners = getHotCodeReplaceListeners(target); + for (IJavaHotCodeReplaceListener listener : listeners) { + listener.obsoleteMethods(target); + } + } + + /** + * Looks for the deepest affected stack frame in the stack and forces a drop + * to frame. Does this for all of the active stack frames in the target. + * + * @param target + * the debug target in which frames are to be dropped + * @param replacedClassNames + * the classes that have been redefined + */ + protected void attemptDropToFrame(JDIDebugTarget target, List resources, + List replacedClassNames) throws DebugException { + List dropFrames = getAffectedFrames(target.getThreads(), resources, + replacedClassNames); + + // All threads that want to drop to frame are able. Proceed with the + // drop + JDIStackFrame dropFrame = null; + Iterator iter = dropFrames.iterator(); + while (iter.hasNext()) { + try { + dropFrame = iter.next(); + dropFrame.dropToFrame(); + } catch (DebugException de) { + notifyFailedDrop( + ((JDIThread) dropFrame.getThread()) + .computeStackFrames(), + replacedClassNames); + } + } + } + + /** + * Looks for the deepest affected stack frame in the stack and forces a drop + * to frame. Does this for all of the active stack frames in the target. + * + * @param target + * the debug target in which frames are to be dropped + * @param replacedClassNames + * the classes that have been redefined + * @param poppedThreads + * a list of the threads in which frames were popped.This + * parameter may have entries added by this method + */ + protected void attemptPopFrames(JDIDebugTarget target, List resources, + List replacedClassNames, List poppedThreads) throws DebugException { + List popFrames = getAffectedFrames(target.getThreads(), resources, + replacedClassNames); + + // All threads that want to drop to frame are able. Proceed with the + // drop + JDIStackFrame popFrame = null; + Iterator iter = popFrames.iterator(); + while (iter.hasNext()) { + try { + popFrame = iter.next(); + popFrame.popFrame(); + poppedThreads.add(popFrame.getThread()); + } catch (DebugException de) { + poppedThreads.remove(popFrame.getThread()); + notifyFailedDrop( + ((JDIThread) popFrame.getThread()).computeStackFrames(), + replacedClassNames); + } + } + } + + /** + * Returns whether or not the given target contains stack frames with + * obsolete methods. + */ + protected boolean containsObsoleteMethods(JDIDebugTarget target) + throws DebugException { + IThread[] threads = target.getThreads(); + List frames = null; + for (IThread thread : threads) { + frames = ((JDIThread) thread).computeNewStackFrames(); + for(IJavaStackFrame frame : frames) { + if(frame.isObsolete()) { + return true; + } + } + } + return false; + } + + /** + * Returns a list of frames which should be popped in the given threads. + */ + protected List getAffectedFrames(IThread[] threads, List resourceList, + List replacedClassNames) throws DebugException { + JDIThread thread = null; + JDIStackFrame affectedFrame = null; + List popFrames = new ArrayList<>(); + int numThreads = threads.length; + IResource[] resources = new IResource[resourceList.size()]; + resourceList.toArray(resources); + for (int i = 0; i < numThreads; i++) { + thread = (JDIThread) threads[i]; + if (thread.isSuspended()) { + affectedFrame = getAffectedFrame(thread, replacedClassNames); + if (affectedFrame == null) { + // No frame to drop to in this thread + continue; + } + if (affectedFrame.supportsDropToFrame()) { + popFrames.add(affectedFrame); + } else { + // if any thread that should drop does not support the drop, + // do not drop in any threads. + for (int j = 0; j < numThreads; j++) { + notifyFailedDrop( + ((JDIThread) threads[i]).computeStackFrames(), + replacedClassNames); + } + throw new DebugException( + new Status( + IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.NOT_SUPPORTED, + JDIDebugHCRMessages.JavaHotCodeReplaceManager_Drop_to_frame_not_supported, + null)); + } + } + } + return popFrames; + } + + /** + * Returns the stack frame that should be dropped to in the given thread + * after a hot code replace. This is calculated by determining if the + * threads contain stack frames that reside in one of the given replaced + * class names. If possible, only stack frames whose methods were directly + * affected (and not simply all frames in affected types) will be returned. + */ + protected JDIStackFrame getAffectedFrame(JDIThread thread, + List replacedClassNames) throws DebugException { + List frames = thread.computeStackFrames(); + JDIStackFrame affectedFrame = null; + JDIStackFrame frame = null; + ICompilationUnit compilationUnit = null; + CompilationUnitDelta delta = null; + IProject project = null; + for (int j = 0; j < frames.size(); j++) { + frame = (JDIStackFrame) frames.get(j); + if (containsChangedType(frame, replacedClassNames)) { + // smart drop to frame support + compilationUnit = getCompilationUnit(frame); + // if we can't find the source, then do type-based drop + if (compilationUnit != null) { + try { + project = compilationUnit.getCorrespondingResource() + .getProject(); + delta = getDelta(compilationUnit, + getLastProjectBuildTime(project)); + + String typeName = frame.getDeclaringTypeName(); + typeName = typeName.replace('$', '.'); + + if (!delta.hasChanged(typeName, frame.getName(), + frame.getSignature())) { + continue; + } + } catch (CoreException exception) { + // If smart drop to frame fails, just do type-based drop + } + } + + if (frame.supportsDropToFrame()) { + affectedFrame = frame; + break; + } + // The frame we wanted to drop to cannot be popped. + // Set the affected frame to the next lowest pop-able + // frame on the stack. + while (j > 0) { + j--; + frame = (JDIStackFrame) frames.get(j); + if (frame.supportsDropToFrame()) { + affectedFrame = frame; + break; + } + } + break; + } + } + return affectedFrame; + } + + /** + * Returns the delta object for the given compilation unit + * + * @param cu + * compilation unit + * @param time + * time to compare to (i.e. compare to first version before this + * time) + * @return delta object + */ + private CompilationUnitDelta getDelta(ICompilationUnit cu, long time) + throws CoreException { + CompilationUnitDelta delta = fDeltaCache.get(cu); + if (delta == null) { + delta = new CompilationUnitDelta(cu, time); + fDeltaCache.put(cu, delta); + } + return delta; + } + + /** + * Returns whether the given frame's declaring type was changed based on the + * given list of changed class names. + */ + protected boolean containsChangedType(JDIStackFrame frame, + List replacedClassNames) throws DebugException { + String declaringTypeName = frame.getDeclaringTypeName(); + // Check if the frame's declaring type was changed + if (replacedClassNames.contains(declaringTypeName)) { + return true; + } + // Check if one of the frame's declaring type's inner classes have + // changed + Iterator iter = replacedClassNames.iterator(); + int index; + String className = null; + while (iter.hasNext()) { + className = iter.next(); + index = className.indexOf('$'); + if (index > -1 + && declaringTypeName.equals(className.substring(0, index))) { + return true; + } + } + return false; + } + + /** + * Performs a "step into" operation on the given threads. + */ + protected void attemptStepIn(List threads) throws DebugException { + Iterator iter = threads.iterator(); + while (iter.hasNext()) { + ((JDIThread) iter.next()).stepInto(); + } + } + + /** + * Returns the compilation unit associated with this Java stack frame. + * Returns null for a binary stack frame. + */ + protected ICompilationUnit getCompilationUnit(IJavaStackFrame frame) { + ILaunch launch = frame.getLaunch(); + if (launch == null) { + return null; + } + try { + IJavaElement sourceElement = JavaDebugUtils.resolveJavaElement(frame, launch); + if (sourceElement instanceof IType) { + return ((IType) sourceElement).getCompilationUnit(); + } + if (sourceElement instanceof ICompilationUnit) { + return (ICompilationUnit) sourceElement; + } + return null; + } + catch (CoreException e) { + return null; + } + } + + /** + * Returns the method in which this stack frame is suspended or + * null if none can be found + */ + public IMethod getMethod(JDIStackFrame frame, ICompilationUnit unit) + throws CoreException { + String declaringTypeName = frame.getDeclaringTypeName(); + String methodName = frame.getMethodName(); + String[] arguments = null; + try { + arguments = Signature.getParameterTypes(frame.getSignature()); + } catch (IllegalArgumentException exception) { + // If Signature can't parse the signature, we can't + // create the method + return null; + } + String typeName = getUnqualifiedName(declaringTypeName); + int index = typeName.indexOf('$'); + IType type = null; + if (index > 0) { + String remaining = typeName.substring(index + 1); + typeName = typeName.substring(0, index); + type = unit.getType(typeName); + while (remaining != null) { + index = remaining.indexOf('$'); + if (index > 0) { + typeName = remaining.substring(0, index); + remaining = remaining.substring(index + 1); + } else { + typeName = remaining; + remaining = null; + } + type = type.getType(typeName); + } + } else { + type = unit.getType(typeName); + } + if (type != null) { + return type.getMethod(methodName, arguments); + } + return null; + } + + /** + * Given a fully qualified name, return the unqualified name. + */ + protected String getUnqualifiedName(String qualifiedName) { + int index = qualifiedName.lastIndexOf('.'); + return qualifiedName.substring(index + 1); + } + + /** + * Notify the given frames that a drop to frame has failed after an HCR with + * the given class names. + */ + private void notifyFailedDrop(List frames, List replacedClassNames) + throws DebugException { + for(IJavaStackFrame frame : frames) { + if (replacedClassNames.contains(frame.getDeclaringTypeName())) { + ((JDIStackFrame)frame).setOutOfSynch(true); + } + } + } + + /** + * Returns the class file visitor after visiting the resource change. The + * visitor contains the changed class files and qualified type names. + * Returns null if the visitor encounters an exception, or the + * delta is not a POST_BUILD. + */ + protected ChangedClassFilesVisitor getChangedClassFiles( + IResourceChangeEvent event) { + IResourceDelta delta = event.getDelta(); + if (event.getType() != IResourceChangeEvent.POST_BUILD || delta == null) { + return null; + } + fClassfileVisitor.reset(); + try { + delta.accept(fClassfileVisitor); + } catch (CoreException e) { + JDIDebugPlugin.log(e); + return null; // quiet failure + } + return fClassfileVisitor; + } + + /** + * A visitor which collects changed class files. + */ + class ChangedClassFilesVisitor implements IResourceDeltaVisitor { + /** + * The collection of changed class files. + */ + protected List fFiles = null; + + /** + * Collection of qualified type names, corresponding to class files. + */ + protected List fNames = null; + + /** + * Answers whether children should be visited. + *

                  + * If the associated resource is a class file which has been changed, + * record it. + */ + @Override + public boolean visit(IResourceDelta delta) { + if (delta == null + || 0 == (delta.getKind() & IResourceDelta.CHANGED)) { + return false; + } + IResource resource = delta.getResource(); + if (resource != null) { + switch (resource.getType()) { + case IResource.FILE: + if (0 == (delta.getFlags() & IResourceDelta.CONTENT)) { + return false; + } + if (CLASS_FILE_EXTENSION.equals(resource.getFullPath() + .getFileExtension())) { + IPath localLocation = resource.getLocation(); + if (localLocation != null) { + String path = localLocation.toOSString(); + IClassFileReader reader = ToolFactory + .createDefaultClassFileReader( + path, + IClassFileReader.CLASSFILE_ATTRIBUTES); + if (reader != null) { + // this name is slash-delimited + String qualifiedName = new String( + reader.getClassName()); + boolean hasBlockingErrors = false; + try { + if (!Platform.getPreferencesService().getBoolean( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, + true, + null)) { + // If the user doesn't want to replace + // classfiles containing + // compilation errors, get the source + // file associated with + // the class file and query it for + // compilation errors + IJavaProject pro = JavaCore + .create(resource.getProject()); + ISourceAttribute sourceAttribute = reader + .getSourceFileAttribute(); + String sourceName = null; + if (sourceAttribute != null) { + sourceName = new String( + sourceAttribute + .getSourceFileName()); + } + IResource sourceFile = getSourceFile( + pro, qualifiedName, sourceName); + if (sourceFile != null) { + IMarker[] problemMarkers = null; + problemMarkers = sourceFile + .findMarkers( + IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, + true, + IResource.DEPTH_INFINITE); + for (IMarker problemMarker : problemMarkers) { + if (problemMarker.getAttribute( + IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR) { + hasBlockingErrors = true; + break; + } + } + } + } + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + if (!hasBlockingErrors) { + fFiles.add(resource); + // dot-delimit the name + fNames.add(qualifiedName.replace('/', '.')); + } + } + } + } + return false; + + default: + return true; + } + } + return true; + } + + /** + * Resets the file collection to empty + */ + public void reset() { + fFiles = new ArrayList<>(); + fNames = new ArrayList<>(); + } + + /** + * Answers a collection of changed class files or null + */ + public List getChangedClassFiles() { + return fFiles; + } + + /** + * Returns a collection of qualified type names corresponding to the + * changed class files. + * + * @return List + */ + public List getQualifiedNamesList() { + return fNames; + } + + /** + * Returns the source file associated with the given type, or + * null if no source file could be found. + * + * @param project + * the java project containing the classfile + * @param qualifiedName + * fully qualified name of the type, slash delimited + * @param sourceAttribute + * debug source attribute, or null if none + */ + private IResource getSourceFile(IJavaProject project, + String qualifiedName, String sourceAttribute) { + String name = null; + IJavaElement element = null; + try { + if (sourceAttribute == null) { + element = JavaDebugUtils + .findElement(qualifiedName, project); + } else { + int i = qualifiedName.lastIndexOf('/'); + if (i > 0) { + name = qualifiedName.substring(0, i + 1); + name = name + sourceAttribute; + } else { + name = sourceAttribute; + } + element = project.findElement(new Path(name)); + } + if (element instanceof ICompilationUnit) { + ICompilationUnit cu = (ICompilationUnit) element; + return cu.getCorrespondingResource(); + } + } catch (CoreException e) { + } + return null; + } + } + + /** + * Adds the given listener to the collection of hot code replace listeners. + * Listeners are notified when hot code replace attempts succeed or fail. + */ + public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) { + fHotCodeReplaceListeners.add(listener); + } + + /** + * Removes the given listener from the collection of hot code replace + * listeners. Once a listener is removed, it will no longer be notified of + * hot code replace attempt successes or failures. + */ + public void removeHotCodeReplaceListener( + IJavaHotCodeReplaceListener listener) { + fHotCodeReplaceListeners.remove(listener); + } + + /** + * @see ILaunchListener#launchRemoved(ILaunch) + */ + @Override + public void launchRemoved(ILaunch launch) { + IDebugTarget[] debugTargets = launch.getDebugTargets(); + for (IDebugTarget debugTarget : debugTargets) { + IJavaDebugTarget jt = debugTarget + .getAdapter(IJavaDebugTarget.class); + if (jt != null) { + deregisterTarget((JDIDebugTarget) jt); + } + } + } + + /** + * Begin listening for resource changes when a launch is registered with a + * hot swap-able target. + * + * @see org.eclipse.debug.core.ILaunchListener#launchAdded(org.eclipse.debug.core.ILaunch) + */ + @Override + public void launchAdded(ILaunch launch) { + IDebugTarget[] debugTargets = launch.getDebugTargets(); + for (IDebugTarget debugTarget : debugTargets) { + IJavaDebugTarget jt = debugTarget + .getAdapter(IJavaDebugTarget.class); + if (jt != null) { + JDIDebugTarget target = (JDIDebugTarget) jt; + if (target.supportsHotCodeReplace()) { + addHotSwapTarget(target); + } else if (target.isAvailable()) { + addNonHotSwapTarget(target); + } + } + } + synchronized (this) { + if (!fHotSwapTargets.isEmpty() || !fNoHotSwapTargets.isEmpty()) { + getWorkspace().addResourceChangeListener(this, + IResourceChangeEvent.POST_BUILD); + } + } + } + + /** + * Begin listening for resource changes when a launch is registered with a + * hot swap-able target. + * + * @see ILaunchListener#launchChanged(ILaunch) + */ + @Override + public void launchChanged(ILaunch launch) { + launchAdded(launch); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse + * .debug.core.DebugEvent[]) + */ + @Override + public void handleDebugEvents(DebugEvent[] events) { + for (DebugEvent event : events) { + if (event.getKind() == DebugEvent.TERMINATE) { + Object source = event.getSource(); + if (source instanceof IAdaptable + && source instanceof IDebugTarget) { + IJavaDebugTarget jt = ((IAdaptable) source) + .getAdapter(IJavaDebugTarget.class); + if (jt != null) { + deregisterTarget((JDIDebugTarget) jt); + } + } + } + } + } + + protected void deregisterTarget(JDIDebugTarget target) { + // Remove the target from its hot swap target cache. + if (!fHotSwapTargets.remove(target)) { + fNoHotSwapTargets.remove(target); + } + ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager() + .getLaunches(); + // If there are no more active JDIDebugTargets, stop + // listening to resource changes. + for (ILaunch launche : launches) { + IDebugTarget[] targets = launche.getDebugTargets(); + for (IDebugTarget debugTarget : targets) { + IJavaDebugTarget jt = debugTarget + .getAdapter(IJavaDebugTarget.class); + if (jt != null) { + if (((JDIDebugTarget) jt).isAvailable()) { + return; + } + } + } + } + } + + /** + * Adds the given target to the list of hot-swap-able targets. Has no effect + * if the target is already registered. + * + * @param target + * a target that supports hot swap + */ + protected synchronized void addHotSwapTarget(JDIDebugTarget target) { + if (!fHotSwapTargets.contains(target)) { + fHotSwapTargets.add(target); + } + } + + /** + * Adds the given target to the list of non hot-swap-able targets. Has no + * effect if the target is already registered. + * + * @param target + * a target that does not support hot swap + */ + protected synchronized void addNonHotSwapTarget(JDIDebugTarget target) { + if (!fNoHotSwapTargets.contains(target)) { + fNoHotSwapTargets.add(target); + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/MethodSearchVisitor.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/MethodSearchVisitor.java new file mode 100644 index 0000000000..e26a95b03a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/MethodSearchVisitor.java @@ -0,0 +1,639 @@ +/******************************************************************************* + * Copyright (c) 2000, 2014 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Yevgen Kogan - Bug 403475 - Hot Code Replace drops too much frames in some cases + * Jacob Saoumi - Bug 434695 - Hot Code Replace drops some frames in case of anonymous classes + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.hcr; + +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; +import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.ArrayAccess; +import org.eclipse.jdt.core.dom.ArrayCreation; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.AssertStatement; +import org.eclipse.jdt.core.dom.Assignment; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BlockComment; +import org.eclipse.jdt.core.dom.BooleanLiteral; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.CastExpression; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.CharacterLiteral; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ConditionalExpression; +import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EmptyStatement; +import org.eclipse.jdt.core.dom.EnhancedForStatement; +import org.eclipse.jdt.core.dom.EnumConstantDeclaration; +import org.eclipse.jdt.core.dom.EnumDeclaration; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.FieldAccess; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.InstanceofExpression; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.LabeledStatement; +import org.eclipse.jdt.core.dom.LineComment; +import org.eclipse.jdt.core.dom.MarkerAnnotation; +import org.eclipse.jdt.core.dom.MemberRef; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.MethodRef; +import org.eclipse.jdt.core.dom.MethodRefParameter; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.NullLiteral; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.ParenthesizedExpression; +import org.eclipse.jdt.core.dom.PostfixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.QualifiedType; +import org.eclipse.jdt.core.dom.ReturnStatement; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SimpleType; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; +import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SwitchCase; +import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.TagElement; +import org.eclipse.jdt.core.dom.TextBlock; +import org.eclipse.jdt.core.dom.TextElement; +import org.eclipse.jdt.core.dom.ThisExpression; +import org.eclipse.jdt.core.dom.ThrowStatement; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.TypeLiteral; +import org.eclipse.jdt.core.dom.TypeParameter; +import org.eclipse.jdt.core.dom.UnionType; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; +import org.eclipse.jdt.core.dom.WildcardType; + +/** + * Visits an AST to find a method declaration + */ +public class MethodSearchVisitor extends ASTVisitor { + + /** + * Class the method belongs to + */ + private String fClassName; + /** + * Method to search for + */ + private String fName; + private String[] fParameterTypes; + + /** + * The search result, or null if none + */ + private MethodDeclaration fMatch; + + /** + * Sets the signature of the method to search for + * + * @param methodName + * name of method to search for + * @param methodSignature + * signature of the method to search for + */ + public void setTargetMethod(String className, String methodName, String methodSignature) { + fClassName = className; + fName = methodName; + fParameterTypes = Signature.getParameterTypes(methodSignature); + // convert parameter types same format that we get from the AST type + // bindings + for (int i = 0; i < fParameterTypes.length; i++) { + String type = fParameterTypes[i]; + type = type.replace('/', '.'); + fParameterTypes[i] = type; + } + fMatch = null; + } + + /** + * Returns the search result, or null if none + * + * @return matching method declartion or null + */ + public MethodDeclaration getMatch() { + return fMatch; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MethodDeclaration) + */ + @Override + public boolean visit(MethodDeclaration node) { + ITypeBinding binding = null; + IMethodBinding mbinding = node.resolveBinding(); + if(mbinding != null) { + binding = mbinding.getDeclaringClass(); + } + else { + ASTNode parent = node.getParent(); + if(parent instanceof AbstractTypeDeclaration) { + binding = ((AbstractTypeDeclaration) parent).resolveBinding(); + } + else if(parent instanceof AnonymousClassDeclaration) { + binding = ((AnonymousClassDeclaration) parent).resolveBinding(); + } + } + String typeName = null; + if (binding != null) { + typeName = binding.getQualifiedName(); + if ((typeName == null || "".equals(typeName)) && binding.getBinaryName() != null) { //$NON-NLS-1$ + typeName = binding.getBinaryName().replace('$', '.'); + } + } + // if no binding exists, the behaviour should be the same as without checking for type name + if (node.getName().getIdentifier().equals(fName) && (typeName == null || typeName.equals(fClassName))) { + IMethodBinding methodBinding = node.resolveBinding(); + if (methodBinding != null) { + ITypeBinding[] typeBindings = methodBinding.getParameterTypes(); + if (typeBindings.length == fParameterTypes.length) { + for (int i = 0; i < typeBindings.length; i++) { + ITypeBinding typeBinding = typeBindings[i]; + String typeSignature = Signature.createTypeSignature( + typeBinding.getQualifiedName(), true); + if (!fParameterTypes[i].equals(typeSignature)) { + return true; + } + } + fMatch = node; + } + } + } + return isSearching(); + } + + /** + * Returns whether this visitor is still searching for a match. + * + * @return whether this visitor is still searching for a match + */ + private boolean isSearching() { + return fMatch == null; + } + + @Override + public boolean visit(AnnotationTypeDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(AnnotationTypeMemberDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(AnonymousClassDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(ArrayAccess node) { + return isSearching(); + } + + @Override + public boolean visit(ArrayCreation node) { + return isSearching(); + } + + @Override + public boolean visit(ArrayInitializer node) { + return isSearching(); + } + + @Override + public boolean visit(ArrayType node) { + return isSearching(); + } + + @Override + public boolean visit(AssertStatement node) { + return isSearching(); + } + + @Override + public boolean visit(Assignment node) { + return isSearching(); + } + + @Override + public boolean visit(Block node) { + return isSearching(); + } + + @Override + public boolean visit(BlockComment node) { + return isSearching(); + } + + @Override + public boolean visit(BooleanLiteral node) { + return isSearching(); + } + + @Override + public boolean visit(BreakStatement node) { + return isSearching(); + } + + @Override + public boolean visit(CastExpression node) { + return isSearching(); + } + + @Override + public boolean visit(CatchClause node) { + return isSearching(); + } + + @Override + public boolean visit(CharacterLiteral node) { + return isSearching(); + } + + @Override + public boolean visit(ClassInstanceCreation node) { + return isSearching(); + } + + @Override + public boolean visit(CompilationUnit node) { + return isSearching(); + } + + @Override + public boolean visit(ConditionalExpression node) { + return isSearching(); + } + + @Override + public boolean visit(ConstructorInvocation node) { + return isSearching(); + } + + @Override + public boolean visit(ContinueStatement node) { + return isSearching(); + } + + @Override + public boolean visit(DoStatement node) { + return isSearching(); + } + + @Override + public boolean visit(EmptyStatement node) { + return isSearching(); + } + + @Override + public boolean visit(EnhancedForStatement node) { + return isSearching(); + } + + @Override + public boolean visit(EnumConstantDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(EnumDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(ExpressionStatement node) { + return isSearching(); + } + + @Override + public boolean visit(FieldAccess node) { + return isSearching(); + } + + @Override + public boolean visit(FieldDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(ForStatement node) { + return isSearching(); + } + + @Override + public boolean visit(IfStatement node) { + return isSearching(); + } + + @Override + public boolean visit(ImportDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(InfixExpression node) { + return isSearching(); + } + + @Override + public boolean visit(Initializer node) { + return isSearching(); + } + + @Override + public boolean visit(InstanceofExpression node) { + return isSearching(); + } + + @Override + public boolean visit(Javadoc node) { + return isSearching(); + } + + @Override + public boolean visit(LabeledStatement node) { + return isSearching(); + } + + @Override + public boolean visit(LineComment node) { + return isSearching(); + } + + @Override + public boolean visit(MarkerAnnotation node) { + return isSearching(); + } + + @Override + public boolean visit(MemberRef node) { + return isSearching(); + } + + @Override + public boolean visit(MemberValuePair node) { + return isSearching(); + } + + @Override + public boolean visit(MethodInvocation node) { + return isSearching(); + } + + @Override + public boolean visit(MethodRef node) { + return isSearching(); + } + + @Override + public boolean visit(MethodRefParameter node) { + return isSearching(); + } + + @Override + public boolean visit(Modifier node) { + return isSearching(); + } + + @Override + public boolean visit(NormalAnnotation node) { + return isSearching(); + } + + @Override + public boolean visit(NullLiteral node) { + return isSearching(); + } + + @Override + public boolean visit(NumberLiteral node) { + return isSearching(); + } + + @Override + public boolean visit(PackageDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(ParameterizedType node) { + return isSearching(); + } + + @Override + public boolean visit(ParenthesizedExpression node) { + return isSearching(); + } + + @Override + public boolean visit(PostfixExpression node) { + return isSearching(); + } + + @Override + public boolean visit(PrefixExpression node) { + return isSearching(); + } + + @Override + public boolean visit(PrimitiveType node) { + return isSearching(); + } + + @Override + public boolean visit(QualifiedName node) { + return isSearching(); + } + + @Override + public boolean visit(QualifiedType node) { + return isSearching(); + } + + @Override + public boolean visit(ReturnStatement node) { + return isSearching(); + } + + @Override + public boolean visit(SimpleName node) { + return isSearching(); + } + + @Override + public boolean visit(SimpleType node) { + return isSearching(); + } + + @Override + public boolean visit(SingleMemberAnnotation node) { + return isSearching(); + } + + @Override + public boolean visit(SingleVariableDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(StringLiteral node) { + return isSearching(); + } + + @Override + public boolean visit(TextBlock node) { + return isSearching(); + } + + @Override + public boolean visit(SuperConstructorInvocation node) { + return isSearching(); + } + + @Override + public boolean visit(SuperFieldAccess node) { + return isSearching(); + } + + @Override + public boolean visit(SuperMethodInvocation node) { + return isSearching(); + } + + @Override + public boolean visit(SwitchCase node) { + return isSearching(); + } + + @Override + public boolean visit(SwitchStatement node) { + return isSearching(); + } + + @Override + public boolean visit(SynchronizedStatement node) { + return isSearching(); + } + + @Override + public boolean visit(TagElement node) { + return isSearching(); + } + + @Override + public boolean visit(TextElement node) { + return isSearching(); + } + + @Override + public boolean visit(ThisExpression node) { + return isSearching(); + } + + @Override + public boolean visit(ThrowStatement node) { + return isSearching(); + } + + @Override + public boolean visit(TryStatement node) { + return isSearching(); + } + + @Override + public boolean visit(TypeDeclaration node) { + return isSearching(); + } + + @Override + public boolean visit(TypeDeclarationStatement node) { + return isSearching(); + } + + @Override + public boolean visit(TypeLiteral node) { + return isSearching(); + } + + @Override + public boolean visit(TypeParameter node) { + return isSearching(); + } + + @Override + public boolean visit(UnionType node) { + return super.visit(node); + } + + @Override + public boolean visit(VariableDeclarationExpression node) { + return isSearching(); + } + + @Override + public boolean visit(VariableDeclarationFragment node) { + return isSearching(); + } + + @Override + public boolean visit(VariableDeclarationStatement node) { + return isSearching(); + } + + @Override + public boolean visit(WhileStatement node) { + return isSearching(); + } + + @Override + public boolean visit(WildcardType node) { + return isSearching(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/IJavaStructuresListener.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/IJavaStructuresListener.java new file mode 100644 index 0000000000..5277573c6a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/IJavaStructuresListener.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2004, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +/** + * Listener which can be notified when the Java logical structures are changed + * in some way. + */ +public interface IJavaStructuresListener { + + /** + * Notifies this listener that the Java logical structures have changed. + */ + public void logicalStructuresChanged(); + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIAllInstancesValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIAllInstancesValue.java new file mode 100644 index 0000000000..aec0b82104 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIAllInstancesValue.java @@ -0,0 +1,337 @@ +/******************************************************************************* + * Copyright (c) 2007, 2013 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Stepan Vavra - Bug 419316 - All References or All instances may throw NPE in Eclipse + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.HeapWalkingManager; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIArrayValue; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIPlaceholderValue; +import org.eclipse.jdt.internal.debug.core.model.JDIReferenceType; + + + +/** + * Java value containing an array of java objects. This value is used to hold a + * list of all instances of a specific java type. + * + * @since 3.3 + * @see org.eclipse.jdt.internal.debug.ui.heapwalking.AllInstancesActionDelegate + */ +public class JDIAllInstancesValue extends JDIArrayValue { + + private IJavaObject[] fInstances; + private final JDIReferenceType fRoot; + private IJavaArrayType fType; + private boolean fIsMoreThanPreference; + + /** + * Constructor, specifies whether there are more instances available than + * should be displayed according to the user's preference settings. + * + * @param target + * the target VM + * @param root + * the root object to get instances for + */ + public JDIAllInstancesValue(JDIDebugTarget target, JDIReferenceType root) { + super(target, null); + fRoot = root; + try { + IJavaType[] javaTypes = target.getJavaTypes("java.lang.Object[]"); //$NON-NLS-1$ + if (javaTypes != null && javaTypes.length > 0) { + fType = (IJavaArrayType) javaTypes[0]; + } + } catch (DebugException e) { + } + } + + /** + * @return an array of java objects that are instances of the root type + */ + protected IJavaObject[] getInstances() { + if (fInstances != null) { + return fInstances; + } + IJavaObject[] instances = new IJavaObject[0]; + fIsMoreThanPreference = false; + if (fRoot != null) { + int max = HeapWalkingManager.getDefault() + .getAllInstancesMaxCount(); + try { + if (max == 0) { + instances = fRoot.getInstances(max); + } else { + instances = fRoot.getInstances(max + 1); + if (instances.length > max) { + instances[max] = new JDIPlaceholderValue( + (JDIDebugTarget) fRoot.getDebugTarget(), + MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_2, Integer.toString(max))); + fIsMoreThanPreference = true; + } + } + } catch (DebugException e) { + JDIDebugPlugin.log(e); + } + } + fInstances = instances; + return instances; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getLength() + */ + @Override + public synchronized int getLength() throws DebugException { + return getInstances().length; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getSize() + */ + @Override + public int getSize() throws DebugException { + return getInstances().length; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getValue(int) + */ + @Override + public IJavaValue getValue(int index) throws DebugException { + if (index > getInstances().length - 1 || index < 0) { + internalError(LogicalStructuresMessages.JDIAllInstancesValue_0); + } + return getInstances()[index]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getValues() + */ + @Override + public IJavaValue[] getValues() throws DebugException { + return getInstances(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getVariable(int) + */ + @Override + public IVariable getVariable(int offset) throws DebugException { + if (offset > getInstances().length - 1 || offset < 0) { + internalError(LogicalStructuresMessages.JDIAllInstancesValue_1); + } + if (isMoreThanPreference() && offset == getInstances().length - 1) { + return new JDIPlaceholderVariable( + LogicalStructuresMessages.JDIAllInstancesValue_4, + getInstances()[offset]); + } + return new JDIPlaceholderVariable(MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_5, + Integer.toString(offset)), + getInstances()[offset]); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getVariables(int, + * int) + */ + @Override + public IVariable[] getVariables(int offset, int length) + throws DebugException { + if (length == 0) { + return new IVariable[0]; + } + if (offset > getInstances().length - 1 || offset < 0) { + internalError(LogicalStructuresMessages.JDIAllInstancesValue_1); + } + IVariable[] vars = new JDIPlaceholderVariable[length]; + for (int i = 0; i < length; i++) { + vars[i] = getVariable(i + offset); + } + return vars; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getVariables() + */ + @Override + public IVariable[] getVariables() throws DebugException { + return getVariables(0, getInstances().length); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getReferringObjects + * (long) + */ + @Override + public IJavaObject[] getReferringObjects(long max) throws DebugException { + return new IJavaObject[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#isAllocated() + */ + @Override + public boolean isAllocated() throws DebugException { + return getJavaDebugTarget().isAvailable(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#getInitialOffset + * () + */ + @Override + public int getInitialOffset() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIArrayValue#hasVariables() + */ + @Override + public boolean hasVariables() throws DebugException { + return getInstances().length > 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return fType; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getSignature() + */ + @Override + public String getSignature() throws DebugException { + return fType.getSignature(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getReferenceTypeName + * () + */ + @Override + public String getReferenceTypeName() throws DebugException { + return fType.getName(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getValueString() + */ + @Override + public String getValueString() throws DebugException { + if (isMoreThanPreference()) { + return MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_7, + Integer.toString(getInstances().length - 1)); + } else if (getInstances().length == 1) { + return MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_8, + Integer.toString(getInstances().length)); + } else { + return MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_9, + Integer.toString(getInstances().length)); + } + } + + /** + * Returns a string representation of this value intended to be displayed in + * the detail pane of views. Lists the references on separate lines. + * + * @return a string representation of this value to display in the detail + * pane + */ + public String getDetailString() { + StringBuilder buf = new StringBuilder(); + Object[] elements = getInstances(); + if (elements.length == 0) { + buf.append(LogicalStructuresMessages.JDIAllInstancesValue_10); + } else { + String length = null; + if (isMoreThanPreference()) { + length = MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_11, + Integer.toString(elements.length - 1)); + } else { + length = Integer.toString(elements.length); + } + if (elements.length == 1) { + buf.append(MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_12, length)); + } else { + buf.append(MessageFormat.format(LogicalStructuresMessages.JDIAllInstancesValue_13, length)); + } + for (Object element : elements) { + buf.append(element + "\n"); //$NON-NLS-1$ + } + } + return buf.toString(); + } + + /** + * @return whether there are more instances available than should be + * displayed + */ + protected boolean isMoreThanPreference() { + getInstances(); // The instances must be requested to know if there are + // more than the preference + return fIsMoreThanPreference; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDILambdaVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDILambdaVariable.java new file mode 100644 index 0000000000..055455d616 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDILambdaVariable.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2018 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Paul Pazderski - Bug 542989 - inherit from {@link JDIPlaceholderVariable} to prevent NPEs + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import org.eclipse.jdt.debug.core.IJavaValue; + +/** + * Represents the closure context inside a lambda expression. + */ +public class JDILambdaVariable extends JDIPlaceholderVariable { + + public JDILambdaVariable(IJavaValue value) { + super("Lambda", value); //$NON-NLS-1$ + } + + @Override + public boolean isSynthetic() { + return true; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIPlaceholderVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIPlaceholderVariable.java new file mode 100644 index 0000000000..8da5a3f9b4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIPlaceholderVariable.java @@ -0,0 +1,356 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.debug.core.IJavaModifiers; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +/** + * Encapsulates a name and a value. Used when a variable is required (such as + * for the VariablesView), but we only have a value available (such as the + * result of an evaluation for an object browser). + * + * @since 3.0 + */ +public class JDIPlaceholderVariable extends PlatformObject implements + IJavaVariable { + + private final String fName; + private final IJavaValue fValue; + + /** + * When created for a logical structure we hold onto the original + * non-logical value for purposes of equality. This way a logical + * structure's children remain more stable in the variables view. + * + * This is null when not created for a logical structure. + */ + private IJavaValue fLogicalParent; + + public JDIPlaceholderVariable(String name, IJavaValue value) { + fName = name; + fValue = value; + } + + /** + * Constructs a place holder with the given name and value originating from + * the specified logical parent. + * + * @param name + * variable name + * @param value + * variable value + * @param logicalParent + * original value this value is a logical child for or + * null if none + */ + public JDIPlaceholderVariable(String name, IJavaValue value, + IJavaValue logicalParent) { + this(name, value); + fLogicalParent = logicalParent; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getSignature() + */ + @Override + public String getSignature() throws DebugException { + return ((IJavaValue) getValue()).getSignature(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + return ((IJavaValue) getValue()).getGenericSignature(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return ((IJavaValue) getValue()).getJavaType(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#isLocal() + */ + @Override + public boolean isLocal() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IVariable#getValue() + */ + @Override + public IValue getValue() { + return fValue; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IVariable#getName() + */ + @Override + public String getName() { + return fName; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + return ((IJavaValue) getValue()).getReferenceTypeName(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IVariable#hasValueChanged() + */ + @Override + public boolean hasValueChanged() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPublic() + */ + @Override + public boolean isPublic() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPrivate() + */ + @Override + public boolean isPrivate() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isProtected() + */ + @Override + public boolean isProtected() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPackagePrivate() + */ + @Override + public boolean isPackagePrivate() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isFinal() + */ + @Override + public boolean isFinal() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isStatic() + */ + @Override + public boolean isStatic() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isSynthetic() + */ + @Override + public boolean isSynthetic() { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + @Override + public String getModelIdentifier() { + return getValue().getModelIdentifier(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + @Override + public IDebugTarget getDebugTarget() { + return ((IJavaValue) getValue()).getDebugTarget(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + @Override + public ILaunch getLaunch() { + return getValue().getLaunch(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#setValue(java.lang.String + * ) + */ + @Override + public void setValue(String expression) { + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#setValue(org.eclipse. + * debug.core.model.IValue) + */ + @Override + public void setValue(IValue value) { + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#supportsValueModification + * () + */ + @Override + public boolean supportsValueModification() { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#verifyValue(java.lang + * .String) + */ + @Override + public boolean verifyValue(String expression) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#verifyValue(org.eclipse + * .debug.core.model.IValue) + */ + @Override + public boolean verifyValue(IValue value) { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @Override + @SuppressWarnings("unchecked") + public T getAdapter(Class adapter) { + if (IJavaVariable.class.equals(adapter) + || IJavaModifiers.class.equals(adapter)) { + return (T) this; + } + return super.getAdapter(adapter); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof JDIPlaceholderVariable) { + JDIPlaceholderVariable var = (JDIPlaceholderVariable) obj; + if (fLogicalParent != null) { + return var.getName().equals(getName()) + && fLogicalParent.equals(var.fLogicalParent); + } + return var.getName().equals(getName()) + && var.getValue().equals(getValue()); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + if (fLogicalParent != null) { + return fLogicalParent.hashCode() + fName.hashCode(); + } + return fName.hashCode() + fValue.hashCode(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIReturnValueVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIReturnValueVariable.java new file mode 100644 index 0000000000..1bd1806940 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JDIReturnValueVariable.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2016 Till Brychcy and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Till Brychcy - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import org.eclipse.jdt.debug.core.IJavaValue; + +/** + * Represents the return value after a "step-return". + */ +public class JDIReturnValueVariable extends JDIPlaceholderVariable { + public final boolean hasResult; + + public JDIReturnValueVariable(String name, IJavaValue value, boolean hasResult) { + super(name, value); + this.hasResult = hasResult; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaLogicalStructure.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaLogicalStructure.java new file mode 100644 index 0000000000..d3b326aa2a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaLogicalStructure.java @@ -0,0 +1,577 @@ +/******************************************************************************* + * Copyright (c) 2004, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Igor Fedorenko - Bug 368212 - JavaLineBreakpoint.computeJavaProject does not let ISourceLocator evaluate the stackFrame + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILogicalStructureType; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.ILogicalStructureTypeDelegate3; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; +import org.eclipse.jdt.debug.eval.ICompiledExpression; +import org.eclipse.jdt.debug.eval.IEvaluationListener; +import org.eclipse.jdt.debug.eval.IEvaluationResult; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; + +import com.sun.jdi.VMDisconnectedException; + + +@SuppressWarnings("restriction") +public class JavaLogicalStructure implements ILogicalStructureType, ILogicalStructureTypeDelegate3 { + + private static IStatusHandler fgStackFrameProvider; + + /** + * Fully qualified type name. + */ + private String fType; + /** + * Indicate if this java logical structure should be used on object instance + * of subtype of the specified type. + */ + private boolean fSubtypes; + /** + * Code snippet to evaluate to create the logical value. + */ + private String fValue; + /** + * Description of the logical structure. + */ + private String fDescription; + /** + * Name and associated code snippet of the variables of the logical value. + */ + private String[][] fVariables; + /** + * The plugin identifier of the plugin which contributed this logical + * structure or null if this structure was defined by the user. + */ + private String fContributingPluginId = null; + + /** + * Performs the evaluations. + */ + private class EvaluationBlock implements IEvaluationListener { + + private final IJavaObject fEvaluationValue; + private final IJavaReferenceType fEvaluationType; + private final IJavaThread fThread; + private final IAstEvaluationEngine fEvaluationEngine; + private IEvaluationResult fResult; + + /** + * Constructor + * + * @param value + * @param type + * @param thread + * @param evaluationEngine + */ + public EvaluationBlock(IJavaObject value, IJavaReferenceType type, + IJavaThread thread, IAstEvaluationEngine evaluationEngine) { + fEvaluationValue = value; + fEvaluationType = type; + fThread = thread; + fEvaluationEngine = evaluationEngine; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.eval.IEvaluationListener#evaluationComplete + * (org.eclipse.jdt.debug.eval.IEvaluationResult) + */ + @Override + public void evaluationComplete(IEvaluationResult result) { + synchronized (this) { + fResult = result; + this.notify(); + } + } + + /** + * Evaluates the specified snippet and returns the + * IJavaValue from the evaluation + * + * @param snippet + * the snippet to evaluate + * @return the IJavaValue from the evaluation + * @throws DebugException + */ + public IJavaValue evaluate(String snippet) throws DebugException { + Map compileOptions = + Collections.singletonMap(CompilerOptions.OPTION_IgnoreUnnamedModuleForSplitPackage, JavaCore.ENABLED); + ICompiledExpression compiledExpression = fEvaluationEngine + .getCompiledExpression(snippet, fEvaluationType, compileOptions); + if (compiledExpression.hasErrors()) { + String[] errorMessages = compiledExpression.getErrorMessages(); + log(errorMessages); + return new JavaStructureErrorValue(errorMessages, + fEvaluationValue); + } + fResult = null; + fEvaluationEngine.evaluateExpression(compiledExpression, + fEvaluationValue, fThread, this, + DebugEvent.EVALUATION_IMPLICIT | IAstEvaluationEngine.DISABLE_GC_ON_RESULT, false); + synchronized (this) { + if (fResult == null) { + try { + this.wait(); + } catch (InterruptedException e) { + } + } + } + if (fResult == null) { + return new JavaStructureErrorValue( + LogicalStructuresMessages.JavaLogicalStructure_1, + fEvaluationValue); + } + if (fResult.hasErrors()) { + DebugException exception = fResult.getException(); + String message; + if (exception != null) { + if (exception.getStatus().getException() instanceof UnsupportedOperationException) { + message = LogicalStructuresMessages.JavaLogicalStructure_0; + } else if (exception.getStatus().getCode() == IJavaThread.ERR_THREAD_NOT_SUSPENDED) { + // throw this exception so the content provider can + // handle if (cancel the update) + throw exception; + } else { + message = MessageFormat.format(LogicalStructuresMessages.JavaLogicalStructure_2, exception.getMessage()); + } + } else { + message = LogicalStructuresMessages.JavaLogicalStructure_3; + } + return new JavaStructureErrorValue(message, fEvaluationValue); + } + return fResult.getValue(); + } + + /** + * Logs the given error messages if this logical structure was + * contributed via extension. + */ + private void log(String[] messages) { + if (isContributed()) { + String log = Arrays.asList(messages).stream().collect(Collectors.joining("\n")); //$NON-NLS-1$ + String error = String.format("Error while evaluating '%s' logical structure for type %s with the value '%s'", //$NON-NLS-1$ + getDescription(), getQualifiedTypeName(), getValue()); + JDIDebugPlugin.log(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.ERROR, error, new IllegalStateException(log))); + } + } + } + + /** + * Constructor from parameters. + */ + public JavaLogicalStructure(String type, boolean subtypes, String value, + String description, String[][] variables) { + fType = type; + fSubtypes = subtypes; + fValue = value; + fDescription = description; + fVariables = variables; + } + + /** + * Constructor from configuration element. + */ + public JavaLogicalStructure(IConfigurationElement configurationElement) + throws CoreException { + fType = configurationElement.getAttribute("type"); //$NON-NLS-1$ + if (fType == null) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.ERROR, + LogicalStructuresMessages.JavaLogicalStructures_0, null)); + } + fSubtypes = Boolean.parseBoolean(configurationElement.getAttribute("subtypes")); //$NON-NLS-1$ + fValue = configurationElement.getAttribute("value"); //$NON-NLS-1$ + fDescription = configurationElement.getAttribute("description"); //$NON-NLS-1$ + if (fDescription == null) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.ERROR, + LogicalStructuresMessages.JavaLogicalStructures_4, null)); + } + IConfigurationElement[] variableElements = configurationElement + .getChildren("variable"); //$NON-NLS-1$ + if (fValue == null && variableElements.length == 0) { + throw new CoreException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.ERROR, + LogicalStructuresMessages.JavaLogicalStructures_1, null)); + } + fVariables = new String[variableElements.length][2]; + for (int j = 0; j < fVariables.length; j++) { + String variableName = variableElements[j].getAttribute("name"); //$NON-NLS-1$ + if (variableName == null) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.ERROR, + LogicalStructuresMessages.JavaLogicalStructures_2, + null)); + } + fVariables[j][0] = variableName; + String variableValue = variableElements[j].getAttribute("value"); //$NON-NLS-1$ + if (variableValue == null) { + throw new CoreException( + new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.ERROR, + LogicalStructuresMessages.JavaLogicalStructures_3, + null)); + } + fVariables[j][1] = variableValue; + } + fContributingPluginId = configurationElement.getContributor().getName(); + } + + /** + * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#providesLogicalStructure(IValue) + */ + @Override + public boolean providesLogicalStructure(IValue value) { + if (!(value instanceof IJavaObject)) { + return false; + } + return getType((IJavaObject) value) != null; + } + + /** + * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#getLogicalStructure(IValue) + */ + @Override + public IValue getLogicalStructure(IValue value) throws CoreException { + if (!(value instanceof IJavaObject)) { + return value; + } + IJavaObject javaValue = (IJavaObject) value; + try { + IJavaReferenceType type = getType(javaValue); + if (type == null) { + return value; + } + IJavaStackFrame stackFrame = getStackFrame(javaValue); + if (stackFrame == null) { + return value; + } + IJavaProject project = JavaDebugUtils.resolveJavaProject(stackFrame); + if (project == null) { + return value; + } + + IAstEvaluationEngine evaluationEngine = JDIDebugPlugin.getDefault() + .getEvaluationEngine(project, + (IJavaDebugTarget) stackFrame.getDebugTarget()); + + EvaluationBlock evaluationBlock = new EvaluationBlock(javaValue, + type, (IJavaThread) stackFrame.getThread(), + evaluationEngine); + if (fValue == null) { + // evaluate each variable + JDIPlaceholderVariable[] variables = new JDIPlaceholderVariable[fVariables.length]; + for (int i = 0; i < fVariables.length; i++) { + variables[i] = new JDIPlaceholderVariable(fVariables[i][0], + evaluationBlock.evaluate(fVariables[i][1]), + javaValue); + } + return new LogicalObjectStructureValue(javaValue, variables); + } + // evaluate the logical value + IJavaValue logicalValue = evaluationBlock.evaluate(fValue); + if (logicalValue instanceof JDIValue) { + ((JDIValue) logicalValue).setLogicalParent(javaValue); + } + return logicalValue; + + } catch (CoreException e) { + if (e.getStatus().getCode() == IJavaThread.ERR_THREAD_NOT_SUSPENDED) { + throw e; + } + JDIDebugPlugin.log(e); + } + return value; + } + + @Override + public void releaseValue(IValue value) { + if (value instanceof IJavaObject) { + try { + ((IJavaObject) value).enableCollection(); + } catch (DebugException e) { + if (!(e.getStatus().getException() instanceof VMDisconnectedException)) { + // don't worry about GC if the VM has terminated + JDIDebugPlugin.log(e); + } + } + } + } + + /** + * Returns the IJavaReferenceType from the specified + * IJavaObject + * + * @param value + * @return the IJavaReferenceType from the specified + * IJavaObject + */ + private IJavaReferenceType getType(IJavaObject value) { + try { + IJavaType type = value.getJavaType(); + if (!(type instanceof IJavaClassType)) { + return null; + } + IJavaClassType classType = (IJavaClassType) type; + if (classType.getName().equals(fType)) { + // found the type + return classType; + } + if (!fSubtypes) { + // if not checking the subtypes, stop here + return null; + } + IJavaClassType superClass = classType.getSuperclass(); + while (superClass != null) { + if (superClass.getName().equals(fType)) { + // found the type, it's a super class + return superClass; + } + superClass = superClass.getSuperclass(); + } + IJavaInterfaceType[] superInterfaces = classType.getAllInterfaces(); + for (IJavaInterfaceType superInterface : superInterfaces) { + if (superInterface.getName().equals(fType)) { + // found the type, it's a super interface + return superInterface; + } + } + } catch (DebugException e) { + JDIDebugPlugin.log(e); + return null; + } + return null; + } + + /** + * Return the current stack frame context, or a valid stack frame for the + * given value. + * + * @param value + * @return the current stack frame context, or a valid stack frame for the + * given value. + * @throws CoreException + */ + private IJavaStackFrame getStackFrame(IValue value) throws CoreException { + IStatusHandler handler = getStackFrameProvider(); + if (handler != null) { + IJavaStackFrame stackFrame = (IJavaStackFrame) handler + .handleStatus(JDIDebugPlugin.STATUS_GET_EVALUATION_FRAME, + value); + if (stackFrame != null) { + return stackFrame; + } + } + IDebugTarget target = value.getDebugTarget(); + IJavaDebugTarget javaTarget = target + .getAdapter(IJavaDebugTarget.class); + if (javaTarget != null) { + IThread[] threads = javaTarget.getThreads(); + for (IThread thread : threads) { + if (thread.isSuspended()) { + return (IJavaStackFrame) thread.getTopStackFrame(); + } + } + } + return null; + } + + /** + * Returns the singleton stackframe provider + * + * @return the singleton stackframe provider + */ + private static IStatusHandler getStackFrameProvider() { + if (fgStackFrameProvider == null) { + fgStackFrameProvider = DebugPlugin.getDefault().getStatusHandler( + JDIDebugPlugin.STATUS_GET_EVALUATION_FRAME); + } + return fgStackFrameProvider; + } + + /** + * Returns if this logical structure should be used for subtypes too. + * + * @return if this logical structure should be used for subtypes too. + */ + public boolean isSubtypes() { + return fSubtypes; + } + + /** + * Sets if this logical structure should be used for subtypes or not. + * + * @param subtypes + */ + public void setSubtypes(boolean subtypes) { + fSubtypes = subtypes; + } + + /** + * Returns the name of the type this logical structure should be used for. + * + * @return the name of the type this logical structure should be used for. + */ + public String getQualifiedTypeName() { + return fType; + } + + /** + * Sets the name of the type this logical structure should be used for. + * + * @param type + */ + public void setType(String type) { + fType = type; + } + + /** + * Returns the code snippet to use to generate the logical structure. + * + * @return the code snippet to use to generate the logical structure. + */ + public String getValue() { + return fValue; + } + + /** + * Sets the code snippet to use to generate the logical structure. + * + * @param value + */ + public void setValue(String value) { + fValue = value; + } + + /** + * Returns the variables of this logical structure. + * + * @return the variables of this logical structure. + */ + public String[][] getVariables() { + return fVariables; + } + + /** + * Sets the variables of this logical structure. + * + * @param variables + */ + public void setVariables(String[][] variables) { + fVariables = variables; + } + + /** + * Set the description of this logical structure. + * + * @param description + */ + public void setDescription(String description) { + fDescription = description; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.ILogicalStructureTypeDelegate2#getDescription + * (org.eclipse.debug.core.model.IValue) + */ + @Override + public String getDescription(IValue value) { + return getDescription(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.ILogicalStructureType#getDescription() + */ + @Override + public String getDescription() { + return fDescription; + } + + /** + * Indicates if this logical structure was contributed by a plug-in or + * defined by a user. + * + * @return if this logical structure is contributed + */ + public boolean isContributed() { + return fContributingPluginId != null; + } + + /** + * Returns the plugin identifier of the plugin which contributed this + * logical structure or null if this structure was defined by + * the user. + * + * @return the plugin identifier of the plugin which contributed this + * structure or null + */ + public String getContributingPluginId() { + return fContributingPluginId; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.ILogicalStructureType#getId() + */ + @Override + public String getId() { + return JDIDebugPlugin.getUniqueIdentifier() + fType + fDescription; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaLogicalStructures.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaLogicalStructures.java new file mode 100644 index 0000000000..5687af9cbe --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaLogicalStructures.java @@ -0,0 +1,324 @@ +/******************************************************************************* + * Copyright (c) 2004, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILogicalStructureProvider; +import org.eclipse.debug.core.ILogicalStructureType; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.osgi.service.prefs.BackingStoreException; + +public class JavaLogicalStructures implements ILogicalStructureProvider { + + // preference values + static final char IS_SUBTYPE_TRUE = 'T'; + static final char IS_SUBTYPE_FALSE = 'F'; + + /** + * The list of java logical structures. + */ + private static Map> fJavaLogicalStructureMap; + + /** + * The list of java logical structures in this Eclipse install. + */ + private static List fPluginContributedJavaLogicalStructures; + + /** + * The list of java logical structures defined by the user. + */ + private static List fUserDefinedJavaLogicalStructures; + + /** + * The list of java logical structures listeners. + */ + private static Set fListeners = new HashSet<>(); + + /** + * Preference key for the list of user defined Java logical structures + * + * @since 3.1 + */ + private static final String PREF_JAVA_LOGICAL_STRUCTURES = JDIDebugModel + .getPluginIdentifier() + ".PREF_JAVA_LOGICAL_STRUCTURES"; //$NON-NLS-1$ + + /** + * Updates user defined logical structures if the preference changes + */ + static class PreferenceListener implements IPreferenceChangeListener { + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) + */ + @Override + public void preferenceChange(PreferenceChangeEvent event) { + if (PREF_JAVA_LOGICAL_STRUCTURES.equals(event.getKey())) { + initUserDefinedJavaLogicalStructures(); + initJavaLogicalStructureMap(); + Iterator iter = fListeners.iterator(); + while (iter.hasNext()) { + iter.next().logicalStructuresChanged(); + } + } + } + } + + /** + * Get the logical structure from the extension point and the preference + * store, and initialize the map. + */ + static { + initPluginContributedJavaLogicalStructure(); + initUserDefinedJavaLogicalStructures(); + initJavaLogicalStructureMap(); + IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(prefs != null) { + prefs.addPreferenceChangeListener(new PreferenceListener()); + } + } + + private static void initJavaLogicalStructureMap() { + fJavaLogicalStructureMap = new HashMap<>(); + addAllLogicalStructures(fPluginContributedJavaLogicalStructures); + addAllLogicalStructures(fUserDefinedJavaLogicalStructures); + } + + /** + * @param pluginContributedJavaLogicalStructures + */ + private static void addAllLogicalStructures( + List pluginContributedJavaLogicalStructures) { + for (JavaLogicalStructure logicalStructure : pluginContributedJavaLogicalStructures) { + addLogicalStructure(logicalStructure); + } + } + + /** + * @param structure + */ + private static void addLogicalStructure(JavaLogicalStructure structure) { + String typeName = structure.getQualifiedTypeName(); + List logicalStructure = fJavaLogicalStructureMap.get(typeName); + if (logicalStructure == null) { + logicalStructure = new ArrayList<>(); + fJavaLogicalStructureMap.put(typeName, logicalStructure); + } + logicalStructure.add(structure); + } + + /** + * Get the configuration elements for the extension point. + */ + private static void initPluginContributedJavaLogicalStructure() { + fPluginContributedJavaLogicalStructures = new ArrayList<>(); + IExtensionPoint extensionPoint = Platform.getExtensionRegistry() + .getExtensionPoint(JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.EXTENSION_POINT_JAVA_LOGICAL_STRUCTURES); + IConfigurationElement[] javaLogicalStructureElements = extensionPoint + .getConfigurationElements(); + for (IConfigurationElement javaLogicalStructureElement : javaLogicalStructureElements) { + try { + fPluginContributedJavaLogicalStructures + .add(new JavaLogicalStructure( + javaLogicalStructureElement)); + } catch (CoreException e) { + JDIDebugPlugin.log(e); + } + } + } + + /** + * Get the user defined logical structures (from the preference store). + */ + private static void initUserDefinedJavaLogicalStructures() { + fUserDefinedJavaLogicalStructures = new ArrayList<>(); + String logicalStructuresString = Platform.getPreferencesService().getString( + JDIDebugPlugin.getUniqueIdentifier(), + PREF_JAVA_LOGICAL_STRUCTURES, + "", //$NON-NLS-1$ + null); + StringTokenizer tokenizer = new StringTokenizer( + logicalStructuresString, "\0", true); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + String type = tokenizer.nextToken(); + tokenizer.nextToken(); + String description = tokenizer.nextToken(); + tokenizer.nextToken(); + String isSubtypeValue = tokenizer.nextToken(); + boolean isSubtype = isSubtypeValue.charAt(0) == IS_SUBTYPE_TRUE; + tokenizer.nextToken(); + String value = tokenizer.nextToken(); + if (value.charAt(0) == '\0') { + value = null; + } else { + tokenizer.nextToken(); + } + String variablesCounterValue = tokenizer.nextToken(); + int variablesCounter = Integer.parseInt(variablesCounterValue); + tokenizer.nextToken(); + String[][] variables = new String[variablesCounter][2]; + for (int i = 0; i < variablesCounter; i++) { + variables[i][0] = tokenizer.nextToken(); + tokenizer.nextToken(); + variables[i][1] = tokenizer.nextToken(); + tokenizer.nextToken(); + } + fUserDefinedJavaLogicalStructures.add(new JavaLogicalStructure( + type, isSubtype, value, description, variables)); + } + } + + /** + * Save the user defined logical structures in the preference store. + */ + public static void saveUserDefinedJavaLogicalStructures() { + StringBuilder logicalStructuresString = new StringBuilder(); + for (JavaLogicalStructure logicalStructure : fUserDefinedJavaLogicalStructures) { + logicalStructuresString.append( + logicalStructure.getQualifiedTypeName()).append('\0'); + logicalStructuresString.append(logicalStructure.getDescription()) + .append('\0'); + logicalStructuresString.append( + logicalStructure.isSubtypes() ? IS_SUBTYPE_TRUE + : IS_SUBTYPE_FALSE).append('\0'); + String value = logicalStructure.getValue(); + if (value != null) { + logicalStructuresString.append(value); + } + logicalStructuresString.append('\0'); + String[][] variables = logicalStructure.getVariables(); + logicalStructuresString.append(variables.length).append('\0'); + for (String[] strings : variables) { + logicalStructuresString.append(strings[0]).append('\0'); + logicalStructuresString.append(strings[1]).append('\0'); + } + } + IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier()); + if(node != null) { + node.put(PREF_JAVA_LOGICAL_STRUCTURES, logicalStructuresString.toString()); + try { + node.flush(); + } catch (BackingStoreException e) { + JDIDebugPlugin.log(e); + } + } + } + + /** + * Return all the defined logical structures. + */ + public static JavaLogicalStructure[] getJavaLogicalStructures() { + JavaLogicalStructure[] logicalStructures = new JavaLogicalStructure[fPluginContributedJavaLogicalStructures + .size() + fUserDefinedJavaLogicalStructures.size()]; + int i = 0; + for (JavaLogicalStructure logicalStructure : fPluginContributedJavaLogicalStructures) { + logicalStructures[i++] = logicalStructure; + } + for (JavaLogicalStructure logicalStructure : fUserDefinedJavaLogicalStructures) { + logicalStructures[i++] = logicalStructure; + } + return logicalStructures; + } + + /** + * Set the user defined logical structures. + */ + public static void setUserDefinedJavaLogicalStructures( + JavaLogicalStructure[] logicalStructures) { + fUserDefinedJavaLogicalStructures = Arrays.asList(logicalStructures); + saveUserDefinedJavaLogicalStructures(); + } + + public static void addStructuresListener(IJavaStructuresListener listener) { + fListeners.add(listener); + } + + public static void removeStructuresListener(IJavaStructuresListener listener) { + fListeners.remove(listener); + } + + @Override + public ILogicalStructureType[] getLogicalStructureTypes(IValue value) { + if (!(value instanceof IJavaObject)) { + return new ILogicalStructureType[0]; + } + IJavaObject javaValue = (IJavaObject) value; + List logicalStructures = new ArrayList<>(); + try { + IJavaType type = javaValue.getJavaType(); + if (!(type instanceof IJavaClassType)) { + return new ILogicalStructureType[0]; + } + IJavaClassType classType = (IJavaClassType) type; + List list = fJavaLogicalStructureMap + .get(classType.getName()); + if (list != null) { + logicalStructures.addAll(list); + } + IJavaClassType superClass = classType.getSuperclass(); + while (superClass != null) { + addIfIsSubtype(logicalStructures, + fJavaLogicalStructureMap.get(superClass + .getName())); + superClass = superClass.getSuperclass(); + } + IJavaInterfaceType[] superInterfaces = classType.getAllInterfaces(); + for (IJavaInterfaceType superInterface : superInterfaces) { + addIfIsSubtype(logicalStructures, + fJavaLogicalStructureMap.get(superInterface + .getName())); + } + } catch (DebugException e) { + JDIDebugPlugin.log(e); + return new ILogicalStructureType[0]; + } + return logicalStructures + .toArray(new ILogicalStructureType[logicalStructures.size()]); + } + + private void addIfIsSubtype(List logicalStructures, List list) { + if (list == null) { + return; + } + for(JavaLogicalStructure jls : list) { + if (jls.isSubtypes()) { + logicalStructures.add(jls); + } + } + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaStructureErrorValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaStructureErrorValue.java new file mode 100644 index 0000000000..b09c4e9378 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/JavaStructureErrorValue.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2004, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.JDIDebugModel; + +/** + * + */ +public class JavaStructureErrorValue implements IJavaValue { + + private final String[] fMessages; + private final IJavaValue fValue; + + public JavaStructureErrorValue(String errorMessage, IJavaValue value) { + fMessages = new String[] { errorMessage }; + fValue = value; + } + + public JavaStructureErrorValue(String[] errorMessages, IJavaValue value) { + fMessages = errorMessages; + fValue = value; + } + + /** + * Returns this error node's parent value. This is the value for which a + * logical structure could not be calculated. + * + * @return the parent value of this error node + */ + public IJavaValue getParentValue() { + return fValue; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getSignature() + */ + @Override + public String getSignature() throws DebugException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + return ""; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#getValueString() + */ + @Override + public String getValueString() throws DebugException { + return fMessages[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#isAllocated() + */ + @Override + public boolean isAllocated() throws DebugException { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#getVariables() + */ + @Override + public IVariable[] getVariables() throws DebugException { + IVariable[] variables = new IVariable[fMessages.length]; + for (int i = 0; i < variables.length; i++) { + StringBuilder varName = new StringBuilder(); + if (variables.length > 1) { + varName.append( + LogicalStructuresMessages.JavaStructureErrorValue_0) + .append('[').append(i).append(']'); + } else { + varName.append(LogicalStructuresMessages.JavaStructureErrorValue_1); + } + variables[i] = new JDIPlaceholderVariable(varName.toString(), + new JavaStructureErrorValue(fMessages[i], fValue)); + } + return variables; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#hasVariables() + */ + @Override + public boolean hasVariables() throws DebugException { + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + @Override + public String getModelIdentifier() { + return JDIDebugModel.getPluginIdentifier(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + @Override + public IDebugTarget getDebugTarget() { + return fValue.getDebugTarget(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + @Override + public ILaunch getLaunch() { + return getDebugTarget().getLaunch(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @Override + public T getAdapter(Class adapter) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#isNull() + */ + @Override + public boolean isNull() { + return false; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalObjectStructureValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalObjectStructureValue.java new file mode 100644 index 0000000000..d9de303eb2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalObjectStructureValue.java @@ -0,0 +1,310 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; + +/** + * A proxy to an object representing the logical structure of that object. + */ +public class LogicalObjectStructureValue implements IJavaObject { + + private final IJavaObject fObject; + private final JDIPlaceholderVariable[] fVariables; + + /** + * Constructs a proxy to the given object, with the given variables as + * children. + * + * @param object + * original object + * @param variables + * java variables to add as children to this object + */ + public LogicalObjectStructureValue(IJavaObject object, + JDIPlaceholderVariable[] variables) { + fObject = object; + fVariables = variables; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread, boolean) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, boolean superSend) + throws DebugException { + return fObject + .sendMessage(selector, signature, args, thread, superSend); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread, java.lang.String) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, String typeSignature) + throws DebugException { + return fObject.sendMessage(selector, signature, args, thread, + typeSignature); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getField(java.lang.String, + * boolean) + */ + @Override + public IJavaFieldVariable getField(String name, boolean superField) + throws DebugException { + return fObject.getField(name, superField); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getField(java.lang.String, + * java.lang.String) + */ + @Override + public IJavaFieldVariable getField(String name, String typeSignature) + throws DebugException { + return fObject.getField(name, typeSignature); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getSignature() + */ + @Override + public String getSignature() throws DebugException { + return fObject.getSignature(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + return fObject.getGenericSignature(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return fObject.getJavaType(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + return fObject.getReferenceTypeName(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#getValueString() + */ + @Override + public String getValueString() throws DebugException { + return fObject.getValueString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#isAllocated() + */ + @Override + public boolean isAllocated() throws DebugException { + return fObject.isAllocated(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#getVariables() + */ + @Override + public IVariable[] getVariables() { + return fVariables; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#hasVariables() + */ + @Override + public boolean hasVariables() { + return fVariables.length > 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + @Override + public String getModelIdentifier() { + return fObject.getModelIdentifier(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + @Override + public IDebugTarget getDebugTarget() { + return fObject.getDebugTarget(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + @Override + public ILaunch getLaunch() { + return fObject.getLaunch(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @Override + public T getAdapter(Class adapter) { + return fObject.getAdapter(adapter); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getWaitingThreads() + */ + @Override + public IJavaThread[] getWaitingThreads() throws DebugException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getOwningThread() + */ + @Override + public IJavaThread getOwningThread() throws DebugException { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getReferringObjects(long) + */ + @Override + public IJavaObject[] getReferringObjects(long max) throws DebugException { + return fObject.getReferringObjects(max); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#disableCollection() + */ + @Override + public void disableCollection() throws DebugException { + fObject.disableCollection(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#enableCollection() + */ + @Override + public void enableCollection() throws DebugException { + fObject.enableCollection(); + + for (JDIPlaceholderVariable variable : fVariables) { + IValue variableValue = variable.getValue(); + if (variableValue instanceof IJavaObject) { + ((IJavaObject) variableValue).enableCollection(); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getUniqueId() + */ + @Override + public long getUniqueId() throws DebugException { + return fObject.getUniqueId(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#isNull() + */ + @Override + public boolean isNull() { + return false; + } + + @Override + public String getLabel() throws DebugException { + return fObject.getLabel(); + } + + @Override + public void setLabel(String newLabel) throws DebugException { + fObject.setLabel(newLabel); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalStructuresMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalStructuresMessages.java new file mode 100644 index 0000000000..bcdb325bf0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalStructuresMessages.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.logicalstructures; + +import org.eclipse.osgi.util.NLS; + +public class LogicalStructuresMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.core.logicalstructures.LogicalStructuresMessages";//$NON-NLS-1$ + + public static String JavaLogicalStructure_0; + + public static String JDIAllInstancesValue_0; + public static String JDIAllInstancesValue_1; + public static String JDIAllInstancesValue_2; + public static String JDIAllInstancesValue_4; + public static String JDIAllInstancesValue_5; + public static String JDIAllInstancesValue_7; + public static String JDIAllInstancesValue_8; + public static String JDIAllInstancesValue_9; + public static String JDIAllInstancesValue_10; + public static String JDIAllInstancesValue_11; + public static String JDIAllInstancesValue_12; + public static String JDIAllInstancesValue_13; + + public static String JavaLogicalStructures_0; + public static String JavaLogicalStructures_1; + public static String JavaLogicalStructures_2; + public static String JavaLogicalStructures_3; + public static String JavaLogicalStructures_4; + public static String JavaStructureErrorValue_0; + public static String JavaStructureErrorValue_1; + public static String JavaLogicalStructure_1; + public static String JavaLogicalStructure_2; + public static String JavaLogicalStructure_3; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, LogicalStructuresMessages.class); + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalStructuresMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalStructuresMessages.properties new file mode 100644 index 0000000000..eb0e51ecdd --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/logicalstructures/LogicalStructuresMessages.properties @@ -0,0 +1,37 @@ +############################################################################### +# Copyright (c) 2000, 2009 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +JavaLogicalStructures_0=Required attribute type missing for javaLogicalStructure element. +JavaLogicalStructures_1=javaLogicalStructure element require an attribute value, or >0 variable element as children. +JavaLogicalStructures_2=Required attribute name missing for javaLogicalStructure/variable element. +JavaLogicalStructures_3=Required attribute value missing for javaLogicalStructure/variable element. +JavaLogicalStructures_4=Required attribute description missing for javaLogicalStructure element. +JavaStructureErrorValue_0=Errors +JavaStructureErrorValue_1=Error +JavaLogicalStructure_1=Java logical structure evaluation failed. +JavaLogicalStructure_2=Exception occurred: {0}. +JavaLogicalStructure_3=Internal error(s) occurred. See log for details. +JavaLogicalStructure_0= +JDIAllInstancesValue_0=The specified index is outside the range of this array +JDIAllInstancesValue_1=The specified offset is outside the range of this collection +JDIAllInstancesValue_10=No instances +JDIAllInstancesValue_11={0}+ +JDIAllInstancesValue_12={0} instance:\n +JDIAllInstancesValue_13={0} instances:\n +JDIAllInstancesValue_2=Display limited to {0} instances, see Heap Walking preference page. +JDIAllInstancesValue_4=... +JDIAllInstancesValue_5=[{0}] +JDIAllInstancesValue_7={0}+ instances +JDIAllInstancesValue_8={0} instance +JDIAllInstancesValue_9={0} instances diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/ITimeoutListener.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/ITimeoutListener.java new file mode 100644 index 0000000000..1de6cef096 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/ITimeoutListener.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +/** + * A timeout listener is notified when a timer expires. + * + * @see Timer + */ +public interface ITimeoutListener { + + /** + * Notifies this listener that its timeout request has expired. + */ + public void timeout(); +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayEntryVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayEntryVariable.java new file mode 100644 index 0000000000..44d404e125 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayEntryVariable.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * An entry in an array. + */ + +public class JDIArrayEntryVariable extends JDIModificationVariable { + + /** + * The index of the variable entry + */ + private final int fIndex; + + /** + * The array object + */ + private final ArrayReference fArray; + + /** + * The reference type name of this variable. Cached lazily. + */ + private String fReferenceTypeName = null; + + /** + * When created for a logical structure we hold onto the original + * non-logical object for purposes of equality. This way a logical + * structure's children remain more stable in the variables view. + * + * This is null when not created for a logical structure. + */ + private final IJavaValue fLogicalParent; + + /** + * Constructs an array entry at the given index in an array. + * + * @param target + * debug target containing the array entry + * @param array + * array containing the entry + * @param index + * index into the array + * @param logicalParent + * original logical parent value, or null if not a + * child of a logical structure + */ + public JDIArrayEntryVariable(JDIDebugTarget target, ArrayReference array, + int index, IJavaValue logicalParent) { + super(target); + fArray = array; + fIndex = index; + fLogicalParent = logicalParent; + } + + /** + * Returns this variable's current underlying value. + */ + @Override + protected Value retrieveValue() { + ArrayReference ar = getArrayReference(); + if (ar != null) { + return ar.getValue(getIndex()); + } + return null; + } + + /** + * @see IVariable#getName() + */ + @Override + public String getName() { + return "[" + getIndex() + "]"; //$NON-NLS-2$ //$NON-NLS-1$ + } + + @Override + protected void setJDIValue(Value value) throws DebugException { + ArrayReference ar = getArrayReference(); + if (ar == null) { + requestFailed( + JDIDebugModelMessages.JDIArrayEntryVariable_value_modification_failed, + null); + } + try { + ar.setValue(getIndex(), value); + fireChangeEvent(DebugEvent.CONTENT); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_modifying_variable_value, + e.toString()), e); + } catch (InvalidTypeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_modifying_variable_value, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_modifying_variable_value, + e.toString()), e); + } + + } + + protected ArrayReference getArrayReference() { + return fArray; + } + + protected int getIndex() { + return fIndex; + } + + /** + * @see IVariable#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + try { + if (fReferenceTypeName == null) { + fReferenceTypeName = stripBrackets(JDIReferenceType + .getGenericName(getArrayReference().referenceType())); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_retrieving_reference_type, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + return fReferenceTypeName; + } + + /** + * Given a type name, strip out one set of array brackets and return the + * result. Example: "int[][][]" becomes "int[][]". + */ + protected String stripBrackets(String typeName) { + int lastLeft = typeName.lastIndexOf("[]"); //$NON-NLS-1$ + if (lastLeft < 0) { + return typeName; + } + StringBuilder buffer = new StringBuilder(typeName); + buffer.replace(lastLeft, lastLeft + 2, ""); //$NON-NLS-1$ + return buffer.toString(); + } + + /** + * @see IJavaVariable#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + return ((ArrayType) getArrayReference().type()) + .componentSignature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_retrieving_type_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + try { + ReferenceType referenceType = getArrayReference().referenceType(); + String genericSignature = referenceType.genericSignature(); + if (genericSignature != null) { + return genericSignature; + } + return referenceType.signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_retrieving_type_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * @see JDIVariable#getUnderlyingType() + */ + @Override + protected Type getUnderlyingType() throws DebugException { + try { + return ((ArrayType) getArrayReference().type()).componentType(); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_while_retrieving_type_of_array_entry, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayEntryVariable_exception_while_retrieving_type_of_array_entry, + e.toString()), e); + } + // this line will not be executed as an exception + // will be throw in type retrieval fails + return null; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof JDIArrayEntryVariable) { + JDIArrayEntryVariable entry = (JDIArrayEntryVariable) obj; + if (fLogicalParent != null) { + try { + return fLogicalParent.equals(entry.fLogicalParent) + && getValue().equals(entry.getValue()); + } catch (CoreException e) { + } + } + return entry.getArrayReference().equals(getArrayReference()) + && entry.getIndex() == getIndex(); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + if (fLogicalParent != null) { + return fLogicalParent.hashCode() + getIndex(); + } + return getArrayReference().hashCode() + getIndex(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayType.java new file mode 100644 index 0000000000..123b874bab --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayType.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaType; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Type; + +/** + * The type of an array + */ +public class JDIArrayType extends JDIReferenceType implements IJavaArrayType { + + /** + * Constructs a new array type on the given target referencing the specified + * array type. + */ + public JDIArrayType(JDIDebugTarget target, ArrayType type) { + super(target, type); + } + + /** + * @see IJavaArrayType#newInstance(int) + */ + @Override + public IJavaArray newInstance(int size) throws DebugException { + try { + ArrayReference ar = ((ArrayType) getUnderlyingType()) + .newInstance(size); + return (IJavaArray) JDIValue.createValue(getJavaDebugTarget(), ar); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayType_exception_while_creating_new_instance_of_array, + e.toString()), e); + } + // execution will not reach this line as + // an exception will be thrown + return null; + } + + /** + * @see IJavaArray#getComponentType() + */ + @Override + public IJavaType getComponentType() throws DebugException { + try { + Type type = ((ArrayType) getUnderlyingType()).componentType(); + return JDIType.createType(getJavaDebugTarget(), type); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayType_exception_while_retrieving_component_type_of_array, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayType_exception_while_retrieving_component_type_of_array, + e.toString()), e); + } + // execution will not reach this line as + // an exception will be thrown + return null; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayValue.java new file mode 100644 index 0000000000..5b635b6e35 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIArrayValue.java @@ -0,0 +1,307 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IIndexedValue; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaValue; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.Value; + +public class JDIArrayValue extends JDIObjectValue implements IJavaArray, + IIndexedValue { + + private int fLength = -1; + + /** + * Constructs a value which is a reference to an array. + * + * @param target + * debug target on which the array exists + * @param value + * the reference to the array + */ + public JDIArrayValue(JDIDebugTarget target, ArrayReference value) { + super(target, value); + } + + /** + * @see IJavaArray#getValues() + */ + @Override + public IJavaValue[] getValues() throws DebugException { + List list = getUnderlyingValues(); + + int count = list.size(); + IJavaValue[] values = new IJavaValue[count]; + JDIDebugTarget target = (JDIDebugTarget) getDebugTarget(); + for (int i = 0; i < count; i++) { + Value value = list.get(i); + values[i] = JDIValue.createValue(target, value); + } + return values; + } + + /** + * @see IJavaArray#getValue(int) + */ + @Override + public IJavaValue getValue(int index) throws DebugException { + Value v = getUnderlyingValue(index); + return JDIValue.createValue((JDIDebugTarget) getDebugTarget(), v); + } + + /** + * @see IJavaArray#getLength() + */ + @Override + public synchronized int getLength() throws DebugException { + if (fLength == -1) { + try { + fLength = getArrayReference().length(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_retrieving_array_length, + e.toString()), e); + } + } + return fLength; + } + + /** + * @see IJavaArray#setValue(int, IJavaValue) + */ + @Override + public void setValue(int index, IJavaValue value) throws DebugException { + try { + getArrayReference().setValue(index, + ((JDIValue) value).getUnderlyingValue()); + } catch (IndexOutOfBoundsException e) { + throw e; + } catch (InvalidTypeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_setting_value_in_array, + e.toString()), e); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_setting_value_in_array, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_setting_value_in_array, + e.toString()), e); + } + } + + /** + * Returns the underlying array reference for this array. + * + * @return underlying array reference + */ + @Override + protected ArrayReference getArrayReference() { + return (ArrayReference) getUnderlyingValue(); + } + + /** + * Returns the underlying value at the given index from the underlying array + * reference. + * + * @param index + * the index at which to retrieve a value + * @return value + * @exception DebugException + * if this method fails. Reasons include: + *

                    + *
                  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                  • + *
                  + */ + protected Value getUnderlyingValue(int index) throws DebugException { + try { + return getArrayReference().getValue(index); + } catch (IndexOutOfBoundsException e) { + throw e; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_retrieving_value_from_array, + e.toString()), e); + } + // execution will not reach this line as + // an exception will be thrown + return null; + } + + /** + * Returns the underlying values from the underlying array reference. + * + * @return list of values + * @exception DebugException + * if this method fails. Reasons include: + *
                    + *
                  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                  • + *
                  + */ + protected List getUnderlyingValues() throws DebugException { + try { + return getArrayReference().getValues(); + } catch (IndexOutOfBoundsException e) { + return Collections.EMPTY_LIST; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_retrieving_values_from_array, + e.toString()), e); + } + // execution will not reach this line as + // an exception will be thrown + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getSize() + */ + @Override + public int getSize() throws DebugException { + return getLength(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getVariable(int) + */ + @Override + public IVariable getVariable(int offset) throws DebugException { + if (offset >= getLength()) { + requestFailed(JDIDebugModelMessages.JDIArrayValue_6, new IndexOutOfBoundsException(Integer.toString(offset))); + } + return new JDIArrayEntryVariable(getJavaDebugTarget(), + getArrayReference(), offset, fLogicalParent); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getVariables(int, int) + */ + @Override + public IVariable[] getVariables(int offset, int length) + throws DebugException { + if (offset >= getLength()) { + requestFailed(JDIDebugModelMessages.JDIArrayValue_6, new IndexOutOfBoundsException(Integer.toString(offset))); + } + if ((offset + length - 1) >= getLength()) { + requestFailed(JDIDebugModelMessages.JDIArrayValue_8, new IndexOutOfBoundsException(Integer.toString(offset + length - 1))); + } + IVariable[] variables = new IVariable[length]; + int index = offset; + for (int i = 0; i < length; i++) { + variables[i] = new JDIArrayEntryVariable(getJavaDebugTarget(), + getArrayReference(), index, fLogicalParent); + index++; + } + return variables; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getInitialOffset() + */ + @Override + public int getInitialOffset() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IValue#hasVariables() + */ + @Override + public boolean hasVariables() throws DebugException { + return getLength() > 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaArray#setValues(int, int, + * org.eclipse.jdt.debug.core.IJavaValue[], int) + */ + @Override + public void setValues(int offset, int length, IJavaValue[] values, + int startOffset) throws DebugException { + try { + List list = new ArrayList<>(values.length); + for (IJavaValue value : values) { + list.add(((JDIValue) value).getUnderlyingValue()); + } + getArrayReference().setValues(offset, list, startOffset, length); + } catch (IndexOutOfBoundsException e) { + throw e; + } catch (InvalidTypeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_setting_value_in_array, + e.toString()), e); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_setting_value_in_array, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIArrayValue_exception_while_setting_value_in_array, + e.toString()), e); + } + + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaArray#setValues(org.eclipse.jdt.debug + * .core.IJavaValue[]) + */ + @Override + public void setValues(IJavaValue[] values) throws DebugException { + int length = Math.min(values.length, getSize()); + setValues(0, length, values, 0); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIClassObjectValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIClassObjectValue.java new file mode 100644 index 0000000000..757628f68b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIClassObjectValue.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaType; + +import com.sun.jdi.ClassObjectReference; + +/** + * An object on the target VM that is an instance of + * java.lang.Class. + * + * @see IJavaClassObject + */ +public class JDIClassObjectValue extends JDIObjectValue implements + IJavaClassObject { + + /** + * Constructs a reference to a class object. + */ + public JDIClassObjectValue(JDIDebugTarget target, + ClassObjectReference object) { + super(target, object); + } + + /** + * @see IJavaClassObject#getInstanceType() + */ + @Override + public IJavaType getInstanceType() { + return JDIType.createType((JDIDebugTarget) getDebugTarget(), + getUnderlyingClassObject().reflectedType()); + } + + /** + * Returns the underlying class object + */ + protected ClassObjectReference getUnderlyingClassObject() { + return (ClassObjectReference) getUnderlyingValue(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIClassType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIClassType.java new file mode 100644 index 0000000000..936bcab269 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIClassType.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; + +import com.sun.jdi.ClassType; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.Value; + +/** + * The class of an object in a debug target. + */ +public class JDIClassType extends JDIReferenceType implements IJavaClassType { + + /** + * Constructs a new class type on the given target referencing the specified + * class type. + */ + public JDIClassType(JDIDebugTarget target, ClassType type) { + super(target, type); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaClassType#newInstance(java.lang.String, + * org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread) + */ + @Override + public IJavaObject newInstance(String signature, IJavaValue[] args, + IJavaThread thread) throws DebugException { + if (getUnderlyingType() instanceof ClassType) { + ClassType clazz = (ClassType) getUnderlyingType(); + JDIThread javaThread = (JDIThread) thread; + List arguments = convertArguments(args); + Method method = null; + try { + List methods = clazz.methodsByName("", signature); //$NON-NLS-1$ + if (methods.isEmpty()) { + requestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_Type_does_not_implement_cosntructor, + signature), null); + } else { + method = methods.get(0); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_performing_method_lookup_for_constructor, + e.toString(), signature), e); + } + ObjectReference result = javaThread.newInstance(clazz, method, + arguments); + return (IJavaObject) JDIValue.createValue(getJavaDebugTarget(), + result); + } + requestFailed( + JDIDebugModelMessages.JDIClassType_Type_is_not_a_class_type, + null); + // execution will not fall through to here, + // as #requestFailed will throw an exception + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaClassType#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread) throws DebugException { + if (getUnderlyingType() instanceof ClassType) { + ClassType clazz = (ClassType) getUnderlyingType(); + JDIThread javaThread = (JDIThread) thread; + List arguments = convertArguments(args); + Method method = null; + try { + List methods = clazz.methodsByName(selector, signature); + if (methods.isEmpty()) { + requestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_Type_does_not_implement_selector, + selector, signature), null); + } else { + method = methods.get(0); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_performing_method_lookup_for_selector, + e.toString(), selector, signature), e); + } + Value result = javaThread.invokeMethod(clazz, null, method, + arguments, false); + return JDIValue.createValue(getJavaDebugTarget(), result); + } + requestFailed( + JDIDebugModelMessages.JDIClassType_Type_is_not_a_class_type, + null); + // execution will not fall through to here, + // as #requestFailed will throw an exception + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaClassType#getSuperclass() + */ + @Override + public IJavaClassType getSuperclass() throws DebugException { + try { + ClassType superclazz = ((ClassType) getUnderlyingType()) + .superclass(); + if (superclazz != null) { + return (IJavaClassType) JDIType.createType( + getJavaDebugTarget(), superclazz); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_superclass, + e.toString()), e); + } + // it is possible to return null + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaClassType#getAllInterfaces() + */ + @Override + public IJavaInterfaceType[] getAllInterfaces() throws DebugException { + try { + List interfaceList = ((ClassType) getUnderlyingType()) + .allInterfaces(); + List javaInterfaceTypeList = new ArrayList<>(interfaceList.size()); + for(InterfaceType interfaceType : interfaceList) { + if (interfaceType != null) { + javaInterfaceTypeList.add(JDIType.createType( + getJavaDebugTarget(), interfaceType)); + } + } + IJavaInterfaceType[] javaInterfaceTypeArray = new IJavaInterfaceType[javaInterfaceTypeList + .size()]; + javaInterfaceTypeArray = javaInterfaceTypeList + .toArray(javaInterfaceTypeArray); + return javaInterfaceTypeArray; + } catch (RuntimeException re) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_superclass, + re.toString()), re); + } + return new IJavaInterfaceType[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaClassType#getInterfaces() + */ + @Override + public IJavaInterfaceType[] getInterfaces() throws DebugException { + try { + List interfaceList = ((ClassType) getUnderlyingType()).interfaces(); + List javaInterfaceTypeList = new ArrayList<>(interfaceList.size()); + for(InterfaceType interfaceType : interfaceList) { + if (interfaceType != null) { + javaInterfaceTypeList.add(JDIType.createType( + getJavaDebugTarget(), interfaceType)); + } + } + IJavaInterfaceType[] javaInterfaceTypeArray = new IJavaInterfaceType[javaInterfaceTypeList + .size()]; + javaInterfaceTypeArray = javaInterfaceTypeList + .toArray(javaInterfaceTypeArray); + return javaInterfaceTypeArray; + } catch (RuntimeException re) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_superclass, + re.toString()), re); + } + return new IJavaInterfaceType[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaClassType#isEnum() + */ + @Override + public boolean isEnum() { + return ((ClassType) getReferenceType()).isEnum(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugElement.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugElement.java new file mode 100644 index 0000000000..c18433f594 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugElement.java @@ -0,0 +1,450 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.DebugElement; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IDisconnect; +import org.eclipse.debug.core.model.IStepFilters; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.jdi.TimeoutException; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.EventDispatcher; +import org.eclipse.jdt.internal.debug.core.IJDIEventListener; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; + +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; + +public abstract class JDIDebugElement extends DebugElement implements + IDisconnect { + + /** + * Creates a JDI debug element associated with the specified debug target. + * + * @param target + * The associated debug target + */ + public JDIDebugElement(JDIDebugTarget target) { + super(target); + } + + /** + * Convenience method to log errors + */ + protected void logError(Exception e) { + if (!((JDIDebugTarget) getDebugTarget()).isAvailable()) { + // Don't log VMDisconnectedExceptions that occur + // when the VM is unavailable. + if (e instanceof VMDisconnectedException + || (e instanceof CoreException && ((CoreException) e) + .getStatus().getException() instanceof VMDisconnectedException)) { + return; + } + } + JDIDebugPlugin.log(e); + } + + /** + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter == IDebugElement.class) { + return (T) this; + } + if (adapter == IStepFilters.class) { + return (T) getDebugTarget(); + } + if (adapter == IDebugTarget.class) { + return (T) getDebugTarget(); + } + if (adapter == ITerminate.class) { + return (T) getDebugTarget(); + } + if (adapter == IJavaDebugTarget.class) { + return (T) getJavaDebugTarget(); + } + return super.getAdapter(adapter); + } + + /** + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + @Override + public String getModelIdentifier() { + return JDIDebugModel.getPluginIdentifier(); + } + + /** + * Queues a debug event with the event dispatcher to be fired as an event + * set when all event processing is complete. + * + * @param event + * the event to queue + * @param set + * the event set the event is associated with + */ + public void queueEvent(DebugEvent event, EventSet set) { + EventDispatcher dispatcher = ((JDIDebugTarget) getDebugTarget()) + .getEventDispatcher(); + if (dispatcher != null) { + dispatcher.queue(event, set); + } + } + + /** + * Fires a debug event marking the SUSPEND of this element with the + * associated detail. + * + * @param detail + * The int detail of the event + * @see org.eclipse.debug.core.DebugEvent + */ + @Override + public void fireSuspendEvent(int detail) { + getJavaDebugTarget().incrementSuspendCount(detail); + super.fireSuspendEvent(detail); + } + + /** + * Queues a debug event marking the SUSPEND of this element with the + * associated detail. + * + * @param detail + * The int detail of the event + * @param set + * the event set the event is associated with + * @see org.eclipse.debug.core.DebugEvent + */ + public void queueSuspendEvent(int detail, EventSet set) { + getJavaDebugTarget().incrementSuspendCount(detail); + queueEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail), set); + } + + /** + * Throws a new debug exception with a status code of + * REQUEST_FAILED. + * + * @param message + * Failure message + * @param e + * Exception that has occurred (can be null) + * @throws DebugException + * The exception with a status code of + * REQUEST_FAILED + */ + public void requestFailed(String message, Exception e) + throws DebugException { + requestFailed(message, e, DebugException.REQUEST_FAILED); + } + + /** + * Throws a new debug exception with a status code of + * TARGET_REQUEST_FAILED with the given underlying exception. + * If the underlying exception is not a JDI exception, the original + * exception is thrown. + * + * @param message + * Failure message + * @param e + * underlying exception that has occurred + * @throws DebugException + * The exception with a status code of + * TARGET_REQUEST_FAILED + */ + public void targetRequestFailed(String message, RuntimeException e) + throws DebugException { + if (e == null + || e.getClass().getName().startsWith("com.sun.jdi") || e instanceof TimeoutException) { //$NON-NLS-1$ + requestFailed(message, e, DebugException.TARGET_REQUEST_FAILED); + } else { + throw e; + } + } + + /** + * Throws a new debug exception with the given status code. + * + * @param message + * Failure message + * @param e + * Exception that has occurred (can be null) + * @param code + * status code + * @throws DebugException + * a new exception with given status code + */ + public void requestFailed(String message, Throwable e, int code) + throws DebugException { + throwDebugException(message, code, e); + } + + /** + * Throws a new debug exception with a status code of + * TARGET_REQUEST_FAILED. + * + * @param message + * Failure message + * @param e + * Throwable that has occurred + * @throws DebugException + * The exception with a status code of + * TARGET_REQUEST_FAILED + */ + public void targetRequestFailed(String message, Throwable e) + throws DebugException { + throwDebugException(message, DebugException.TARGET_REQUEST_FAILED, e); + } + + /** + * Throws a new debug exception with a status code of + * TARGET_REQUEST_FAILED with the given underlying exception. + * The underlying exception is an exception thrown by a JDI request. + * + * @param message + * Failure message + * @param e + * throwable exception that has occurred + * @throws DebugException + * the exception with a status code of + * TARGET_REQUEST_FAILED + */ + public void jdiRequestFailed(String message, Throwable e) + throws DebugException { + throwDebugException(message, DebugException.TARGET_REQUEST_FAILED, e); + } + + /** + * Throws a new debug exception with a status code of + * NOT_SUPPORTED. + * + * @param message + * Failure message + * @throws DebugException + * The exception with a status code of + * NOT_SUPPORTED. + */ + public void notSupported(String message) throws DebugException { + throwDebugException(message, DebugException.NOT_SUPPORTED, null); + } + + /** + * Throws a debug exception with the given message, error code, and + * underlying exception. + */ + protected void throwDebugException(String message, int code, + Throwable exception) throws DebugException { + if (exception instanceof VMDisconnectedException) { + disconnected(); + } + throw new DebugException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), code, message, exception)); + } + + /** + * Logs the given exception if it is a JDI exception, otherwise throws the + * runtime exception. + * + * @param e + * The internal runtime exception + */ + public void internalError(RuntimeException e) { + if (e.getClass().getName().startsWith("com.sun.jdi") || e instanceof TimeoutException) { //$NON-NLS-1$ + logError(e); + } else { + throw e; + } + } + + /** + * Logs a debug exception with the given message, with a status code of + * INTERNAL_ERROR. + * + * @param message + * The internal error message + */ + protected void internalError(String message) { + logError(new DebugException(new Status(IStatus.ERROR, + JDIDebugModel.getPluginIdentifier(), + DebugException.INTERNAL_ERROR, message, null))); + } + + /** + * Returns the common "<unknown>" message. + * + * @return the unknown String + */ + protected String getUnknownMessage() { + return JDIDebugModelMessages.JDIDebugElement_unknown; + } + + /** + * Returns this elements debug target as its implementation class. + * + * @return Java debug target + */ + public JDIDebugTarget getJavaDebugTarget() { + return (JDIDebugTarget) getDebugTarget(); + } + + /** + * Returns the target VM associated with this element, or null + * if none. + * + * @return target VM or null if none + */ + protected VirtualMachine getVM() { + return ((JDIDebugTarget) getDebugTarget()).getVM(); + } + + /** + * Returns the underlying VM's event request manager, or null + * if none (disconnected/terminated) + * + * @return event request manager or null + */ + public EventRequestManager getEventRequestManager() { + VirtualMachine vm = getVM(); + if (vm == null) { + return null; + } + return vm.eventRequestManager(); + } + + /** + * Adds the given listener to this target's event dispatcher's table of + * listeners for the specified event request. The listener will be notified + * each time the event occurs. + * + * @param listener + * the listener to register + * @param request + * the event request + */ + public void addJDIEventListener(IJDIEventListener listener, + EventRequest request) { + EventDispatcher dispatcher = ((JDIDebugTarget) getDebugTarget()) + .getEventDispatcher(); + if (dispatcher != null) { + dispatcher.addJDIEventListener(listener, request); + } + } + + /** + * Removes the given listener from this target's event dispatcher's table of + * listeners for the specifed event request. The listener will no longer be + * notified when the event occurs. Listeners are responsible for deleting + * the event request if desired. + * + * @param listener + * the listener to remove + * @param request + * the event request + */ + public void removeJDIEventListener(IJDIEventListener listener, + EventRequest request) { + EventDispatcher dispatcher = ((JDIDebugTarget) getDebugTarget()) + .getEventDispatcher(); + if (dispatcher != null) { + dispatcher.removeJDIEventListener(listener, request); + } + } + + /** + * The VM has disconnected. Notify the target. + */ + protected void disconnected() { + if (getDebugTarget() != null) { + getJavaDebugTarget().disconnected(); + } + } + + /** + * @see IJavaDebugTarget#setRequestTimeout(int) + */ + public void setRequestTimeout(int timeout) { + if (supportsRequestTimeout()) { + VirtualMachine vm = getVM(); + if (vm != null) { + ((org.eclipse.jdi.VirtualMachine) vm) + .setRequestTimeout(timeout); + } + } + } + + /** + * @see IJavaDebugTarget#getRequestTimeout() + */ + public int getRequestTimeout() { + if (supportsRequestTimeout()) { + VirtualMachine vm = getVM(); + if (vm != null) { + return ((org.eclipse.jdi.VirtualMachine) vm) + .getRequestTimeout(); + } + } + return -1; + } + + /** + * @see IJavaDebugTarget#supportsRequestTimeout() + */ + public boolean supportsRequestTimeout() { + return getJavaDebugTarget().isAvailable() + && getVM() instanceof org.eclipse.jdi.VirtualMachine; + } + + /** + * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect() + */ + @Override + public boolean canDisconnect() { + return getDebugTarget().canDisconnect(); + } + + /** + * @see org.eclipse.debug.core.model.IDisconnect#disconnect() + */ + @Override + public void disconnect() throws DebugException { + getDebugTarget().disconnect(); + } + + /** + * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected() + */ + @Override + public boolean isDisconnected() { + return getDebugTarget().isDisconnected(); + } + + /** + * @see org.eclipse.debug.core.model.IStepFilters#isStepFiltersEnabled() + */ + public boolean isStepFiltersEnabled() { + return getJavaDebugTarget().isStepFiltersEnabled(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java new file mode 100644 index 0000000000..0b0fcf2280 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java @@ -0,0 +1,241 @@ +/******************************************************************************* + * Copyright (c) 2000, 2018 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.osgi.util.NLS; + +public class JDIDebugModelMessages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.core.model.JDIDebugModelMessages";//$NON-NLS-1$ + + public static String JDIArrayEntryVariable_exception_modifying_variable_value; + public static String JDIArrayEntryVariable_exception_retrieving_reference_type; + public static String JDIArrayEntryVariable_exception_retrieving_type_signature; + public static String JDIArrayEntryVariable_exception_while_retrieving_type_of_array_entry; + public static String JDIArrayEntryVariable_value_modification_failed; + + public static String JDIArrayType_exception_while_creating_new_instance_of_array; + public static String JDIArrayType_exception_while_retrieving_component_type_of_array; + + public static String JDIArrayValue_exception_while_retrieving_array_length; + public static String JDIArrayValue_exception_while_retrieving_value_from_array; + public static String JDIArrayValue_exception_while_retrieving_values_from_array; + public static String JDIArrayValue_exception_while_setting_value_in_array; + public static String JDIArrayValue_6; + public static String JDIArrayValue_8; + + public static String JDIClassType_exception_while_performing_method_lookup_for_constructor; + public static String JDIClassType_exception_while_performing_method_lookup_for_selector; + public static String JDIClassType_exception_while_retrieving_class_object; + public static String JDIClassType_exception_while_retrieving_field; + public static String JDIClassType_exception_while_retrieving_superclass; + public static String JDIClassType_Type_does_not_implement_cosntructor; + public static String JDIClassType_Type_does_not_implement_selector; + public static String JDIClassType_Type_is_not_a_class_type; + + public static String JDIDebugElement_unknown; + + public static String JDIDebugTarget_2; + + public static String JDIDebugTarget_4; + public static String JDIDebugTarget_does_not_support_disconnect; + public static String JDIDebugTarget_does_not_support_storage_retrieval; + public static String JDIDebugTarget_does_not_support_termination; + public static String JDIDebugTarget_exception_disconnecting; + public static String JDIDebugTarget_exception_resume; + public static String JDIDebugTarget_exception_retrieving_version_information; + public static String JDIDebugTarget_exception_suspend; + public static String JDIDebugTarget_exception_terminating; + public static String JDIDebugTarget_JDI_Event_Dispatcher; + public static String JDIDebugTarget_Unable_to_create_class_prepare_request___VM_disconnected__2; + public static String JDIDebugTarget_Unable_to_create_class_prepare_request__3; + public static String JDIDebugTarget_Unable_to_retrieve_types___VM_disconnected__4; + public static String JDIDebugTarget_0; + public static String JDIDebugTarget_ThreadNameNotifier; + + public static String JDIFieldVariable_exception_modifying_value; + public static String JDIFieldVariable_exception_retrieving_field_name; + public static String JDIFieldVariable_exception_retrieving_field_signature; + public static String JDIFieldVariable_exception_while_retrieving_type_of_field; + + public static String JDILocalVariable_exception_modifying_local_variable_value; + public static String JDILocalVariable_exception_retrieving_local_variable_name; + public static String JDILocalVariable_exception_retrieving_local_variable_type_name; + public static String JDILocalVariable_exception_retrieving_local_variable_type_signature; + public static String JDILocalVariable_exception_while_retrieving_type_of_local_variable; + + public static String JDIModificationVariable_0; + + public static String JDIModificationVariable_Unable_to_generate_value___VM_disconnected__1; + + public static String JDINullValue_0; + + public static String JDIObjectValue_12; + + public static String JDIObjectValue_13; + + public static String JDIObjectValue_14; + + public static String JDIObjectValue_exception_retrieving_field; + public static String JDIObjectValue_exception_retrieving_reference_type; + public static String JDIObjectValue_exception_while_performing_method_lookup_for_selector; + public static String JDIObjectValue_11; + public static String JDIObjectValue_0; + public static String JDIObjectValue_1; + + public static String JDIReferenceListValue_0; + public static String JDIReferenceListValue_2; + public static String JDIReferenceListValue_3; + public static String JDIReferenceListValue_4; + public static String JDIReferenceListValue_6; + public static String JDIReferenceListValue_7; + public static String JDIReferenceListValue_8; + public static String JDIReferenceListValue_9; + public static String JDIReferenceListValue_11; + public static String JDIReferenceListValue_15; + + public static String JDIReferenceType_5; + + public static String JDIStackFrame__unknown_declaring_type__1; + public static String JDIStackFrame__unknown_method__1; + public static String JDIStackFrame__unknown_receiving_type__2; + + public static String JDIStackFrame_26; + public static String JDIStackFrame_Drop_to_frame_not_supported; + public static String JDIStackFrame_exception_retreiving_declaring_type; + public static String JDIStackFrame_exception_retrieving_argument_type_names; + public static String JDIStackFrame_exception_retrieving_declaring_type; + public static String JDIStackFrame_exception_retrieving_fields; + public static String JDIStackFrame_exception_retrieving_line_number; + public static String JDIStackFrame_exception_retrieving_method_name; + public static String JDIStackFrame_exception_retrieving_method_signature; + public static String JDIStackFrame_exception_retrieving_receiving_type; + public static String JDIStackFrame_exception_retrieving_source_name; + public static String JDIStackFrame_exception_retrieving_source_path; + public static String JDIStackFrame_exception_retrieving_this; + public static String JDIStackFrame_exception_retrieving_visible_variables_2; + public static String JDIStackFrame_exception_retrieving_visible_variables; + public static String JDIStackFrame_pop_frame_not_supported; + public static String JDIStackFrame_Variable_information_unavailable_for_native_methods; + public static String JDIStackFrame_ReturnValue; + public static String JDIStackFrame_ReturningValue; + public static String JDIStackFrame_ExceptionThrown; + public static String JDIStackFrame_ThrowingException; + public static String JDIStackFrame_NoMethodReturnValue; + public static String JDIStackFrame_NotObservedBecauseOfTimeout; + public static String JDIStackFrame_NoLongerAvailable; + + public static String JDIThisVariable_exception_while_retrieving_type_this; + public static String JDIThisVariableexception_retrieving_reference_type_name; + public static String JDIThisVariableexception_retrieving_type_signature; + public static String JDIThisVariable_Exception_occurred_while_retrieving_modifiers__1; + + public static String JDIThread_47; + + public static String JDIThread_48; + + public static String JDIThread_can_only_specify_one_receiver_for_a_method_invocation; + public static String JDIThread_Cannot_perform_nested_evaluations_2; + public static String JDIThread_Cannot_perform_nested_evaluations; + public static String JDIThread_Evaluation_failed___thread_not_suspended; + public static String JDIThread_exception_creating_step_request; + public static String JDIThread_exception_determining_if_system_thread; + public static String JDIThread_exception_dropping_to_frame; + public static String JDIThread_exception_invoking_method; + public static String JDIThread_exception_popping; + public static String JDIThread_exception_resuming; + public static String JDIThread_exception_retrieving_frame_count; + + public static String JDIThread_exception_retrieving_stack_frames_2; + public static String JDIThread_exception_retrieving_thread_group_name; + public static String JDIThread_exception_retrieving_thread_group; + public static String JDIThread_exception_retrieving_thread_name; + public static String JDIThread_exception_retrieving_thread_priority; + public static String JDIThread_exception_stepping; + public static String JDIThread_exception_suspending; + public static String JDIThread_exception_while_popping_stack_frame; + public static String JDIThread_no_priority_field; + public static String JDIThread_priority_not_an_integer; + public static String JDIThread_Thread_must_be_suspended_by_step_or_breakpoint_to_perform_method_invocation_1; + public static String JDIThread_suspend_timeout; + public static String JDIThread_garbage_collected_1; + public static String JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1; + public static String JDIThread_Unable_to_create_step_request___VM_disconnected__1; + public static String JDIThread_Unable_to_create_step_request___VM_disconnected__2; + public static String JDIThread_39; + + public static String JDIThread_42; + public static String JDIThread_43; + public static String JDIThread_44; + public static String JDIThread_45; + public static String JDIThread_46; + public static String JDIThread_0; + + public static String JDIThread_1; + + public static String JDIType_exception_while_retrieving_signature; + public static String JDIType_exception_while_retrieving_type_name; + + public static String JDIValue_deallocated; + public static String JDIValue_exception_is_collected; + public static String JDIValue_exception_retrieving_fields; + public static String JDIValue_exception_retrieving_length_of_array; + public static String JDIValue_exception_retrieving_reference_type_name; + public static String JDIValue_exception_retrieving_type_signature; + public static String JDIValue_exception_retrieving_type; + public static String JDIValue_exception_retrieving_unique_id; + public static String JDIValue_exception_retrieving_value; + public static String JDIValue_id_8; + public static String JDIValue_null_4; + + public static String JDIVariable_does_not_support_value_modification; + public static String JDIVariable_exception_retrieving; + + public static String Timer_Timer_cannot_be_started_more_than_once_1; + + public static String JDIObjectValueMethod_declaring_type_not_found_1; + public static String JDIObjectValue_method_lookup_failed_for_selector____0____with_signature____1___1; + public static String JDIThread_exception_stoping_thread; + + public static String JDIReferenceType_2; + public static String JDIReferenceType_3; + public static String JDIReferenceType_0; + public static String JDIReferenceType_1; + public static String JDIStackFrame_25; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, JDIDebugModelMessages.class); + } + + public static String JDIStackFrame_0; + + public static String JDIFieldVariable_0; + + public static String JDIReferenceType_4; + + public static String JDIThreadGroup_0; + + public static String JDIThreadGroup_1; + + public static String JDIThreadGroup_2; + + public static String JDIThreadGroup_3; + + public static String JDIThreadGroup_4; + + public static String JDIThreadGroup_5; + + public static String JDIDebugTarget_1; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties new file mode 100644 index 0000000000..75fce958f2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties @@ -0,0 +1,211 @@ +############################################################################### +# Copyright (c) 2000, 2018 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +JDIArrayEntryVariable_exception_modifying_variable_value={0} occurred while modifying variable value. +JDIArrayEntryVariable_exception_retrieving_reference_type={0} occurred retrieving reference type. +JDIArrayEntryVariable_exception_retrieving_type_signature={0} occurred retrieving type signature. +JDIArrayEntryVariable_exception_while_retrieving_type_of_array_entry={0} occurred while retrieving type of array entry. +JDIArrayEntryVariable_value_modification_failed=Value modification failed - unable to retrieve array. + +JDIArrayType_exception_while_creating_new_instance_of_array={0} occurred while creating new instance of array. +JDIArrayType_exception_while_retrieving_component_type_of_array={0} occurred while retrieving component type of array. + +JDIArrayValue_exception_while_retrieving_array_length={0} occurred while retrieving array length. +JDIArrayValue_exception_while_retrieving_value_from_array={0} occurred while retrieving value from array. +JDIArrayValue_exception_while_retrieving_values_from_array={0} occurred while retrieving values from array. +JDIArrayValue_exception_while_setting_value_in_array={0} occurred while setting value in array. +JDIArrayValue_6=Index out of bounds. +JDIArrayValue_8=Specified range out of bounds. + +JDIClassType_exception_while_performing_method_lookup_for_constructor={0} occurred while performing method lookup for constructor with signature {1} +JDIClassType_exception_while_performing_method_lookup_for_selector={0} occurred while performing method lookup for selector {1} and signature {2} +JDIClassType_exception_while_retrieving_class_object={0} occurred while retrieving class object +JDIClassType_exception_while_retrieving_field={0} occurred while retrieving field {1} +JDIClassType_exception_while_retrieving_superclass={0} occurred while retrieving superclass +JDIClassType_Type_does_not_implement_cosntructor=Type does not implement constructor with signature {0} +JDIClassType_Type_does_not_implement_selector=Type does not implement selector {0} and signature {1} +JDIClassType_Type_is_not_a_class_type=Type is not a class type. + +JDIDebugElement_unknown= +JDIDebugTarget_does_not_support_disconnect=VM does not support 'disconnect'. +JDIDebugTarget_does_not_support_storage_retrieval=Does not support memory block retrieval +JDIDebugTarget_does_not_support_termination=VM does not support termination. +JDIDebugTarget_exception_disconnecting={0} occurred disconnecting from VM. +JDIDebugTarget_exception_resume={0} occurred resuming VM. +JDIDebugTarget_exception_retrieving_version_information={0} occurred retrieving version information for {1}. +JDIDebugTarget_exception_suspend={0} occurred suspending VM. +JDIDebugTarget_exception_terminating={0} occurred while terminating VM. +JDIDebugTarget_JDI_Event_Dispatcher=: JDI Event Dispatcher +JDIDebugTarget_Unable_to_create_class_prepare_request___VM_disconnected__2=Unable to create class prepare request - VM disconnected. +JDIDebugTarget_Unable_to_create_class_prepare_request__3=Unable to create class prepare request. +JDIDebugTarget_Unable_to_retrieve_types___VM_disconnected__4=Unable to retrieve types - VM disconnected. + +JDIFieldVariable_exception_modifying_value={0} occurred modifying value. +JDIFieldVariable_exception_retrieving_field_name={0} occurred retrieving field name. +JDIFieldVariable_exception_retrieving_field_signature={0} occurred retrieving field signature. +JDIFieldVariable_exception_while_retrieving_type_of_field={0} occurred while retrieving type of field. + +JDILocalVariable_exception_modifying_local_variable_value={0} occurred modifying local variable value. +JDILocalVariable_exception_retrieving_local_variable_name={0} occurred retrieving local variable name. +JDILocalVariable_exception_retrieving_local_variable_type_name={0} occurred retrieving local variable type name. +JDILocalVariable_exception_retrieving_local_variable_type_signature={0} occurred retrieving local variable type signature. +JDILocalVariable_exception_while_retrieving_type_of_local_variable={0} occurred while retrieving type of local variable. + +JDIModificationVariable_0=The value''s format is incompatible with type {0} +JDIModificationVariable_Unable_to_generate_value___VM_disconnected__1=Unable to generate value - VM disconnected. + +JDIObjectValue_exception_retrieving_field={0} occurred retrieving field. +JDIObjectValue_exception_retrieving_reference_type={0} occurred retrieving reference type. +JDIObjectValue_exception_while_performing_method_lookup_for_selector={0} occurred while performing method lookup for selector \"{1}\" with signature \"{2}\" +JDIObjectValue_11=Method "{0}" with signature "{1}" is not applicable on this object +JDIObjectValue_12=Unable to retrieve references +JDIObjectValue_13=Disabling garbage collection failed. +JDIObjectValue_14=Enabling garbage collection failed. +JDIObjectValue_0=Failed to retrieve waiting threads +JDIObjectValue_1=Failed to retrieve owning thread + +JDIStackFrame__unknown_declaring_type__1= +JDIStackFrame__unknown_method__1= +JDIStackFrame__unknown_receiving_type__2= +JDIStackFrame_Drop_to_frame_not_supported=Drop to frame not supported. +JDIStackFrame_exception_retreiving_declaring_type={0} occurred retrieving declaring type. +JDIStackFrame_exception_retrieving_argument_type_names={0} occurred retrieving argument type names. +JDIStackFrame_exception_retrieving_declaring_type={0} occurred retrieving declaring type. +JDIStackFrame_exception_retrieving_fields={0} occurred retrieving fields of declaring type. +JDIStackFrame_exception_retrieving_line_number={0} occurred retrieving line number. +JDIStackFrame_exception_retrieving_method_name={0} occurred retrieving method name. +JDIStackFrame_exception_retrieving_method_signature={0} occurred retrieving method signature. +JDIStackFrame_exception_retrieving_receiving_type={0} occurred retrieving receiving type. +JDIStackFrame_exception_retrieving_source_name={0} occurred retrieving source name debug attribute. +JDIStackFrame_exception_retrieving_source_path={0} occurred retrieving source path debug attribute. +JDIStackFrame_exception_retrieving_this={0} occurred retrieving ''this'' from stack frame. +JDIStackFrame_exception_retrieving_visible_variables_2={0} occurred retrieving visible variables. +JDIStackFrame_exception_retrieving_visible_variables={0} occurred retrieving visible variables. +JDIStackFrame_pop_frame_not_supported=Popping frames not supported. +JDIStackFrame_Variable_information_unavailable_for_native_methods=Variable information unavailable for native methods +JDIStackFrame_ReturnValue={0}() returned +JDIStackFrame_ReturningValue={0}() is returning +JDIStackFrame_ExceptionThrown={0}() threw +JDIStackFrame_ThrowingException={0}() is throwing +JDIStackFrame_NoMethodReturnValue=no method return value +JDIStackFrame_NotObservedBecauseOfTimeout=(Not observed to speed up the long running step operation) +JDIStackFrame_NoLongerAvailable=Stack frame is no longer available + +JDIThisVariable_exception_while_retrieving_type_this={0} occurred while retrieving type ''this''. +JDIThisVariableexception_retrieving_reference_type_name={0} occurred retrieving reference type name. +JDIThisVariableexception_retrieving_type_signature={0} occurred retrieving type signature. +JDIThisVariable_Exception_occurred_while_retrieving_modifiers__1=Exception occurred while retrieving modifiers. + +JDIThread_can_only_specify_one_receiver_for_a_method_invocation=Internal error - can only specify one receiver for a method invocation +JDIThread_Cannot_perform_nested_evaluations_2=Cannot perform nested evaluations +JDIThread_Cannot_perform_nested_evaluations=Cannot perform nested evaluations. +JDIThread_Evaluation_failed___thread_not_suspended=Evaluation failed - thread not suspended. +JDIThread_exception_creating_step_request={0} occurred creating step request. +JDIThread_exception_determining_if_system_thread={0} occurred while determining if thread is a ''System'' thread. +JDIThread_exception_dropping_to_frame={0} occurred while dropping to stack frame. +JDIThread_exception_invoking_method={0} occurred invoking method. +JDIThread_exception_popping={0} occurred popping stack frame. +JDIThread_exception_resuming={0} occurred resuming thread. +JDIThread_exception_retrieving_frame_count={0} occurred retrieving frame count. + +JDIThread_exception_retrieving_stack_frames_2={0} occurred retrieving stack frames. +JDIThread_exception_retrieving_thread_group_name={0} occurred retrieving thread group name. +JDIThread_exception_retrieving_thread_group={0} occurred retrieving thread group. +JDIThread_exception_retrieving_thread_name={0} occurred retrieving thread name. +JDIThread_exception_retrieving_thread_priority={0} occurred retrieving thread priority. +JDIThread_exception_stepping={0} occurred stepping in thread. +JDIThread_exception_suspending={0} occurred suspending thread. +JDIThread_exception_while_popping_stack_frame={0} occurred while popping stack frame. +JDIThread_no_priority_field=Unable to find 'priority' field in thread. +JDIThread_priority_not_an_integer=Value of thread 'priority' is not an integer. +JDIThread_Thread_must_be_suspended_by_step_or_breakpoint_to_perform_method_invocation_1=Thread must be suspended by step or breakpoint to perform method invocation +JDIThread_suspend_timeout=Thread did not suspend within specified timeout: {0} (ms) +JDIThread_garbage_collected_1=garbage collected +JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1=Unable to retrieve stack frame - thread not suspended. +JDIThread_Unable_to_create_step_request___VM_disconnected__1=Unable to create step request - VM disconnected. +JDIThread_Unable_to_create_step_request___VM_disconnected__2=Unable to create step request - VM disconnected. +JDIThread_39=JDI thread evaluations + +JDIThread_42=disconnected +JDIThread_43=Failed to retrieve owned monitor. +JDIThread_44=Failed to retrieve owned monitor. +JDIThread_45=Failed to retrieve contended monitor. +JDIThread_46=Failed to retrieve contended monitor. +JDIThread_47=Unable to determine thread daemon status +JDIThread_48=Force return failed. +JDIThread_0=Exception processing async thread queue +JDIThread_1=Suspend failed waiting for an expression evaluation to complete. +JDIThreadGroup_0=Error retrieving threads in thread group +JDIThreadGroup_1=Error retrieving parent of thread group +JDIThreadGroup_2=Error retrieving groups in thread group +JDIThreadGroup_3=Error retrieving thread group name +JDIThreadGroup_4=Error retrieving groups in thread group +JDIThreadGroup_5=Error retrieving threads in thread group +JDIType_exception_while_retrieving_signature={0} occurred while retrieving signature. +JDIType_exception_while_retrieving_type_name={0} occurred while retrieving type name. + +JDIValue_deallocated=deallocated +JDIValue_exception_is_collected={0} occurred determining if object has been garbage collected. +JDIValue_exception_retrieving_fields={0} occurred retrieving fields. +JDIValue_exception_retrieving_length_of_array={0} occurred retrieving length of array. +JDIValue_exception_retrieving_reference_type_name={0} occurred retrieving reference type name. +JDIValue_exception_retrieving_type_signature={0} occurred retrieving type signature. +JDIValue_exception_retrieving_type={0} occurred retrieving type +JDIValue_exception_retrieving_unique_id={0} occurred retrieving unique id. +JDIValue_exception_retrieving_value={0} occurred retrieving value. +JDIValue_id_8=(id={0}) +JDIValue_null_4=null + +JDIVariable_does_not_support_value_modification=Variable does not support value modification. +JDIVariable_exception_retrieving={0} occurred while retrieving value. + +Timer_Timer_cannot_be_started_more_than_once_1=Timer cannot be started more than once + +JDIObjectValueMethod_declaring_type_not_found_1=Method declaring type not found +JDIObjectValue_method_lookup_failed_for_selector____0____with_signature____1___1=method lookup failed for selector \"{0}\" with signature \"{1}" +JDIThread_exception_stoping_thread={0} occurred stopping thread. + +JDIReferenceType_2=Exception occurred while retrieving fields. +JDIReferenceType_3=Exception occurred while retrieving declared fields. +JDIReferenceType_0={0} occurred while retrieving class loader +JDIReferenceType_1=Unable to retrieve default stratum +JDIReferenceType_4=Error retrieving source debug attribute +JDIReferenceType_5=Unable to retrieve instances + +JDIReferenceListValue_0=[{0}] +JDIReferenceListValue_2=No references +JDIReferenceListValue_3={0} reference:\n +JDIReferenceListValue_4={0} references:\n +JDIReferenceListValue_6=''{0}'' referenced from: +JDIReferenceListValue_7=Failed to retrieve variable +JDIReferenceListValue_8=Failed to retrieve variables +JDIReferenceListValue_9=Display limited to {0} references, see Heap Walking preference page. +JDIReferenceListValue_11=... +JDIReferenceListValue_15={0}+ + +JDIFieldVariable_0=Unable to perform an assignment to a field declared in an interface +JDIStackFrame_25=Invalid stack frame + +# This is for the 'force return' function. When a user forces a method to return +# the returned expression's value has to be compatible with the declared +# return type of the method. +JDIStackFrame_26=Return value not assignment compatible with method return type + +JDIStackFrame_0=Declaring type is not a class +JDINullValue_0=java.lang.NullPointerException at {0} +JDIDebugTarget_0=Disconnecting Java Debug Target +JDIDebugTarget_1=Error retrieving top level thread groups +JDIDebugTarget_2=Unable to retrieve name +JDIDebugTarget_4=Unable to retrieve version +JDIDebugTarget_ThreadNameNotifier=Thread name change notifier diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java new file mode 100644 index 0000000000..5a6cfa5ded --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java @@ -0,0 +1,3331 @@ +/******************************************************************************* + * Copyright (c) 2000, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Moller - enhancement 254677 - filter getters/setters + * Andrey Loskutov - bug 5188 - breakpoint filtering + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.io.IOException; +import java.net.URI; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.IBreakpointManagerListener; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchListener; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.ISuspendResume; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.jdi.TimeoutException; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.core.search.TypeNameMatch; +import org.eclipse.jdt.core.search.TypeNameMatchRequestor; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaThreadGroup; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.eval.EvaluationManager; +import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; +import org.eclipse.jdt.internal.debug.core.EventDispatcher; +import org.eclipse.jdt.internal.debug.core.IJDIEventListener; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint; + +import com.sun.jdi.ClassType; +import com.sun.jdi.InternalException; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadGroupReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.LocatableEvent; +import com.sun.jdi.event.ThreadDeathEvent; +import com.sun.jdi.event.ThreadStartEvent; +import com.sun.jdi.event.VMDeathEvent; +import com.sun.jdi.event.VMDisconnectEvent; +import com.sun.jdi.event.VMStartEvent; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; + +/** + * Debug target for JDI debug model. + */ +public class JDIDebugTarget extends JDIDebugElement implements + IJavaDebugTarget, ILaunchListener, IBreakpointManagerListener, + IDebugEventSetListener { + + /** + * Threads contained in this debug target. When a thread starts it is added + * to the list. When a thread ends it is removed from the list. + * + * TODO investigate making this a synchronized collection, to remove all this copying + * @see #getThreadIterator() + */ + private List fThreads; + + /** + * List of thread groups in this target. + */ + private final List fGroups; + + /** + * Associated system process, or null if not available. + */ + private IProcess fProcess; + /** + * Underlying virtual machine. + */ + private VirtualMachine fVirtualMachine; + /** + * Whether terminate is supported. Not all targets support terminate. For + * example, a VM that was attached to remotely may not allow the user to + * terminate it. + */ + private boolean fSupportsTerminate; + /** + * Whether terminated + */ + private boolean fTerminated; + + /** + * Whether in the process of terminating + */ + private boolean fTerminating; + + /** + * Whether in the process of disconnecting + */ + private boolean fDisconnecting; + + /** + * Whether disconnected + */ + private boolean fDisconnected; + /** + * Whether disconnect is supported. + */ + private boolean fSupportsDisconnect; + /** + * Whether enable/disable object GC is allowed + */ + private boolean fSupportsDisableGC; + /** + * Collection of breakpoints added to this target. Values are of type + * IJavaBreakpoint. + */ + private List fBreakpoints; + + /** + * Collection of types that have attempted HCR, but failed. The types are + * stored by their fully qualified names. + */ + private Set fOutOfSynchTypes; + /** + * Whether or not this target has performed a hot code replace. + */ + private boolean fHasHCROccurred; + + /** + * The name of this target - set by the client on creation, or retrieved + * from the underlying VM. + */ + private String fName; + + /** + * The event dispatcher for this debug target, which runs in its own thread. + */ + private EventDispatcher fEventDispatcher; + + /** + * The thread start event handler + */ + private ThreadStartHandler fThreadStartHandler; + + /** + * Handles changes in thread names, detected via a breakpoint in {@link java.lang.Thread#setName(String)}. + */ + private ThreadNameChangeHandler fThreadNameChangeHandler; + + /** + * Whether this VM is suspended. + */ + private boolean fSuspended = true; + + /** + * Whether the VM should be resumed on startup + */ + private boolean fResumeOnStartup; + + /** + * The launch this target is contained in + */ + private ILaunch fLaunch; + + /** + * Count of the number of suspend events in this target + */ + private int fSuspendCount; + + /** + * Evaluation engine cache by Java project. Engines are disposed when this + * target terminates. + */ + private Map fEngines; + + /** + * List of step filters - each string is a pattern/fully qualified name of a + * type to filter. + */ + private String[] fStepFilters; + + /** + * Step filter state mask. + */ + private int fStepFilterMask; + + /** + * Step filter bit mask - indicates if step filters are enabled. + */ + private static final int STEP_FILTERS_ENABLED = 0x001; + + /** + * Step filter bit mask - indicates if synthetic methods are filtered. + */ + private static final int FILTER_SYNTHETICS = 0x002; + + /** + * Step filter bit mask - indicates if static initializers are filtered. + */ + private static final int FILTER_STATIC_INITIALIZERS = 0x004; + + /** + * Step filter bit mask - indicates if constructors are filtered. + */ + private static final int FILTER_CONSTRUCTORS = 0x008; + + /** + * When a step lands in a filtered location, this indicates whether stepping + * should proceed "through" to an unfiltered location or step return. + * + * @since 3.3 + */ + private static final int STEP_THRU_FILTERS = 0x010; + + /** + * Step filter bit mask - indicates if simple getters are filtered. + * + * @since 3.7 + */ + private static final int FILTER_GETTERS = 0x020; + + /** + * Step filter bit mask - indicates if simple setters are filtered. + * + * @since 3.7 + */ + private static final int FILTER_SETTERS = 0x040; + + /** + * Mask used to flip individual bit masks via XOR + */ + private static final int XOR_MASK = 0xFFF; + /** + * Whether this debug target is currently performing a hot code replace + */ + private boolean fIsPerformingHotCodeReplace; + + /** + * Target specific HCR listeners + * + * @since 3.6 + */ + private final ListenerList fHCRListeners = new ListenerList<>(); + + /** + * Java scope of the current launch, "null" means everything is in scope + */ + private IJavaSearchScope fScope; + + /** + * Java projects of the current launch, "null" means everything is in scope + */ + private Set fProjects; + + /** + * Java types from breakpoints with the flag if they are in scope for current launch + */ + private Map fKnownTypes = new HashMap<>(); + + /** + * Labels given by the user is stored in this map, where the key is the unique ID of the object. + */ + private final Map objectLabels = new HashMap<>(); + + /** + * Creates a new JDI debug target for the given virtual machine. + * + * @param jvm + * the underlying VM + * @param name + * the name to use for this VM, or null if the name + * should be retrieved from the underlying VM + * @param supportsTerminate + * whether the terminate action is supported by this debug target + * @param supportsDisconnect + * whether the disconnect action is supported by this debug + * target + * @param process + * the system process associated with the underlying VM, or + * null if no system process is available (for + * example, a remote VM) + * @param resume + * whether the VM should be resumed on startup. Has no effect if + * the VM is already resumed/running when the connection is made. + */ + public JDIDebugTarget(ILaunch launch, VirtualMachine jvm, String name, + boolean supportTerminate, boolean supportDisconnect, + IProcess process, boolean resume) { + super(null); + setLaunch(launch); + setResumeOnStartup(resume); + setSupportsTerminate(supportTerminate); + setSupportsDisconnect(supportDisconnect); + setVM(jvm); + jvm.setDebugTraceMode(VirtualMachine.TRACE_NONE); + setProcess(process); + setTerminated(false); + setTerminating(false); + setDisconnected(false); + setDisconnecting(false); + setName(name); + prepareBreakpointsSearchScope(); + setBreakpoints(new ArrayList<>(5)); + setThreadList(new ArrayList<>()); + fGroups = new ArrayList<>(5); + setOutOfSynchTypes(new ArrayList<>(0)); + setHCROccurred(false); + initialize(); + DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); + DebugPlugin.getDefault().getBreakpointManager() + .addBreakpointManagerListener(this); + } + + + private void prepareBreakpointsSearchScope() { + boolean enableFiltering = Platform.getPreferencesService().getBoolean( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES, + true, + null); + ILaunchConfiguration config = getLaunch().getLaunchConfiguration(); + if (!enableFiltering || config == null) { + return; + } + try { + // See IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH + boolean defaultClasspath = config.getAttribute("org.eclipse.jdt.launching.DEFAULT_CLASSPATH", true); //$NON-NLS-1$ + if(!defaultClasspath){ + return; + } + + IResource[] resources = config.getMappedResources(); + if (resources != null && resources.length != 0) { + Set javaProjects = getJavaProjects(resources); + fProjects = collectReferencedJavaProjects(javaProjects); + fScope = createSourcesOnlyScope(); + return; + } + // See IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME + String projectName = config.getAttribute("org.eclipse.jdt.launching.PROJECT_ATTR", (String)null); //$NON-NLS-1$ + if(projectName != null && !projectName.isEmpty()){ + Set javaProjects = getJavaProjects(ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)); + fProjects = collectReferencedJavaProjects(javaProjects); + fScope = createSourcesOnlyScope(); + return; + } + } catch (CoreException e) { + logError(e); + } + } + + private IJavaSearchScope createSourcesOnlyScope() { + int includeMask = IJavaSearchScope.SOURCES; + Set javaProjects = getJavaProjects(ResourcesPlugin.getWorkspace().getRoot().getProjects()); + return SearchEngine.createJavaSearchScope(javaProjects.toArray(new IJavaElement[javaProjects.size()]), includeMask); + } + + /** + * Returns the event dispatcher for this debug target. There is one event + * dispatcher per debug target. + * + * @return event dispatcher + */ + public EventDispatcher getEventDispatcher() { + return fEventDispatcher; + } + + /** + * Sets the event dispatcher for this debug target. Set once at + * initialization. + * + * @param dispatcher + * event dispatcher + * @see #initialize() + */ + private void setEventDispatcher(EventDispatcher dispatcher) { + fEventDispatcher = dispatcher; + } + + /** + * Returns an iterator over the collection of threads. The returned iterator + * is made on a copy of the thread list so that it is thread safe. This + * method should always be used instead of getThreadList().iterator() + * + * @return an iterator over the collection of threads + */ + private Iterator getThreadIterator() { + List threadList; + synchronized (fThreads) { + //TODO investigate making fThreads be a synchronized collection, to remove all this copying + threadList = new ArrayList<>(fThreads); + } + return threadList.iterator(); + } + + /** + * Sets the list of threads contained in this debug target. Set to an empty + * collection on creation. Threads are added and removed as they start and + * end. On termination this collection is set to the immutable singleton + * empty list. + * + * @param threads + * empty list + */ + private void setThreadList(List threads) { + fThreads = threads; + } + + /** + * Returns the collection of breakpoints installed in this debug target. + * + * @return list of installed breakpoints - instances of + * IJavaBreakpoint + */ + public List getBreakpoints() { + return fBreakpoints; + } + + /** + * Sets the list of breakpoints installed in this debug target. Set to an + * empty list on creation. + * + * @param breakpoints + * empty list + */ + private void setBreakpoints(List breakpoints) { + fBreakpoints = breakpoints; + } + + /** + * Notifies this target that the underlying VM has started. This is the + * first event received from the VM. The VM is resumed. This event is not + * generated when an attach is made to a VM that is already running (has + * already started up). The VM is resumed as specified on creation. + * + * @param event + * VM start event + */ + public void handleVMStart(VMStartEvent event) { + if (isResumeOnStartup()) { + try { + setSuspended(true); + resume(); + } catch (DebugException e) { + logError(e); + } + } + // If any threads have resumed since thread collection was initialized, + // update their status (avoid concurrent modification - use + // #getThreads()) + IThread[] threads = getThreads(); + for (IThread thread2 : threads) { + JDIThread thread = (JDIThread) thread2; + if (thread.isSuspended()) { + try { + boolean suspended = thread.getUnderlyingThread() + .isSuspended(); + if (!suspended) { + thread.setRunning(true); + thread.fireResumeEvent(DebugEvent.CLIENT_REQUEST); + } + } catch (VMDisconnectedException e) { + } catch (ObjectCollectedException e) { + } catch (RuntimeException e) { + logError(e); + } + } + } + + } + + /** + * Initialize event requests and state from the underlying VM. This method + * is synchronized to ensure that we do not start to process an events from + * the target until our state is initialized. + */ + protected synchronized void initialize() { + setEventDispatcher(new EventDispatcher(this)); + setRequestTimeout(Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_REQUEST_TIMEOUT, + JDIDebugModel.DEF_REQUEST_TIMEOUT, + null)); + initializeRequests(); + initializeState(); + initializeBreakpoints(); + getLaunch().addDebugTarget(this); + DebugPlugin plugin = DebugPlugin.getDefault(); + plugin.addDebugEventListener(this); + fireCreationEvent(); + // begin handling/dispatching events after the creation event is handled + // by all listeners + plugin.asyncExec(() -> { + EventDispatcher dispatcher = getEventDispatcher(); + if (dispatcher != null) { + Thread t = new Thread( + dispatcher, + JDIDebugModel.getPluginIdentifier() + + JDIDebugModelMessages.JDIDebugTarget_JDI_Event_Dispatcher); + t.setDaemon(true); + t.start(); + } + }); + } + + /** + * Adds all of the pre-existing threads to this debug target. + */ + protected void initializeState() { + + List threads = null; + VirtualMachine vm = getVM(); + if (vm != null) { + try { + String name = vm.name(); + fSupportsDisableGC = !name.equals("Classic VM"); //$NON-NLS-1$ + } catch (RuntimeException e) { + internalError(e); + } + try { + threads = vm.allThreads(); + } catch (RuntimeException e) { + internalError(e); + } + if (threads != null) { + Iterator initialThreads = threads.iterator(); + while (initialThreads.hasNext()) { + createThread(initialThreads.next()); + } + } + } + + if (isResumeOnStartup()) { + setSuspended(false); + } + } + + /** + * Registers event handlers for thread creation, thread termination. + */ + protected void initializeRequests() { + setThreadStartHandler(new ThreadStartHandler()); + setThreadNameChangeHandler(new ThreadNameChangeHandler()); + new ThreadDeathHandler(); + } + + /** + * Installs all Java breakpoints that currently exist in the breakpoint + * manager + */ + protected void initializeBreakpoints() { + IBreakpointManager manager = DebugPlugin.getDefault() + .getBreakpointManager(); + manager.addBreakpointListener(this); + IBreakpoint[] bps = manager.getBreakpoints(JDIDebugModel + .getPluginIdentifier()); + for (IBreakpoint bp : bps) { + if (bp instanceof IJavaBreakpoint) { + breakpointAdded(bp); + } + } + } + + /** + * Creates, adds and returns a thread for the given underlying thread + * reference. A creation event is fired for the thread. Returns + * null if during the creation of the thread this target is set + * to the disconnected state. + * + * @param thread + * underlying thread + * @return model thread + */ + protected JDIThread createThread(ThreadReference thread) { + JDIThread jdiThread = newThread(thread); + if (jdiThread == null) { + return null; + } + if (isDisconnected()) { + return null; + } + synchronized (fThreads) { + fThreads.add(jdiThread); + } + jdiThread.fireCreationEvent(); + return jdiThread; + } + + /** + * Factory method for creating new threads. Creates and returns a new thread + * object for the underlying thread reference, or null if none + * + * @param reference + * thread reference + * @return JDI model thread + */ + protected JDIThread newThread(ThreadReference reference) { + try { + return new JDIThread(this, reference); + } catch (ObjectCollectedException exception) { + // ObjectCollectionException can be thrown if the thread has already + // completed (exited) in the VM. + } + return null; + } + + @Override + public IThread[] getThreads() { + synchronized (fThreads) { + IThread[] threads = new IThread[fThreads.size()]; + int index = 0; + for (JDIThread thread : fThreads) { + if (!thread.isSystemThread()) { + threads[index] = thread; + ++index; + } + } + for (JDIThread thread : fThreads) { + if (thread.isSystemThread()) { + threads[index] = thread; + ++index; + } + } + return threads; + } + } + + @Override + public boolean canResume() { + return (isSuspended() || canResumeThreads()) && isAvailable() + && !isPerformingHotCodeReplace(); + } + + /** + * Returns whether this target has any threads which can be resumed. + * + * @return true if any thread can be resumed, false otherwise + * @since 3.2 + */ + private boolean canResumeThreads() { + Iterator it = getThreadIterator(); + while (it.hasNext()) { + IThread thread = it.next(); + if (thread.canResume()) { + return true; + } + } + return false; + } + + @Override + public boolean canSuspend() { + if (isAvailable()) { + // allow suspend when one or more threads are currently running + IThread[] threads = getThreads(); + for (IThread thread : threads) { + if (((JDIThread) thread).canSuspend()) { + return true; + } + } + return !isSuspended(); + } + return false; + } + + @Override + public boolean canTerminate() { + return supportsTerminate() && isAvailable(); + } + + @Override + public boolean canDisconnect() { + return supportsDisconnect() && !isDisconnected(); + } + + /** + * Returns whether this debug target supports disconnecting. + * + * @return whether this debug target supports disconnecting + */ + protected boolean supportsDisconnect() { + return fSupportsDisconnect; + } + + /** + * Sets whether this debug target supports disconnection. Set on creation. + * + * @param supported + * true if this target supports disconnection, + * otherwise false + */ + private void setSupportsDisconnect(boolean supported) { + fSupportsDisconnect = supported; + } + + /** + * Returns whether this debug target supports termination. + * + * @return whether this debug target supports termination + */ + protected boolean supportsTerminate() { + return fSupportsTerminate; + } + + /** + * Sets whether this debug target supports termination. Set on creation. + * + * @param supported + * true if this target supports termination, + * otherwise false + */ + private void setSupportsTerminate(boolean supported) { + fSupportsTerminate = supported; + } + + @Override + public boolean supportsHotCodeReplace() { + return supportsJ9HotCodeReplace() || supportsJDKHotCodeReplace(); + } + + @Override + public boolean supportsInstanceBreakpoints() { + if (isAvailable() + && JDIDebugPlugin.isJdiVersionGreaterThanOrEqual(new int[] { 1, + 4 })) { + VirtualMachine vm = getVM(); + if (vm != null) { + return vm.canUseInstanceFilters(); + } + } + return false; + } + + /** + * Returns whether this debug target supports hot code replace for the J9 + * VM. + * + * @return whether this debug target supports J9 hot code replace + */ + public boolean supportsJ9HotCodeReplace() { + VirtualMachine vm = getVM(); + if (isAvailable() && vm instanceof org.eclipse.jdi.hcr.VirtualMachine) { + try { + return ((org.eclipse.jdi.hcr.VirtualMachine) vm) + .canReloadClasses(); + } catch (UnsupportedOperationException e) { + // This is not an error condition - + // UnsupportedOperationException is thrown when a VM does + // not support HCR + } + } + return false; + } + + /** + * Returns whether this debug target supports hot code replace for JDK VMs. + * + * @return whether this debug target supports JDK hot code replace + */ + public boolean supportsJDKHotCodeReplace() { + if (isAvailable() + && JDIDebugPlugin.isJdiVersionGreaterThanOrEqual(new int[] { 1, + 4 })) { + VirtualMachine vm = getVM(); + if (vm != null) { + return vm.canRedefineClasses(); + } + } + return false; + } + + /** + * Returns whether this debug target supports popping stack frames. + * + * @return whether this debug target supports popping stack frames. + */ + public boolean canPopFrames() { + if (isAvailable() + && JDIDebugPlugin.isJdiVersionGreaterThanOrEqual(new int[] { 1, + 4 })) { + VirtualMachine vm = getVM(); + if (vm != null) { + return vm.canPopFrames(); + } + } + return false; + } + + @Override + public void disconnect() throws DebugException { + + if (!isAvailable()) { + // already done + return; + } + + if (!canDisconnect()) { + notSupported(JDIDebugModelMessages.JDIDebugTarget_does_not_support_disconnect); + } + + try { + setDisconnecting(true); + disposeThreadHandlers(); + VirtualMachine vm = getVM(); + if (vm != null) { + vm.dispose(); + } + } catch (VMDisconnectedException e) { + // if the VM disconnects while disconnecting, perform + // normal disconnect handling + disconnected(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIDebugTarget_exception_disconnecting, + e.toString()), e); + } + + } + + /** + * Allows for ThreadStartHandler to do clean up/disposal. + */ + private void disposeThreadHandlers() { + ThreadStartHandler handler = getThreadStartHandler(); + if (handler != null) { + handler.deleteRequest(); + } + ThreadNameChangeHandler nameChangeHandler = getThreadNameChangeHandler(); + if (nameChangeHandler != null) { + nameChangeHandler.deleteRequest(); + } + } + + public String getObjectLabel(IJavaObject javaObject) throws DebugException { + long id = javaObject.getUniqueId(); + return objectLabels.get(id); + } + + public void setObjectLabel(IJavaObject javaObject, String label) throws DebugException { + long id = javaObject.getUniqueId(); + if (label == null || label.isBlank()) { + objectLabels.remove(id); + } else { + objectLabels.put(id, label); + } + } + + /** + * Returns the underlying virtual machine associated with this debug target, + * or null if none (disconnected/terminated) + * + * @return the underlying VM or null + */ + @Override + public VirtualMachine getVM() { + return fVirtualMachine; + } + + /** + * Sets the underlying VM associated with this debug target. Set on + * creation. + * + * @param vm + * underlying VM + */ + private void setVM(VirtualMachine vm) { + fVirtualMachine = vm; + } + + /** + * Sets whether this debug target has performed a hot code replace. + */ + public void setHCROccurred(boolean occurred) { + fHasHCROccurred = occurred; + } + + public void removeOutOfSynchTypes(List qualifiedNames) { + fOutOfSynchTypes.removeAll(qualifiedNames); + } + + /** + * Sets the list of out of synch types to the given list. + */ + private void setOutOfSynchTypes(List qualifiedNames) { + fOutOfSynchTypes = new HashSet<>(); + fOutOfSynchTypes.addAll(qualifiedNames); + } + + /** + * The given types have failed to be reloaded by HCR. Add them to the list + * of out of synch types. + */ + public void addOutOfSynchTypes(List qualifiedNames) { + fOutOfSynchTypes.addAll(qualifiedNames); + } + + /** + * Returns whether the given type is out of synch in this target. + */ + public boolean isOutOfSynch(String qualifiedName) { + if (fOutOfSynchTypes == null || fOutOfSynchTypes.isEmpty()) { + return false; + } + return fOutOfSynchTypes.contains(qualifiedName); + } + + @Override + public boolean isOutOfSynch() throws DebugException { + Iterator threads = getThreadIterator(); + while (threads.hasNext()) { + JDIThread thread = threads.next(); + if (thread.isOutOfSynch()) { + return true; + } + } + return false; + } + + @Override + public boolean mayBeOutOfSynch() { + Iterator threads = getThreadIterator(); + while (threads.hasNext()) { + JDIThread thread = threads.next(); + if (thread.mayBeOutOfSynch()) { + return true; + } + } + return false; + } + + /** + * Returns whether a hot code replace attempt has failed. + * + * HCR has failed if there are any out of synch types + */ + public boolean hasHCRFailed() { + return fOutOfSynchTypes != null && !fOutOfSynchTypes.isEmpty(); + } + + /** + * Returns whether this debug target has performed a hot code replace + */ + public boolean hasHCROccurred() { + return fHasHCROccurred; + } + + /** + * Reinstall all breakpoints installed in the given resources + * @param resources + * @param classNames + */ + public void reinstallBreakpointsIn(List resources, List classNames) { + List breakpoints = getBreakpoints(); + IJavaBreakpoint[] copy = new IJavaBreakpoint[breakpoints.size()]; + breakpoints.toArray(copy); + IJavaBreakpoint breakpoint = null; + String installedType = null; + + for (IJavaBreakpoint element : copy) { + breakpoint = element; + if (breakpoint instanceof JavaLineBreakpoint) { + try { + installedType = breakpoint.getTypeName(); + if (classNames.contains(installedType)) { + breakpointRemoved(breakpoint, null); + breakpointAdded(breakpoint); + } + } catch (CoreException ce) { + logError(ce); + continue; + } + } + } + } + + /** + * Finds and returns the JDI thread for the associated thread reference, or + * null if not found. + * + * @param the + * underlying thread reference + * @return the associated model thread + */ + public JDIThread findThread(ThreadReference tr) { + Iterator iter = getThreadIterator(); + while (iter.hasNext()) { + JDIThread thread = iter.next(); + if (thread.getUnderlyingThread().equals(tr)) { + return thread; + } + } + return null; + } + + @Override + public String getName() throws DebugException { + if (fName == null) { + setName(getVMName()); + } + return fName; + } + + /** + * Sets the name of this debug target. Set on creation, and if set to + * null the name will be retrieved lazily from the underlying + * VM. + * + * @param name + * the name of this VM or null if the name should be + * retrieved from the underlying VM + */ + protected void setName(String name) { + fName = name; + } + + /** + * Sets the process associated with this debug target, possibly + * null. Set on creation. + * + * @param process + * the system process associated with the underlying VM, or + * null if no process is associated with this debug + * target (for example, a remote VM). + */ + protected void setProcess(IProcess process) { + fProcess = process; + } + + @Override + public IProcess getProcess() { + return fProcess; + } + + /** + * Notification the underlying VM has died. Updates the state of this target + * to be terminated. + * + * @param event + * VM death event + */ + public void handleVMDeath(VMDeathEvent event) { + terminated(); + } + + /** + * Notification the underlying VM has disconnected. Updates the state of + * this target to be terminated. + * + * @param event + * disconnect event + */ + public void handleVMDisconnect(VMDisconnectEvent event) { + if (isTerminating()) { + terminated(); + } else { + disconnected(); + } + } + + @Override + public boolean isSuspended() { + return fSuspended; + } + + /** + * Sets whether this VM is suspended. + * + * @param suspended + * whether this VM is suspended + */ + private void setSuspended(boolean suspended) { + fSuspended = suspended; + } + + /** + * Returns whether this target is available to handle VM requests + */ + public boolean isAvailable() { + return !(isTerminated() || isTerminating() || isDisconnected() || isDisconnecting()); + } + + @Override + public boolean isTerminated() { + return fTerminated; + } + + /** + * Sets whether this debug target is terminated + * + * @param terminated + * true if this debug target is terminated, + * otherwise false + */ + protected void setTerminated(boolean terminated) { + fTerminated = terminated; + } + + /** + * Sets whether this debug target is disconnected + * + * @param disconnected + * true if this debug target is disconnected, + * otherwise false + */ + protected void setDisconnected(boolean disconnected) { + fDisconnected = disconnected; + } + + @Override + public boolean isDisconnected() { + return fDisconnected; + } + + /** + * Creates, enables and returns a class prepare request for the specified + * class name in this target. + * + * @param classPattern + * regular expression specifying the pattern of class names that + * will cause the event request to fire. Regular expressions may + * begin with a '*', end with a '*', or be an exact match. + * @exception CoreException + * if unable to create the request + */ + public ClassPrepareRequest createClassPrepareRequest(String classPattern) + throws CoreException { + return createClassPrepareRequest(classPattern, null); + } + + /** + * Creates, enables and returns a class prepare request for the specified + * class name in this target. Can specify a class exclusion filter as well. + * This is a utility method used by event requesters that need to create + * class prepare requests. + * + * @param classPattern + * regular expression specifying the pattern of class names that + * will cause the event request to fire. Regular expressions may + * begin with a '*', end with a '*', or be an exact match. + * @param classExclusionPattern + * regular expression specifying the pattern of class names that + * will not cause the event request to fire. Regular expressions + * may begin with a '*', end with a '*', or be an exact match. + * May be null. + * @exception CoreException + * if unable to create the request + */ + public ClassPrepareRequest createClassPrepareRequest(String classPattern, + String classExclusionPattern) throws CoreException { + return createClassPrepareRequest(classPattern, classExclusionPattern, + true); + } + + /** + * Creates, enables and returns a class prepare request for the specified + * class name in this target. Can specify a class exclusion filter as well. + * This is a utility method used by event requesters that need to create + * class prepare requests. + * + * @param classPattern + * regular expression specifying the pattern of class names that + * will cause the event request to fire. Regular expressions may + * begin with a '*', end with a '*', or be an exact match. + * @param classExclusionPattern + * regular expression specifying the pattern of class names that + * will not cause the event request to fire. Regular expressions + * may begin with a '*', end with a '*', or be an exact match. + * May be null. + * @param enabled + * whether to enable the event request + * @exception CoreException + * if unable to create the request + * @since 3.3 + */ + public ClassPrepareRequest createClassPrepareRequest(String classPattern, + String classExclusionPattern, boolean enabled) throws CoreException { + return createClassPrepareRequest(classPattern, classExclusionPattern, + enabled, null); + } + + /** + * Creates, enables and returns a class prepare request for the specified + * class name in this target. Can specify a class exclusion filter as well. + * This is a utility method used by event requesters that need to create + * class prepare requests. + * + * @param classPattern + * regular expression specifying the pattern of class names that + * will cause the event request to fire. Regular expressions may + * begin with a '*', end with a '*', or be an exact match. May be + * null if sourceName is specified + * @param classExclusionPattern + * regular expression specifying the pattern of class names that + * will not cause the event request to fire. Regular expressions + * may begin with a '*', end with a '*', or be an exact match. + * May be null. + * @param enabled + * whether to enable the event request + * @param sourceName + * source name pattern to match or null if + * classPattern is specified + * @exception CoreException + * if unable to create the request + * @since 3.3 + */ + public ClassPrepareRequest createClassPrepareRequest(String classPattern, + String classExclusionPattern, boolean enabled, String sourceName) + throws CoreException { + EventRequestManager manager = getEventRequestManager(); + if (manager == null || !isAvailable()) { + requestFailed( + JDIDebugModelMessages.JDIDebugTarget_Unable_to_create_class_prepare_request___VM_disconnected__2, + new VMDisconnectedException()); + } + ClassPrepareRequest req = null; + try { + req = manager.createClassPrepareRequest(); + if (classPattern != null) { + req.addClassFilter(classPattern); + } + if (classExclusionPattern != null) { + req.addClassExclusionFilter(classExclusionPattern); + } + req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + if (sourceName != null) { + req.addSourceNameFilter(sourceName); + } + if (enabled) { + req.enable(); + } + } catch (RuntimeException e) { + targetRequestFailed( + JDIDebugModelMessages.JDIDebugTarget_Unable_to_create_class_prepare_request__3, + e); + // execution will not reach here + return null; + } + return req; + } + + @Override + public void resume() throws DebugException { + // if a client calls resume, then we should resume on a VMStart event in + // case + // it has not yet been received, and the target was created with the + // "resume" + // flag as "false". See bug 32372. + setResumeOnStartup(true); + resume(true); + } + + /** + * @see ISuspendResume#resume() + * + * Updates the state of this debug target to resumed, but does not fire + * notification of the resumption. + */ + public void resumeQuiet() throws DebugException { + resume(false); + } + + /** + * @see ISuspendResume#resume() + * + * Updates the state of this debug target, but only fires notification + * to listeners if fireNotification is true. + */ + protected void resume(boolean fireNotification) throws DebugException { + if ((!isSuspended() && !canResumeThreads()) || !isAvailable()) { + return; + } + try { + setSuspended(false); + resumeThreads(); + VirtualMachine vm = getVM(); + if (vm != null) { + vm.resume(); + } + if (fireNotification) { + fireResumeEvent(DebugEvent.CLIENT_REQUEST); + } + } catch (VMDisconnectedException e) { + disconnected(); + return; + } catch (RuntimeException e) { + setSuspended(true); + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIDebugTarget_exception_resume, + e.toString()), e); + } + } + + @Override + public boolean supportsBreakpoint(IBreakpoint breakpoint) { + boolean isJava = breakpoint instanceof IJavaBreakpoint; + if(!isJava){ + return false; + } + if(fScope == null){ + // No checks, everything in scope: the filtering is disabled + return true; + } + + IJavaBreakpoint jBreakpoint = (IJavaBreakpoint) breakpoint; + + // Check if the breakpoint from resources in target scope + IMarker marker = jBreakpoint.getMarker(); + if(marker == null) { + // Marker not available, so don't guess and allow the breakpoint to be set + return true; + } + + return supportsResource(() -> jBreakpoint.getTypeName(), marker.getResource()); + } + + + public boolean supportsResource(Callable typeNameSupplier, IResource resource) { + if (fScope == null) { + // No checks, everything in scope: the filtering is disabled + return true; + } + // Java exception breakpoints have wsp root as resource + if(resource == null || resource == ResourcesPlugin.getWorkspace().getRoot()) { + return true; + } + Set projects = fProjects; + if(projects == null){ + return true; + } + + // Breakpoint from project known by the resource mapping + if (projects.contains(resource.getProject())) { + return true; + } + + // Check if this is a resource which is linked to any of the projects + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + URI uri = resource.getLocationURI(); + if(uri != null){ + IFile[] files = root.findFilesForLocationURI(uri); + for (IFile file : files) { + if(projects.contains(file.getProject())){ + return true; + } + } + } + + Map knownTypes = fKnownTypes; + if(knownTypes == null){ + return true; + } + + // breakpoint belongs to resource outside of referenced projects? + // This can be also an incomplete resource mapping. + // Try to see if the type available multiple times in workspace + try { + String typeName = typeNameSupplier.call(); + if(typeName != null){ + Boolean known = knownTypes.get(typeName); + if(known != null){ + return known.booleanValue(); + } + boolean supportedBreakpoint = !hasMultipleMatchesInWorkspace(typeName); + knownTypes.put(typeName, Boolean.valueOf(supportedBreakpoint)); + return supportedBreakpoint; + } + } + catch (Exception e) { + logError(e); + } + // we don't know why computation failed, so let assume the breakpoint is supported. + return true; + } + + private Set getJavaProjects(IResource... resources) { + Set projects = new LinkedHashSet<>(); + for (IResource resource : resources) { + IProject project = resource.getProject(); + if(!project.isAccessible()){ + continue; + } + IJavaElement javaElement = JavaCore.create(project); + if(javaElement != null) { + projects.add(javaElement.getJavaProject()); + } + } + return projects; + } + + /** + * @param javaProjects the set which will be updated with all referenced java projects + * @return corresponding resource projects + */ + private Set collectReferencedJavaProjects(Set javaProjects) { + Set projects = new LinkedHashSet<>(); + // collect all references + for (IJavaProject jProject : javaProjects) { + projects.add(jProject.getProject()); + addReferencedProjects(jProject, projects); + } + // update java projects set with new java projects we might collected + for (IProject project : projects) { + IJavaProject jProject = JavaCore.create(project); + if(jProject != null){ + javaProjects.add(jProject); + } + } + return projects; + } + + private void addReferencedProjects(IJavaProject jProject, Set projects) { + IClasspathEntry[] cp; + try { + // we want resolved classpath to get variables and containers resolved for us + cp = jProject.getResolvedClasspath(true); + } catch (JavaModelException e) { + // we don't care here + return; + } + for (IClasspathEntry cpe : cp) { + int entryKind = cpe.getEntryKind(); + IProject project = null; + switch (entryKind) { + case IClasspathEntry.CPE_LIBRARY: + // we must check for external folders coming from other projects in the workspace + project = getProjectOfExternalFolder(cpe); + break; + case IClasspathEntry.CPE_PROJECT: + // we must add any projects referenced + project = getProject(cpe); + break; + case IClasspathEntry.CPE_SOURCE: + // we have the project already + case IClasspathEntry.CPE_VARIABLE: + // should not happen on resolved classpath + case IClasspathEntry.CPE_CONTAINER: + // should not happen on resolved classpath + default: + break; + } + + if(project == null || projects.contains(project) || !project.isAccessible()){ + continue; + } + + IJavaProject referenced = JavaCore.create(project); + if (referenced != null) { + // we have found new project, start recursion + projects.add(project); + addReferencedProjects(referenced, projects); + } + } + } + + private IProject getProject(IClasspathEntry cpe) { + IPath projectPath = cpe.getPath(); + if (projectPath == null || projectPath.isEmpty()) { + return null; + } + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IProject project = root.getProject(projectPath.lastSegment()); + if (project.isAccessible()) { + return project; + } + return null; + } + + private static IProject getProjectOfExternalFolder(IClasspathEntry cpe){ + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + if(cpe.getContentKind() == IPackageFragmentRoot.K_BINARY){ + IPath path = cpe.getPath(); + if(path == null || path.isEmpty()){ + return null; + } + IProject project = root.getProject(path.segment(0)); + if(project.isAccessible()) { + return project; + } + } + return null; + } + + /* + * Checks if the given type (computed from a breakpoint resource) exists multiple times in the workspace. + */ + private boolean hasMultipleMatchesInWorkspace(final String typeName) { + final AtomicInteger matchCount = new AtomicInteger(0); + String packageName = null; + String simpleName = typeName; + int lastDot = typeName.lastIndexOf('.'); + if(lastDot > 0 && lastDot < typeName.length() - 1){ + packageName = typeName.substring(0, lastDot); + simpleName = typeName.substring(lastDot + 1); + } + // get rid of inner types, use outer type name + final String fqName; + int firstDoll = simpleName.indexOf('$'); + if(firstDoll > 0 && firstDoll < simpleName.length() - 1){ + simpleName = simpleName.substring(0, firstDoll); + fqName = packageName + "." + simpleName; //$NON-NLS-1$ + } else { + fqName = typeName; + } + + final IProgressMonitor monitor = new NullProgressMonitor(); + TypeNameMatchRequestor requestor = new TypeNameMatchRequestor() { + @Override + public void acceptTypeNameMatch(TypeNameMatch match) { + IType type = match.getType(); + if(fqName.equals(type.getFullyQualifiedName())){ + int count = matchCount.incrementAndGet(); + if(count > 1) { + monitor.setCanceled(true); + } + return; + } + } + }; + try { + SearchEngine searchEngine = new SearchEngine(); + searchEngine.searchAllTypeNames(packageName != null? packageName.toCharArray() : null, + SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, + simpleName.toCharArray(), + SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, + IJavaSearchConstants.TYPE, + fScope, + requestor, + IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, + monitor); + } catch (JavaModelException e) { + logError(e); + return true; + } catch (OperationCanceledException e){ + // expected if we cancelled the search on second match + } + return matchCount.get() > 1; + } + + /** + * Notification a breakpoint has been added to the breakpoint manager. If + * the breakpoint is a Java breakpoint and this target is not terminated, + * the breakpoint is installed. + * + * @param breakpoint + * the breakpoint added to the breakpoint manager + */ + @Override + public void breakpointAdded(IBreakpoint breakpoint) { + if (!isAvailable()) { + return; + } + if (supportsBreakpoint(breakpoint)) { + try { + JavaBreakpoint javaBreakpoint = (JavaBreakpoint) breakpoint; + if (!getBreakpoints().contains(breakpoint)) { + if (!javaBreakpoint.shouldSkipBreakpoint()) { + // If the breakpoint should be skipped, don't add the + // breakpoint + // request to the VM. Just add the breakpoint to the + // collection so + // we have it if the manager is later enabled. + javaBreakpoint.addToTarget(this); + } + getBreakpoints().add(breakpoint); + } + } catch (CoreException e) { + logError(e); + } + } + } + + /** + * Notification that one or more attributes of the given breakpoint has + * changed. If the breakpoint is a Java breakpoint, the associated event + * request in the underlying VM is updated to reflect the new state of the + * breakpoint. + * + * @param breakpoint + * the breakpoint that has changed + */ + @Override + public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { + } + + /** + * Notification that the given breakpoint has been removed from the + * breakpoint manager. If this target is not terminated, the breakpoint is + * removed from the underlying VM. + * + * @param breakpoint + * the breakpoint has been removed from the breakpoint manager. + */ + @Override + public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { + if (!isAvailable()) { + return; + } + if (supportsBreakpoint(breakpoint)) { + try { + ((JavaBreakpoint) breakpoint).removeFromTarget(this); + getBreakpoints().remove(breakpoint); + Iterator threads = getThreadIterator(); + while (threads.hasNext()) { + threads.next() + .removeCurrentBreakpoint(breakpoint); + } + } catch (CoreException e) { + logError(e); + } + } + } + + @Override + public void suspend() throws DebugException { + if (isSuspended()) { + IThread[] threads = getThreads(); + for (IThread thread : threads) { + ((JDIThread) thread).suspend(); + } + return; + } + try { + VirtualMachine vm = getVM(); + prepareThreadsForClientSuspend(); + if (vm != null) { + vm.suspend(); + } + suspendThreads(); + setSuspended(true); + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + } catch (RuntimeException e) { + setSuspended(false); + resumeThreads(); + fireResumeEvent(DebugEvent.CLIENT_REQUEST); + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIDebugTarget_exception_suspend, + e.toString()), e); + } + + } + + /** + * Prepares threads to suspend (terminates evaluations, waits for + * invocations, etc.). + * + * @exception DebugException + * if a thread times out + */ + protected void prepareThreadsForClientSuspend() throws DebugException { + Iterator threads = getThreadIterator(); + while (threads.hasNext()) { + threads.next().prepareForClientSuspend(); + } + } + + /** + * Notifies threads that they have been suspended + */ + protected void suspendThreads() { + Iterator threads = getThreadIterator(); + while (threads.hasNext()) { + JDIThread thread = threads.next(); + if (!thread.isBreakpointHandlingOngoing()) { + thread.suspendedByVM(); + } + } + } + + /** + * Notifies threads that they have been resumed + */ + protected void resumeThreads() throws DebugException { + Iterator threads = getThreadIterator(); + while (threads.hasNext()) { + JDIThread thread = threads.next(); + if (!thread.isBreakpointHandlingOngoing()) { + thread.resumedByVM(); + } + } + } + + /** + * Notifies this VM to update its state in preparation for a suspend. + * + * @param breakpoint + * the breakpoint that caused the suspension + */ + public void prepareToSuspendByBreakpoint(JavaBreakpoint breakpoint) { + setSuspended(true); + suspendThreads(); + } + + /** + * Notifies this VM it has been suspended by the given breakpoint + * + * @param breakpoint + * the breakpoint that caused the suspension + */ + protected void suspendedByBreakpoint(JavaBreakpoint breakpoint, + boolean queueEvent, EventSet set) { + if (queueEvent) { + queueSuspendEvent(DebugEvent.BREAKPOINT, set); + } else { + fireSuspendEvent(DebugEvent.BREAKPOINT); + } + } + + /** + * Notifies this VM suspension has been cancelled + * + * @param breakpoint + * the breakpoint that caused the suspension + */ + protected void cancelSuspendByBreakpoint(JavaBreakpoint breakpoint) + throws DebugException { + setSuspended(false); + resumeThreads(); + } + + @Override + public void terminate() throws DebugException { + if (!isAvailable()) { + return; + } + if (!supportsTerminate()) { + notSupported(JDIDebugModelMessages.JDIDebugTarget_does_not_support_termination); + } + try { + setTerminating(true); + disposeThreadHandlers(); + VirtualMachine vm = getVM(); + if (vm != null) { + vm.exit(1); + } + IProcess process = getProcess(); + if (process != null) { + process.terminate(); + } + } catch (VMDisconnectedException e) { + // if the VM disconnects while exiting, perform + // normal termination processing + terminated(); + } catch (TimeoutException exception) { + // if there is a timeout see if the associated process is terminated + IProcess process = getProcess(); + if (process != null && process.isTerminated()) { + terminated(); + } else { + // All we can do is disconnect + disconnected(); + } + } catch (RuntimeException e) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIDebugTarget_exception_terminating, + e.toString()), e); + } + } + + /** + * Updates the state of this target to be terminated, if not already + * terminated. + */ + protected void terminated() { + setTerminating(false); + if (!isTerminated()) { + setTerminated(true); + setDisconnected(true); + cleanup(); + fireTerminateEvent(); + } + } + + /** + * Updates the state of this target for disconnection from the VM. + */ + @Override + protected void disconnected() { + setDisconnecting(false); + if (!isDisconnected()) { + setDisconnected(true); + cleanup(); + fireTerminateEvent(); + } + } + + /** + * Cleans up the internal state of this debug target as a result of a + * session ending with a VM (as a result of a disconnect or termination of + * the VM). + *

                  + * All threads are removed from this target. This target is removed as a + * breakpoint listener, and all breakpoints are removed from this target. + *

                  + */ + protected void cleanup() { + removeAllThreads(); + DebugPlugin plugin = DebugPlugin.getDefault(); + plugin.getBreakpointManager().removeBreakpointListener(this); + plugin.getLaunchManager().removeLaunchListener(this); + plugin.getBreakpointManager().removeBreakpointManagerListener(this); + plugin.removeDebugEventListener(this); + removeAllBreakpoints(); + DebugPlugin.getDefault().getBreakpointManager().enableTriggerPoints(null, true); + fOutOfSynchTypes.clear(); + if (fEngines != null) { + Iterator engines = fEngines.values().iterator(); + while (engines.hasNext()) { + IAstEvaluationEngine engine = engines + .next(); + engine.dispose(); + } + fEngines.clear(); + } + fVirtualMachine = null; + setThreadStartHandler(null); + setEventDispatcher(null); + setStepFilters(new String[0]); + fHCRListeners.clear(); + fKnownTypes = null; + fProjects = null; + fScope = null; + } + + /** + * Removes all threads from this target's collection of threads, firing a + * terminate event for each. + */ + protected void removeAllThreads() { + Iterator itr = getThreadIterator(); + while (itr.hasNext()) { + JDIThread child = itr.next(); + child.terminated(); + } + synchronized (fThreads) { + fThreads.clear(); + } + } + + /** + * Removes all breakpoints from this target, such that each breakpoint can + * update its install count. This target's collection of breakpoints is + * cleared. + */ + protected void removeAllBreakpoints() { + List list = new ArrayList<>(getBreakpoints()); + for(IBreakpoint bp : list) { + JavaBreakpoint breakpoint = (JavaBreakpoint) bp; + try { + breakpoint.removeFromTarget(this); + } catch (CoreException e) { + logError(e); + } + } + getBreakpoints().clear(); + } + + /** + * Adds all the breakpoints in this target's collection to this debug + * target. + */ + protected void reinstallAllBreakpoints() { + List list = new ArrayList<>(getBreakpoints()); + for(IBreakpoint bp : list) { + JavaBreakpoint breakpoint = (JavaBreakpoint) bp; + try { + breakpoint.addToTarget(this); + } catch (CoreException e) { + logError(e); + } + } + } + + /** + * Returns VirtualMachine.classesByName(String), logging any JDI exceptions. + * + * @see com.sun.jdi.VirtualMachine + */ + public List jdiClassesByName(String className) { + VirtualMachine vm = getVM(); + if (vm != null) { + try { + return vm.classesByName(className); + } catch (VMDisconnectedException e) { + if (!isAvailable()) { + return Collections.EMPTY_LIST; + } + logError(e); + } catch (RuntimeException e) { + internalError(e); + } + } + return Collections.EMPTY_LIST; + } + + @Override + public IJavaVariable findVariable(String varName) throws DebugException { + IThread[] threads = getThreads(); + for (IThread thread2 : threads) { + IJavaThread thread = (IJavaThread) thread2; + IJavaVariable var = thread.findVariable(varName); + if (var != null) { + return var; + } + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter == IJavaDebugTarget.class) { + return (T) this; + } + return super.getAdapter(adapter); + } + + /** + * The JDIDebugPlugin is shutting down. Shutdown the event dispatcher and do + * local cleanup. + */ + public void shutdown() { + EventDispatcher dispatcher = ((JDIDebugTarget) getDebugTarget()) + .getEventDispatcher(); + if (dispatcher != null) { + dispatcher.shutdown(); + } + try { + if (supportsTerminate()) { + terminate(); + } else if (supportsDisconnect()) { + disconnect(); + } + } catch (DebugException e) { + JDIDebugPlugin.log(e); + } + cleanup(); + } + + /** + * Returns the CRC-32 of the entire class file contents associated with + * given type, on the target VM, or null if the type is not + * loaded, or a CRC for the type is not known. + * + * @param typeName + * fully qualified name of the type for which a CRC is required. + * For example, "com.example.Example". + * @return 32 bit CRC, or null + * @exception DebugException + * if this method fails. Reasons include: + *
                    + *
                  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                  • + *
                  + */ + protected Integer getCRC(String typeName) throws DebugException { + if (getVM() instanceof org.eclipse.jdi.hcr.VirtualMachine) { + List classes = jdiClassesByName(typeName); + if (!classes.isEmpty()) { + ReferenceType type = classes.get(0); + if (type instanceof org.eclipse.jdi.hcr.ReferenceType) { + try { + org.eclipse.jdi.hcr.ReferenceType rt = (org.eclipse.jdi.hcr.ReferenceType) type; + if (rt.isVersionKnown()) { + return Integer.valueOf(rt.getClassFileVersion()); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIDebugTarget_exception_retrieving_version_information, + e.toString(), type.name()), e); + // execution will never reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + } + } + return null; + } + + @Override + public IJavaType[] getJavaTypes(String name) throws DebugException { + try { + // get java.lang.Class + VirtualMachine vm = getVM(); + if (vm == null) { + requestFailed( + JDIDebugModelMessages.JDIDebugTarget_Unable_to_retrieve_types___VM_disconnected__4, + new VMDisconnectedException()); + } + List classes = vm.classesByName(name); + if (classes.isEmpty()) { + switch (name.charAt(0)) { + case 'b': + if (name.equals("boolean")) { //$NON-NLS-1$ + return new IJavaType[] { newValue(true).getJavaType() }; + } else if (name.equals("byte")) { //$NON-NLS-1$ + return new IJavaType[] { newValue((byte) 1) + .getJavaType() }; + } + break; + case 'i': + if (name.equals("int")) { //$NON-NLS-1$ + return new IJavaType[] { newValue(1).getJavaType() }; + } + break; + case 'l': + if (name.equals("long")) { //$NON-NLS-1$ + return new IJavaType[] { newValue(1l).getJavaType() }; + } + break; + case 'c': + if (name.equals("char")) { //$NON-NLS-1$ + return new IJavaType[] { newValue(' ').getJavaType() }; + } + break; + case 's': + if (name.equals("short")) { //$NON-NLS-1$ + return new IJavaType[] { newValue((short) 1) + .getJavaType() }; + } + break; + case 'f': + if (name.equals("float")) { //$NON-NLS-1$ + return new IJavaType[] { newValue(1f).getJavaType() }; + } + break; + case 'd': + if (name.equals("double")) { //$NON-NLS-1$ + return new IJavaType[] { newValue(1d).getJavaType() }; + } + break; + } + return null; + } + IJavaType[] types = new IJavaType[classes.size()]; + for (int i = 0; i < types.length; i++) { + types[i] = JDIType.createType(this, classes.get(i)); + } + return types; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat + .format("{0} occurred while retrieving class for name {1}", e.toString(), name), e); //$NON-NLS-1$ + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + + @Override + public IJavaValue newValue(boolean value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(byte value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(char value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(double value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(float value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(int value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(long value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(short value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue newValue(String value) { + VirtualMachine vm = getVM(); + if (vm != null) { + Value v = vm.mirrorOf(value); + return JDIValue.createValue(this, v); + } + return null; + } + + @Override + public IJavaValue nullValue() { + return JDIValue.createValue(this, null); + } + + @Override + public IJavaValue voidValue() { + return new JDIVoidValue(this); + } + + protected boolean isTerminating() { + return fTerminating; + } + + protected void setTerminating(boolean terminating) { + fTerminating = terminating; + } + + protected boolean isDisconnecting() { + return fDisconnecting; + } + + protected void setDisconnecting(boolean disconnecting) { + fDisconnecting = disconnecting; + } + + /** + * An event handler for thread start events. When a thread starts in the + * target VM, a model thread is created. + */ + class ThreadStartHandler implements IJDIEventListener { + + protected EventRequest fRequest; + + protected ThreadStartHandler() { + createRequest(); + } + + /** + * Creates and registers a request to handle all thread start events + */ + protected void createRequest() { + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + try { + EventRequest req = manager.createThreadStartRequest(); + req.setSuspendPolicy(EventRequest.SUSPEND_NONE); + req.enable(); + addJDIEventListener(this, req); + setRequest(req); + } catch (RuntimeException e) { + logError(e); + } + } + } + + /** + * Creates a model thread for the underlying JDI thread and adds it to + * the collection of threads for this debug target. As a side effect of + * creating the thread, a create event is fired for the model thread. + * The event is ignored if the underlying thread is already marked as + * collected. + * + * @param event + * a thread start event + * @param target + * the target in which the thread started + * @return true - the thread should be resumed + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet) { + ThreadReference thread = ((ThreadStartEvent) event).thread(); + try { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=443727 + // the backing ThreadReference could be read in as null + if (thread == null || thread.isCollected()) { + return false; + } + } catch (VMDisconnectedException exception) { + return false; + } catch (ObjectCollectedException e) { + return false; + } catch (TimeoutException e) { + // continue - attempt to create the thread + } + JDIThread jdiThread = findThread(thread); + if (jdiThread == null) { + jdiThread = createThread(thread); + if (jdiThread == null) { + return false; + } + } else { + jdiThread.disposeStackFrames(); + jdiThread.fireChangeEvent(DebugEvent.CONTENT); + } + return !jdiThread.isSuspended(); + } + + @Override + public void eventSetComplete(Event event, JDIDebugTarget target, + boolean suspend, EventSet eventSet) { + // do nothing + } + + /** + * unregisters this event listener. + */ + protected void deleteRequest() { + if (getRequest() != null) { + removeJDIEventListener(this, getRequest()); + setRequest(null); + } + } + + protected EventRequest getRequest() { + return fRequest; + } + + protected void setRequest(EventRequest request) { + fRequest = request; + } + } + + /** + * An event handler for thread death events. When a thread dies in the + * target VM, its associated model thread is removed from the debug target. + */ + class ThreadDeathHandler implements IJDIEventListener { + + // terminated threads marked for removal from the fThreads list + private final Map toRemove = Collections.synchronizedMap(new HashMap<>()); + + protected ThreadDeathHandler() { + createRequest(); + } + + /** + * Creates and registers a request to listen to thread death events. + */ + protected void createRequest() { + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + try { + EventRequest req = manager.createThreadDeathRequest(); + req.setSuspendPolicy(EventRequest.SUSPEND_NONE); + req.enable(); + addJDIEventListener(this, req); + } catch (RuntimeException e) { + logError(e); + } + } + } + + /** + * Locates the model thread associated with the underlying JDI thread that has terminated, and marks it for removal from the collection of + * threads belonging to this debug target. A terminate event is fired for the model thread. + * + * @param event + * a thread death event + * @param target + * the target in which the thread died + * @return true - the thread should be resumed + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspend, EventSet eventSet) { + ThreadReference ref = ((ThreadDeathEvent) event).thread(); + JDIThread thread = findThread(ref); + if (thread == null) { + thread = target.findThread(ref); + } + if (thread != null) { + toRemove.put(event, thread); + // triggers DebugEvent + thread.terminated(); + } + return true; + } + + /** + * Removes the model thread associated with the underlying JDI thread that has terminated from the collection of threads belonging to this + * debug target. + * + * @param event + * a thread death event + * @param target + * the target in which the thread died + */ + @Override + public void eventSetComplete(Event event, JDIDebugTarget target, boolean suspendVote, EventSet eventSet) { + JDIThread thread = toRemove.remove(event); + if (thread != null) { + synchronized (fThreads) { + fThreads.remove(thread); + } + } + } + + } + + /** + * Triggers updates on a thread when {@link java.lang.Thread#setName(String)} is called on that thread, in the target JVM. + */ + class ThreadNameChangeHandler implements IJDIEventListener { + + /** + * Environment variable that can be passed down to Eclipse, to disable this listener. + */ + private static final String DISABLE_THREAD_NAME_CHANGE_LISTENER = "org.eclipse.jdt.internal.debug.core.model.ThreadNameChangeListener.disable"; //$NON-NLS-1$ + private static final String TYPE_NAME = "java.lang.Thread"; //$NON-NLS-1$ + private static final String METHOD_NAME = "setName"; //$NON-NLS-1$ + private static final String METHOD_SIGNATURE = "(Ljava/lang/String;)V"; //$NON-NLS-1$ + + private EventRequest request; + private ThreadChangeNotifierJob notfierJob; + + ThreadNameChangeHandler() { + String disableListenerSystemProperty = System.getProperty(DISABLE_THREAD_NAME_CHANGE_LISTENER); + boolean isDisabled = String.valueOf(Boolean.TRUE).equals(disableListenerSystemProperty); + if (!isDisabled) { + createRequest(); + notfierJob = new ThreadChangeNotifierJob(); + } + } + + /** + * Creates a breakpoint request at {@link java.lang.Thread#setName(String)} that doesn't suspend the target JVM. + */ + void createRequest() { + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + try { + Location location = locationOfSetNameMethod(); + if (location != null) { + request = manager.createBreakpointRequest(location); + request.setSuspendPolicy(EventRequest.SUSPEND_NONE); + request.enable(); + addJDIEventListener(this, request); + } + } catch (RuntimeException e) { + String errorMessage = "Failed to add thread name change listener to debug target " + JDIDebugTarget.this; //$NON-NLS-1$ + IStatus errorStatus = new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), errorMessage, e); + logRequestStatus(errorStatus); + } + } + } + + private Location locationOfSetNameMethod() { + List types = jdiClassesByName(TYPE_NAME); + boolean foundThreadType = false; + for (ReferenceType type : types) { + if (type instanceof ClassType) { + foundThreadType = true; + Method method = ((ClassType) type).concreteMethodByName(METHOD_NAME, METHOD_SIGNATURE); + if (method != null && !method.isNative()) { + Location location = method.location(); + if (location != null && location.codeIndex() != -1) { + return location; + } + logRequestWarning("Unable to find location of java.lang.Thread.setName() in debuggee JVM, for type " + type); //$NON-NLS-1$ + } else { + logRequestWarning("Unable to find java.lang.Thread.setName() method in debuggee JVM, for type " + type); //$NON-NLS-1$ + } + } + } + if (!foundThreadType) { + logRequestWarning("Unable to find type java.lang.Thread.setName() in debuggee JVM"); //$NON-NLS-1$ + } + return null; + } + + void deleteRequest() { + if (request != null) { + removeJDIEventListener(this, request); + } + if (notfierJob != null) { + notfierJob.stop(); + } + } + + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, boolean suspend, EventSet eventSet) { + ThreadReference ref = ((LocatableEvent) event).thread(); + JDIThread thread = findThread(ref); + if (thread == null) { + thread = target.findThread(ref); + } + if (thread != null) { + // trigger updates on the thread + notfierJob.notifyAboutChange(thread); + } + // we never suspend the thread + return true; + } + + @Override + public void eventSetComplete(Event event, JDIDebugTarget target, boolean suspendVote, EventSet eventSet) { + // nothing to do here, we do work in handleEvent + } + + private void logRequestWarning(String warningMessage) { + IStatus warningStatus = new Status(IStatus.WARNING, JDIDebugPlugin.getUniqueIdentifier(), warningMessage); + logRequestStatus(warningStatus); + } + + private void logRequestStatus(IStatus status) { + if (isAvailable()) { + JDIDebugPlugin.log(status); + } + } + } + + /** + * Job to throttle thread name change events notification. + */ + class ThreadChangeNotifierJob extends Job { + + private final LinkedHashSet queue; + + public ThreadChangeNotifierJob() { + super(JDIDebugModelMessages.JDIDebugTarget_ThreadNameNotifier); + setSystem(true); + setPriority(Job.DECORATE); + queue = new LinkedHashSet<>(); + } + + public void notifyAboutChange(JDIThread thread) { + synchronized (queue) { + if (queue.add(thread)) { + // if there are too many threads changing names, they may slow down debugger + int delay = Math.min(1000, 300 * queue.size()); + schedule(delay); + } + } + } + + void stop() { + synchronized (queue) { + queue.clear(); + } + cancel(); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + DebugEvent[] events; + synchronized (queue) { + events = queue.stream().map(t -> new DebugEvent(t, DebugEvent.CHANGE, DebugEvent.STATE)).toArray(DebugEvent[]::new); + queue.clear(); + } + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + // Dispatch known events + DebugPlugin.getDefault().fireDebugEventSet(events); + return Status.OK_STATUS; + } + + + @Override + public boolean belongsTo(Object family) { + return family == JDIDebugTarget.this; + } + } + + class CleanUpJob extends Job { + + /** + * Constructs a job to cleanup a hanging target. + */ + public CleanUpJob() { + super(JDIDebugModelMessages.JDIDebugTarget_0); + setSystem(true); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + if (isAvailable()) { + if (fEventDispatcher != null) { + fEventDispatcher.shutdown(); + } + disconnected(); + } + return Status.OK_STATUS; + } + + @Override + public boolean shouldRun() { + return isAvailable(); + } + + @Override + public boolean shouldSchedule() { + return isAvailable(); + } + + } + + protected ThreadStartHandler getThreadStartHandler() { + return fThreadStartHandler; + } + + protected void setThreadStartHandler(ThreadStartHandler threadStartHandler) { + fThreadStartHandler = threadStartHandler; + } + + private ThreadNameChangeHandler getThreadNameChangeHandler() { + return fThreadNameChangeHandler; + } + + private void setThreadNameChangeHandler(ThreadNameChangeHandler threadNameChangeHandler) { + fThreadNameChangeHandler = threadNameChangeHandler; + } + + /** + * Java debug targets do not support storage retrieval. + * + * @see IMemoryBlockRetrieval#supportsStorageRetrieval() + */ + @Override + public boolean supportsStorageRetrieval() { + return false; + } + + @Override + public IMemoryBlock getMemoryBlock(long startAddress, long length) + throws DebugException { + notSupported(JDIDebugModelMessages.JDIDebugTarget_does_not_support_storage_retrieval); + // this line will not be executed as #notSupported(String) + // will throw an exception + return null; + } + + @Override + public void launchRemoved(ILaunch launch) { + if (!isAvailable()) { + return; + } + if (launch.equals(getLaunch())) { + // This target has been unregistered, but it hasn't successfully + // terminated. + // Update internal state to reflect that it is disconnected + disconnected(); + } + } + + @Override + public void launchAdded(ILaunch launch) { + } + + @Override + public void launchChanged(ILaunch launch) { + } + + /** + * Sets whether the VM should be resumed on startup. Has no effect if the VM + * is already running when this target is created. + * + * @param resume + * whether the VM should be resumed on startup + */ + private synchronized void setResumeOnStartup(boolean resume) { + fResumeOnStartup = resume; + } + + /** + * Returns whether this VM should be resumed on startup. + * + * @return whether this VM should be resumed on startup + */ + protected synchronized boolean isResumeOnStartup() { + return fResumeOnStartup; + } + + @Override + public String[] getStepFilters() { + return fStepFilters; + } + + @Override + public boolean isFilterConstructors() { + return (fStepFilterMask & FILTER_CONSTRUCTORS) > 0; + } + + @Override + public boolean isFilterStaticInitializers() { + return (fStepFilterMask & FILTER_STATIC_INITIALIZERS) > 0; + } + + @Override + public boolean isFilterSynthetics() { + return (fStepFilterMask & FILTER_SYNTHETICS) > 0; + } + + /* + * (non-Javadoc) Was added in 3.3, made API in 3.5 + */ + @Override + public boolean isStepThruFilters() { + return (fStepFilterMask & STEP_THRU_FILTERS) > 0; + } + + @Override + public boolean isStepFiltersEnabled() { + return (fStepFilterMask & STEP_FILTERS_ENABLED) > 0; + } + + @Override + public void setFilterConstructors(boolean filter) { + if (filter) { + fStepFilterMask = fStepFilterMask | FILTER_CONSTRUCTORS; + } else { + fStepFilterMask = fStepFilterMask + & (FILTER_CONSTRUCTORS ^ XOR_MASK); + } + } + + @Override + public void setFilterStaticInitializers(boolean filter) { + if (filter) { + fStepFilterMask = fStepFilterMask | FILTER_STATIC_INITIALIZERS; + } else { + fStepFilterMask = fStepFilterMask + & (FILTER_STATIC_INITIALIZERS ^ XOR_MASK); + } + } + + @Override + public void setFilterSynthetics(boolean filter) { + if (filter) { + fStepFilterMask = fStepFilterMask | FILTER_SYNTHETICS; + } else { + fStepFilterMask = fStepFilterMask & (FILTER_SYNTHETICS ^ XOR_MASK); + } + } + + /* + * (non-Javadoc) Was added in 3.3, made API in 3.5 + */ + @Override + public void setStepThruFilters(boolean thru) { + if (thru) { + fStepFilterMask = fStepFilterMask | STEP_THRU_FILTERS; + } else { + fStepFilterMask = fStepFilterMask & (STEP_THRU_FILTERS ^ XOR_MASK); + } + } + + @Override + public boolean isFilterGetters() { + return (fStepFilterMask & FILTER_GETTERS) > 0; + } + + @Override + public void setFilterGetters(boolean filter) { + if (filter) { + fStepFilterMask = fStepFilterMask | FILTER_GETTERS; + } else { + fStepFilterMask = fStepFilterMask & (FILTER_GETTERS ^ XOR_MASK); + } + } + + @Override + public boolean isFilterSetters() { + return (fStepFilterMask & FILTER_SETTERS) > 0; + } + + @Override + public void setFilterSetters(boolean filter) { + if (filter) { + fStepFilterMask = fStepFilterMask | FILTER_SETTERS; + } else { + fStepFilterMask = fStepFilterMask & (FILTER_SETTERS ^ XOR_MASK); + } + } + + @Override + public void setStepFilters(String[] list) { + fStepFilters = list; + } + + @Override + public void setStepFiltersEnabled(boolean enabled) { + if (enabled) { + fStepFilterMask = fStepFilterMask | STEP_FILTERS_ENABLED; + } else { + fStepFilterMask = fStepFilterMask + & (STEP_FILTERS_ENABLED ^ XOR_MASK); + } + } + + @Override + public boolean hasThreads() { + return fThreads.size() > 0; + } + + @Override + public ILaunch getLaunch() { + return fLaunch; + } + + /** + * Sets the launch this target is contained in + * + * @param launch + * the launch this target is contained in + */ + private void setLaunch(ILaunch launch) { + fLaunch = launch; + } + + /** + * Returns the number of suspend events that have occurred in this target. + * + * @return the number of suspend events that have occurred in this target + */ + protected int getSuspendCount() { + return fSuspendCount; + } + + /** + * Increments the suspend counter for this target based on the reason for + * the suspend event. The suspend count is not updated for implicit + * evaluations. + * + * @param eventDetail + * the reason for the suspend event + */ + protected void incrementSuspendCount(int eventDetail) { + if (eventDetail != DebugEvent.EVALUATION_IMPLICIT) { + fSuspendCount++; + } + } + + /** + * Returns an evaluation engine for the given project, creating one if + * necessary. + * + * @param project + * java project + * @return evaluation engine + */ + public IAstEvaluationEngine getEvaluationEngine(IJavaProject project) { + if (fEngines == null) { + fEngines = new HashMap<>(2); + } + IAstEvaluationEngine engine = fEngines + .get(project); + if (engine == null) { + engine = EvaluationManager.newAstEvaluationEngine(project, this); + fEngines.put(project, engine); + } + return engine; + } + + @Override + public boolean supportsMonitorInformation() { + if (!isAvailable()) { + return false; + } + VirtualMachine vm = getVM(); + if (vm != null) { + return vm.canGetCurrentContendedMonitor() && vm.canGetMonitorInfo() + && vm.canGetOwnedMonitorInfo(); + } + return false; + } + + /** + * Sets whether or not this debug target is currently performing a hot code + * replace. + */ + public void setIsPerformingHotCodeReplace(boolean isPerformingHotCodeReplace) { + fIsPerformingHotCodeReplace = isPerformingHotCodeReplace; + } + + @Override + public boolean isPerformingHotCodeReplace() { + return fIsPerformingHotCodeReplace; + } + + @Override + public boolean supportsAccessWatchpoints() { + VirtualMachine vm = getVM(); + if (isAvailable() && vm != null) { + return vm.canWatchFieldAccess(); + } + return false; + } + + @Override + public boolean supportsModificationWatchpoints() { + VirtualMachine vm = getVM(); + if (isAvailable() && vm != null) { + return vm.canWatchFieldModification(); + } + return false; + } + + @Override + public void setDefaultStratum(String stratum) { + VirtualMachine vm = getVM(); + if (vm != null) { + vm.setDefaultStratum(stratum); + } + } + + @Override + public String getDefaultStratum() { + VirtualMachine vm = getVM(); + if (vm != null) { + return vm.getDefaultStratum(); + } + return null; + } + + @Override + public boolean supportsStepFilters() { + return isAvailable(); + } + + /** + * When the breakpoint manager disables, remove all registered breakpoints + * requests from the VM. When it enables, reinstall them. + */ + @Override + public void breakpointManagerEnablementChanged(boolean enabled) { + if (!isAvailable()) { + return; + } + List list = new ArrayList<>(getBreakpoints()); + for(IBreakpoint bp : list) { + JavaBreakpoint breakpoint = (JavaBreakpoint) bp; + try { + if (enabled) { + breakpoint.addToTarget(this); + } else if (breakpoint.shouldSkipBreakpoint()) { + breakpoint.removeFromTarget(this); + } + } catch (CoreException e) { + logError(e); + } + } + } + + @Override + public void handleDebugEvents(DebugEvent[] events) { + if (events.length == 1) { + DebugEvent event = events[0]; + if (event.getSource().equals(getProcess()) + && event.getKind() == DebugEvent.TERMINATE) { + // schedule a job to clean up the target in case we never get a + // terminate/disconnect + // event from the VM + int timeout = getRequestTimeout(); + if (timeout < 0) { + timeout = 3000; + } + new CleanUpJob().schedule(timeout); + } + } + } + + @Override + public IDebugTarget getDebugTarget() { + return this; + } + + /** + * Adds the given thread group to the list of known thread groups. Also adds + * any parent thread groups that have not already been added to the list. + * + * @param group + * thread group to add + */ + void addThreadGroup(ThreadGroupReference group) { + ThreadGroupReference currentGroup = group; + while (currentGroup != null) { + synchronized (fGroups) { + if (findThreadGroup(currentGroup) == null) { + JDIThreadGroup modelGroup = new JDIThreadGroup(this, + currentGroup); + fGroups.add(modelGroup); + currentGroup = currentGroup.parent(); + } else { + currentGroup = null; + } + } + } + } + + JDIThreadGroup findThreadGroup(ThreadGroupReference group) { + synchronized (fGroups) { + Iterator groups = fGroups.iterator(); + while (groups.hasNext()) { + JDIThreadGroup modelGroup = groups.next(); + if (modelGroup.getUnderlyingThreadGroup().equals(group)) { + return modelGroup; + } + } + } + return null; + } + + @Override + public IJavaThreadGroup[] getRootThreadGroups() throws DebugException { + try { + VirtualMachine vm = getVM(); + if (vm == null) { + return new IJavaThreadGroup[0]; + } + List groups = vm.topLevelThreadGroups(); + List modelGroups = new ArrayList<>(groups.size()); + for(ThreadGroupReference ref : groups) { + JDIThreadGroup group = findThreadGroup(ref); + if (group != null) { + modelGroups.add(group); + } + } + return modelGroups.toArray(new IJavaThreadGroup[modelGroups.size()]); + } catch (VMDisconnectedException e) { + // if the VM has disconnected, there are no thread groups + return new IJavaThreadGroup[0]; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIDebugTarget_1, e); + } + return null; + } + + @Override + public IJavaThreadGroup[] getAllThreadGroups() throws DebugException { + synchronized (fGroups) { + return fGroups + .toArray(new IJavaThreadGroup[fGroups.size()]); + } + } + + @Override + public boolean supportsInstanceRetrieval() { + VirtualMachine vm = getVM(); + if (vm != null) { + return vm.canGetInstanceInfo(); + } + return false; + } + + /** + * Sends a JDWP command to the back end and returns the JDWP reply packet as + * bytes. This method creates an appropriate command header and packet id, + * before sending to the back end. + * + * @param commandSet + * command set identifier as defined by JDWP + * @param commandId + * command identifier as defined by JDWP + * @param data + * any bytes required for the command that follow the command + * header or null for commands that have no data + * @return raw reply packet as bytes defined by JDWP + * @exception IOException + * if an error occurs sending the packet or receiving the + * reply + * @since 3.3 + */ + public byte[] sendJDWPCommand(byte commandSet, byte commandId, byte[] data) + throws IOException { + int command = (256 * commandSet) + commandId; + JdwpReplyPacket reply = ((VirtualMachineImpl) getVM()).requestVM( + command, data); + return reply.getPacketAsBytes(); + } + + @Override + public boolean supportsForceReturn() { + VirtualMachine machine = getVM(); + if (machine == null) { + return false; + } + return machine.canForceEarlyReturn(); + } + + @Override + public boolean supportsSelectiveGarbageCollection() { + return fSupportsDisableGC; + } + + /** + * Sets whether this target supports selectively disabling/enabling garbage + * collection of specific objects. + * + * @param enableGC + * whether this target supports selective GC + */ + void setSupportsSelectiveGarbageCollection(boolean enableGC) { + fSupportsDisableGC = enableGC; + } + + @Override + public String getVMName() throws DebugException { + VirtualMachine vm = getVM(); + if (vm == null) { + requestFailed(JDIDebugModelMessages.JDIDebugTarget_2, + new VMDisconnectedException()); + } + try { + return vm.name(); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIDebugTarget_2, e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + + @Override + public String getVersion() throws DebugException { + VirtualMachine vm = getVM(); + if (vm == null) { + requestFailed(JDIDebugModelMessages.JDIDebugTarget_4, + new VMDisconnectedException()); + } + try { + return vm.version(); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIDebugTarget_4, e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + + @Override + public void refreshState() throws DebugException { + if (isTerminated() || isDisconnected()) { + return; + } + boolean prevSuspend = isSuspended(); + int running = 0; + List toSuspend = new ArrayList<>(); + List toResume = new ArrayList<>(); + List toRefresh = new ArrayList<>(); + Iterator iterator = getThreadIterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + boolean modelSuspended = thread.isSuspended(); + ThreadReference reference = thread.getUnderlyingThread(); + try { + boolean realSuspended = reference.isSuspended(); + if (realSuspended) { + if (modelSuspended) { + // Even if the model is suspended, it might be in a + // different location so refresh + toRefresh.add(thread); + } else { + // The thread is actually suspended, refresh frames and + // fire suspend event. + toSuspend.add(thread); + } + } else { + running++; + if (modelSuspended) { + // thread is actually running, model is suspended, + // resume model + toResume.add(thread); + } + // else both are running - OK + } + } catch (InternalException e) { + requestFailed(e.getMessage(), e); + } + } + // if the entire target changed state/fire events at target level, else + // fire thread events + boolean targetLevelEvent = false; + if (prevSuspend) { + if (running > 0) { + // was suspended, but now a thread is running + targetLevelEvent = true; + } + } else { + if (running == 0) { + // was running, but now all threads are suspended + targetLevelEvent = true; + } + } + if (targetLevelEvent) { + iterator = toSuspend.iterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + thread.suspendedByVM(); + } + iterator = toResume.iterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + thread.resumedByVM(); + } + iterator = toRefresh.iterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + thread.preserveStackFrames(); + } + if (running == 0) { + synchronized (this) { + setSuspended(true); + } + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + } else { + synchronized (this) { + setSuspended(false); + } + fireResumeEvent(DebugEvent.CLIENT_REQUEST); + } + } else { + iterator = toSuspend.iterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + thread.preserveStackFrames(); + thread.setRunning(false); + thread.fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + } + iterator = toResume.iterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + thread.setRunning(true); + thread.fireResumeEvent(DebugEvent.CLIENT_REQUEST); + } + iterator = toRefresh.iterator(); + while (iterator.hasNext()) { + JDIThread thread = iterator.next(); + thread.preserveStackFrames(); + thread.fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + } + } + + } + + @Override + public byte[] sendCommand(byte commandSet, byte commandId, byte[] data) + throws DebugException { + try { + return sendJDWPCommand(commandSet, commandId, data); + } catch (IOException e) { + requestFailed(e.getMessage(), e); + } + return null; + } + + @Override + public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) { + fHCRListeners.add(listener); + } + + @Override + public void removeHotCodeReplaceListener( + IJavaHotCodeReplaceListener listener) { + fHCRListeners.remove(listener); + } + + /** + * Returns the current hot code replace listeners. + * + * @return registered hot code replace listeners + * @since 3.10 + */ + public ListenerList getHotCodeReplaceListeners() { + return fHCRListeners; + } + + /** + * Filters elements out of the given collections of resources and qualified names if there is no related resources in the given debug target. This + * method allows us to avoid bogus HCR attempts and "HCR failed" notifications. + * + * @param resourcesToFilter + * the list of resources to filter + * @param qualifiedNamesToFilter + * the list of qualified names to filter, which corresponds to the list of resources on a one-to-one-basis + */ + public void filterUnrelatedResources(List resourcesToFilter, List qualifiedNamesToFilter) { + Iterator resources = resourcesToFilter.iterator(); + Iterator names = qualifiedNamesToFilter.iterator(); + while (resources.hasNext()) { + boolean supported = supportsResource(() -> names.next(), resources.next()); + if (!supported) { + resources.remove(); + names.remove(); + } + } + } + + /** + * Filters elements out of the given collections of resources and qualified names if there is no type corresponding type loaded in the given debug + * target. This method allows us to avoid bogus HCR attempts and "HCR failed" notifications. + * + * @param resources + * the list of resources to filter + * @param qualifiedNames + * the list of qualified names to filter, which corresponds to the list of resources on a one-to-one-basis + */ + public void filterNotLoadedTypes(List resources, List qualifiedNames) { + for (int i = 0, numElements = qualifiedNames.size(); i < numElements; i++) { + String name = qualifiedNames.get(i); + List list = jdiClassesByName(name); + if (list.isEmpty()) { + // If no classes with the given name are loaded in the VM, don't + // waste cycles trying to replace. + qualifiedNames.remove(i); + resources.remove(i); + // Decrement the index and number of elements to compensate for + // item removal + i--; + numElements--; + } + } + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIFieldVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIFieldVariable.java new file mode 100644 index 0000000000..28d3779edc --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIFieldVariable.java @@ -0,0 +1,397 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaModifiers; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * A field member. + */ +public class JDIFieldVariable extends JDIModificationVariable implements + IJavaFieldVariable { + /** + * The underlying field + */ + private final Field fField; + /** + * The object containing the field, or null for a static field. + */ + private ObjectReference fObject; + /** + * The type containing the field. + */ + private final ReferenceType fType; + + /** + * When created for a logical structure we hold onto the original + * non-logical value for purposes of equality. This way a logical + * structure's children remain more stable in the variables view. + * + * This is null when not created for a logical structure. + */ + private IJavaValue fLogicalParent; + + /** + * Constructs a field for the given field. + */ + public JDIFieldVariable(JDIDebugTarget target, Field field, + ObjectReference objectRef, IJavaValue logicalParent) { + super(target); + fField = field; + if (!field.isStatic()) { + fObject = objectRef; + } + fType = (ReferenceType) objectRef.type(); + fLogicalParent = logicalParent; + } + + /** + * Constructs a field to wrap the given field. + */ + public JDIFieldVariable(JDIDebugTarget target, Field field, + ReferenceType refType) { + super(target); + fField = field; + fType = refType; + } + + /** + * Returns this variable's current Value. + */ + @Override + protected Value retrieveValue() { + if (getField().isStatic()) { + return (getField().declaringType().getValue(getField())); + } + return getObjectReference().getValue(getField()); + } + + /** + * @see IJavaFieldVariable#getDeclaringType() + */ + @Override + public IJavaType getDeclaringType() { + return JDIType.createType((JDIDebugTarget) getDebugTarget(), + fField.declaringType()); + } + + /** + * @see IVariable#getName() + */ + @Override + public String getName() throws DebugException { + try { + return getField().name(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_retrieving_field_name, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + @Override + protected void setJDIValue(Value value) throws DebugException { + try { + if (isStatic()) { + ReferenceType declaringType = getField().declaringType(); + if (declaringType instanceof InterfaceType) { + requestFailed(JDIDebugModelMessages.JDIFieldVariable_0, + null); + } + ((ClassType) declaringType).setValue(getField(), value); + } else { + getObjectReference().setValue(getField(), value); + } + fireChangeEvent(DebugEvent.CONTENT); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_modifying_value, + e.toString()), e); + } catch (InvalidTypeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_modifying_value, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_modifying_value, + e.toString()), e); + } + + } + + /** + * @see IJavaVariable#isVolatile() + */ + @Override + public boolean isVolatile() { + return getField().isVolatile(); + } + + /** + * @see IJavaVariable#isTransient() + */ + @Override + public boolean isTransient() { + return getField().isTransient(); + } + + /** + * @see IJavaModifiers#isSynthetic() + */ + @Override + public boolean isSynthetic() { + return getField().isSynthetic(); + } + + /** + * @see IJavaModifiers#isPublic() + */ + @Override + public boolean isPublic() { + return getField().isPublic(); + } + + /** + * @see IJavaModifiers#isPrivate() + */ + @Override + public boolean isPrivate() { + return getField().isPrivate(); + } + + /** + * @see IJavaModifiers#isProtected() + */ + @Override + public boolean isProtected() { + return getField().isProtected(); + } + + /** + * @see IJavaModifiers#isPackagePrivate() + */ + @Override + public boolean isPackagePrivate() { + return getField().isPackagePrivate(); + } + + /** + * @see IJavaModifiers#isStatic() + */ + @Override + public boolean isStatic() { + return getField().isStatic(); + } + + /** + * @see IJavaModifiers#isFinal() + */ + @Override + public boolean isFinal() { + return getField().isFinal(); + } + + /** + * @see IVariable#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + String genericSignature = getField().genericSignature(); + if (genericSignature != null) { + return JDIReferenceType.getTypeName(genericSignature); + } + Type underlyingType = getUnderlyingType(); + if (underlyingType instanceof ReferenceType) { + return JDIReferenceType + .getGenericName((ReferenceType) underlyingType); + } + return getField().typeName(); + } + + /** + * @see IJavaVariable#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + return getField().signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_retrieving_field_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + try { + String genericSignature = fField.genericSignature(); + if (genericSignature != null) { + return genericSignature; + } + return fField.signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_retrieving_field_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + public Field getField() { + return fField; + } + + public ObjectReference getObjectReference() { + return fObject; + } + + public ReferenceType getReferenceType() { + return fType; + } + + @Override + public boolean supportsValueModification() { + if (getField().declaringType() instanceof InterfaceType) { + return false; + } + return super.supportsValueModification(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getField().toString(); + } + + /** + * @see JDIVariable#getUnderlyingType() + */ + @Override + protected Type getUnderlyingType() throws DebugException { + try { + return getField().type(); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_while_retrieving_type_of_field, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIFieldVariable_exception_while_retrieving_type_of_field, + e.toString()), e); + } + // this line will not be executed as an exception + // will be throw in type retrieval fails + return null; + } + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (o instanceof JDIFieldVariable) { + JDIFieldVariable f = (JDIFieldVariable) o; + if (fLogicalParent != null) { + return fLogicalParent.equals(f.fLogicalParent) + && f.fField.equals(fField); + } + if (fObject != null) { + return fObject.equals(f.fObject) && f.fField.equals(fField); + } + return f.fField.equals(fField); + } + return false; + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + if (fLogicalParent != null) { + return fLogicalParent.hashCode() + fField.hashCode(); + } + if (fObject != null) { + return fField.hashCode() + fObject.hashCode(); + } + return fField.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaFieldVariable#getObject() + */ + @Override + public IJavaObject getReceiver() { + ObjectReference objectReference = getObjectReference(); + if (objectReference == null) { + return null; + } + return (IJavaObject) JDIValue.createValue(getJavaDebugTarget(), + objectReference); + } + + @Override + public IJavaReferenceType getReceivingType() { + return (IJavaReferenceType) JDIType.createType(getJavaDebugTarget(), + getReferenceType()); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIInterfaceType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIInterfaceType.java new file mode 100644 index 0000000000..be0c946a2b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIInterfaceType.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; + +import com.sun.jdi.ClassType; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Method; +import com.sun.jdi.Value; + +/** + * The interface of an object in a debug target. + */ +public class JDIInterfaceType extends JDIReferenceType implements + IJavaInterfaceType { + + /** + * Constructs a new interface type on the given target referencing the + * specified interface type. + */ + public JDIInterfaceType(JDIDebugTarget target, InterfaceType type) { + super(target, type); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaInterfaceType#getImplementors() + */ + @Override + public IJavaClassType[] getImplementors() throws DebugException { + try { + List implementorList = ((InterfaceType) getUnderlyingType()) + .implementors(); + List javaClassTypeList = new ArrayList<>(implementorList.size()); + Iterator iterator = implementorList.iterator(); + while (iterator.hasNext()) { + ClassType classType = iterator.next(); + if (classType != null) { + javaClassTypeList.add(JDIType.createType( + getJavaDebugTarget(), classType)); + } + } + IJavaClassType[] javaClassTypeArray = new IJavaClassType[javaClassTypeList + .size()]; + javaClassTypeArray = javaClassTypeList + .toArray(javaClassTypeArray); + return javaClassTypeArray; + } catch (RuntimeException re) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_superclass, + re.toString()), re); + } + return new IJavaClassType[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaInterfaceType#getSubInterfaces() + */ + @Override + public IJavaInterfaceType[] getSubInterfaces() throws DebugException { + try { + List subList = ((InterfaceType) getUnderlyingType()) + .subinterfaces(); + List javaInterfaceTypeList = new ArrayList<>(subList.size()); + Iterator iterator = subList.iterator(); + while (iterator.hasNext()) { + InterfaceType interfaceType = iterator.next(); + if (interfaceType != null) { + javaInterfaceTypeList.add(JDIType.createType( + getJavaDebugTarget(), interfaceType)); + } + } + IJavaInterfaceType[] javaInterfaceTypeArray = new IJavaInterfaceType[javaInterfaceTypeList + .size()]; + javaInterfaceTypeArray = javaInterfaceTypeList + .toArray(javaInterfaceTypeArray); + return javaInterfaceTypeArray; + } catch (RuntimeException re) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_superclass, + re.toString()), re); + } + return new IJavaInterfaceType[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaInterfaceType#getSuperInterfaces() + */ + @Override + public IJavaInterfaceType[] getSuperInterfaces() throws DebugException { + try { + List superList = ((InterfaceType) getUnderlyingType()) + .superinterfaces(); + List javaInterfaceTypeList = new ArrayList<>(superList.size()); + Iterator iterator = superList.iterator(); + while (iterator.hasNext()) { + InterfaceType interfaceType = iterator.next(); + if (interfaceType != null) { + javaInterfaceTypeList.add(JDIType.createType( + getJavaDebugTarget(), interfaceType)); + } + } + IJavaInterfaceType[] javaInterfaceTypeArray = new IJavaInterfaceType[javaInterfaceTypeList + .size()]; + javaInterfaceTypeArray = javaInterfaceTypeList + .toArray(javaInterfaceTypeArray); + return javaInterfaceTypeArray; + } catch (RuntimeException re) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_superclass, + re.toString()), re); + } + return new IJavaInterfaceType[0]; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaInterfaceType#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread) throws DebugException { + if (getUnderlyingType() instanceof InterfaceType) { + InterfaceType iface = (InterfaceType) getUnderlyingType(); + JDIThread javaThread = (JDIThread) thread; + List arguments = convertArguments(args); + Method method = null; + try { + List methods = iface.methodsByName(selector, signature); + if (methods.isEmpty()) { + requestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_Type_does_not_implement_selector, + selector, signature), null); + } else { + method = methods.get(0); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_performing_method_lookup_for_selector, + e.toString(), selector, signature), e); + } + Value result = javaThread.invokeMethod(iface, method, arguments); + return JDIValue.createValue(getJavaDebugTarget(), result); + } + requestFailed( + JDIDebugModelMessages.JDIClassType_Type_is_not_a_class_type, + null); + // execution will not fall through to here, + // as #requestFailed will throw an exception + return null; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDILocalVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDILocalVariable.java new file mode 100644 index 0000000000..d87e8ab700 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDILocalVariable.java @@ -0,0 +1,257 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaVariable; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * A JDILocalVariable represents a local variable in a stack frame. + */ + +public class JDILocalVariable extends JDIModificationVariable { + /** + * The underlying local variable + */ + private LocalVariable fLocal; + + /** + * The stack frame the local is contained in + */ + private final JDIStackFrame fStackFrame; + + /** + * Constructs a local variable for the given local in a stack frame. + */ + public JDILocalVariable(JDIStackFrame frame, LocalVariable local) { + super((JDIDebugTarget) frame.getDebugTarget()); + fStackFrame = frame; + fLocal = local; + } + + /** + * Returns this variable's current Value. + */ + @Override + protected Value retrieveValue() throws DebugException { + synchronized (fStackFrame.getThread()) { + if (getStackFrame().isSuspended()) { + StackFrame frame = getStackFrame().getUnderlyingStackFrame(); + if (frame != null) { + return frame.getValue(fLocal); + } + } + } + // bug 6518 + return getLastKnownValue(); + } + + /** + * @see IVariable#getName() + */ + @Override + public String getName() throws DebugException { + try { + return getLocal().name(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_retrieving_local_variable_name, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * @see JDIModificationVariable#setValue(Value) + */ + @Override + protected void setJDIValue(Value value) throws DebugException { + try { + synchronized (getStackFrame().getThread()) { + StackFrame frame = getStackFrame().getUnderlyingStackFrame(); + if (frame != null) { + frame.setValue(getLocal(), value); + } else { + String errorMessage = JDIDebugModelMessages.JDIStackFrame_NoLongerAvailable; + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_modifying_local_variable_value, + errorMessage), new Throwable(errorMessage)); // use Throwable, as RuntimeException is re-thrown + } + } + fireChangeEvent(DebugEvent.CONTENT); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_modifying_local_variable_value, + e.toString()), e); + } catch (InvalidTypeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_modifying_local_variable_value, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_modifying_local_variable_value, + e.toString()), e); + } + } + + /** + * @see IVariable#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + try { + String genericSignature = getLocal().genericSignature(); + if (genericSignature != null) { + return JDIReferenceType.getTypeName(genericSignature); + } + try { + Type underlyingType = getUnderlyingType(); + if (underlyingType instanceof ReferenceType) { + return JDIReferenceType + .getGenericName((ReferenceType) underlyingType); + } + } catch (DebugException e) { + if (!(e.getStatus().getException() instanceof ClassNotLoadedException)) { + throw e; + } + } + return getLocal().typeName(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_retrieving_local_variable_type_name, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * @see IJavaVariable#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + return getLocal().signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_retrieving_local_variable_type_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + try { + String genericSignature = fLocal.genericSignature(); + if (genericSignature != null) { + return genericSignature; + } + return fLocal.signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_retrieving_local_variable_type_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * Updates this local's underlying variable. Called by enclosing stack frame + * when doing an incremental update. + */ + protected void setLocal(LocalVariable local) { + fLocal = local; + } + + protected LocalVariable getLocal() { + return fLocal; + } + + protected JDIStackFrame getStackFrame() { + return fStackFrame; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getLocal().toString(); + } + + /** + * @see JDIVariable#getUnderlyingType() + */ + @Override + protected Type getUnderlyingType() throws DebugException { + try { + return getLocal().type(); + } catch (ClassNotLoadedException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_while_retrieving_type_of_local_variable, + e.toString()), e); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDILocalVariable_exception_while_retrieving_type_of_local_variable, + e.toString()), e); + } + // this line will not be executed as an exception + // will be throw in type retrieval fails + return null; + } + + /** + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#isLocal() + */ + @Override + public boolean isLocal() { + return true; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIMethod.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIMethod.java new file mode 100644 index 0000000000..d384b07bb1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIMethod.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 Jesper Steen Moller and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Jesper Steen Moller - initial API and implementation + * IBM Corporation - Bug fixing + *******************************************************************************/ + +package org.eclipse.jdt.internal.debug.core.model; + +import com.sun.jdi.Method; + +/** + * Class for analysing Java methods while debugging. + * + * @author jmoeller2 + * + */ +public class JDIMethod { + + // Known Java byte codes, from the JVM spec + private static final int ALOAD_0 = 0x2a; + + private static final int ILOAD_1 = 0x1b; + private static final int LLOAD_1 = 0x1f; + private static final int FLOAD_1 = 0x23; + private static final int DLOAD_1 = 0x27; + private static final int ALOAD_1 = 0x2b; + + private static final int IRETURN = 0xac; + private static final int LRETURN = 0xad; + private static final int FRETURN = 0xae; + private static final int DRETURN = 0xaf; + private static final int ARETURN = 0xb0; + + private static final int GETFIELD = 0xb4; + private static final int PUTFIELD = 0xb5; + + private static final int RETURN = 0xb1; + + /** + * Determines if the opcode passes in is one of the value return + * instructions. + * + * @param opCode + * opCode to check + * @return If opCode is one of 'areturn', 'ireturn', etc. + */ + public static final boolean isXReturn(byte opCode) { + return (opCode & 0xFF) == IRETURN || (opCode & 0xFF) == LRETURN + || (opCode & 0xFF) == FRETURN || (opCode & 0xFF) == DRETURN + || (opCode & 0xFF) == ARETURN; + } + + /** + * Determines if the opcode passes in is one of the 'loado_1' instruxtions. + * + * @param opCode + * opCode to check + * @return If opCode is one of 'aload_1', 'iload_1', etc. + */ + public static final boolean isXLoad1(byte opCode) { + return (opCode & 0xFF) == ILOAD_1 || (opCode & 0xFF) == LLOAD_1 + || (opCode & 0xFF) == FLOAD_1 || (opCode & 0xFF) == DLOAD_1 + || (opCode & 0xFF) == ALOAD_1; + } + + /** + * Determines if the method in question is a simple getter, JavaBean style. + * + * Simple getters have byte code which look like this, and they start with + * "get" or "is": + * + * 0 aload_0 1 getfield 4 Xreturn + * + * @param method + * Method to check + * @return true if the method is a simple getter + */ + public static boolean isGetterMethod(Method method) { + if (!(method.name().startsWith("get") || method.name().startsWith("is"))) //$NON-NLS-1$ //$NON-NLS-2$ + { + return false; + } + + byte[] bytecodes = method.bytecodes(); + return bytecodes.length == 5 && (bytecodes[0] & 0xFF) == ALOAD_0 + && (bytecodes[1] & 0xFF) == GETFIELD && isXReturn(bytecodes[4]); + } + + /** + * Determines if the method in question is a simple getter, JavaBean style. + * + * Simple setters have byte code which look like this, and they start with + * "set": + * + * 0 aload_0 1 Xload_1 2 putfield 5 return + * + * @param method + * Method to check + * @return true if the method is a simple setter + */ + public static boolean isSetterMethod(Method method) { + if (!method.name().startsWith("set")) { //$NON-NLS-1$ + return false; + } + + byte[] bytecodes = method.bytecodes(); + return bytecodes.length == 6 && (bytecodes[0] & 0xFF) == ALOAD_0 + && isXLoad1(bytecodes[1]) && (bytecodes[2] & 0xFF) == PUTFIELD + && (bytecodes[5] & 0xFF) == RETURN; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIModificationVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIModificationVariable.java new file mode 100644 index 0000000000..87230b19fa --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIModificationVariable.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2000, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdi.internal.ValueImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; + +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; + +/** + * Common functionality for variables that support value modification + */ +public abstract class JDIModificationVariable extends JDIVariable { + + public JDIModificationVariable(JDIDebugTarget target) { + super(target); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#supportsValueModification + * () + */ + @Override + public boolean supportsValueModification() { + return true; + } + + /** + * Returns a value generated by the vm from the given expression + * + * @param expression + * the expression to produce a value from + * @return generated value, null is a valid value + * @throws DebugException + * if there is a problem generating the value + */ + protected Value generateVMValue(String expression) throws DebugException { + VirtualMachine vm = getVM(); + if (vm == null) { + requestFailed( + JDIDebugModelMessages.JDIModificationVariable_Unable_to_generate_value___VM_disconnected__1, + new VMDisconnectedException()); + } + String signature = getJavaType().getSignature(); + Value vmValue = null; + try { + switch (signature.charAt(0)) { + case 'Z': + String flse = Boolean.FALSE.toString(); + String tre = Boolean.TRUE.toString(); + if (expression.equals(tre) || expression.equals(flse)) { + boolean booleanValue = Boolean.parseBoolean(expression); + vmValue = vm.mirrorOf(booleanValue); + } + break; + case 'B': + byte byteValue = Byte.parseByte(expression); + vmValue = vm.mirrorOf(byteValue); + break; + case 'C': + if (expression.length() == 1) { + char charValue = expression.charAt(0); + vmValue = vm.mirrorOf(charValue); + } else if (expression.length() == 2) { + char charValue; + if (!(expression.charAt(0) == '\\')) { + return null; + } + switch (expression.charAt(1)) { + case 'b': + charValue = '\b'; + break; + case 'f': + charValue = '\f'; + break; + case 'n': + charValue = '\n'; + break; + case 'r': + charValue = '\r'; + break; + case 't': + charValue = '\t'; + break; + case '\'': + charValue = '\''; + break; + case '\"': + charValue = '\"'; + break; + case '\\': + charValue = '\\'; + break; + default: + return null; + } + vmValue = vm.mirrorOf(charValue); + } + break; + case 'S': + short shortValue = Short.parseShort(expression); + vmValue = vm.mirrorOf(shortValue); + break; + case 'I': + int intValue = Integer.parseInt(expression); + vmValue = vm.mirrorOf(intValue); + break; + case 'J': + long longValue = Long.parseLong(expression); + vmValue = vm.mirrorOf(longValue); + break; + case 'F': + float floatValue = Float.parseFloat(expression); + vmValue = vm.mirrorOf(floatValue); + break; + case 'D': + double doubleValue = Double.parseDouble(expression); + vmValue = vm.mirrorOf(doubleValue); + break; + case 'L': + if (expression.equals("null")) { //$NON-NLS-1$ + vmValue = null; + } else if (expression.equals("\"null\"")) { //$NON-NLS-1$ + vmValue = vm.mirrorOf("null"); //$NON-NLS-1$ + } else { + vmValue = vm.mirrorOf(expression); + } + break; + + } + } catch (NumberFormatException nfe) { + requestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIModificationVariable_0, + getJavaType().toString()), nfe); + } + return vmValue; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#verifyValue(java.lang + * .String) + */ + @Override + public boolean verifyValue(String expression) throws DebugException { + Value vmValue = generateVMValue(expression); + IValue value = JDIValue.createValue(getJavaDebugTarget(), vmValue); + return verifyValue(value); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#verifyValue(org.eclipse + * .debug.core.model.IValue) + */ + @Override + public boolean verifyValue(IValue value) throws DebugException { + if (value instanceof JDIValue + && value.getDebugTarget().equals(getDebugTarget())) { + JDIValue jv = (JDIValue) value; + try { + ValueImpl.checkValue(jv.getUnderlyingValue(), + getUnderlyingType(), (VirtualMachineImpl) getVM()); + return true; + } catch (InvalidTypeException e) { + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.debug.core.model.IValueModification#setValue(java.lang.String + * ) + */ + @Override + public final void setValue(String expression) throws DebugException { + Value value = generateVMValue(expression); + setJDIValue(value); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIVariable#setValue(org.eclipse + * .debug.core.model.IValue) + */ + @Override + public final void setValue(IValue v) throws DebugException { + if (v instanceof JDIValue) { + JDIValue value = (JDIValue) v; + setJDIValue(value.getUnderlyingValue()); + } + } + + /** + * Set this variable's value to the given value + */ + protected abstract void setJDIValue(Value value) throws DebugException; + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDINullValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDINullValue.java new file mode 100644 index 0000000000..72e7437517 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDINullValue.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + + + +/** + * Represents a value of "null" + */ +public class JDINullValue extends JDIObjectValue { + + /** + * Constructor + * + * @param target + */ + public JDINullValue(JDIDebugTarget target) { + super(target, null); + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getVariablesList() + */ + @Override + protected List getVariablesList() { + return Collections.EMPTY_LIST; + } + + /** + * @see IValue#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() { + return "null"; //$NON-NLS-1$ + } + + /** + * @see IValue#getValueString() + */ + @Override + public String getValueString() { + return "null"; //$NON-NLS-1$ + } + + /** + * @see IJavaValue#getSignature() + */ + @Override + public String getSignature() { + return null; + } + + /** + * @see IJavaValue#getArrayLength() + */ + @Override + public int getArrayLength() { + return -1; + } + + /** + * @see IJavaValue#getJavaType() + */ + @Override + public IJavaType getJavaType() { + return null; + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object obj) { + return obj instanceof JDINullValue; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return getClass().hashCode(); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "null"; //$NON-NLS-1$ + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getField(java.lang.String, + * boolean) + */ + @Override + public IJavaFieldVariable getField(String name, boolean superField) { + return null; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getField(java.lang.String, + * java.lang.String) + */ + @Override + public IJavaFieldVariable getField(String name, String typeSignature) { + return null; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getWaitingThreads() + */ + @Override + public IJavaThread[] getWaitingThreads() { + return null; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getOwningThread() + */ + @Override + public IJavaThread getOwningThread() { + return null; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getReferringObjects(long) + */ + @Override + public IJavaObject[] getReferringObjects(long max) { + return new IJavaObject[0]; + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread, boolean) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, boolean superSend) + throws DebugException { + return npe(selector, signature); + } + + /** + * @see org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread, java.lang.String) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, String typeSignature) + throws DebugException { + return npe(selector, signature); + } + + /** + * Creates an artificial NPE for display to the user as an error message + * + * @param selector + * @param signature + * @return + * @throws DebugException + */ + private IJavaValue npe(String selector, String signature) + throws DebugException { + StringBuilder buffer = new StringBuilder(); + buffer.append(selector); + String[] parameterTypes = Signature.getParameterTypes(signature); + buffer.append('('); + for (int i = 0; i < parameterTypes.length; i++) { + buffer.append(Signature.getSignatureSimpleName(parameterTypes[i] + .replace('/', '.'))); + if (i + 1 < parameterTypes.length) { + buffer.append(", "); //$NON-NLS-1$ + } + } + buffer.append(')'); + requestFailed(MessageFormat.format( + JDIDebugModelMessages.JDINullValue_0, + buffer.toString()), new NullPointerException()); + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#disableCollection + * () + */ + @Override + public void disableCollection() throws DebugException { + // Do nothing for null values + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#enableCollection + * () + */ + @Override + public void enableCollection() throws DebugException { + // Do nothing for null values + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#isNull() + */ + @Override + public boolean isNull() { + return true; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIObjectValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIObjectValue.java new file mode 100644 index 0000000000..9345fbbe0e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIObjectValue.java @@ -0,0 +1,649 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper S. Møller - bug 422029: [1.8] Enable debug evaluation support for default methods + * Jesper Steen Møller - bug 426903: [1.8] Cannot evaluate super call to default method + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdi.internal.InterfaceTypeImpl; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; + +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; + +/** + * Implementation of a value referencing an object on the target VM. + */ +public class JDIObjectValue extends JDIValue implements IJavaObject { + + private IJavaObject[] fCachedReferences; + private int fSuspendCount; + private long fPreviousMax; + + /** + * Constructs a new target object on the given target with the specified + * object reference. + */ + public JDIObjectValue(JDIDebugTarget target, ObjectReference object) { + super(target, object); + fSuspendCount = -1; + fCachedReferences = null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread, boolean) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, boolean superSend) + throws DebugException { + JDIThread javaThread = (JDIThread) thread; + List arguments = null; + if (args == null) { + arguments = Collections.EMPTY_LIST; + } else { + arguments = new ArrayList<>(args.length); + for (IJavaValue arg : args) { + arguments.add(((JDIValue) arg).getUnderlyingValue()); + } + } + ObjectReference object = getUnderlyingObject(); + Method method = null; + ReferenceType refType = getUnderlyingReferenceType(); + try { + if (superSend) { + // begin lookup in superclass + refType = ((ClassType) refType).superclass(); + } + method = concreteMethodByName(refType, selector, signature); + if (method == null) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_11, selector, signature), null); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat + .format(JDIDebugModelMessages.JDIObjectValue_exception_while_performing_method_lookup_for_selector, + e.toString(), selector, signature), + e); + } + Value result = javaThread.invokeMethod(null, object, method, arguments, + superSend); + return JDIValue.createValue((JDIDebugTarget) getDebugTarget(), result); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#sendMessage(java.lang.String, + * java.lang.String, org.eclipse.jdt.debug.core.IJavaValue[], + * org.eclipse.jdt.debug.core.IJavaThread, java.lang.String) + */ + @Override + public IJavaValue sendMessage(String selector, String signature, + IJavaValue[] args, IJavaThread thread, String typeSignature) + throws DebugException { + JDIThread javaThread = (JDIThread) thread; + List arguments = null; + if (args == null) { + arguments = Collections.EMPTY_LIST; + } else { + arguments = new ArrayList<>(args.length); + for (IJavaValue arg : args) { + arguments.add(((JDIValue) arg).getUnderlyingValue()); + } + } + ObjectReference object = getUnderlyingObject(); + Method method = null; + ReferenceType refType = getUnderlyingReferenceType(); + try { + found: while (typeSignature != null && refType != null && !refType.signature().equals(typeSignature)) { + // Didin't match, could be a method from inheirited interface + for (InterfaceType iface : ((ClassType) refType).allInterfaces()) { + if (iface.signature().equals(typeSignature)) { + refType = iface; + break found; + } + } + // lookup correct type through the hierarchy + refType = ((ClassType) refType).superclass(); + if (refType == null) { + targetRequestFailed( + JDIDebugModelMessages.JDIObjectValueMethod_declaring_type_not_found_1, + null); + } + } + method = concreteMethodByName(refType, selector, signature); + if (method == null) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_11, selector, signature), null); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat + .format(JDIDebugModelMessages.JDIObjectValue_exception_while_performing_method_lookup_for_selector, + e.toString(), selector, signature), + e); + } + Value result = javaThread.invokeMethod(null, object, method, arguments, + true); + return JDIValue.createValue((JDIDebugTarget) getDebugTarget(), result); + } + + private Method concreteMethodByName(ReferenceType refType, String selector, + String signature) throws DebugException { + if (refType instanceof ClassType) { + Method m = ((ClassType) refType).concreteMethodByName(selector, + signature); + if (m != null) { + return m; + } + + for (InterfaceType iface : ((ClassType) refType).allInterfaces()) { + List matches = iface.methodsByName(selector, signature); + for (Method ifaceMethod : matches) { + if (! ifaceMethod.isAbstract()) { + return ifaceMethod; + } + } + } + } + if (refType instanceof InterfaceTypeImpl) { + Method m = ((InterfaceTypeImpl) refType).concreteMethodByName(selector, + signature); + if (m != null) { + return m; + } + } + if (refType instanceof ArrayType) { + // the jdi spec specifies that all methods on methods return an + // empty list for array types. + // use a trick to get the right method from java.lang.Object + return ((ClassType) refType.classObject().referenceType()) + .superclass().concreteMethodByName(selector, signature); + } + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_method_lookup_failed_for_selector____0____with_signature____1___1, + selector, signature), null); + // it is not possible to return null + return null; + } + + /** + * Returns this object's the underlying object reference + * + * @return underlying object reference + */ + public ObjectReference getUnderlyingObject() { + return (ObjectReference) getUnderlyingValue(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getField(java.lang.String, + * boolean) + */ + @Override + public IJavaFieldVariable getField(String name, boolean superField) + throws DebugException { + ReferenceType ref = getUnderlyingReferenceType(); + try { + if (superField) { + // begin lookup in superclass + ref = ((ClassType) ref).superclass(); + } + Field field = ref.fieldByName(name); + if (field != null) { + return new JDIFieldVariable((JDIDebugTarget) getDebugTarget(), + field, getUnderlyingObject(), fLogicalParent); + } + Field enclosingThis = null; + Iterator fields = ref.fields().iterator(); + while (fields.hasNext()) { + Field fieldTmp = fields.next(); + if (fieldTmp.name().startsWith("this$")) { //$NON-NLS-1$ + enclosingThis = fieldTmp; + break; + } + } + + if (enclosingThis != null) { + return ((JDIObjectValue) (new JDIFieldVariable( + (JDIDebugTarget) getDebugTarget(), enclosingThis, + getUnderlyingObject(), fLogicalParent)).getValue()) + .getField(name, false); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_exception_retrieving_field, + e.toString()), e); + } + // it is possible to return null + return null; + } + + @Override + public IJavaFieldVariable getField(final String name, final String declaringTypeSignature) throws DebugException { + ReferenceType ref = getUnderlyingReferenceType(); + try { + Field field = null; + Field fieldTmp = null; + List synteticFields = new ArrayList<>(); + Iterator fields = ref.allFields().iterator(); + List superTypes = null; + main: while (fields.hasNext()) { + fieldTmp = fields.next(); + if (name.equals(fieldTmp.name())) { + ReferenceType declaringType = fieldTmp.declaringType(); + String signature = declaringType.signature(); + if (declaringTypeSignature.equals(signature)) { + field = fieldTmp; + break; + } + // check if we are inside local type - Signature.createTypeSignature + // can't create proper type name out of source field in JavaDebugHover + // we get LDebugHoverTest$InnerClass2; instead of LDebugHoverTest$1InnerClass2; + signature = signature.replaceFirst("\\$\\d+", "\\$"); //$NON-NLS-1$ //$NON-NLS-2$ + if (declaringTypeSignature.equals(signature)) { + field = fieldTmp; + break; + } + if (superTypes == null) { + superTypes = superTypes(ref); + } + for (ReferenceType st : superTypes) { + if (st.signature().equals(signature)) { + field = fieldTmp; + break main; + } + } + } + if (fieldTmp.isSynthetic()) { + synteticFields.add(fieldTmp); + } + } + JDIDebugTarget debugTarget = (JDIDebugTarget) getDebugTarget(); + if (field != null) { + return new JDIFieldVariable(debugTarget, field, getUnderlyingObject(), fLogicalParent); + } + + // Check possible references of variables defined in outer class + for (Field outer : synteticFields) { + // retrieve the reference to the "outer" object + JDIFieldVariable syntVariable = new JDIFieldVariable(debugTarget, outer, getUnderlyingObject(), fLogicalParent); + IValue value = syntVariable.getValue(); + if (value instanceof JDIObjectValue) { + JDIObjectValue outerObject = (JDIObjectValue) value; + // ask "outer" object about field probably declared within + return outerObject.getField(name, outer.signature()); + } + } + + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_exception_retrieving_field, + e.toString()), e); + } + // it is possible to return null + return null; + } + + static List superTypes(ReferenceType type) { + List superTypes = new ArrayList<>(); + ReferenceType t = type; + while (t instanceof ClassType) { + ClassType ct = (ClassType) t; + t = ct.superclass(); + if (t == null || "java.lang.Object".equals(t.name())) { //$NON-NLS-1$ + break; + } + superTypes.add(t); + } + return superTypes; + } + + /** + * Returns a variable representing the field in this object with the given + * name, or null if there is no field with the given name, or + * the name is ambiguous. + * + * @param name + * field name + * @param superClassLevel + * the level of the desired field in the hierarchy. Level 0 + * returns the field from the current type, level 1 from the + * super type, etc. + * @return the variable representing the field, or null + * @exception DebugException + * if this method fails. Reasons include: + *
                    + *
                  • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                  • + */ + public IJavaFieldVariable getField(String name, int superClassLevel) + throws DebugException { + ReferenceType ref = getUnderlyingReferenceType(); + try { + for (int i = 0; i < superClassLevel; i++) { + ref = ((ClassType) ref).superclass(); + } + Field field = ref.fieldByName(name); + if (field != null) { + return new JDIFieldVariable((JDIDebugTarget) getDebugTarget(), + field, getUnderlyingObject(), fLogicalParent); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_exception_retrieving_field, + e.toString()), e); + } + // it is possible to return null + return null; + } + + /** + * Returns the underlying reference type for this object. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                      + *
                    • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                    • + */ + protected ReferenceType getUnderlyingReferenceType() throws DebugException { + try { + return getUnderlyingObject().referenceType(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_exception_retrieving_reference_type, + e.toString()), e); + } + // execution will not reach this line, as an exception will + // be thrown. + return null; + + } + + /** + * Return the enclosing object of this object at the specified level. Level + * 0 returns the object, level 1 returns the enclosing object, etc. + */ + public IJavaObject getEnclosingObject(int enclosingLevel) + throws DebugException { + JDIObjectValue res = this; + for (int i = 0; i < enclosingLevel; i++) { + ReferenceType ref = res.getUnderlyingReferenceType(); + try { + Field enclosingThis = null, fieldTmp = null; + Iterator fields = ref.fields().iterator(); + while (fields.hasNext()) { + fieldTmp = fields.next(); + if (fieldTmp.name().startsWith("this$")) { //$NON-NLS-1$ + enclosingThis = fieldTmp; + } + } + if (enclosingThis != null) { + JDIDebugTarget debugTarget = (JDIDebugTarget) getDebugTarget(); + JDIFieldVariable fieldVariable = new JDIFieldVariable( + debugTarget, enclosingThis, + res.getUnderlyingObject(), fLogicalParent); + res = (JDIObjectValue) fieldVariable.getValue(); + } else { + // it is possible to return null + return null; + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_exception_retrieving_field, + e.toString()), e); + } + } + return res; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getWaitingThreads() + */ + @Override + public IJavaThread[] getWaitingThreads() throws DebugException { + List waiting = new ArrayList<>(); + try { + JDIDebugTarget debugTarget = (JDIDebugTarget) getDebugTarget(); + for (ThreadReference threadReference : getUnderlyingObject().waitingThreads()) { + JDIThread jdiThread = debugTarget.findThread(threadReference); + if (jdiThread != null) { + waiting.add(jdiThread); + } + } + } catch (IncompatibleThreadStateException e) { + targetRequestFailed(JDIDebugModelMessages.JDIObjectValue_0, e); + } catch (VMDisconnectedException e) { + // Ignore + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIObjectValue_0, e); + } + return waiting.toArray(new IJavaThread[waiting.size()]); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getOwningThread() + */ + @Override + public IJavaThread getOwningThread() throws DebugException { + IJavaThread owningThread = null; + try { + ThreadReference thread = getUnderlyingObject().owningThread(); + JDIDebugTarget debugTarget = (JDIDebugTarget) getDebugTarget(); + if (thread != null) { + owningThread = debugTarget.findThread(thread); + } + } catch (IncompatibleThreadStateException e) { + targetRequestFailed(JDIDebugModelMessages.JDIObjectValue_1, e); + } catch (VMDisconnectedException e) { + return null; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIObjectValue_1, e); + } + return owningThread; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIValue#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + try { + return JDIReferenceType + .getGenericName(getUnderlyingReferenceType()); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_reference_type_name, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getUniqueId() + */ + @Override + public long getUniqueId() throws DebugException { + try { + ObjectReference underlyingObject = getUnderlyingObject(); + if (underlyingObject != null) { + return underlyingObject.uniqueID(); + } + return -1L; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_unique_id, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return 0; + } + } + + @Override + public String getLabel() throws DebugException { + JDIDebugTarget debugTarget = getJavaDebugTarget(); + return debugTarget.getObjectLabel(this); + } + + @Override + public void setLabel(String newLabel) throws DebugException { + JDIDebugTarget debugTarget = getJavaDebugTarget(); + debugTarget.setObjectLabel(this, newLabel); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#getReferringObjects(long) + */ + @Override + public IJavaObject[] getReferringObjects(long max) throws DebugException { + // The cached references should be reloaded if the suspend count has + // changed, or the maximum entries has changed + if (fCachedReferences == null + || fSuspendCount < ((JDIDebugTarget) getDebugTarget()) + .getSuspendCount() || fPreviousMax != max) { + reloadReferringObjects(max); + fPreviousMax = max; + fSuspendCount = ((JDIDebugTarget) getDebugTarget()) + .getSuspendCount(); + } + return fCachedReferences; + } + + /** + * Returns true if references to this object have been calculated and + * cached. This method will return true even if the cached references are + * stale. + * + * @return true is references to this object have been calculated and + * cached, false otherwise + */ + public boolean isReferencesLoaded() { + return fCachedReferences != null; + } + + /** + * Gets the list of objects that reference this object from the VM, + * overwriting the cached list (if one exists). + * + * @param max + * The maximum number of entries to return + * @throws DebugException + * if the VM cannot return a list of referring objects + */ + protected void reloadReferringObjects(long max) throws DebugException { + try { + List list = getUnderlyingObject().referringObjects(max); + IJavaObject[] references = new IJavaObject[list.size()]; + for (int i = 0; i < references.length; i++) { + references[i] = (IJavaObject) JDIValue.createValue( + getJavaDebugTarget(), list.get(i)); + } + fCachedReferences = references; + } catch (RuntimeException e) { + fCachedReferences = null; + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIObjectValue_12, + e.toString()), e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#disableCollection() + */ + @Override + public void disableCollection() throws DebugException { + if (getJavaDebugTarget().supportsSelectiveGarbageCollection()) { + try { + getUnderlyingObject().disableCollection(); + } catch (UnsupportedOperationException e) { + // The VM does not support enable/disable GC - update target + // capabilities and ignore (bug 246577) + getJavaDebugTarget().setSupportsSelectiveGarbageCollection( + false); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIObjectValue_13, e); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaObject#enableCollection() + */ + @Override + public void enableCollection() throws DebugException { + if (getJavaDebugTarget().supportsSelectiveGarbageCollection()) { + try { + getUnderlyingObject().enableCollection(); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIObjectValue_14, e); + } + } + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIPlaceholderValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIPlaceholderValue.java new file mode 100644 index 0000000000..0e5dd53e84 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIPlaceholderValue.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +/** + * This class is used to create a variable/value that displays a warning message + * to the user. Currently used to inform users that references are not available + * for the current VM. It extends JDINullValue so that most actions + * will ignore it, but returns the message instead of "null" for it's value. + * + * @since 3.3 + */ +public class JDIPlaceholderValue extends JDINullValue { + + private final String fMessage; + + /** + * Constructor, passes the debug target to the super class. + * + * @param target + * debug target this value belongs to + */ + public JDIPlaceholderValue(JDIDebugTarget target, String message) { + super(target); + fMessage = message; + } + + /** + * @return the message supplied in the constructor + * @see org.eclipse.jdt.internal.debug.core.model.JDINullValue#getValueString() + */ + @Override + public String getValueString() { + return fMessage; + } + + /** + * @return the message supplied in the constructor + * @see org.eclipse.jdt.internal.debug.core.model.JDINullValue#toString() + */ + @Override + public String toString() { + return fMessage; + } + + /** + * Returns signature for a java string object so that the string message + * passed in the constructor is displayed in the detail pane. + * + * @return signature for a java string object + * @see org.eclipse.jdt.internal.debug.core.model.JDINullValue#getSignature() + */ + @Override + public String getSignature() { + return "Ljava/lang/String;"; //$NON-NLS-1$ + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIPrimitiveValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIPrimitiveValue.java new file mode 100644 index 0000000000..8a882c59e3 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIPrimitiveValue.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; + +import com.sun.jdi.PrimitiveValue; +import com.sun.jdi.Value; + +/** + * A primitive value on a Java debug target + */ +public class JDIPrimitiveValue extends JDIValue implements IJavaPrimitiveValue { + + /** + * Constructs a new primitive value. + * + * @param target + * the Java debug target + * @param value + * the underlying JDI primitive value + */ + public JDIPrimitiveValue(JDIDebugTarget target, Value value) { + super(target, value); + } + + /** + * Returns this value's underlying primtive value + * + * @return underlying primtive value + */ + protected PrimitiveValue getUnderlyingPrimitiveValue() { + return (PrimitiveValue) getUnderlyingValue(); + } + + /* + * @see IJavaPrimitiveValue#getBooleanValue() + */ + @Override + public boolean getBooleanValue() { + return getUnderlyingPrimitiveValue().booleanValue(); + } + + /* + * @see IJavaPrimitiveValue#getByteValue() + */ + @Override + public byte getByteValue() { + return getUnderlyingPrimitiveValue().byteValue(); + } + + /* + * @see IJavaPrimitiveValue#getCharValue() + */ + @Override + public char getCharValue() { + return getUnderlyingPrimitiveValue().charValue(); + } + + /* + * @see IJavaPrimitiveValue#getDoubleValue() + */ + @Override + public double getDoubleValue() { + return getUnderlyingPrimitiveValue().doubleValue(); + } + + /* + * @see IJavaPrimitiveValue#getFloatValue() + */ + @Override + public float getFloatValue() { + return getUnderlyingPrimitiveValue().floatValue(); + } + + /* + * @see IJavaPrimitiveValue#getIntValue() + */ + @Override + public int getIntValue() { + return getUnderlyingPrimitiveValue().intValue(); + } + + /* + * @see IJavaPrimitiveValue#getLongValue() + */ + @Override + public long getLongValue() { + return getUnderlyingPrimitiveValue().longValue(); + } + + /* + * @see IJavaPrimitiveValue#getShortValue() + */ + @Override + public short getShortValue() { + return getUnderlyingPrimitiveValue().shortValue(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListEntryVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListEntryVariable.java new file mode 100644 index 0000000000..0b732c4c5a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListEntryVariable.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable; + +/** + * This variable is created as the child of JDIReferenceListValue. + * It represents one reference to a root object stored in the parent value. + * + * @see JDIReferenceListValue + * @since 3.3 + */ +public class JDIReferenceListEntryVariable extends JDIPlaceholderVariable { + + /** + * Constructor. + * + * @param name + * The name that this variable should use as its label + * @param reference + * The value that this variable contains + */ + public JDIReferenceListEntryVariable(String name, IJavaValue reference) { + super(name, reference); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListValue.java new file mode 100644 index 0000000000..d6784c91b4 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListValue.java @@ -0,0 +1,344 @@ +/******************************************************************************* + * Copyright (c) 2007, 2013 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Stepan Vavra - Bug 419316 - All References or All instances may throw NPE in Eclipse + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IIndexedValue; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.HeapWalkingManager; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable; + +import com.sun.jdi.ObjectReference; + +/** + * A JDI Value representing a set of references to the root object specified in + * the constructor. Used to add a list of all references to an object to various + * views including the variables view. The value should belong to a + * JDIReferenceListVariable. The children of this value will be + * JDIReferenceListEntryVariable, each representing one reference + * to the root object. + * + * @see JDIReferenceListVariable + * @see JDIReferenceListEntryVariable + * @since 3.3 + */ +public class JDIReferenceListValue extends JDIObjectValue implements + IIndexedValue { + + private final IJavaObject fRoot; + private boolean fIsMoreThanPreference; + private IJavaType fType = null; + + /** + * Constructor, initializes this value with its debug target and root object + * + * @param target + * The debug target associated with this value + * @param root + * The root object that the elements in the array refer to. + */ + public JDIReferenceListValue(IJavaObject root) { + super((JDIDebugTarget) root.getDebugTarget(), ((JDIObjectValue) root) + .getUnderlyingObject()); + fRoot = root; + try { + IJavaType[] javaTypes = ((JDIDebugTarget) root.getDebugTarget()) + .getJavaTypes("java.lang.Object[]"); //$NON-NLS-1$ + if (javaTypes != null && javaTypes.length > 0) { + fType = javaTypes[0]; + } + } catch (DebugException e) { + } + } + + /** + * @return all references to the root object as an array of IJavaObjects + */ + protected synchronized IJavaObject[] getReferences() { + try { + int max = HeapWalkingManager.getDefault() + .getAllReferencesMaxCount(); + IJavaObject[] referringObjects = null; + fIsMoreThanPreference = false; + if (max == 0) { + referringObjects = fRoot.getReferringObjects(max); + } else { + referringObjects = fRoot.getReferringObjects(max + 1); + if (referringObjects.length > max) { + fIsMoreThanPreference = true; + referringObjects[max] = new JDIPlaceholderValue( + (JDIDebugTarget) fRoot.getDebugTarget(), + MessageFormat + .format(JDIDebugModelMessages.JDIReferenceListValue_9, + Integer.toString(max))); + } + } + return referringObjects; + } catch (DebugException e) { + JDIDebugPlugin.log(e); + return new IJavaObject[0]; + } + } + + /** + * @return whether the references to the root object have been loaded from + * the vm yet. + */ + protected synchronized boolean referencesLoaded() { + if (fRoot instanceof JDIObjectValue) { + return ((JDIObjectValue) fRoot).isReferencesLoaded(); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getVariables() + */ + @Override + public IVariable[] getVariables() throws DebugException { + IJavaObject[] elements = getReferences(); + IVariable[] vars = new JDIPlaceholderVariable[elements.length]; + int length = elements.length; + if (fIsMoreThanPreference) { + length--; + vars[length] = new JDIPlaceholderVariable( + JDIDebugModelMessages.JDIReferenceListValue_11, + elements[length]); + } + + for (int i = 0; i < length; i++) { + vars[i] = new JDIReferenceListEntryVariable(MessageFormat.format( + JDIDebugModelMessages.JDIReferenceListValue_0, + Integer.toString(i)), elements[i]); + } + return vars; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getUnderlyingObject + * () + */ + @Override + public ObjectReference getUnderlyingObject() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#hasVariables() + */ + @Override + public boolean hasVariables() throws DebugException { + if (referencesLoaded()) { + return getReferences().length > 0; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#isAllocated() + */ + @Override + public boolean isAllocated() throws DebugException { + return fRoot.isAllocated(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return fType; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getSignature() + */ + @Override + public String getSignature() throws DebugException { + return "[Ljava/lang/Object;"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIObjectValue#getReferenceTypeName + * () + */ + @Override + public String getReferenceTypeName() throws DebugException { + return "java.lang.Object[]"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#getValueString() + */ + @Override + public String getValueString() throws DebugException { + return ""; //$NON-NLS-1$ + } + + /** + * Returns a string representation of this value intended to be displayed in + * the detail pane of views. Lists the references on separate lines. + * + * @return a string representation of this value to display in the detail + * pane + */ + public String getDetailString() { + StringBuilder buf = new StringBuilder(); + Object[] elements = getReferences(); + if (elements.length == 0) { + buf.append(JDIDebugModelMessages.JDIReferenceListValue_2); + } else { + String length = null; + if (fIsMoreThanPreference) { + length = MessageFormat.format( + JDIDebugModelMessages.JDIReferenceListValue_15, + Integer.toString(elements.length - 1)); + } else { + length = Integer.toString(elements.length); + } + if (elements.length == 1) { + buf.append(MessageFormat.format( + JDIDebugModelMessages.JDIReferenceListValue_3, + length)); + } else { + buf.append(MessageFormat.format( + JDIDebugModelMessages.JDIReferenceListValue_4, + length)); + } + for (Object element : elements) { + buf.append(element + "\n"); //$NON-NLS-1$ + } + } + return buf.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#toString() + */ + @Override + public String toString() { + return MessageFormat.format( + JDIDebugModelMessages.JDIReferenceListValue_6, + getUnderlyingValue().toString()); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIValue#equals(java.lang.Object + * ) + */ + @Override + public boolean equals(Object o) { + // Two JDIReferenceListValues are equal if they both have the same root + // object. + if (o instanceof JDIReferenceListValue) { + JDIReferenceListValue ref = (JDIReferenceListValue) o; + return ref.fRoot.equals(fRoot); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.internal.debug.core.model.JDIValue#hashCode() + */ + @Override + public int hashCode() { + return getClass().hashCode() + fRoot.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getInitialOffset() + */ + @Override + public int getInitialOffset() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getSize() + */ + @Override + public int getSize() throws DebugException { + return getVariables().length; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getVariable(int) + */ + @Override + public IVariable getVariable(int offset) throws DebugException { + IVariable[] variables = getVariables(); + if (offset < variables.length) { + return variables[offset]; + } + requestFailed(JDIDebugModelMessages.JDIReferenceListValue_7, new IndexOutOfBoundsException()); + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IIndexedValue#getVariables(int, int) + */ + @Override + public IVariable[] getVariables(int offset, int length) + throws DebugException { + IVariable[] variables = getVariables(); + if (offset < variables.length && (offset + length) <= variables.length) { + IJavaVariable[] vars = new IJavaVariable[length]; + System.arraycopy(variables, offset, vars, 0, length); + return vars; + } + requestFailed(JDIDebugModelMessages.JDIReferenceListValue_8, new IndexOutOfBoundsException()); + return null; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListVariable.java new file mode 100644 index 0000000000..f98784b873 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceListVariable.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable; + +/** + * A variable that stores a list of references. Used to display reference + * information collected from the vm using the 'all references' utility in Java + * 6.0. This variable uses a JDIReferenceListValue as its value. + * Its children will be JDIReferenceListEntryVariable. + * + * @since 3.3 + * @see JDIReferenceListValue + * @see JDIReferenceListEntryVariable + */ +public class JDIReferenceListVariable extends JDIPlaceholderVariable { + + /** + * Creates a new variable that stores a list of references, all referring to + * the java object specified by the parameter root. + * + * @param name + * The name this variable should use + * @param root + * The root java object that references will be collected for + */ + public JDIReferenceListVariable(String name, IJavaObject root) { + super(name, new JDIReferenceListValue(root)); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable + * #equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + // Two JDIReferenceListVariables are equal if their values are equal + if (obj instanceof JDIReferenceListVariable) { + JDIReferenceListVariable var = (JDIReferenceListVariable) obj; + if (getValue() instanceof JDIPlaceholderValue + || var.getValue() instanceof JDIPlaceholderValue) { + // A placeholder value is only equal to the same instance + return this == obj; + } + return getValue().equals(var.getValue()); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable + * #hashCode() + */ + @Override + public int hashCode() { + return getValue().hashCode(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceType.java new file mode 100644 index 0000000000..2a020f8c6b --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIReferenceType.java @@ -0,0 +1,430 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaValue; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassLoaderReference; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.Field; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; + +/** + * References a class, interface, or array type. + */ +public abstract class JDIReferenceType extends JDIType implements + IJavaReferenceType { + + // field names declared in this type + private String[] fDeclaredFields = null; + // field names declared in this type, super types, implemented interfaces + // and super-interfaces + private String[] fAllFields = null; + + /** + * Constructs a new reference type in the given target. + * + * @param target + * associated VM + * @param type + * reference type + */ + public JDIReferenceType(JDIDebugTarget target, Type type) { + super(target, type); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getAvailableStrata() + */ + @Override + public String[] getAvailableStrata() { + List strata = getReferenceType().availableStrata(); + return strata.toArray(new String[strata.size()]); + } + + /** + * Returns the underlying reference type. + * + * @return the underlying reference type + */ + protected ReferenceType getReferenceType() { + return (ReferenceType) getUnderlyingType(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getDefaultStratum() + */ + @Override + public String getDefaultStratum() throws DebugException { + try { + return getReferenceType().defaultStratum(); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_1, e); + } + // execution will not reach here + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaReferenceType#getField(java.lang.String) + */ + @Override + public IJavaFieldVariable getField(String name) throws DebugException { + try { + ReferenceType type = (ReferenceType) getUnderlyingType(); + Field field = type.fieldByName(name); + if (field != null && field.isStatic()) { + return new JDIFieldVariable(getJavaDebugTarget(), field, type); + } + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_field, + e.toString(), name), e); + } + // it is possible to return null + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getClassObject() + */ + @Override + public IJavaClassObject getClassObject() throws DebugException { + try { + ReferenceType type = (ReferenceType) getUnderlyingType(); + return (IJavaClassObject) JDIValue.createValue( + getJavaDebugTarget(), type.classObject()); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIClassType_exception_while_retrieving_class_object, + e.toString()), e); + } + // execution will not fall through to here, + // as #requestFailed will throw an exception + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getAllFieldNames() + */ + @Override + public String[] getAllFieldNames() throws DebugException { + if (fAllFields == null) { + try { + List fields = ((ReferenceType) getUnderlyingType()).allFields(); + fAllFields = new String[fields.size()]; + Iterator iterator = fields.iterator(); + int i = 0; + while (iterator.hasNext()) { + Field field = iterator.next(); + fAllFields[i] = field.name(); + i++; + } + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_2, e); + } + } + return fAllFields; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaReferenceType#getDeclaredFieldNames() + */ + @Override + public String[] getDeclaredFieldNames() throws DebugException { + if (fDeclaredFields == null) { + try { + List fields = ((ReferenceType) getUnderlyingType()).fields(); + fDeclaredFields = new String[fields.size()]; + Iterator iterator = fields.iterator(); + int i = 0; + while (iterator.hasNext()) { + Field field = iterator.next(); + fDeclaredFields[i] = field.name(); + i++; + } + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_3, e); + } + } + return fDeclaredFields; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaReferenceType#getSourcePaths(java.lang + * .String) + */ + @Override + public String[] getSourcePaths(String stratum) throws DebugException { + try { + List sourcePaths = getReferenceType().sourcePaths(stratum); + return sourcePaths + .toArray(new String[sourcePaths.size()]); + } catch (AbsentInformationException e) { + } catch (RuntimeException e) { + requestFailed(JDIDebugModelMessages.JDIReferenceType_4, e, + DebugException.TARGET_REQUEST_FAILED); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getSourceName() + */ + @Override + public String getSourceName() throws DebugException { + try { + return getReferenceType().sourceName(); + } catch (AbsentInformationException e) { + } catch (RuntimeException e) { + requestFailed(JDIDebugModelMessages.JDIReferenceType_4, e, + DebugException.TARGET_REQUEST_FAILED); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaReferenceType#getSourceNames(java.lang + * .String) + */ + @Override + public String[] getSourceNames(String stratum) throws DebugException { + try { + List sourceNames = getReferenceType().sourceNames(stratum); + return sourceNames + .toArray(new String[sourceNames.size()]); + } catch (AbsentInformationException e) { + } catch (RuntimeException e) { + requestFailed(JDIDebugModelMessages.JDIReferenceType_4, e, + DebugException.TARGET_REQUEST_FAILED); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getClassLoaderObject() + */ + @Override + public IJavaObject getClassLoaderObject() throws DebugException { + try { + ReferenceType type = (ReferenceType) getUnderlyingType(); + ClassLoaderReference classLoader = type.classLoader(); + if (classLoader != null) { + return (IJavaObject) JDIValue.createValue(getJavaDebugTarget(), + classLoader); + } + } catch (RuntimeException e) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIReferenceType_0, + e.toString()), e); + } + return null; + } + + static public String getGenericName(ReferenceType type) + throws DebugException { + if (type instanceof ArrayType) { + try { + Type componentType; + componentType = ((ArrayType) type).componentType(); + if (componentType instanceof ReferenceType) { + return getGenericName((ReferenceType) componentType) + "[]"; //$NON-NLS-1$ + } + return type.name(); + } catch (ClassNotLoadedException e) { + // we cannot create the generic name using the component type, + // just try to create one with the information + } + } + String signature = type.signature(); + StringBuilder res = new StringBuilder(getTypeName(signature)); + String genericSignature = type.genericSignature(); + if (genericSignature != null) { + String[] typeParameters = Signature + .getTypeParameters(genericSignature); + if (typeParameters.length > 0) { + res.append('<').append( + Signature.getTypeVariable(typeParameters[0])); + for (int i = 1; i < typeParameters.length; i++) { + res.append(',').append( + Signature.getTypeVariable(typeParameters[i])); + } + res.append('>'); + } + } + return res.toString(); + } + + /** + * Return the name from the given signature. Keep the '$' characters. + * + * @param genericTypeSignature + * the signature to derive the type name from + * @return the type name + */ + public static String getTypeName(String genericTypeSignature) { + int arrayDimension = 0; + while (genericTypeSignature.charAt(arrayDimension) == '[') { + arrayDimension++; + } + int parameterStart = genericTypeSignature.indexOf('<'); + StringBuilder name = new StringBuilder(); + if (parameterStart < 0) { + name.append(genericTypeSignature.substring(arrayDimension + 1, + genericTypeSignature.length() - 1).replace('/', '.')); + } else { + if (parameterStart != 0) { + name.append(genericTypeSignature.substring(arrayDimension + 1, + parameterStart).replace('/', '.')); + } + try { + String sig = Signature.toString(genericTypeSignature) + .substring( + Math.max(parameterStart - 1, 0) + - arrayDimension); + name.append(sig.replace('/', '.')); + } catch (IllegalArgumentException iae) { + // do nothing + name.append(genericTypeSignature); + } + } + for (int i = 0; i < arrayDimension; i++) { + name.append("[]"); //$NON-NLS-1$ + } + return name.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + return getReferenceType().genericSignature(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getInstances(long) + */ + @Override + public IJavaObject[] getInstances(long max) throws DebugException { + try { + List list = getReferenceType().instances(max); + IJavaObject[] instances = new IJavaObject[list.size()]; + for (int i = 0; i < instances.length; i++) { + instances[i] = (IJavaObject) JDIValue.createValue( + getJavaDebugTarget(), list.get(i)); + } + return instances; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_5, e); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getInstanceCount() + */ + @Override + public long getInstanceCount() throws DebugException { + JDIDebugTarget target = getJavaDebugTarget(); + if (target.supportsInstanceRetrieval()) { + Type type = getUnderlyingType(); + if(type instanceof ReferenceType) { + ArrayList list = new ArrayList<>(2); + list.add((ReferenceType) type); + VirtualMachine vm = getVM(); + try { + long[] counts = vm.instanceCounts(list); + return counts[0]; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_5, e); + } + } + } + return -1; + } + + /** + * Utility method to convert argument array to an argument list. + * + * @param args + * array of arguments, as IJavaValues, possibly + * null or empty + * @return a list of underlying Values + */ + protected List convertArguments(IJavaValue[] args) { + List arguments = null; + if (args == null) { + arguments = Collections.EMPTY_LIST; + } else { + arguments = new ArrayList<>(args.length); + for (IJavaValue arg : args) { + arguments.add(((JDIValue) arg).getUnderlyingValue()); + } + } + return arguments; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java new file mode 100644 index 0000000000..f613ad060a --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java @@ -0,0 +1,1738 @@ +/******************************************************************************* + * Copyright (c) 2000, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Samrat Dhillon samrat.dhillon@gmail.com - Bug 384458 - debug shows value of variable in another scope + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IRegisterGroup; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IStep; +import org.eclipse.debug.core.model.ISuspendResume; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdi.internal.FieldImpl; +import org.eclipse.jdi.internal.ReferenceTypeImpl; +import org.eclipse.jdi.internal.ValueImpl; +import org.eclipse.jdi.internal.VirtualMachineImpl; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaModifiers; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDILambdaVariable; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIReturnValueVariable; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.LocalVariable; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.NativeMethodException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.Type; +import com.sun.jdi.VirtualMachine; + +/** + * Proxy to a stack frame on the target. + */ + +public class JDIStackFrame extends JDIDebugElement implements IJavaStackFrame { + + /** + * This frame's depth in the call stack (0 == bottom of stack). A new frame + * is indicated by -2. An invalid frame is indicated by -1. + */ + private int fDepth = -2; + + /** + * Underlying JDI stack frame. + */ + private StackFrame fStackFrame; + + /** + * Containing thread. + */ + private JDIThread fThread; + /** + * Visible variables. + */ + private List fVariables; + + /** + * The underlying Object associated with this stack frame. Cached lazily on + * first access. + */ + private ObjectReference fThisObject; + + /** + * The name of the type of the object that received the method call + * associated with this stack frame. Cached lazily on first access. + */ + private String fReceivingTypeName; + /** + * Whether the variables need refreshing + */ + private boolean fRefreshVariables = true; + /** + * Whether this stack frame has been marked as out of synch. If set to + * true this stack frame will stop dynamically calculating its + * out of synch state. + */ + private boolean fIsOutOfSynch = false; + + /** + * Whether local variable information was available + */ + private boolean fLocalsAvailable = true; + + /** + * Location of this stack frame + */ + private Location fLocation; + + /** + * Whether the current stack frame is the top of the stack + */ + private boolean fIsTop; + + @SuppressWarnings("restriction") + private static final String SYNTHETIC_OUTER_LOCAL_PREFIX = new String(org.eclipse.jdt.internal.compiler.lookup.TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX); + + /** + * Creates a new stack frame in the given thread. + * + * @param thread + * The parent JDI thread + * @param frame + * underlying frame + * @param depth + * depth on the stack (0 is bottom) + */ + public JDIStackFrame(JDIThread thread, StackFrame frame, int depth) { + super((JDIDebugTarget) thread.getDebugTarget()); + setThread(thread); + bind(frame, depth); + } + + /** + * Binds this frame to the given underlying frame on the target VM or + * returns a new frame representing the given frame. A frame can only be + * re-bound to an underlying frame if it refers to the same depth on the + * stack in the same method. + * + * @param frame + * underlying frame, or null + * @param depth + * depth in the call stack, or -1 to indicate the frame should + * become invalid + * @param return a frame to refer to the given frame or null + */ + protected JDIStackFrame bind(StackFrame frame, int depth) { + synchronized (fThread) { + if (fDepth == -2) { + // first initialization + fStackFrame = frame; + fDepth = depth; + fLocation = frame.location(); + return this; + } else if (depth == -1) { + // mark as invalid + fDepth = -1; + fStackFrame = null; + fIsTop = false; + return null; + } else if (fDepth == depth) { + Location location = frame.location(); + Method method = location.method(); + if (method.equals(fLocation.method())) { + try { + if (method.declaringType().defaultStratum() + .equals("Java") || //$NON-NLS-1$ + equals(getSourceName(location), + getSourceName(fLocation))) { + // TODO: what about receiving type being the same? + fStackFrame = frame; + fLocation = location; + clearCachedData(); + return this; + } + } catch (DebugException e) { + } + } + } + // invalidate this frame + bind(null, -1); + // return a new frame + return new JDIStackFrame(fThread, frame, depth); + } + + } + + /** + * @see IStackFrame#getThread() + */ + @Override + public IThread getThread() { + return fThread; + } + + /** + * @see ISuspendResume#canResume() + */ + @Override + public boolean canResume() { + return getThread().canResume(); + } + + /** + * @see ISuspendResume#canSuspend() + */ + @Override + public boolean canSuspend() { + return getThread().canSuspend(); + } + + /** + * @see IStep#canStepInto() + */ + @Override + public boolean canStepInto() { + try { + return exists() && isTopStackFrame() && !isObsolete() + && getThread().canStepInto(); + } catch (DebugException e) { + logError(e); + return false; + } + } + + /** + * @see IStep#canStepOver() + */ + @Override + public boolean canStepOver() { + return exists() && !isObsolete() && getThread().canStepOver(); + } + + /** + * @see IStep#canStepReturn() + */ + @Override + public boolean canStepReturn() { + try { + if (!exists() || isObsolete() || !getThread().canStepReturn()) { + return false; + } + List frames = ((JDIThread) getThread()) + .computeStackFrames(); + if (frames != null && !frames.isEmpty()) { + boolean bottomFrame = this + .equals(frames.get(frames.size() - 1)); + boolean aboveObsoleteFrame = false; + if (!bottomFrame) { + int index = frames.indexOf(this); + if (index < frames.size() - 1 + && ((JDIStackFrame) frames.get(index + 1)) + .isObsolete()) { + aboveObsoleteFrame = true; + } + } + return !bottomFrame && !aboveObsoleteFrame; + } + } catch (DebugException e) { + logError(e); + } + return false; + } + + /** + * Returns the underlying method associated with this stack frame, + * retrieving the method is necessary. + */ + public Method getUnderlyingMethod() { + synchronized (fThread) { + return fLocation.method(); + } + } + + /** + * @see IStackFrame#getVariables() + */ + @Override + public IVariable[] getVariables() throws DebugException { + List list = getVariables0(); + return list.toArray(new IVariable[list.size()]); + } + + protected List getVariables0() throws DebugException { + synchronized (fThread) { + if (fVariables == null) { + + // throw exception if native method, so variable view will + // update + // with information message + if (isNative()) { + requestFailed( + JDIDebugModelMessages.JDIStackFrame_Variable_information_unavailable_for_native_methods, + null); + } + + Method method = getUnderlyingMethod(); + fVariables = new ArrayList<>(); + // #isStatic() does not claim to throw any exceptions - so it is + // not try/catch coded + if (method.isStatic()) { + // add statics + List allFields = null; + ReferenceType declaringType = method.declaringType(); + try { + allFields = declaringType.allFields(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_fields, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return Collections.EMPTY_LIST; + } + if (allFields != null) { + Iterator fields = allFields.iterator(); + while (fields.hasNext()) { + Field field = fields.next(); + if (field.isStatic()) { + fVariables.add(new JDIFieldVariable( + (JDIDebugTarget) getDebugTarget(), + field, declaringType)); + } + } + Collections.sort(fVariables, + (a, b) -> { + JDIFieldVariable v1 = (JDIFieldVariable) a; + JDIFieldVariable v2 = (JDIFieldVariable) b; + try { + return v1.getName() + .compareToIgnoreCase( + v2.getName()); + } catch (DebugException de) { + logError(de); + return -1; + } + }); + } + } else { + // add "this" + ObjectReference t = getUnderlyingThisObject(); + if (t != null) { + fVariables.add(new JDIThisVariable( + (JDIDebugTarget) getDebugTarget(), t)); + } + } + if (LambdaUtils.isLambdaFrame(this)) { + List frames = fThread.computeStackFrames(); + int previousIndex = frames.indexOf(this) + 1; + if (previousIndex > 0 && previousIndex < frames.size()) { + IJavaStackFrame previousFrame = frames.get(previousIndex); + ObjectReference underlyingThisObject = ((JDIStackFrame) previousFrame).getUnderlyingThisObject(); + IJavaValue closureValue = JDIValue.createValue((JDIDebugTarget) getDebugTarget(), underlyingThisObject); + tryToResolveLambdaVariableNames(closureValue, underlyingThisObject); + fVariables.add(new JDILambdaVariable(closureValue)); + } + } + addStepReturnValue(fVariables); + // add locals + Iterator variables = getUnderlyingVisibleVariables() + .iterator(); + while (variables.hasNext()) { + LocalVariable var = variables.next(); + fVariables.add(new JDILocalVariable(this, var)); + } + } else if (fRefreshVariables) { + updateVariables(); + } + fRefreshVariables = false; + return fVariables; + } + } + + /** + * Tries to resolve "real" captured variable names by inspecting corresponding Java source code (if available) + */ + protected void tryToResolveLambdaVariableNames(IJavaValue value, ObjectReference underlyingThisObject) { + if (!isProbablyJavaCode()) { + // See bug 562056: we won't parse Java code if the current frame doesn't belong to Java, because + // we will most likely have different source line numbers and will produce garbage or errors + return; + } + try { + IType type = JavaDebugUtils.resolveType(value.getJavaType()); + if (type == null) { + return; + } + ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); + parser.setResolveBindings(true); + parser.setSource(type.getTypeRoot()); + try { + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + List allLineLocations = getUnderlyingMethod().allLineLocations(); + int lineNo = allLineLocations.get(0).lineNumber(); + cu.accept(new LambdaASTVisitor(false, underlyingThisObject, getUnderlyingMethod().isStatic(), cu, lineNo)); + } catch (AbsentInformationException | IllegalStateException e) { + // Nothing to be done - either no source or no line numbers + } + } catch (CoreException e) { + logError(e); + } + } + + /** + * @return {@code true} if the current frame relates to the class generated from Java source file (and not from some different language) + */ + protected boolean isProbablyJavaCode() { + try { + String sourceName = getSourceName(); + // Note: JavaCore.isJavaLikeFileName(sourceName) is too generic to be used here + // because it allows files that aren't using Java syntax, like groovy + // See https://github.com/groovy/groovy-eclipse/blob/master/base/org.eclipse.jdt.groovy.core/plugin.xml + if (sourceName == null || sourceName.endsWith(".java")) { //$NON-NLS-1$ + // if nothing is defined (no source attributes), assume Java + return true; + } + } catch (DebugException e) { + // If we fail, assume Java + return true; + } + // Underlined source code is most likely not written in Java + return false; + } + + private final static class LambdaASTVisitor extends ASTVisitor { + private final ObjectReference underlyingThisObject; + private final boolean methodIsStatic; + private final CompilationUnit cu; + private final int lineNo; + + private LambdaASTVisitor(boolean visitDocTags, ObjectReference underlyingThisObject, boolean methodIsStatic, CompilationUnit cu, int lineNo) { + super(visitDocTags); + this.underlyingThisObject = underlyingThisObject; + this.methodIsStatic = methodIsStatic; + this.cu = cu; + this.lineNo = lineNo; + } + + @Override + public boolean visit(LambdaExpression lambdaExpression) { + // check if the lineNo fall in lambda region, it can either be single or multiline lambda body. + if (lineNo < cu.getLineNumber(lambdaExpression.getStartPosition()) + || lineNo > cu.getLineNumber(lambdaExpression.getStartPosition() + lambdaExpression.getLength())) { + return true; + } + IMethodBinding binding = lambdaExpression.resolveMethodBinding(); + if (binding == null) { + return true; + } + IVariableBinding[] synVars = binding.getSyntheticOuterLocals(); + if (synVars == null || synVars.length == 0) {// name cannot be updated if Synthetic Outer Locals are not available + return true; + } + List allFields = underlyingThisObject.referenceType().fields(); + ListIterator listIterator = allFields.listIterator(); + int i = 0; + if (methodIsStatic) { + if (synVars.length == allFields.size()) { + while (listIterator.hasNext()) { + FieldImpl field = (FieldImpl) listIterator.next(); + String newName = synVars[i].getName(); + FieldImpl newField = createRenamedCopy(field, newName); + listIterator.set(newField); + i++; + } + } + } else { + if (synVars.length + 1 == allFields.size()) { + while (listIterator.hasNext()) { + FieldImpl field = (FieldImpl) listIterator.next(); + // remove 'this' field from the fields of the lambda + if (i == 0) { + listIterator.remove(); + } else { + String newName = synVars[i - 1].getName(); + FieldImpl newField = createRenamedCopy(field, newName); + listIterator.set(newField); + } + i++; + } + } + } + return true; + } + + private FieldImpl createRenamedCopy(FieldImpl field, String newName) { + return new FieldImpl((VirtualMachineImpl) field.virtualMachine(), (ReferenceTypeImpl) field.declaringType(), field.getFieldID(), newName, field.signature(), field.genericSignature(), field.modifiers()); + } + } + + /** + * If there is a return value from a "step return" that belongs to this frame, insert it as first element + * + * @param variables + */ + private void addStepReturnValue(List variables) { + if (fIsTop) { + MethodResult methodResult = fThread.getMethodResult(); + if (methodResult != null && methodResult.fResultType != null) { + switch (methodResult.fResultType) { + case returned:{ + if (fDepth + 1 != methodResult.fTargetFrameCount) { + // can happen e.g., because of checkPackageAccess/System.getSecurityManager() + return; + } + String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturnValue, methodResult.fMethod.name()); + variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true)); + break; + } + case returning:{ + String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ReturningValue, methodResult.fMethod.name()); + variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true)); + break; + } + case threw:{ + if (fDepth + 1 > methodResult.fTargetFrameCount) { + // don't know if this really can happen, but other jvm suprises were not expected either + return; + } + String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ExceptionThrown, methodResult.fMethod.name()); + variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true)); + break; + } + case throwing:{ + String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ThrowingException, methodResult.fMethod.name()); + variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true)); + break; + } + case step_timeout: + String msg = JDIDebugModelMessages.JDIStackFrame_NotObservedBecauseOfTimeout; + variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), msg), false)); + break; + default: + break; + } + } else if (JDIThread.showStepResultIsEnabled(getDebugTarget())) { + variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), ""), false)); //$NON-NLS-1$ + } + } + } + + /** + * @see IStackFrame#getName() + */ + @Override + public String getName() throws DebugException { + return getMethodName(); + } + + /** + * @see IJavaStackFrame#getArgumentTypeNames() + */ + @Override + public List getArgumentTypeNames() throws DebugException { + try { + Method underlyingMethod = getUnderlyingMethod(); + String genericSignature = underlyingMethod.genericSignature(); + if (genericSignature == null) { + // no generic signature + return underlyingMethod.argumentTypeNames(); + } + // generic signature + String[] parameterTypes = Signature + .getParameterTypes(genericSignature); + List argumentTypeNames = new ArrayList<>(); + for (String parameterType : parameterTypes) { + argumentTypeNames.add(Signature.toString(parameterType) + .replace('/', '.')); + } + return argumentTypeNames; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_argument_type_names, + e.toString()), e); + // execution will never reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + + /** + * @see IStackFrame#getLineNumber() + */ + @Override + public int getLineNumber() throws DebugException { + synchronized (fThread) { + try { + return fLocation.lineNumber(); + } catch (RuntimeException e) { + if (getThread().isSuspended()) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_line_number, + e.toString()), e); + } + } + } + return -1; + } + + /** + * @see IStep#isStepping() + */ + @Override + public boolean isStepping() { + return getThread().isStepping(); + } + + /** + * @see ISuspendResume#isSuspended() + */ + @Override + public boolean isSuspended() { + return getThread().isSuspended(); + } + + /** + * @see ISuspendResume#resume() + */ + @Override + public void resume() throws DebugException { + getThread().resume(); + } + + /** + * @see IStep#stepInto() + */ + @Override + public void stepInto() throws DebugException { + if (!canStepInto()) { + return; + } + getThread().stepInto(); + } + + /** + * @see IStep#stepOver() + */ + @Override + public void stepOver() throws DebugException { + if (!canStepOver()) { + return; + } + if (isTopStackFrame()) { + getThread().stepOver(); + } else { + ((JDIThread) getThread()).stepToFrame(this); + } + } + + /** + * @see IStep#stepReturn() + */ + @Override + public void stepReturn() throws DebugException { + if (!canStepReturn()) { + return; + } + if (isTopStackFrame()) { + getThread().stepReturn(); + } else { + List frames = ((JDIThread) getThread()) + .computeStackFrames(); + int index = frames.indexOf(this); + if (index >= 0 && index < frames.size() - 1) { + IStackFrame nextFrame = frames.get(index + 1); + ((JDIThread) getThread()).stepToFrame(nextFrame); + } + } + } + + /** + * @see ISuspendResume#suspend() + */ + @Override + public void suspend() throws DebugException { + getThread().suspend(); + } + + /** + * Incrementally updates this stack frames variables. + * + * @see JDIDebugElement#targetRequestFailed(String, RuntimeException) + */ + protected void updateVariables() throws DebugException { + if (fVariables == null) { + return; + } + + // remove old return value first, so the "this" updating logic below works + if (!fVariables.isEmpty() && fVariables.get(0) instanceof JDIReturnValueVariable) { + fVariables.remove(0); + } + + Method method = getUnderlyingMethod(); + int index = 0; + if (!method.isStatic()) { + // update "this" + ObjectReference thisObject; + thisObject = getUnderlyingThisObject(); + JDIThisVariable oldThisObject = null; + if (!fVariables.isEmpty() + && fVariables.get(0) instanceof JDIThisVariable) { + oldThisObject = (JDIThisVariable) fVariables.get(0); + } + if (thisObject == null && oldThisObject != null) { + // removal of 'this' + fVariables.remove(0); + index = 0; + } else { + if (oldThisObject == null && thisObject != null) { + // creation of 'this' + oldThisObject = new JDIThisVariable( + (JDIDebugTarget) getDebugTarget(), thisObject); + fVariables.add(0, oldThisObject); + index = 1; + } else { + if (oldThisObject != null) { + // 'this' still exists, replace with new 'this' if a + // different receiver + if (!oldThisObject.retrieveValue().equals(thisObject)) { + fVariables.remove(0); + fVariables.add(0, new JDIThisVariable( + (JDIDebugTarget) getDebugTarget(), + thisObject)); + } + index = 1; + } + } + } + } + + List locals = Collections.EMPTY_LIST; + try { + StackFrame frame = getUnderlyingStackFrame(); + if (frame != null) { + locals = frame.visibleVariables(); + } + } catch (AbsentInformationException e) { + // continue with empty list of variables + } catch (NativeMethodException e) { + // continue with empty list of variables + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_visible_variables, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return; + } + int localIndex = -1; + while (index < fVariables.size()) { + Object var = fVariables.get(index); + if (var instanceof JDILocalVariable) { + JDILocalVariable local = (JDILocalVariable) fVariables + .get(index); + localIndex = locals.indexOf(local.getLocal()); + if (localIndex >= 0) { + // update variable with new underling JDI LocalVariable + local.setLocal(locals.get(localIndex)); + locals.remove(localIndex); + index++; + } else { + // remove variable + fVariables.remove(index); + } + } else { + // field variable of a static frame + index++; + } + } + + // add any new locals + Iterator newOnes = locals.iterator(); + while (newOnes.hasNext()) { + JDILocalVariable local = new JDILocalVariable(this, newOnes.next()); + fVariables.add(local); + } + + addStepReturnValue(fVariables); + } + + /** + * @see org.eclipse.debug.core.model.IDropToFrame#canDropToFrame() + */ + @Override + public boolean canDropToFrame() { + return supportsDropToFrame(); + } + + /** + * @see IJavaStackFrame#supportsDropToFrame() + */ + @Override + public boolean supportsDropToFrame() { + JDIThread thread = (JDIThread) getThread(); + JDIDebugTarget target = (JDIDebugTarget) thread.getDebugTarget(); + try { + if (!target.isAvailable() || !thread.isSuspended() + || thread.isTerminated() || thread.isInvokingMethod()) { + return false; + } + boolean j9Support = false; + boolean jdkSupport = target.canPopFrames(); + VirtualMachine vm = getVM(); + if (vm == null) { + return false; + } + try { + j9Support = (thread.getUnderlyingThread() instanceof org.eclipse.jdi.hcr.ThreadReference) + && ((org.eclipse.jdi.hcr.VirtualMachine) vm) + .canDoReturn(); + } catch (UnsupportedOperationException uoe) { + j9Support = false; + } + + if (jdkSupport || j9Support) { + // Also ensure that this frame and no frames above this + // frame are native. Unable to pop native stack frames. + List frames = thread.computeStackFrames(); + if (jdkSupport) { + // JDK 1.4 VMs are currently unable to pop the bottom + // stack frame. + if ((frames.size() > 0) + && frames.get(frames.size() - 1) == this) { + return false; + } + } + int index = 0; + JDIStackFrame frame = null; + while (index < frames.size()) { + frame = (JDIStackFrame) frames.get(index); + index++; + if (frame.isNative()) { + return false; + } + if (frame.equals(this)) { + if (jdkSupport) { + // JDK 1.4 VMs are currently unable to pop the + // frame directly above a native frame + if (index < frames.size() + && ((JDIStackFrame) frames.get(index)) + .isNative()) { + return false; + } + } + return true; + } + } + } + return false; + } catch (DebugException e) { + if (e.getStatus().getException() instanceof IncompatibleThreadStateException + || e.getStatus().getCode() == IJavaThread.ERR_THREAD_NOT_SUSPENDED) { + // if the thread has since resumed, drop is not supported + return false; + } + logError(e); + } catch (UnsupportedOperationException e) { + // drop to frame not supported - this is an expected + // exception for VMs that do not support drop to frame + return false; + } catch (RuntimeException e) { + internalError(e); + } + return false; + } + + /** + * @see IJavaStackFrame#dropToFrame() + */ + @Override + public void dropToFrame() throws DebugException { + if (supportsDropToFrame()) { + ((JDIThread) getThread()).dropToFrame(this); + } else { + notSupported(JDIDebugModelMessages.JDIStackFrame_Drop_to_frame_not_supported); + } + } + + public void popFrame() throws DebugException { + if (supportsDropToFrame()) { + ((JDIThread) getThread()).popFrame(this); + } else { + notSupported(JDIDebugModelMessages.JDIStackFrame_pop_frame_not_supported); + } + } + + /** + * @see IJavaStackFrame#findVariable(String) + */ + @Override + public IJavaVariable findVariable(String varName) throws DebugException { + if (isNative()) { + return null; + } + IVariable[] variables = getVariables(); + List possibleMatches = new ArrayList<>(); + IJavaVariable thisVariable = null; + for (IVariable variable : variables) { + IJavaVariable var = (IJavaVariable) variable; + if (var.getName().equals(varName)) { + possibleMatches.add(var); + } + if (var instanceof JDIThisVariable) { + // save for later - check for instance and static variables + thisVariable = var; + } + if (var instanceof JDILambdaVariable) { + // Check if we have match in synthetic fields generated + // by compiler for the captured variables (they start with "val$") + JDILambdaVariable lambda = (JDILambdaVariable) var; + JDIObjectValue ov = (JDIObjectValue) lambda.getValue(); + IVariable[] lvars = ov.getVariables(); + for (IVariable lv : lvars) { + String name = lv.getName(); + if (name.startsWith(SYNTHETIC_OUTER_LOCAL_PREFIX) && (SYNTHETIC_OUTER_LOCAL_PREFIX + varName).equals(name)) { + possibleMatches.add((IJavaVariable) lv); + } + } + } + } + for(IJavaVariable variable: possibleMatches){ + // Local Variable has more preference than Field Variable + if(variable instanceof JDILocalVariable){ + return variable; + } + } + if(possibleMatches.size() > 0) { + return possibleMatches.get(0); + } + + if (thisVariable != null) { + IVariable[] thisChildren = thisVariable.getValue().getVariables(); + for (IVariable element : thisChildren) { + IJavaVariable var = (IJavaVariable) element; + if (var.getName().equals(varName)) { + return var; + } + } + } + return null; + } + + /** + * Retrieves visible variables in this stack frame handling any exceptions. + * Returns an empty list if there are no variables. + * + * @see JDIDebugElement#targetRequestFailed(String, RuntimeException) + */ + protected List getUnderlyingVisibleVariables() throws DebugException { + synchronized (fThread) { + List variables = Collections.EMPTY_LIST; + try { + StackFrame frame = getUnderlyingStackFrame(); + if (frame != null) { + variables = frame.visibleVariables(); + } else { + setLocalsAvailable(false); + } + } catch (AbsentInformationException e) { + setLocalsAvailable(false); + } catch (NativeMethodException e) { + setLocalsAvailable(false); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_visible_variables_2, + e.toString()), e); + } + return variables; + } + } + + /** + * Retrieves 'this' from the underlying stack frame. Returns + * null for static stack frames. + * + * @see JDIDebugElement#targetRequestFailed(String, RuntimeException) + */ + protected ObjectReference getUnderlyingThisObject() throws DebugException { + synchronized (fThread) { + if ((fStackFrame == null || fThisObject == null) && !isStatic() && !(getUnderlyingStackFrame() == null)) { + try { + fThisObject = getUnderlyingStackFrame().thisObject(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_this, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + return fThisObject; + } + } + + /** + * @see IAdaptable#getAdapter(Class) + */ + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter == IJavaStackFrame.class || adapter == IJavaModifiers.class) { + return (T) this; + } + return super.getAdapter(adapter); + } + + /** + * @see IJavaStackFrame#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + return getUnderlyingMethod().signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_method_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + + /** + * @see IJavaStackFrame#getDeclaringTypeName() + */ + @Override + public String getDeclaringTypeName() throws DebugException { + synchronized (fThread) { + try { + if (isObsolete()) { + return JDIDebugModelMessages.JDIStackFrame__unknown_declaring_type__1; + } + return JDIReferenceType.getGenericName(getUnderlyingMethod() + .declaringType()); + } catch (RuntimeException e) { + if (getThread().isSuspended()) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_declaring_type, + e.toString()), e); + } + return JDIDebugModelMessages.JDIStackFrame__unknown_declaring_type__1; + } + } + } + + /** + * @see IJavaStackFrame#getReceivingTypeName() + */ + @Override + public String getReceivingTypeName() throws DebugException { + if (fStackFrame == null || fReceivingTypeName == null) { + try { + if (isObsolete()) { + fReceivingTypeName = JDIDebugModelMessages.JDIStackFrame__unknown_receiving_type__2; + } else { + ObjectReference thisObject = getUnderlyingThisObject(); + if (thisObject == null) { + fReceivingTypeName = getDeclaringTypeName(); + } else { + fReceivingTypeName = JDIReferenceType + .getGenericName(thisObject.referenceType()); + } + } + } catch (RuntimeException e) { + if (getThread().isSuspended()) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_receiving_type, + e.toString()), e); + } + return JDIDebugModelMessages.JDIStackFrame__unknown_receiving_type__2; + } + } + return fReceivingTypeName; + } + + /** + * @see IJavaStackFrame#getMethodName() + */ + @Override + public String getMethodName() throws DebugException { + try { + return getUnderlyingMethod().name(); + } catch (RuntimeException e) { + if (getThread().isSuspended()) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_method_name, + e.toString()), e); + } + return JDIDebugModelMessages.JDIStackFrame__unknown_method__1; + } + } + + /** + * @see IJavaStackFrame#isNative() + */ + @Override + public boolean isNative() throws DebugException { + return getUnderlyingMethod().isNative(); + } + + /** + * @see IJavaStackFrame#isConstructor() + */ + @Override + public boolean isConstructor() throws DebugException { + return getUnderlyingMethod().isConstructor(); + } + + /** + * @see IJavaStackFrame#isStaticInitializer() + */ + @Override + public boolean isStaticInitializer() throws DebugException { + return getUnderlyingMethod().isStaticInitializer(); + } + + /** + * @see IJavaModifiers#isFinal() + */ + @Override + public boolean isFinal() throws DebugException { + return getUnderlyingMethod().isFinal(); + } + + /** + * @see IJavaStackFrame#isSynchronized() + */ + @Override + public boolean isSynchronized() throws DebugException { + return getUnderlyingMethod().isSynchronized(); + } + + /** + * @see IJavaModifiers#isSynthetic() + */ + @Override + public boolean isSynthetic() throws DebugException { + return getUnderlyingMethod().isSynthetic(); + } + + /** + * @see IJavaModifiers#isPublic() + */ + @Override + public boolean isPublic() throws DebugException { + return getUnderlyingMethod().isPublic(); + } + + /** + * @see IJavaModifiers#isPrivate() + */ + @Override + public boolean isPrivate() throws DebugException { + return getUnderlyingMethod().isPrivate(); + } + + /** + * @see IJavaModifiers#isProtected() + */ + @Override + public boolean isProtected() throws DebugException { + return getUnderlyingMethod().isProtected(); + } + + /** + * @see IJavaModifiers#isPackagePrivate() + */ + @Override + public boolean isPackagePrivate() throws DebugException { + return getUnderlyingMethod().isPackagePrivate(); + } + + /** + * @see IJavaModifiers#isStatic() + */ + @Override + public boolean isStatic() throws DebugException { + return getUnderlyingMethod().isStatic(); + } + + /** + * @see IJavaStackFrame#getSourceName() + */ + @Override + public String getSourceName() throws DebugException { + synchronized (fThread) { + return getSourceName(fLocation); + } + } + + /** + * Returns the source from the default stratum of the given location or + * null if not available (missing attribute). + */ + private String getSourceName(Location location) throws DebugException { + try { + return location.sourceName(); + } catch (AbsentInformationException e) { + return null; + } catch (NativeMethodException e) { + return null; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_source_name, + e.toString()), e); + } + return null; + } + + private boolean equals(Object o1, Object o2) { + if (o1 == null) { + return o2 == null; + } + return o1.equals(o2); + } + + protected boolean isTopStackFrame() throws DebugException { + IStackFrame tos = getThread().getTopStackFrame(); + return tos != null && tos.equals(this); + } + + /** + * Sets this stack frame to be out of synch. Note that passing + * true to this method marks this stack frame as out of synch + * permanently (statically). + */ + public void setOutOfSynch(boolean outOfSynch) { + fIsOutOfSynch = outOfSynch; + } + + /** + * @see IJavaStackFrame#isOutOfSynch() + */ + @Override + public boolean isOutOfSynch() throws DebugException { + if (fIsOutOfSynch) { + return true; + } + // if this frame's thread is not suspended, the out-of-synch info cannot + // change until it suspends again + if (getThread().isSuspended()) { + JDIDebugTarget target = (JDIDebugTarget) getDebugTarget(); + if (target.hasHCROccurred() + && target.isOutOfSynch(getUnderlyingMethod() + .declaringType().name())) { + return true; + } + } + return false; + } + + /** + * @see IJavaStackFrame#isObsolete() + */ + @Override + public boolean isObsolete() { + if (!JDIDebugPlugin.isJdiVersionGreaterThanOrEqual(new int[] { 1, 4 }) + || !((JDIDebugTarget) getDebugTarget()).hasHCROccurred()) { + // If no hot code replace has occurred, this frame + // cannot be obsolete. + return false; + } + // if this frame's thread is not suspended, the obsolete status cannot + // change until it suspends again + synchronized (fThread) { + if (getThread().isSuspended()) { + return getUnderlyingMethod().isObsolete(); + } + return false; + } + } + + protected boolean exists() { + synchronized (fThread) { + return fDepth != -1; + } + } + + /** + * @see ITerminate#canTerminate() + */ + @Override + public boolean canTerminate() { + return exists() && getThread().canTerminate() + || getDebugTarget().canTerminate(); + } + + /** + * @see ITerminate#isTerminated() + */ + @Override + public boolean isTerminated() { + return getThread().isTerminated(); + } + + /** + * @see ITerminate#terminate() + */ + @Override + public void terminate() throws DebugException { + if (getThread().canTerminate()) { + getThread().terminate(); + } else { + getDebugTarget().terminate(); + } + } + + /** + * Returns this stack frame's underlying JDI frame. + * + * @exception DebugException + * if this stack frame does not currently have an underlying + * frame (is in an interim state where this frame's thread + * has been resumed, and is not yet suspended). + */ + protected StackFrame getUnderlyingStackFrame() throws DebugException { + synchronized (fThread) { + if (fStackFrame == null) { + if (fDepth == -1) { + throw new DebugException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IJavaStackFrame.ERR_INVALID_STACK_FRAME, + JDIDebugModelMessages.JDIStackFrame_25, new IllegalStateException())); + } + if (fThread.isSuspended()) { + // re-index stack frames - See Bug 47198 + fThread.computeStackFrames(); + if (fDepth == -1) { + // try it once more before throwing error + fThread.computeStackFrames(); + if (fDepth == -1) { + // If depth is -1, then this is an invalid frame + throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IJavaStackFrame.ERR_INVALID_STACK_FRAME, JDIDebugModelMessages.JDIStackFrame_25, new IllegalStateException())); + } + } + } else { + throw new DebugException(new Status(IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + IJavaThread.ERR_THREAD_NOT_SUSPENDED, + JDIDebugModelMessages.JDIStackFrame_25, new IllegalStateException())); + } + } + return fStackFrame; + } + } + + /** + * Sets the underlying JDI StackFrame. Called by a thread when incrementally + * updating after a step has completed. + * + * @param frame + * The underlying stack frame + */ + protected void setUnderlyingStackFrame(StackFrame frame) { + synchronized (fThread) { + fStackFrame = frame; + if (frame == null) { + fRefreshVariables = true; + } + } + } + + protected void setThread(JDIThread thread) { + fThread = thread; + } + + protected void setVariables(List variables) { + fVariables = variables; + } + + /** + * @see IJavaStackFrame#getLocalVariables() + */ + @Override + public IJavaVariable[] getLocalVariables() throws DebugException { + List list = getUnderlyingVisibleVariables(); + IJavaVariable[] locals = new IJavaVariable[list.size()]; + for (int i = 0; i < list.size(); i++) { + locals[i] = new JDILocalVariable(this, list.get(i)); + } + return locals; + } + + /** + * @see IJavaStackFrame#getThis() + */ + @Override + public IJavaObject getThis() throws DebugException { + IJavaObject receiver = null; + if (!isStatic() && !isNative()) { + ObjectReference thisObject = getUnderlyingThisObject(); + if (thisObject != null) { + receiver = (IJavaObject) JDIValue.createValue( + (JDIDebugTarget) getDebugTarget(), thisObject); + } + } + return receiver; + } + + /** + * Java stack frames do not support registers + * + * @see IStackFrame#getRegisterGroups() + */ + @Override + public IRegisterGroup[] getRegisterGroups() { + return new IRegisterGroup[0]; + } + + /** + * @see IJavaStackFrame#getDeclaringType() + */ + @Override + public IJavaClassType getDeclaringType() throws DebugException { + Method method = getUnderlyingMethod(); + try { + Type type = method.declaringType(); + if (type instanceof ClassType) { + return (IJavaClassType) JDIType.createType( + (JDIDebugTarget) getDebugTarget(), type); + } + targetRequestFailed(JDIDebugModelMessages.JDIStackFrame_0, null); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retreiving_declaring_type, + e.toString()), e); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaStackFrame#getReferenceType() + */ + @Override + public IJavaReferenceType getReferenceType() throws DebugException { + Method method = getUnderlyingMethod(); + try { + Type type = method.declaringType(); + return (IJavaReferenceType) JDIType.createType( + (JDIDebugTarget) getDebugTarget(), type); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retreiving_declaring_type, + e.toString()), e); + } + return null; + } + + /** + * Expression level stepping not supported. + * + * @see IStackFrame#getCharEnd() + */ + @Override + public int getCharEnd() { + return -1; + } + + /** + * Expression level stepping not supported. + * + * @see IStackFrame#getCharStart() + */ + @Override + public int getCharStart() { + return -1; + } + + /** + * Clears the cached data of this stack frame. The underlying stack frame + * has changed in such a way that the cached data may not be valid. + */ + private void clearCachedData() { + fThisObject = null; + fReceivingTypeName = null; + } + + /** + * @see IJavaStackFrame#wereLocalsAvailable() + */ + @Override + public boolean wereLocalsAvailable() { + return fLocalsAvailable; + } + + /** + * Sets whether locals were available. If the setting is not the same as the + * current value, a change event is fired such that a UI client can update. + * + * @param available + * whether local variable information is available for this stack + * frame. + */ + private void setLocalsAvailable(boolean available) { + if (available != fLocalsAvailable) { + fLocalsAvailable = available; + fireChangeEvent(DebugEvent.STATE); + } + } + + /** + * @see IStackFrame#hasRegisterGroups() + */ + @Override + public boolean hasRegisterGroups() { + return false; + } + + /** + * @see IStackFrame#hasVariables() + */ + @Override + public boolean hasVariables() throws DebugException { + return getVariables0().size() > 0; + } + + /** + * @see org.eclipse.debug.core.model.IFilteredStep#canStepWithFilters() + */ + @Override + public boolean canStepWithFilters() { + if (canStepInto()) { + String[] filters = getJavaDebugTarget().getStepFilters(); + return filters != null && filters.length > 0; + } + return false; + } + + /** + * @see org.eclipse.debug.core.model.IFilteredStep#stepWithFilters() + */ + @SuppressWarnings("deprecation") + @Override + public void stepWithFilters() throws DebugException { + ((IJavaThread) getThread()).stepWithFilters(); + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaStackFrame#getSourcePath(java.lang.String) + */ + @Override + public String getSourcePath(String stratum) throws DebugException { + synchronized (fThread) { + try { + return fLocation.sourcePath(stratum); + } catch (AbsentInformationException e) { + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_source_path, + e.toString()), e); + } + } + return null; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaStackFrame#getSourcePath() + */ + @Override + public String getSourcePath() throws DebugException { + synchronized (fThread) { + try { + return fLocation.sourcePath(); + } catch (AbsentInformationException e) { + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_source_path, + e.toString()), e); + } + } + return null; + } + + /* + * @see + * org.eclipse.jdt.debug.core.IJavaStackFrame#getLineNumber(java.lang.String + * ) + */ + @Override + public int getLineNumber(String stratum) throws DebugException { + synchronized (fThread) { + try { + return fLocation.lineNumber(stratum); + } catch (RuntimeException e) { + if (getThread().isSuspended()) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_line_number, + e.toString()), e); + } + } + } + return -1; + } + + /* + * @see + * org.eclipse.jdt.debug.core.IJavaStackFrame#getSourceName(java.lang.String + * ) + */ + @Override + public String getSourceName(String stratum) throws DebugException { + synchronized (fThread) { + try { + return fLocation.sourceName(stratum); + } catch (AbsentInformationException e) { + } catch (NativeMethodException e) { + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIStackFrame_exception_retrieving_source_name, + e.toString()), e); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaStackFrame#isVarargs() + */ + @Override + public boolean isVarArgs() throws DebugException { + return getUnderlyingMethod().isVarArgs(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaStackFrame#canForceReturn() + */ + @Override + public boolean canForceReturn() { + if (getJavaDebugTarget().supportsForceReturn() && isSuspended()) { + try { + if (!isNative()) { + if (isTopStackFrame()) { + return true; + } + List frames = fThread.computeStackFrames(); + int index = frames.indexOf(this); + if (index > 0) { + JDIStackFrame prev = (JDIStackFrame) frames + .get(index - 1); + return prev.canDropToFrame(); + } + } + } catch (DebugException e) { + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.debug.core.IJavaStackFrame#forceReturn(org.eclipse.jdt + * .debug.core.IJavaValue) + */ + @Override + public void forceReturn(IJavaValue value) throws DebugException { + if (isTopStackFrame()) { + fThread.forceReturn(value); + } else { + // first check assignment compatible + Method method = getUnderlyingMethod(); + try { + ValueImpl.checkValue(((JDIValue) value).getUnderlyingValue(), + method.returnType(), + (VirtualMachineImpl) method.virtualMachine()); + } catch (InvalidTypeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIStackFrame_26, e); + } catch (ClassNotLoadedException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e); + } + List frames = fThread.computeStackFrames(); + int index = frames.indexOf(this); + if (index > 0) { + JDIStackFrame prev = (JDIStackFrame) frames.get(index - 1); + fThread.popFrame(prev); + fThread.forceReturn(value); + } + } + } + + public void setIsTop(boolean isTop) { + this.fIsTop = isTop; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThisVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThisVariable.java new file mode 100644 index 0000000000..2e3a27be53 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThisVariable.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaVariable; + +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +/** + * Represents the receiver in a stack frame. + */ + +public class JDIThisVariable extends JDIVariable { + /** + * The wrapped object + */ + private final ObjectReference fObject; + + /** + * Constructs a variable representing 'this' in a stack frame. + */ + public JDIThisVariable(JDIDebugTarget target, ObjectReference object) { + super(target); + fObject = object; + } + + /** + * Returns this variable's current Value. + */ + @Override + protected Value retrieveValue() { + return fObject; + } + + /** + * @see IVariable#getName() + */ + @Override + public String getName() { + return "this"; //$NON-NLS-1$ + } + + /** + * @see IJavaVariable#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + return retrieveValue().type().signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThisVariableexception_retrieving_type_signature, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaVariable#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + return getSignature(); + } + + /** + * @see IVariable#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + try { + return getValue().getReferenceTypeName(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThisVariableexception_retrieving_reference_type_name, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * @see JDIVariable#getUnderlyingType() + */ + @Override + protected Type getUnderlyingType() throws DebugException { + try { + return retrieveValue().type(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThisVariable_exception_while_retrieving_type_this, + e.toString()), e); + } + // this line will not be executed as an exception + // will be throw in type retrieval fails + return null; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPrivate() + */ + @Override + public boolean isPrivate() throws DebugException { + try { + return ((ReferenceType) getUnderlyingType()).isPrivate(); + } catch (RuntimeException e) { + targetRequestFailed( + JDIDebugModelMessages.JDIThisVariable_Exception_occurred_while_retrieving_modifiers__1, + e); + } + // this line will not be executed as an exception + // will be throw + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isProtected() + */ + @Override + public boolean isProtected() throws DebugException { + try { + return ((ReferenceType) getUnderlyingType()).isProtected(); + } catch (RuntimeException e) { + targetRequestFailed( + JDIDebugModelMessages.JDIThisVariable_Exception_occurred_while_retrieving_modifiers__1, + e); + } + // this line will not be executed as an exception + // will be throw + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaModifiers#isPublic() + */ + @Override + public boolean isPublic() throws DebugException { + try { + return ((ReferenceType) getUnderlyingType()).isPublic(); + } catch (RuntimeException e) { + targetRequestFailed( + JDIDebugModelMessages.JDIThisVariable_Exception_occurred_while_retrieving_modifiers__1, + e); + } + // this line will not be executed as an exception + // will be throw + return false; + } + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (o instanceof JDIThisVariable) { + return ((JDIThisVariable) o).fObject.equals(fObject); + } + return false; + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return fObject.hashCode(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java new file mode 100644 index 0000000000..dc06d14a08 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java @@ -0,0 +1,3679 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * BEA - Daniel R Somerfield - Bug 89643 + * Jesper Steen Moller - Enhancement 254677 - filter getters/setters + * Jesper Steen Møller - Bug 430839 + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IStep; +import org.eclipse.debug.core.model.IStepFilter; +import org.eclipse.debug.core.model.ISuspendResume; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.debug.core.IEvaluationRunnable; +import org.eclipse.jdt.debug.core.IJavaBreakpoint; +import org.eclipse.jdt.debug.core.IJavaBreakpointListener; +import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint; +import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint.SuspendOnRecurrenceStrategy; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaThreadGroup; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.internal.debug.core.IJDIEventListener; +import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.breakpoints.ConditionalBreakpointHandler; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaExceptionBreakpoint; +import org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint; +import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType; + +import com.sun.jdi.BooleanValue; +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.ClassType; +import com.sun.jdi.Field; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.IntegerValue; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.InvalidStackFrameException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.Location; +import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StackFrame; +import com.sun.jdi.ThreadGroupReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.ExceptionEvent; +import com.sun.jdi.event.MethodEntryEvent; +import com.sun.jdi.event.MethodExitEvent; +import com.sun.jdi.event.StepEvent; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.EventRequestManager; +import com.sun.jdi.request.ExceptionRequest; +import com.sun.jdi.request.MethodEntryRequest; +import com.sun.jdi.request.MethodExitRequest; +import com.sun.jdi.request.StepRequest; + +/** + * Model thread implementation for an underlying thread on a VM. + */ +public class JDIThread extends JDIDebugElement implements IJavaThread { + + /** + * Constant for the name of the default Java stratum + */ + private static final String JAVA_STRATUM_CONSTANT = "Java"; //$NON-NLS-1$ + + /** + * Constant for the name of the main thread group. + */ + private static final String MAIN_THREAD_GROUP = "main"; //$NON-NLS-1$ + + /** + * @since 3.5 + */ + public static final int RESUME_QUIET = 500; + + /** + * @since 3.5 + */ + public static final int SUSPEND_QUIET = 501; + + /** + * Status code indicating that a request to suspend this thread has timed + * out + */ + public static final int SUSPEND_TIMEOUT = 161; + /** + * Underlying thread. + */ + private ThreadReference fThread; + /** + * Cache of previous name, used in case thread is garbage collected. + */ + private String fPreviousName; + /** + * Collection of stack frames + */ + private volatile List fStackFrames; + /** + * Underlying thread group, cached on first access. + */ + private ThreadGroupReference fThreadGroup; + /** + * Name of underlying thread group, cached on first access. + */ + private String fThreadGroupName; + /** + * Whether children need to be refreshed. Set to true when + * stack frames are re-used on the next suspend. + */ + private boolean fRefreshChildren = true; + /** + * Currently pending step handler, null when not performing a + * step. + */ + private volatile StepHandler fStepHandler; + /** + * Whether running. + */ + private volatile boolean fRunning; + /** + * Whether terminated. + */ + private volatile boolean fTerminated; + + /** + * Whether this thread is a system thread. + */ + private boolean fIsSystemThread; + + /** + * Whether this thread is a daemon thread + * + * @since 3.3 + */ + private boolean fIsDaemon; + + /** + * Lock used to guard access to internal data that need to be updated in atomic manner + */ + private final Object breakpointAcessLock = new Object(); + + /** + * The collection of breakpoints that caused the last suspend, or an empty collection if the thread is not suspended or was not suspended by any + * breakpoint(s). + */ + private final List fCurrentBreakpoints = new Vector<>(2); + /** + * Non-null when this thread is executing an evaluation runnable. An + * evaluation may involve a series of method invocations. + */ + private volatile IEvaluationRunnable fEvaluationRunnable; + + /** + * Whether this thread was manually suspended during an evaluation. + */ + private volatile boolean fEvaluationInterrupted; + + /** + * true when there has been a request to suspend this thread + * via {@link #suspend()}. Remains true until there is a + * request to resume this thread via {@link #resume()}. + */ + private volatile boolean fClientSuspendRequest; + + /** + * Whether this thread is currently invoking a method. Nested method + * invocations cannot be performed. + */ + private volatile boolean fIsInvokingMethod; + + /** + * Lock used to wait for method invocations to complete. + */ + private final Object fInvocationLock = new Object(); + + /** + * Lock used to wait for evaluations to complete. + */ + private final Object fEvaluationLock = new Object(); + + /** + * Whether or not this thread is currently honoring breakpoints. This flag + * allows breakpoints to be disabled during evaluations. + */ + private volatile boolean fHonorBreakpoints = true; + + /** + * Whether a suspend vote is currently in progress. While voting this thread + * does not allow other breakpoints to be hit. + * + * @since 3.5 + */ + private volatile boolean fSuspendVoteInProgress; + + /** + * The kind of step that was originally requested. Zero or more 'secondary + * steps' may be performed programmatically after the original + * user-requested step, and this field tracks the type (step into, over, + * return) of the original step. + */ + private volatile int fOriginalStepKind; + + /** + * The JDI Location from which an original user-requested step began. + */ + private volatile Location fOriginalStepLocation; + + /** + * The total stack depth at the time an original (user-requested) step is + * initiated. This is used along with the original step Location to + * determine if a step into comes back to the starting location and needs to + * be 'nudged' forward. Checking the stack depth eliminates undesired + * 'nudging' in recursive methods. + */ + private volatile int fOriginalStepStackDepth; + + /** + * Whether or not this thread is currently suspending (user-requested). + */ + private volatile boolean fIsSuspending; + + private final ThreadJob fAsyncJob; + + private volatile boolean fRunningAsyncJob; + + /** + * The current MethodExitRequest if a step-return or step-over is in progress. + */ + private volatile MethodExitRequest fCurrentMethodExitRequest; + + private volatile Thread fCurrentMethodExitRequestDisabler; + + /** + * The current ExceptionRequest if a step-return or step-over is in progress. + */ + private volatile ExceptionRequest fCurrentExceptionRequest; + + /** + * The current MethodEntryRequest if a step-over is in progress. + */ + private volatile MethodEntryRequest fCurrentMethodEntryRequest; + + /** + * Method for which a result value is expected + */ + private volatile Method fStepResultMethod; + + /** + * The location if a step-over is in progress. + */ + private volatile Location fStepOverLocation; + + /** + * The depth if a step-over is in progress. + */ + private volatile int fStepOverFrameCount; + + /** + * Candidate for depth of stack that will be returned values belong to. Is copied to fStepReturnTargetDepth only when step-return is actually + * observed + */ + private volatile int fStepReturnTargetFrameCount; + + private volatile MethodResult fStepResultCandidate; + + private final AtomicBoolean fStepResultTimeoutTriggered = new AtomicBoolean(); + + /** + * Result of the last step step-over or step-return operation or method exit breakpoint of exception break point + */ + private volatile MethodResult fMethodResult; + + /** + * If previous suspend was on an exception breakpoint, this variable holds that Java exception instance, else {@code null}. + */ + private volatile IJavaObject fPreviousException; + + private final AtomicBoolean fCompletingBreakpointHandling; + private final AtomicBoolean fHandlingSuspendForBreakpoint; + + /** + * Creates a new thread on the underlying thread reference in the given + * debug target. + * + * @param target + * the debug target in which this thread is contained + * @param thread + * the underlying thread on the VM + * @exception ObjectCollectedException + * if the underlying thread has been garbage collected and + * cannot be properly initialized + */ + public JDIThread(JDIDebugTarget target, ThreadReference thread) + throws ObjectCollectedException { + super(target); + setUnderlyingThread(thread); + fAsyncJob = new ThreadJob(); + initialize(); + fCompletingBreakpointHandling = new AtomicBoolean(false); + fHandlingSuspendForBreakpoint = new AtomicBoolean(false); + } + + /** + * Thread initialization: + *
                        + *
                      • Determines if this thread is a system thread
                      • + *
                      • Sets terminated state to false
                      • + *
                      • Determines suspended state from underlying thread
                      • + *
                      • Sets this threads stack frames to an empty collection
                      • + *
                      + * + * @exception ObjectCollectedException + * if the thread has been garbage collected and cannot be + * initialized + */ + protected void initialize() throws ObjectCollectedException { + fStackFrames = new Vector<>(); + // system thread + try { + determineIfSystemThread(); + } catch (DebugException e) { + Throwable underlyingException = e.getStatus().getException(); + if (underlyingException instanceof VMDisconnectedException) { + // Threads may be created by the VM at shutdown + // as finalizers. The VM may be disconnected by + // the time we hear about the thread creation. + disconnected(); + return; + } + if (underlyingException instanceof ObjectCollectedException) { + throw (ObjectCollectedException) underlyingException; + } + logError(e); + } + + try { + determineIfDaemonThread(); + } catch (DebugException e) { + Throwable underlyingException = e.getStatus().getException(); + if (underlyingException instanceof VMDisconnectedException) { + // Threads may be created by the VM at shutdown + // as finalizers. The VM may be disconnected by + // the time we hear about the thread creation. + disconnected(); + return; + } + logError(e); + } + + try { + ThreadGroupReference group = getUnderlyingThreadGroup(); + // might already be terminated + if (group != null) { + getJavaDebugTarget().addThreadGroup(group); + } + } catch (DebugException e1) { + } + + // state + setTerminated(false); + setRunning(false); + try { + // see bug 30816 + if (fThread.status() == ThreadReference.THREAD_STATUS_UNKNOWN) { + setRunning(true); + return; + } + } catch (VMDisconnectedException e) { + disconnected(); + return; + } catch (ObjectCollectedException e) { + throw e; + } catch (RuntimeException e) { + logError(e); + } + + try { + // This may be a transient suspend state (for example, a thread is + // handling a + // class prepare event quietly). The class prepare event handler + // will notify + // this thread when it resumes + setRunning(!fThread.isSuspended()); + } catch (VMDisconnectedException e) { + disconnected(); + return; + } catch (ObjectCollectedException e) { + throw e; + } catch (RuntimeException e) { + logError(e); + } + } + + /** + * Adds the given breakpoint to the list of breakpoints this thread is + * suspended at + * + * @param bp + * the breakpoint to add to the listing + */ + protected void addCurrentBreakpoint(IBreakpoint bp) { + synchronized (breakpointAcessLock) { + fCurrentBreakpoints.add(bp); + } + } + + /** + * Removes the given breakpoint from the list of breakpoints this thread is + * suspended at (called when a breakpoint is deleted, in case we are + * suspended at that breakpoint) + * + * @param bp + * the breakpoint to remove from the listing + */ + protected void removeCurrentBreakpoint(IBreakpoint bp) { + synchronized (breakpointAcessLock) { + fCurrentBreakpoints.remove(bp); + } + } + + @Override + public IBreakpoint[] getBreakpoints() { + synchronized (breakpointAcessLock) { + return fCurrentBreakpoints.toArray(new IBreakpoint[fCurrentBreakpoints.size()]); + } + } + + @Override + public boolean canResume() { + return isSuspended() + && (!isPerformingEvaluation() || isInvokingMethod()) + && !isSuspendVoteInProgress() + || getDebugTarget().isSuspended(); + } + + @Override + public boolean canSuspend() { + return !isSuspended() + || (isPerformingEvaluation() && !isInvokingMethod()) + || isSuspendVoteInProgress(); + } + + @Override + public boolean canTerminate() { + return getDebugTarget().canTerminate(); + } + + @Override + public boolean canStepInto() { + return canStep(); + } + + @Override + public boolean canStepOver() { + return canStep(); + } + + @Override + public boolean canStepReturn() { + return canStep(); + } + + /** + * Returns whether this thread is in a valid state to step. + * + * @return whether this thread is in a valid state to step + */ + protected boolean canStep() { + try { + return isSuspended() + && (!isPerformingEvaluation() || isInvokingMethod()) + && !isSuspendVoteInProgress() && !isStepping() + && getTopStackFrame() != null + && !getJavaDebugTarget().isPerformingHotCodeReplace(); + } catch (DebugException e) { + return false; + } + } + + /** + * Determines and sets whether this thread represents a system thread. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void determineIfSystemThread() throws DebugException { + fIsSystemThread = false; + ThreadGroupReference tgr = getUnderlyingThreadGroup(); + fIsSystemThread = tgr != null; + while (tgr != null) { + String tgn = null; + try { + tgn = tgr.name(); + tgr = tgr.parent(); + } catch (UnsupportedOperationException e) { + fIsSystemThread = false; + break; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_determining_if_system_thread, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return; + } + if (tgn != null && tgn.equals(MAIN_THREAD_GROUP)) { + fIsSystemThread = false; + break; + } + } + } + + /** + * Determines whether this is a daemon thread. + * + * @throws DebugException + * on failure + */ + protected void determineIfDaemonThread() throws DebugException { + fIsDaemon = false; + try { + ReferenceType referenceType = getUnderlyingThread().referenceType(); + Field field = referenceType.fieldByName("daemon"); //$NON-NLS-1$ + if (field == null) { + field = referenceType.fieldByName("isDaemon"); //$NON-NLS-1$ + } + if (field != null) { + if (field.signature().equals(Signature.SIG_BOOLEAN)) { + Value value = getUnderlyingThread().getValue(field); + if (value instanceof BooleanValue) { + fIsDaemon = ((BooleanValue) value).booleanValue(); + } + } + } + } catch (ObjectCollectedException oce) {/* + * do nothing thread does not + * exist + */ + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_47, e); + } + } + + /** + * NOTE: this method returns a copy of this thread's stack frames. + * + * @see IThread#getStackFrames() + */ + @Override + public synchronized IStackFrame[] getStackFrames() throws DebugException { + List list = computeStackFrames(); + return list.toArray(new IStackFrame[list.size()]); + } + + /** + * @see #computeStackFrames() + * + * @param refreshChildren + * whether or not this method should request new stack frames + * from the VM + * @return the list of stackframes + * @throws DebugException + * if an exception occurs retrieving frames + */ + protected synchronized List computeStackFrames(boolean refreshChildren) + throws DebugException { + if (isSuspended()) { + if (isTerminated()) { + fStackFrames.clear(); + } else if (refreshChildren) { + List frames = getUnderlyingFrames(); + int oldSize = fStackFrames.size(); + if (oldSize > 0) { + ((JDIStackFrame) fStackFrames.get(0)).setIsTop(false); + } + int newSize = frames.size(); + int discard = oldSize - newSize; // number of old frames to + // discard, if any + for (int i = 0; i < discard; i++) { + JDIStackFrame invalid = (JDIStackFrame) fStackFrames + .remove(0); + invalid.bind(null, -1); + } + int newFrames = newSize - oldSize; // number of frames to + // create, if any + int depth = oldSize; + for (int i = newFrames - 1; i >= 0; i--) { + fStackFrames.add(0, new JDIStackFrame(this, + frames.get(i), depth)); + depth++; + } + int numToRebind = Math.min(newSize, oldSize); // number of + // frames to + // attempt to + // re-bind + int offset = newSize - 1; + for (depth = 0; depth < numToRebind; depth++) { + JDIStackFrame oldFrame = (JDIStackFrame) fStackFrames + .get(offset); + StackFrame frame = frames.get(offset); + JDIStackFrame newFrame = oldFrame.bind(frame, depth); + if (newFrame != oldFrame) { + fStackFrames.set(offset, newFrame); + } + offset--; + } + if (newSize > 0) { + ((JDIStackFrame) fStackFrames.get(0)).setIsTop(true); + } + } + fRefreshChildren = false; + } else { + return Collections.EMPTY_LIST; + } + return fStackFrames; + } + + /** + * Returns this thread's current stack frames as a list, computing them if + * required. Returns an empty collection if this thread is not currently + * suspended, or this thread is terminated. This method should be used + * internally to get the current stack frames, instead of calling + * #getStackFrames(), which makes a copy of the current list. + *

                      + * Before a thread is resumed a call must be made to one of: + *

                        + *
                      • preserveStackFrames()
                      • + *
                      • disposeStackFrames()
                      • + *
                      + * If stack frames are disposed before a thread is resumed, stack frames are + * completely re-computed on the next call to this method. If stack frames + * are to be preserved, this method will attempt to re-use any stack frame + * objects which represent the same stack frame as on the previous suspend. + * Stack frames are cached until a subsequent call to preserve or dispose + * stack frames. + *

                      + * + * @return list of IJavaStackFrame + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + public synchronized List computeStackFrames() throws DebugException { + return computeStackFrames(fRefreshChildren); + } + + /** + * This method differs from computeStackFrames() in that it always requests + * new stack frames from the VM. As this is an expensive operation, this + * method should only be used by clients who know for certain that the stack + * frames on the VM have changed. + * + * @see JDIThread#computeStackFrames() + * @return the listing of stackframes or an empty list, never + * null + * @throws DebugException + * if an exception occurs retrieving the stackframes + */ + public List computeNewStackFrames() throws DebugException { + return computeStackFrames(true); + } + + private List getUnderlyingFrames() throws DebugException { + if (!isSuspended()) { + // Checking isSuspended here eliminates a race condition in resume + // between the time stack frames are preserved and the time the + // underlying thread is actually resumed. + requestFailed( + JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1, + null, IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } + try { + return fThread.frames(); + } catch (IncompatibleThreadStateException e) { + requestFailed( + JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1, + e, IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2, + e.toString()), e); + } catch (InternalError e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2, + e.toString()), e); + } + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + + /** + * Returns the number of frames on the stack from the underlying thread. + * + * @return number of frames on the stack + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      • This thread is not suspended
                      • + *
                      + */ + protected int getUnderlyingFrameCount() throws DebugException { + try { + return fThread.frameCount(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_frame_count, + e.toString()), e); + } catch (IncompatibleThreadStateException e) { + requestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_frame_count, + e.toString()), e, + IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } + // execution will not reach here - try block will either + // return or exception will be thrown + return -1; + } + + @Override + public void runEvaluation(IEvaluationRunnable evaluation, + IProgressMonitor monitor, int evaluationDetail, + boolean hitBreakpoints) throws DebugException { + if (isPerformingEvaluation()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, + null, IJavaThread.ERR_NESTED_METHOD_INVOCATION); // + } + + if (!canRunEvaluation()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, + null, IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } + + synchronized (fEvaluationLock) { + fEvaluationRunnable = evaluation; + fHonorBreakpoints = hitBreakpoints; + } + boolean quiet = isSuspendVoteInProgress(); + if (quiet) { + // evaluations are quiet when a suspend vote is in progress + // (conditional breakpoints, etc.). + fireEvent(new DebugEvent(this, DebugEvent.MODEL_SPECIFIC, + RESUME_QUIET)); + } else { + fireResumeEvent(evaluationDetail); + } + // save and restore current breakpoint information - bug 30837 + IBreakpoint[] breakpoints = getBreakpoints(); + ISchedulingRule rule = null; + if (evaluationDetail == DebugEvent.EVALUATION_IMPLICIT) { + rule = getThreadRule(); + } + try { + if (rule != null) { + Job.getJobManager().beginRule(rule, monitor); + } + if (monitor == null || !monitor.isCanceled()) { + evaluation.run(this, monitor); + } + } catch (DebugException e) { + throw e; + } finally { + if (rule != null) { + Job.getJobManager().endRule(rule); + } + synchronized (fEvaluationLock) { + fEvaluationRunnable = null; + fHonorBreakpoints = true; + fEvaluationLock.notifyAll(); + } + if (getBreakpoints().length == 0 && breakpoints.length > 0) { + for (IBreakpoint breakpoint : breakpoints) { + addCurrentBreakpoint(breakpoint); + } + } + if (quiet) { + fireEvent(new DebugEvent(this, DebugEvent.MODEL_SPECIFIC, + SUSPEND_QUIET)); + } else { + fireSuspendEvent(evaluationDetail); + } + if (fEvaluationInterrupted + && fAsyncJob.isEmpty() && fRunningAsyncJob == false) { + // @see bug 31585: + // When an evaluation was interrupted & resumed, the launch view + // does + // not update properly. It cannot know when it is safe to + // display frames + // since it does not know about queued evaluations. Thus, when + // the queue + // is empty, we fire a change event to force the view to update. + fEvaluationInterrupted = false; + fireChangeEvent(DebugEvent.CONTENT); + } + } + } + + /** + * Returns whether this thread is in a valid state to run an evaluation. + * + * @return whether this thread is in a valid state to run an evaluation + */ + protected boolean canRunEvaluation() { + // NOTE similar to #canStep, except an evaluation can be run when in the + // middle of + // a step (conditional breakpoint, breakpoint listener, etc.) + try { + return isSuspended() + && !(isPerformingEvaluation() || isInvokingMethod()) + && getTopStackFrame() != null + && !getJavaDebugTarget().isPerformingHotCodeReplace(); + } catch (DebugException e) { + return false; + } + } + + @Override + public void queueRunnable(Runnable evaluation) { + fAsyncJob.addRunnable(evaluation); + } + + @Override + public void terminateEvaluation() throws DebugException { + synchronized (fEvaluationLock) { + if (canTerminateEvaluation()) { + fEvaluationInterrupted = true; + ((ITerminate) fEvaluationRunnable).terminate(); + } + } + } + + @Override + public boolean canTerminateEvaluation() { + synchronized (fEvaluationLock) { + return fEvaluationRunnable instanceof ITerminate; + } + } + + /** + * Invokes a method on the target, in this thread, and returns the result. + * Only one receiver may be specified - either a class or an object, the + * other must be null. This thread is left suspended after the + * invocation is complete, unless a call is made to + * abortEvaluation while + * performing a method invocation. In that case, this thread is automatically + * resumed when/if this invocation (eventually) completes. + *

                      + * Method invocations cannot be nested. That is, this method must + * return before another call to this method can be made. This + * method does not return until the invocation is complete. + * Breakpoints can suspend a method invocation, and it is possible + * that an invocation will not complete due to an infinite loop + * or deadlock. + *

                      + *

                      + * Stack frames are preserved during method invocations, unless + * a timeout occurs. Although this thread's state is updated to + * running while performing an evaluation, no debug events are + * fired unless this invocation is interrupted by a breakpoint, + * or the invocation times out. + *

                      + *

                      + * When performing an invocation, the communication timeout with + * the target VM is set to infinite, as the invocation may not + * complete in a timely fashion, if at all. The timeout value + * is reset to its original value when the invocation completes. + *

                      + * + * @param receiverClass + * the class in the target representing the receiver of a static + * message send, or null + * @param receiverObject + * the object in the target to be the receiver of the message + * send, or null + * @param method + * the underlying method to be invoked + * @param args + * the arguments to invoke the method with (an empty list if + * none) + * @param invokeNonvirtual + * if the super-class method should be invoked + * @return the result of the method, as an underlying value + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      • This thread is not suspended (status code + * IJavaThread.ERR_THREAD_NOT_SUSPENDED)
                      • + *
                      • This thread is already invoking a method (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
                      • + *
                      • This thread is not suspended by a JDI request (status + * code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
                      • + *
                      + */ + protected Value invokeMethod(ClassType receiverClass, + ObjectReference receiverObject, Method method, List args, + boolean invokeNonvirtual) throws DebugException { + if (receiverClass != null && receiverObject != null) { + throw new IllegalArgumentException( + JDIDebugModelMessages.JDIThread_can_only_specify_one_receiver_for_a_method_invocation); + } + Value result = null; + int timeout = getRequestTimeout(); + try { + // this is synchronized such that any other operation that + // might be resuming this thread has a chance to complete before + // we determine if it is safe to continue with a method invocation. + // See bugs 6518, 14069 + synchronized (this) { + if (!isSuspended()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, + null, IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } + if (isInvokingMethod()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, + null, IJavaThread.ERR_NESTED_METHOD_INVOCATION); + } + // set the request timeout to be infinite + setRequestTimeout(Integer.MAX_VALUE); + setRunning(true); + setInvokingMethod(true); + } + preserveStackFrames(); + int flags = ClassType.INVOKE_SINGLE_THREADED; + if (invokeNonvirtual) { + // Superclass method invocation must be performed non-virtual. + flags |= ObjectReference.INVOKE_NONVIRTUAL; + } + if (receiverClass == null) { + result = receiverObject.invokeMethod(fThread, method, args, + flags); + } else { + result = receiverClass.invokeMethod(fThread, method, args, + flags); + } + } catch (InvalidTypeException e) { + invokeFailed(e, timeout); + } catch (ClassNotLoadedException e) { + invokeFailed(e, timeout); + } catch (IncompatibleThreadStateException e) { + invokeFailed( + JDIDebugModelMessages.JDIThread_Thread_must_be_suspended_by_step_or_breakpoint_to_perform_method_invocation_1, + IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE, e, timeout); + } catch (InvocationException e) { + invokeFailed(e, timeout); + } catch (RuntimeException e) { + invokeFailed(e, timeout); + } + + invokeComplete(timeout); + return result; + } + + /** + * Invokes a method on the target, in this thread, and returns the result. + * This thread is left suspended after the invocation is complete, unless + * a call is made to abortEvaluation while performing a method + * invocation. In that case, this thread is automatically resumed when/if + * this invocation (eventually) completes. + *

                      + * Method invocations cannot be nested. That is, this method must + * return before another call to this method can be made. This + * method does not return until the invocation is complete. + * Breakpoints can suspend a method invocation, and it is possible + * that an invocation will not complete due to an infinite loop + * or deadlock. + *

                      + *

                      + * Stack frames are preserved during method invocations, unless + * a timeout occurs. Although this thread's state is updated to + * running while performing an evaluation, no debug events are + * fired unless this invocation is interrupted by a breakpoint, + * or the invocation times out. + *

                      + *

                      + * When performing an invocation, the communication timeout with + * the target VM is set to infinite, as the invocation may not + * complete in a timely fashion, if at all. The timeout value + * is reset to its original value when the invocation completes. + *

                      + * + * @param receiverInterface + * the class in the target representing the receiver of a static + * message send, or null + * @param method + * the underlying method to be invoked + * @param args + * the arguments to invoke the method with (an empty list if + * none) + * @return the result of the method, as an underlying value + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      • This thread is not suspended (status code + * IJavaThread.ERR_THREAD_NOT_SUSPENDED)
                      • + *
                      • This thread is already invoking a method (status code + * IJavaThread.ERR_NESTED_METHOD_INVOCATION)
                      • + *
                      • This thread is not suspended by a JDI request (status + * code + * IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE)
                      • + *
                      + */ + protected Value invokeMethod(InterfaceType receiverInterface, + Method method, List args) throws DebugException { + Value result = null; + int timeout = getRequestTimeout(); + try { + // this is synchronized such that any other operation that + // might be resuming this thread has a chance to complete before + // we determine if it is safe to continue with a method invocation. + // See bugs 6518, 14069 + synchronized (this) { + if (!isSuspended()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, + null, IJavaThread.ERR_THREAD_NOT_SUSPENDED); + } + if (isInvokingMethod()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, + null, IJavaThread.ERR_NESTED_METHOD_INVOCATION); + } + // set the request timeout to be infinite + setRequestTimeout(Integer.MAX_VALUE); + setRunning(true); + setInvokingMethod(true); + } + preserveStackFrames(); + int flags = ClassType.INVOKE_SINGLE_THREADED; + result = receiverInterface.invokeMethod(fThread, method, args, + flags); + } catch (InvalidTypeException e) { + invokeFailed(e, timeout); + } catch (ClassNotLoadedException e) { + invokeFailed(e, timeout); + } catch (IncompatibleThreadStateException e) { + invokeFailed( + JDIDebugModelMessages.JDIThread_Thread_must_be_suspended_by_step_or_breakpoint_to_perform_method_invocation_1, + IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE, e, timeout); + } catch (InvocationException e) { + invokeFailed(e, timeout); + } catch (RuntimeException e) { + invokeFailed(e, timeout); + } + + invokeComplete(timeout); + return result; + } + + /** + * Invokes a constructor in this thread, creating a new instance of the + * given class, and returns the result as an object reference. This thread + * is left suspended after the invocation is complete. + *

                      + * Method invocations cannot be nested. That is, this method must return + * before another call to this method can be made. This method does not + * return until the invocation is complete. Breakpoints can suspend a method + * invocation, and it is possible that an invocation will not complete due + * to an infinite loop or deadlock. + *

                      + *

                      + * Stack frames are preserved during method invocations, unless a timeout + * occurs. Although this thread's state is updated to running while + * performing an evaluation, no debug events are fired unless this + * invocation is interrupted by a breakpoint, or the invocation times out. + *

                      + *

                      + * When performing an invocation, the communication timeout with the target + * VM is set to infinite, as the invocation may not complete in a timely + * fashion, if at all. The timeout value is reset to its original value when + * the invocation completes. + *

                      + * + * @param receiverClass + * the class in the target representing the receiver of the 'new' + * message send + * @param constructor + * the underlying constructor to be invoked + * @param args + * the arguments to invoke the constructor with (an empty list if + * none) + * @return a new object reference + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected ObjectReference newInstance(ClassType receiverClass, + Method constructor, List args) throws DebugException { + if (isInvokingMethod()) { + requestFailed( + JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations_2, + null); + } + ObjectReference result = null; + int timeout = getRequestTimeout(); + try { + // set the request timeout to be infinite + setRequestTimeout(Integer.MAX_VALUE); + setRunning(true); + setInvokingMethod(true); + preserveStackFrames(); + result = receiverClass.newInstance(fThread, constructor, args, + ClassType.INVOKE_SINGLE_THREADED); + } catch (InvalidTypeException e) { + invokeFailed(e, timeout); + } catch (ClassNotLoadedException e) { + invokeFailed(e, timeout); + } catch (IncompatibleThreadStateException e) { + invokeFailed(e, timeout); + } catch (InvocationException e) { + invokeFailed(e, timeout); + } catch (RuntimeException e) { + invokeFailed(e, timeout); + } + + invokeComplete(timeout); + return result; + } + + /** + * Called when an invocation fails. Performs cleanup and throws an + * exception. + * + * @param e + * the exception that caused the failure + * @param restoreTimeout + * the communication timeout value, in milliseconds, that should + * be reset + * @see #invokeComplete(int) + * @exception DebugException + * Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void invokeFailed(Throwable e, int restoreTimeout) + throws DebugException { + invokeFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_invoking_method, + e.toString()), + DebugException.TARGET_REQUEST_FAILED, e, restoreTimeout); + } + + /** + * Called when an invocation fails. Performs cleanup and throws an + * exception. + * + * @param message + * error message + * @param code + * status code + * @param e + * the exception that caused the failure + * @param restoreTimeout + * the communication timeout value, in milliseconds, that should + * be reset + * @see #invokeComplete(int) + * @exception DebugException + * Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void invokeFailed(String message, int code, Throwable e, + int restoreTimeout) throws DebugException { + invokeComplete(restoreTimeout); + requestFailed(message, e, code); + } + + /** + * Called when a method invocation has returned, successfully or not. This + * method performs cleanup: + *
                        + *
                      • Resets the state of this thread to suspended
                      • + *
                      • Restores the communication timeout value
                      • + *
                      • Computes the new set of stack frames for this thread + *
                      + * + * @param restoreTimeout + * the communication timeout value, in milliseconds, that should + * be reset + * @see #invokeMethod(ClassType, ObjectReference, Method, List, boolean) + * @see #newInstance(ClassType, Method, List) + */ + protected synchronized void invokeComplete(int restoreTimeout) { + setInvokingMethod(false); + setRunning(false); + setRequestTimeout(restoreTimeout); + // update preserved stack frames + try { + computeStackFrames(); + } catch (DebugException e) { + logError(e); + } + } + + @Override + public String getName() throws DebugException { + try { + fPreviousName = fThread.name(); + } catch (RuntimeException e) { + // Don't bother reporting the exception when retrieving the name + // (bug 30785 & bug 33276) + if (e instanceof ObjectCollectedException) { + if (fPreviousName == null) { + fPreviousName = JDIDebugModelMessages.JDIThread_garbage_collected_1; + } + } else if (e instanceof VMDisconnectedException) { + if (fPreviousName == null) { + fPreviousName = JDIDebugModelMessages.JDIThread_42; + } + } else { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_thread_name, + e.toString()), e); + } + } + return fPreviousName; + } + + /** + * Returns the priority from the underlying {@link ReferenceType}, failing + * that the backing {@link Value} for the underlying {@link ThreadReference} + * is consulted + * + * @return the priority from the backing {@link ReferenceType} or + * {@link Value} + * @throws DebugException + * if an exception occurs retrieving the priority + * @see IThread#getPriority + */ + @Override + public int getPriority() throws DebugException { + // to get the priority, we must get the value from the "priority" field + Field p = null; + try { + p = fThread.referenceType().fieldByName("priority"); //$NON-NLS-1$ + if (p == null) { + requestFailed( + JDIDebugModelMessages.JDIThread_no_priority_field, null); + } + Value v = fThread.getValue(p); + if (v instanceof IntegerValue) { + return ((IntegerValue) v).value(); + } + requestFailed( + JDIDebugModelMessages.JDIThread_priority_not_an_integer, + null); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_thread_priority, + e.toString()), e); + } + // execution will not fall through to this line, as + // #targetRequestFailed or #requestFailed will throw + // an exception + return -1; + } + + @Override + public synchronized IStackFrame getTopStackFrame() throws DebugException { + List c = computeStackFrames(); + if (c.isEmpty()) { + return null; + } + return c.get(0); + } + + /** + * A breakpoint has suspended execution of this thread. Aborts any step + * currently in process and notifies listeners of the breakpoint to allow a + * vote to determine if the thread should suspend. + * + * @param breakpoint + * the breakpoint that caused the suspend + * @param suspendVote + * current vote before listeners are notified (for example, if a + * step request happens at the same location as a breakpoint, the + * step may have voted to suspend already - this allows a + * conditional breakpoint to avoid evaluation) + * @return whether this thread suspended + */ + public boolean handleSuspendForBreakpoint(JavaBreakpoint breakpoint, + boolean suspendVote) { + fHandlingSuspendForBreakpoint.set(true); + try { + return handleSuspendForBreakpointInternal(breakpoint); + } finally { + fHandlingSuspendForBreakpoint.set(false); + } + } + + private boolean handleSuspendForBreakpointInternal(JavaBreakpoint breakpoint) { + int policy = IJavaBreakpoint.SUSPEND_THREAD; + synchronized (this) { + if (fClientSuspendRequest) { + // a request to suspend has overridden the breakpoint request - + // suspend and + // ignore the breakpoint + return true; + } + fSuspendVoteInProgress = true; + addCurrentBreakpoint(breakpoint); + try { + policy = breakpoint.getSuspendPolicy(); + } catch (CoreException e) { + logError(e); + setRunning(true); + return false; + } + + // update state to suspended but don't actually + // suspend unless a registered listener agrees + if (policy == IJavaBreakpoint.SUSPEND_VM) { + ((JDIDebugTarget) getDebugTarget()) + .prepareToSuspendByBreakpoint(breakpoint); + suspendedByVM(); + } else { + setRunning(false); + } + } + + try { + if (!(breakpoint.isTriggerPoint())) { + if (DebugPlugin.getDefault().getBreakpointManager().hasActiveTriggerPoints()){ + fSuspendVoteInProgress = false; + return false; + } + + } + } + catch (CoreException e) { + e.printStackTrace(); + } + // Evaluate breakpoint condition (if any). The condition is evaluated + // regardless of the current suspend vote status, since breakpoint + // listeners + // should only be notified when a condition is true (i.e. when the + // breakpoint + // is really hit). + if (breakpoint instanceof JavaLineBreakpoint) { + JavaLineBreakpoint lbp = (JavaLineBreakpoint) breakpoint; + // evaluate condition unless we're in an evaluation already (bug + // 284022) + if (lbp.hasCondition() && !isPerformingEvaluation()) { + ConditionalBreakpointHandler handler = new ConditionalBreakpointHandler(); + int vote = handler.breakpointHit(this, breakpoint); + if (vote == IJavaBreakpointListener.DONT_SUSPEND) { + // condition is false, breakpoint is not hit + synchronized (this) { + fSuspendVoteInProgress = false; + return false; + } + } + if (handler.hasErrors()) { + // there were errors, suspend and do not notify listeners of + // hit since + // they were already notified of compilation/runtime errors + synchronized (this) { + fSuspendVoteInProgress = false; + return true; + } + } + DebugPlugin.getDefault().getBreakpointManager().enableTriggerPoints(null, false); + // make a note that we auto-disabled the trigger point for this breakpoint. + // we re enable it at cleanup of JDITarget + } + } + + // poll listeners without holding lock on thread + boolean suspend = true; + try { + suspend = JDIDebugPlugin.getDefault().fireBreakpointHit(this, + breakpoint); + } finally { + synchronized (this) { + fSuspendVoteInProgress = false; + if (fClientSuspendRequest) { + // if a client has requested a suspend, then override the + // vote to suspend + suspend = true; + } + } + } + return suspend; + } + + /** + * To be called whenever a Java exception breakpoint is called. This thread will remember the Java exception instance associated with this event + * and will answer if suspending should be skipped as per the breakpoint's {@link IJavaExceptionBreakpoint.SuspendOnRecurrenceStrategy suspend on + * recurrence} strategy. + * + * @param breakpoint + * the breakpoint about to trigger + * @return either {@code null} to signal that this breakpoint hit is not a recurrence, or one of + * {@link SuspendOnRecurrenceStrategy#RECURRENCE_UNCONFIGURED}, {@link SuspendOnRecurrenceStrategy#SKIP_RECURRENCES}, or + * {@link SuspendOnRecurrenceStrategy#SUSPEND_ALWAYS}. + */ + public SuspendOnRecurrenceStrategy shouldSkipExceptionRecurrence(IJavaExceptionBreakpoint breakpoint) { + if (breakpoint instanceof JavaExceptionBreakpoint) { + JavaExceptionBreakpoint exceptionBreakpoint = (JavaExceptionBreakpoint) breakpoint; + try { + IJavaObject lastException = exceptionBreakpoint.getLastException(); + IJavaObject previousException = fPreviousException; + if (previousException != null && previousException.equals(lastException)) { + return exceptionBreakpoint.getSuspendOnRecurrenceStrategy(); + } + fPreviousException = lastException; + } catch (CoreException e) { + // ignore + } + } + return null; // skipping not applicable, since this is no recurrence + } + + /** + * Called after an event set with a breakpoint is done being processed. + * Updates thread state based on the result of handling the event set. + * Aborts any step in progress and fires a suspend event is suspending. + * + * @param breakpoint + * the breakpoint that was hit + * @param suspend + * whether to suspend + * @param queue + * whether to queue events or fire immediately + * @param set + * event set handling is associated with + */ + public void completeBreakpointHandling(JavaBreakpoint breakpoint, + boolean suspend, boolean queue, EventSet set) { + fCompletingBreakpointHandling.set(true); + try { + completeBreakpointHandlingInternal(breakpoint, suspend, queue, set); + } finally { + fCompletingBreakpointHandling.set(false); + } + } + + private void completeBreakpointHandlingInternal(JavaBreakpoint breakpoint, boolean suspend, boolean queue, EventSet set) { + synchronized (this) { + try { + int policy = breakpoint.getSuspendPolicy(); + // suspend or resume + if (suspend) { + if (policy == IJavaBreakpoint.SUSPEND_VM) { + ((JDIDebugTarget) getDebugTarget()) + .suspendedByBreakpoint(breakpoint, false, set); + } + abortStep(); + if (queue) { + queueSuspendEvent(DebugEvent.BREAKPOINT, set); + } else { + fireSuspendEvent(DebugEvent.BREAKPOINT); + } + } else { + if (policy == IJavaBreakpoint.SUSPEND_VM) { + ((JDIDebugTarget) getDebugTarget()) + .cancelSuspendByBreakpoint(breakpoint); + resumedByVM(); + } else { + setRunning(true); + // dispose cached stack frames so we re-retrieve on the + // next breakpoint + preserveStackFrames(); + } + } + } catch (CoreException e) { + logError(e); + setRunning(true); + } + } + } + + @Override + public boolean isStepping() { + return getPendingStepHandler() != null; + } + + @Override + public boolean isSuspended() { + return !fRunning && !fTerminated; + } + + @Override + public boolean isSystemThread() { + return fIsSystemThread; + } + + @Override + public boolean isDaemon() throws DebugException { + return fIsDaemon; + } + + @Override + public String getThreadGroupName() throws DebugException { + if (fThreadGroupName == null) { + ThreadGroupReference tgr = getUnderlyingThreadGroup(); + + // bug# 20370 + if (tgr == null) { + return null; + } + + try { + fThreadGroupName = tgr.name(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_thread_group_name, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + return fThreadGroupName; + } + + @Override + public boolean isTerminated() { + return fTerminated; + } + + @Override + public synchronized boolean isOutOfSynch() throws DebugException { + if (isSuspended() && ((JDIDebugTarget) getDebugTarget()).hasHCRFailed()) { + List frames = computeStackFrames(); + for(IJavaStackFrame frame : frames) { + if(((JDIStackFrame)frame).isOutOfSynch()) { + return true; + } + } + return false; + } + // If the thread is not suspended, there's no way to + // say for certain that it is running out of synch code + return false; + } + + @Override + public boolean mayBeOutOfSynch() { + if (!isSuspended()) { + return ((JDIDebugTarget) getDebugTarget()).hasHCRFailed(); + } + return false; + } + + /** + * Sets whether this thread is terminated + * + * @param terminated + * whether this thread is terminated + */ + protected void setTerminated(boolean terminated) { + fTerminated = terminated; + } + + @Override + public synchronized void resume() throws DebugException { + if (!isSuspended() && getDebugTarget().isSuspended()) { + getDebugTarget().resume(); + } else { + fClientSuspendRequest = false; + resumeThread(true); + } + } + + /** + * + * Updates the state of this thread, but only fires notification to + * listeners if fireNotification is true. + * + * @see ISuspendResume#resume() + * @param fireNotification + * if a resume event should be fired + * @throws DebugException + * if an exception occurs trying to resume the thread + */ + private synchronized void resumeThread(boolean fireNotification) + throws DebugException { + if (!isSuspended() || (isPerformingEvaluation() && !isInvokingMethod())) { + return; + } + try { + setRunning(true); + clearMethodResult(); + if (fireNotification) { + fireResumeEvent(DebugEvent.CLIENT_REQUEST); + } + preserveStackFrames(); + fThread.resume(); + } catch (VMDisconnectedException e) { + disconnected(); + } catch (RuntimeException e) { + setRunning(false); + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_resuming, + e.toString()), e); + } + } + + /** + * Sets whether this thread is currently executing. When set to + * true, this thread's current breakpoints are cleared. + * + * @param running + * whether this thread is executing + */ + protected void setRunning(boolean running) { + fRunning = running; + if (running) { + synchronized (breakpointAcessLock) { + fCurrentBreakpoints.clear(); + } + } + } + + private void clearMethodResult() { + setMethodResult(null); + } + + /** + * Preserves stack frames to be used on the next suspend event. Iterates + * through all current stack frames, setting their state as invalid. This + * method should be called before this thread is resumed, when stack frames + * are to be re-used when it later suspends. + * + * @see #computeStackFrames() + */ + protected synchronized void preserveStackFrames() { + fRefreshChildren = true; + for(IJavaStackFrame frame : fStackFrames) { + ((JDIStackFrame)frame).setUnderlyingStackFrame(null); + } + } + + /** + * Disposes stack frames, to be completely re-computed on the next suspend + * event. This method should be called before this thread is resumed when + * stack frames are not to be re-used on the next suspend. + * + * @see #computeStackFrames() + */ + protected synchronized void disposeStackFrames() { + fStackFrames.clear(); + fRefreshChildren = true; + } + + /** + * This method is synchronized, such that the step request begins before a + * background evaluation can be performed. + * + * @see IStep#stepInto() + */ + @Override + public void stepInto() throws DebugException { + synchronized (this) { + if (!canStepInto()) { + return; + } + } + StepHandler handler = createStepIntoHandler(); + handler.step(); + } + + /** + * This method is synchronized, such that the step request begins before a + * background evaluation can be performed. + * + * @see IStep#stepOver() + */ + @Override + public void stepOver() throws DebugException { + synchronized (this) { + if (!canStepOver()) { + return; + } + } + StepHandler handler = createStepOverHandler(); + handler.step(); + } + + /** + * This method is synchronized, such that the step request begins before a + * background evaluation can be performed. + * + * @see IStep#stepReturn() + */ + @Override + public void stepReturn() throws DebugException { + synchronized (this) { + if (!canStepReturn()) { + return; + } + } + StepHandler handler = createStepReturnHandler(); + handler.step(); + } + + protected void setOriginalStepKind(int stepKind) { + fOriginalStepKind = stepKind; + } + + protected int getOriginalStepKind() { + return fOriginalStepKind; + } + + protected void setOriginalStepLocation(Location location) { + fOriginalStepLocation = location; + } + + protected Location getOriginalStepLocation() { + return fOriginalStepLocation; + } + + protected void setOriginalStepStackDepth(int depth) { + fOriginalStepStackDepth = depth; + } + + protected int getOriginalStepStackDepth() { + return fOriginalStepStackDepth; + } + + /** + * In cases where a user-requested step into encounters nothing but filtered + * code (static initializers, synthetic methods, etc.), the default JDI + * behavior is to put the instruction pointer back where it was before the + * step into. This requires a second step to move forward. Since this is + * confusing to the user, we do an extra step into in such situations. This + * method determines when such an extra step into is necessary. It compares + * the current Location to the original Location when the user step into was + * initiated. It also makes sure the stack depth now is the same as when the + * step was initiated. + * + * @param location + * the location to consider + * @return true if we should do an extra step, + * false otherwise + * @throws DebugException + * if an exception occurs + */ + protected boolean shouldDoExtraStepInto(Location location) + throws DebugException { + if (getOriginalStepKind() != StepRequest.STEP_INTO) { + return false; + } + if (getOriginalStepStackDepth() != getUnderlyingFrameCount()) { + return false; + } + Location origLocation = getOriginalStepLocation(); + if (origLocation == null) { + return false; + } + // We cannot simply check if the two Locations are equal using the + // equals() + // method, since this checks the code index within the method. Even if + // the + // code indices are different, the line numbers may be the same, in + // which case + // we need to do the extra step into. + Method origMethod = origLocation.method(); + Method currMethod = location.method(); + if (!origMethod.equals(currMethod)) { + return false; + } + if (origLocation.lineNumber() != location.lineNumber()) { + return false; + } + return true; + } + + /** + * Determines if a user did a step into and stepped through filtered code. + * In this case, do a step return if the user has requested not to step thru + * to an unfiltered location. + * + * @return true if we should do a step return + * @throws DebugException + * if an exception occurs + */ + protected boolean shouldDoStepReturn() throws DebugException { + if (getOriginalStepKind() == StepRequest.STEP_INTO) { + if ((getOriginalStepStackDepth() + 1) < getUnderlyingFrameCount()) { + return true; + } + } + return false; + } + + @Override + public void suspend() throws DebugException { + // prepare for the suspend request + prepareForClientSuspend(); + + synchronized (this) { + try { + // Abort any pending step request + abortStep(); + suspendUnderlyingThread(); + } catch (RuntimeException e) { + fClientSuspendRequest = false; + setRunning(true); + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_suspending, + e.toString()), e); + } + } + } + + /** + * Prepares to suspend this thread as requested by a client. Terminates any + * current evaluation (to stop after next instruction). Waits for any method + * invocations to complete. + * + * @throws DebugException + * if thread does not suspend before timeout + */ + protected void prepareForClientSuspend() throws DebugException { + // note that a suspend request has started + synchronized (this) { + // this will abort notification to pending breakpoint listeners + fClientSuspendRequest = true; + } + + synchronized (fEvaluationLock) { + // terminate active evaluation, if any + if (fEvaluationRunnable != null) { + if (canTerminateEvaluation()) { + fEvaluationInterrupted = true; + ((ITerminate) fEvaluationRunnable).terminate(); + } + // wait for termination to complete + int timeout = Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_REQUEST_TIMEOUT, + JDIDebugModel.DEF_REQUEST_TIMEOUT, + null); + try { + fEvaluationLock.wait(timeout); + } catch (InterruptedException e) { + } + if (fEvaluationRunnable != null) { + fClientSuspendRequest = false; + targetRequestFailed(JDIDebugModelMessages.JDIThread_1, null); + } + } + } + + // first wait for any method invocation in progress to complete its + // method invocation + synchronized (fInvocationLock) { + if (isInvokingMethod()) { + int timeout = Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_REQUEST_TIMEOUT, + JDIDebugModel.DEF_REQUEST_TIMEOUT, + null); + try { + fInvocationLock.wait(timeout); + } catch (InterruptedException e) { + } + if (isInvokingMethod()) { + // timeout waiting for invocation to complete, abort + fClientSuspendRequest = false; + targetRequestFailed(JDIDebugModelMessages.JDIThread_1, null); + } + } + } + } + + /** + * Suspends the underlying thread asynchronously and fires notification when + * the underlying thread is suspended. + */ + protected synchronized void suspendUnderlyingThread() { + if (fIsSuspending) { + return; + } + if (isSuspended()) { + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + return; + } + fIsSuspending = true; + Thread thread = new Thread(() -> { + try { + fThread.suspend(); + int timeout = Platform.getPreferencesService().getInt( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugModel.PREF_REQUEST_TIMEOUT, + JDIDebugModel.DEF_REQUEST_TIMEOUT, + null); + long stop = System.currentTimeMillis() + timeout; + boolean suspended = isUnderlyingThreadSuspended(); + while (System.currentTimeMillis() < stop && !suspended) { + try { + Thread.sleep(50); + } catch (InterruptedException e1) { + } + suspended = isUnderlyingThreadSuspended(); + if (suspended) { + break; + } + } + if (!suspended) { + IStatus status = new Status( + IStatus.ERROR, + JDIDebugPlugin.getUniqueIdentifier(), + SUSPEND_TIMEOUT, + MessageFormat.format(JDIDebugModelMessages.JDIThread_suspend_timeout, timeout), + null); + IStatusHandler handler = DebugPlugin.getDefault() + .getStatusHandler(status); + if (handler != null) { + try { + handler.handleStatus(status, JDIThread.this); + } catch (CoreException e2) { + } + } + } + setRunning(false); + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + } catch (RuntimeException exception) { + } finally { + fIsSuspending = false; + } + }); + thread.setDaemon(true); + thread.start(); + } + + public boolean isUnderlyingThreadSuspended() { + return fThread.isSuspended(); + } + + /** + * Notifies this thread that it has been suspended due to a VM suspend. + */ + protected synchronized void suspendedByVM() { + setRunning(false); + } + + /** + * Notifies this thread that is about to be resumed due to a VM resume. + * + * @throws DebugException + * if an exception occurs + */ + protected synchronized void resumedByVM() throws DebugException { + fClientSuspendRequest = false; + setRunning(true); + clearMethodResult(); + preserveStackFrames(); + // This method is called *before* the VM is actually resumed. + // To ensure that all threads will fully resume when the VM + // is resumed, make sure the suspend count of each thread + // is no greater than 1. @see Bugs 23328 and 27622 + ThreadReference thread = fThread; + try { + while (thread.suspendCount() > 1) { + thread.resume(); + } + } catch (ObjectCollectedException e) { + } catch (VMDisconnectedException e) { + disconnected(); + } catch (RuntimeException e) { + setRunning(false); + fireSuspendEvent(DebugEvent.CLIENT_REQUEST); + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_resuming, + e.toString()), e); // + } + } + + @Override + public void terminate() throws DebugException { + terminateEvaluation(); + getDebugTarget().terminate(); + } + + /** + * Drops to the given stack frame + * + * @param frame + * the stack frame to try dropping to + * + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void dropToFrame(IStackFrame frame) throws DebugException { + JDIDebugTarget target = (JDIDebugTarget) getDebugTarget(); + if (target.canPopFrames()) { + // JDK 1.4 support + try { + // Pop the drop frame and all frames above it + popFrame(frame); + stepInto(); + } catch (RuntimeException exception) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_dropping_to_frame, + exception.toString()), + exception); + } + } else { + // J9 support + // This block is synchronized, such that the step request + // begins before a background evaluation can be performed. + synchronized (this) { + StepHandler handler = createDropToFrameHandler(frame); + handler.step(); + } + } + } + + protected void popFrame(IStackFrame frame) throws DebugException { + JDIDebugTarget target = (JDIDebugTarget) getDebugTarget(); + if (target.canPopFrames()) { + // JDK 1.4 support + try { + // Pop the frame and all frames above it + StackFrame jdiFrame = null; + int desiredSize = fStackFrames.size() + - fStackFrames.indexOf(frame) - 1; + int lastSize = fStackFrames.size() + 1; // Set up to pass the + // first test + int size = fStackFrames.size(); + while (size < lastSize && size > desiredSize) { + // Keep popping frames until the stack stops getting smaller + // or popFrame is gone. + // see Bug 8054 + jdiFrame = ((JDIStackFrame) frame) + .getUnderlyingStackFrame(); + preserveStackFrames(); + fThread.popFrames(jdiFrame); + lastSize = size; + size = computeStackFrames().size(); + } + } catch (IncompatibleThreadStateException exception) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_popping, + exception.toString()), exception); + } catch (InvalidStackFrameException exception) { + // InvalidStackFrameException can be thrown when all but the + // deepest frame were popped. Fire a changed notification + // in case this has occurred. + fireChangeEvent(DebugEvent.CONTENT); + targetRequestFailed(exception.toString(), exception); + } catch (RuntimeException exception) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_popping, + exception.toString()), exception); + } + } + } + + /** + * Steps until the specified stack frame is the top frame. Provides ability + * to step over/return in the non-top stack frame. This method is + * synchronized, such that the step request begins before a background + * evaluation can be performed. + * + * @param frame + * the stack frame to try and step to + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void stepToFrame(IStackFrame frame) throws DebugException { + synchronized (this) { + if (!canStepReturn()) { + return; + } + } + StepHandler handler = createStepToFrameHandler(frame); + handler.step(); + } + + /** + * Aborts the current step, if any. + */ + protected void abortStep() { + StepHandler handler = getPendingStepHandler(); + if (handler != null) { + handler.abort(); + } + } + + @Override + public IJavaVariable findVariable(String varName) throws DebugException { + if (isSuspended()) { + try { + IStackFrame[] stackFrames = getStackFrames(); + for (IStackFrame stackFrame : stackFrames) { + IJavaStackFrame sf = (IJavaStackFrame) stackFrame; + IJavaVariable var = sf.findVariable(varName); + if (var != null) { + return var; + } + } + } catch (DebugException e) { + // if the thread has since resumed, return null (no need to + // report error) + if (e.getStatus().getCode() != IJavaThread.ERR_THREAD_NOT_SUSPENDED) { + throw e; + } + } + } + return null; + } + + /** + * Notification this thread has terminated - update state and fire a + * terminate event. + */ + protected void terminated() { + setTerminated(true); + setRunning(false); + fireTerminateEvent(); + } + + /** + * Returns this thread on the underlying VM which this model thread is a + * proxy to. + * + * @return underlying thread + */ + public ThreadReference getUnderlyingThread() { + return fThread; + } + + /** + * Sets the underlying thread that this model object is a proxy to. + * + * @param thread + * underlying thread on target VM + */ + protected void setUnderlyingThread(ThreadReference thread) { + fThread = thread; + } + + /** + * Returns this thread's underlying thread group. + * + * @return thread group + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      • Retrieving the underlying thread group is not + * supported on the underlying VM
                      • + *
                      + */ + protected ThreadGroupReference getUnderlyingThreadGroup() + throws DebugException { + if (fThreadGroup == null) { + try { + fThreadGroup = fThread.threadGroup(); + } catch (UnsupportedOperationException e) { + requestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_thread_group, + e.toString()), e); + // execution will not reach this line, as + // #requestFailed will throw an exception + return null; + } catch (VMDisconnectedException e) { + // ignore disconnect + return null; + } catch (ObjectCollectedException e) { + // ignore object collected + return null; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_retrieving_thread_group, + e.toString()), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + return fThreadGroup; + } + + @Override + public boolean isPerformingEvaluation() { + return fEvaluationRunnable != null; + } + + /** + * Returns whether this thread is currently performing a method invocation + * + * @return if the thread is currently invoking a method + */ + public boolean isInvokingMethod() { + return fIsInvokingMethod; + } + + /** + * Returns whether this thread is currently ignoring breakpoints. + * + * @return if the thread is currently ignoring breakpoints + */ + public boolean isIgnoringBreakpoints() { + return !fHonorBreakpoints || fSuspendVoteInProgress + || hasClientRequestedSuspend(); + } + + /** + * Returns whether a client has requested the target/thread to suspend. + * + * @return whether a client has requested the target/thread to suspend + */ + public boolean hasClientRequestedSuspend() { + return fClientSuspendRequest; + } + + /** + * Sets whether this thread is currently invoking a method. Notifies any + * threads waiting for the method invocation lock + * + * @param invoking + * whether this thread is currently invoking a method + */ + protected void setInvokingMethod(boolean invoking) { + synchronized (fInvocationLock) { + fIsInvokingMethod = invoking; + if (!invoking) { + fInvocationLock.notifyAll(); + } + } + } + + /** + * Sets the step handler currently handling a step request. + * + * @param handler + * the current step handler, or null if none + */ + protected void setPendingStepHandler(StepHandler handler) { + fStepHandler = handler; + } + + /** + * Returns the step handler currently handling a step request, or + * null if none. + * + * @return step handler, or null if none + */ + protected StepHandler getPendingStepHandler() { + return fStepHandler; + } + + /** + * Helper class to perform stepping an a thread. + */ + abstract class StepHandler implements IJDIEventListener { + /** + * Request for stepping in the underlying VM + */ + private StepRequest fStepRequest; + + /** + * Initiates a step in the underlying VM by creating a step request of + * the appropriate kind (over, into, return), and resuming this thread. + * When a step is initiated it is registered with its thread as a + * pending step. A pending step could be cancelled if a breakpoint + * suspends execution during the step. + *

                      + * This thread's state is set to running and stepping, and stack frames + * are invalidated (but preserved to be re-used when the step + * completes). A resume event with a step detail is fired for this + * thread. + *

                      + * Note this method does nothing if this thread has no stack frames. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void step() throws DebugException { + ISchedulingRule rule = getThreadRule(); + try { + Job.getJobManager().beginRule(rule, null); + JDIStackFrame top = (JDIStackFrame) getTopStackFrame(); + if (top == null) { + return; + } + setOriginalStepKind(getStepKind()); + StackFrame frame = top.getUnderlyingStackFrame(); + if (frame == null) { + return; + } + Location location = frame.location(); + setOriginalStepLocation(location); + setOriginalStepStackDepth(computeStackFrames().size()); + setStepRequest(createStepRequest()); + setPendingStepHandler(this); + addJDIEventListener(this, getStepRequest()); + setRunning(true); + clearMethodResult(); + preserveStackFrames(); + fireResumeEvent(getStepDetail()); + invokeThread(); + } finally { + Job.getJobManager().endRule(rule); + } + } + + /** + * Resumes the underlying thread to initiate the step. By default the + * thread is resumed. Step handlers that require other actions can + * override this method. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void invokeThread() throws DebugException { + try { + synchronized (JDIThread.this) { + fClientSuspendRequest = false; + } + fThread.resume(); + } catch (RuntimeException e) { + stepEnd(null); + fireSuspendEvent(DebugEvent.STEP_END); + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_stepping, + e.toString()), e); + } + } + + /** + * Creates and returns a step request specific to this step handler. + * Subclasses must override getStepKind() to return the + * kind of step it implements. + * + * @return step request + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected StepRequest createStepRequest() throws DebugException { + return createStepRequest(getStepKind()); + } + + /** + * Creates and returns a step request of the specified kind. + * + * @param kind + * of StepRequest.STEP_INTO, + * StepRequest.STEP_OVER, + * StepRequest.STEP_OUT + * @return step request + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected StepRequest createStepRequest(int kind) throws DebugException { + EventRequestManager manager = getEventRequestManager(); + if (manager == null) { + requestFailed( + JDIDebugModelMessages.JDIThread_Unable_to_create_step_request___VM_disconnected__1, + new VMDisconnectedException()); + } + try { + StepRequest request = manager.createStepRequest(fThread, + StepRequest.STEP_LINE, kind); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.addCountFilter(1); + attachFiltersToStepRequest(request); + request.enable(); + + if (manager.virtualMachine().canGetMethodReturnValues() && showStepResultIsEnabled(getDebugTarget())) { + if (fCurrentMethodExitRequest != null) { + removeJDIEventListener(this, fCurrentMethodExitRequest); + manager.deleteEventRequest(fCurrentMethodExitRequest); + fCurrentMethodExitRequest = null; + Thread t = fCurrentMethodExitRequestDisabler; + if (t != null) { + t.interrupt(); + fCurrentMethodExitRequestDisabler = null; + } + } + if (fCurrentExceptionRequest != null) { + removeJDIEventListener(this, fCurrentExceptionRequest); + manager.deleteEventRequest(fCurrentExceptionRequest); + fCurrentExceptionRequest = null; + } + if (fCurrentMethodEntryRequest != null) { + removeJDIEventListener(this, fCurrentMethodEntryRequest); + manager.deleteEventRequest(fCurrentMethodEntryRequest); + fCurrentMethodEntryRequest = null; + } + fStepResultCandidate = null; + fStepResultTimeoutTriggered.set(false); + List frames = computeStackFrames(); + int frameCount = 0; + StackFrame currentFrame = null; + if (!frames.isEmpty()) { + frameCount = frames.size(); + currentFrame = ((JDIStackFrame) frames.get(0)).getUnderlyingStackFrame(); + } else { + // can happen, e.g. when step filters are active. + if (fThread.isSuspended()) { + try { + // try to get the required info from the underlying object. + frameCount = fThread.frameCount(); + currentFrame = fThread.frame(0); + } + catch (IncompatibleThreadStateException e) { + // cannot not happen because of the enclosing isSuspended() check. + logError(e); + } + } + } + if (currentFrame != null) { + MethodExitRequest methodExitRequest = manager.createMethodExitRequest(); + methodExitRequest.addThreadFilter(fThread); + methodExitRequest.addClassFilter(currentFrame.location().declaringType()); + + if (manager.virtualMachine().canUseInstanceFilters()) { + ObjectReference thisObject = null; + try { + thisObject = currentFrame.thisObject(); + } catch (Exception e) { + // ignore errors here, continue without filtering + } + if (thisObject != null) { + methodExitRequest.addInstanceFilter(thisObject); + } + } + methodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + methodExitRequest.enable(); + fCurrentMethodExitRequest = methodExitRequest; + Method method = currentFrame.location().method(); + + fStepResultMethod = method; + fStepReturnTargetFrameCount = frameCount - 1; // depth of the frame that is returned to + addJDIEventListener(this, methodExitRequest); + + ExceptionRequest exceptionRequest = manager.createExceptionRequest(null, true, false); + exceptionRequest.addThreadFilter(fThread); + exceptionRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + exceptionRequest.enable(); + fCurrentExceptionRequest = exceptionRequest; + addJDIEventListener(this, exceptionRequest); + + if (kind == StepRequest.STEP_OVER) { + MethodEntryRequest methodEntryRequest = manager.createMethodEntryRequest(); + methodEntryRequest.addThreadFilter(fThread); + methodEntryRequest.enable(); + methodEntryRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + fCurrentMethodEntryRequest = methodEntryRequest; + fStepOverLocation = currentFrame.location(); + fStepOverFrameCount = frameCount; // depth of the frame where the step-over is being done + addJDIEventListener(this, methodEntryRequest); + } + + int timeout = getStepResultTimeout(); + if (timeout != 0) { + Runnable r = () -> { + try { + if (timeout > 0) { + Thread.sleep(timeout); + } + } catch (InterruptedException e) { + return; + } + fStepResultTimeoutTriggered.set(true); + if (fCurrentMethodExitRequest == methodExitRequest) { + try { + methodExitRequest.disable(); + if (fCurrentExceptionRequest == exceptionRequest) { + exceptionRequest.disable(); + } + } catch (Exception e) { + // ignore + } + } + }; + if (timeout > 0) { + Thread t = new Thread(r, "JDIThread: MethodExitDisabler"); //$NON-NLS-1$ + t.setDaemon(true); + t.start(); + fCurrentMethodExitRequestDisabler = t; + } else { + // negative timeout: simulate immediate timeout (for testing) + r.run(); + } + } + } + } + return request; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_creating_step_request, + e.toString()), e); + } + // this line will never be executed, as the try block + // will either return, or the catch block will throw + // an exception + return null; + + } + + /** + * Returns the kind of step this handler implements. + * + * @return one of StepRequest.STEP_INTO, + * StepRequest.STEP_OVER, + * StepRequest.STEP_OUT + */ + protected abstract int getStepKind(); + + /** + * Returns the detail for this step event. + * + * @return one of DebugEvent.STEP_INTO, + * DebugEvent.STEP_OVER, + * DebugEvent.STEP_RETURN + */ + protected abstract int getStepDetail(); + + /** + * Sets the step request created by this handler in the underlying VM. + * Set to null when + * this handler deletes its request. + * + * @param request + * step request + */ + protected void setStepRequest(StepRequest request) { + fStepRequest = request; + } + + /** + * Returns the step request created by this handler in the underlying + * VM. + * + * @return step request + */ + protected StepRequest getStepRequest() { + return fStepRequest; + } + + /** + * Deletes this handler's step request from the underlying VM and + * removes this handler as an event listener. + */ + protected void deleteStepRequest() { + try { + if (fCurrentMethodExitRequest != null) { + removeJDIEventListener(this, fCurrentMethodExitRequest); + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + manager.deleteEventRequest(fCurrentMethodExitRequest); + } + fCurrentMethodExitRequest = null; + Thread t = fCurrentMethodExitRequestDisabler; + if (t != null) { + t.interrupt(); + fCurrentMethodExitRequestDisabler = null; + } + } + if (fCurrentExceptionRequest != null) { + removeJDIEventListener(this, fCurrentExceptionRequest); + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + manager.deleteEventRequest(fCurrentExceptionRequest); + } + fCurrentExceptionRequest = null; + } + if (fCurrentMethodEntryRequest != null) { + removeJDIEventListener(this, fCurrentMethodEntryRequest); + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + manager.deleteEventRequest(fCurrentMethodEntryRequest); + } + fCurrentMethodEntryRequest = null; + } + StepRequest req = getStepRequest(); + if (req != null) { + removeJDIEventListener(this, req); + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + manager.deleteEventRequest(req); + } + } + } catch (RuntimeException e) { + logError(e); + } finally { + setStepRequest(null); + } + } + + /** + * If step filters are currently switched on and the current location is + * not a filtered location, set all active filters on the step request. + * + * @param request + * the request to augment + */ + protected void attachFiltersToStepRequest(StepRequest request) { + + if (applyStepFilters() && isStepFiltersEnabled()) { + Location currentLocation = getOriginalStepLocation(); + if (!isSupported(currentLocation)) { + return; + } + // Removed the fix for bug 5587, to address bug 41510 + // //check if the user has already stopped in a filtered + // location + // //is so do not filter @see bug 5587 + // ReferenceType type= currentLocation.declaringType(); + // String typeName= type.name(); + String[] activeFilters = getJavaDebugTarget().getStepFilters(); + // for (int i = 0; i < activeFilters.length; i++) { + // StringMatcher matcher = new StringMatcher(activeFilters[i], + // false, false); + // if (matcher.match(typeName)) { + // return; + // } + // } + if (activeFilters != null) { + for (String activeFilter : activeFilters) { + request.addClassExclusionFilter(activeFilter); + } + } + } + } + + /** + * Returns whether this step handler should use step filters when + * creating its step request. By default, step filters can be used by + * any step request. Subclasses must override if/when required. + * + * @return whether this step handler should use step filters when + * creating its step request + */ + protected boolean applyStepFilters() { + return true; + } + + /** + * Notification the step request has completed. If the current location + * matches one of the user-specified step filter criteria (e.g., + * synthetic methods, static initializers), then continue stepping. + * + * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget, boolean, + * EventSet) + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet) { + try { + if (event instanceof MethodExitEvent) { + Method stepResultMethod = fStepResultMethod; + if (stepResultMethod != null) { + MethodExitEvent methodExitEvent = (MethodExitEvent) event; + if (methodExitEvent.location().method().equals(stepResultMethod)) { + fStepResultCandidate = new MethodResult(stepResultMethod, fStepReturnTargetFrameCount, methodExitEvent.returnValue(), ResultType.returned); + } + } + return true; + } + if (event instanceof ExceptionEvent) { + ExceptionEvent exceptionEvent = (ExceptionEvent) event; + Method stepResultMethod = fStepResultMethod; + if (stepResultMethod != null) { // should always be true unless some third-party plugins manipulate internal state + fStepResultCandidate = new MethodResult(stepResultMethod, fStepReturnTargetFrameCount, exceptionEvent.exception(), ResultType.threw); + } + return true; + } + if (event instanceof MethodEntryEvent) { + removeJDIEventListener(this, fCurrentMethodEntryRequest); + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + manager.deleteEventRequest(fCurrentMethodEntryRequest); + } + fCurrentMethodEntryRequest = null; + deleteStepRequest(); + createSecondaryStepRequest(StepRequest.STEP_OUT); + return true; + } + StepEvent stepEvent = (StepEvent) event; + Location currentLocation = stepEvent.location(); + + if (fStepResultTimeoutTriggered.get()) { + Method m = fStepResultMethod; + if (m != null) { + setMethodResult(new MethodResult(m, -1, null, ResultType.step_timeout)); + } + fStepResultMethod = null; + fStepReturnTargetFrameCount = -1; + fStepResultCandidate = null; + fStepResultTimeoutTriggered.set(false); + } else if (fStepResultCandidate != null) { + setMethodResult(fStepResultCandidate); + fStepResultMethod = null; + fStepReturnTargetFrameCount = -1; + fStepResultCandidate = null; + fStepResultTimeoutTriggered.set(false); + } + + Location stepOverLocation2 = fStepOverLocation; + if (getStepKind() == StepRequest.STEP_OVER) { + if (stepOverLocation2 != null && fStepOverFrameCount >= 0) { + int underlyingFrameCount = getUnderlyingFrameCount(); + if (underlyingFrameCount > fStepOverFrameCount) { + // sometimes a MethodEntryEvent does not stop the thread but is delivered with another one grouped + // in an event set. in this situation, multiple step-returns must be done. + deleteStepRequest(); + createSecondaryStepRequest(StepRequest.STEP_OUT); + return true; + } + if (underlyingFrameCount == fStepOverFrameCount && stepOverLocation2.method().equals(currentLocation.method())) { + int lineNumber = stepOverLocation2.lineNumber(); + if (lineNumber != -1 && lineNumber == currentLocation.lineNumber()) { + // line has not changed yet (probably returned from invocation with STEP_OUT) + deleteStepRequest(); + createSecondaryStepRequest(StepRequest.STEP_OVER); + return true; + } + } + fStepOverLocation = null; + fStepOverFrameCount = -1; + } + } + + if (!target.isStepThruFilters()) { + if (shouldDoStepReturn()) { + deleteStepRequest(); + createSecondaryStepRequest(StepRequest.STEP_OUT); + return true; + } + } + // if the ending step location is filtered and we did not start + // from + // a filtered location, or if we're back where + // we started on a step into, do another step of the same kind + if (locationShouldBeFiltered(currentLocation) + || shouldDoExtraStepInto(currentLocation) + || (getStepKind() == StepRequest.STEP_OVER && isSyntheticAndNotAvailable(currentLocation, stepOverLocation2))) { + setRunning(true); + deleteStepRequest(); + createSecondaryStepRequest(); + clearMethodResult(); + return true; + // otherwise, we're done stepping + } + stepEnd(eventSet); + return false; + } catch (DebugException e) { + logError(e); + stepEnd(eventSet); + return false; + } + } + + @Override + public void eventSetComplete(Event event, JDIDebugTarget target, + boolean suspend, EventSet eventSet) { + // do nothing + } + + /** + * Returns true if the StepEvent's Location is a Method + * that the user has indicated (via the step filter preferences) should + * be filtered and the step was not initiated from a filtered location. + * Returns false otherwise. + * + * @param location + * the location to check + * @return if the given {@link Location} should be filtered + * @throws DebugException + * if an exception occurs + */ + protected boolean locationShouldBeFiltered(Location location) + throws DebugException { + if (applyStepFilters()) { + Location origLocation = getOriginalStepLocation(); + if (origLocation != null) { + return !locationIsFiltered(origLocation.method(), true) && locationIsFiltered(location.method(), false); + } + } + return false; + } + + /** + * Returns true if the StepEvent's Location is a Method + * that the user has indicated (via the step filter preferences) should + * be filtered. Returns false otherwise. + * + * @param method + * the {@link Method} location to check + * @param orig + * true if the {@link Method} {@link Location} is the JDI Location + * from which an original user-requested step began, false otherwise + * @return true if the {@link Method} {@link Location} + * should be filtered, false otherwise + */ + protected boolean locationIsFiltered(Method method, boolean orig) { + if (isStepFiltersEnabled()) { + JDIDebugTarget target = getJavaDebugTarget(); + if ((target.isFilterStaticInitializers() && method.isStaticInitializer()) + || (target.isFilterSynthetics() && method.isSynthetic()) + || (target.isFilterConstructors() && method.isConstructor()) + || (target.isFilterGetters() && JDIMethod.isGetterMethod(method)) + || (target.isFilterSetters() && JDIMethod.isSetterMethod(method))) { + return true; + } + if(!orig) { + for (IStepFilter contributedFilter : DebugPlugin.getStepFilters(JDIDebugPlugin.getUniqueIdentifier())) { + if (contributedFilter.isFiltered(method)) { + return true; + } + } + } + } + return false; + } + + /** + * Cleans up when a step completes. + *
                        + *
                      • Thread state is set to suspended.
                      • + *
                      • Stepping state is set to false
                      • + *
                      • Stack frames and variables are incrementally updated
                      • + *
                      • The step request is deleted and removed as and event listener
                      • + *
                      • A suspend event is fired
                      • + *
                      + * + * @param set + * the remaining {@link EventSet} to queue + */ + protected void stepEnd(EventSet set) { + setRunning(false); + deleteStepRequest(); + setPendingStepHandler(null); + if (set != null) { + queueSuspendEvent(DebugEvent.STEP_END, set); + } + } + + /** + * Creates another step request in the underlying thread of the + * appropriate kind (over, into, return). This thread will be resumed by + * the event dispatcher as this event handler will vote to resume + * suspended threads. When a step is initiated it is registered with its + * thread as a pending step. A pending step could be cancelled if a + * breakpoint suspends execution during the step. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void createSecondaryStepRequest() throws DebugException { + createSecondaryStepRequest(getStepKind()); + } + + /** + * Creates another step request in the underlying thread of the + * specified kind (over, into, return). This thread will be resumed by + * the event dispatcher as this event handler will vote to resume + * suspended threads. When a step is initiated it is registered with its + * thread as a pending step. A pending step could be cancelled if a + * breakpoint suspends execution during the step. + * + * @param kind + * of StepRequest.STEP_INTO, + * StepRequest.STEP_OVER, + * StepRequest.STEP_OUT + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void createSecondaryStepRequest(int kind) + throws DebugException { + setStepRequest(createStepRequest(kind)); + setPendingStepHandler(this); + addJDIEventListener(this, getStepRequest()); + } + + /** + * Aborts this step request if active. The step event request is deleted + * from the underlying VM. + */ + protected void abort() { + if (getStepRequest() != null) { + deleteStepRequest(); + setPendingStepHandler(null); + fStepOverLocation = null; + fStepOverFrameCount = -1; + } + } + + private boolean isSyntheticAndNotAvailable(Location currentLocation, Location previousLocation) { + if (previousLocation != null) { + Method method = previousLocation.method(); + if (method != null && method.isSynthetic()) { + boolean isLambdaMethod = LambdaUtils.isLambdaMethod(method); + if (isLambdaMethod) { + int currentLineNumber = currentLocation.lineNumber(); + if (currentLineNumber == -1) { + return true; + } + } + } + } + return false; + } + } + + /** + * Handler for step over requests. + */ + class StepOverHandler extends StepHandler { + + @Override + protected int getStepKind() { + return StepRequest.STEP_OVER; + } + + @Override + protected int getStepDetail() { + return DebugEvent.STEP_OVER; + } + } + + /** + * Handler for step into requests. + */ + protected class StepIntoHandler extends StepHandler { + + @Override + protected int getStepKind() { + return StepRequest.STEP_INTO; + } + + @Override + protected int getStepDetail() { + return DebugEvent.STEP_INTO; + } + + } + + /** + * Handler for step return requests. + */ + protected class StepReturnHandler extends StepHandler { + + @Override + protected boolean locationShouldBeFiltered(Location location) + throws DebugException { + // if still at the same depth, do another step return (see bug + // 38744) + if (getOriginalStepStackDepth() == getUnderlyingFrameCount()) { + return true; + } + return super.locationShouldBeFiltered(location); + } + + @Override + protected int getStepKind() { + return StepRequest.STEP_OUT; + } + + @Override + protected int getStepDetail() { + return DebugEvent.STEP_RETURN; + } + } + + /** + * Handler for stepping to a specific stack frame (stepping in the non-top + * stack frame). Step returns are performed until a specified stack frame is + * reached or the thread is suspended (explicitly, or by a breakpoint). + */ + protected class StepToFrameHandler extends StepReturnHandler { + + /** + * The number of frames that should be left on the stack + */ + private int fRemainingFrames; + + /** + * Constructs a step handler to step until the specified stack frame is + * reached. + * + * @param frame + * the stack frame to step to + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected StepToFrameHandler(IStackFrame frame) throws DebugException { + List frames = computeStackFrames(); + setRemainingFrames(frames.size() - frames.indexOf(frame)); + } + + /** + * Sets the number of frames that should be remaining on the stack when + * done. + * + * @param num + * number of remaining frames + */ + protected void setRemainingFrames(int num) { + fRemainingFrames = num; + } + + /** + * Returns number of frames that should be remaining on the stack when + * done + * + * @return number of frames that should be left + */ + protected int getRemainingFrames() { + return fRemainingFrames; + } + + /** + * Notification the step request has completed. If in the desired frame, + * complete the step request normally. If not in the desired frame, + * another step request is created and this thread is resumed. + * + * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget, boolean, + * EventSet) + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet) { + try { + int numFrames = getUnderlyingFrameCount(); + // top of stack should not be null + if (numFrames <= getRemainingFrames()) { + stepEnd(eventSet); + return false; + } + // reset running state and keep going + setRunning(true); + deleteStepRequest(); + createSecondaryStepRequest(); + clearMethodResult(); + return true; + } catch (DebugException e) { + logError(e); + stepEnd(eventSet); + return false; + } + } + } + + /** + * Handles dropping to a specified frame. + */ + protected class DropToFrameHandler extends StepReturnHandler { + + /** + * The number of frames to drop off the stack. + */ + private int fFramesToDrop; + + /** + * Constructs a handler to drop to the specified stack frame. + * + * @param frame + * the stack frame to drop to + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected DropToFrameHandler(IStackFrame frame) throws DebugException { + List frames = computeStackFrames(); + setFramesToDrop(frames.indexOf(frame)); + } + + /** + * Sets the number of frames to pop off the stack. + * + * @param num + * number of frames to pop + */ + protected void setFramesToDrop(int num) { + fFramesToDrop = num; + } + + /** + * Returns the number of frames to pop off the stack. + * + * @return remaining number of frames to pop + */ + protected int getFramesToDrop() { + return fFramesToDrop; + } + + /** + * To drop a frame or re-enter, the underlying thread is instructed to + * do a return. When the frame count is less than zero, the step being + * performed is a "step return", so a regular invocation is performed. + * + * @throws DebugException + * if an exception occurs + */ + @Override + protected void invokeThread() throws DebugException { + if (getFramesToDrop() < 0) { + super.invokeThread(); + } else { + try { + org.eclipse.jdi.hcr.ThreadReference hcrThread = (org.eclipse.jdi.hcr.ThreadReference) fThread; + hcrThread.doReturn(null, true); + } catch (RuntimeException e) { + stepEnd(null); + fireSuspendEvent(DebugEvent.STEP_END); + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_while_popping_stack_frame, + e.toString()), e); + } + } + } + + /** + * Notification that the pop has completed. If there are more frames to + * pop, keep going, otherwise re-enter the top frame. Returns false, as + * this handler will resume this thread with a special invocation ( + * doReturn). + * + * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget, boolean, + * EventSet) + * @see #invokeThread() + */ + @Override + public boolean handleEvent(Event event, JDIDebugTarget target, + boolean suspendVote, EventSet eventSet) { + // pop is complete, update number of frames to drop + setFramesToDrop(getFramesToDrop() - 1); + try { + if (getFramesToDrop() >= -1) { + deleteStepRequest(); + doSecondaryStep(); + } else { + stepEnd(eventSet); + } + } catch (DebugException e) { + stepEnd(eventSet); + logError(e); + } + return false; + } + + /** + * Pops a secondary frame off the stack, does a re-enter, or a + * step-into. + * + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + protected void doSecondaryStep() throws DebugException { + setStepRequest(createStepRequest()); + setPendingStepHandler(this); + addJDIEventListener(this, getStepRequest()); + invokeThread(); + } + + /** + * Creates and returns a step request. If there are no more frames to + * drop, a re-enter request is made. If the re-enter is complete, a + * step-into request is created. + * + * @return step request + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + *
                      + */ + @Override + protected StepRequest createStepRequest() throws DebugException { + EventRequestManager manager = getEventRequestManager(); + if (manager == null) { + requestFailed( + JDIDebugModelMessages.JDIThread_Unable_to_create_step_request___VM_disconnected__2, + new VMDisconnectedException()); + } + int num = getFramesToDrop(); + if (num > 0) { + return super.createStepRequest(); + } else if (num == 0) { + try { + StepRequest request = ((org.eclipse.jdi.hcr.EventRequestManager) manager).createReenterStepRequest(fThread); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.addCountFilter(1); + request.enable(); + return request; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_creating_step_request, + e.toString()), e); + } + } else if (num == -1) { + try { + StepRequest request = manager.createStepRequest(fThread, StepRequest.STEP_LINE, StepRequest.STEP_INTO); + request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + request.addCountFilter(1); + request.enable(); + return request; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_creating_step_request, + e.toString()), e); + } + } + // this line will never be executed, as the try block + // will either return, or the catch block with throw + // an exception + return null; + } + } + + @Override + public boolean hasStackFrames() throws DebugException { + return isSuspended(); + } + + @Override + public T getAdapter(Class adapter) { + if (adapter == IJavaThread.class) { + return adapter.cast(this); + } + if (adapter == IJavaStackFrame.class) { + try { + return adapter.cast(getTopStackFrame()); + } catch (DebugException e) { + // do nothing if not able to get frame + } + } + return super.getAdapter(adapter); + } + + @Override + public boolean hasOwnedMonitors() throws DebugException { + return isSuspended() && getOwnedMonitors().length > 0; + } + + @Override + public IJavaObject[] getOwnedMonitors() throws DebugException { + try { + JDIDebugTarget target = (JDIDebugTarget) getDebugTarget(); + List ownedMonitors = fThread.ownedMonitors(); + IJavaObject[] javaOwnedMonitors = new IJavaObject[ownedMonitors + .size()]; + Iterator itr = ownedMonitors.iterator(); + int i = 0; + while (itr.hasNext()) { + ObjectReference element = itr.next(); + javaOwnedMonitors[i] = new JDIObjectValue(target, element); + i++; + } + return javaOwnedMonitors; + } catch (IncompatibleThreadStateException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_43, e); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_44, e); + } + return null; + } + + @Override + public IJavaObject getContendedMonitor() throws DebugException { + try { + ObjectReference monitor = fThread.currentContendedMonitor(); + if (monitor != null) { + return new JDIObjectValue((JDIDebugTarget) getDebugTarget(), + monitor); + } + } catch (IncompatibleThreadStateException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_45, e); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_46, e); + } + + return null; + } + + @Override + public boolean canStepWithFilters() { + if (canStepInto()) { + String[] filters = getJavaDebugTarget().getStepFilters(); + return filters != null && filters.length > 0; + } + return false; + } + + @Override + public void stepWithFilters() throws DebugException { + if (!canStepWithFilters()) { + return; + } + stepInto(); + } + + /** + * Class which managed the queue of runnable associated with this thread. + */ + class ThreadJob extends Job { + + private final Vector fRunnables; + + public ThreadJob() { + super(JDIDebugModelMessages.JDIThread_39); + fRunnables = new Vector<>(5); + setSystem(true); + } + + public void addRunnable(Runnable runnable) { + synchronized (fRunnables) { + fRunnables.add(runnable); + } + schedule(); + } + + public boolean isEmpty() { + return fRunnables.isEmpty(); + } + + @Override + public IStatus run(IProgressMonitor monitor) { + fRunningAsyncJob = true; + Object[] runnables; + synchronized (fRunnables) { + runnables = fRunnables.toArray(); + fRunnables.clear(); + } + + MultiStatus failed = null; + monitor.beginTask(JDIDebugModelMessages.JDIThread_39, runnables.length); + int i = 0; + while (i < runnables.length && !isTerminated() + && !monitor.isCanceled()) { + try { + ((Runnable) runnables[i]).run(); + } catch (Exception e) { + if (failed == null) { + failed = new MultiStatus( + JDIDebugPlugin.getUniqueIdentifier(), + JDIDebugPlugin.ERROR, + JDIDebugModelMessages.JDIThread_0, null); + } + failed.add(new Status(IStatus.ERROR, JDIDebugPlugin + .getUniqueIdentifier(), JDIDebugPlugin.ERROR, + JDIDebugModelMessages.JDIThread_0, e)); + } + i++; + monitor.worked(1); + } + fRunningAsyncJob = false; + monitor.done(); + if (failed == null) { + return Status.OK_STATUS; + } + return failed; + } + + @Override + public boolean shouldRun() { + return !isTerminated() && !fRunnables.isEmpty(); + } + + @Override + public boolean belongsTo(Object family) { + return JDIThread.class == family || JDIThread.this == family; + } + } + + @Override + public void stop(IJavaObject exception) throws DebugException { + try { + fThread.stop(((JDIObjectValue) exception).getUnderlyingObject()); + } catch (InvalidTypeException e) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIThread_exception_stoping_thread, + e.toString()), e); + } + } + + @Override + public IJavaThreadGroup getThreadGroup() throws DebugException { + ThreadGroupReference group = getUnderlyingThreadGroup(); + if (group != null) { + return getJavaDebugTarget().findThreadGroup(group); + } + return null; + } + + @Override + public int getFrameCount() throws DebugException { + return getUnderlyingFrameCount(); + } + + protected void forceReturn(IJavaValue value) throws DebugException { + if (!isSuspended()) { + return; + } + try { + fThread.forceEarlyReturn(((JDIValue) value).getUnderlyingValue()); + stepReturn(); + } catch (VMDisconnectedException e) { + disconnected(); + } catch (InvalidTypeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e); + } catch (ClassNotLoadedException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e); + } catch (IncompatibleThreadStateException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e); + } catch (UnsupportedOperationException e) { + requestFailed(JDIDebugModelMessages.JDIThread_48, e); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThread_48, e); + } + } + + /** + * Implementation of a scheduling rule for this thread, which defines how it + * should behave when a request for content job tries to run while the + * thread is evaluating + * + * @since 3.3.0 + */ + static class SerialPerObjectRule implements ISchedulingRule { + + private Object fObject = null; + + public SerialPerObjectRule(Object lock) { + fObject = lock; + } + + @Override + public boolean contains(ISchedulingRule rule) { + return rule == this; + } + + @Override + public boolean isConflicting(ISchedulingRule rule) { + if (rule instanceof SerialPerObjectRule) { + SerialPerObjectRule vup = (SerialPerObjectRule) rule; + return fObject == vup.fObject; + } + return false; + } + + } + + /** + * returns the scheduling rule for getting content while evaluations are + * running + * + * @return the ISchedulingRule for this thread + * + * @since 3.3.0 + */ + public ISchedulingRule getThreadRule() { + return new SerialPerObjectRule(this); + } + + /** + * A class prepare has resumed this thread - if the thread was suspended at + * startup then fix up the state to running and fire an event to update UI. + */ + public synchronized void resumedFromClassPrepare() { + if (isSuspended()) { + setRunning(true); + fireResumeEvent(DebugEvent.CLIENT_REQUEST); + } + } + + /** + * Returns whether a suspend vote is currently in progress. + * + * @return whether a suspend vote is currently in progress + */ + public boolean isSuspendVoteInProgress() { + return fSuspendVoteInProgress; + } + + @Override + public IJavaObject getThreadObject() throws DebugException { + return (IJavaObject) JDIValue + .createValue(getJavaDebugTarget(), fThread); + } + + protected StepIntoHandler createStepIntoHandler() { + return new StepIntoHandler(); + } + + protected StepOverHandler createStepOverHandler() { + return new StepOverHandler(); + } + + protected StepReturnHandler createStepReturnHandler() { + return new StepReturnHandler(); + } + + protected StepToFrameHandler createStepToFrameHandler(IStackFrame stackFrame) throws DebugException { + return new StepToFrameHandler(stackFrame); + } + + protected DropToFrameHandler createDropToFrameHandler(IStackFrame stackFrame) throws DebugException { + return new DropToFrameHandler(stackFrame); + } + public static boolean showStepResultIsEnabled(IDebugTarget debugTarget) { + if (debugTarget == null || debugTarget.getProcess() == null) { + return Platform.getPreferencesService().getBoolean(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugModel.PREF_SHOW_STEP_RESULT_REMOTE, false, null); + } + return Platform.getPreferencesService().getBoolean(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugModel.PREF_SHOW_STEP_RESULT, true, null); + } + + public static int getStepResultTimeout() { + return Platform.getPreferencesService().getInt(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT, null); + } + + protected boolean isSupported(Location currentLocation) { + if (currentLocation == null) { + return false; + } + return JAVA_STRATUM_CONSTANT.equals(currentLocation.declaringType().defaultStratum()); + } + + public MethodResult getMethodResult() { + return fMethodResult; + } + + public void setMethodResult(MethodResult fMethodResult) { + this.fMethodResult = fMethodResult; + } + + boolean isBreakpointHandlingOngoing() { + return fCompletingBreakpointHandling.get() || fHandlingSuspendForBreakpoint.get(); + } +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThreadGroup.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThreadGroup.java new file mode 100644 index 0000000000..9aad20c170 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThreadGroup.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaThreadGroup; + +import com.sun.jdi.ThreadGroupReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.VMDisconnectedException; + +/** + * @since 3.2 + * + */ +public class JDIThreadGroup extends JDIDebugElement implements + IJavaThreadGroup, ITerminate { + + private ThreadGroupReference fGroup = null; + private String fName = null; + + /** + * Constructs a new thread group in the given target based on the underlying + * thread group reference. + * + * @param target + * debug target + * @param group + * thread group reference + */ + public JDIThreadGroup(JDIDebugTarget target, ThreadGroupReference group) { + super(target); + fGroup = group; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaThreadGroup#getThreads() + */ + @Override + public synchronized IJavaThread[] getThreads() throws DebugException { + try { + List threads = fGroup.threads(); + List modelThreads = new ArrayList<>(threads.size()); + Iterator iterator = threads.iterator(); + while (iterator.hasNext()) { + ThreadReference ref = iterator.next(); + JDIThread thread = getJavaDebugTarget().findThread(ref); + if (thread != null) { + modelThreads.add(thread); + } + } + return modelThreads + .toArray(new IJavaThread[modelThreads.size()]); + } catch (VMDisconnectedException e) { + // terminated/disconnected, return empty collection + return new IJavaThread[0]; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThreadGroup_0, e); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaThreadGroup#getThreadGroup() + */ + @Override + public IJavaThreadGroup getThreadGroup() throws DebugException { + try { + ThreadGroupReference reference = fGroup.parent(); + if (reference != null) { + return getJavaDebugTarget().findThreadGroup(reference); + } + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThreadGroup_1, e); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaThreadGroup#getThreadGroups() + */ + @Override + public IJavaThreadGroup[] getThreadGroups() throws DebugException { + try { + List groups = fGroup.threadGroups(); + List modelGroups = new ArrayList<>(groups.size()); + Iterator iterator = groups.iterator(); + while (iterator.hasNext()) { + ThreadGroupReference ref = iterator + .next(); + JDIThreadGroup group = getJavaDebugTarget() + .findThreadGroup(ref); + if (group != null) { + modelGroups.add(group); + } + } + return modelGroups + .toArray(new IJavaThreadGroup[modelGroups.size()]); + } catch (VMDisconnectedException e) { + return new IJavaThreadGroup[0]; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThreadGroup_2, e); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaThreadGroup#getName() + */ + @Override + public synchronized String getName() throws DebugException { + if (fName == null) { + try { + fName = fGroup.name(); + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThreadGroup_3, e); + } + } + return fName; + } + + ThreadGroupReference getUnderlyingThreadGroup() { + return fGroup; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaThreadGroup#hasThreadGroups() + */ + @Override + public boolean hasThreadGroups() throws DebugException { + try { + List groups = fGroup.threadGroups(); + return groups.size() > 0; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThreadGroup_4, e); + } + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaThreadGroup#hasThreads() + */ + @Override + public boolean hasThreads() throws DebugException { + try { + List threads = fGroup.threads(); + return threads.size() > 0; + } catch (RuntimeException e) { + targetRequestFailed(JDIDebugModelMessages.JDIThreadGroup_5, e); + } + return false; + } + + /** + * @see org.eclipse.debug.core.model.ITerminate#canTerminate() + */ + @Override + public boolean canTerminate() { + // the group can terminate if the target can terminate + return getDebugTarget().canTerminate(); + } + + /** + * @see org.eclipse.debug.core.model.ITerminate#isTerminated() + */ + @Override + public boolean isTerminated() { + return getDebugTarget().isTerminated(); + } + + /** + * @see org.eclipse.debug.core.model.ITerminate#terminate() + */ + @Override + public void terminate() throws DebugException { + getDebugTarget().terminate(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIType.java new file mode 100644 index 0000000000..0cc5740de0 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIType.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.jdi.TimeoutException; +import org.eclipse.jdt.debug.core.IJavaType; + +import com.sun.jdi.ArrayType; +import com.sun.jdi.ClassType; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Type; + +/** + * A type of an object or primitive data type in a debug target. + */ +public class JDIType extends JDIDebugElement implements IJavaType { + + /** + * Underlying type on target VM + */ + private Type fType; + + /** + * Constructs a new type based on the specified underlying type, in the + * given debug target + * + * @param target + * the debug target this type originated from + * @param type + * underlying type on the target VM + */ + protected JDIType(JDIDebugTarget target, Type type) { + super(target); + setUnderlyingType(type); + } + + /** + * Throws a new debug exception with the given status code. + * + * @param message + * Failure message + * @param e + * Exception that has occurred (can be null) + * @param code + * status code + * @throws DebugException + * a new exception with given status code + */ + @Override + public void requestFailed(String message, Throwable e, int code) + throws DebugException { + throwDebugException(message, code, e); + } + + /** + * Throws a new debug exception with a status code of + * TARGET_REQUEST_FAILED with the given underlying exception. + * If the underlying exception is not a JDI exception, the original + * exception is thrown. + * + * @param message + * Failure message + * @param e + * underlying exception that has occurred + * @throws DebugException + * The exception with a status code of + * TARGET_REQUEST_FAILED + */ + @Override + public void targetRequestFailed(String message, RuntimeException e) + throws DebugException { + if (e == null + || e.getClass().getName().startsWith("com.sun.jdi") || e instanceof TimeoutException) { //$NON-NLS-1$ + requestFailed(message, e, DebugException.TARGET_REQUEST_FAILED); + } else { + throw e; + } + } + + /** + * Creates the appropriate kind of type, based on the specialized type. + */ + public static JDIType createType(JDIDebugTarget target, Type type) { + if (type instanceof ArrayType) { + return new JDIArrayType(target, (ArrayType) type); + } + if (type instanceof ClassType) { + return new JDIClassType(target, (ClassType) type); + } + if (type instanceof InterfaceType) { + return new JDIInterfaceType(target, (InterfaceType) type); + } + return new JDIType(target, type); + } + + /** + * @see IJavaType#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + return getUnderlyingType().signature(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIType_exception_while_retrieving_signature, + e.toString()), e); + // execution will not reach this line as + // #targetRequestFailed will throw an exception + return null; + } + } + + /** + * Returns the underlying type on the VM. + * + * @return the underlying type on the VM + */ + public Type getUnderlyingType() { + return fType; + } + + /** + * Sets the underlying type on the VM. + * + * @param type + * the underlying type on the VM + */ + protected void setUnderlyingType(Type type) { + fType = type; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getUnderlyingType().toString(); + } + + /** + * @see IJavaType#getName() + */ + @Override + public String getName() throws DebugException { + try { + return getUnderlyingType().name(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIType_exception_while_retrieving_type_name, + e.toString()), e); + } + // execution will not fall through as an exception + // will be thrown by the catch block + return null; + } + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object instanceof JDIType + && fType.equals(((JDIType) object).fType); + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return fType.hashCode(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIValue.java new file mode 100644 index 0000000000..2a03a88639 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIValue.java @@ -0,0 +1,516 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +import com.sun.jdi.ArrayReference; +import com.sun.jdi.ClassObjectReference; +import com.sun.jdi.Field; +import com.sun.jdi.ObjectCollectedException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.PrimitiveValue; +import com.sun.jdi.ReferenceType; +import com.sun.jdi.StringReference; +import com.sun.jdi.Type; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.Value; +import com.sun.jdi.VoidValue; + +/** + * Represents the value of a java variable + * + * @see IJavaValue + */ +public class JDIValue extends JDIDebugElement implements IJavaValue { + + private final Value fValue; + private List fVariables; + + /** + * A flag indicating if this value is still allocated (valid) + */ + private boolean fAllocated = true; + + /** + * When created for a logical structure we hold onto the original + * non-logical value for purposes of equality. This way a logical + * structure's children remain more stable in the variables view. + * + * This is null when not created for a logical structure. + */ + protected IJavaValue fLogicalParent; + + /** + * Constructor + * + * @param target + * debug target that this value belongs to + * @param value + * the underlying value this value represents + */ + public JDIValue(JDIDebugTarget target, Value value) { + super(target); + fValue = value; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jdt.internal.debug.core.model.JDIDebugElement#getAdapter( + * java.lang.Class) + */ + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter == IJavaValue.class) { + return (T) this; + } + return super.getAdapter(adapter); + } + + /** + * Creates the appropriate kind of value - i.e. a primitive value, object, + * class object, array, null or void. + */ + public static JDIValue createValue(JDIDebugTarget target, Value value) { + if (value == null) { + return new JDINullValue(target); + } + if (value instanceof ArrayReference) { + return new JDIArrayValue(target, (ArrayReference) value); + } + if (value instanceof ClassObjectReference) { + return new JDIClassObjectValue(target, (ClassObjectReference) value); + } + if (value instanceof ObjectReference) { + return new JDIObjectValue(target, (ObjectReference) value); + } + if (value instanceof PrimitiveValue) { + return new JDIPrimitiveValue(target, value); + } + if (value instanceof VoidValue) { + return new JDIVoidValue(target); + } + return new JDIValue(target, value); + } + + /** + * @see IValue#getValueString() + */ + @Override + public String getValueString() throws DebugException { + if (fValue == null) { + return JDIDebugModelMessages.JDIValue_null_4; + } + if (fValue instanceof StringReference) { + try { + return ((StringReference) fValue).value(); + } catch (ObjectCollectedException e) { + return JDIDebugModelMessages.JDIValue_deallocated; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_value, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + if (fValue instanceof ObjectReference) { + StringBuilder name = new StringBuilder(); + if (fValue instanceof ClassObjectReference) { + name.append('('); + name.append(((ClassObjectReference) fValue).reflectedType()); + name.append(')'); + } + long id = 0; + try { + id = ((ObjectReference) fValue).uniqueID(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_unique_id, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + name.append(" "); //$NON-NLS-1$ + name.append(MessageFormat.format( + JDIDebugModelMessages.JDIValue_id_8, + new Object[] { String.valueOf(id) })); + return name.toString(); + } + // see bug 43285 + return String.valueOf(fValue); + } + + /** + * @see IValue#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() throws DebugException { + try { + if (fValue == null) { + return JDIDebugModelMessages.JDIValue_null_4; + } + return getUnderlyingType().name(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_reference_type_name, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + if (fValue == null) { + return getClass().hashCode(); + } + return fValue.hashCode(); + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof JDIValue) { + Value other = ((JDIValue) o).getUnderlyingValue(); + if (fValue == null) { + return false; + } + if (other == null) { + return false; + } + return fValue.equals(other); + } + return false; + } + + /** + * @see IValue#getVariables() + */ + @Override + public IVariable[] getVariables() throws DebugException { + List list = getVariablesList(); + return list.toArray(new IVariable[list.size()]); + } + + /** + * Returns a list of variables that are children of this value. The result + * is cached. + * + * @return list of variable children + * @throws DebugException + */ + protected synchronized List getVariablesList() throws DebugException { + if (fVariables != null) { + return fVariables; + } else if (fValue instanceof ObjectReference) { + ObjectReference object = (ObjectReference) fValue; + fVariables = new ArrayList<>(); + if (isArray()) { + try { + int length = getArrayLength(); + for (int i = 0; i < length; i++) { + fVariables.add(new JDIArrayEntryVariable( + getJavaDebugTarget(), getArrayReference(), i, + fLogicalParent)); + } + } catch (DebugException e) { + if (e.getCause() instanceof ObjectCollectedException) { + return Collections.EMPTY_LIST; + } + throw e; + } + } else { + List fields = null; + try { + ReferenceType refType = object.referenceType(); + fields = refType.allFields(); + } catch (ObjectCollectedException e) { + return Collections.EMPTY_LIST; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_fields, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + Iterator list = fields.iterator(); + while (list.hasNext()) { + Field field = list.next(); + fVariables.add(new JDIFieldVariable( + (JDIDebugTarget) getDebugTarget(), field, object, + fLogicalParent)); + } + Collections.sort(fVariables, (a, b) -> sortChildren(a, b)); + } + + return fVariables; + } else { + return Collections.EMPTY_LIST; + } + } + + /** + * Group statics and instance variables, sort alphabetically within each + * group. + */ + protected int sortChildren(Object a, Object b) { + IJavaVariable v1 = (IJavaVariable) a; + IJavaVariable v2 = (IJavaVariable) b; + + try { + boolean v1isStatic = v1.isStatic(); + boolean v2isStatic = v2.isStatic(); + if (v1isStatic && !v2isStatic) { + return -1; + } + if (!v1isStatic && v2isStatic) { + return 1; + } + return v1.getName().compareToIgnoreCase(v2.getName()); + } catch (DebugException de) { + logError(de); + return -1; + } + } + + /** + * Returns whether this value is an array + */ + protected boolean isArray() { + return fValue instanceof ArrayReference; + } + + /** + * Returns this value as an array reference, or null + */ + protected ArrayReference getArrayReference() { + if (isArray()) { + return (ArrayReference) fValue; + } + return null; + } + + /** + * @see IValue#isAllocated() + */ + @Override + public boolean isAllocated() throws DebugException { + if (fAllocated) { + if (fValue instanceof ObjectReference) { + try { + fAllocated = !((ObjectReference) fValue).isCollected(); + } catch (VMDisconnectedException e) { + // if the VM disconnects, this value is not allocated + fAllocated = false; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_is_collected, + new Object[] { e.toString() }), e); + // execution will fall through, as + // #targetRequestFailed will thrown an exception + } + } else { + JDIDebugTarget dt = (JDIDebugTarget) getDebugTarget(); + fAllocated = dt.isAvailable(); + } + } + return fAllocated; + } + + /** + * @see IJavaValue#getSignature() + */ + @Override + public String getSignature() throws DebugException { + try { + if (fValue != null) { + return fValue.type().signature(); + } + return null; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_type_signature, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#getGenericSignature() + */ + @Override + public String getGenericSignature() throws DebugException { + try { + if (fValue != null) { + Type type = fValue.type(); + if (type instanceof ReferenceType) { + return ((ReferenceType) type).genericSignature(); + } + return null; + } + return null; + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_type_signature, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will thrown an exception + return null; + } + } + + /** + * @see IJavaValue#getArrayLength() + */ + public int getArrayLength() throws DebugException { + if (isArray()) { + try { + return getArrayReference().length(); + } catch (RuntimeException e) { + targetRequestFailed( + MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_length_of_array, + new Object[] { e.toString() }), e); + } + } + return -1; + } + + /** + * Returns this value's underlying JDI value + */ + protected Value getUnderlyingValue() { + return fValue; + } + + /** + * @see IJavaValue#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return JDIType.createType((JDIDebugTarget) getDebugTarget(), + getUnderlyingType()); + } + + /** + * Returns this value's underlying type. + * + * @return type + * @exception DebugException + * if this method fails. Reasons include: + *
                        + *
                      • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                      • + */ + protected Type getUnderlyingType() throws DebugException { + try { + return getUnderlyingValue().type(); + } catch (RuntimeException e) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIValue_exception_retrieving_type, + new Object[] { e.toString() }), e); + // execution will not fall through to here, + // as #requestFailed will throw an exception + return null; + } + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return getUnderlyingValue().toString(); + } + + /** + * @see IValue#hasVariables() + */ + @Override + public boolean hasVariables() throws DebugException { + return getVariablesList().size() > 0; + } + + /** + * Sets the value that is the original non-logical value that this child + * value was computed for. + * + * @param logicalParent + * parent value + */ + public void setLogicalParent(IJavaValue logicalParent) { + fLogicalParent = logicalParent; + } + + /** + * Returns the value that is the original non-logical value that this child + * value was computed for or null if none + * + * @param logicalParent + * parent value or null + */ + public IJavaValue getLogicalParent() { + return fLogicalParent; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.debug.core.IJavaValue#isNull() + */ + @Override + public boolean isNull() { + return false; + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVariable.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVariable.java new file mode 100644 index 0000000000..921f0e4869 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVariable.java @@ -0,0 +1,287 @@ +/******************************************************************************* + * Copyright (c) 2000, 2015 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.text.MessageFormat; + +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IValueModification; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaModifiers; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaVariable; + +import com.sun.jdi.Type; +import com.sun.jdi.Value; + +public abstract class JDIVariable extends JDIDebugElement implements + IJavaVariable { + + /** + * Cache of current value - see #getValue(). + */ + private JDIValue fValue; + + /** + * Counter corresponding to this variable's debug target suspend count + * indicating the last time this value changed. This variable's value has + * changed on the last suspend event if this counter is equal to the debug + * target's suspend count. + */ + private int fLastChangeIndex = -1; + + protected final static String jdiStringSignature = "Ljava/lang/String;"; //$NON-NLS-1$ + + public JDIVariable(JDIDebugTarget target) { + super(target); + } + + /** + * @see PlatformObject#getAdapter(Class) + */ + @SuppressWarnings("unchecked") + @Override + public T getAdapter(Class adapter) { + if (adapter == IJavaVariable.class || adapter == IJavaModifiers.class) { + return (T) this; + } + return super.getAdapter(adapter); + } + + /** + * Returns this variable's current underlying jdi value. Subclasses must + * implement #retrieveValue() and do not need to guard against JDI + * exceptions, as this method handles them. + * + * @exception DebugException + * if unable to access the value + */ + protected final Value getCurrentValue() throws DebugException { + try { + return retrieveValue(); + } catch (RuntimeException e) { + targetRequestFailed(MessageFormat.format( + JDIDebugModelMessages.JDIVariable_exception_retrieving, + new Object[] { e.toString() }), e); + // execution will not reach this line, as + // #targetRequestFailed will throw an exception + return null; + } + } + + /** + * Returns this variable's underlying jdi value + */ + protected abstract Value retrieveValue() throws DebugException; + + /** + * Returns the current value of this variable. The value is cached, but on + * each access we see if the value has changed and update if required. + * + * @see IVariable#getValue() + */ + @Override + public IValue getValue() throws DebugException { + Value currentValue = getCurrentValue(); + if (fValue == null) { + fValue = JDIValue.createValue((JDIDebugTarget) getDebugTarget(), + currentValue); + } else { + Value previousValue = fValue.getUnderlyingValue(); + if (currentValue == previousValue) { + return fValue; + } + if (previousValue == null || currentValue == null) { + fValue = JDIValue.createValue( + (JDIDebugTarget) getDebugTarget(), currentValue); + setChangeCount(getJavaDebugTarget().getSuspendCount()); + } else if (!previousValue.equals(currentValue)) { + fValue = JDIValue.createValue( + (JDIDebugTarget) getDebugTarget(), currentValue); + setChangeCount(getJavaDebugTarget().getSuspendCount()); + } + } + return fValue; + } + + /** + * @see IValueModification#supportsValueModification() + */ + @Override + public boolean supportsValueModification() { + return false; + } + + /** + * @see IValueModification#setValue(String) + */ + @Override + public void setValue(String expression) throws DebugException { + notSupported(JDIDebugModelMessages.JDIVariable_does_not_support_value_modification); + } + + /** + * @see IValueModification#setValue(IValue) + */ + @Override + public void setValue(IValue value) throws DebugException { + notSupported(JDIDebugModelMessages.JDIVariable_does_not_support_value_modification); + } + + /** + * @see IValueModification#verifyValue(String) + */ + @Override + public boolean verifyValue(String expression) throws DebugException { + return false; + } + + /** + * @see IValueModification#verifyValue(IValue) + */ + @Override + public boolean verifyValue(IValue value) throws DebugException { + return false; + } + + /** + * @see IJavaModifiers#isSynthetic() + */ + @Override + public boolean isSynthetic() { + return false; + } + + /** + * @see IJavaModifiers#isPublic() + */ + @Override + public boolean isPublic() throws DebugException { + return false; + } + + /** + * @see IJavaModifiers#isPrivate() + */ + @Override + public boolean isPrivate() throws DebugException { + return false; + } + + /** + * @see IJavaModifiers#isProtected() + */ + @Override + public boolean isProtected() throws DebugException { + return false; + } + + /** + * @see IJavaModifiers#isPackagePrivate() + */ + @Override + public boolean isPackagePrivate() { + return false; + } + + /** + * @see IJavaModifiers#isStatic() + */ + @Override + public boolean isStatic() { + return false; + } + + /** + * @see IJavaModifiers#isFinal() + */ + @Override + public boolean isFinal() { + return false; + } + + /** + * @see org.eclipse.jdt.debug.core.IJavaVariable#isLocal() + */ + @Override + public boolean isLocal() { + return false; + } + + /** + * @see IJavaVariable#getJavaType() + */ + @Override + public IJavaType getJavaType() throws DebugException { + return JDIType.createType((JDIDebugTarget) getDebugTarget(), + getUnderlyingType()); + } + + /** + * Returns the underlying type of this variable + * + * @return the underlying type of this variable + * + * @exception DebugException + * if this method fails. Reasons include: + *
                          + *
                        • Failure communicating with the VM. The + * DebugException's status code contains the underlying + * exception responsible for the failure.
                        • + *
                        • The type associated with this variable is not yet + * loaded
                        • + *
                        + */ + protected abstract Type getUnderlyingType() throws DebugException; + + /** + * Returns the last known value for this variable + */ + protected Value getLastKnownValue() { + if (fValue == null) { + return null; + } + return fValue.getUnderlyingValue(); + } + + /** + * Sets this variable's change counter to the specified value + * + * @param count + * new value + */ + protected void setChangeCount(int count) { + fLastChangeIndex = count; + } + + /** + * Returns this variable's change counter. This corresponds to the last time + * this variable changed. + * + * @return this variable's change counter + */ + protected int getChangeCount() { + return fLastChangeIndex; + } + + /** + * @see IVariable#hasValueChanged() + */ + @Override + public boolean hasValueChanged() { + return getChangeCount() == getJavaDebugTarget().getSuspendCount(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVoidType.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVoidType.java new file mode 100644 index 0000000000..461d71a005 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVoidType.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import org.eclipse.jdt.debug.core.IJavaType; + +/** + * Void type. Since it is not possible to retrieve the void type from the target + * VM on demand, there is a special implementation for the void type. + */ + +public class JDIVoidType extends JDIType { + + /** + * Constructs a new void type for the given VM. + */ + protected JDIVoidType(JDIDebugTarget target) { + super(target, null); + } + + /** + * @see IJavaType#getName() + */ + @Override + public String getName() { + return "void"; //$NON-NLS-1$ + } + + /** + * @see IJavaType#getSignature() + */ + @Override + public String getSignature() { + return "V"; //$NON-NLS-1$ + } + + /** + * @see java.lang.Object#equals(Object) + */ + @Override + public boolean equals(Object object) { + return object instanceof JDIVoidType + && getDebugTarget().equals( + ((JDIVoidType) object).getDebugTarget()); + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return super.hashCode(); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVoidValue.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVoidValue.java new file mode 100644 index 0000000000..81f52c6a4e --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIVoidValue.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.debug.core.model.IValue; +import org.eclipse.jdt.debug.core.IJavaType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; + +/** + * Represents a value of "void" + */ +public class JDIVoidValue extends JDIValue { + + public JDIVoidValue(JDIDebugTarget target) { + super(target, target.getVM() != null ? target.getVM().mirrorOfVoid() + : null); + } + + @Override + protected List getVariablesList() { + return Collections.EMPTY_LIST; + } + + /** + * @see IValue#getReferenceTypeName() + */ + @Override + public String getReferenceTypeName() { + return "void"; //$NON-NLS-1$ + } + + /** + * @see IValue#getValueString() + */ + @Override + public String getValueString() { + return "null"; //$NON-NLS-1$ + } + + /** + * @see IJavaValue#getSignature() + */ + @Override + public String getSignature() { + return "V"; //$NON-NLS-1$ + } + + /** + * @see IJavaValue#getArrayLength() + */ + @Override + public int getArrayLength() { + return -1; + } + + /** + * @see IJavaValue#getJavaType() + */ + @Override + public IJavaType getJavaType() { + return new JDIVoidType((JDIDebugTarget) getDebugTarget()); + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "void"; //$NON-NLS-1$ + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java new file mode 100644 index 0000000000..0337e239d2 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2018, 2022 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.debug.core.IJavaFieldVariable; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.internal.debug.core.logicalstructures.JDILambdaVariable; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; + +import com.sun.jdi.AbsentInformationException; +import com.sun.jdi.Location; +import com.sun.jdi.Method; + +/** + * Utility class for Lambda Expressions and Stack frames Place holder for all Lambda operation encapsulation. + */ +public class LambdaUtils { + + private static final String LAMBDA_METHOD_PREFIX = "lambda$"; //$NON-NLS-1$ + private static final Pattern LAMBDA_TYPE_PATTERN = Pattern.compile(".*\\$\\$Lambda[\\$,\\.].*"); //$NON-NLS-1$ + + /** + * Inspects the top stack frame of the context; if that frame is a lambda frame, looks for a variable with the specified name in that frame and + * outer frames visible from that frame. + * + * @param context + * The context in which to check. + * @param variableName + * The name of the variable. + * @return The variable with the specified name if found, {@code null} otherwise. Also returns {@code null} if no thread or top stack frame is + * available. If there are multiple variables with the same name in the lambda context, the most local one is returned. + * @throws DebugException + * If accessing the top stack frame or the local variables on stack frames fails, due to failure to communicate with the debug target. + */ + public static IVariable findLambdaFrameVariable(IRuntimeContext context, String variableName) throws DebugException { + IStackFrame stackFrame = context.getFrame(); + if (stackFrame != null) { + List variables = getLambdaFrameVariables(stackFrame); + for (IVariable variable : variables) { + if (variable.getName().equals(variableName)) { + return variable; + } + } + } + return null; + } + + /** + * Collects variables visible from a lambda stack frame. + * + * If the debugging class generates all debugging info in its classfile (e.g. line number and source file name), we can use these info to find all + * enclosing frames of the paused line number and collect their variables. Otherwise, collect variables from that lambda frame and two more frames + * below it. + * + * @param frame + * The lambda frame at which to check. + * @return The variables visible from the stack frame. An empty list if the specified stack frame is not a lambda frame. The variables are ordered + * top-down, i.e. if shadowing occurs, the more local variable will be first in the resulting list. + * @throws DebugException + * If accessing the top stack frame or the local variables on stack frames fails, due to failure to communicate with the debug target. + */ + public static List getLambdaFrameVariables(IStackFrame frame) throws DebugException { + if (LambdaUtils.isLambdaFrame(frame)) { + int lineNumber = frame.getLineNumber(); + String sourceName = ((IJavaStackFrame) frame).getSourceName(); + if (lineNumber == -1 || sourceName == null) { + return collectVariablesFromLambdaFrame(frame); + } + return collectVariablesFromEnclosingFrames(frame); + } + return Collections.emptyList(); + } + + /** + * Collects variables visible from a lambda stack frame and two frames below that frame. + * + * Inside a lambda expression, variable names are mangled by the compiler. Its therefore necessary to check the outer frame when at a lambda + * frame, in order to find a variable with its name. The lambda expression itself is called by a synthetic static method, which is the first frame + * below the lambda frame. So in total we collect variables from 3 stack frames. + * + * @param frame + * The lambda frame at which to check. + * @return The variables visible from the stack frame. The variables are ordered top-down, i.e. if shadowing occurs, the more local variable will + * be first in the resulting list. + * @throws DebugException + * If accessing the top stack frame or the local variables on stack frames fails, due to failure to communicate with the debug target. + */ + private static List collectVariablesFromLambdaFrame(IStackFrame frame) throws DebugException { + List variables = new ArrayList<>(); + IThread thread = frame.getThread(); + // look for two frames below the frame which is provided instead starting from first frame. + List stackFrames = Stream.of(thread.getStackFrames()).dropWhile(f -> f != frame) + .limit(3).collect(Collectors.toUnmodifiableList()); + for (IStackFrame stackFrame : stackFrames) { + IVariable[] stackFrameVariables = stackFrame.getVariables(); + variables.addAll(Arrays.asList(stackFrameVariables)); + for (IVariable frameVariable : stackFrameVariables) { + if (isLambdaObjectVariable(frameVariable)) { + variables.addAll(extractVariablesFromLambda(frameVariable)); + } + } + } + return Collections.unmodifiableList(variables); + } + + /** + * Collect variables from all enclosing frames starting from the provided frame. + */ + private static List collectVariablesFromEnclosingFrames(IStackFrame frame) throws DebugException { + List variables = new ArrayList<>(); + IThread thread = frame.getThread(); + List stackFrames = Stream.of(thread.getStackFrames()).dropWhile(f -> f != frame) + .collect(Collectors.toUnmodifiableList()); + int pausedLineNumber = frame.getLineNumber(); + String pausedSourceName = ((IJavaStackFrame) frame).getSourceName(); + String pausedSourcePath = ((IJavaStackFrame) frame).getSourcePath(); + boolean isFocusFrame = true; + for (IStackFrame stackFrame : stackFrames) { + JDIStackFrame jdiFrame = (JDIStackFrame) stackFrame; + if (isFocusFrame) { + isFocusFrame = false; + } else { + if (!Objects.equals(pausedSourceName, jdiFrame.getSourceName()) + || !Objects.equals(pausedSourcePath, jdiFrame.getSourcePath())) { + continue; + } + List locations; + try { + locations = jdiFrame.getUnderlyingMethod().allLineLocations(); + } catch (AbsentInformationException e) { + continue; + } + if (locations.isEmpty()) { + continue; + } + int methodStartLine = locations.get(0).lineNumber(); + int methodEndLine = locations.get(locations.size() - 1).lineNumber(); + if (methodStartLine > pausedLineNumber || methodEndLine < pausedLineNumber) { + continue; + } + } + IVariable[] stackFrameVariables = jdiFrame.getVariables(); + variables.addAll(Arrays.asList(stackFrameVariables)); + for (IVariable frameVariable : stackFrameVariables) { + if (isLambdaObjectVariable(frameVariable)) { + variables.addAll(extractVariablesFromLambda(frameVariable)); + } + } + } + return Collections.unmodifiableList(variables); + } + + /** + * Evaluates if the input frame is a lambda frame. + * + * @param frame + * the frame which needs to be evaluated + * @return True if the frame is a lambda frame else return False + */ + public static boolean isLambdaFrame(IStackFrame frame) throws DebugException { + return frame instanceof IJavaStackFrame && isLambdaFrame((IJavaStackFrame) frame); + } + + /** + * Evaluates if the input frame is a lambda frame. + * + * @param frame + * the frame which needs to be evaluated + * @return True if the frame is a lambda frame else return False + * @since 3.8 + */ + public static boolean isLambdaFrame(IJavaStackFrame frame) throws DebugException { + return frame.isSynthetic() && frame.getName().startsWith(LAMBDA_METHOD_PREFIX); + } + + /** + * Returns if the variable represent a variable embedded into Lambda object. + * + * @param variable + * the variable which needs to be evaluated + * @return True if the variable is inside the Lambda object else return False + * @since 3.15 + */ + public static boolean isLambdaField(IVariable variable) throws DebugException { + return (variable instanceof IJavaFieldVariable) && + LAMBDA_TYPE_PATTERN.matcher(((IJavaFieldVariable) variable).getDeclaringType().getName()).matches(); + } + + /** + * Returns if the method is a lambda method. + * + * @param method + * the method for which to check + * @return True if the method is a lambda method else return False + * @since 3.20 + */ + public static boolean isLambdaMethod(Method method) { + return method.name().startsWith(LAMBDA_METHOD_PREFIX); + } + + private static boolean isLambdaObjectVariable(IVariable variable) { + return variable instanceof JDILambdaVariable; + } + + private static List extractVariablesFromLambda(IVariable variable) throws DebugException { + if (variable.getValue() instanceof IJavaObject) { + return Arrays.asList(variable.getValue().getVariables()); + } + return Collections.emptyList(); + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java new file mode 100644 index 0000000000..b0d93d9b74 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2016, 2018 Till Brychcy and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Till Brychcy - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.internal.debug.core.model; + +import com.sun.jdi.Method; +import com.sun.jdi.Value; + +public class MethodResult { + public enum ResultType { + /** fValue is returned value after a step operation */ + returned, + + /** fValue is exception thrown after a step operation */ + threw, + + /** fValue is value being returned at a method exit breakpoint */ + returning, + + /** fValue is exception being thrown in a exception breakpoint */ + throwing, + + /** fValue is not set because the step operation took too long */ + step_timeout + } + + public MethodResult(Method method, int targetFrameCount, Value value, ResultType resultType) { + this.fMethod = method; + this.fTargetFrameCount = targetFrameCount; + this.fValue = value; + this.fResultType = resultType; + } + + /** + * The method from which {@link #fValue} originates + */ + public final Method fMethod; + + /** + * If a step-return or step-over is in progress, this is the stack size at which the result value is expected. Otherwise ignored. + */ + public final int fTargetFrameCount; + + /** + * Return value or exception + */ + public final Value fValue; + + /** + * Whether {@link #fValue} was returned or thrown + */ + public final ResultType fResultType; +} \ No newline at end of file diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/SyntheticVariableUtils.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/SyntheticVariableUtils.java new file mode 100644 index 0000000000..b898892389 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/SyntheticVariableUtils.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2020 Gayan Perera and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Gayan Perera - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine; + +/** + * Utility class for handling Synthetic Variables. + */ +public final class SyntheticVariableUtils { + private static final String ENCLOSING_INSTANCE_PREFIX = "this$"; //$NON-NLS-1$ + private static final String ANONYMOUS_VAR_PREFIX = ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX; + + private SyntheticVariableUtils() { + } + + /** + * When many anonymous objects are nested as below + * + *
                        +	 * public Bar exec(Predicate<String> predicate) {
                        +	 *
                        +	 * 	return new Bar() {
                        +	 * 		private Object bar;
                        +	 *
                        +	 * 		@Override
                        +	 * 		public Foo bar(String vbar) {
                        +	 * 			return new Foo() {
                        +	 * 				private Object foo;
                        +	 *
                        +	 * 				@Override
                        +	 * 				public String foo(String vfoo) {
                        +	 * 					predicate.test("vfoo");
                        +	 * 					return vfoo;
                        +	 * 				}
                        +	 * 			};
                        +	 * 		}
                        +	 * 	};
                        +	 * }
                        +	 * 
                        + * + * The outermost method parameters are not available as synthetic variables in the bottom most object. This method try to extract those variables + * from the variable graph. This method looks for synthetic variables in enclosing instances and traverse variables of those instances and collect + * synthetic outer local variables and return them. + * + * @param variables + * variable to search on + * @return array of variables + * @throws DebugException + */ + public static IVariable[] findSyntheticVariables(IVariable[] variables) throws DebugException { + ArrayList extracted = new ArrayList<>(); + for (IVariable variable : variables) { + if (variable.getName().startsWith(ANONYMOUS_VAR_PREFIX)) { + extracted.add(variable); + } + + if (variable.getName().startsWith(ENCLOSING_INSTANCE_PREFIX)) { + extracted.addAll(Arrays.asList(findSyntheticVariables(variable.getValue().getVariables()))); + } + } + return extracted.toArray(new IVariable[extracted.size()]); + } + +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/Timer.java b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/Timer.java new file mode 100644 index 0000000000..fce9869811 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/Timer.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.debug.core.model; + +/** + * A timer notifies listeners when a specific amount of time has passed. + * + * @see ITimeoutListener + */ +public class Timer { + + /** + * Listener to notify of a timeout + */ + private ITimeoutListener fListener; + + /** + * Timeout value, in milliseconds + */ + private int fTimeout; + + /** + * Whether this timer's thread is alive + */ + private boolean fAlive = true; + + /** + * Whether this timer has been started and has not yet timed out or been + * stopped. + */ + private boolean fStarted = false; + + /** + * The single thread used for each request. + */ + private Thread fThread; + + /** + * Constructs a new timer + */ + public Timer() { + setTimeout(Integer.MAX_VALUE); + Runnable r = () -> { + while (isAlive()) { + boolean interrupted = false; + try { + Thread.sleep(getTimeout()); + } catch (InterruptedException e) { + interrupted = true; + } + if (!interrupted) { + if (getListener() != null) { + setStarted(false); + setTimeout(Integer.MAX_VALUE); + getListener().timeout(); + setListener(null); + } + } + } + }; + setThread(new Thread(r, "Evaluation Timer")); //$NON-NLS-1$ + getThread().setDaemon(true); + getThread().start(); + } + + /** + * Starts this timer, and notifies the given listener when the time has + * passed. A call to stop, before the time expires, will cancel + * the the timer and timeout callback. This method can only be called if + * this timer is idle (i.e. isStarted() == false). + * + * @param listener + * The timer listener + * @param ms + * The number of milliseconds to wait before notifying the + * listener + */ + public void start(ITimeoutListener listener, int ms) { + if (isStarted()) { + throw new IllegalStateException( + JDIDebugModelMessages.Timer_Timer_cannot_be_started_more_than_once_1); + } + setListener(listener); + setTimeout(ms); + setStarted(true); + getThread().interrupt(); + } + + /** + * Stops this timer, cancelling any pending timeout notification. + */ + public void stop() { + if (isAlive()) { + setStarted(false); + setTimeout(Integer.MAX_VALUE); + getThread().interrupt(); + } + } + + /** + * Disposes this timer + */ + public void dispose() { + if (isAlive()) { + setAlive(false); + getThread().interrupt(); + setThread(null); + } + } + + /** + * Returns whether this timer's thread is alive + * + * @return whether this timer's thread is alive + */ + private boolean isAlive() { + return fAlive; + } + + /** + * Sets whether this timer's thread is alive. When set to false + * this timer's thread will exit on its next iteration. + * + * @param alive + * whether this timer's thread should be alive + * @see #dispose() + */ + private void setAlive(boolean alive) { + fAlive = alive; + } + + /** + * Returns the current timeout listener + * + * @return timeout listener + */ + protected ITimeoutListener getListener() { + return fListener; + } + + /** + * Sets the listener to be notified if this timer times out. + * + * @param listener + * timeout listener + */ + private void setListener(ITimeoutListener listener) { + fListener = listener; + } + + /** + * Returns whether this timer has been started, and has not yet timed out, + * or been stopped. + * + * @return whether this timer has been started, and has not yet timed out, + * or been stopped + */ + public boolean isStarted() { + return fStarted; + } + + /** + * Sets whether this timer has been started, and has not yet timed out, or + * been stopped. + * + * @param started + * whether this timer has been started, and has not yet timed + * out, or been stopped + */ + private void setStarted(boolean started) { + fStarted = started; + } + + /** + * Returns this timer's thread + * + * @return thread that waits for a timeout + */ + private Thread getThread() { + return fThread; + } + + /** + * Sets this timer's thread used to perform timeout processing + * + * @param thread + * thread that waits for a timeout + */ + private void setThread(Thread thread) { + fThread = thread; + } + + /** + * Returns the amount of time, in milliseconds, that this timer is/was + * waiting for. + * + * @return timeout value, in milliseconds + */ + protected int getTimeout() { + return fTimeout; + } + + /** + * Sets the amount of time, in milliseconds, that this timer will wait for + * before timing out. + * + * @param timeout + * value, in milliseconds + */ + private void setTimeout(int timeout) { + fTimeout = timeout; + } +} diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/plugin.properties b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/plugin.properties new file mode 100644 index 0000000000..05dd0ae06d --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/plugin.properties @@ -0,0 +1,48 @@ +############################################################################### +# Copyright (c) 2000, 2014 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + + +pluginName=JDI Debug Model +providerName=Eclipse.org + +descriptionCollection=Array +descriptionMap=Map Entries +descriptionMapEntry=Key and Value + +javaLineBreakpoint.name=Java Line Breakpoints +javaClassLoadBreakpoint.name=Java Class Load Breakpoints +javaExceptionBreakpoint.name=Java Exception Breakpoints +javaWatchpoint.name=Java Watchpoints +javaMethodBreakpoint.name=Java Method Breakpoints + +virtualMachineManagerImpl= org.eclipse.jdi.internal.VirtualMachineManagerImpl +javaLogicalStructures= Java Logical Structures + +JavaBreakpoint.name = Java Breakpoint +JavaClassLoadBreakpoint.name = Java Class Load Breakpoint +CommonJavaLineBreakpoint.name = Common Java Line Breakpoint +JavaLineBreakpoint.name = Java Line Breakpoint +JavaPatternBreakpoint.name = Java Pattern Breakpoint +JavaTargetPatternBreakpoint.name = Java Target Pattern Breakpoint +JavaExceptionBreakpoint.name = Java Exception Breakpoint +JavaWatchpoint.name = Java Watchpoint +JavaMethodBreakpoint.name = Java Method Breakpoint +JavaMethodEntryBreakpoint.name = Java Method Entry Breakpoint +JavaStratumLineBreakpoint.name = Java Stratum Line Breakpoint + +breakpointListeners.name = Java Breakpoint Listeners + +descriptionDomNode = XML DOM Element + +trace.name = JDT Debug Core diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/plugin.xml b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/plugin.xml new file mode 100644 index 0000000000..10b70a4ea5 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/plugin.xml @@ -0,0 +1,378 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/breakpointListeners.exsd b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/breakpointListeners.exsd new file mode 100644 index 0000000000..74cc9080ac --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/breakpointListeners.exsd @@ -0,0 +1,156 @@ + + + + + + + + + Allow clients to contribute listeners for Java breakpoint notifications. For example, listeners are called when a breakpoint is hit and about to suspend execution. The listener can vote to resume or suspend the debug session. Listeners can be programmatically added to and removed from specific Java breakpoints (specified by breakpoint listener identifers), or be registered to listen for notifications for all Java breakpoints. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unique identifier of the breakpoint listener + + + + + + + + + + Delegate for breakpoint notifications - must be an instance of <code>IJavaBreakpointListener</code> + + + + + + + + + + Controls whether the breakpoint listener is notified for all breakpoints. Currently, the only option allowed is "*" indicating all breakpoints. When unspecified, listeners must be added to breakpoints programmatically via their <code>id</code>. + + + + + + + + + + + + + + + + + + 3.5 + + + + + + + + + The following is an example for defining a breakpoint listener. In this example, the listener is only notified of breakpoint events for the specific breakpoints it is programatically registered for. + +<p> +<pre> +<extension + point="org.eclipse.jdt.debug.breakpointListeners"> + <breakpointActionDelegate + class="com.example.BreakpointActionDelegate" + id="com.example.breakpoint.action"> + </breakpointActionDelegate> +</extension> +</pre> +</p> + + + + + + + + + <p> +<li>Value of the attribute <b>class</b> in a <b>breakpointListener</b> element must be a fully qualifed name of a Java class that implements <b>org.eclipse.jdt.debug.core.IJavaBreakpointListener</b>.</li> +<li>Listeners are added to and removed from a breakpoint programmatically. See <code>IJavaBreakpoint.addBreakpointListener(String id)</code> and <code>IJavaBreakpoint.removeBreakpointListener(String id)</code></li> +</p> +<br> + + + + + + + + + None + + + + + + + + + Copyright (c) 2009 IBM Corporation and others.<br> + +This program and the accompanying materials are made +available under the terms of the Eclipse Public License 2.0 which +accompanies this distribution, and is available at +<a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-v20.html</a>/ + +SPDX-License-Identifier: EPL-2.0 + + + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/javaLogicalStructures.exsd b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/javaLogicalStructures.exsd new file mode 100644 index 0000000000..9e7583135f --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/javaLogicalStructures.exsd @@ -0,0 +1,184 @@ + + + + + + + + + This extension point allows developers to define a logical structure for Java objects of a specified type. The logical value is created by evaluating the provided code snippet. + + + + + + + + + + + + a fully qualified identifier of the target extension point + + + + + + + an optional identifier of the extension instance + + + + + + + an optional name of the extension instance + + + + + + + + + + + + + + + Fully qualified name of the type. + + + + + + + + + + specify if this Java logical structure should be used also for the objects of a subtype of the specified type, or only for the objects of the specified type. This attribute is optional, the default value is <code>true</code>. + + + + + + + The code snippet to evaluate to create the logical value. This attribute is optional, if unspecified, the extension must declare one or more variables. + + + + + + + a description of this logical structure. + + + + + + + + + + + + + One variable of the logical value for the object of this type. + + + + + + + The name of the variable which will be created + + + + + + + The code snippet which will be evaluated as the value of the variable + + + + + + + + + + + + 3.1 + + + + + + + + + Following is an example of a Java logical structure extension point with two structures: + +<p> +<pre> +<extension point="org.eclipse.jdt.debug.javaLogicalStructures"> + <javaLogitalStructure + subtypes="true" + value="return entrySet().toArray();" + type="java.util.Map"/> + <javaLogitalStructure + subtypes="true" + type="java.util.Map$Entry"> + <variable + value="return getKey();" + name="key"/> + <variable + value="return getValue();" + name="value"/> + </javaLogitalStructure> +</extension> +</pre> +</p> + +In the example above a Map is translated into its entries and a Map$Entry is translated into its key and value. + + + + + + + + + [Enter API information here.] + + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + Copyright (c) 2004, 2005 IBM Corporation and others.<br> + +This program and the accompanying materials are made +available under the terms of the Eclipse Public License 2.0 which +accompanies this distribution, and is available at +<a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-v20.html</a>/ + +SPDX-License-Identifier: EPL-2.0 + + + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/jdiclient.exsd b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/jdiclient.exsd new file mode 100644 index 0000000000..097dbbac90 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/schema/jdiclient.exsd @@ -0,0 +1,104 @@ + + + + + + + + + This is an internal extension point specifying the JDI implementation to use with the Java debugger. Clients are not intended to use this extension point. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The name of the extension point is the fully qualified name of a Java class implementing <code>com.sun.jdi.VirtualMachineManager</code> used to bootstrap the JDI implementation. + + + + + + + + + + + + + + + 2.0 + + + + + + + + + The JDI client used by the Java debugger, is by default the JDI implementation that is provided with the Eclipse SDK: +<pre> + <extension-point id="jdiclient" name="org.eclipse.jdi.internal.VirtualMachineManagerImpl"/> +</pre> + + + + + + + + + The name of the extension point is the fully qualified name of a Java class implementing <code>com.sun.jdi.VirtualMachineManager</code>. + + + + + + + + + The Java debugger provides an implementation of <code>com.sun.jdi.VirtualMachineManager</code> + + + + + + + + + Copyright (c) 2002, 2005 IBM Corporation and others.<br> + +This program and the accompanying materials are made +available under the terms of the Eclipse Public License 2.0 which +accompanies this distribution, and is available at +<a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-v20.html</a>/ + +SPDX-License-Identifier: EPL-2.0 + + + + diff --git a/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/scripts/exportplugin.xml b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/scripts/exportplugin.xml new file mode 100644 index 0000000000..4bd1b074aa --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/org.eclipse.jdt.debug/scripts/exportplugin.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tycho-its/projects/api-tools/single-jar/pom.xml b/tycho-its/projects/api-tools/single-jar/pom.xml new file mode 100644 index 0000000000..63cc445db1 --- /dev/null +++ b/tycho-its/projects/api-tools/single-jar/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + org.eclipse.tycho.tycho-its + apitools-parent + 0.0.1-SNAPSHOT + pom + + org.eclipse.jdt.debug + + + 5.0.0-SNAPSHOT + https://download.eclipse.org/releases/2023-09/ + https://download.eclipse.org/eclipse/updates/4.29/R-4.29-202309031000/ + + + + platform + ${target-platform} + p2 + + + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho-version} + true + + + org.eclipse.tycho + tycho-apitools-plugin + ${tycho-version} + + + + baseline + ${baselineRepo} + + + + + + generate + + generate + + + + analyse + + verify + + + + + + + \ No newline at end of file diff --git a/tycho-its/repositories/api-tools/artifacts.xml b/tycho-its/repositories/api-tools/artifacts.xml index a5e050e8e6..90bee66822 100644 --- a/tycho-its/repositories/api-tools/artifacts.xml +++ b/tycho-its/repositories/api-tools/artifacts.xml @@ -66,5 +66,18 @@ + + + + + + + + + + + + + diff --git a/tycho-its/repositories/api-tools/content.xml b/tycho-its/repositories/api-tools/content.xml index c9568f90e2..ca607e2112 100644 --- a/tycho-its/repositories/api-tools/content.xml +++ b/tycho-its/repositories/api-tools/content.xml @@ -192,6 +192,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true Bundle-Version: 3.21.100.v20230728-0612 + + + + diff --git a/tycho-its/repositories/api-tools/plugins/org.eclipse.jdt.debug_3.21.100.v20230728-0612.jar b/tycho-its/repositories/api-tools/plugins/org.eclipse.jdt.debug_3.21.100.v20230728-0612.jar new file mode 100644 index 0000000000..5f1f11b9d2 Binary files /dev/null and b/tycho-its/repositories/api-tools/plugins/org.eclipse.jdt.debug_3.21.100.v20230728-0612.jar differ diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/apitools/ApiToolsTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/apitools/ApiToolsTest.java index e8a9bfe127..5f0c8a3703 100644 --- a/tycho-its/src/test/java/org/eclipse/tycho/test/apitools/ApiToolsTest.java +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/apitools/ApiToolsTest.java @@ -124,4 +124,22 @@ public void testNoBin() throws Exception { verifier.executeGoals(List.of("clean", "verify")); verifier.verifyErrorFreeLog(); } + + /** + * This test an api compare where there is a single jar that makes up the + * bundle, the expectation is that everything works and no API errors are + * reported, in case of problems some invalid API error are reported similar to + * "The type org.eclipse.jdt.debug.eval.IEvaluationResult has been removed from + * org.eclipse.jdt.debug" + * + * @throws Exception + */ + @Test + public void testSingleJar() throws Exception { + Verifier verifier = getVerifier("api-tools/missing-bin", true, true); + File repo = ResourceUtil.resolveTestResource("repositories/api-tools"); + verifier.addCliOption("-DbaselineRepo=" + repo.toURI()); + verifier.executeGoals(List.of("clean", "verify")); + verifier.verifyErrorFreeLog(); + } }