Skip to content

Commit

Permalink
some fixes/enhancements for the typed array support (#436)
Browse files Browse the repository at this point in the history
* fix broken in operator for typed arrays (zero is a valid index too)

* typed arrays are doing the buffer encoding based on little/big endian from the architecture they run on. So far Rhino always uses big endian. With this patch we are able to simulate little endian also by setting a context feature.

* regarding the spec the default is always big endian and not architecture dependent

* fix toString() for typed arrays
  • Loading branch information
rbri authored and gbrail committed May 15, 2018
1 parent a715323 commit bfd2271
Show file tree
Hide file tree
Showing 15 changed files with 145 additions and 28 deletions.
7 changes: 7 additions & 0 deletions src/org/mozilla/javascript/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,13 @@ public class Context
*/
public static final int FEATURE_INTEGER_WITHOUT_DECIMAL_PLACE = 18;

/**
* TypedArray buffer uses little/big endian depending on the platform.
* The default is big endian for Rhino.
* @since 1.7 Release 11
*/
public static final int FEATURE_LITTLE_ENDIAN = 19;

public static final String languageVersionProperty = "language version";
public static final String errorReporterProperty = "error reporter";

Expand Down
3 changes: 3 additions & 0 deletions src/org/mozilla/javascript/ContextFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ protected boolean hasFeature(Context cx, int featureIndex)

case Context.FEATURE_INTEGER_WITHOUT_DECIMAL_PLACE:
return false;

case Context.FEATURE_LITTLE_ENDIAN:
return false;
}
// It is a bug to call the method with unknown featureIndex
throw new IllegalArgumentException(String.valueOf(featureIndex));
Expand Down
15 changes: 15 additions & 0 deletions src/org/mozilla/javascript/typedarrays/NativeArrayBufferView.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package org.mozilla.javascript.typedarrays;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.IdScriptableObject;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Undefined;
Expand All @@ -20,6 +21,8 @@ public abstract class NativeArrayBufferView
{
private static final long serialVersionUID = 6884475582973958419L;

private static Boolean useLittleEndian = null;

/** Many view objects can share the same backing array */
protected final NativeArrayBuffer arrayBuffer;
/** The offset, in bytes, from the start of the backing array */
Expand Down Expand Up @@ -62,6 +65,18 @@ public int getByteLength() {
return byteLength;
}

protected static boolean useLittleEndian() {
if (useLittleEndian == null) {
Context ctx = Context.getCurrentContext();
// for some unit tests this might be null
if (ctx == null) {
return false;
}
useLittleEndian = ctx.hasFeature(Context.FEATURE_LITTLE_ENDIAN);
}
return useLittleEndian.booleanValue();
}

protected static boolean isArg(Object[] args, int i)
{
return ((args.length > i) && !Undefined.instance.equals(args[i]));
Expand Down
12 changes: 4 additions & 8 deletions src/org/mozilla/javascript/typedarrays/NativeDataView.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ private Object js_getInt(int bytes, boolean signed, Object[] args)
int pos = ScriptRuntime.toInt32(args[0]);
rangeCheck(pos, bytes);

boolean littleEndian =
(isArg(args, 1) && (bytes > 1) && ScriptRuntime.toBoolean(args[1]));
boolean littleEndian = isArg(args, 1) && (bytes > 1) && ScriptRuntime.toBoolean(args[1]);

switch (bytes) {
case 1:
Expand All @@ -124,8 +123,7 @@ private Object js_getFloat(int bytes, Object[] args)
int pos = ScriptRuntime.toInt32(args[0]);
rangeCheck(pos, bytes);

boolean littleEndian =
(isArg(args, 1) && (bytes > 1) && ScriptRuntime.toBoolean(args[1]));
boolean littleEndian = isArg(args, 1) && (bytes > 1) && ScriptRuntime.toBoolean(args[1]);

switch (bytes) {
case 4:
Expand All @@ -145,8 +143,7 @@ private void js_setInt(int bytes, boolean signed, Object[] args)
int pos = ScriptRuntime.toInt32(args[0]);
rangeCheck(pos, bytes);

boolean littleEndian =
(isArg(args, 2) && (bytes > 1) && ScriptRuntime.toBoolean(args[2]));
boolean littleEndian = isArg(args, 2) && (bytes > 1) && ScriptRuntime.toBoolean(args[2]);

switch (bytes) {
case 1:
Expand Down Expand Up @@ -183,8 +180,7 @@ private void js_setFloat(int bytes, Object[] args)
int pos = ScriptRuntime.toInt32(args[0]);
rangeCheck(pos, bytes);

boolean littleEndian =
(isArg(args, 2) && (bytes > 1) && ScriptRuntime.toBoolean(args[2]));
boolean littleEndian = isArg(args, 2) && (bytes > 1) && ScriptRuntime.toBoolean(args[2]);
double val = ScriptRuntime.toNumber(args[1]);

switch (bytes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protected Object js_get(int index)
if (checkIndex(index)) {
return Undefined.instance;
}
return ByteIo.readFloat32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, false);
return ByteIo.readFloat32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, useLittleEndian());
}

@Override
Expand All @@ -88,7 +88,7 @@ protected Object js_set(int index, Object c)
return Undefined.instance;
}
double val = ScriptRuntime.toNumber(c);
ByteIo.writeFloat32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, false);
ByteIo.writeFloat32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, useLittleEndian());
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protected Object js_get(int index)
if (checkIndex(index)) {
return Undefined.instance;
}
long base = ByteIo.readUint64Primitive(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, false);
long base = ByteIo.readUint64Primitive(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, useLittleEndian());
return Double.longBitsToDouble(base);
}

Expand All @@ -90,7 +90,7 @@ protected Object js_set(int index, Object c)
}
double val = ScriptRuntime.toNumber(c);
long base = Double.doubleToLongBits(val);
ByteIo.writeUint64(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, base, false);
ByteIo.writeUint64(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, base, useLittleEndian());
return null;
}

Expand Down
4 changes: 2 additions & 2 deletions src/org/mozilla/javascript/typedarrays/NativeInt16Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected Object js_get(int index)
if (checkIndex(index)) {
return Undefined.instance;
}
return ByteIo.readInt16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, false);
return ByteIo.readInt16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, useLittleEndian());
}

@Override
Expand All @@ -87,7 +87,7 @@ protected Object js_set(int index, Object c)
return Undefined.instance;
}
int val = Conversions.toInt16(c);
ByteIo.writeInt16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, false);
ByteIo.writeInt16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, useLittleEndian());
return null;
}

Expand Down
4 changes: 2 additions & 2 deletions src/org/mozilla/javascript/typedarrays/NativeInt32Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protected Object js_get(int index)
if (checkIndex(index)) {
return Undefined.instance;
}
return ByteIo.readInt32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, false);
return ByteIo.readInt32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, useLittleEndian());
}

@Override
Expand All @@ -88,7 +88,7 @@ protected Object js_set(int index, Object c)
return Undefined.instance;
}
int val = ScriptRuntime.toInt32(c);
ByteIo.writeInt32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, false);
ByteIo.writeInt32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, useLittleEndian());
return null;
}

Expand Down
35 changes: 27 additions & 8 deletions src/org/mozilla/javascript/typedarrays/NativeTypedArrayView.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public Object get(int index, Scriptable start)
@Override
public boolean has(int index, Scriptable start)
{
return ((index > 0) && (index < length));
return !checkIndex(index);
}

@Override
Expand Down Expand Up @@ -245,6 +245,19 @@ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
case Id_constructor:
return js_constructor(cx, scope, args);

case Id_toString:
NativeTypedArrayView realThis = realThis(thisObj, f);
final int arrayLength = realThis.getArrayLength();
final StringBuilder builder = new StringBuilder();
if (arrayLength > 0) {
builder.append(ScriptRuntime.toString(realThis.js_get(0)));
}
for (int i = 1; i < arrayLength; i++) {
builder.append(',');
builder.append(ScriptRuntime.toString(realThis.js_get(i)));
}
return builder.toString();

case Id_get:
if (args.length > 0) {
return realThis(thisObj, f).js_get(ScriptRuntime.toInt32(args[0]));
Expand Down Expand Up @@ -303,6 +316,7 @@ protected void initPrototypeId(int id)
int arity;
switch (id) {
case Id_constructor: arity = 1; s = "constructor"; break;
case Id_toString: arity = 0; s = "toString"; break;
case Id_get: arity = 1; s = "get"; break;
case Id_set: arity = 2; s = "set"; break;
case Id_subarray: arity = 2; s = "subarray"; break;
Expand All @@ -326,15 +340,19 @@ protected int findPrototypeId(Symbol k)
protected int findPrototypeId(String s)
{
int id;
// #generated# Last update: 2016-03-04 20:59:23 GMT
// #generated# Last update: 2018-05-13 12:51:10 MESZ
L0: { id = 0; String X = null; int c;
int s_length = s.length();
if (s_length==3) {
c=s.charAt(0);
if (c=='g') { if (s.charAt(2)=='t' && s.charAt(1)=='e') {id=Id_get; break L0;} }
else if (c=='s') { if (s.charAt(2)=='t' && s.charAt(1)=='e') {id=Id_set; break L0;} }
}
else if (s_length==8) { X="subarray";id=Id_subarray; }
else if (s_length==8) {
c=s.charAt(0);
if (c=='s') { X="subarray";id=Id_subarray; }
else if (c=='t') { X="toString";id=Id_toString; }
}
else if (s_length==11) { X="constructor";id=Id_constructor; }
if (X!=null && X!=s && !X.equals(s)) id = 0;
break L0;
Expand All @@ -346,10 +364,11 @@ protected int findPrototypeId(String s)
// Table of all functions
private static final int
Id_constructor = 1,
Id_get = 2,
Id_set = 3,
Id_subarray = 4,
SymbolId_iterator = 5;
Id_toString = 2,
Id_get = 3,
Id_set = 4,
Id_subarray = 5,
SymbolId_iterator = 6;

protected static final int
MAX_PROTOTYPE_ID = SymbolId_iterator;
Expand Down Expand Up @@ -401,7 +420,7 @@ protected Object getInstanceIdValue(int id)
protected int findInstanceIdInfo(String s)
{
int id;
// #generated# Last update: 2014-12-08 17:33:28 PST
// #generated# Last update: 2018-05-13 12:51:10 MESZ
L0: { id = 0; String X = null;
int s_length = s.length();
if (s_length==6) { X="length";id=Id_length; }
Expand Down
4 changes: 2 additions & 2 deletions src/org/mozilla/javascript/typedarrays/NativeUint16Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected Object js_get(int index)
if (checkIndex(index)) {
return Undefined.instance;
}
return ByteIo.readUint16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, false);
return ByteIo.readUint16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, useLittleEndian());
}

@Override
Expand All @@ -87,7 +87,7 @@ protected Object js_set(int index, Object c)
return Undefined.instance;
}
int val = Conversions.toUint16(c);
ByteIo.writeUint16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, false);
ByteIo.writeUint16(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, useLittleEndian());
return null;
}

Expand Down
4 changes: 2 additions & 2 deletions src/org/mozilla/javascript/typedarrays/NativeUint32Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ protected Object js_get(int index)
if (checkIndex(index)) {
return Undefined.instance;
}
return ByteIo.readUint32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, false);
return ByteIo.readUint32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, useLittleEndian());
}

@Override
Expand All @@ -87,7 +87,7 @@ protected Object js_set(int index, Object c)
return Undefined.instance;
}
long val = Conversions.toUint32(c);
ByteIo.writeUint32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, false);
ByteIo.writeUint32(arrayBuffer.buffer, (index * BYTES_PER_ELEMENT) + offset, val, useLittleEndian());
return null;
}

Expand Down
28 changes: 28 additions & 0 deletions testsrc/jstests/harmony/typed-array-in.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
load("testsrc/assert.js");

var types = [Int8Array, Uint8Array, Int16Array, Uint16Array,
Int32Array, Uint32Array, Uint8ClampedArray, Float32Array,
Float64Array];

for (var t = 0; t < types.length; t++) {
var type = types[t];

var empty = new type(0);
assertFalse(0 in empty);
assertFalse(1 in empty);

var one = new type(1);
one[0] = 1;
assertTrue(0 in one);
assertFalse(1 in one);

var two = new type(2);
assertTrue(0 in two);
assertTrue(1 in two);
assertFalse(2 in two);

two[1] = 2;
assertFalse(2 in two);
}

"success";
23 changes: 23 additions & 0 deletions testsrc/jstests/harmony/typed-array-to-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
load("testsrc/assert.js");

var types = [Int8Array, Uint8Array, Int16Array, Uint16Array,
Int32Array, Uint32Array, Uint8ClampedArray, Float32Array,
Float64Array];

for (var t = 0; t < types.length; t++) {
var type = types[t];

var empty = new type(0);
assertEquals("", empty.toString());

var one = new type([7]);
assertEquals("7", one.toString());

var two = new type([7,13]);
assertEquals("7,13", two.toString());

var many = new type([7,13,21,17,0,1,11]);
assertEquals("7,13,21,17,0,1,11", many.toString());
}

"success";
13 changes: 13 additions & 0 deletions testsrc/org/mozilla/javascript/tests/harmony/TypedArrayInTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript.tests.harmony;

import org.mozilla.javascript.drivers.RhinoTest;
import org.mozilla.javascript.drivers.ScriptTestsBase;

@RhinoTest("testsrc/jstests/harmony/typed-array-in.js")
public class TypedArrayInTest extends ScriptTestsBase
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript.tests.harmony;

import org.mozilla.javascript.drivers.RhinoTest;
import org.mozilla.javascript.drivers.ScriptTestsBase;

@RhinoTest("testsrc/jstests/harmony/typed-array-to-string.js")
public class TypedArrayToStringTest extends ScriptTestsBase
{
}

0 comments on commit bfd2271

Please sign in to comment.