Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

[new AA] implement aaLiteral #933

Merged
merged 1 commit into from Oct 4, 2014

Conversation

IgorStepanov
Copy link
Contributor

This functions will be used to constructing AA values: literals and nulls. When this PR will be merged, I will create PR for dmd, which uses this functions, and when dmd PR will be merged, I'll create PR, which rewrite this functions to use new AA implementation.

values ~= cast(Value)args[i+1];
}

void[] key_slice = (cast(void*)keys.ptr)[0 .. keys.length];
Copy link
Member

Choose a reason for hiding this comment

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

Huh? What if Key.sizeof != (void*).sizeof ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is void slice, not void*. And yes, Key.sizeof can be not equals with void.sizeof. However _d_assocarrayliteralTX void[] takes slice with length == keys count. See rt/aaA.d:562:

Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values)
{
    ...
    const length = keys.length;
    ...
    assert(length == values.length);
    ...
    for (size_t j = 0; j < length; j++)
    {   auto pkey = keys.ptr + j * keysize;
        auto pvalue = values.ptr + j * valuesize;
        ...
    }
    ...
}

Copy link
Member

Choose a reason for hiding this comment

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

Oh yuck it's one of those APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes :)
This is another one reason to replace old AA implementation.

Copy link
Member

Choose a reason for hiding this comment

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

I'd rather you did it via *(cast(void[]*)&keys) instead to make it clear it's a reinterpret cast.

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

@IgorStepanov IgorStepanov force-pushed the newaa-aaLiteral-and-aaInit branch 4 times, most recently from 8396e88 to 2c03e7a Compare August 26, 2014 19:37
@IgorStepanov IgorStepanov changed the title [new AA] implement aaLiteral and aaInit [new AA] implement aaLiteral Aug 26, 2014
@IgorStepanov
Copy link
Contributor Author

Reworked. Now this PR introduce only aaLiteral, because my last AA implementation use zero AA init (similar old AA).

@IgorStepanov
Copy link
Contributor Author

@MartinNowak ping

@quickfur
Copy link
Member

Is the dmd pull ready yet, or were you planning to merge this first and submit the dmd changes later?

@IgorStepanov
Copy link
Contributor Author

This PR should be merged first. After that, dmd pull should pass tests (they are passed on my machine). After dmd pull will be merged (of course, it should be reviewed first), I will create the next druntime PR. It will be simple and use AA implementation from #934 (which are also waitinig for review).
This work is done on my machine and passed tests.
And all stages of this work need LGTM from @MartinNowak and @yebblies, even if PR's will be reviewed by another one.

@quickfur
Copy link
Member

OK, makes sense. I'll leave it to them to approve this PR then.

void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) @trusted pure;
}

auto aaLiteral(Key, Value, T...)(T args) @trusted
Copy link
Member

Choose a reason for hiding this comment

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

Isn't @trusted a potential safety hole here if any of the argument types define a custom opCast?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Current AA implementation is one big hole:

void* p;
struct MyKey
{
    size_t a;
    size_t toHash() const
    {
        p = cast(void*)a;
        if (a == 5)
            throw new Exception("hello");
        return a;
    }
}

void main() @safe pure nothrow
{
    int[MyKey] aa;
    aa[MyKey(3)] = 3;
    aa[MyKey(5)] = 5; //BOOOM
}

This code succesfully compiles and runs on dmd v2.066

This PR is a transitional stage between current implementation and new good, safe template-based implementation.
This PR doesn't brings something new. Where dmd inserts aaLiteral, it called _d_assocarrayliteralTX without any checks early.

Copy link
Member

Choose a reason for hiding this comment

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

Should this use auto ref T args to avoid temporary copies?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

auto ref causes an unexpected troubles on some tests. May be it's a compiler bug, may be it is my bug in dmd code. If dlang/dmd#3904 will be reviewed by someone dmd guru like @9rnsr my possible bug can be found. But for review 3904 we need merge this code.
I think this is not big issue, because this code will be replaced with new AA fast enough (I hope until the next release).

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. I've fixed bug in my dmd patch. Now we can use auto ref arguments in aaLiteral.

Key[] keys;
Value[] values;
keys.reserve(T.length / 2);
values.reserve(T.length / 2);
Copy link
Member

Choose a reason for hiding this comment

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

auto keys = new Key[](T.length / 2);
auto values = new Value[](T.length / 2);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. If I'll construct a array compiler will initialize it with init data (is Value is a struct with @disable this() it causes a error).
After that I'll shoud to assign (call opAssign) instead of adding new values.

@IgorStepanov IgorStepanov force-pushed the newaa-aaLiteral-and-aaInit branch 2 times, most recently from a36d857 to ea68760 Compare September 21, 2014 01:43
@IgorStepanov
Copy link
Contributor Author

@MartinNowak I've applied changes that you asked, except setting array elements by index (I said why).
Also I've reworked and retested dlang/dmd#3904
I'll apply asked changes to #934 tomorrow, it need more thoughtful work.

@IgorStepanov
Copy link
Contributor Author

@MartinNowak Please, rereview it.
BTW, what happens with FreeBSD server? This PR cant fails because it contains three templates, which never instatiated.

@IgorStepanov
Copy link
Contributor Author

@MartinNowak ping

@IgorStepanov
Copy link
Contributor Author

@MartinNowak may be this PR can be merged? It is so trivial and its merging allows to start review of dmd part. And when you will able to review #934 PR?

@IgorStepanov
Copy link
Contributor Author

@MartinNowak ping

foreach (i; staticIota!(0, args.length / 2))
{
keys ~= cast(Key)args[2*i];
values ~= cast(Value)args[2*i + 1];
Copy link
Member

Choose a reason for hiding this comment

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

Casting could be unsafe here, so remove the @trusted from above and let the compiler infer it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm. I've removed casts and tests have been passed. I can't remember, why I added them. =/

I can't remove @trusted, because void[] key_slice = *cast(void[]*)&keys; is unsafe. (It's part of old AA API)

@MartinNowak
Copy link
Member

OK, let's get this going. I'm still not really happy with the template bloat caused the variadic template arguments, but we can optimize the details later.

@IgorStepanov
Copy link
Contributor Author

@MartinNowak is it ok now?

@IgorStepanov
Copy link
Contributor Author

@MartinNowak Please, if you see my changes but not ready to review this, tell me something like printf("I see this, but I haven't time/energy to review this now. Remind me in %s", time_until_remind)
I'm sorry that I bother all my PR's ping, but lack of response makes me think that my action banal not seen.

@MartinNowak
Copy link
Member

I'm sorry that I bother all my PR's ping, but lack of response makes me think that my action banal not seen.

Well it isn't seen, because I only look at my github inbox when I have time.

@MartinNowak
Copy link
Member

We still have to let the compiler infer safety because appending a struct to an array might call an unsafe postblit.
You can make the cast trusted by using a trusted function literal.

void[] key_slice, value_slice;
() @trusted {
    key_slice = *cast(void[]*)&keys;
    value_slice = *cast(void[]*)&values;
}();

void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) @trusted pure;
}

auto aaLiteral(Key, Value, T...)(auto ref T args) @trusted
Copy link
Member

Choose a reason for hiding this comment

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

Let's add if (T.sizeof % 2 == 0) as template constraint.

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

@IgorStepanov
Copy link
Contributor Author

You can make the cast trusted by using a trusted function literal.

Pretty syntax. Done.

@IgorStepanov
Copy link
Contributor Author

@MartinNowak done. Also I've moved _d_assocarrayliteralTX call to @trusted delegate and removed @trusted from _d_assocarrayliteralTX signature.

@MartinNowak
Copy link
Member

Pretty syntax. Done.

Yikes, I'm not even sure we can optimize away the function call.

@MartinNowak
Copy link
Member

removed @trusted from _d_assocarrayliteralTX signature

Oh, hadn't seen that before. Please also add all declared attributes to the implementation, it probably cannot be pure.

@IgorStepanov
Copy link
Contributor Author

Oh, hadn't seen that before. Please also add all declared attributes to the implementation, it probably cannot be pure.

It CAN be impure. And we can't check the purity.
This example works in current dmd version.

void* p;
struct MyKey
{
    size_t a;
    size_t toHash() const
    {
        p = cast(void*)a;
        if (a == 5)
            throw new Exception("hello");
        return a;
    }
}

void main() @safe pure nothrow
{
    int[MyKey] aa;
    aa[MyKey(3)] = 3;
    aa[MyKey(5)] = 5; //BOOOM
}

Compiler doesn't provide any check and inserts _d_assocarrayliteralTX into safe code without a doubt.
It's another one reason to migrate to new AA implementation as possible faster :)

@IgorStepanov
Copy link
Contributor Author

In other words, we can't make _d_assocarrayliteralTX pure, because it can call impure hash function, and we can't make _d_assocarrayliteralTX impure, because aa listerals can be created in pure code. However I don't add any new holes in this PR. Current hole exists in old implementation, and we should move to new implementation to fix this hole.

@MartinNowak
Copy link
Member

Compiler doesn't provide any check and inserts _d_assocarrayliteralTX into safe code without a doubt.
It's another one reason to migrate to new AA implementation as possible faster :)

Then please add a comment to the declaration explaining why it is marked as pure even though it isn't.

@IgorStepanov
Copy link
Contributor Author

Then please add a comment to the declaration explaining why it is marked as pure even though it isn't.

done

@MartinNowak
Copy link
Member

Auto-merge toggled on

@MartinNowak
Copy link
Member

Thanks a lot for driving this.

@9rnsr
Copy link
Contributor

9rnsr commented Oct 4, 2014

Why aaLiteral is necessary? It looks a thin wrapper and I cannot see the benefit to add it.

@9rnsr
Copy link
Contributor

9rnsr commented Oct 4, 2014

Sorry, ignore my comment.

@IgorStepanov
Copy link
Contributor Author

Thanks! Now it's time to #934
When we done it, we will done the most part of new AA transtion.

MartinNowak added a commit that referenced this pull request Oct 4, 2014
@MartinNowak MartinNowak merged commit 7e2a075 into dlang:master Oct 4, 2014
@MartinNowak
Copy link
Member

We need to improve this even if it's only an interim interface.
Moving the keys and value to a temporary array is not acceptable, even if it weren't GC allocated.

@IgorStepanov
Copy link
Contributor Author

Moving the keys and value to a temporary array is not acceptable, even if it weren't GC allocated.

How your sugest to do it? Arguments passed in stack in rotation. We need to two separate slices.

if it's only an interim interface.

If we will not linger, we will apply all parts of work and throw _d_assocarrayliteralTX before the next release. End users will not notice this interface.

@MartinNowak
Copy link
Member

How your sugest to do it?

Indeed it's fairly difficult as long as the implementation sits in rt. So yes we need to defer this.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
6 participants