JIT-ting Swift


(Alex Denisov) #1

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904

···

--
AlexDenisov
Software Engineer, https://lowlevelbits.org


(Brian Gesiak) #2

I think this is the best mailing list for your question, but as for a
mailing list dedicated to swift-corelibs-xctest:
swift-corelibs-dev@swift.org is for corelibs-libdispatch,
corelibs-foundation, and corelibs-xctest.

- Brian Gesiak

···

On Mon, Mar 6, 2017 at 12:33 PM, Alex Denisov via swift-dev < swift-dev@swift.org> wrote:

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/
swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to
the way Swift treats the command line arguments. Or, to be more precise, to
the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using
JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8*
}>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the
'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(Robert Widmann) #3

%Sp is not an argument, it is the space necessary to hold a reference to the CommandLine enumeration's static argv member.

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318. Do you have a trace for the crash?

~Robert Widmann

2017/03/06 12:33、Alex Denisov via swift-dev <swift-dev@swift.org> のメッセージ:

···

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(Alex Denisov) #4

The `main` entry point ought to be a standard C "main" function. The argv argument is an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, which ought to be ABI-compatible with a char** in C.

That was my assumption when I started, thank you for confirmation :slight_smile:

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318.

Hm, can you tell a bit more about this? I do not load the runtime, my crash may be caused by something not being initialized.
Here is my simplified use-case: I compile a swift project with tests into bitcode, then I load the bitcode into memory, and then compile and execute a program using ORC JIT.

Do you have a trace for the crash?

Sure, here it is: https://gist.github.com/AlexDenisov/2a8d9b0d391de73a97bce9e33a650f0f#file-trace-txt-L22-L42

···

On 6 Mar 2017, at 20:14, Robert Widmann <devteam.codafi@gmail.com> wrote:

%Sp is not an argument, it is the space necessary to hold a reference to the CommandLine enumeration's static argv member.

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318. Do you have a trace for the crash?

~Robert Widmann

2017/03/06 12:33、Alex Denisov via swift-dev <swift-dev@swift.org> のメッセージ:

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

--
AlexDenisov
Software Engineer, https://lowlevelbits.org


(Robert Widmann) #5

We used to have a callback in the standard library that would set the process arguments, but that approach was fragile and would still have broken here. Instead, we load the Swift standard library (a step we would have had to do anyway) before entering main and call out to platform-specific functions that grab command line arguments. Because you’re running on Linux, we’re asking /proc/self/cmdline, but I’m not sure how exactly that interacts with the JIT. If you’re going to JIT, you should at least follow our lead here by loading the standard library which will in turn load the stubs. You can override the platform-specific getters by calling out to _swift_stdlib_overrideUnsafeArgvArgc <https://github.com/apple/swift/blob/adc54c8a4d13fbebfeb68244bac401ef2528d6d0/stdlib/public/SwiftShims/RuntimeStubs.h#L40>.

···

On Mar 6, 2017, at 3:14 PM, Alex Denisov <1101.debian@gmail.com> wrote:

The `main` entry point ought to be a standard C "main" function. The argv argument is an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, which ought to be ABI-compatible with a char** in C.

That was my assumption when I started, thank you for confirmation :slight_smile:

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318.

Hm, can you tell a bit more about this? I do not load the runtime, my crash may be caused by something not being initialized.
Here is my simplified use-case: I compile a swift project with tests into bitcode, then I load the bitcode into memory, and then compile and execute a program using ORC JIT.

Do you have a trace for the crash?

Sure, here it is: https://gist.github.com/AlexDenisov/2a8d9b0d391de73a97bce9e33a650f0f#file-trace-txt-L22-L42

On 6 Mar 2017, at 20:14, Robert Widmann <devteam.codafi@gmail.com> wrote:

%Sp is not an argument, it is the space necessary to hold a reference to the CommandLine enumeration's static argv member.

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318. Do you have a trace for the crash?

~Robert Widmann

2017/03/06 12:33、Alex Denisov via swift-dev <swift-dev@swift.org> のメッセージ:

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

--
AlexDenisov
Software Engineer, https://lowlevelbits.org


(Alex Denisov) #6

Thank you everybody for your hints and suggestions. It helped me a lot!
I have found the source of the crash I’ve been facing recently.

I run a program by passing argc=1 and argv=[“foo”]. For some reason the 'program under JIT’ was getting argc=2.
Based on this number it creates an array of strings, to fulfil the CommandLine.arguments, which fails because there is only one string argument passed.
So far I use a workaround: I call the main function with argc=1 and argv=[“foo”, “bar”] and everything works just fine.
The next would be to actually utilize the _swift_stdlib_overrideUnsafeArgvArgc to pass arguments.

However, there is one open question: why the JITted program sees ‘argc' as ‘2'?

···

On 6 Mar 2017, at 21:37, Robert Widmann <devteam.codafi@gmail.com> wrote:

We used to have a callback in the standard library that would set the process arguments, but that approach was fragile and would still have broken here. Instead, we load the Swift standard library (a step we would have had to do anyway) before entering main and call out to platform-specific functions that grab command line arguments. Because you’re running on Linux, we’re asking /proc/self/cmdline, but I’m not sure how exactly that interacts with the JIT. If you’re going to JIT, you should at least follow our lead here by loading the standard library which will in turn load the stubs. You can override the platform-specific getters by calling out to _swift_stdlib_overrideUnsafeArgvArgc.

On Mar 6, 2017, at 3:14 PM, Alex Denisov <1101.debian@gmail.com> wrote:

The `main` entry point ought to be a standard C "main" function. The argv argument is an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, which ought to be ABI-compatible with a char** in C.

That was my assumption when I started, thank you for confirmation :slight_smile:

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318.

Hm, can you tell a bit more about this? I do not load the runtime, my crash may be caused by something not being initialized.
Here is my simplified use-case: I compile a swift project with tests into bitcode, then I load the bitcode into memory, and then compile and execute a program using ORC JIT.

Do you have a trace for the crash?

Sure, here it is: https://gist.github.com/AlexDenisov/2a8d9b0d391de73a97bce9e33a650f0f#file-trace-txt-L22-L42

On 6 Mar 2017, at 20:14, Robert Widmann <devteam.codafi@gmail.com> wrote:

%Sp is not an argument, it is the space necessary to hold a reference to the CommandLine enumeration's static argv member.

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318. Do you have a trace for the crash?

~Robert Widmann

2017/03/06 12:33、Alex Denisov via swift-dev <swift-dev@swift.org> のメッセージ:

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

--
AlexDenisov
Software Engineer, https://lowlevelbits.org

--
AlexDenisov
Software Engineer, https://lowlevelbits.org


(Greg Parker) #7

What exactly does your code that 'passes argc=1 and argv=["foo"]' look like? Did you null-terminate argv as is required?

···

On Mar 10, 2017, at 1:45 AM, Alex Denisov via swift-dev <swift-dev@swift.org> wrote:

Thank you everybody for your hints and suggestions. It helped me a lot!
I have found the source of the crash I’ve been facing recently.

I run a program by passing argc=1 and argv=[“foo”]. For some reason the 'program under JIT’ was getting argc=2.
Based on this number it creates an array of strings, to fulfil the CommandLine.arguments, which fails because there is only one string argument passed.
So far I use a workaround: I call the main function with argc=1 and argv=[“foo”, “bar”] and everything works just fine.
The next would be to actually utilize the _swift_stdlib_overrideUnsafeArgvArgc to pass arguments.

However, there is one open question: why the JITted program sees ‘argc' as ‘2'?

On 6 Mar 2017, at 21:37, Robert Widmann <devteam.codafi@gmail.com> wrote:

We used to have a callback in the standard library that would set the process arguments, but that approach was fragile and would still have broken here. Instead, we load the Swift standard library (a step we would have had to do anyway) before entering main and call out to platform-specific functions that grab command line arguments. Because you’re running on Linux, we’re asking /proc/self/cmdline, but I’m not sure how exactly that interacts with the JIT. If you’re going to JIT, you should at least follow our lead here by loading the standard library which will in turn load the stubs. You can override the platform-specific getters by calling out to _swift_stdlib_overrideUnsafeArgvArgc.

On Mar 6, 2017, at 3:14 PM, Alex Denisov <1101.debian@gmail.com> wrote:

The `main` entry point ought to be a standard C "main" function. The argv argument is an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, which ought to be ABI-compatible with a char** in C.

That was my assumption when I started, thank you for confirmation :slight_smile:

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318.

Hm, can you tell a bit more about this? I do not load the runtime, my crash may be caused by something not being initialized.
Here is my simplified use-case: I compile a swift project with tests into bitcode, then I load the bitcode into memory, and then compile and execute a program using ORC JIT.

Do you have a trace for the crash?

Sure, here it is: https://gist.github.com/AlexDenisov/2a8d9b0d391de73a97bce9e33a650f0f#file-trace-txt-L22-L42

On 6 Mar 2017, at 20:14, Robert Widmann <devteam.codafi@gmail.com> wrote:

%Sp is not an argument, it is the space necessary to hold a reference to the CommandLine enumeration's static argv member.

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318. Do you have a trace for the crash?

~Robert Widmann

2017/03/06 12:33、Alex Denisov via swift-dev <swift-dev@swift.org> のメッセージ:

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

--
AlexDenisov
Software Engineer, https://lowlevelbits.org

--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(Alex Denisov) #8

What exactly does your code that 'passes argc=1 and argv=["foo"]' look like? Did you null-terminate argv as is required?

This is exact code I had initially:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

This is the code I have now, working version:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 2;
const char *argv[] = { "mull", "CryptoSwiftTests.DigestTests/testMD5" , NULL };
auto res = main(argc, argv);

···

On 10 Mar 2017, at 22:20, Greg Parker <gparker@apple.com> wrote:

What exactly does your code that 'passes argc=1 and argv=["foo"]' look like? Did you null-terminate argv as is required?

On Mar 10, 2017, at 1:45 AM, Alex Denisov via swift-dev <swift-dev@swift.org> wrote:

Thank you everybody for your hints and suggestions. It helped me a lot!
I have found the source of the crash I’ve been facing recently.

I run a program by passing argc=1 and argv=[“foo”]. For some reason the 'program under JIT’ was getting argc=2.
Based on this number it creates an array of strings, to fulfil the CommandLine.arguments, which fails because there is only one string argument passed.
So far I use a workaround: I call the main function with argc=1 and argv=[“foo”, “bar”] and everything works just fine.
The next would be to actually utilize the _swift_stdlib_overrideUnsafeArgvArgc to pass arguments.

However, there is one open question: why the JITted program sees ‘argc' as ‘2'?

On 6 Mar 2017, at 21:37, Robert Widmann <devteam.codafi@gmail.com> wrote:

We used to have a callback in the standard library that would set the process arguments, but that approach was fragile and would still have broken here. Instead, we load the Swift standard library (a step we would have had to do anyway) before entering main and call out to platform-specific functions that grab command line arguments. Because you’re running on Linux, we’re asking /proc/self/cmdline, but I’m not sure how exactly that interacts with the JIT. If you’re going to JIT, you should at least follow our lead here by loading the standard library which will in turn load the stubs. You can override the platform-specific getters by calling out to _swift_stdlib_overrideUnsafeArgvArgc.

On Mar 6, 2017, at 3:14 PM, Alex Denisov <1101.debian@gmail.com> wrote:

The `main` entry point ought to be a standard C "main" function. The argv argument is an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>, which ought to be ABI-compatible with a char** in C.

That was my assumption when I started, thank you for confirmation :slight_smile:

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318.

Hm, can you tell a bit more about this? I do not load the runtime, my crash may be caused by something not being initialized.
Here is my simplified use-case: I compile a swift project with tests into bitcode, then I load the bitcode into memory, and then compile and execute a program using ORC JIT.

Do you have a trace for the crash?

Sure, here it is: https://gist.github.com/AlexDenisov/2a8d9b0d391de73a97bce9e33a650f0f#file-trace-txt-L22-L42

On 6 Mar 2017, at 20:14, Robert Widmann <devteam.codafi@gmail.com> wrote:

%Sp is not an argument, it is the space necessary to hold a reference to the CommandLine enumeration's static argv member.

When JIT'ing Swift, the value of argv doesn't matter because we replace the process' arguments dynamically https://github.com/apple/swift/blob/master/lib/Immediate/Immediate.cpp#L318. Do you have a trace for the crash?

~Robert Widmann

2017/03/06 12:33、Alex Denisov via swift-dev <swift-dev@swift.org> のメッセージ:

Hi there,

I could not find a list for swift-corelibs-xctest so I am posting it here.

I am trying to run tests based on XCTest (https://github.com/apple/swift-corelibs-xctest) using LLVM's JIT.
Everything is working good so far. However, I am getting a crash.
Based on a shallow investigation I can see that this is somehow related to the way Swift treats the command line arguments. Or, to be more precise, to the way I pass the arguments to the swift's 'main' function.

What I did so far is not different from what I do to run C or C++ using JIT:

auto main = ((int (*)(int, const char **))(intptr_t)mainPointer);
const int argc = 1;
const char *argv[] = { "some-name", NULL };
auto result = main(argc, argv);

Based on what I see in the IR[1] the 'argv' has type "%Sp = type <{ i8* }>", which seems to be a struct with a pointer to something.

So the question is: what is being passed as a second argument to the 'main' function of a swift program?

Any other advice on JIT-ting Swift are more than welcome :slight_smile:

[1] https://gist.github.com/AlexDenisov/3c10540b544e82cfb6e58e1452491904
--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

--
AlexDenisov
Software Engineer, https://lowlevelbits.org

--
AlexDenisov
Software Engineer, https://lowlevelbits.org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev