compilation - How does the Julia JIT compiler handle return values from functions? - Stack Overflow

admin2025-05-02  0

I am trying to get a better conceptual understanding of how the Julia JIT compilation process (perhaps better phrased as "compilation sequence") works.

Specifically, I am interested to know how Julia handles function return values.

For context, I am coming from this from a background of C/C++/x86 ASM.

Allow me to describe, briefly, how compilation of functions works in this context. My explanation will not be particularly detailed, but I hope it will be sufficient to illustrate the point.

Let's consider the following C++ code.

void example_function() {
    auto tmp = another_function();
    std::cout << tmp << std::endl;
    return;
}

std::vector<double> another_function() {
    std::vector<double> tmp;
    tmp.push_back(1.0);
    return tmp;
}

Here is a list of the important concepts illustrated in this example.

  • The example shows one function calling another function
  • The type of the return value of the called function is known std::vector<double>
  • This return value has static size on the stack, and is known at compile time
  • Don't be distracted by the cout statement - just assume an implementation of std::cout for a std::vector<double> is provided somewhere. It's just there to illustrate the return value being used for something

In a static language such as C++, the return value types are known at compile time. Typically, the compiler will allocate some space on the stack for the return value before calling a function.

In this example, before calling another_function, the compiler typically will push a block of stack memory onto the stack. The size of this block is large enough to hold the return value. This size is known at compile time, because the compiler knows (at compile time) the return type, and therefore the size of the return type.

Typically the compiler will do this "stack push" operation by adding (or subtracting?) from the stack pointer. (If I recall correctly?)

The point is, the return value size is known at compile time.

How does this work in Julia?

A Julia function can return multiple types. Here are some questions:

  • Is the returned value from a Julia function call stored on the stack in the same way as other languages?
  • How does the Julia JIT know how much space should be allocated for a return value?
  • Does it perform some kind of search to follow all code paths to figure out what the set of possible return types is, creating enough space for the largest of these?

I am trying to get a better conceptual understanding of how the Julia JIT compilation process (perhaps better phrased as "compilation sequence") works.

Specifically, I am interested to know how Julia handles function return values.

For context, I am coming from this from a background of C/C++/x86 ASM.

Allow me to describe, briefly, how compilation of functions works in this context. My explanation will not be particularly detailed, but I hope it will be sufficient to illustrate the point.

Let's consider the following C++ code.

void example_function() {
    auto tmp = another_function();
    std::cout << tmp << std::endl;
    return;
}

std::vector<double> another_function() {
    std::vector<double> tmp;
    tmp.push_back(1.0);
    return tmp;
}

Here is a list of the important concepts illustrated in this example.

  • The example shows one function calling another function
  • The type of the return value of the called function is known std::vector<double>
  • This return value has static size on the stack, and is known at compile time
  • Don't be distracted by the cout statement - just assume an implementation of std::cout for a std::vector<double> is provided somewhere. It's just there to illustrate the return value being used for something

In a static language such as C++, the return value types are known at compile time. Typically, the compiler will allocate some space on the stack for the return value before calling a function.

In this example, before calling another_function, the compiler typically will push a block of stack memory onto the stack. The size of this block is large enough to hold the return value. This size is known at compile time, because the compiler knows (at compile time) the return type, and therefore the size of the return type.

Typically the compiler will do this "stack push" operation by adding (or subtracting?) from the stack pointer. (If I recall correctly?)

The point is, the return value size is known at compile time.

How does this work in Julia?

A Julia function can return multiple types. Here are some questions:

  • Is the returned value from a Julia function call stored on the stack in the same way as other languages?
  • How does the Julia JIT know how much space should be allocated for a return value?
  • Does it perform some kind of search to follow all code paths to figure out what the set of possible return types is, creating enough space for the largest of these?
Share Improve this question edited Jan 3 at 9:09 user2138149 asked Jan 2 at 14:13 user2138149user2138149 18k31 gold badges151 silver badges300 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 4

To make a long story short, there are basically two flavors of Julia functions: those where the return type can be inferred, and those where it can't be. When it can be, then you basically get the equivalent of a C++ function. When it can't be, or it's known to be one of several types, then the return value gets boxed and you lose a lot of performance.

To give a slightly longer answer, the answer to this depends on the calling convention that the compiler chooses to use for the function. Julia's compiler will choose a calling convention based on what it knows about the function. If it doesn't know the input types that the function will be called with, it will "box" all the arguments and return value (basically putting them in a heap allocated object that stores the type). However, most of the time, the compiler is able to figure out what the code is doing (via type inference), and can use a specialized calling convention for the argument types.

转载请注明原文地址:http://anycun.com/QandA/1746115370a91882.html