Coder Social home page Coder Social logo

proposal-limited-arraybuffer's People

Contributors

jack-works avatar jamiebuilds avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

proposal-limited-arraybuffer's Issues

Problem of the interoperability with Wasm.

Since JavaScript and WebAssembly can communicate with each other by accessing the same Arraybuffer, and the WebAssembly.Memory object has the ability to export its internal Arraybuffer by calling the buffer method on it. If so, what would be the behavior if we freeze the exported Arraybuffer and mutate the corresponding memory of this Arraybuffer by the Wasm instruction like i32.store?Without messing things up, I think the better ways are:

  1. Proposing a new type like "ReadOnlyArraybuffer", for example. And It should be inherited from Arraybuffer, then moving the read-only property from Arraybuffer to this new type without touching anything of the inherited Arraybuffer. And also, by leveraging the "fixed-view" proposal (which could be extended more on this new type), people cannot get the internal Arraybuffer of this new type directly. (so, it's just something like a fix-view and read-only TypedArray). And here comes the next solution.
  2. Simply adding two new methods on all the TypedArray objects, the first one is called "freeze()" which is almost the same as you just proposed. By calling this method, people cannot mutate any bytes of the underlying Arraybuffer through this view. The second method can be called "hide()" which can make it impossible to get the internal Arraybuffer reference of a specific view. And the result is that we should keep the Arraybuffer as is since it's more of an underlying mechanism.
var memory = new WebAssembly.Memory({ initial:10, maximum:100 });
var arraybuffer = memory.buffer;  // returns an Arraybuffer instance.
arraybuffer.prototype.freeze();  // freeze the buffer.
WebAssembly.instantiateStreaming(fetch('memory.wasm'), { js: { mem: memory } })
.then(obj => {
  // ...
  // call the exported method which would mutate the value of a specific location of memory, 
  // what should be the behavior here?
});

In conclusion, I think ArrayBuffer itself should not take the responsibility of the mutability, this ability should be controlled by the view lying on it. How do you think?

ArrayBuffer ranged views

Consider an application using JavaScript and WebAssembly, communicating through the Wasm heap.

If the JS wants to pass around a read-only slice of the Wasm heap (a JS ArrayBuffer object), the JS must either pass around a TypedArray and always make sure to use it's .byteLength and .byteOffset properties to ensure correct usage, or copy the memory in the slice into a new ArrayBuffer.

One wants the slice to be read-only in order to prevent writing to the memory, and one doesn't want to move around the entire ArrayBuffer object, as that would allow reading into the memory at practically arbitrary locations.

Without being able to do both, view a section of an ArrayBuffer, and mark it as read-only, developers will have to find a workaround, which will likely come to creating ad-hoc wrapper classes or copying.

Could sliced views be introduced into the proposal alongside read-only views?


The only two questions that I would have regarding an introduction of the idea would be the following:

  • Would the views have alignment requirements? Would they expose their alignment? (E.g. TypedArrays need to know alignment)
  • What would be the construction API?

API suggestion: focus on RO ArrayBuffer(s)

From the README:

Cannot construct the read-write view from readOnlyView.buffer

To prevent this problem ^, and the potential problem mentioned on the 5th slide of the current stage 1 proposal slides, I suggest introducing a new class, ReadOnlyArrayBuffer, analogous to the present SharedArrayBuffer.

By constructing a ReadOnlyArrayBuffer from a read-write ArrayBuffer, and creating a TypedArray view on the read-only buffer, TypedArray.buffer will yield the same ReadOnlyArrayBuffer object.

Example:

const rw_buffer = new ArrayBuffer (10);

const rw_view = new Uint8Array(rw_buffer);

// nothing changes here
for ( let i = 0; i < 10; ++i ) {
    rw_view[i] = I;
}

const ro_buffer = new ReadOnlyArrayBuffer(rw_buffer);

const ro_view = Uint8Array(ro_buffer);

assert(ro_buffer === ro_view.buffer);

// ro_view is an Uint8Array containing 0..=10
for ( let i = 0; i < 10; ++i ) {
    assert(ro_view[i] === i);
}

ro_view[0] = 1; // TypeError

The class would be usable in almost every place that ArrayBuffers and SharedArrayBuffers are currently usable, including DataViews, and any WebIDL functions that accept ArrayBuffer sources.

(On second thought, wouldn't there need to be a SharedReadOnlyArrayBuffer too?)

Creating a ReadOnly view of buffer must copy data to new buffer

This must copy the data into a new readonly array buffer. For the data properties to be truly readonly, they must be frozen with non-configurable, non-writable descriptors, so the Object.getOwnPropertyDescriptor(typedarray, '0') must have { configurable: false, writeable: false } (and a data value). However, if the readonly view of the underlying buffer shared the same memory, the data property could be changed by the original readwrite buffer:

const readwrite = new Uint8Array(1);
assert.equal(readwrite[0], 0);
assert.equal(Object.getOwnPropertyDescriptor(readwrite, '0').configurable, true);
assert.equal(Object.getOwnPropertyDescriptor(readwrite, '0').writable, true);

const readonly = new Uint8Array(array.buffer, { readonly: true });
assert.equal(readonly[0], 0);
assert.equal(Object.getOwnPropertyDescriptor(readonly, '0').configurable, false);
assert.equal(Object.getOwnPropertyDescriptor(readonly, '0').writable, false);

// This cannot change the readonly data, per the proxy invariants
readwrite[0] = 1;

// This data property must always report `value === 0`, per the proxy invariants
assert.equal(readonly[0], 0);

This just means the underlying buffer must be copied to a new readonly buffer, and isn't just a "view" of the underlying data.

New integrity level

Follow-on of discussion in #13, I organized ideas with a new "new integrity level" that freeze the internal state of an object. What do you think?

(cc @erights, @ljharb, @phoddie, @syg)

stabilized state (temporally name)

A new integrity level of object:

  • Its internal state is immutable (NOT recursive).
  • This does not mean it is frozen (in the meaning of Object.freeze)
  • Stabilize an object might throw!
  • Some objects may be refused to be stabilized (e.g: when an ArrayBuffer is used by WebAssembly as memory?)

difference between harden

  • harden is recursive, stabilize is not.
  • harden care about the property descriptors, stabilize only care about the meaningful fields (and internal slots) that play roles in its data structure.

New APIs:

  • isStable(x)
  • stablilzed(x)

Terms

  • 🌟 `born stabilized: the value is already stabilized after creation
  • βœ…: can be stabilized after creation
  • ❌: cannot be stabilized
  • ❓: to be decided

ECMAScript defined:

Data type Status Description
Primitive (1, true) 🌟 Born stabilized.
Boxed primitive (new Number(1)) 🌟 Born stabilized.
Array βœ… Make its all array index properties unconfigurable and non-writable.
Refuse to add new array index properties.
ArrayBuffer βœ… Refuse to modify data inside [[ArrayBufferData]] (but allowing detach to transfer).
Refuse to modify [[ArrayBufferByteLength]] (refuse to expand/shrink size).
Date βœ… Refuse to modify [[DateValue]].
Errors (EvalError, ...) ❓ To be decided.
FinalizationRegistry & WeakRef ❓ To be decided.
Function πŸŒŸβ“ Can you change it anyway? Make length and name unconfigurable?
globalThis ❓ To be decided. Refuse to define new global variable? What about DOM with ID?
Iterators (ArrayIterator, ...) ❓ To be decided.
Map & Set βœ… Refuse to modify [[MapData]] or [[SetData]] field.
Promise ❌ Refuse to be stabilized.
It's either already stabilized (fulfilled/rejected), or useless after hardened (pending).
Proxy ➑️ Passthrough. It will invoke the [[Get]] trap with Symbol.harden.
RegExp βœ… Make its lastIndex property non-writable.
Refuse to compile().
ShadowRealm ❓ To be decided. Possible options:
❌ Refuse to be stabilized
βœ… Refuse to compile new code (by evaluate, eval, Function or importValue)
TypedArrays/DataView ❌ Refuse to be stabilized.
It is a view, you must freeze the underlying buffer with the buffer directly.
WeakMap & WeakSet βœ… Refuse to modify [[WeakMapData]] or [[WeakSetData]] field.

Userland objects:

Symbol.stabilize protocol:

class T {
    #data = new Set()
    #hardened = false
    ;[Symbol.stabilize]() {
        harden(this.#data)
        this.#hardened = true
    }
    add(x) {
        this.#data.add(x)
    }
}

Extra APIs:

Those methods are useful but not directly related to the new integrity level, and not possible to make a unified protocol for all objects. I list them case-by-case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.