Skip to content

8360389: Support printing from C2 compiled code #26475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from

Conversation

benoitmaillard
Copy link
Contributor

@benoitmaillard benoitmaillard commented Jul 25, 2025

This PR adds support for printf-style from C2 compiled code. This is implemented as a runtime call to a C++ method that prints the values of the nodes passed as arguments. The runtime C++ method is with the help of variadic templates, as it is expected to support various combination of argument types.

Usage

Suppose we have the following java code:

public class HelloWorld {
    public static void main(String[] args) {
        testMethod(new int[]{0, 1, 2, 3, 4}, "Hello there!", Long.MAX_VALUE,  172);
    }

    static boolean testMethod(int[] array, String o, long l, int x) {
        return array.length > 0 || o.length() > 2 || l > 0 || x > 0;
    }
}

We can attempt to print several things using the debug node. Here are two examples:

Printing arguments

Let's change the Compile::return_values method as follows. We can extract the argument nodes in a static array and then pass them to GraphKit::make_debug_print along with a static string.

//--------------------------return_values--------------------------------------
void Compile::return_values(JVMState* jvms) {
  GraphKit kit(jvms);

  // <---- debug node definition
  Node* args[5];
  uint pos = 0;
  StartNode* start_node = start();
  for (DUIterator_Fast imax, i = start_node->fast_outs(imax); i < imax; i++) {
    if (pos > TypeFunc::Parms) {
      args[pos - TypeFunc::Parms - 1] = start_node->fast_out(i);
    }
    pos++;
  }

  Node* test = kit.make_debug_print<oopDesc*, oopDesc*, jlong, jint>("arguments: ",
                                                                        args[0],          // int[]
                                                                        args[1],          // String
                                                                        args[2], args[3], // long
                                                                        args[4]);         // int
  record_for_igvn(test);
  initial_gvn()->transform(test);
  // <---- end of debug node definition

  Node* ret = new ReturnNode(TypeFunc::Parms,
                             kit.control(),
                             kit.i_o(),
                             kit.reset_memory(),
                             kit.frameptr(),
                             kit.returnadr());
...

Printing the return value

Similarly, we can extract the return value and pass it to GraphKit::make_debug_print:

//--------------------------return_values--------------------------------------
void Compile::return_values(JVMState* jvms) {
  GraphKit kit(jvms);

  // <---- debug node definition
  Node* return_value = kit.argument(-1);
  Node* test = kit.make_debug_print<jboolean>("return value: ", return_value);
  record_for_igvn(test);
  initial_gvn()->transform(test);
  // <---- end of debug node definition

  Node* ret = new ReturnNode(TypeFunc::Parms,
                             kit.control(),
                             kit.i_o(),
                             kit.reset_memory(),
                             kit.frameptr(),
                             kit.returnadr());
...

Running the code

We can then execute either example as follows:

java -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,HelloWorld::testMethod -XX:-TieredCompilation -Xcomp HelloWorld.java

We obtain the following output for the arguments example:

values: [I 
{0x000000042a96df90} - klass: {type array int} - flags: is_cloneable_fast 

 - length: 5
 -   0: 0x0 0
 -   1: 0x1 1
 -   2: 0x2 2
 -   3: 0x3 3
 -   4: 0x4 4
java.lang.String 
{0x000000042a96dfb8} - klass: 'java/lang/String' - flags: 

 - string: "Hello there!"
 - ---- fields (total size 3 words):
 - private 'hash' 'I' @12  0 (0x00000000)
 - private final 'coder' 'B' @16  0 (0x00)
 - private 'hashIsZero' 'Z' @17  false (0x00)
 - injected 'flags' 'B' @18  0 (0x00)
 - private final 'value' '[B' @20  [B{0x000000042a96dfd0} (0x8552dbfa)
[9223372036854775807] [172]

Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8360389: Support printing from C2 compiled code (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/26475/head:pull/26475
$ git checkout pull/26475

Update a local copy of the PR:
$ git checkout pull/26475
$ git pull https://git.openjdk.org/jdk.git pull/26475/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 26475

View PR using the GUI difftool:
$ git pr show -t 26475

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/26475.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Jul 25, 2025

👋 Welcome back bmaillard! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Jul 25, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk bot changed the title 8360389 8360389: Support printing from C2 compiled code Jul 25, 2025
@openjdk
Copy link

openjdk bot commented Jul 25, 2025

@benoitmaillard The following label will be automatically applied to this pull request:

  • hotspot

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

Copy link
Member

@TobiHartmann TobiHartmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work Benoît! This will be very useful for debugging.

With the current changes, we only support adding printing during parsing, i.e. when GraphKit is available. I think it would be great if we could add printing after parsing, for example only once a specific IGVN or loop optimization happened. Do you think that's feasible?

void OptoRuntime::debug_print_convert_type(const Type** fields, int* argp, Node *parm) {
switch (parm->bottom_type()->basic_type()) {
case T_BOOLEAN:
fields[(*argp)++] = TypeInt::BOOL;
Copy link
Member

@TobiHartmann TobiHartmann Jul 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use Type::get_const_basic_type(parm->bottom_type()->basic_type()) here and special case T_DOUBLE / T_LONG.

fields[(*argp)++] = Type::HALF;
break;
case T_OBJECT:
fields[(*argp)++] = TypePtr::NOTNULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think passing null should be okay as well, right? I would use TypeInstPtr::BOTTOM here, which will be taking care of by Type::get_const_basic_type.

int flags = RC_LEAF;
address call_addr = CAST_FROM_FN_PTR(address, SharedRuntime::debug_print<TT...>);

Node* str_node = new ConPNode(TypeRawPtr::make(((address) str)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need a transform here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

2 participants