Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a helper method to copy an array of numbers to a JS TypedArray #31

Merged
merged 26 commits into from
Sep 10, 2020

Conversation

j-f1
Copy link
Member

@j-f1 j-f1 commented Aug 4, 2020

Extracted from #26.

Copy link
Contributor

@MaxDesiatov MaxDesiatov left a comment

Choose a reason for hiding this comment

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

Does DOMKit need this for anything? If so, wouldn't there be a use case for conversion in the other direction, from JS to Swift? Do I understand correctly that it's not supported in this PR? If it is planned, it would be totally fine (preferred even) to land that as a separate PR, just wanted to clarify it.

@j-f1
Copy link
Member Author

j-f1 commented Aug 4, 2020

I did a quick search, and it seems like a TypedArray is used as input to the Blob constructor. There’s also ways to construct TypedArrays out of the ArrayBuffer you get back from a Blob. The TypedArray stuff is separate from the main part of DOMKit, and there is no support for creating one from an ArrayBuffer yet, so we could push that feature to a future PR.

@j-f1
Copy link
Member Author

j-f1 commented Aug 4, 2020

Also happy to write something that goes the other way now, though.

elementsPtr: pointer, length: number,
result_obj: pointer
) => {
const ArrayType: TypedArray = this.heap.referenceHeap(0)[JavaScriptTypedArrayKind[kind] + 'Array']
Copy link
Member

Choose a reason for hiding this comment

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

Please don't abuse address 0 just to access global context.
It would be better to store global or window as a member of SwiftRuntime and access it directly 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

I created a globalVariable variable as a replacement. Is that a good name or should I go with something else?

Runtime/src/index.ts Outdated Show resolved Hide resolved
Sources/JavaScriptKit/JSObject.swift Outdated Show resolved Hide resolved
Sources/JavaScriptKit/JSObject.swift Outdated Show resolved Hide resolved
@j-f1
Copy link
Member Author

j-f1 commented Aug 13, 2020

I’ve created a JSTypedArray protocol that all the concrete types inherit from. Should I do it this way (matching the JS API) or just make JSTypedArray a generic class?

j-f1 added 12 commits August 13, 2020 15:33
This matches the Objective-C names and better corresponds with their tasks (freeHeap just decreases ref count so it doesn’t always free). I’m not as sure about allocHeap → retain because it adds to the heap in addition to increasing the refcount.
Previously it would just return undefined which would throw an error when attempting to use the object later on. Now you’re able to demangle the stack trace to find exactly where you’re misusing a ref.
@j-f1
Copy link
Member Author

j-f1 commented Aug 15, 2020

Another consideration: While working on #26, I changed the JSTypedArray class to wrap a regular JSObjectRef (like JSArrayRef does) instead of extending it (like JSFunction does). That makes use of a JSBridgedClass type which I could implement in a separate PR. Which approach is better?

Copy link
Member

@kateinoigakukun kateinoigakukun left a comment

Choose a reason for hiding this comment

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

First of all, I'm not confident with the current interface design.


When bridging JavaScript object into Swift, the class inheritance relationship information is not given into Swift world.
So they are flattened into JSObjectRef and users need to use JavaScript cast outside of Swift system. (In this case, JavaScript cast means a cast that checks the type of value at runtime using instanceof when casting like JSArrayRef.)

But for JSFunctionRef, we need to consider it as a special class because JavaScript cast depends on JSFunction itself. For example, if JavaScriptKit treats JSFunction as well as JSArrayRef, when casting a JSObjectRef into JSFunctionRef, JavaScript cast system needs to check that the object is a function using obj instanceof Function. But how can we get Function class? It can't.

For this reason, JSFunctionRef and JSObjectRef should be distinguished when taking it from JavaScript.


I'd like to see the JSBridgedClass impl. Could you send another PR to review it?

}

public init(length: Int) {
let jsObject = Element.typedArrayClass.new(length)
Copy link
Member

Choose a reason for hiding this comment

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

How about having the jsObject in JSTypedArray instead of manual reference count management?

@@ -8,6 +8,17 @@ type pointer = number;
interface GlobalVariable { }
declare const window: GlobalVariable;
declare const global: GlobalVariable;
let globalVariable: any;
Copy link
Member

Choose a reason for hiding this comment

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

I think this variable can be capsulized in SwiftRuntimeHeap.

Runtime/src/index.ts Show resolved Hide resolved
@kateinoigakukun
Copy link
Member

I’ve created a JSTypedArray protocol that all the concrete types inherit from. Should I do it this way (matching the JS API) or just make JSTypedArray a generic class?

I prefer current generic class version. 👍

@j-f1
Copy link
Member Author

j-f1 commented Aug 16, 2020

I'd like to see the JSBridgedClass impl. Could you send another PR to review it?

It’s not 100% clean yet (there’s a few other things in the PR that are unrelated) but I added it in #26. (see diff between it and this PR)

There’s the JSBridgedType protocol which adds an init?(from: JSValue) initializer, which returns nil if the given value isn’t supported by the implementation. It extends JSValueCodable (aka JSValueConvertible & JSValueConstructible) so you can convert it back and forth from a JSValue using those APIs [maybe I should change it so that JSValueConvertible uses a jsValue read-only property and you do SomeJSValueConstructible(from: JSValue) instead of having a static func construct method?]

Then there’s the JSBridgedClass protocol which has a static classRef property pointing to the JS constructor for the class being represented and an instance objectRef property containing the JSObjectRef being wrapped. The init?(from: JSValue) implementation in JSBridgedClass ensures that the passed value is an object and is an instance of the classRef before calling init(withCompatibleObject: JSObjectRef) to delegate to the specific implementation.

For example, if JavaScriptKit treats JSFunction as well as JSArrayRef, when casting a JSObjectRef into JSFunctionRef, JavaScript cast system needs to check that the object is a function using obj instanceof Function. But how can we get Function class? It can't.

I might be misunderstanding this but there is a Function property on the JS global object that all functions (including generator, async, and arrow functions) are instanceof. I do think it makes sense to treat functions differently since they have a different typeof though.

@MaxDesiatov
Copy link
Contributor

I'm thinking of generating some WebGLKit code, thankfully an IDL file for it is available. Using typed arrays is pretty much a requirement for WebGL, so I'd be very happy for this PR to move forward. Is there any way I can help here?

@j-f1
Copy link
Member Author

j-f1 commented Sep 8, 2020

The main sticking point is on the bridging API. I think the one in #26 can be extracted out to another PR, if @kateinoigakukun likes it.

@kateinoigakukun
Copy link
Member

kateinoigakukun commented Sep 9, 2020

This is my change proposal j-f1#1

If you accept my proposal, I can immediately merge your PR #31
In the future, I also want to implement CoW system on typed-array to avoid heavy copy but it's out of scope of this PR.

@kateinoigakukun kateinoigakukun merged commit 171c391 into swiftwasm:master Sep 10, 2020
@j-f1 j-f1 deleted the typed-array branch September 12, 2020 23:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants