Skip to content

Comments

Don't generate exception handling code if Throwable is not declared#7786

Merged
dlang-bot merged 1 commit intodlang:masterfrom
JinShil:optional_throwable
Jan 28, 2018
Merged

Don't generate exception handling code if Throwable is not declared#7786
dlang-bot merged 1 commit intodlang:masterfrom
JinShil:optional_throwable

Conversation

@JinShil
Copy link
Contributor

@JinShil JinShil commented Jan 26, 2018

This PR is a follow up to #7395 and #7768. It is to Throwable what #7395 and #7768 were to ModuleInfo.

In D, anything that can be thrown must inherit from object.Throwable. Therefore, if object.Throwable does not exist, no exception handling code should be generated, and any attempt to throw should emit compilation error.

With #7395, #7768, and this PR, we can now generate a minimal executable with almost no boilerplate and produce very small resulting binaries.

Example 1

object.d

module object;

private alias extern(C) int function(char[][] args) MainFunc;
private extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc)
{
    return mainFunc(null);
}

main.d

void main() { }

Compile

dmd -conf= -defaultlib= main.d object.d -of=main

Result

size main
   text	   data	    bss	    dec	    hex	filename
   1403	    584	     16	   2003	    7d3	main

Example 2

object.d

module object;

extern(C) void __d_sys_exit(long arg1)
{
    asm
    {
        mov RAX, 60;
        mov RDI, arg1;
        syscall;
    }
}

extern void main();
private extern(C) void _start()
{
    main();
    __d_sys_exit(0);
}

main.d

void main() { }

Compile and link

dmd -c -lib main.d object.d -of=main.o
ld main.o -o main

Result

size main
   text	   data	    bss	    dec	    hex	filename
     56	      0	      0	     56	     38	main

Again, this will be of interest to users wishing to incrementally or partially port D to new platforms, users hoping to target resource constrained platforms, and users wishing to use D as a library from other languages without druntime.

@dlang-bot
Copy link
Contributor

Thanks for your pull request, @JinShil!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

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

How about adding the second example to the testsuite too?

src/dmd/dclass.d Outdated
extern (C++) class ClassDeclaration : AggregateDeclaration
{
extern (C++) __gshared
extern (C++) static __gshared
Copy link
Contributor

Choose a reason for hiding this comment

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

It's already __gshared. DMD should emit a warning when both are used as this doesn't make any sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was following the example here:

extern (C++) static __gshared AggregateDeclaration moduleinfo;

But, I'll change it.

@JinShil JinShil added Review:WIP Work In Progress - not ready for review or pulling and removed Review:WIP Work In Progress - not ready for review or pulling labels Jan 26, 2018
@JinShil
Copy link
Contributor Author

JinShil commented Jan 27, 2018

How about adding the second example to the testsuite too?

There's a few concerns I have about that:

  • It requires compiling and linking separately due to all the hard-coded linking logic in DMD. I'm not sure how to do that in the test suite.
  • It's very Linux 64-bit specific.
  • I think verifying the size will be quite brittle and too sensitive to small insignificant changes.

But I'll add it if it's desired, and I can figure out how to compile and link separately in the test suite.

SegData[seg]->SDbuf->write(name, strlen(name));
SegData[seg]->SDbuf->writeByte('"');
return true;
if (name && strlen(name) > 0)
Copy link
Member

Choose a reason for hiding this comment

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

This isn't checked in cgobj.c, why here? What does it have to do with Throwable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's because the tests are compiled with defaultlib=, and the mircosoft linker rejects empty arguments to /DEFAULTLIB:. It's just necessary to get the tests to pass on Windows.

Copy link
Member

Choose a reason for hiding this comment

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

BTW, in glue.d where this function is called:

if (global.params.mscrtlib && global.params.mscrtlib[0])
      objmod.includelib(global.params.mscrtlib);

so now the check is being done twice. Also, the strlen can be safely replaced with [0].

src/dmd/link.d Outdated
cmdbuf.writeByte(' ');
cmdbuf.writestring("/DEFAULTLIB:");
writeFilename(&cmdbuf, f);
}
Copy link
Member

Choose a reason for hiding this comment

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

This looks like it belongs in a separate PR?

Copy link
Contributor Author

@JinShil JinShil Jan 27, 2018

Choose a reason for hiding this comment

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

I could do that, but I don't have a test to verify it. This PR has the logic necessary to create a test that actually benefits from defaultlib= (i.e. no defaultlib). So, I think they need to go together.

Copy link
Member

Choose a reason for hiding this comment

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

Should clearly set up the code so that no default lib has defaultlib set to null, not a 0 length string.


if (!global.params.useExceptions) // if not worrying about exceptions
// if not worrying about exceptions
if (!global.params.useExceptions || !ClassDeclaration.throwable)
Copy link
Member

Choose a reason for hiding this comment

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

Elsewhere is written useExceptions && throwable, so I suggest rewriting this to be consistent:

if (!(global.params.useExceptions && ClassDeclaration.throwable))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

src/dmd/link.d Outdated
writeFilename(&cmdbuf, global.params.libfiles[i]);
// The `/DEFAULTLIB:` argument cannot be empty
const f = global.params.libfiles[i];
if (f && strlen(f) > 0)
Copy link
Member

Choose a reason for hiding this comment

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

replace strlen(f) > 0 with f[0]

Copy link
Member

Choose a reason for hiding this comment

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

also, perhaps this check should be done where libfiles[] is filled, rather than where it is used.

@WalterBright
Copy link
Member

Good idea!

@JinShil
Copy link
Contributor Author

JinShil commented Jan 27, 2018

The tests in this PR require defaultlib= (i.e. no defaultlib). Prior to this PR, that parameter set defaultlibname to an empty string, which was then passed to the /DEFAULTLIB: argument of Microsoft's linker on Windows. However, Microsoft's linker throws an error if the argument to /DEFAULTLIB: is empty.

Per @WalterBright's suggestion in prior comments in this PR, defaultlibname is now set to null in mars.d. However, that means logic in link.d and glue.d now needs to check defaultlibname for null to ensure there are no segfaults and that the /DEFAULTLIB: argument is not empty.

@WalterBright, this is ready for another look. Thanks.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants