зеркало из https://github.com/mozilla/gecko-dev.git
Bug 778559 - Implement ParallelArray API with sequential execution (r=dmandelin)
This commit is contained in:
Родитель
971cd5b3f4
Коммит
23c5258d59
|
@ -120,6 +120,7 @@ CPPSRCS = \
|
|||
BytecodeCompiler.cpp \
|
||||
BytecodeEmitter.cpp \
|
||||
FoldConstants.cpp \
|
||||
ParallelArray.cpp \
|
||||
ParseMaps.cpp \
|
||||
ParseNode.cpp \
|
||||
Parser.cpp \
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
#ifndef ParallelArray_inl_h__
|
||||
#define ParallelArray_inl_h__
|
||||
|
||||
#include "builtin/ParallelArray.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline uint32_t
|
||||
ParallelArrayObject::IndexInfo::scalarLengthOfDimensions()
|
||||
{
|
||||
JS_ASSERT(isInitialized());
|
||||
return dimensions[0] * partialProducts[0];
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
ParallelArrayObject::IndexInfo::toScalar()
|
||||
{
|
||||
JS_ASSERT(isInitialized());
|
||||
JS_ASSERT(indices.length() <= partialProducts.length());
|
||||
|
||||
if (indices.length() == 0)
|
||||
return 0;
|
||||
if (dimensions.length() == 1)
|
||||
return indices[0];
|
||||
|
||||
uint32_t index = indices[0] * partialProducts[0];
|
||||
for (uint32_t i = 1; i < indices.length(); i++)
|
||||
index += indices[i] * partialProducts[i];
|
||||
return index;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::IndexInfo::fromScalar(uint32_t index)
|
||||
{
|
||||
JS_ASSERT(isInitialized());
|
||||
if (!indices.resize(partialProducts.length()))
|
||||
return false;
|
||||
|
||||
if (dimensions.length() == 1) {
|
||||
indices[0] = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t prev = index;
|
||||
uint32_t d;
|
||||
for (d = 0; d < partialProducts.length() - 1; d++) {
|
||||
indices[d] = prev / partialProducts[d];
|
||||
prev = prev % partialProducts[d];
|
||||
}
|
||||
indices[d] = prev;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::IndexInfo::initialize(uint32_t space)
|
||||
{
|
||||
// Initialize using a manually set dimension vector.
|
||||
JS_ASSERT(dimensions.length() > 0);
|
||||
JS_ASSERT(space <= dimensions.length());
|
||||
|
||||
// Compute the partial products of the dimensions.
|
||||
//
|
||||
// NB: partialProducts[i] is the scalar length of dimension i. The scalar
|
||||
// length of the entire space is thus dimensions[0] * partialProducts[0].
|
||||
uint32_t ndims = dimensions.length();
|
||||
if (!partialProducts.resize(ndims))
|
||||
return false;
|
||||
partialProducts[ndims - 1] = 1;
|
||||
for (uint32_t i = ndims - 1; i > 0; i--)
|
||||
partialProducts[i - 1] = dimensions[i] * partialProducts[i];
|
||||
|
||||
// Reserve indices.
|
||||
return indices.reserve(ndims) && indices.resize(space);
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::IndexInfo::initialize(JSContext *cx, HandleParallelArrayObject source,
|
||||
uint32_t space)
|
||||
{
|
||||
// Initialize using a dimension vector gotten from a parallel array
|
||||
// source.
|
||||
if (!source->getDimensions(cx, dimensions))
|
||||
return false;
|
||||
|
||||
return initialize(space);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::DenseArrayToIndexVector(JSContext *cx, HandleObject obj,
|
||||
IndexVector &indices)
|
||||
{
|
||||
uint32_t length = obj->getDenseArrayInitializedLength();
|
||||
if (!indices.resize(length))
|
||||
return false;
|
||||
|
||||
// Read the index vector out of the dense array into an actual Vector for
|
||||
// ease of access. We're guaranteed that the elements of the dense array
|
||||
// are uint32s, so just cast.
|
||||
const Value *src = obj->getDenseArrayElements();
|
||||
const Value *end = src + length;
|
||||
for (uint32_t *dst = indices.begin(); src < end; dst++, src++)
|
||||
*dst = static_cast<uint32_t>(src->toInt32());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::is(const Value &v)
|
||||
{
|
||||
return v.isObject() && is(&v.toObject());
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::is(JSObject *obj)
|
||||
{
|
||||
return obj->hasClass(&class_);
|
||||
}
|
||||
|
||||
inline ParallelArrayObject *
|
||||
ParallelArrayObject::as(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(is(obj));
|
||||
return static_cast<ParallelArrayObject *>(obj);
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
ParallelArrayObject::dimensionArray()
|
||||
{
|
||||
JSObject &dimObj = getSlot(SLOT_DIMENSIONS).toObject();
|
||||
JS_ASSERT(dimObj.isDenseArray());
|
||||
return &dimObj;
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
ParallelArrayObject::buffer()
|
||||
{
|
||||
JSObject &buf = getSlot(SLOT_BUFFER).toObject();
|
||||
JS_ASSERT(buf.isDenseArray());
|
||||
return &buf;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
ParallelArrayObject::bufferOffset()
|
||||
{
|
||||
return static_cast<uint32_t>(getSlot(SLOT_BUFFER_OFFSET).toInt32());
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
ParallelArrayObject::outermostDimension()
|
||||
{
|
||||
return static_cast<uint32_t>(dimensionArray()->getDenseArrayElement(0).toInt32());
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::isOneDimensional()
|
||||
{
|
||||
return dimensionArray()->getDenseArrayInitializedLength() == 1;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::inOutermostDimensionRange(uint32_t index)
|
||||
{
|
||||
return index < outermostDimension();
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::inOutermostDimensionRange(JSContext *cx, HandleId id)
|
||||
{
|
||||
uint32_t i;
|
||||
return js_IdIsIndex(id, &i) && inOutermostDimensionRange(i);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ParallelArrayObject::getDimensions(JSContext *cx, IndexVector &dims)
|
||||
{
|
||||
RootedObject obj(cx, dimensionArray());
|
||||
if (!obj)
|
||||
return false;
|
||||
return DenseArrayToIndexVector(cx, obj, dims);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // ParallelArray_inl_h__
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,399 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* 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/. */
|
||||
|
||||
#ifndef ParallelArray_h__
|
||||
#define ParallelArray_h__
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class ParallelArrayObject;
|
||||
typedef Rooted<ParallelArrayObject *> RootedParallelArrayObject;
|
||||
typedef Handle<ParallelArrayObject *> HandleParallelArrayObject;
|
||||
|
||||
//
|
||||
// ParallelArray Overview
|
||||
//
|
||||
// Parallel arrays are immutable, possibly multi-dimensional arrays which
|
||||
// enable parallel computation based on a few base operations. The execution
|
||||
// model is one of fallback: try to execute operations in parallel, falling
|
||||
// back to sequential implementation if (for whatever reason) the operation
|
||||
// could not be executed in paralle. The API allows leeway to implementers to
|
||||
// decide both representation and what is considered parallelizable.
|
||||
//
|
||||
// Currently ParallelArray objects are backed by dense arrays for ease of
|
||||
// GC. For the higher-dimensional case, data is stored in a packed, row-major
|
||||
// order representation in the backing dense array. See notes below about
|
||||
// IndexInfo in how to convert between scalar offsets into the backing array
|
||||
// and a vector of indices.
|
||||
//
|
||||
// Except for the comprehension form, all operations (e.g. map, filter,
|
||||
// reduce) operate on the outermost dimension only. That is, those operations
|
||||
// only operate on the "rows" of the array. "Element" is used in context of
|
||||
// ParallelArray objects to mean any indexable value of a ParallelArray
|
||||
// object. For a one dimensional array, elements are always scalar values. For
|
||||
// a higher dimensional array, elements could either be scalar values
|
||||
// (i.e. leaves) or ParallelArray objects of lesser dimensions
|
||||
// (i.e. subarrays).
|
||||
//
|
||||
|
||||
class ParallelArrayObject : public JSObject {
|
||||
public:
|
||||
typedef Vector<uint32_t, 4> IndexVector;
|
||||
|
||||
//
|
||||
// Helper structure to help index higher-dimensional arrays to convert
|
||||
// between a vector of indices and scalar offsets for use in the flat
|
||||
// backing dense array.
|
||||
//
|
||||
// IndexInfo instances _must_ be initialized using one of the initialize
|
||||
// methods before use.
|
||||
//
|
||||
// Typical usage is stack allocating an IndexInfo, initializing it with a
|
||||
// particular source ParallelArray object's dimensionality, and mutating
|
||||
// the indices member vector. For instance, to iterate through everything
|
||||
// in the first 2 dimensions of an array of > 2 dimensions:
|
||||
//
|
||||
// IndexInfo iv(cx);
|
||||
// if (!iv.initialize(cx, source, 2))
|
||||
// return false;
|
||||
// for (uint32_t i = 0; i < iv.dimensions[0]; i++) {
|
||||
// for (uint32_t j = 0; j < iv.dimensions[1]; j++) {
|
||||
// iv.indices[0] = i;
|
||||
// iv.indices[1] = j;
|
||||
// if (source->getParallelArrayElement(cx, iv, &elem))
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Note from the above that it is not required to fill out the indices
|
||||
// vector up to the full dimensionality. For an N-dimensional array,
|
||||
// having an indices vector of length D < N indexes a subarray.
|
||||
//
|
||||
|
||||
struct IndexInfo {
|
||||
// Vector of indices. Should be large enough to hold up to
|
||||
// dimensions.length indices.
|
||||
IndexVector indices;
|
||||
|
||||
// Vector of dimensions of the ParallelArray object that the indices
|
||||
// are meant to index into.
|
||||
IndexVector dimensions;
|
||||
|
||||
// Cached partial products of the dimensions defined by the following
|
||||
// recurrence:
|
||||
//
|
||||
// partialProducts[n] =
|
||||
// 1 if n == |dimensions|
|
||||
// dimensions[n+1] * partialProducts[n+1] otherwise
|
||||
//
|
||||
// These are used for computing scalar offsets.
|
||||
IndexVector partialProducts;
|
||||
|
||||
IndexInfo(JSContext *cx)
|
||||
: indices(cx), dimensions(cx), partialProducts(cx)
|
||||
{}
|
||||
|
||||
// Prepares indices and computes partial products. The space argument
|
||||
// is the index space. The indices vector is resized to be of length
|
||||
// space.
|
||||
//
|
||||
// The dimensions vector must be filled already, and space must be <=
|
||||
// dimensions.length().
|
||||
inline bool initialize(uint32_t space);
|
||||
|
||||
// Load dimensions from a source, then initialize as above.
|
||||
inline bool initialize(JSContext *cx, HandleParallelArrayObject source,
|
||||
uint32_t space);
|
||||
|
||||
// Get the scalar length according to the dimensions vector, i.e. the
|
||||
// product of the dimensions vector.
|
||||
inline uint32_t scalarLengthOfDimensions();
|
||||
|
||||
// Compute the scalar index from the current index vector.
|
||||
inline uint32_t toScalar();
|
||||
|
||||
// Set the index vector according to a scalar index.
|
||||
inline bool fromScalar(uint32_t index);
|
||||
|
||||
bool isInitialized();
|
||||
};
|
||||
|
||||
static JSObject *initClass(JSContext *cx, JSObject *obj);
|
||||
static Class class_;
|
||||
|
||||
static inline bool is(const Value &v);
|
||||
static inline bool is(JSObject *obj);
|
||||
static inline ParallelArrayObject *as(JSObject *obj);
|
||||
|
||||
inline JSObject *dimensionArray();
|
||||
inline JSObject *buffer();
|
||||
inline uint32_t bufferOffset();
|
||||
inline uint32_t outermostDimension();
|
||||
inline bool isOneDimensional();
|
||||
inline bool inOutermostDimensionRange(uint32_t index);
|
||||
inline bool inOutermostDimensionRange(JSContext *cx, HandleId id);
|
||||
inline bool getDimensions(JSContext *cx, IndexVector &dims);
|
||||
|
||||
// Specialized for one dimensional arrays. Use this if possible.
|
||||
bool getElementFromOnlyDimension(JSContext *cx, uint32_t index, MutableHandleValue vp);
|
||||
|
||||
// The general case; works for arrays of any dimensionality.
|
||||
bool getParallelArrayElement(JSContext *cx, IndexInfo &iv, MutableHandleValue vp);
|
||||
|
||||
// Convenience function for getting an element from the outermost
|
||||
// dimension in the general case. This creates a temporary IndexInfo of
|
||||
// length 1 with the 1st index set to the index parameter.
|
||||
bool getParallelArrayElement(JSContext *cx, uint32_t index, MutableHandleValue vp);
|
||||
|
||||
bool toStringBuffer(JSContext *cx, bool useLocale, StringBuffer &sb);
|
||||
|
||||
private:
|
||||
enum {
|
||||
// The ParallelArray API refers to dimensions as "shape", but to avoid
|
||||
// confusion with the internal engine notion of a shape we call it
|
||||
// "dimensions" here.
|
||||
SLOT_DIMENSIONS = 0,
|
||||
|
||||
// Underlying dense array.
|
||||
SLOT_BUFFER,
|
||||
|
||||
// First index of the underlying buffer to be considered in bounds.
|
||||
SLOT_BUFFER_OFFSET,
|
||||
|
||||
RESERVED_SLOTS
|
||||
};
|
||||
|
||||
enum ExecutionStatus {
|
||||
ExecutionFailed = 0,
|
||||
ExecutionCompiled,
|
||||
ExecutionSucceeded
|
||||
};
|
||||
|
||||
// Execution modes are kept as static instances of structs that implement
|
||||
// a signature that comprises of build, map, fold, scatter, and filter,
|
||||
// whose argument lists are defined in the macros below.
|
||||
//
|
||||
// Even though the base class |ExecutionMode| is purely abstract, we only
|
||||
// use dynamic dispatch when using the debug options. Almost always we
|
||||
// directly call the member function on one of the statics.
|
||||
|
||||
#define JS_PA_build_ARGS \
|
||||
JSContext *cx, \
|
||||
IndexInfo &iv, \
|
||||
HandleObject elementalFun, \
|
||||
HandleObject buffer
|
||||
|
||||
#define JS_PA_map_ARGS \
|
||||
JSContext *cx, \
|
||||
HandleParallelArrayObject source, \
|
||||
HandleObject elementalFun, \
|
||||
HandleObject buffer
|
||||
|
||||
#define JS_PA_reduce_ARGS \
|
||||
JSContext *cx, \
|
||||
HandleParallelArrayObject source, \
|
||||
HandleObject elementalFun, \
|
||||
HandleObject buffer, \
|
||||
MutableHandleValue vp
|
||||
|
||||
#define JS_PA_scatter_ARGS \
|
||||
JSContext *cx, \
|
||||
HandleParallelArrayObject source, \
|
||||
HandleObject targets, \
|
||||
const Value &defaultValue, \
|
||||
HandleObject conflictFun, \
|
||||
HandleObject buffer
|
||||
|
||||
#define JS_PA_filter_ARGS \
|
||||
JSContext *cx, \
|
||||
HandleParallelArrayObject source, \
|
||||
HandleObject filters, \
|
||||
HandleObject buffer
|
||||
|
||||
#define JS_PA_DECLARE_OP(NAME) \
|
||||
ExecutionStatus NAME(JS_PA_ ## NAME ## _ARGS)
|
||||
|
||||
#define JS_PA_DECLARE_ALL_OPS \
|
||||
JS_PA_DECLARE_OP(build); \
|
||||
JS_PA_DECLARE_OP(map); \
|
||||
JS_PA_DECLARE_OP(reduce); \
|
||||
JS_PA_DECLARE_OP(scatter); \
|
||||
JS_PA_DECLARE_OP(filter);
|
||||
|
||||
class ExecutionMode {
|
||||
public:
|
||||
// The comprehension form. Builds a higher-dimensional array using a
|
||||
// kernel function.
|
||||
virtual JS_PA_DECLARE_OP(build) = 0;
|
||||
|
||||
// Maps a kernel function over the outermost dimension of the array.
|
||||
virtual JS_PA_DECLARE_OP(map) = 0;
|
||||
|
||||
// Reduce to a value using a kernel function. Scan is like reduce, but
|
||||
// keeps the intermediate results in an array.
|
||||
virtual JS_PA_DECLARE_OP(reduce) = 0;
|
||||
|
||||
// Scatter elements according to an index map.
|
||||
virtual JS_PA_DECLARE_OP(scatter) = 0;
|
||||
|
||||
// Filter elements according to a truthy array.
|
||||
virtual JS_PA_DECLARE_OP(filter) = 0;
|
||||
|
||||
virtual const char *toString() = 0;
|
||||
};
|
||||
|
||||
// Fallback means try parallel first, and if unable to execute in
|
||||
// parallel, execute sequentially.
|
||||
class FallbackMode : public ExecutionMode {
|
||||
public:
|
||||
JS_PA_DECLARE_ALL_OPS
|
||||
const char *toString() { return "fallback"; }
|
||||
};
|
||||
|
||||
class ParallelMode : public ExecutionMode {
|
||||
public:
|
||||
JS_PA_DECLARE_ALL_OPS
|
||||
const char *toString() { return "parallel"; }
|
||||
};
|
||||
|
||||
class SequentialMode : public ExecutionMode {
|
||||
public:
|
||||
JS_PA_DECLARE_ALL_OPS
|
||||
const char *toString() { return "sequential"; }
|
||||
};
|
||||
|
||||
static SequentialMode sequential;
|
||||
static ParallelMode parallel;
|
||||
static FallbackMode fallback;
|
||||
|
||||
#undef JS_PA_build_ARGS
|
||||
#undef JS_PA_map_ARGS
|
||||
#undef JS_PA_reduce_ARGS
|
||||
#undef JS_PA_scatter_ARGS
|
||||
#undef JS_PA_filter_ARGS
|
||||
#undef JS_PA_DECLARE_OP
|
||||
#undef JS_PA_DECLARE_ALL_OPS
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug options can be passed in as an extra argument to the
|
||||
// operations. The grammar is:
|
||||
//
|
||||
// options ::= { mode: "par" | "seq",
|
||||
// expect: "fail" | "bail" | "success" }
|
||||
struct DebugOptions {
|
||||
ExecutionMode *mode;
|
||||
ExecutionStatus expect;
|
||||
bool init(JSContext *cx, const Value &v);
|
||||
bool check(JSContext *cx, ExecutionStatus actual);
|
||||
};
|
||||
|
||||
static const char *ExecutionStatusToString(ExecutionStatus ss);
|
||||
#endif
|
||||
|
||||
static JSFunctionSpec methods[];
|
||||
static Class protoClass;
|
||||
|
||||
static inline bool DenseArrayToIndexVector(JSContext *cx, HandleObject obj,
|
||||
IndexVector &indices);
|
||||
|
||||
bool toStringBufferImpl(JSContext *cx, IndexInfo &iv, bool useLocale,
|
||||
HandleObject buffer, StringBuffer &sb);
|
||||
|
||||
static bool create(JSContext *cx, MutableHandleValue vp);
|
||||
static bool create(JSContext *cx, HandleObject buffer, MutableHandleValue vp);
|
||||
static bool create(JSContext *cx, HandleObject buffer, uint32_t offset,
|
||||
const IndexVector &dims, MutableHandleValue vp);
|
||||
static JSBool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool map(JSContext *cx, CallArgs args);
|
||||
static bool reduce(JSContext *cx, CallArgs args);
|
||||
static bool scan(JSContext *cx, CallArgs args);
|
||||
static bool scatter(JSContext *cx, CallArgs args);
|
||||
static bool filter(JSContext *cx, CallArgs args);
|
||||
static bool flatten(JSContext *cx, CallArgs args);
|
||||
static bool partition(JSContext *cx, CallArgs args);
|
||||
static bool get(JSContext *cx, CallArgs args);
|
||||
static bool dimensionsGetter(JSContext *cx, CallArgs args);
|
||||
static bool lengthGetter(JSContext *cx, CallArgs args);
|
||||
static bool toString(JSContext *cx, CallArgs args);
|
||||
static bool toLocaleString(JSContext *cx, CallArgs args);
|
||||
static bool toSource(JSContext *cx, CallArgs args);
|
||||
|
||||
static void mark(JSTracer *trc, JSObject *obj);
|
||||
static JSBool lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
static JSBool lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
static JSBool lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
static JSBool lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
static JSBool defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
|
||||
JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
static JSBool defineProperty(JSContext *cx, HandleObject obj,
|
||||
HandlePropertyName name, HandleValue value,
|
||||
JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
static JSBool defineElement(JSContext *cx, HandleObject obj,
|
||||
uint32_t index, HandleValue value,
|
||||
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
static JSBool defineSpecial(JSContext *cx, HandleObject obj,
|
||||
HandleSpecialId sid, HandleValue value,
|
||||
PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
|
||||
static JSBool getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp);
|
||||
static JSBool getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
HandlePropertyName name, MutableHandleValue vp);
|
||||
static JSBool getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
uint32_t index, MutableHandleValue vp);
|
||||
static JSBool getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
HandleSpecialId sid, MutableHandleValue vp);
|
||||
static JSBool setGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleValue vp, JSBool strict);
|
||||
static JSBool setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
MutableHandleValue vp, JSBool strict);
|
||||
static JSBool setElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleValue vp, JSBool strict);
|
||||
static JSBool setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
MutableHandleValue vp, JSBool strict);
|
||||
static JSBool getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,
|
||||
unsigned *attrsp);
|
||||
static JSBool getPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
unsigned *attrsp);
|
||||
static JSBool getElementAttributes(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
unsigned *attrsp);
|
||||
static JSBool getSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
unsigned *attrsp);
|
||||
static JSBool setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id,
|
||||
unsigned *attrsp);
|
||||
static JSBool setPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
unsigned *attrsp);
|
||||
static JSBool setElementAttributes(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
unsigned *attrsp);
|
||||
static JSBool setSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
unsigned *attrsp);
|
||||
static JSBool deleteGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
MutableHandleValue rval, JSBool strict);
|
||||
static JSBool deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
|
||||
MutableHandleValue rval, JSBool strict);
|
||||
static JSBool deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleValue rval, JSBool strict);
|
||||
static JSBool deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
|
||||
MutableHandleValue rval, JSBool strict);
|
||||
static JSBool enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
|
||||
Value *statep, jsid *idp);
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
extern JSObject *
|
||||
js_InitParallelArrayClass(JSContext *cx, JSObject *obj);
|
||||
|
||||
#endif // ParallelArray_h__
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
function buildComprehension() {
|
||||
// 1D comprehension
|
||||
var p = new ParallelArray(10, function (idx) { return idx; });
|
||||
var a = [0,1,2,3,4,5,6,7,8,9];
|
||||
assertEq(p.toString(), "<" + a.join(",") + ">");
|
||||
}
|
||||
|
||||
buildComprehension();
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
function buildMultidim() {
|
||||
// 2D comprehension
|
||||
var p = new ParallelArray([2,2], function (i,j) { return i + j; });
|
||||
assertEq(p.shape.toString(), [2,2].toString());
|
||||
assertEq(p.toString(), "<<0,1>,<1,2>>");
|
||||
}
|
||||
|
||||
buildMultidim();
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
function buildComprehension() {
|
||||
// Test kernel function arguments
|
||||
var shape = [];
|
||||
for (var i = 0; i < 8; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function () {
|
||||
assertEq(arguments.length, shape.length);
|
||||
for (var j = 0; j < shape.length; j++)
|
||||
assertEq(arguments[j] >= 0 && arguments[j] < shape[j], true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
buildComprehension();
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
function buildComprehension() {
|
||||
var H = 96;
|
||||
var W = 96;
|
||||
var d = 4;
|
||||
// 3D 96x96x4 texture-like PA
|
||||
var p = new ParallelArray([H,W,d], function (i,j,k) { return i + j + k; });
|
||||
var a = "<";
|
||||
for (var i = 0; i < H; i++) {
|
||||
a += "<";
|
||||
for (var j = 0; j < W; j++) {
|
||||
a += "<";
|
||||
for (var k = 0; k < d; k++) {
|
||||
a += i+j+k;
|
||||
if (k !== d - 1)
|
||||
a += ",";
|
||||
}
|
||||
a += ">";
|
||||
if (j !== W - 1)
|
||||
a += ","
|
||||
}
|
||||
a += ">";
|
||||
if (i !== H - 1)
|
||||
a += ","
|
||||
}
|
||||
a += ">"
|
||||
|
||||
assertEq(p.toString(), a);
|
||||
}
|
||||
|
||||
buildComprehension();
|
|
@ -0,0 +1,7 @@
|
|||
// |jit-test| error: TypeError;
|
||||
function buildComprehension() {
|
||||
// Throws if elemental fun not callable
|
||||
var p = new ParallelArray([2,2], undefined);
|
||||
}
|
||||
|
||||
buildComprehension();
|
|
@ -0,0 +1,16 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function buildSimple() {
|
||||
// Simple constructor
|
||||
var a = [1,2,3,4,5];
|
||||
var p = new ParallelArray(a);
|
||||
var e = a.join(",");
|
||||
assertEq(p.toString(), bracket(e));
|
||||
a[0] = 9;
|
||||
// No sharing
|
||||
assertEq(p.toString(), bracket(e));
|
||||
}
|
||||
|
||||
buildSimple();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function buildWithHoles() {
|
||||
// Test holes
|
||||
var a = new Array(5);
|
||||
for (var cnt = 0; cnt < a.length; cnt+=2) {
|
||||
a[cnt] = cnt;
|
||||
}
|
||||
var b = [0,1,2,3,4];
|
||||
var p = new ParallelArray(a);
|
||||
assertEq(Object.keys(p).join(","), Object.keys(b).join(","));
|
||||
}
|
||||
|
||||
buildWithHoles();
|
|
@ -0,0 +1,13 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function buildArrayLike() {
|
||||
// Construct copying from array-like
|
||||
var a = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 };
|
||||
var p = new ParallelArray(a);
|
||||
var e = Array.prototype.join.call(a, ",");
|
||||
assertEq(p.toString(), bracket(e));
|
||||
}
|
||||
|
||||
buildArrayLike();
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
function buildPA() {
|
||||
// Construct copying from PA
|
||||
var p1 = new ParallelArray([1,2,3,4]);
|
||||
var p2 = new ParallelArray(p1);
|
||||
assertEq(p1.toString(), p2.toString());
|
||||
var p1d = new ParallelArray([2,2], function(i,j) { return i + j; });
|
||||
var p2d = new ParallelArray(p1d);
|
||||
assertEq(p1d.toString(), p2d.toString());
|
||||
}
|
||||
|
||||
buildPA();
|
|
@ -0,0 +1,13 @@
|
|||
function testElement() {
|
||||
// Test getting element from 1D
|
||||
var a = [1,{},"a",false]
|
||||
var p = new ParallelArray(a);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
assertEq(p[i], p[i]);
|
||||
assertEq(p[i], a[i]);
|
||||
}
|
||||
// Test out of bounds
|
||||
assertEq(p[42], undefined);
|
||||
}
|
||||
|
||||
testElement();
|
|
@ -0,0 +1,11 @@
|
|||
function testElement() {
|
||||
// Test getting element from higher dimension
|
||||
var p = new ParallelArray([2,2,2], function () { return 0; });
|
||||
assertEq(p[0].toString(), "<<0,0>,<0,0>>");
|
||||
// Should create new wrapper
|
||||
assertEq(p[0] !== p[0], true);
|
||||
// Test out of bounds
|
||||
assertEq(p[42], undefined);
|
||||
}
|
||||
|
||||
testElement();
|
|
@ -0,0 +1,10 @@
|
|||
function testElement() {
|
||||
var p = new ParallelArray([9]);
|
||||
var desc = Object.getOwnPropertyDescriptor(p, "0");
|
||||
assertEq(desc.enumerable, true);
|
||||
assertEq(desc.configurable, false);
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.value, 9);
|
||||
}
|
||||
|
||||
testElement();
|
|
@ -0,0 +1,8 @@
|
|||
function testElement() {
|
||||
// Test crazy prototype walking
|
||||
ParallelArray.prototype[42] = "foo";
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
assertEq(p[42], "foo");
|
||||
}
|
||||
|
||||
testElement();
|
|
@ -0,0 +1,7 @@
|
|||
function testEnumerate() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
for (var i in p)
|
||||
assertEq(i >= 0 && i < p.length, true);
|
||||
}
|
||||
|
||||
testEnumerate();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function testFilterAll() {
|
||||
// Test filtering everything (leaving everything in)
|
||||
var p = new ParallelArray([0,1,2,3,4]);
|
||||
var all = p.map(function (i) { return true; });
|
||||
var r = p.filter(all);
|
||||
assertEq(r.toString(), "<0,1,2,3,4>");
|
||||
var p = new ParallelArray([5,2], function(i,j) { return i+j; });
|
||||
var r = p.filter(all);
|
||||
assertEq(r.toString(), "<<0,1>,<1,2>,<2,3>,<3,4>,<4,5>>");
|
||||
}
|
||||
|
||||
testFilterAll();
|
|
@ -0,0 +1,12 @@
|
|||
function testFilterNone() {
|
||||
// Test filtering (removing everything)
|
||||
var p = new ParallelArray([0,1,2,3,4]);
|
||||
var none = p.map(function () { return false; });
|
||||
var r = p.filter(none);
|
||||
assertEq(r.toString(), "<>");
|
||||
var p = new ParallelArray([5,2], function(i,j) { return i+j; });
|
||||
var r = p.filter(none);
|
||||
assertEq(r.toString(), "<>");
|
||||
}
|
||||
|
||||
testFilterNone();
|
|
@ -0,0 +1,16 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function testFilterSome() {
|
||||
var p = new ParallelArray([0,1,2,3,4]);
|
||||
var evenBelowThree = p.map(function (i) { return ((i%2) === 0) && (i < 3); });
|
||||
var r = p.filter(evenBelowThree);
|
||||
assertEq(r.toString(), bracket([0,2].join(",")));
|
||||
var p = new ParallelArray([5,2], function (i,j) { return i; });
|
||||
var evenBelowThree = p.map(function (i) { return ((i[0]%2) === 0) && (i[0] < 3); });
|
||||
var r = p.filter(evenBelowThree);
|
||||
assertEq(r.toString(), bracket(["<0,0>","<2,2>"].join(",")));
|
||||
}
|
||||
|
||||
testFilterSome();
|
|
@ -0,0 +1,18 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function testFilterMisc() {
|
||||
var p = new ParallelArray([0,1,2]);
|
||||
// Test array
|
||||
var r = p.filter([true, false, true]);
|
||||
assertEq(r.toString(), bracket([0,2].join(",")));
|
||||
// Test array-like
|
||||
var r = p.filter({ 0: true, 1: false, 2: true, length: 3 });
|
||||
assertEq(r.toString(), bracket([0,2].join(",")));
|
||||
// Test truthy
|
||||
var r = p.filter([1, "", {}]);
|
||||
assertEq(r.toString(), bracket([0,2].join(",")));
|
||||
}
|
||||
|
||||
testFilterMisc();
|
|
@ -0,0 +1,11 @@
|
|||
function testFlatten() {
|
||||
var shape = [5];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function(i,j) { return i+j; });
|
||||
var flatShape = ([shape[0] * shape[1]]).concat(shape.slice(2));
|
||||
assertEq(p.flatten().shape.toString(), flatShape.toString());
|
||||
}
|
||||
}
|
||||
|
||||
testFlatten();
|
|
@ -0,0 +1,7 @@
|
|||
function testFlatten() {
|
||||
var p = new ParallelArray([2,2], function(i,j) { return i+j; });
|
||||
var p2 = new ParallelArray([0,1,1,2]);
|
||||
assertEq(p.flatten().toString(), p2.toString());
|
||||
}
|
||||
|
||||
testFlatten();
|
|
@ -0,0 +1,9 @@
|
|||
// |jit-test| error: Error;
|
||||
|
||||
function testFlattenFlat() {
|
||||
// Throw on flattening flat array
|
||||
var p = new ParallelArray([1]);
|
||||
var f = p.flatten();
|
||||
}
|
||||
|
||||
testFlattenFlat();
|
|
@ -0,0 +1,8 @@
|
|||
function testGet() {
|
||||
var a = [1,2,3,4,5];
|
||||
var p = new ParallelArray(a);
|
||||
for (var i = 0; i < a.length; i++)
|
||||
assertEq(p.get([i]), a[i]);
|
||||
}
|
||||
|
||||
testGet();
|
|
@ -0,0 +1,10 @@
|
|||
function testGet() {
|
||||
var p = new ParallelArray([2,2,2], function(i,j,k) { return i+j+k; });
|
||||
assertEq(p.get([1,1,1]), 1+1+1);
|
||||
var p2 = new ParallelArray([2], function(i) { return 1+1+i; });
|
||||
assertEq(p.get([1,1]).toString(), p2.toString());
|
||||
var p3 = new ParallelArray([2,2], function(i,j) { return 1+i+j; });
|
||||
assertEq(p.get([1]).toString(), p3.toString());
|
||||
}
|
||||
|
||||
testGet();
|
|
@ -0,0 +1,8 @@
|
|||
function testGetNoCraziness() {
|
||||
// .get shouldn't do prototype walks
|
||||
ParallelArray.prototype[42] = "foo";
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
assertEq(p.get([42]), undefined);
|
||||
}
|
||||
|
||||
testGetNoCraziness();
|
|
@ -0,0 +1,6 @@
|
|||
function testGetBounds() {
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
assertEq(p.get([42]), undefined);
|
||||
}
|
||||
|
||||
testGetBounds();
|
|
@ -0,0 +1,9 @@
|
|||
function testGet() {
|
||||
// Test .get on array-like
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
assertEq(p.get({ 0: 1, length: 1 }), 2);
|
||||
var p2 = new ParallelArray([2,2], function(i,j) { return i+j; });
|
||||
assertEq(p2.get({ 0: 1, 1: 0, length: 2 }), 1);
|
||||
}
|
||||
|
||||
testGet();
|
|
@ -0,0 +1,9 @@
|
|||
// |jit-test| error: TypeError;
|
||||
|
||||
function testGetThrows() {
|
||||
// Throw if argument not object
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
p.get(42);
|
||||
}
|
||||
|
||||
testGetThrows();
|
|
@ -0,0 +1,11 @@
|
|||
function testLength() {
|
||||
var a = [1,2,3];
|
||||
var p = new ParallelArray(a);
|
||||
assertEq(p.length, a.length);
|
||||
// Test holes
|
||||
var a = [1,,3];
|
||||
var p = new ParallelArray(a);
|
||||
assertEq(p.length, a.length);
|
||||
}
|
||||
|
||||
testLength();
|
|
@ -0,0 +1,12 @@
|
|||
function testLength() {
|
||||
// Test higher dimension shape up to 8D
|
||||
var shape = [];
|
||||
for (var i = 0; i < 8; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function () { return 0; });
|
||||
// Length should be outermost dimension
|
||||
assertEq(p.length, shape[0]);
|
||||
}
|
||||
}
|
||||
|
||||
testLength();
|
|
@ -0,0 +1,11 @@
|
|||
function testLength() {
|
||||
// Test length attributes
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
var desc = Object.getOwnPropertyDescriptor(p, "length");
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, false);
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.value, 4);
|
||||
}
|
||||
|
||||
testLength();
|
|
@ -0,0 +1,11 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function testMap() {
|
||||
var p = new ParallelArray([0,1,2,3,4]);
|
||||
var m = p.map(function (v) { return v+1; });
|
||||
assertEq(m.toString(), bracket([1,2,3,4,5].join(",")));
|
||||
}
|
||||
|
||||
testMap();
|
|
@ -0,0 +1,9 @@
|
|||
function testMap() {
|
||||
// Test overflow
|
||||
var p = new ParallelArray([1 << 30]);
|
||||
var m = p.map(function(x) { return x * 4; });
|
||||
assertEq(m[0], (1 << 30) * 4);
|
||||
}
|
||||
|
||||
testMap();
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
function testMap() {
|
||||
// Test mapping higher dimensional
|
||||
var p = new ParallelArray([2,2], function (i,j) { return i+j; });
|
||||
var m = p.map(function(x) { return x.toString(); });
|
||||
assertEq(m.toString(), "<<0,1>,<1,2>>");
|
||||
}
|
||||
|
||||
testMap();
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
function testMap() {
|
||||
// Test map elemental fun args
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
var m = p.map(function(e) {
|
||||
assertEq(e >= 1 && e <= 4, true);
|
||||
});
|
||||
var m = p.map(function(e,i) {
|
||||
assertEq(e >= 1 && e <= 4, true);
|
||||
assertEq(i >= 0 && i < 4, true);
|
||||
});
|
||||
var m = p.map(function(e,i,c) {
|
||||
assertEq(e >= 1 && e <= 4, true);
|
||||
assertEq(i >= 0 && i < 4, true);
|
||||
assertEq(c, p);
|
||||
});
|
||||
}
|
||||
|
||||
testMap();
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// |jit-test| error: TypeError;
|
||||
function testMap() {
|
||||
// Test map throws
|
||||
var p = new ParallelArray([1,2,3,4])
|
||||
var m = p.map(42);
|
||||
}
|
||||
|
||||
testMap();
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
function testPartition() {
|
||||
var p = new ParallelArray([1,2,3,4,5,6,7,8]);
|
||||
var pp = p.partition(2);
|
||||
var ppp = pp.partition(2);
|
||||
var ppShape = [p.shape[0] / 2, 2].concat(p.shape.slice(1));
|
||||
var pppShape = [pp.shape[0] / 2, 2].concat(pp.shape.slice(1));
|
||||
assertEq(pp.shape.toString(), ppShape.toString())
|
||||
assertEq(pp.toString(), "<<1,2>,<3,4>,<5,6>,<7,8>>");
|
||||
assertEq(ppp.shape.toString(), pppShape.toString())
|
||||
assertEq(ppp.toString(), "<<<1,2>,<3,4>>,<<5,6>,<7,8>>>");
|
||||
}
|
||||
|
||||
testPartition();
|
|
@ -0,0 +1,8 @@
|
|||
// |jit-test| error: Error;
|
||||
|
||||
function testPartitionDivisible() {
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
var pp = p.partition(3);
|
||||
}
|
||||
|
||||
testPartitionDivisible();
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
function testReduce() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.reduce(function (v, p) { return v*p; });
|
||||
assertEq(r, 120);
|
||||
}
|
||||
|
||||
testReduce();
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
function testReduceOne() {
|
||||
var p = new ParallelArray([1]);
|
||||
var r = p.reduce(function (v, p) { return v*p; });
|
||||
assertEq(r, 1);
|
||||
}
|
||||
|
||||
testReduceOne();
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
function testReduce() {
|
||||
// Test reduce on higher dimensional
|
||||
// XXX Can we test this better?
|
||||
var shape = [2];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function () { return i+1; });
|
||||
var r = p.reduce(function (a, b) { return a; });
|
||||
assertEq(r.shape.length, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
testReduce();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function testReduce() {
|
||||
// Test reduce elemental fun args
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
var r = p.reduce(function (a, b) {
|
||||
assertEq(a >= 1 && a <= 4, true);
|
||||
assertEq(b >= 1 && b <= 4, true);
|
||||
return a;
|
||||
});
|
||||
assertEq(r >= 1 && r <= 4, true);
|
||||
}
|
||||
|
||||
testReduce();
|
|
@ -0,0 +1,16 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
function testReduceThrows() {
|
||||
// Throw on empty
|
||||
assertThrowsInstanceOf(function () {
|
||||
var p = new ParallelArray([]);
|
||||
p.reduce(function (v, p) { return v*p; });
|
||||
}, Error);
|
||||
// Throw on not function
|
||||
assertThrowsInstanceOf(function () {
|
||||
var p = new ParallelArray([1]);
|
||||
p.reduce(42);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
testReduceThrows();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function testScan() {
|
||||
function f(v, p) { return v*p; }
|
||||
var a = [1,2,3,4,5];
|
||||
var p = new ParallelArray(a);
|
||||
var s = p.scan(f);
|
||||
for (var i = 0; i < p.length; i++) {
|
||||
var p2 = new ParallelArray(a.slice(0, i+1));
|
||||
assertEq(s[i], p2.reduce(f));
|
||||
}
|
||||
}
|
||||
|
||||
testScan();
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
function testScanOne() {
|
||||
function f(v, p) { return v*p; }
|
||||
var p = new ParallelArray([1]);
|
||||
var s = p.scan(f);
|
||||
assertEq(s[0], p.reduce(f));
|
||||
}
|
||||
|
||||
testScanOne();
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
function testScan() {
|
||||
// Test reduce on higher dimensional
|
||||
// XXX Can we test this better?
|
||||
function f(a, b) { return a; }
|
||||
var shape = [2];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function () { return i+1; });
|
||||
var r = p.reduce(f);
|
||||
var s = p.scan(f)
|
||||
for (var j = 0; j < s.length; j++)
|
||||
assertEq(s[0].shape.length, i + 1);
|
||||
assertEq(r.shape.length, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
testScan();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function testScan() {
|
||||
// Test reduce elemental fun args
|
||||
var p = new ParallelArray([1,2,3,4]);
|
||||
var r = p.reduce(function (a, b) {
|
||||
assertEq(a >= 1 && a <= 4, true);
|
||||
assertEq(b >= 1 && b <= 4, true);
|
||||
return a;
|
||||
});
|
||||
assertEq(r >= 1 && r <= 4, true);
|
||||
}
|
||||
|
||||
testScan();
|
|
@ -0,0 +1,16 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
function testScanThrows() {
|
||||
// Throw on empty
|
||||
assertThrowsInstanceOf(function () {
|
||||
var p = new ParallelArray([]);
|
||||
p.scan(function (v, p) { return v*p; });
|
||||
}, Error);
|
||||
// Throw on not function
|
||||
assertThrowsInstanceOf(function () {
|
||||
var p = new ParallelArray([1]);
|
||||
p.scan(42);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
testScanThrows();
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
function testScatter() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([0,1,0,3,4], 9, function (a,b) { return a+b; }, 10);
|
||||
assertEq(r.length, 10);
|
||||
}
|
||||
|
||||
testScatter();
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
function testScatterIdentity() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([0,1,2,3,4]);
|
||||
assertEq(p.toString(), r.toString());
|
||||
}
|
||||
|
||||
testScatterIdentity();
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
function testScatter() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([1,0,3,2,4]);
|
||||
var p2 = new ParallelArray([2,1,4,3,5]);
|
||||
assertEq(r.toString(), p2.toString());
|
||||
}
|
||||
|
||||
testScatter();
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function testScatterDefault() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([0,2,4], 9);
|
||||
assertEq(r.toString(), bracket([1,9,2,9,3].join(",")));
|
||||
}
|
||||
|
||||
testScatterDefault();
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
function bracket(s) {
|
||||
return "<" + s + ">";
|
||||
}
|
||||
|
||||
function testScatterConflict() {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([0,1,0,3,4], 9, function (a,b) { return a+b; });
|
||||
assertEq(r.toString(), bracket([4,2,9,4,5].join(",")));
|
||||
}
|
||||
|
||||
testScatterConflict();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function testScatter() {
|
||||
// Test scatter on higher dimension
|
||||
var shape = [5];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function(k) { return k; });
|
||||
var r = p.scatter([0,1,0,3,4], 9, function (a,b) { return a+b; }, 10);
|
||||
assertEq(r.length, 10);
|
||||
}
|
||||
}
|
||||
|
||||
testScatter();
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
function testScatterIdentity() {
|
||||
var shape = [5];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function(k) { return k; });
|
||||
var r = p.scatter([0,1,2,3,4]);
|
||||
assertEq(p.toString(), r.toString());
|
||||
}
|
||||
}
|
||||
|
||||
testScatterIdentity();
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
function testScatter() {
|
||||
var shape = [5];
|
||||
for (var i = 0; i < 7; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function(k) { return k; });
|
||||
var r = p.scatter([1,0,3,2,4]);
|
||||
var p2 = new ParallelArray([p[1], p[0], p[3], p[2], p[4]]);
|
||||
assertEq(p2.toString(), r.toString());
|
||||
}
|
||||
}
|
||||
|
||||
testScatter();
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
function testScatter() {
|
||||
// Ignore the rest of the scatter vector if longer than source
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([1,0,3,2,4,1,2,3]);
|
||||
var p2 = new ParallelArray([2,1,4,3,5]);
|
||||
assertEq(r.toString(), p2.toString());
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
function testScatterThrows() {
|
||||
// Throw on conflict with no resolution function
|
||||
assertThrowsInstanceOf(function () {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([0,1,0,3,4]);
|
||||
}, Error);
|
||||
// Throw on out of bounds
|
||||
assertThrowsInstanceOf(function () {
|
||||
var p = new ParallelArray([1,2,3,4,5]);
|
||||
var r = p.scatter([0,1,0,3,11]);
|
||||
}, Error);
|
||||
}
|
||||
|
||||
testScatterThrows();
|
|
@ -0,0 +1,8 @@
|
|||
function testShape() {
|
||||
var a = [1,2,3];
|
||||
var p = new ParallelArray(a);
|
||||
assertEq(p.shape.length, 1);
|
||||
assertEq(p.shape[0], a.length);
|
||||
}
|
||||
|
||||
testShape();
|
|
@ -0,0 +1,14 @@
|
|||
function testShape() {
|
||||
// Test higher dimension shape up to 8D
|
||||
var shape = [];
|
||||
for (var i = 0; i < 8; i++) {
|
||||
shape.push(i+1);
|
||||
var p = new ParallelArray(shape, function () { return 0; });
|
||||
// Test shape identity and shape
|
||||
assertEq(p.shape, p.shape);
|
||||
assertEq(p.shape !== shape, true);
|
||||
assertEq(p.shape.toString(), shape.toString());
|
||||
}
|
||||
}
|
||||
|
||||
testShape();
|
|
@ -0,0 +1,37 @@
|
|||
// ParallelArray surfaces
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(this, "ParallelArray");
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
assertEq(desc.writable, true);
|
||||
|
||||
assertEq(typeof ParallelArray, 'function');
|
||||
assertEq(Object.keys(ParallelArray).length, 0);
|
||||
assertEq(ParallelArray.length, 0);
|
||||
assertEq(ParallelArray.name, "ParallelArray");
|
||||
|
||||
assertEq(Object.getPrototypeOf(ParallelArray.prototype), Object.prototype);
|
||||
assertEq(Object.prototype.toString.call(ParallelArray.prototype), "[object ParallelArray]");
|
||||
assertEq(Object.prototype.toString.call(new ParallelArray), "[object ParallelArray]");
|
||||
assertEq(Object.prototype.toString.call(ParallelArray()), "[object ParallelArray]");
|
||||
assertEq(Object.keys(ParallelArray.prototype).join(), "");
|
||||
assertEq(ParallelArray.prototype.constructor, ParallelArray);
|
||||
|
||||
function checkMethod(name, arity) {
|
||||
var desc = Object.getOwnPropertyDescriptor(ParallelArray.prototype, name);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(typeof desc.value, 'function');
|
||||
assertEq(desc.value.name, name);
|
||||
assertEq(desc.value.length, arity);
|
||||
}
|
||||
|
||||
checkMethod("map", 1);
|
||||
checkMethod("reduce", 1);
|
||||
checkMethod("scan", 1);
|
||||
checkMethod("scatter", 1);
|
||||
checkMethod("filter", 1);
|
||||
checkMethod("flatten", 0);
|
||||
checkMethod("partition", 1);
|
||||
checkMethod("get", 1);
|
|
@ -0,0 +1,27 @@
|
|||
// ParallelArray methods throw when passed a this-value that isn't a ParallelArray.
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
function testcase(obj, fn) {
|
||||
assertEq(typeof fn, "function");
|
||||
var args = Array.slice(arguments, 2);
|
||||
assertThrowsInstanceOf(function () { fn.apply(obj, args); }, TypeError);
|
||||
}
|
||||
|
||||
function test(obj) {
|
||||
function f() {}
|
||||
testcase(obj, ParallelArray.prototype.map, f);
|
||||
testcase(obj, ParallelArray.prototype.reduce, f);
|
||||
testcase(obj, ParallelArray.prototype.scan, f);
|
||||
testcase(obj, ParallelArray.prototype.scatter, [0]);
|
||||
testcase(obj, ParallelArray.prototype.filter, [0]);
|
||||
testcase(obj, ParallelArray.prototype.flatten);
|
||||
testcase(obj, ParallelArray.prototype.partition, 2);
|
||||
testcase(obj, ParallelArray.prototype.get, [1]);
|
||||
}
|
||||
|
||||
test(ParallelArray.prototype);
|
||||
test(Object.create(new ParallelArray));
|
||||
test({});
|
||||
test(null);
|
||||
test(undefined);
|
|
@ -354,3 +354,10 @@ MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "paramet
|
|||
MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression")
|
||||
MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
|
||||
MSG_DEF(JSMSG_ALREADY_HAS_SOURCEMAP, 303, 1, JSEXN_ERR, "{0} is being assigned a source map, yet already has one")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_IMMUTABLE, 304, 0, JSEXN_TYPEERR, "ParallelArray objects are immutable")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 305, 1, JSEXN_TYPEERR, "invalid ParallelArray{0} argument")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_BAD_PARTITION, 306, 0, JSEXN_ERR, "argument must be divisible by outermost dimension")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_REDUCE_EMPTY, 307, 0, JSEXN_ERR, "cannot reduce empty ParallelArray object")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_ALREADY_FLAT, 308, 0, JSEXN_ERR, "cannot flatten 1-dimensional ParallelArray object")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 309, 0, JSEXN_ERR, "no conflict resolution function provided")
|
||||
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS, 310, 0, JSEXN_ERR, "index in scatter vector out of bounds")
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "builtin/Eval.h"
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/RegExp.h"
|
||||
#include "builtin/ParallelArray.h"
|
||||
#include "ds/LifoAlloc.h"
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/TreeContext.h"
|
||||
|
@ -1867,6 +1868,7 @@ static JSStdName standard_class_atoms[] = {
|
|||
{js_InitWeakMapClass, EAGER_CLASS_ATOM(WeakMap), &js::WeakMapClass},
|
||||
{js_InitMapClass, EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
|
||||
{js_InitSetClass, EAGER_CLASS_ATOM(Set), &js::SetObject::class_},
|
||||
{js_InitParallelArrayClass, EAGER_CLASS_ATOM(ParallelArray), &js::ParallelArrayObject::class_},
|
||||
{NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ DEFINE_PROTOTYPE_ATOM(WeakMap)
|
|||
DEFINE_ATOM(buffer, "buffer")
|
||||
DEFINE_ATOM(byteLength, "byteLength")
|
||||
DEFINE_ATOM(byteOffset, "byteOffset")
|
||||
DEFINE_ATOM(shape, "shape")
|
||||
DEFINE_KEYWORD_ATOM(return)
|
||||
DEFINE_KEYWORD_ATOM(throw)
|
||||
DEFINE_ATOM(url, "url")
|
||||
|
|
|
@ -64,6 +64,7 @@ JS_PROTO(WeakMap, 36, js_InitWeakMapClass)
|
|||
JS_PROTO(Map, 37, js_InitMapClass)
|
||||
JS_PROTO(Set, 38, js_InitSetClass)
|
||||
JS_PROTO(DataView, 39, js_InitTypedArrayClasses)
|
||||
JS_PROTO(ParallelArray, 40, js_InitParallelArrayClass)
|
||||
|
||||
#undef XML_INIT
|
||||
#undef NAMESPACE_INIT
|
||||
|
|
Загрузка…
Ссылка в новой задаче