Skip to content

Add DataView to standard library #316

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

Merged
merged 1 commit into from
Nov 12, 2018
Merged

Conversation

LinusU
Copy link
Contributor

@LinusU LinusU commented Nov 7, 2018

Opening this for early feedback, as soon as I know I'm on the right track it should be very easy for me to add all the required methods.

Some questions:

  1. Should I just throw new RangeError('Out of bounds access') when trying to access outside the bounds?

  2. Is there any way to overload the get* functions for when littleEndian is known at compile time, or will the compiler just figure it out anyway?

    e.g. something like this:

    function getUint32(offset: number, littleEndian: false) { ... }
    function getUint32(offset: number, littleEndian: true) { ... }
    function getUint32(offset: number, littleEndian: boolean) { ... }
  3. Do I have to register DataView as a global variable somewhere?

  4. Where do I put the tests? I'm assuming somewhere under tests/, but then I'm a bit lost ☺️

Thank you for your time, looking forward to working a lot more on this project, it rocks! 🙌

fixes #315

FIXME:

  • Don't commit dist/* files
  • Add me to NOTICE file

@MaxGraey
Copy link
Member

MaxGraey commented Nov 7, 2018

Is there any way to overload the get* functions for when littleEndian is known at compile time, or will the compiler just figure it out anyway?

Don't worry about that. Binaryen has dae (dead argument elimination) and constant propagation if argument knows in compile time during optimization

@LinusU
Copy link
Contributor Author

LinusU commented Nov 7, 2018

I will rebase and order/squash the commits in a good way when I'm done, just pushing now so that you can see the changes more easily 👍


@inline
function get<T>(buffer: ArrayBuffer, byteOffset: i32, littleEndian: boolean): T {
const result = load<T>(changetype<usize>(buffer) + byteOffset, HEADER_SIZE);
Copy link
Member

Choose a reason for hiding this comment

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

in AS better use var instead const if this variable can't compute in compile time or store in data section

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good to know, will fix 👍

Do you mind explaining why? ☺️ it is also better than let?

Copy link
Member

Choose a reason for hiding this comment

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

It better ask to @dcodeIO

Copy link
Member

Choose a reason for hiding this comment

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

As a rule of thumb, const currently behaves pretty much like static const in other languages, indicating storage in static memory. I'm considering changing that, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dcodeIO Should we use let (unless const changes) then instead of var?

@MaxGraey
Copy link
Member

MaxGraey commented Nov 7, 2018

About alignment. wasm can read/store unalignment memory without caveat:
WebAssembly/design#30 (comment)

@@ -16,9 +16,11 @@ export class DataView {
constructor(
readonly buffer: ArrayBuffer,
readonly byteOffset: i32 = 0,
readonly byteLength: i32 = i32.MAX_VALUE,
readonly byteLength: i32 = buffer.byteLength - byteOffset,
Copy link
Member

@MaxGraey MaxGraey Nov 7, 2018

Choose a reason for hiding this comment

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

I don't think this support yet

Copy link
Contributor Author

@LinusU LinusU Nov 7, 2018

Choose a reason for hiding this comment

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

alas, it is not

ERROR TS2304: Cannot find name 'a'.

 function test (a: ArrayBuffer, l: i32 = a.byteLength): i32 {
                                         ~

Would it be hard to fix? 😁 maybe a bit out of scope for this PR though 😂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

diff --git a/std/assembly/dataview.ts b/std/assembly/dataview.ts
index f1a8ebe..ef5df88 100644
--- a/std/assembly/dataview.ts
+++ b/std/assembly/dataview.ts
@@ -16,8 +16,10 @@ export class DataView {
   constructor(
     readonly buffer: ArrayBuffer,
     readonly byteOffset: i32 = 0,
-    readonly byteLength: i32 = buffer.byteLength - byteOffset,
+    readonly byteLength: i32 = i32.MIN_VALUE,
   ) {
+    if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset
+
     if (byteOffset < 0) throw new RangeError("byteOffset cannot be negative");
     if (byteLength < 0) throw new RangeError("byteLength cannot be negative");
     if (byteOffset + byteLength > buffer.byteLength) throw new RangeError("Length out of range of buffer");

Is this an acceptable compromise?

It won't give a proper error if someone passes in i32.MIN_VALUE as the byteLength, but I think we have to choose one i32 value to mean "nothing was passed"

(btw. creating a DataView with a byteLength of 0 is totally valid)

Copy link
Member

Choose a reason for hiding this comment

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

What about this?

byteLength = min(buffer.byteLength - byteOffset, byteLength);

Copy link
Contributor Author

@LinusU LinusU Nov 7, 2018

Choose a reason for hiding this comment

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

I was thinking that it would be preferable to throw if a too long byteLength was passed, rather than silently truncating the length of the DataView. That is how the spec says as well:

https://www.ecma-international.org/ecma-262/6.0/#sec-dataview-buffer-byteoffset-bytelength

12.c. If offset+viewByteLength > bufferByteLength, throw a RangeError exception.

@LinusU
Copy link
Contributor Author

LinusU commented Nov 7, 2018

Hmm, without fb34590 I'm getting the following error, would love some insight 🤔

ERROR AS200: Conversion from type 'i32' to 'u16' requires an explicit cast.

   return littleEndian ? result : bswap<T>(result);
                                           ~~~~~~
 in ~lib/dataview.ts(6,42)

ERROR AS200: Conversion from type 'i32' to 'u16' requires an explicit cast.

   return littleEndian ? result : bswap<T>(result);
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 in ~lib/dataview.ts(6,9)

@MaxGraey
Copy link
Member

MaxGraey commented Nov 8, 2018

Also plz add tests to new file tests/compiler/std/dataview.ts

@LinusU
Copy link
Contributor Author

LinusU commented Nov 9, 2018

I think that everything should be good to go now 🙌

I've rebased on master and squashed everything into one clean commit 😎

@MaxGraey
Copy link
Member

MaxGraey commented Nov 9, 2018

Also need declare declare class DataView { .... } inside portable/index.d.ts. Just copy-paste this from assembly/index.d.ts

@LinusU
Copy link
Contributor Author

LinusU commented Nov 11, 2018

Added entry to portable/index.d.ts and rebased on master again 👍

@LinusU LinusU changed the title [WIP] Add DataView to standard library Add DataView to standard library Nov 11, 2018
@dcodeIO
Copy link
Member

dcodeIO commented Nov 11, 2018

Looking good to me, except that it somewhat feels like the get and set helpers aren't strictly necessary. Also, some methods use them, and others like getFloat32 don't?

@LinusU
Copy link
Contributor Author

LinusU commented Nov 11, 2018

Yeah, they are currently only used for getting and setting integers, since floats require special handling. I'd be happy to either 1) remove the functions and just have the code at each callsite, 2) update them to also work for floats, so that they are used all the time or 3) rename them getInteger/setInteger or similar. Just let me know ☺️

@dcodeIO
Copy link
Member

dcodeIO commented Nov 11, 2018

Regarding 2) I think that these could have been wrapped in a reinterpret instruction to make them work with no other changes, but I'd personally favor 1) to save the additional inlining step and resulting block in untouched output.

@LinusU
Copy link
Contributor Author

LinusU commented Nov 11, 2018

Done 🚀

@dcodeIO dcodeIO merged commit 3f9758f into AssemblyScript:master Nov 12, 2018
@dcodeIO
Copy link
Member

dcodeIO commented Nov 12, 2018

Thank you! :)

@LinusU LinusU deleted the dataview branch November 12, 2018 09:47
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.

[Feature] Add DataView implementation
3 participants