[Issue 19279] mutable does not promote to shared
https://issues.dlang.org/show_bug.cgi?id=19279 --- Comment #1 from Manu --- Conversation: https://github.com/dlang/dmd/pull/8782 Reveals that `scope` is also necessary to guarantee that the promoted reference does not escape. Promotion is safe so long as no promoted-reference outlives the call where the instance was promoted. struct Bob { void setThing() shared scope; } void f(ref shared Bob a, ref Bob b) { a.setThing(); // I have a shared object, can call shared method b.setThing(); // this should work with `scope` } --
Typo: to not be a warning (n/t)
Typo: to not* be a warning
Re: Warn on unused imports?
On Wednesday, 26 September 2018 at 16:29:24 UTC, Neia Neutuladh wrote: * If you encounter a mixin in the module you're analyzing, give up. Unfortunately, our code uses mixins heavily, so I don't think this would be useful for us. In any case, I fundamentally don't consider the approach of "well if you want *this* side of D, you can't use *that* side of D" an acceptable way to find solutions. To weigh in on the warnings debate, while I generally think that warnings being fine-grained toggleable makes sense, I also think it's correct for this specific feature to be a warning, because it's only useful if you're using D in a certain mode (one-shot recursive compilation of a closed set of source files into a binary), which just happens to also be the mode that most of our code uses. In any case, the linter/compiler separation simply does not make sense for D, simply because the language is under heavy development and having the linter depend on the same frontend as the compiler means you're perennially forced to develop to the intersection subset of compiler-supported features and linter-supported features. Even with a pure-syntax linter like D-Scanner, we've ran into this issue quite recently with the in() contract syntax change causing breakage all over Github. The only sane way to write a semantic linter in D is to ship the DMDFE as a global library with a stable interface that linters can link against, so you can upgrade DMD and get a linter frontend upgrade "for free", or else as a tool shipped with the compiler distro so that it's again linked against the same code. In any case, this approach is still inherently inefficient because you're essentially compiling the *exact same* code twice in a row, since in modern D at least 50% of the time is spent in the frontend. It makes more sense, in my opinion, both from a design and performance perspective to process the information in the natural place it is produced in the first place - the frontend. Making DMD available as a library with a stable API is a good second place. Hell, even allowing DMD plugins to load from the commandline (with a semistable API) would work. Making DMD available as a non version tagged separate package so that you have to rebuild all your tools during a compiler upgrade, manually checkout a specific revision of the DMD repo, hodge together a manual build process because dub, D's native package system can't be used due to some weird insistence on keeping strict semver on the dub side and arbitrarily violating semver on the DMD side, so that you then have to manually run the D compile workflow in order to finally dump some information that you immediately read back in and output as warnings - I cannot see this as a sane approach.
[Issue 19280] New: Remove unnecessary error checks in core.time.currSystemTick
https://issues.dlang.org/show_bug.cgi?id=19280 Issue ID: 19280 Summary: Remove unnecessary error checks in core.time.currSystemTick Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: druntime Assignee: nob...@puremagic.com Reporter: n8sh.second...@hotmail.com Microsoft Windows QueryPerformanceCounter doesn't fail on Windows XP or later. https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx Posix gettimeofday called with a valid timeval address and a null second parameter doesn't fail. http://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html Posix clock_gettime called with a valid clock_id and a valid timespec address is in principle allowed to fail if the number of seconds doesn't fit in time_t, so even though no known implementation does this it is probably best to retain the error check at this time. http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html --
Re: `shared`...
On Monday, 1 October 2018 at 04:22:24 UTC, Manu wrote: Ah, good point. So, it could only be allowed if scope... struct Bob { void setThing() shared scope; } That's going to require far-reaching proliferation of `scope`. Do we infer `scope` like the other attributes? For templates (either the function or the struct it is in) and auto returning functions, I think so: definitely under -dip1000, probably also when not using -dip1000. The default for `scope` is totally backwards. :/ Alas, such is the nature of retrofitting.
Re: `shared`...
On Sun, Sep 30, 2018 at 9:00 PM Nicholas Wilson via Digitalmars-d wrote: > > On Monday, 1 October 2018 at 03:33:16 UTC, Manu wrote: > > On Sun, Sep 30, 2018 at 8:20 PM Nicholas Wilson via > > Digitalmars-d wrote: > >> > >> On Monday, 1 October 2018 at 02:29:40 UTC, Manu wrote: > >> > struct Bob > >> > { > >> > void setThing() shared; > >> > } > >> > > >> > As I understand, `shared` attribution intends to guarantee > >> > that > >> > I dun > >> > synchronisation internally. > >> > This method is declared shared, so if I have shared > >> > instances, > >> > I can > >> > call it... because it must handle thread-safety internally. > >> > >> seems reasonable > >> > >> https://github.com/dlang/dmd/pull/8782 > > > > Haha, sneaky bugger :P > > I reckon the patch is gonna be a lot bigger than that though! > > Of course, there will be updating the test suite. And Walter will > probably tell you to bugzilla this. > > implicit conversion of mutable (i.e. no mods) to const share > should be absolutely no problem, as that it rusts borrowing model > (one owning mutable thread local reference and zero or more non > thread local non-owning const references) and is fine. > > mutable to mutable shared I'm not so sure as references to > otherwise owned references could escape. > > shared Bob* sneaky; > > struct Bob > { >void setSneaky() shared // legit as this is shared > { >sneaky = > } > } > void oblivious(ref shared Bob a, ref Bob b) > { >a.setSneaky(); // Fine > >b. setSneaky(); // would become not an error, but totally not > fine. > } > > unfortunately scope is not a modifier so the PR will have to be > larger, oh well. Ah, good point. So, it could only be allowed if scope... struct Bob { void setThing() shared scope; } That's going to require far-reaching proliferation of `scope`. Do we infer `scope` like the other attributes? The default for `scope` is totally backwards. :/
[Issue 19279] New: mutable does not promote to shared
https://issues.dlang.org/show_bug.cgi?id=19279 Issue ID: 19279 Summary: mutable does not promote to shared Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: turkey...@gmail.com struct Bob { void setThing() shared; } As I understand, `shared` attribution intends to guarantee that I dun synchronisation internally. This method is declared shared, so if I have shared instances, I can call it... because it must handle thread-safety internally. void f(ref shared Bob a, ref Bob b) { a.setThing(); // I have a shared object, can call shared method b.setThing(); // ERROR } The method is shared, which suggests that it must handle thread-safety. My instance `b` is NOT shared, that is, it is thread-local. A method that handles thread-safety doesn't not work when it's only accessed from a single thread. mutable -> shared should work the same as mutable -> const... because surely that's safe? --
Re: `shared`...
On Monday, 1 October 2018 at 03:33:16 UTC, Manu wrote: On Sun, Sep 30, 2018 at 8:20 PM Nicholas Wilson via Digitalmars-d wrote: On Monday, 1 October 2018 at 02:29:40 UTC, Manu wrote: > struct Bob > { > void setThing() shared; > } > > As I understand, `shared` attribution intends to guarantee > that > I dun > synchronisation internally. > This method is declared shared, so if I have shared > instances, > I can > call it... because it must handle thread-safety internally. seems reasonable https://github.com/dlang/dmd/pull/8782 Haha, sneaky bugger :P I reckon the patch is gonna be a lot bigger than that though! Of course, there will be updating the test suite. And Walter will probably tell you to bugzilla this. implicit conversion of mutable (i.e. no mods) to const share should be absolutely no problem, as that it rusts borrowing model (one owning mutable thread local reference and zero or more non thread local non-owning const references) and is fine. mutable to mutable shared I'm not so sure as references to otherwise owned references could escape. shared Bob* sneaky; struct Bob { void setSneaky() shared // legit as this is shared { sneaky = } } void oblivious(ref shared Bob a, ref Bob b) { a.setSneaky(); // Fine b. setSneaky(); // would become not an error, but totally not fine. } unfortunately scope is not a modifier so the PR will have to be larger, oh well.
Re: `shared`...
On Sun, Sep 30, 2018 at 8:20 PM Nicholas Wilson via Digitalmars-d wrote: > > On Monday, 1 October 2018 at 02:29:40 UTC, Manu wrote: > > struct Bob > > { > > void setThing() shared; > > } > > > > As I understand, `shared` attribution intends to guarantee that > > I dun > > synchronisation internally. > > This method is declared shared, so if I have shared instances, > > I can > > call it... because it must handle thread-safety internally. > > seems reasonable > > https://github.com/dlang/dmd/pull/8782 Haha, sneaky bugger :P I reckon the patch is gonna be a lot bigger than that though!
Re: `shared`...
On Monday, 1 October 2018 at 02:29:40 UTC, Manu wrote: struct Bob { void setThing() shared; } As I understand, `shared` attribution intends to guarantee that I dun synchronisation internally. This method is declared shared, so if I have shared instances, I can call it... because it must handle thread-safety internally. seems reasonable https://github.com/dlang/dmd/pull/8782
`shared`...
struct Bob { void setThing() shared; } As I understand, `shared` attribution intends to guarantee that I dun synchronisation internally. This method is declared shared, so if I have shared instances, I can call it... because it must handle thread-safety internally. void f(ref shared Bob a, ref Bob b) { a.setThing(); // I have a shared object, can call shared method b.setThing(); // ERROR } This is the bit of the design that doesn't make sense to me... The method is shared, which suggests that it must handle thread-safety. My instance `b` is NOT shared, that is, it is thread-local. So, I know that there's not a bunch of threads banging on this object... but the shared method should still work! A method that handles thread-safety doesn't suddenly not work when it's only accessed from a single thread. I feel like I don't understand the design... mutable -> shared should work the same as mutable -> const... because surely that's safe? I'm not sure what the intended use here is... for every method I write `shared`, I also need a non-shared shim that casts `` to shared, and calls through... and that's just pointless and noisy busy-work. The only reason I should have to overload for mutable and shared is when I want to implement a non-thread-safe overload for performance when interacting with non-shared instances.
[Issue 19278] extern(C++, "name") doesn't accept expressions
https://issues.dlang.org/show_bug.cgi?id=19278 --- Comment #1 from Manu --- String expressions don't work (obviously) ``` extern (C++, "std" ~ (UseCxx11Namespace ? "::__1" : "")): ``` --
[Issue 19278] extern(C++, "name") doesn't accept expressions
https://issues.dlang.org/show_bug.cgi?id=19278 Manu changed: What|Removed |Added Keywords||C++ Hardware|x86 |All OS|Windows |All --
[Issue 19278] New: extern(C++, "name") doesn't accept expressions
https://issues.dlang.org/show_bug.cgi?id=19278 Issue ID: 19278 Summary: extern(C++, "name") doesn't accept expressions Product: D Version: D2 Hardware: x86 OS: Windows Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: turkey...@gmail.com Consider: ``` version (A) enum NS = "something"; else enum NS = "something_else"; extern(C++, NS): //... ``` In this example, the parser sees an identifier and assumes that to be the name for the namespace, rather than check if it's an expression that evaluates to a string. I think it should attempt to evaluate the expression as a string. It could be argued that may be ambiguous, but this isn't: ``` string GetNs() { version (A) { return "A"; } else { return "B"; } } extern(C++, GetNs()): ``` There's also this: ``` alias NS = AliasSeq!("A", "B"); extern(C++, NS): ``` That is, do want `extern(C++, "A", "B")` in this case, but again, it looks like an identifier to the parser. Various work-around constructions don't work: ``` version (A) extern(C++, "A"): else extern(C++, "B"): void f(); // <- f is not in any namespace, the externs are scoped inside the version cases ``` ``` mixin(`extern(C++, "NS"):`); void f(); // <- f is not namespaced; it seems the mixin statement has some sort of scope which the extern doesn't escape ``` One of the goals of the string namespace was that you could synthesise the name, so it really just needs to work with expressions. --
[Issue 19258] Cannot @disable ~this()
https://issues.dlang.org/show_bug.cgi?id=19258 --- Comment #5 from Nicholas Wilson --- For structs if no destructor is given then no destructor is compiled. struct S { this(int i){} } extern(C++) S foo() { return S(3); } void main() { import std.traits; import std.stdio; writeln(__traits(allMembers,S)); // Prints: __ctor } For classes, inheritance is involved so you can't disable it anyway. --
Re: lodash like utility/algorithms library for D
On Sunday, 30 September 2018 at 22:17:05 UTC, aliak wrote: On Saturday, 29 September 2018 at 19:27:29 UTC, Paul Backus wrote: I agree that this is useful, but why not just return a naked `SumType!(string, JSONError)` in that case? Is there some additional value added by the `Expect` wrapper that I'm not seeing? That's an option as well I guess. But then you'd need to rely on convention and you couldn't do SumType!(int, int) f(), and Expect also gives you some more purposeful APIs that makes the code's intent clear. Plus I'm considering range behavior as well. Is being able to write `Expect!(int, int)` actually desirable, though? It seems to me like being forced to write something like `SumType!(int, ErrorCode)` to distinguish the two cases would be a good thing, even if ErrorCode itself is just a renamed int (e.g., `struct ErrorCode { int code; alias code this; }`). I guess you could argue that `return typeof(return).unexpected(...)` is better than `return typeof(return)(ErrorCode(...))`, which is what you'd get with SumType, but they look equally ugly to me. What's really needed to make that look nice is implicit constructors. Treating an Expect as a range basically turns it into an Optional, in the sense that it collapses any error information it contains down to the boolean of empty vs not-empty. In fact, probably the easiest way to add range behavior to Expect would be to add a method that returns an Optional containing the expected value, since Optional already has range behavior. Could you also return a union voldermort type then instead of a SumType? Raw unions in D are horrifically unsafe, so I wouldn't recommend it. If you want a voldemort SumType, you can get one like this: auto f() { struct Result { SumType(T, U) data; alias data this; } return Result(...); }
Re: lodash like utility/algorithms library for D
On Saturday, 29 September 2018 at 19:27:29 UTC, Paul Backus wrote: On Saturday, 29 September 2018 at 12:40:14 UTC, aliak wrote: I.e. by allowing you to define the unexepcted you could for instance: enum JSONError { invalidKey, notString, notNumber } auto a = parse(jsonData); a.getAsString("key").match!( (string value) => // yay (JSONError error) => // small domain of what went wrong ); I agree that this is useful, but why not just return a naked `SumType!(string, JSONError)` in that case? Is there some additional value added by the `Expect` wrapper that I'm not seeing? That's an option as well I guess. But then you'd need to rely on convention and you couldn't do SumType!(int, int) f(), and Expect also gives you some more purposeful APIs that makes the code's intent clear. Plus I'm considering range behavior as well. Could you also return a union voldermort type then instead of a SumType?
Re: automem v0.3.5 - now with more vector (like std::vector, not Physics)!
On Thursday, 20 September 2018 at 14:57:42 UTC, Atila Neves wrote: If you've never heard of automem before, I wrote it to have C++-style smart pointers in D that I could use in @nogc code: http://code.dlang.org/packages/automem Sorry for asking here. Shouldn't this code work? import automem; struct X { int i; } struct Y { RefCounted!X x; // fails //X x; // ok } void main() { Y y1; Y y2; y2 = y1; } https://run.dlang.io/is/k2qWhm
Re: Linking with a non-default druntime
On Sunday, 30 September 2018 at 19:03:17 UTC, Per Nordlöw wrote: How can I link my dmd-compiled program with a specific version of the druntime? druntime is within libphobos. So you must change this. I need this when experimenting with a new GC. Did you try what i proposed earlier ? Until the handlers are plugged there can be a fallback to the manual allocs. For example you start with the manual implementation and add handlers + fallback for every functions, like here for malloc ``` __gshared void* function(size_t, uint, const TypeInfo) nothrow mallocHandler; void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow { if (mallocHandler) // experimental stuff { return mallocHandler(size, bits, ti); } else // fallback until handler is assigned { void* p = cstdlib.malloc(size); if (size && p is null) onOutOfMemoryError(); return p; } } ``` this way you can very easily change-compile-test, without recompiling the whole runtime and phobos each time.
Linking with a non-default druntime
How can I link my dmd-compiled program with a specific version of the druntime? I need this when experimenting with a new GC.
[Issue 19277] New: storage class used in alias statement has no effect
https://issues.dlang.org/show_bug.cgi?id=19277 Issue ID: 19277 Summary: storage class used in alias statement has no effect Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: turkey...@gmail.com alias T = ref int; void f(T not_a_ref_arg); This is invalid, but it compiles and gives the user no indication that it's mal-formed... --
[Issue 19258] Cannot @disable ~this()
https://issues.dlang.org/show_bug.cgi?id=19258 --- Comment #4 from Илья Ярошенко --- (In reply to Nicholas Wilson from comment #3) > I'm not sure what the desired effect of @disabling the destructor is > supposed to achieve? If this is for C++ integration either: a) don't declare > it or b) if is required to consume a viable slot declare a dummy function. The reason is to be sure that a D compiler does not compile ~this at all. --
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 14:06:20 UTC, Vinod K Chandran wrote: Thanks. It worked. I would like to compile this as a gui. Now it starts with the cmd. Google search didn't gave me the link i want. Any help ? With the default OPTLINK linker: dmd -L/SUBSYSTEM:windows app.d In this case, user32.lib where MessageBoxW and MessageBoxA reside is automatically linked. When using the MS linker: dmd -m64 -L/SUBSYSTEM:windows -L/ENTRY:mainCRTStartup app.d user32.lib In this case, user32.lib is not automatically linked. Replace -m64 with -m32mscoff for 32-bit output with the MS linker. -L passes command line options to the current linker.
Re: inline ASM function calling conventions.
On Sunday, 30 September 2018 at 12:32:08 UTC, kinke wrote: 1) `asm {}` is supported by DMD and LDC, but not by GDC. Good to know. Guess I will be targeting DMD and LDC then. 4) For x86_64, there are 2 (completely different) ABIs, Win64 and the System V one. Specs can be found online. In your case: void Foo(MyStrunct* first_arg, MyStrunct* second_arg) { asm { naked; } version (D_InlineAsm_X86) { // first_arg is on the stack, at [ESP+4] // second_arg is in EAX } else version (D_InlineAsm_X86_64) { version (Win64) { // first_arg is in RDX // second_arg is in RCX } else { // first_arg is in RSI // second_arg is in RDI } } } So in X86 asm, if I want to pas two parameters to a function I can have one in a register, but not two. The second will go via the stack. But on X86_64 it won't? Guess I'll just have to live with that. Thank you!
Re: inline ASM function calling conventions.
On Sunday, 30 September 2018 at 12:07:53 UTC, Basile B. wrote: On Sunday, 30 September 2018 at 11:53:17 UTC, Basile B. wrote: Hello, i think this should be here (https://dlang.org/spec/abi.html) because myself i never remember them correctly without playing a bit with a disassembler. After playing a bit: Thank you for the link, very informative! I'm spitting it through right now. Without all the save/restore BS: module runnable; import std.stdio; alias write4Int = writeln!(int,int,int,int); struct MyStruct{int i;} extern(D) void foo(ref MyStruct s1, ref MyStruct s2, ref MyStruct s3, ref MyStruct s4) { asm { naked; mov RCX, MyStruct.i.offsetof[RCX]; mov RDX, MyStruct.i.offsetof[RDX]; mov RSI, MyStruct.i.offsetof[RSI]; mov RDI, MyStruct.i.offsetof[RDI]; callwrite4Int; ret; } } void main() { MyStruct s1 = MyStruct(1); MyStruct s2 = MyStruct(2); MyStruct s3 = MyStruct(3); MyStruct s4 = MyStruct(4); foo(s1, s2, s3, s4); } In X86_64 it works beautiful! But in X86 it will pass them via the stack, and I'm trying to get rid of that.
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 13:21:59 UTC, Adam D. Ruppe wrote: On Sunday, 30 September 2018 at 13:17:33 UTC, Vinod K Chandran wrote: Thanks for the reply. But it says "toUTFz" is not defined. do i missing any import statement ? import std.utf; Thanks. It worked. I would like to compile this as a gui. Now it starts with the cmd. Google search didn't gave me the link i want. Any help ?
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 13:17:33 UTC, Vinod K Chandran wrote: On Sunday, 30 September 2018 at 12:48:17 UTC, Adam D. Ruppe wrote: so usage is: toUTFz!(wchar*)(your_string_here); If passing string literals to Windows, you can put a w at the end, like: MessageBoxW(null, "Hello"w, "World"w, 0); // note the ""w Thanks for the reply. But it says "toUTFz" is not defined. do i missing any import statement ? I am trying to make this function, but compiler is rejecting all my attempts. ```D int MsgBox(string MsgTxt, string titleTxt = "MessageBox") { const wchar* Mesg = toUTFz! (wchar*)(MsgTxt) ; const wchar* Tit = toUTFz! (wchar*)(itleTxt) ; MessageBoxW(null, Mesg, Tit, 0) ; return 0 ; } ```
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 13:17:33 UTC, Vinod K Chandran wrote: Thanks for the reply. But it says "toUTFz" is not defined. do i missing any import statement ? import std.utf;
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 12:48:17 UTC, Adam D. Ruppe wrote: so usage is: toUTFz!(wchar*)(your_string_here); If passing string literals to Windows, you can put a w at the end, like: MessageBoxW(null, "Hello"w, "World"w, 0); // note the ""w Thanks for the reply. But it says "toUTFz" is not defined. do i missing any import statement ?
Re: LDC 1.12.0-beta2 (based on LLVM 7)
On Sunday, 30 September 2018 at 12:31:20 UTC, Dennis wrote: "LTO now basically working for Win64 too" That's great! Why the "basically"? Just a precaution as it hasn't been tested extensively yet; Guillaume Piolat (p0nce) successfully tested it with his commercial codebase though, so it's looking good. * New, Easy::jit-like interface for dynamic/JIT compilation. What are the applications of that? Is there a code sample I can check out? The linked PR contains some tests, but they aren't showcases. The dynamic compilation feature per se isn't new; its main application is probably for a bunch of hot key functions, compiling them at runtime to fully exploit the CPU's instruction set (and having the ability to treat some variables as const for these functions). You may want to contact Ivan Butygin (Hardcode84) for more infos, this feature is exclusively his baby. :)
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 06:56:41 UTC, bauss wrote: There is function that does it for you called toStringz() https://dlang.org/library/std/string/to_stringz.html Not really best for Windows. That's for calling C functions with char*, for Windows, you should be working with wchar* instead. http://dpldocs.info/experimental-docs/std.utf.toUTFz.html so usage is: toUTFz!(wchar*)(your_string_here); If passing string literals to Windows, you can put a w at the end, like: MessageBoxW(null, "Hello"w, "World"w, 0); // note the ""w
[Issue 19276] Document accurately calling conventions and demo them in inline asm
https://issues.dlang.org/show_bug.cgi?id=19276 ki...@gmx.net changed: What|Removed |Added CC||ki...@gmx.net --- Comment #1 from ki...@gmx.net --- The System V ABI (used on all non-Windows x86_64 platforms AFAIK) is way too complex for a Wiki page. See https://www.uclibc.org/docs/psABI-x86_64.pdf. --
Re: LDC 1.12.0-beta2 (based on LLVM 7)
"LTO now basically working for Win64 too" That's great! Why the "basically"? On Saturday, 29 September 2018 at 19:00:09 UTC, kinke wrote: * New, Easy::jit-like interface for dynamic/JIT compilation. What are the applications of that? Is there a code sample I can check out?
Re: inline ASM function calling conventions.
On Sunday, 30 September 2018 at 10:46:33 UTC, Sjoerd Nijboer wrote: I'm kinda puzzled. I'm having trouble getting started with inline asm in D. Suppowse I have the following: void Foo(MyStrunct* first_arg, MyStrunct* second_arg) { asm { naked; version(X86) { /* Do something with the content of I and J. */ } version(X86_64) { /* Do something with the content of I and J. *? } } } void Bar() { MyStrunct heapStructA, heapStructB; // do some initialization. Foo(heapStructA, heapStructB); } Suppose I would like to pass first_arg and second_arg by register to `Foo`, what calling convention should I use? I'm having trouble identifying the correct calling convention I should be using for X86 and X86_64 in D. I've tried a couple using https://godbolt.org/ and DMD parameters '-g -m32', but I can't seem to find any that will pass by register. Is there one? Will it also work for LDC and GDC? 1) `asm {}` is supported by DMD and LDC, but not by GDC. 2) `extern(D)` reverses the args - `foo(a, b)` is actually `foo(b, a)` on a lower level. 3) The 32-bit x86 D calling convention (independent from OS) is specified here: https://dlang.org/spec/abi.html#function_calling_conventions All args are passed on the stack, except for the last one under certain circumstances, see point 38.12.3.3. 4) For x86_64, there are 2 (completely different) ABIs, Win64 and the System V one. Specs can be found online. In your case: void Foo(MyStrunct* first_arg, MyStrunct* second_arg) { asm { naked; } version (D_InlineAsm_X86) { // first_arg is on the stack, at [ESP+4] // second_arg is in EAX } else version (D_InlineAsm_X86_64) { version (Win64) { // first_arg is in RDX // second_arg is in RCX } else { // first_arg is in RSI // second_arg is in RDI } } }
Re: inline ASM function calling conventions.
On Sunday, 30 September 2018 at 11:53:17 UTC, Basile B. wrote: On Sunday, 30 September 2018 at 10:46:33 UTC, Sjoerd Nijboer wrote: [...] Hello, i think this should be here (https://dlang.org/spec/abi.html) because myself i never remember them correctly without playing a bit with a disassembler. After playing a bit: Without all the save/restore BS: module runnable; import std.stdio; alias write4Int = writeln!(int,int,int,int); struct MyStruct{int i;} extern(D) void foo(ref MyStruct s1, ref MyStruct s2, ref MyStruct s3, ref MyStruct s4) { asm { naked; mov RCX, MyStruct.i.offsetof[RCX]; mov RDX, MyStruct.i.offsetof[RDX]; mov RSI, MyStruct.i.offsetof[RSI]; mov RDI, MyStruct.i.offsetof[RDI]; callwrite4Int; ret; } } void main() { MyStruct s1 = MyStruct(1); MyStruct s2 = MyStruct(2); MyStruct s3 = MyStruct(3); MyStruct s4 = MyStruct(4); foo(s1, s2, s3, s4); }
[Issue 19276] New: Document accurately calling conventions and demo them in inline asm
https://issues.dlang.org/show_bug.cgi?id=19276 Issue ID: 19276 Summary: Document accurately calling conventions and demo them in inline asm Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: dlang.org Assignee: nob...@puremagic.com Reporter: b2.t...@gmx.com https://dlang.org/spec/abi.html or https://dlang.org/spec/iasm.html should contain the specification for extern(C) and extern(D) register convention for - linux and windows, - x86 and x86_64 - simple types incl floats - value types that don't fit - array --
Re: inline ASM function calling conventions.
On Sunday, 30 September 2018 at 10:46:33 UTC, Sjoerd Nijboer wrote: I'm kinda puzzled. I'm having trouble getting started with inline asm in D. Suppowse I have the following: void Foo(MyStrunct* first_arg, MyStrunct* second_arg) { asm { naked; version(X86) { /* Do something with the content of I and J. */ } version(X86_64) { /* Do something with the content of I and J. *? } } } void Bar() { MyStrunct heapStructA, heapStructB; // do some initialization. Foo(heapStructA, heapStructB); } Suppose I would like to pass first_arg and second_arg by register to `Foo`, what calling convention should I use? I'm having trouble identifying the correct calling convention I should be using for X86 and X86_64 in D. I've tried a couple using https://godbolt.org/ and DMD parameters '-g -m32', but I can't seem to find any that will pass by register. Is there one? Will it also work for LDC and GDC? Hello, i think this should be here (https://dlang.org/spec/abi.html) because myself i never remember them correctly without playing a bit with a disassembler. After playing a bit: Linux x86_64: extern(D) void Foo(MyStruct* s1, MyStruct* s2, MyStruct* s3, MyStruct* s4) { asm { naked; // rcx -> s1 // rdx -> s2 // rsi -> s3 // rdi -> s4 ret; } } Linux x86 / Window x86: extern(D) void Foo(MyStruct* s1, MyStruct* s2, MyStruct* s3, MyStruct* s4) { asm { naked; // ebx -> s1 // edx -> s2 // ecx -> s3 // eax -> s4 ret; } } Win64 has a different calling convention than Linux64, i cant remember the difference. Linux x86_64 example: module runnable; import std.stdio; alias writeInt = writeln!int; struct MyStruct{int i;} extern(D) void foo(MyStruct* s1, MyStruct* s2, MyStruct* s3, MyStruct* s4) { asm { naked; mov RAX, RDI; // move s4 here since we call something... pushRDX;// save s2 pushRSI;// save s3 pushRAX;// save s4 mov RDI, MyStruct.i.offsetof[RCX]; callwriteInt; pop RAX;// restore... pop RSI; pop RDX; pushRSI; // save s3 pushRAX; // save s4 mov RDI, MyStruct.i.offsetof[RDX]; callwriteInt; pop RAX; // restore pop RSI; pushRAX; // save s4 mov RDI, MyStruct.i.offsetof[RSI]; callwriteInt; pop RAX; // restore mov RDI, MyStruct.i.offsetof[RAX]; callwriteInt; ret; } } void main() { MyStruct s1 = MyStruct(1); MyStruct s2 = MyStruct(2); MyStruct s3 = MyStruct(3); MyStruct s4 = MyStruct(4); foo(, , , ); } here too : https://run.dlang.io/is/CWd4aO
Re: Most Effective way of developing a new GC for D
On Sunday, 30 September 2018 at 09:40:10 UTC, Per Nordlöw wrote: I'm gonna play around with creating a GC that alleviates some of the uses described in https://olshansky.me/gc/runtime/dlang/2017/06/14/inside-d-gc.html What's the most effective way of incrementally developing a new pluggable GC for druntime with regards to prevention of really-hard-to-find-bugs? I'm aware of the run-time flag added in 2.072: https://dlang.org/changelog/2.072.0.html#gc-runtimeswitch-added Is it inevitable to rebuild druntime everytime I make an update to a new GC? No. Is so what's the preferred way of selecting a modified druntime in a standard installation of dmd on a Linux system (Ubuntu 18.04 in my case). Will Digger makes things easier? The immediate idea (and maybe naive too) is to link once against a new GC that follows the interface but has assignable handlers. Once DMD build, you can just do dmd -unittest temp_gc_handlers.d && ./temp_gc_handlers At each iteration. temp_gc_handlers.d would have a static module ctor that assigns its content to the GC handler. Once good you put the handler code in the real GC. I think that it would be possible that a few runtime stuff leak until the devel be almost complete but that doesn't matter if stuff are checked, let's say, from a checkpoint that says "from here this amount of leak is normal, it should disappear automatically in the real GC". But again, this method is very hypothetical.
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote: Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? Alex has mentioned Rebindable, which is the answer to your first question. To answer your second question, no class A {} A a: `a` is always a (possibly null) reference to a class instance. You can have pointers to class references (which is what `` gives you) but that has two indirections between the variable and the data, which if you want high perf is probably not what you are looking for.
inline ASM function calling conventions.
I'm kinda puzzled. I'm having trouble getting started with inline asm in D. Suppowse I have the following: void Foo(MyStrunct* first_arg, MyStrunct* second_arg) { asm { naked; version(X86) { /* Do something with the content of I and J. */ } version(X86_64) { /* Do something with the content of I and J. *? } } } void Bar() { MyStrunct heapStructA, heapStructB; // do some initialization. Foo(heapStructA, heapStructB); } Suppose I would like to pass first_arg and second_arg by register to `Foo`, what calling convention should I use? I'm having trouble identifying the correct calling convention I should be using for X86 and X86_64 in D. I've tried a couple using https://godbolt.org/ and DMD parameters '-g -m32', but I can't seem to find any that will pass by register. Is there one? Will it also work for LDC and GDC?
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 10:28:25 UTC, Alex wrote: On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote: Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? I think, what you are facing here, is the different notion of const, as used from C++. The reasoning about it is described for example here: http://jmdavisprog.com/articles/why-const-sucks.html Jonathan is much better therein as I am. However, there are approaches to solve what you want to do. For example, there is a Rebindable around: https://dlang.org/library/std/typecons/rebindable.html ´´´ import std.stdio; import std.typecons; void main() { class Thing {int dummy; } class ThingSaver { /* A const(Thing) could not be changed in setThing(), but a Rebindable can be reassigned, keeping t const. */ Rebindable!(const Thing) t; void setThing(in Thing thing) { t = thing; // No pointers in use :) } const(Thing) getThing() const { return t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); //saver.t.dummy = 5; fails as expected. const(Thing) t2 = saver.getThing(); } ´´´ I hope, I got your idea right... That pretty much hits the nail on the head, and you're exactly right about where my understanding was coming from (C++). In fact, I'm moving a lot of code from C++ to D and finding equivalents for a lot of high-performance index classes, which end up using this kind of pattern. Now I need to take the time to grok this article!
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote: Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? For example: void main() { class Thing {} class ThingSaver { // A const(Thing) could not be changed in setThing(). const(Thing)* t; void setThing(in Thing thing) { t = thing; // ERROR converting to pointer type! } const(Thing) getThing() const { return *t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); const(Thing) t2 = saver.getThing(); } I think, what you are facing here, is the different notion of const, as used from C++. The reasoning about it is described for example here: http://jmdavisprog.com/articles/why-const-sucks.html Jonathan is much better therein as I am. However, there are approaches to solve what you want to do. For example, there is a Rebindable around: https://dlang.org/library/std/typecons/rebindable.html ´´´ import std.stdio; import std.typecons; void main() { class Thing {int dummy; } class ThingSaver { /* A const(Thing) could not be changed in setThing(), but a Rebindable can be reassigned, keeping t const. */ Rebindable!(const Thing) t; void setThing(in Thing thing) { t = thing; // No pointers in use :) } const(Thing) getThing() const { return t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); //saver.t.dummy = 5; fails as expected. const(Thing) t2 = saver.getThing(); } ´´´ I hope, I got your idea right...
Most Effective way of developing a new GC for D
I'm gonna play around with creating a GC that alleviates some of the uses described in https://olshansky.me/gc/runtime/dlang/2017/06/14/inside-d-gc.html What's the most effective way of incrementally developing a new pluggable GC for druntime with regards to prevention of really-hard-to-find-bugs? I'm aware of the run-time flag added in 2.072: https://dlang.org/changelog/2.072.0.html#gc-runtimeswitch-added Is it inevitable to rebuild druntime everytime I make an update to a new GC? Is so what's the preferred way of selecting a modified druntime in a standard installation of dmd on a Linux system (Ubuntu 18.04 in my case). Will Digger makes things easier?
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 09:16:42 UTC, Nicholas Wilson wrote: On Sunday, 30 September 2018 at 07:29:00 UTC, Vijay Nayar wrote: Second question. const class variables may not be re-assigned, so if you need a variable that may be reassigned, but may never modify the underlying object, a const pointer can be useful. However, it seems that when gets the address of a class variable, you do not get the underlying address of the class object. = 0x7ffd0800acb8, a = 0x7fd6b05b, a.data=4 = 0x7ffd0800acd0, a = 0x7fd6b05b, a.data=4 The stack ^ the heap^data on the heap^ The address of the variable a on the stack has different values across function calls, its value (the reference to the class data) remains the same, as does the data itself. Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? For example: void main() { class Thing {} class ThingSaver { // A const(Thing) could not be changed in setThing(). const(Thing)* t; void setThing(in Thing thing) { t = thing; // ERROR converting to pointer type! } const(Thing) getThing() const { return *t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); const(Thing) t2 = saver.getThing(); }
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 07:29:00 UTC, Vijay Nayar wrote: I have two brief questions. Code that uses "new" to create struct objects appears to compile and run. Is this an actual language feature, to get structs on the heap? void main() { struct S {int data = 1;} S* s1 = new S(); S* s2 = s1; S s3 = *s1; // Still copies on assignment. s3.data = 2; assert(s1.data != s3.data); } Second question. const class variables may not be re-assigned, so if you need a variable that may be reassigned, but may never modify the underlying object, a const pointer can be useful. However, it seems that when gets the address of a class variable, you do not get the underlying address of the class object. How do you get a pointer to the underlying class object? Example of the problem: void main() { import std.stdio; class A { int data = 3; } A a = new A(); void f(A a) { a.data = 4; writeln(" = ", , ", a.data = ", a.data); } f(a); writeln(" = ", , ", a.data = ", a.data); } // Output: = 7FFEA6BA3158, a.data = 4 // Addresses are different, from different class variables. = 7FFEA6BA3180, a.data = 4 // But the same underlying class object. Especially if I'm several levels down the call stack, how do I get a pointer to the underlying class object? the variable `a` is a pointer (well, actually reference) to the underlying data. void main() { import core.stdc.stdio; class A { int data = 3; } A a = new A(); void f(A a) { a.data = 4; printf(" = %p, a = %p, a.data=%d\n", , a,a.data); } f(a); printf(" = %p, a = %p, a.data=%d\n", ,a, a.data); } = 0x7ffd0800acb8, a = 0x7fd6b05b, a.data=4 = 0x7ffd0800acd0, a = 0x7fd6b05b, a.data=4 The stack ^ the heap^ data on the heap^ The address of the variable a on the stack has different values across function calls, its value (the reference to the class data) remains the same, as does the data itself.
Re: DIP 1014
On Sunday, September 30, 2018 1:35:28 AM MDT Shachar Shemesh via Digitalmars-d wrote: > On 30/09/18 10:26, Manu wrote: > > Other implementations make much better use of that built-in space by > > not wasting 8 bytes on an interior pointer for small-strings. > > I will point out that a pointer that *sometimes* points to an internal > member was one of the use cases I documented when I submitted the DIP. > > Starting a long discussion about the merits of the design is a bit > off-topic. I will point out that branch prediction considerations > *might* make this a wise choice, despite the loss of 8 bytes of > potential storage. > > Either way, this is a design that is highly sensitive to precise use > pattern, which, admitably, GNU's std::string probably can't know. I think that the key thing here is that if GNU's std::string is using a design like this, it's that much more critical that we have a way to hook into moves to do stuff like adjust pointers. It's one more example of a real world use case where the DIP (or something like it) is needed, or there are things that we simply won't be able to do in D - and given the push to interface with C++, it's that much more important. And while a discussion could certainly be had as to whether GNU's design decision was a good one or not, it's secondary to what really matters here, which is what the state of the DIP is how we're going to deal with interfacing with this C++ code. We need to worry about how to interface with it whether it's the best design ever or whether it's the worst design ever - and we have to take into account the fact the its design could actually change in future versions if they decide that a different way is better (e.g. GNU could change to match other implementations, or other implementations could change to match GNU, depending on what actually turned out to be best in practice when all of the various factors were taken into account - including developers making future decisions that aren't necessarily good ones; we have to interface with the code whether it's good or bad). All in all though, if anything, I have to think that this issue increases the chances of the DIP being accepted given the importance that Walter and Andrei have been placing on interfacing with C++. And having it come up while they're in the middle of discussing it probably doesn't hurt - though maybe they were already going to accept it. I don't know. Personally, while I tend to think that it's generally better to avoid designs where opPostMove is necessary if possible, I think that the case was well made that we need a solution like it in certain cases, and if we want to interface with C++, which can do more or less arbitrary stuff in its move constructors, I don't see how we can avoid having an analogue unless we want to give up on interfacing with that code without an extra compatibility layer. - Jonathan M Davis
Re: New With Struct and Getting Class Object Pointers
On 30/09/2018 8:29 PM, Vijay Nayar wrote: I have two brief questions. Code that uses "new" to create struct objects appears to compile and run. Is this an actual language feature, to get structs on the heap? void main() { struct S {int data = 1;} S* s1 = new S(); S* s2 = s1; S s3 = *s1; // Still copies on assignment. s3.data = 2; assert(s1.data != s3.data); } Yes. Uses a compiler hook to call into the GC, like with everything else.
Re: DIP 1014
On 30/09/18 10:26, Manu wrote: Other implementations make much better use of that built-in space by not wasting 8 bytes on an interior pointer for small-strings. I will point out that a pointer that *sometimes* points to an internal member was one of the use cases I documented when I submitted the DIP. Starting a long discussion about the merits of the design is a bit off-topic. I will point out that branch prediction considerations *might* make this a wise choice, despite the loss of 8 bytes of potential storage. Either way, this is a design that is highly sensitive to precise use pattern, which, admitably, GNU's std::string probably can't know. Shachar
New With Struct and Getting Class Object Pointers
I have two brief questions. Code that uses "new" to create struct objects appears to compile and run. Is this an actual language feature, to get structs on the heap? void main() { struct S {int data = 1;} S* s1 = new S(); S* s2 = s1; S s3 = *s1; // Still copies on assignment. s3.data = 2; assert(s1.data != s3.data); } Second question. const class variables may not be re-assigned, so if you need a variable that may be reassigned, but may never modify the underlying object, a const pointer can be useful. However, it seems that when gets the address of a class variable, you do not get the underlying address of the class object. How do you get a pointer to the underlying class object? Example of the problem: void main() { import std.stdio; class A { int data = 3; } A a = new A(); void f(A a) { a.data = 4; writeln(" = ", , ", a.data = ", a.data); } f(a); writeln(" = ", , ", a.data = ", a.data); } // Output: = 7FFEA6BA3158, a.data = 4 // Addresses are different, from different class variables. = 7FFEA6BA3180, a.data = 4 // But the same underlying class object. Especially if I'm several levels down the call stack, how do I get a pointer to the underlying class object?
Re: DIP 1014
On Sat, Sep 29, 2018 at 11:50 PM Walter Bright via Digitalmars-d wrote: > > On 9/29/2018 9:34 PM, Manu wrote: > > GNU's std::string implementation stores an interior pointer! >_< > > > > No other implementation does this. It's a really bad implementation > > actually, quite inefficient. It could make better use of its space for > > small-strings if it wasn't wasting 8-bytes for an interior pointer to > > a small string buffer... > > Could you post a synopsis of the layout of std::string? The code's all in the PR if you wanna dig into it. The synopsis is: struct string { char* ptr; size_t len; union { char[16] localBuffer; size_type allocatedCapacity; } bool isAllocated() { return ptr != [0]; } bool capacity() { return isAllocated() ? allocatedCapacity : localBuffer.length; } this(DefaultCtor) { ptr = [0]; } // <- and here it is. interior pointer that breaks move semantics } Other implementations make much better use of that built-in space by not wasting 8 bytes on an interior pointer for small-strings.
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 06:56:41 UTC, bauss wrote: On Sunday, 30 September 2018 at 06:33:47 UTC, rikki cattermole wrote: null terminated, nothing really special. To elaborate on this. There is function that does it for you called toStringz() https://dlang.org/library/std/string/to_stringz.html Thanks for the reply. Let me check it.
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 06:33:47 UTC, rikki cattermole wrote: No. 2. Can we use D strings in win api functions ?, If not, please show me how to convert strings null terminated, nothing really special. Hi, Thanks for the reply. I somehow managed to display a messagebox with "const(wchar)*"
Re: Does the WInMain function is mandatory ?
On Sunday, 30 September 2018 at 06:33:47 UTC, rikki cattermole wrote: null terminated, nothing really special. To elaborate on this. There is function that does it for you called toStringz() https://dlang.org/library/std/string/to_stringz.html
Re: DIP 1014
On 9/29/2018 9:34 PM, Manu wrote: GNU's std::string implementation stores an interior pointer! >_< No other implementation does this. It's a really bad implementation actually, quite inefficient. It could make better use of its space for small-strings if it wasn't wasting 8-bytes for an interior pointer to a small string buffer... Could you post a synopsis of the layout of std::string?
Re: Does the WInMain function is mandatory ?
On 30/09/2018 7:24 PM, Vinod K Chandran wrote: Hi, I would like to do some win api coding in D. I just taste the syntactic sugar but cant do anything more. I have few questions. 1. Does WinMain is needed for a D program in order to use win api ? No. 2. Can we use D strings in win api functions ?, If not, please show me how to convert strings null terminated, nothing really special.
Does the WInMain function is mandatory ?
Hi, I would like to do some win api coding in D. I just taste the syntactic sugar but cant do anything more. I have few questions. 1. Does WinMain is needed for a D program in order to use win api ? 2. Can we use D strings in win api functions ?, If not, please show me how to convert strings
Re: Prevent opening binary/other garbage files
On Saturday, 29 September 2018 at 15:52:30 UTC, helxi wrote: I'm writing a utility that checks for specific keyword(s) found in the files in a given directory recursively. What's the best strategy to avoid opening a bin file or some sort of garbage dump? Check encoding of the given file? If so, what are the most popular encodings (in POSIX if that matters) and how do I detect them? What I would do is read the frist 512 bytes and the last 512 bytes and if over 50% of those bytes are below 32 and not 8, 9, 10, 11, 12 or 13 then chances are you have a binary file, but there is nothing that stops someone from writing "invalid" bytes into a text file. There are no limitations on what a file can hold and generally the system treats all files the same. The reason I recommend to read the first 512 and last 512 bytes is because some binary files may contain legit text strings etc. so by picking two places chances are you won't have two segments with text.
Re: DIP 1014
On Saturday, September 29, 2018 10:34:20 PM MDT Manu via Digitalmars-d wrote: > Who knows about DIP 1014? (struct move hook) > Is it well received? Is it likely to be accepted soon? > > I'm working on the std::string binding, it's almost finished... but > then I hit a brick wall. > GNU's std::string implementation stores an interior pointer! >_< > > No other implementation does this. It's a really bad implementation > actually, quite inefficient. It could make better use of its space for > small-strings if it wasn't wasting 8-bytes for an interior pointer to > a small string buffer... > > Anyway, I'm blocked until this DIP is accepted; so, is it looking > promising? Per https://github.com/dlang/DIPs/tree/master/DIPs, it's at the "Formal Assessement" stage, whatever that means (I'm not well enough versed in all of the stages of the current DIP process to say what that means). However, I would think that if Walter and Andrei were aware of this particular problem with std::string, given the importance they place on interfacing with C++, it would greatly increase the odds of that DIP being accepted. - Jonathan M Davis
Re: DIP 1014
On Sunday, 30 September 2018 at 04:34:20 UTC, Manu wrote: Who knows about DIP 1014? (struct move hook) Is it well received? Is it likely to be accepted soon? I'm working on the std::string binding, it's almost finished... but then I hit a brick wall. GNU's std::string implementation stores an interior pointer! >_< No other implementation does this. It's a really bad implementation actually, quite inefficient. It could make better use of its space for small-strings if it wasn't wasting 8-bytes for an interior pointer to a small string buffer... Anyway, I'm blocked until this DIP is accepted; so, is it looking promising? It's pending a decision from Walter & Andrei, which I hope to hear soon.