Bug 170316 - WebAssembly: Ref count Signature and SignatureInformation should not care about VM
Summary: WebAssembly: Ref count Signature and SignatureInformation should not care abo...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-03-30 17:24 PDT by Saam Barati
Modified: 2017-03-31 15:41 PDT (History)
10 users (show)

See Also:


Attachments
WIP (40.27 KB, patch)
2017-03-30 19:43 PDT, Saam Barati
no flags Details | Formatted Diff | Diff
patch (45.06 KB, patch)
2017-03-30 22:57 PDT, Saam Barati
keith_miller: review-
Details | Formatted Diff | Diff
patch (44.67 KB, patch)
2017-03-31 12:33 PDT, Saam Barati
keith_miller: review+
Details | Formatted Diff | Diff
patch (60.29 KB, patch)
2017-03-31 14:48 PDT, Saam Barati
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Saam Barati 2017-03-30 17:24:03 PDT
We can refcount individual ones. Or we can have VM refcount the entire table.
Comment 1 Saam Barati 2017-03-30 19:43:17 PDT
Created attachment 305937 [details]
WIP

crashes in debug
Comment 2 Saam Barati 2017-03-30 22:57:26 PDT
Created attachment 305943 [details]
patch
Comment 3 JF Bastien 2017-03-30 23:29:59 PDT
Comment on attachment 305943 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=305943&action=review

I'm not sure all the `const Signature *` need to be RefPtr: their lifetime is already bound by their caller. The way I tried to set this up, raw pointers are just things you can access without thinking about who owns it: you don't, someone else up your call chain does. I a way this is the "dumb pointer" idiom.

I'll need to take another look when I'm not as tired :)

> Source/JavaScriptCore/wasm/WasmBinding.cpp:-422
> -    String signatureDescription = SignatureInformation::get(vm, signatureIndex)->toString();

I think Keith had made this conditional on debug because it was slow?

> Source/JavaScriptCore/wasm/WasmFormat.h:237
> +    Vector<RefPtr<Signature>> usedSignatures;

Isn't it kinda weird to duplicate this information? We already have a list of indices we use above, but it's not nicely RAII refcount so we dup it here. :(

> Source/JavaScriptCore/wasm/WasmModuleParser.cpp:111
> +    WASM_PARSER_FAIL_IF(!m_result.module->usedSignatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");

The error message is misleading since this allocation isn't the same as above, but errors out the same.

> Source/JavaScriptCore/wasm/WasmSignature.cpp:74
> +    if (argumentCount > 1024 * 1024)

This is the wrong place to enforce a limit. We should do this in the parser, and in one shot as part of bug #165833.

> Source/JavaScriptCore/wasm/WasmSignature.cpp:77
> +    void* memory = Signature::operator new (allocatedSize(argumentCount));

Other parts of the code use the try* allocators so that wasm can OOM without being sad. It was tryFastCalloc above, we should keep that property here.

> Source/JavaScriptCore/wasm/WasmSignature.cpp:153
> +        info.m_nextIndex = Signature::invalidIndex + 1;

Here and elsewhere, it would be nice to have a symbolic constant for "first valid index". This otherwise assumes that the invalid index is 0.
Comment 4 Keith Miller 2017-03-31 10:16:58 PDT
Comment on attachment 305943 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=305943&action=review

r- on some comments JF and I made.

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:412
> +auto B3IRGenerator::addArguments(const RefPtr<Signature>& signature) -> PartialResult

style: Revert this or use Signature& here. It's an anti-pattern to use a ref to a container class when the function isn't going hold any reference anyway.

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:884
> +auto B3IRGenerator::addCall(uint32_t functionIndex, RefPtr<Signature>&& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult

ditto.

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:965
> +auto B3IRGenerator::addCallIndirect(RefPtr<Signature>&& signature, SignatureIndex signatureIndex, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult

ditto.

> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:1086
> +static void createJSToWasmWrapper(CompilationContext& compilationContext, WasmInternalFunction& function, const RefPtr<Signature>& signature, const ModuleInformation& info)

ditto.

>> Source/JavaScriptCore/wasm/WasmBinding.cpp:-422
>> -    String signatureDescription = SignatureInformation::get(vm, signatureIndex)->toString();
> 
> I think Keith had made this conditional on debug because it was slow?

Moving this into the macro is fine since that case of the macro only runs if you have the option set.

>> Source/JavaScriptCore/wasm/WasmSignature.cpp:74
>> +    if (argumentCount > 1024 * 1024)
> 
> This is the wrong place to enforce a limit. We should do this in the parser, and in one shot as part of bug #165833.

Agreed.

> Source/JavaScriptCore/wasm/WasmSignature.cpp:151
> +    if (!info.m_signatureMap.size()) {

nit: You could do info.m_signatureMap.isEmpty() I think it's a little easier to read.
Comment 5 Saam Barati 2017-03-31 11:52:56 PDT
Comment on attachment 305943 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=305943&action=review

>> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:412
>> +auto B3IRGenerator::addArguments(const RefPtr<Signature>& signature) -> PartialResult
> 
> style: Revert this or use Signature& here. It's an anti-pattern to use a ref to a container class when the function isn't going hold any reference anyway.

I don't agree. I made "const RefPtr<Signature>&" precisely because the function doesn't need to ref it.

>> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:884
>> +auto B3IRGenerator::addCall(uint32_t functionIndex, RefPtr<Signature>&& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
> 
> ditto.

I think these should also be "const RefPtr<Signature>&"

>> Source/JavaScriptCore/wasm/WasmFormat.h:237
>> +    Vector<RefPtr<Signature>> usedSignatures;
> 
> Isn't it kinda weird to duplicate this information? We already have a list of indices we use above, but it's not nicely RAII refcount so we dup it here. :(

I think this is the price to pay for using a raw uint32_t for signature index. We could make this fancier, but I think that belongs in its own patch.

>> Source/JavaScriptCore/wasm/WasmModuleParser.cpp:111
>> +    WASM_PARSER_FAIL_IF(!m_result.module->usedSignatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries");
> 
> The error message is misleading since this allocation isn't the same as above, but errors out the same.

To a user of web assembly, what's the difference?

>>> Source/JavaScriptCore/wasm/WasmSignature.cpp:74
>>> +    if (argumentCount > 1024 * 1024)
>> 
>> This is the wrong place to enforce a limit. We should do this in the parser, and in one shot as part of bug #165833.
> 
> Agreed.

Ok.

>> Source/JavaScriptCore/wasm/WasmSignature.cpp:77
>> +    void* memory = Signature::operator new (allocatedSize(argumentCount));
> 
> Other parts of the code use the try* allocators so that wasm can OOM without being sad. It was tryFastCalloc above, we should keep that property here.

Ok.

>> Source/JavaScriptCore/wasm/WasmSignature.cpp:151
>> +    if (!info.m_signatureMap.size()) {
> 
> nit: You could do info.m_signatureMap.isEmpty() I think it's a little easier to read.

ok.

>> Source/JavaScriptCore/wasm/WasmSignature.cpp:153
>> +        info.m_nextIndex = Signature::invalidIndex + 1;
> 
> Here and elsewhere, it would be nice to have a symbolic constant for "first valid index". This otherwise assumes that the invalid index is 0.

sgtm
Comment 6 Saam Barati 2017-03-31 11:57:59 PDT
Comment on attachment 305943 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=305943&action=review

>>> Source/JavaScriptCore/wasm/WasmSignature.cpp:77
>>> +    void* memory = Signature::operator new (allocatedSize(argumentCount));
>> 
>> Other parts of the code use the try* allocators so that wasm can OOM without being sad. It was tryFastCalloc above, we should keep that property here.
> 
> Ok.

Actually, Ima keep this as is. Our handling of an argument count limit should make tryMalloc here useless. We should enforce our own limit during module parsing.
Comment 7 Saam Barati 2017-03-31 12:02:19 PDT
Comment on attachment 305943 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=305943&action=review

>>> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:412
>>> +auto B3IRGenerator::addArguments(const RefPtr<Signature>& signature) -> PartialResult
>> 
>> style: Revert this or use Signature& here. It's an anti-pattern to use a ref to a container class when the function isn't going hold any reference anyway.
> 
> I don't agree. I made "const RefPtr<Signature>&" precisely because the function doesn't need to ref it.

I misread your comment. Anyways, I still don't agree. We use this pattern all over the place in JSC.
Comment 8 Saam Barati 2017-03-31 12:03:50 PDT
Comment on attachment 305943 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=305943&action=review

>>>> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:412
>>>> +auto B3IRGenerator::addArguments(const RefPtr<Signature>& signature) -> PartialResult
>>> 
>>> style: Revert this or use Signature& here. It's an anti-pattern to use a ref to a container class when the function isn't going hold any reference anyway.
>> 
>> I don't agree. I made "const RefPtr<Signature>&" precisely because the function doesn't need to ref it.
> 
> I misread your comment. Anyways, I still don't agree. We use this pattern all over the place in JSC.

Also, I think the const RefPtr<Signature>& does communicate something to us here. It says somebody calling us is ensuring the proper lifetime. I think it's an information regression to use Signature*. I can see an argument for using Signature&, but I like knowing when something is ref counted.
Comment 9 Saam Barati 2017-03-31 12:33:04 PDT
Created attachment 306001 [details]
patch

Addressed most comments. I also switched to using Ref instead of RefPtr. There is no reason a signature should ever be null. This would be very wrong.
Comment 10 Keith Miller 2017-03-31 14:06:44 PDT
Comment on attachment 306001 [details]
patch

View in context: https://bugs.webkit.org/attachment.cgi?id=306001&action=review

r=me

> Source/JavaScriptCore/wasm/WasmSignature.cpp:72
> +    void* memory = Signature::operator new (allocatedSize(argumentCount));
> +    Signature* result = new (memory) Signature(argumentCount);

Why not use the NotNull flag?
Comment 11 Saam Barati 2017-03-31 14:48:04 PDT
Created attachment 306012 [details]
patch
Comment 12 Saam Barati 2017-03-31 14:48:32 PDT
Comment on attachment 306012 [details]
patch

This is the patch for landing.
Comment 13 Saam Barati 2017-03-31 15:19:03 PDT
landed in:
https://trac.webkit.org/changeset/214691/webkit
Comment 14 JF Bastien 2017-03-31 15:41:56 PDT
Comment on attachment 306012 [details]
patch

Looks good!