mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 898362 - Self-host portions of the typed object logic r=till
This commit is contained in:
parent
876eb7144b
commit
9d6fd5ce28
@ -664,11 +664,12 @@ selfhosting_srcs := \
|
||||
$(srcdir)/builtin/Intl.js \
|
||||
$(srcdir)/builtin/IntlData.js \
|
||||
$(srcdir)/builtin/Iterator.js \
|
||||
$(srcdir)/builtin/Map.js \
|
||||
$(srcdir)/builtin/Number.js \
|
||||
$(srcdir)/builtin/ParallelArray.js \
|
||||
$(srcdir)/builtin/String.js \
|
||||
$(srcdir)/builtin/Set.js \
|
||||
$(srcdir)/builtin/Map.js \
|
||||
$(srcdir)/builtin/TypedObject.js \
|
||||
$(NULL)
|
||||
|
||||
selfhosted_out_h_deps := \
|
||||
|
@ -28,7 +28,8 @@ using namespace mozilla;
|
||||
const Class TypeRepresentation::class_ = {
|
||||
"TypeRepresentation",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_PRIVATE,
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEREPR_SLOTS),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
@ -285,7 +286,29 @@ TypeRepresentation::addToTableOrFree(JSContext *cx,
|
||||
js_free(this);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ownerObject->setPrivate(this);
|
||||
|
||||
// Assign the various reserved slots:
|
||||
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_KIND, Int32Value(kind()));
|
||||
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_SIZE, Int32Value(size()));
|
||||
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_ALIGNMENT, Int32Value(alignment()));
|
||||
|
||||
switch (kind()) {
|
||||
case Array:
|
||||
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_LENGTH,
|
||||
Int32Value(asArray()->length()));
|
||||
break;
|
||||
|
||||
case Scalar:
|
||||
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_TYPE,
|
||||
Int32Value(asScalar()->type()));
|
||||
break;
|
||||
|
||||
case Struct:
|
||||
break;
|
||||
}
|
||||
|
||||
ownerObject_.init(ownerObject);
|
||||
return &*ownerObject;
|
||||
}
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "jscntxt.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "builtin/TypedObjectConstants.h"
|
||||
#include "gc/Barrier.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
@ -90,9 +91,9 @@ typedef js::HashSet<TypeRepresentation *,
|
||||
class TypeRepresentation {
|
||||
public:
|
||||
enum Kind {
|
||||
Scalar,
|
||||
Struct,
|
||||
Array
|
||||
Scalar = JS_TYPEREPR_SCALAR_KIND,
|
||||
Struct = JS_TYPEREPR_STRUCT_KIND,
|
||||
Array = JS_TYPEREPR_ARRAY_KIND
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -109,7 +110,7 @@ class TypeRepresentation {
|
||||
static void obj_trace(JSTracer *trace, JSObject *object);
|
||||
static void obj_finalize(js::FreeOp *fop, JSObject *object);
|
||||
|
||||
js::HeapPtrObject ownerObject_;
|
||||
HeapPtrObject ownerObject_;
|
||||
void traceFields(JSTracer *tracer);
|
||||
|
||||
public:
|
||||
@ -159,20 +160,20 @@ class ScalarTypeRepresentation : public TypeRepresentation {
|
||||
public:
|
||||
// Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
|
||||
enum Type {
|
||||
TYPE_INT8 = 0,
|
||||
TYPE_UINT8,
|
||||
TYPE_INT16,
|
||||
TYPE_UINT16,
|
||||
TYPE_INT32,
|
||||
TYPE_UINT32,
|
||||
TYPE_FLOAT32,
|
||||
TYPE_FLOAT64,
|
||||
TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
|
||||
TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
|
||||
TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
|
||||
TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
|
||||
TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
|
||||
TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
|
||||
TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
|
||||
TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
|
||||
|
||||
/*
|
||||
* Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
|
||||
* Treat the raw data type as a uint8_t.
|
||||
*/
|
||||
TYPE_UINT8_CLAMPED,
|
||||
TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
|
||||
};
|
||||
static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
|
||||
|
||||
@ -198,8 +199,10 @@ class ScalarTypeRepresentation : public TypeRepresentation {
|
||||
static JSObject *Create(JSContext *cx, Type type);
|
||||
};
|
||||
|
||||
// Must be in same order as the enum:
|
||||
#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_) \
|
||||
// Enumerates the cases of ScalarTypeRepresentation::Type which have
|
||||
// unique C representation. In particular, omits Uint8Clamped since it
|
||||
// is just a Uint8.
|
||||
#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_INT8, int8_t, int8) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_UINT8, uint8_t, uint8) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_INT16, int16_t, int16) \
|
||||
@ -207,7 +210,11 @@ class ScalarTypeRepresentation : public TypeRepresentation {
|
||||
macro_(ScalarTypeRepresentation::TYPE_INT32, int32_t, int32) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_UINT32, uint32_t, uint32) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_FLOAT32, float, float32) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_FLOAT64, double, float64) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_FLOAT64, double, float64)
|
||||
|
||||
// Must be in same order as the enum ScalarTypeRepresentation::Type:
|
||||
#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_) \
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
|
||||
|
||||
class ArrayTypeRepresentation : public TypeRepresentation {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "builtin/TypedObjectConstants.h"
|
||||
#include "builtin/TypeRepresentation.h"
|
||||
|
||||
namespace js {
|
||||
@ -20,47 +21,12 @@ namespace js {
|
||||
*/
|
||||
extern const Class TypedObjectClass;
|
||||
|
||||
// Slots common to all type descriptors:
|
||||
enum TypeCommonSlots {
|
||||
// Canonical type representation of this type (see TypeRepresentation.h).
|
||||
SLOT_TYPE_REPR=0,
|
||||
TYPE_RESERVED_SLOTS
|
||||
};
|
||||
|
||||
// Slots for ArrayType type descriptors:
|
||||
enum ArrayTypeCommonSlots {
|
||||
// Type descriptor for the element type.
|
||||
SLOT_ARRAY_ELEM_TYPE = TYPE_RESERVED_SLOTS,
|
||||
ARRAY_TYPE_RESERVED_SLOTS
|
||||
};
|
||||
|
||||
// Slots for StructType type descriptors:
|
||||
enum StructTypeCommonSlots {
|
||||
// JS array containing type descriptors for each field, in order.
|
||||
SLOT_STRUCT_FIELD_TYPES = TYPE_RESERVED_SLOTS,
|
||||
STRUCT_TYPE_RESERVED_SLOTS
|
||||
};
|
||||
|
||||
// Slots for data blocks:
|
||||
enum BlockCommonSlots {
|
||||
// The type descriptor with which this block is associated.
|
||||
SLOT_DATATYPE = 0,
|
||||
|
||||
// If this value is nullptr, then the block instance owns the
|
||||
// uint8_t* in its priate data. Otherwise, this field contains the
|
||||
// owner, and thus keeps the owner alive.
|
||||
SLOT_BLOCKREFOWNER,
|
||||
|
||||
BLOCK_RESERVED_SLOTS
|
||||
};
|
||||
|
||||
template <ScalarTypeRepresentation::Type type, typename T>
|
||||
class NumericType
|
||||
{
|
||||
private:
|
||||
static const Class * typeToClass();
|
||||
public:
|
||||
static bool convert(JSContext *cx, HandleValue val, T* converted);
|
||||
static bool reify(JSContext *cx, void *mem, MutableHandleValue vp);
|
||||
static bool call(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
@ -251,6 +217,54 @@ class BinaryBlock
|
||||
};
|
||||
|
||||
|
||||
// Usage: ClampToUint8(v)
|
||||
//
|
||||
// Same as the C function ClampDoubleToUint8. `v` must be a number.
|
||||
bool ClampToUint8(ThreadSafeContext *cx, unsigned argc, Value *vp);
|
||||
extern const JSJitInfo ClampToUint8JitInfo;
|
||||
|
||||
// Usage: Memcpy(targetTypedObj, targetOffset,
|
||||
// sourceTypedObj, sourceOffset,
|
||||
// size)
|
||||
//
|
||||
// Intrinsic function. Copies size bytes from the data for
|
||||
// `sourceTypedObj` at `sourceOffset` into the data for
|
||||
// `targetTypedObj` at `targetOffset`.
|
||||
bool Memcpy(ThreadSafeContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
extern const JSJitInfo MemcpyJitInfo;
|
||||
|
||||
// Usage: StoreScalar(targetTypedObj, targetOffset, value)
|
||||
//
|
||||
// Intrinsic function. Stores value (which must be an int32 or uint32)
|
||||
// by `scalarTypeRepr` (which must be a type repr obj) and stores the
|
||||
// value at the memory for `targetTypedObj` at offset `targetOffset`.
|
||||
#define JS_STORE_SCALAR_CLASS_DEFN(_constant, T, _name) \
|
||||
class StoreScalar##T { \
|
||||
public: \
|
||||
static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp); \
|
||||
static const JSJitInfo JitInfo; \
|
||||
};
|
||||
|
||||
// Usage: LoadScalar(targetTypedObj, targetOffset, value)
|
||||
//
|
||||
// Intrinsic function. Loads value (which must be an int32 or uint32)
|
||||
// by `scalarTypeRepr` (which must be a type repr obj) and loads the
|
||||
// value at the memory for `targetTypedObj` at offset `targetOffset`.
|
||||
// `targetTypedObj` must be attached.
|
||||
#define JS_LOAD_SCALAR_CLASS_DEFN(_constant, T, _name) \
|
||||
class LoadScalar##T { \
|
||||
public: \
|
||||
static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp); \
|
||||
static const JSJitInfo JitInfo; \
|
||||
};
|
||||
|
||||
// I was using templates for this stuff instead of macros, but ran
|
||||
// into problems with the Unagi compiler.
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_STORE_SCALAR_CLASS_DEFN)
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_LOAD_SCALAR_CLASS_DEFN)
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* builtin_TypedObject_h */
|
||||
|
||||
|
311
js/src/builtin/TypedObject.js
Normal file
311
js/src/builtin/TypedObject.js
Normal file
@ -0,0 +1,311 @@
|
||||
#include "TypedObjectConstants.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Getters and setters for various slots.
|
||||
|
||||
// Type object slots
|
||||
|
||||
#define TYPE_TYPE_REPR(obj) \
|
||||
UnsafeGetReservedSlot(obj, JS_TYPEOBJ_SLOT_TYPE_REPR)
|
||||
|
||||
// Typed object slots
|
||||
|
||||
#define TYPED_TYPE_OBJ(obj) \
|
||||
UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_TYPE_OBJ)
|
||||
|
||||
// Type repr slots
|
||||
|
||||
#define REPR_KIND(obj) \
|
||||
TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_KIND))
|
||||
#define REPR_SIZE(obj) \
|
||||
TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_SIZE))
|
||||
#define REPR_ALIGNMENT(obj) \
|
||||
TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_ALIGNMENT))
|
||||
#define REPR_LENGTH(obj) \
|
||||
TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_LENGTH))
|
||||
#define REPR_TYPE(obj) \
|
||||
TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_TYPE))
|
||||
|
||||
#define HAS_PROPERTY(obj, prop) \
|
||||
callFunction(std_Object_hasOwnProperty, obj, prop)
|
||||
|
||||
function TYPED_TYPE_REPR(obj) {
|
||||
// Eventually this will be a slot on typed objects
|
||||
return TYPE_TYPE_REPR(TYPED_TYPE_OBJ(obj));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TypedObjectPointer
|
||||
//
|
||||
// TypedObjectPointers are internal structs used to represent a
|
||||
// pointer into typed object memory. They pull together:
|
||||
// - typeRepr: the internal type representation
|
||||
// - typeObj: the user-visible type object
|
||||
// - owner: the owner object that contains the allocated block of memory
|
||||
// - offset: an offset into that owner object
|
||||
//
|
||||
// They are basically equivalent to a typed object, except that they
|
||||
// offer lots of internal unsafe methods and are not native objects.
|
||||
// These should never escape into user code; ideally ion would stack
|
||||
// allocate them.
|
||||
//
|
||||
// Most `TypedObjectPointers` methods are written in a "chaining"
|
||||
// style, meaning that they return `this`. This is true even though
|
||||
// they mutate the receiver in place, because it makes for prettier
|
||||
// code.
|
||||
|
||||
function TypedObjectPointer(typeRepr, typeObj, owner, offset) {
|
||||
this.typeRepr = typeRepr;
|
||||
this.typeObj = typeObj;
|
||||
this.owner = owner;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
MakeConstructible(TypedObjectPointer, {});
|
||||
|
||||
#ifdef DEBUG
|
||||
TypedObjectPointer.prototype.toString = function() {
|
||||
return "Ptr(" + this.typeObj.toSource() + " @ " + this.offset + ")";
|
||||
};
|
||||
#endif
|
||||
|
||||
TypedObjectPointer.prototype.copy = function() {
|
||||
return new TypedObjectPointer(this.typeRepr, this.typeObj,
|
||||
this.owner, this.offset);
|
||||
};
|
||||
|
||||
TypedObjectPointer.prototype.reset = function(inPtr) {
|
||||
this.typeRepr = inPtr.typeRepr;
|
||||
this.typeObj = inPtr.typeObj;
|
||||
this.owner = inPtr.owner;
|
||||
this.offset = inPtr.offset;
|
||||
return this;
|
||||
};
|
||||
|
||||
TypedObjectPointer.prototype.kind = function() {
|
||||
return REPR_KIND(this.typeRepr);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Moving the pointer
|
||||
//
|
||||
// The methods in this section adjust `this` in place to point at
|
||||
// subelements or subproperties.
|
||||
|
||||
// Adjusts `this` in place so that it points at the property
|
||||
// `propName`. Throws if there is no such property. Returns `this`.
|
||||
TypedObjectPointer.prototype.moveTo = function(propName) {
|
||||
switch (this.kind()) {
|
||||
case JS_TYPEREPR_SCALAR_KIND:
|
||||
break;
|
||||
|
||||
case JS_TYPEREPR_ARRAY_KIND:
|
||||
// For an array, property must be an element. Note that we use the
|
||||
// length as loaded from the type *representation* as opposed to
|
||||
// the type *object*; this is because some type objects represent
|
||||
// unsized arrays and hence do not have a length.
|
||||
var index = TO_INT32(propName);
|
||||
if (index === propName && index < REPR_LENGTH(this.typeRepr))
|
||||
return this.moveToElem(index);
|
||||
break;
|
||||
|
||||
case JS_TYPEREPR_STRUCT_KIND:
|
||||
if (HAS_PROPERTY(this.typeObj.fieldTypes, propName))
|
||||
return this.moveToField(propName);
|
||||
break;
|
||||
}
|
||||
|
||||
ThrowError(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, propName);
|
||||
};
|
||||
|
||||
// Adjust `this` in place to point at the element `index`. `this`
|
||||
// must be a array type and `index` must be within bounds. Returns
|
||||
// `this`.
|
||||
TypedObjectPointer.prototype.moveToElem = function(index) {
|
||||
assert(this.kind() == JS_TYPEREPR_ARRAY_KIND,
|
||||
"moveToElem invoked on non-array");
|
||||
assert(index < REPR_LENGTH(this.typeRepr),
|
||||
"moveToElem invoked with out-of-bounds index");
|
||||
|
||||
var elementTypeObj = this.typeObj.elementType;
|
||||
var elementTypeRepr = TYPE_TYPE_REPR(elementTypeObj);
|
||||
this.typeRepr = elementTypeRepr;
|
||||
this.typeObj = elementTypeObj;
|
||||
var elementSize = REPR_SIZE(elementTypeRepr);
|
||||
|
||||
// Note: we do not allow construction of arrays where the offset
|
||||
// of an element cannot be represented by an int32.
|
||||
this.offset += std_Math_imul(index, elementSize);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Adjust `this` to point at the field `propName`. `this` must be a
|
||||
// struct type and `propName` must be a valid field name. Returns
|
||||
// `this`.
|
||||
TypedObjectPointer.prototype.moveToField = function(propName) {
|
||||
assert(this.kind() == JS_TYPEREPR_STRUCT_KIND,
|
||||
"moveToField invoked on non-struct");
|
||||
assert(HAS_PROPERTY(this.typeObj.fieldTypes, propName),
|
||||
"moveToField invoked with undefined field");
|
||||
|
||||
var fieldTypeObj = this.typeObj.fieldTypes[propName];
|
||||
var fieldOffset = TO_INT32(this.typeObj.fieldOffsets[propName]);
|
||||
this.typeObj = fieldTypeObj;
|
||||
this.typeRepr = TYPE_TYPE_REPR(fieldTypeObj);
|
||||
|
||||
// Note: we do not allow construction of structs where the
|
||||
// offset of a field cannot be represented by an int32.
|
||||
this.offset += fieldOffset;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Setting values
|
||||
//
|
||||
// The methods in this section modify the data pointed at by `this`.
|
||||
|
||||
// Assigns `fromValue` to the memory pointed at by `this`, adapting it
|
||||
// to `typeRepr` as needed. This is the most general entry point and
|
||||
// works for any type.
|
||||
TypedObjectPointer.prototype.set = function(fromValue) {
|
||||
var typeRepr = this.typeRepr;
|
||||
|
||||
// Fast path: `fromValue` is a typed object with same type
|
||||
// representation as the destination. In that case, we can just do a
|
||||
// memcpy.
|
||||
if (IsObject(fromValue) && HaveSameClass(fromValue, this.owner)) {
|
||||
if (TYPED_TYPE_REPR(fromValue) === typeRepr) {
|
||||
var size = REPR_SIZE(typeRepr);
|
||||
Memcpy(this.owner, this.offset, fromValue, 0, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (REPR_KIND(typeRepr)) {
|
||||
case JS_TYPEREPR_SCALAR_KIND:
|
||||
this.setScalar(fromValue);
|
||||
return;
|
||||
|
||||
case JS_TYPEREPR_ARRAY_KIND:
|
||||
if (!IsObject(fromValue))
|
||||
break;
|
||||
|
||||
// Check that "array-like" fromValue has an appropriate length.
|
||||
var length = REPR_LENGTH(typeRepr);
|
||||
if (fromValue.length !== length)
|
||||
break;
|
||||
|
||||
// Adapt each element.
|
||||
var tempPtr = this.copy().moveToElem(0);
|
||||
var size = REPR_SIZE(tempPtr.typeRepr);
|
||||
for (var i = 0; i < length; i++) {
|
||||
tempPtr.set(fromValue[i]);
|
||||
tempPtr.offset += size;
|
||||
}
|
||||
return;
|
||||
|
||||
case JS_TYPEREPR_STRUCT_KIND:
|
||||
if (!IsObject(fromValue))
|
||||
break;
|
||||
|
||||
// Adapt each field.
|
||||
var tempPtr = this.copy();
|
||||
var fieldNames = this.typeObj.fieldNames;
|
||||
for (var i = 0; i < fieldNames.length; i++) {
|
||||
var fieldName = fieldNames[i];
|
||||
tempPtr.reset(this).moveToField(fieldName).set(fromValue[fieldName]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ThrowError(JSMSG_CANT_CONVERT_TO,
|
||||
typeof(fromValue),
|
||||
this.typeRepr.toSource())
|
||||
}
|
||||
|
||||
// Sets `fromValue` to `this` assuming that `this` is a scalar type.
|
||||
TypedObjectPointer.prototype.setScalar = function(fromValue) {
|
||||
assert(REPR_KIND(this.typeRepr) == JS_TYPEREPR_SCALAR_KIND,
|
||||
"setScalar called with non-scalar");
|
||||
|
||||
var type = REPR_TYPE(this.typeRepr);
|
||||
switch (type) {
|
||||
case JS_SCALARTYPEREPR_INT8:
|
||||
return Store_int8(this.owner, this.offset,
|
||||
TO_INT32(fromValue) & 0xFF);
|
||||
|
||||
case JS_SCALARTYPEREPR_UINT8:
|
||||
return Store_uint8(this.owner, this.offset,
|
||||
TO_UINT32(fromValue) & 0xFF);
|
||||
|
||||
case JS_SCALARTYPEREPR_UINT8_CLAMPED:
|
||||
var v = ClampToUint8(+fromValue);
|
||||
return Store_int8(this.owner, this.offset, v);
|
||||
|
||||
case JS_SCALARTYPEREPR_INT16:
|
||||
return Store_int16(this.owner, this.offset,
|
||||
TO_INT32(fromValue) & 0xFFFF);
|
||||
|
||||
case JS_SCALARTYPEREPR_UINT16:
|
||||
return Store_uint16(this.owner, this.offset,
|
||||
TO_UINT32(fromValue) & 0xFFFF);
|
||||
|
||||
case JS_SCALARTYPEREPR_INT32:
|
||||
return Store_int32(this.owner, this.offset,
|
||||
TO_INT32(fromValue));
|
||||
|
||||
case JS_SCALARTYPEREPR_UINT32:
|
||||
return Store_uint32(this.owner, this.offset,
|
||||
TO_UINT32(fromValue));
|
||||
|
||||
case JS_SCALARTYPEREPR_FLOAT32:
|
||||
return Store_float32(this.owner, this.offset, +fromValue);
|
||||
|
||||
case JS_SCALARTYPEREPR_FLOAT64:
|
||||
return Store_float64(this.owner, this.offset, +fromValue);
|
||||
}
|
||||
|
||||
assert(false, "Unhandled scalar type: " + type);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ Wrappers
|
||||
//
|
||||
// These helpers are invoked by C++ code or used as method bodies.
|
||||
|
||||
// Wrapper for use from C++ code.
|
||||
function ConvertAndCopyTo(destTypeRepr,
|
||||
destTypeObj,
|
||||
destTypedObj,
|
||||
destOffset,
|
||||
fromValue)
|
||||
{
|
||||
var ptr = new TypedObjectPointer(destTypeRepr, destTypeObj,
|
||||
destTypedObj, destOffset);
|
||||
ptr.set(fromValue);
|
||||
}
|
||||
|
||||
function FillTypedArrayWithValue(destArray, fromValue) {
|
||||
var typeRepr = TYPED_TYPE_REPR(destArray);
|
||||
var length = REPR_LENGTH(typeRepr);
|
||||
if (length === 0)
|
||||
return;
|
||||
|
||||
// Use convert and copy to to produce the first element:
|
||||
var ptr = new TypedObjectPointer(typeRepr,
|
||||
TYPED_TYPE_OBJ(destArray),
|
||||
destArray,
|
||||
0);
|
||||
ptr.moveToElem(0);
|
||||
ptr.set(fromValue);
|
||||
|
||||
// Stamp out the remaining copies:
|
||||
var elementSize = REPR_SIZE(ptr.typeRepr);
|
||||
var totalSize = length * elementSize;
|
||||
for (var offset = elementSize; offset < totalSize; offset += elementSize)
|
||||
Memcpy(destArray, offset, destArray, 0, elementSize);
|
||||
}
|
||||
|
||||
|
86
js/src/builtin/TypedObjectConstants.h
Normal file
86
js/src/builtin/TypedObjectConstants.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
// Specialized .h file to be used by both JS and C++ code.
|
||||
|
||||
#ifndef builtin_TypedObjectConstants_h
|
||||
#define builtin_TypedObjectConstants_h
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Slots for type objects
|
||||
//
|
||||
// Some slots apply to all type objects and some are specific to
|
||||
// particular kinds of type objects. Because all type objects, at
|
||||
// least for now, have a distinct class, we can assign them distinct
|
||||
// numbers of slots depending on their kind.
|
||||
|
||||
// Slots on all type objects
|
||||
#define JS_TYPEOBJ_SLOT_TYPE_REPR 0 // Associated Type Representation
|
||||
|
||||
// Slots on scalars
|
||||
#define JS_TYPEOBJ_SCALAR_SLOTS 1 // Maximum number
|
||||
|
||||
// Slots on arrays
|
||||
#define JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE 1
|
||||
#define JS_TYPEOBJ_ARRAY_SLOTS 2 // Maximum number
|
||||
|
||||
// Slots on structs
|
||||
#define JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES 1
|
||||
#define JS_TYPEOBJ_STRUCT_SLOTS 2 // Maximum number
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Slots for type representation objects
|
||||
//
|
||||
// Some slots apply to all type representations and some are specific
|
||||
// to particular kinds of type representations. Because all type
|
||||
// representations share the same class, however, they always have the
|
||||
// same number of slots, though not all of them will be initialized or
|
||||
// used in the same way.
|
||||
|
||||
// Slots on *all* type objects:
|
||||
#define JS_TYPEREPR_SLOT_KIND 0 // One of the `kind` constants below
|
||||
#define JS_TYPEREPR_SLOT_SIZE 1 // Size in bytes.
|
||||
#define JS_TYPEREPR_SLOT_ALIGNMENT 2 // Alignment in bytes.
|
||||
|
||||
// Slots on arrays:
|
||||
#define JS_TYPEREPR_SLOT_LENGTH 3 // Length of the array
|
||||
|
||||
// Slots on scalars:
|
||||
#define JS_TYPEREPR_SLOT_TYPE 3 // One of the constants below
|
||||
|
||||
// Maximum number of slots for any type representation
|
||||
#define JS_TYPEREPR_SLOTS 4
|
||||
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer TypeRepresentation::Scalar etc, since that allows you to
|
||||
// write a switch which will receive a warning if you omit a case.
|
||||
#define JS_TYPEREPR_SCALAR_KIND 0
|
||||
#define JS_TYPEREPR_STRUCT_KIND 1
|
||||
#define JS_TYPEREPR_ARRAY_KIND 2
|
||||
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer ScalarTypeRepresentation::TYPE_INT8 etc, since that allows
|
||||
// you to write a switch which will receive a warning if you omit a
|
||||
// case.
|
||||
#define JS_SCALARTYPEREPR_INT8 0
|
||||
#define JS_SCALARTYPEREPR_UINT8 1
|
||||
#define JS_SCALARTYPEREPR_INT16 2
|
||||
#define JS_SCALARTYPEREPR_UINT16 3
|
||||
#define JS_SCALARTYPEREPR_INT32 4
|
||||
#define JS_SCALARTYPEREPR_UINT32 5
|
||||
#define JS_SCALARTYPEREPR_FLOAT32 6
|
||||
#define JS_SCALARTYPEREPR_FLOAT64 7
|
||||
#define JS_SCALARTYPEREPR_UINT8_CLAMPED 8
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Slots for typed objects
|
||||
|
||||
#define JS_TYPEDOBJ_SLOT_TYPE_OBJ 0 // Type object for a given typed object
|
||||
#define JS_TYPEDOBJ_SLOT_OWNER 1 // Owner of data (if null, this is owner)
|
||||
#define JS_TYPEDOBJ_SLOTS 2 // Number of slots for typed objs
|
||||
|
||||
#endif
|
@ -55,6 +55,7 @@ var std_Function_apply = Function.prototype.apply;
|
||||
var std_Math_floor = Math.floor;
|
||||
var std_Math_max = Math.max;
|
||||
var std_Math_min = Math.min;
|
||||
var std_Math_imul = Math.imul;
|
||||
var std_Number_valueOf = Number.prototype.valueOf;
|
||||
var std_Number_POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
||||
var std_Object_create = Object.create;
|
||||
|
@ -9510,7 +9510,8 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj)
|
||||
if (typedObj->isNewDerivedTypedObject())
|
||||
return typedObj->toNewDerivedTypedObject()->type();
|
||||
|
||||
MInstruction *load = MLoadFixedSlot::New(typedObj, js::SLOT_DATATYPE);
|
||||
MInstruction *load = MLoadFixedSlot::New(typedObj,
|
||||
JS_TYPEDOBJ_SLOT_TYPE_OBJ);
|
||||
current->add(load);
|
||||
return load;
|
||||
}
|
||||
@ -9598,7 +9599,7 @@ IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
|
||||
{
|
||||
// Load list of field type objects.
|
||||
|
||||
MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, SLOT_STRUCT_FIELD_TYPES);
|
||||
MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, JS_TYPEOBJ_SLOT_STRUCT_FIELD_TYPES);
|
||||
current->add(fieldTypes);
|
||||
|
||||
// Index into list with index of field.
|
||||
|
@ -415,3 +415,5 @@ MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPE_OBJECT, 361, 0, JSEXN_ERR, "Expected a type o
|
||||
MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 362, 0, JSEXN_RANGEERR, "too many constructor arguments")
|
||||
MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 363, 0, JSEXN_RANGEERR, "too many function arguments")
|
||||
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE, 364, 2, JSEXN_ERR, "{0} is not a debuggee {1}")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 365, 0, JSEXN_ERR, "Expected a typed object")
|
||||
MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 366, 1, JSEXN_TYPEERR, "No such property: {0}")
|
||||
|
@ -739,6 +739,16 @@ enum ErrorArgumentsType {
|
||||
ArgumentsAreASCII
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Loads and returns a self-hosted function by name. For performance, define
|
||||
* the property name in vm/CommonPropertyNames.h.
|
||||
*
|
||||
* Defined in SelfHosting.cpp.
|
||||
*/
|
||||
JSFunction *
|
||||
SelfHostedFunction(JSContext *cx, HandlePropertyName propName);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef va_start
|
||||
|
15
js/src/tests/ecma_6/TypedObject/Bug914137.js
Normal file
15
js/src/tests/ecma_6/TypedObject/Bug914137.js
Normal file
@ -0,0 +1,15 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
|
||||
var BUGNUMBER = 914137;
|
||||
var summary = 'Fuzz bug';
|
||||
|
||||
function test() {
|
||||
var A = new TypedObject.ArrayType(TypedObject.uint8, 2147483647);
|
||||
var a = new A();
|
||||
assertEq(arguments[5], a);
|
||||
}
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
assertThrows(test);
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
print("Tests complete");
|
@ -97,7 +97,7 @@ function runTests() {
|
||||
assertEq(mario[0][2], 0);
|
||||
|
||||
assertThrows(function() mario[1] = 5);
|
||||
mario[1][1] = [];
|
||||
mario[1][1] = {};
|
||||
assertEq(Number.isNaN(mario[1][1]), true);
|
||||
|
||||
// ok this is just for kicks
|
||||
|
@ -113,7 +113,7 @@ function runTests()
|
||||
check(function() type.toString() === floatStrings[i]);
|
||||
check(function() type(null) == 0);
|
||||
check(function() Number.isNaN(type(undefined)));
|
||||
check(function() Number.isNaN(type([])));
|
||||
check(function() type([]) == 0);
|
||||
check(function() Number.isNaN(type({})));
|
||||
check(function() Number.isNaN(type(/abcd/)));
|
||||
|
||||
|
68
js/src/tests/ecma_6/TypedObject/scalar_types.js
Normal file
68
js/src/tests/ecma_6/TypedObject/scalar_types.js
Normal file
@ -0,0 +1,68 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
|
||||
|
||||
var BUGNUMBER = 578700;
|
||||
var summary = 'Byte-sized type conversion';
|
||||
|
||||
var T = TypedObject;
|
||||
|
||||
function check(results, ctor) {
|
||||
print("ctor = ", ctor.toSource());
|
||||
|
||||
// check applying the ctor directly
|
||||
for (var i = 0; i < results.length; i++)
|
||||
assertEq(results[i][0], ctor(results[i][1]));
|
||||
|
||||
// check writing and reading from a struct
|
||||
var S = new T.StructType({f: ctor});
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var s = new S({f: results[i][1]});
|
||||
assertEq(results[i][0], s.f);
|
||||
}
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var int8results = [
|
||||
[22, 22],
|
||||
[-128, 128],
|
||||
[-1, 255],
|
||||
[-128, -128],
|
||||
[127, -129],
|
||||
[0x75, 0x7575],
|
||||
[-123, 0x7585]
|
||||
];
|
||||
check(int8results, T.int8);
|
||||
|
||||
var uint8results = [
|
||||
[22, 22],
|
||||
[128, 128],
|
||||
[255, 255],
|
||||
[0, 256],
|
||||
[128, -128],
|
||||
[127, -129],
|
||||
[129, 129],
|
||||
[0x75, 0x7575],
|
||||
[0x85, 0x7585]
|
||||
];
|
||||
check(uint8results, T.uint8);
|
||||
|
||||
var uint8clampedresults = [
|
||||
[22, 22],
|
||||
[128, 128],
|
||||
[255, 255],
|
||||
[0, -128],
|
||||
[0, -129],
|
||||
[129, 129],
|
||||
[255, 0x7575],
|
||||
[255, 0x7585]
|
||||
];
|
||||
check(uint8clampedresults, T.uint8Clamped);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
||||
}
|
||||
|
||||
runTests();
|
@ -35,6 +35,7 @@
|
||||
macro(configurable, configurable, "configurable") \
|
||||
macro(construct, construct, "construct") \
|
||||
macro(constructor, constructor, "constructor") \
|
||||
macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \
|
||||
macro(currency, currency, "currency") \
|
||||
macro(currencyDisplay, currencyDisplay, "currencyDisplay") \
|
||||
macro(std_iterator, std_iterator, "@@iterator") \
|
||||
@ -62,6 +63,7 @@
|
||||
macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
|
||||
macro(fieldTypes, fieldTypes, "fieldTypes") \
|
||||
macro(fileName, fileName, "fileName") \
|
||||
macro(FillTypedArrayWithValue, FillTypedArrayWithValue, "FillTypedArrayWithValue") \
|
||||
macro(fix, fix, "fix") \
|
||||
macro(float32, float32, "float32") \
|
||||
macro(float64, float64, "float64") \
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "builtin/Intl.h"
|
||||
#include "builtin/ParallelArray.h"
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "vm/ForkJoin.h"
|
||||
#include "vm/Interpreter.h"
|
||||
@ -588,6 +589,23 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("ShouldForceSequential", intrinsic_ShouldForceSequential, 0,0),
|
||||
JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0),
|
||||
|
||||
// See builtin/TypedObject.h for descriptors of the typedobj functions.
|
||||
JS_FNINFO("ClampToUint8",
|
||||
JSNativeThreadSafeWrapper<js::ClampToUint8>,
|
||||
&js::ClampToUint8JitInfo, 1, 0),
|
||||
JS_FNINFO("Memcpy",
|
||||
JSNativeThreadSafeWrapper<js::Memcpy>,
|
||||
&js::MemcpyJitInfo, 5, 0),
|
||||
|
||||
#define LOAD_AND_STORE_FN_DECLS(_constant, _type, _name) \
|
||||
JS_FNINFO("Store_" #_name, \
|
||||
JSNativeThreadSafeWrapper<js::StoreScalar##_type::Func>, \
|
||||
&js::StoreScalar##_type::JitInfo, 3, 0), \
|
||||
JS_FNINFO("Load_" #_name, \
|
||||
JSNativeThreadSafeWrapper<js::LoadScalar##_type::Func>, \
|
||||
&js::LoadScalar##_type::JitInfo, 3, 0),
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_FN_DECLS)
|
||||
|
||||
// See builtin/Intl.h for descriptions of the intl_* functions.
|
||||
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
||||
JS_FN("intl_availableCollations", intl_availableCollations, 1,0),
|
||||
@ -911,3 +929,15 @@ JSRuntime::maybeWrappedSelfHostedFunction(JSContext *cx, HandleId id, MutableHan
|
||||
|
||||
return cx->compartment()->wrap(cx, funVal);
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
|
||||
{
|
||||
RootedValue func(cx);
|
||||
if (!cx->global()->getIntrinsicValue(cx, propName, &func))
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(func.isObject());
|
||||
JS_ASSERT(func.toObject().is<JSFunction>());
|
||||
return &func.toObject().as<JSFunction>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user