Bug 898362 - Self-host portions of the typed object logic r=till

This commit is contained in:
Nicholas D. Matsakis 2013-09-10 10:35:53 -04:00
parent 0a7ba1108d
commit 7ce97a4d6e
17 changed files with 945 additions and 419 deletions

View File

@ -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 := \

View File

@ -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;
}

View File

@ -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,16 +199,22 @@ class ScalarTypeRepresentation : public TypeRepresentation {
static JSObject *Create(JSContext *cx, Type type);
};
// Must be in same order as the enum:
// 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) \
macro_(ScalarTypeRepresentation::TYPE_UINT16, uint16_t, uint16) \
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)
// Must be in same order as the enum ScalarTypeRepresentation::Type:
#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_) \
macro_(ScalarTypeRepresentation::TYPE_INT8, int8_t, int8) \
macro_(ScalarTypeRepresentation::TYPE_UINT8, uint8_t, uint8) \
macro_(ScalarTypeRepresentation::TYPE_INT16, int16_t, int16) \
macro_(ScalarTypeRepresentation::TYPE_UINT16, uint16_t, uint16) \
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) \
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

View File

@ -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 */

View 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);
}

View 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

View File

@ -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;

View File

@ -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.

View File

@ -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}")

View File

@ -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

View 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");

View File

@ -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

View File

@ -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/)));

View 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();

View File

@ -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") \

View File

@ -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>();
}