LCOV - app.info - js/src/jstypedarray.cpp

LCOV - code coverage report
| Current view: | directory - js/src - jstypedarray.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1088 | 531 | 48.8 %
| Date: | 2012-04-07 | Functions: | 523 | 292 | 55.8 %

           1                 : /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
           2                 : /* vim: set ts=40 sw=4 et tw=99: */
           3                 : /* ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is Mozilla WebGL impl
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is
          19                 :  *   Mozilla Foundation
          20                 :  * Portions created by the Initial Developer are Copyright (C) 2009
          21                 :  * the Initial Developer. All Rights Reserved.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   Vladimir Vukicevic <vladimir@pobox.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include <string.h>
          41                 :
          42                 : #include "mozilla/Util.h"
          43                 :
          44                 : #include "jstypes.h"
          45                 : #include "jsutil.h"
          46                 : #include "jshash.h"
          47                 : #include "jsprf.h"
          48                 : #include "jsapi.h"
          49                 : #include "jsarray.h"
          50                 : #include "jsatom.h"
          51                 : #include "jsbool.h"
          52                 : #include "jscntxt.h"
          53                 : #include "jsversion.h"
          54                 : #include "jsgc.h"
          55                 : #include "jsgcmark.h"
          56                 : #include "jsinterp.h"
          57                 : #include "jslock.h"
          58                 : #include "jsnum.h"
          59                 : #include "jsobj.h"
          60                 : #include "jstypedarray.h"
          61                 :
          62                 : #include "vm/GlobalObject.h"
          63                 :
          64                 : #include "jsatominlines.h"
          65                 : #include "jsinferinlines.h"
          66                 : #include "jsobjinlines.h"
          67                 : #include "jstypedarrayinlines.h"
          68                 :
          69                 : #include "vm/MethodGuard-inl.h"
          70                 :
          71                 : using namespace mozilla;
          72                 : using namespace js;
          73                 : using namespace js::gc;
          74                 : using namespace js::types;
          75                 :
          76                 : /*
          77                 :  * Allocate array buffers with the maximum number of fixed slots marked as
          78                 :  * reserved, so that the fixed slots may be used for the buffer's contents.
          79                 :  * The last fixed slot is kept for the object's private data.
          80                 :  */
          81                 : static const uint8_t ARRAYBUFFER_RESERVED_SLOTS = JSObject::MAX_FIXED_SLOTS - 1;
          82                 :
          83                 : static bool
          84            4932 : ValueIsLength(JSContext *cx, const Value &v, uint32_t *len)
          85                 : {
          86            4932 :     if (v.isInt32()) {
          87            4356 :         int32_t i = v.toInt32();
          88            4356 :         if (i < 0)
          89               0 :             return false;
          90            4356 :         *len = i;
          91            4356 :         return true;
          92                 :     }
          93                 :
          94             576 :     if (v.isDouble()) {
          95               0 :         double d = v.toDouble();
          96               0 :         if (JSDOUBLE_IS_NaN(d))
          97               0 :             return false;
          98                 :
          99               0 :         uint32_t length = uint32_t(d);
         100               0 :         if (d != double(length))
         101               0 :             return false;
         102                 :
         103               0 :         *len = length;
         104               0 :         return true;
         105                 :     }
         106                 :
         107             576 :     return false;
         108                 : }
         109                 :
         110                 : /*
         111                 :  * Convert |v| to an array index for an array of length |length| per
         112                 :  * the Typed Array Specification section 7.0, |subarray|. If successful,
         113                 :  * the output value is in the range [0, length).
         114                 :  */
         115                 : static bool
         116             324 : ToClampedIndex(JSContext *cx, const Value &v, int32_t length, int32_t *out)
         117                 : {
         118             324 :     if (!ToInt32(cx, v, out))
         119               0 :         return false;
         120             324 :     if (*out < 0) {
         121             126 :         *out += length;
         122             126 :         if (*out < 0)
         123              36 :             *out = 0;
         124             198 :     } else if (*out > length) {
         125              27 :         *out = length;
         126                 :     }
         127             324 :     return true;
         128                 : }
         129                 :
         130                 : /*
         131                 :  * ArrayBuffer
         132                 :  *
         133                 :  * This class holds the underlying raw buffer that the TypedArray classes
         134                 :  * access.  It can be created explicitly and passed to a TypedArray, or
         135                 :  * can be created implicitly by constructing a TypedArray with a size.
         136                 :  */
         137                 :
         138                 : /**
         139                 :  * Walks up the prototype chain to find the actual ArrayBuffer data.
         140                 :  * This MAY return NULL. Callers should always use js_IsArrayBuffer()
         141                 :  * first.
         142                 :  */
         143                 : JSObject *
         144             630 : ArrayBuffer::getArrayBuffer(JSObject *obj)
         145                 : {
         146            1260 :     while (obj && !js_IsArrayBuffer(obj))
         147               0 :         obj = obj->getProto();
         148             630 :     return obj;
         149                 : }
         150                 :
         151                 : JSBool
         152               0 : ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
         153                 : {
         154               0 :     JSObject *arrayBuffer = getArrayBuffer(obj);
         155               0 :     if (!arrayBuffer) {
         156               0 :         vp->setInt32(0);
         157               0 :         return true;
         158                 :     }
         159               0 :     vp->setInt32(int32_t(arrayBuffer->arrayBufferByteLength()));
         160               0 :     return true;
         161                 : }
         162                 :
         163                 : JSBool
         164             207 : ArrayBuffer::fun_slice(JSContext *cx, unsigned argc, Value *vp)
         165                 : {
         166             207 :     CallArgs args = CallArgsFromVp(argc, vp);
         167                 :
         168                 :     bool ok;
         169             207 :     JSObject *obj = NonGenericMethodGuard(cx, args, fun_slice, &ArrayBufferClass, &ok);
         170             207 :     if (!obj)
         171               0 :         return ok;
         172                 :
         173             207 :     JSObject *arrayBuffer = getArrayBuffer(obj);
         174             207 :     if (!arrayBuffer)
         175               0 :         return true;
         176                 :
         177                 :     // these are the default values
         178             207 :     int32_t length = int32_t(arrayBuffer->arrayBufferByteLength());
         179             207 :     int32_t begin = 0, end = length;
         180                 :
         181             207 :     if (args.length() > 0) {
         182             207 :         if (!ToClampedIndex(cx, args[0], length, &begin))
         183               0 :             return false;
         184                 :
         185             207 :         if (args.length() > 1) {
         186              99 :             if (!ToClampedIndex(cx, args[1], length, &end))
         187               0 :                 return false;
         188                 :         }
         189                 :     }
         190                 :
         191             207 :     if (begin > end)
         192              18 :         begin = end;
         193                 :
         194             207 :     JSObject *nobj = createSlice(cx, arrayBuffer, begin, end);
         195             207 :     if (!nobj)
         196               0 :         return false;
         197             207 :     args.rval().setObject(*nobj);
         198             207 :     return true;
         199                 : }
         200                 :
         201                 : /*
         202                 :  * new ArrayBuffer(byteLength)
         203                 :  */
         204                 : JSBool
         205             162 : ArrayBuffer::class_constructor(JSContext *cx, unsigned argc, Value *vp)
         206                 : {
         207             162 :     int32_t nbytes = 0;
         208             162 :     if (argc > 0 && !ToInt32(cx, vp[2], &nbytes))
         209               0 :         return false;
         210                 :
         211             162 :     JSObject *bufobj = create(cx, nbytes);
         212             162 :     if (!bufobj)
         213               9 :         return false;
         214             153 :     vp->setObject(*bufobj);
         215             153 :     return true;
         216                 : }
         217                 :
         218                 : bool
         219            5112 : JSObject::allocateArrayBufferSlots(JSContext *cx, uint32_t size, uint8_t *contents)
         220                 : {
         221                 :     /*
         222                 :      * ArrayBuffer objects delegate added properties to another JSObject, so
         223                 :      * their internal layout can use the object's fixed slots for storage.
         224                 :      * Set up the object to look like an array with an elements header.
         225                 :      */
         226            5112 :     JS_ASSERT(isArrayBuffer() && !hasDynamicSlots() && !hasDynamicElements());
         227                 :
         228            5112 :     size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
         229                 :
         230            5112 :     if (size > sizeof(Value) * usableSlots) {
         231             225 :         ObjectElements *newheader = (ObjectElements *)cx->calloc_(size + sizeof(ObjectElements));
         232             225 :         if (!newheader)
         233               9 :             return false;
         234             216 :         elements = newheader->elements();
         235             216 :         if (contents)
         236               0 :             memcpy(elements, contents, size);
         237                 :     } else {
         238            4887 :         elements = fixedElements();
         239            4887 :         if (contents)
         240             207 :             memcpy(elements, contents, size);
         241                 :         else
         242            4680 :             memset(elements, 0, size);
         243                 :     }
         244                 :
         245            5103 :     ObjectElements *header = getElementsHeader();
         246                 :
         247                 :     /*
         248                 :      * Note that |bytes| may not be a multiple of |sizeof(Value)|, so
         249                 :      * |capacity * sizeof(Value)| may underestimate the size by up to
         250                 :      * |sizeof(Value) - 1| bytes.
         251                 :      */
         252            5103 :     header->capacity = size / sizeof(Value);
         253            5103 :     header->initializedLength = 0;
         254            5103 :     header->length = size;
         255            5103 :     header->unused = 0;
         256                 :
         257            5103 :     return true;
         258                 : }
         259                 :
         260                 : static JSObject *
         261             225 : DelegateObject(JSContext *cx, JSObject *obj)
         262                 : {
         263             225 :     if (!obj->getPrivate()) {
         264              27 :         JSObject *delegate = NewObjectWithGivenProto(cx, &ObjectClass, obj->getProto(), NULL);
         265              27 :         obj->setPrivate(delegate);
         266              27 :         return delegate;
         267                 :     }
         268             198 :     return static_cast<JSObject*>(obj->getPrivate());
         269                 : }
         270                 :
         271                 : JSObject *
         272            5112 : ArrayBuffer::create(JSContext *cx, int32_t nbytes, uint8_t *contents)
         273                 : {
         274            5112 :     JSObject *obj = NewBuiltinClassInstance(cx, &ArrayBuffer::slowClass);
         275            5112 :     if (!obj)
         276               0 :         return NULL;
         277                 : #ifdef JS_THREADSAFE
         278            5112 :     JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT16_BACKGROUND);
         279                 : #else
         280                 :     JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT16);
         281                 : #endif
         282                 :
         283            5112 :     if (nbytes < 0) {
         284                 :         /*
         285                 :          * We're just not going to support arrays that are bigger than what will fit
         286                 :          * as an integer value; if someone actually ever complains (validly), then we
         287                 :          * can fix.
         288                 :          */
         289               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
         290               0 :         return NULL;
         291                 :     }
         292                 :
         293            5112 :     JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
         294                 :
         295                 :     js::Shape *empty = EmptyShape::getInitialShape(cx, &ArrayBufferClass,
         296                 :                                                    obj->getProto(), obj->getParent(),
         297            5112 :                                                    gc::FINALIZE_OBJECT16);
         298            5112 :     if (!empty)
         299               0 :         return NULL;
         300            5112 :     obj->setLastPropertyInfallible(empty);
         301                 :
         302                 :     /*
         303                 :      * The first 8 bytes hold the length.
         304                 :      * The rest of it is a flat data store for the array buffer.
         305                 :      */
         306            5112 :     if (!obj->allocateArrayBufferSlots(cx, nbytes, contents))
         307               9 :         return NULL;
         308                 :
         309            5103 :     return obj;
         310                 : }
         311                 :
         312                 : JSObject *
         313             207 : ArrayBuffer::createSlice(JSContext *cx, JSObject *arrayBuffer, uint32_t begin, uint32_t end)
         314                 : {
         315             207 :     JS_ASSERT(arrayBuffer->isArrayBuffer());
         316             207 :     JS_ASSERT(begin <= arrayBuffer->arrayBufferByteLength());
         317             207 :     JS_ASSERT(end <= arrayBuffer->arrayBufferByteLength());
         318                 :
         319             207 :     JS_ASSERT(begin <= end);
         320             207 :     uint32_t length = end - begin;
         321                 :
         322             207 :     return create(cx, length, arrayBuffer->arrayBufferDataOffset() + begin);
         323                 : }
         324                 :
         325               0 : ArrayBuffer::~ArrayBuffer()
         326                 : {
         327               0 : }
         328                 :
         329                 : void
         330              88 : ArrayBuffer::obj_trace(JSTracer *trc, JSObject *obj)
         331                 : {
         332                 :     /*
         333                 :      * If this object changes, it will get marked via the private data barrier,
         334                 :      * so it's safe to leave it Unbarriered.
         335                 :      */
         336              88 :     JSObject *delegate = static_cast<JSObject*>(obj->getPrivate());
         337              88 :     if (delegate) {
         338              30 :         MarkObjectUnbarriered(trc, &delegate, "arraybuffer.delegate");
         339              30 :         obj->setPrivateUnbarriered(delegate);
         340                 :     }
         341              88 : }
         342                 :
         343                 : static JSProperty * const PROPERTY_FOUND = reinterpret_cast<JSProperty *>(1);
         344                 :
         345                 : JSBool
         346               0 : ArrayBuffer::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id,
         347                 :                                JSObject **objp, JSProperty **propp)
         348                 : {
         349               0 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         350               0 :         *propp = PROPERTY_FOUND;
         351               0 :         *objp = getArrayBuffer(obj);
         352               0 :         return true;
         353                 :     }
         354                 :
         355               0 :     JSObject *delegate = DelegateObject(cx, obj);
         356               0 :     if (!delegate)
         357               0 :         return false;
         358                 :
         359               0 :     JSBool delegateResult = delegate->lookupGeneric(cx, id, objp, propp);
         360                 :
         361                 :     /* If false, there was an error, so propagate it.
         362                 :      * Otherwise, if propp is non-null, the property
         363                 :      * was found. Otherwise it was not
         364                 :      * found so look in the prototype chain.
         365                 :      */
         366               0 :     if (!delegateResult)
         367               0 :         return false;
         368                 :
         369               0 :     if (*propp != NULL) {
         370               0 :         if (*objp == delegate)
         371               0 :             *objp = obj;
         372               0 :         return true;
         373                 :     }
         374                 :
         375               0 :     JSObject *proto = obj->getProto();
         376               0 :     if (!proto) {
         377               0 :         *objp = NULL;
         378               0 :         *propp = NULL;
         379               0 :         return true;
         380                 :     }
         381                 :
         382               0 :     return proto->lookupGeneric(cx, id, objp, propp);
         383                 : }
         384                 :
         385                 : JSBool
         386               0 : ArrayBuffer::obj_lookupProperty(JSContext *cx, JSObject *obj, PropertyName *name,
         387                 :                                 JSObject **objp, JSProperty **propp)
         388                 : {
         389               0 :     return obj_lookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
         390                 : }
         391                 :
         392                 : JSBool
         393               0 : ArrayBuffer::obj_lookupElement(JSContext *cx, JSObject *obj, uint32_t index,
         394                 :                                JSObject **objp, JSProperty **propp)
         395                 : {
         396               0 :     JSObject *delegate = DelegateObject(cx, obj);
         397               0 :     if (!delegate)
         398               0 :         return false;
         399                 :
         400                 :     /*
         401                 :      * If false, there was an error, so propagate it.
         402                 :      * Otherwise, if propp is non-null, the property
         403                 :      * was found. Otherwise it was not
         404                 :      * found so look in the prototype chain.
         405                 :      */
         406               0 :     if (!delegate->lookupElement(cx, index, objp, propp))
         407               0 :         return false;
         408                 :
         409               0 :     if (*propp != NULL) {
         410               0 :         if (*objp == delegate)
         411               0 :             *objp = obj;
         412               0 :         return true;
         413                 :     }
         414                 :
         415               0 :     if (JSObject *proto = obj->getProto())
         416               0 :         return proto->lookupElement(cx, index, objp, propp);
         417                 :
         418               0 :     *objp = NULL;
         419               0 :     *propp = NULL;
         420               0 :     return true;
         421                 : }
         422                 :
         423                 : JSBool
         424               0 : ArrayBuffer::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
         425                 :                                JSObject **objp, JSProperty **propp)
         426                 : {
         427               0 :     return obj_lookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
         428                 : }
         429                 :
         430                 : JSBool
         431               0 : ArrayBuffer::obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
         432                 :                                PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
         433                 : {
         434               0 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         435               0 :         return true;
         436                 :
         437               0 :     JSObject *delegate = DelegateObject(cx, obj);
         438               0 :     if (!delegate)
         439               0 :         return false;
         440               0 :     return js_DefineProperty(cx, delegate, id, v, getter, setter, attrs);
         441                 : }
         442                 :
         443                 : JSBool
         444               0 : ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
         445                 :                                 PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
         446                 : {
         447               0 :     return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs);
         448                 : }
         449                 :
         450                 : JSBool
         451               0 : ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *v,
         452                 :                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
         453                 : {
         454               0 :     JSObject *delegate = DelegateObject(cx, obj);
         455               0 :     if (!delegate)
         456               0 :         return false;
         457               0 :     return js_DefineElement(cx, delegate, index, v, getter, setter, attrs);
         458                 : }
         459                 :
         460                 : JSBool
         461               0 : ArrayBuffer::obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
         462                 :                                PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
         463                 : {
         464               0 :     return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
         465                 : }
         466                 :
         467                 : JSBool
         468             423 : ArrayBuffer::obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
         469                 : {
         470             423 :     obj = getArrayBuffer(obj);
         471             423 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         472             207 :         vp->setInt32(obj->arrayBufferByteLength());
         473             207 :         return true;
         474                 :     }
         475                 :
         476             216 :     JSObject *delegate = DelegateObject(cx, obj);
         477             216 :     if (!delegate)
         478               0 :         return false;
         479             216 :     return js_GetProperty(cx, delegate, receiver, id, vp);
         480                 : }
         481                 :
         482                 : JSBool
         483               0 : ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
         484                 :                              Value *vp)
         485                 : {
         486               0 :     obj = getArrayBuffer(obj);
         487               0 :     if (name == cx->runtime->atomState.byteLengthAtom) {
         488               0 :         vp->setInt32(obj->arrayBufferByteLength());
         489               0 :         return true;
         490                 :     }
         491                 :
         492               0 :     JSObject *delegate = DelegateObject(cx, obj);
         493               0 :     if (!delegate)
         494               0 :         return false;
         495               0 :     return js_GetProperty(cx, delegate, receiver, ATOM_TO_JSID(name), vp);
         496                 : }
         497                 :
         498                 : JSBool
         499               0 : ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
         500                 : {
         501               0 :     JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj));
         502               0 :     if (!delegate)
         503               0 :         return false;
         504               0 :     return js_GetElement(cx, delegate, receiver, index, vp);
         505                 : }
         506                 :
         507                 : JSBool
         508               0 : ArrayBuffer::obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver,
         509                 :                                      uint32_t index, Value *vp, bool *present)
         510                 : {
         511               0 :     JSObject *delegate = DelegateObject(cx, getArrayBuffer(obj));
         512               0 :     if (!delegate)
         513               0 :         return false;
         514               0 :     return delegate->getElementIfPresent(cx, receiver, index, vp, present);
         515                 : }
         516                 :
         517                 : JSBool
         518               0 : ArrayBuffer::obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
         519                 : {
         520               0 :     return obj_getGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
         521                 : }
         522                 :
         523                 : JSBool
         524               9 : ArrayBuffer::obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
         525                 : {
         526               9 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         527               0 :         return true;
         528                 :
         529               9 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) {
         530                 :         // setting __proto__ = null
         531                 :         // effectively removes the prototype chain.
         532                 :         // any attempt to set __proto__ on native
         533                 :         // objects after setting them to null makes
         534                 :         // __proto__ just a plain property.
         535                 :         // the following code simulates this behaviour on arrays.
         536                 :         //
         537                 :         // we first attempt to set the prototype on
         538                 :         // the delegate which is a native object
         539                 :         // so that existing code handles the case
         540                 :         // of treating it as special or plain.
         541                 :         // if the delegate's prototype has now changed
         542                 :         // then we change our prototype too.
         543                 :         //
         544                 :         // otherwise __proto__ was a plain property
         545                 :         // and we don't modify our prototype chain
         546                 :         // since obj_getProperty will fetch it as a plain
         547                 :         // property from the delegate.
         548               9 :         JSObject *delegate = DelegateObject(cx, obj);
         549               9 :         if (!delegate)
         550               0 :             return false;
         551                 :
         552               9 :         JSObject *oldDelegateProto = delegate->getProto();
         553                 :
         554               9 :         if (!js_SetPropertyHelper(cx, delegate, id, 0, vp, strict))
         555               0 :             return false;
         556                 :
         557               9 :         if (delegate->getProto() != oldDelegateProto) {
         558                 :             // actual __proto__ was set and not a plain property called
         559                 :             // __proto__
         560               9 :             if (!obj->isExtensible()) {
         561               9 :                 obj->reportNotExtensible(cx);
         562               9 :                 return false;
         563                 :             }
         564               0 :             if (!SetProto(cx, obj, vp->toObjectOrNull(), true)) {
         565                 :                 // this can be caused for example by setting x.__proto__ = x
         566                 :                 // restore delegate prototype chain
         567               0 :                 SetProto(cx, delegate, oldDelegateProto, true);
         568               0 :                 return false;
         569                 :             }
         570                 :         }
         571               0 :         return true;
         572                 :     }
         573                 :
         574               0 :     JSObject *delegate = DelegateObject(cx, obj);
         575               0 :     if (!delegate)
         576               0 :         return false;
         577                 :
         578               0 :     return js_SetPropertyHelper(cx, delegate, id, 0, vp, strict);
         579                 : }
         580                 :
         581                 : JSBool
         582               0 : ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
         583                 : {
         584               0 :     return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
         585                 : }
         586                 :
         587                 : JSBool
         588               0 : ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
         589                 : {
         590               0 :     JSObject *delegate = DelegateObject(cx, obj);
         591               0 :     if (!delegate)
         592               0 :         return false;
         593                 :
         594               0 :     return js_SetElementHelper(cx, delegate, index, 0, vp, strict);
         595                 : }
         596                 :
         597                 : JSBool
         598               0 : ArrayBuffer::obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
         599                 : {
         600               0 :     return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
         601                 : }
         602                 :
         603                 : JSBool
         604               0 : ArrayBuffer::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
         605                 : {
         606               0 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         607               0 :         *attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
         608               0 :         return true;
         609                 :     }
         610                 :
         611               0 :     JSObject *delegate = DelegateObject(cx, obj);
         612               0 :     if (!delegate)
         613               0 :         return false;
         614               0 :     return js_GetAttributes(cx, delegate, id, attrsp);
         615                 : }
         616                 :
         617                 : JSBool
         618               0 : ArrayBuffer::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
         619                 : {
         620               0 :     return obj_getGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
         621                 : }
         622                 :
         623                 : JSBool
         624               0 : ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
         625                 : {
         626               0 :     JSObject *delegate = DelegateObject(cx, obj);
         627               0 :     if (!delegate)
         628               0 :         return false;
         629               0 :     return js_GetElementAttributes(cx, delegate, index, attrsp);
         630                 : }
         631                 :
         632                 : JSBool
         633               0 : ArrayBuffer::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
         634                 : {
         635               0 :     return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
         636                 : }
         637                 :
         638                 : JSBool
         639               0 : ArrayBuffer::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
         640                 : {
         641               0 :     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         642                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
         643               0 :                              JSMSG_CANT_SET_ARRAY_ATTRS);
         644               0 :         return false;
         645                 :     }
         646                 :
         647               0 :     JSObject *delegate = DelegateObject(cx, obj);
         648               0 :     if (!delegate)
         649               0 :         return false;
         650               0 :     return js_SetAttributes(cx, delegate, id, attrsp);
         651                 : }
         652                 :
         653                 : JSBool
         654               0 : ArrayBuffer::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
         655                 : {
         656               0 :     return obj_setGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
         657                 : }
         658                 :
         659                 : JSBool
         660               0 : ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
         661                 : {
         662               0 :     JSObject *delegate = DelegateObject(cx, obj);
         663               0 :     if (!delegate)
         664               0 :         return false;
         665               0 :     return js_SetElementAttributes(cx, delegate, index, attrsp);
         666                 : }
         667                 :
         668                 : JSBool
         669               0 : ArrayBuffer::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
         670                 : {
         671               0 :     return obj_setGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
         672                 : }
         673                 :
         674                 : JSBool
         675               0 : ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
         676                 : {
         677               0 :     if (name == cx->runtime->atomState.byteLengthAtom) {
         678               0 :         rval->setBoolean(false);
         679               0 :         return true;
         680                 :     }
         681                 :
         682               0 :     JSObject *delegate = DelegateObject(cx, obj);
         683               0 :     if (!delegate)
         684               0 :         return false;
         685               0 :     return js_DeleteProperty(cx, delegate, name, rval, strict);
         686                 : }
         687                 :
         688                 : JSBool
         689               0 : ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
         690                 : {
         691               0 :     JSObject *delegate = DelegateObject(cx, obj);
         692               0 :     if (!delegate)
         693               0 :         return false;
         694               0 :     return js_DeleteElement(cx, delegate, index, rval, strict);
         695                 : }
         696                 :
         697                 : JSBool
         698               0 : ArrayBuffer::obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
         699                 : {
         700               0 :     JSObject *delegate = DelegateObject(cx, obj);
         701               0 :     if (!delegate)
         702               0 :         return false;
         703               0 :     return js_DeleteSpecial(cx, delegate, sid, rval, strict);
         704                 : }
         705                 :
         706                 : JSBool
         707              18 : ArrayBuffer::obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
         708                 :               Value *statep, jsid *idp)
         709                 : {
         710              18 :     statep->setNull();
         711              18 :     return true;
         712                 : }
         713                 :
         714                 : JSType
         715               0 : ArrayBuffer::obj_typeOf(JSContext *cx, JSObject *obj)
         716                 : {
         717               0 :     return JSTYPE_OBJECT;
         718                 : }
         719                 :
         720                 : /*
         721                 :  * TypedArray
         722                 :  *
         723                 :  * The non-templated base class for the specific typed implementations.
         724                 :  * This class holds all the member variables that are used by
         725                 :  * the subclasses.
         726                 :  */
         727                 :
         728                 : JSObject *
         729        38757882 : TypedArray::getTypedArray(JSObject *obj)
         730                 : {
         731        77515764 :     while (!js_IsTypedArray(obj))
         732               0 :         obj = obj->getProto();
         733        38757882 :     return obj;
         734                 : }
         735                 :
         736                 : inline bool
         737           22517 : TypedArray::isArrayIndex(JSContext *cx, JSObject *obj, jsid id, uint32_t *ip)
         738                 : {
         739                 :     uint32_t index;
         740           22517 :     if (js_IdIsIndex(id, &index) && index < getLength(obj)) {
         741           20308 :         if (ip)
         742           20308 :             *ip = index;
         743           20308 :         return true;
         744                 :     }
         745                 :
         746            2209 :     return false;
         747                 : }
         748                 :
         749                 : typedef Value (* TypedArrayPropertyGetter)(JSObject *tarray);
         750                 :
         751                 : template <TypedArrayPropertyGetter Get>
         752                 : class TypedArrayGetter {
         753                 :   public:
         754              27 :     static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) {
         755               9 :         do {
         756              27 :             if (js_IsTypedArray(obj)) {
         757              18 :                 JSObject *tarray = TypedArray::getTypedArray(obj);
         758              18 :                 if (tarray)
         759              18 :                     *vp = Get(tarray);
         760              18 :                 return true;
         761                 :             }
         762                 :         } while ((obj = obj->getProto()) != NULL);
         763               0 :         return true;
         764                 :     }
         765                 : };
         766                 :
         767                 : /*
         768                 :  * For now (until slots directly hold data)
         769                 :  * slots data element points to the JSObject representing the ArrayBuffer.
         770                 :  */
         771                 : inline Value
         772               9 : getBufferValue(JSObject *tarray)
         773                 : {
         774               9 :     JSObject *buffer = TypedArray::getBuffer(tarray);
         775               9 :     return ObjectValue(*buffer);
         776                 : }
         777                 :
         778                 : JSBool
         779               9 : TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
         780                 : {
         781               9 :     return TypedArrayGetter<getBufferValue>::get(cx, obj, id, vp);
         782                 : }
         783                 :
         784                 : inline Value
         785               0 : getByteOffsetValue(JSObject *tarray)
         786                 : {
         787               0 :     return Int32Value(TypedArray::getByteOffset(tarray));
         788                 : }
         789                 :
         790                 : JSBool
         791               0 : TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
         792                 : {
         793               0 :     return TypedArrayGetter<getByteOffsetValue>::get(cx, obj, id, vp);
         794                 : }
         795                 :
         796                 : inline Value
         797               0 : getByteLengthValue(JSObject *tarray)
         798                 : {
         799               0 :     return Int32Value(TypedArray::getByteLength(tarray));
         800                 : }
         801                 :
         802                 : JSBool
         803               0 : TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
         804                 : {
         805               0 :     return TypedArrayGetter<getByteLengthValue>::get(cx, obj, id, vp);
         806                 : }
         807                 :
         808                 : inline Value
         809               9 : getLengthValue(JSObject *tarray)
         810                 : {
         811               9 :     return Int32Value(TypedArray::getLength(tarray));
         812                 : }
         813                 :
         814                 : JSBool
         815               9 : TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
         816                 : {
         817               9 :     return TypedArrayGetter<getLengthValue>::get(cx, obj, id, vp);
         818                 : }
         819                 :
         820                 : JSBool
         821              22 : TypedArray::obj_lookupGeneric(JSContext *cx, JSObject *obj, jsid id,
         822                 :                               JSObject **objp, JSProperty **propp)
         823                 : {
         824              22 :     JSObject *tarray = getTypedArray(obj);
         825              22 :     JS_ASSERT(tarray);
         826                 :
         827              22 :     if (isArrayIndex(cx, tarray, id)) {
         828               0 :         *propp = PROPERTY_FOUND;
         829               0 :         *objp = obj;
         830               0 :         return true;
         831                 :     }
         832                 :
         833              22 :     JSObject *proto = obj->getProto();
         834              22 :     if (!proto) {
         835               0 :         *objp = NULL;
         836               0 :         *propp = NULL;
         837               0 :         return true;
         838                 :     }
         839                 :
         840              22 :     return proto->lookupGeneric(cx, id, objp, propp);
         841                 : }
         842                 :
         843                 : JSBool
         844               0 : TypedArray::obj_lookupProperty(JSContext *cx, JSObject *obj, PropertyName *name,
         845                 :                                JSObject **objp, JSProperty **propp)
         846                 : {
         847               0 :     return obj_lookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
         848                 : }
         849                 :
         850                 : JSBool
         851               0 : TypedArray::obj_lookupElement(JSContext *cx, JSObject *obj, uint32_t index,
         852                 :                               JSObject **objp, JSProperty **propp)
         853                 : {
         854               0 :     JSObject *tarray = getTypedArray(obj);
         855               0 :     JS_ASSERT(tarray);
         856                 :
         857               0 :     if (index < getLength(tarray)) {
         858               0 :         *propp = PROPERTY_FOUND;
         859               0 :         *objp = obj;
         860               0 :         return true;
         861                 :     }
         862                 :
         863               0 :     if (JSObject *proto = obj->getProto())
         864               0 :         return proto->lookupElement(cx, index, objp, propp);
         865                 :
         866               0 :     *objp = NULL;
         867               0 :     *propp = NULL;
         868               0 :     return true;
         869                 : }
         870                 :
         871                 : JSBool
         872               0 : TypedArray::obj_lookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid,
         873                 :                               JSObject **objp, JSProperty **propp)
         874                 : {
         875               0 :     return obj_lookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
         876                 : }
         877                 :
         878                 : JSBool
         879               0 : TypedArray::obj_getGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
         880                 : {
         881               0 :     *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         882                 :               ? JSPROP_PERMANENT | JSPROP_READONLY
         883               0 :               : JSPROP_PERMANENT | JSPROP_ENUMERATE;
         884               0 :     return true;
         885                 : }
         886                 :
         887                 : JSBool
         888               0 : TypedArray::obj_getPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
         889                 : {
         890               0 :     *attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE;
         891               0 :     return true;
         892                 : }
         893                 :
         894                 : JSBool
         895               0 : TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
         896                 : {
         897               0 :     *attrsp = JSPROP_PERMANENT | JSPROP_ENUMERATE;
         898               0 :     return true;
         899                 : }
         900                 :
         901                 : JSBool
         902               0 : TypedArray::obj_getSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
         903                 : {
         904               0 :     return obj_getGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
         905                 : }
         906                 :
         907                 : JSBool
         908               0 : TypedArray::obj_setGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
         909                 : {
         910               0 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
         911               0 :     return false;
         912                 : }
         913                 :
         914                 : JSBool
         915               0 : TypedArray::obj_setPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
         916                 : {
         917               0 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
         918               0 :     return false;
         919                 : }
         920                 :
         921                 : JSBool
         922               0 : TypedArray::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
         923                 : {
         924               0 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
         925               0 :     return false;
         926                 : }
         927                 :
         928                 : JSBool
         929               0 : TypedArray::obj_setSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
         930                 : {
         931               0 :     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
         932               0 :     return false;
         933                 : }
         934                 :
         935                 : /* static */ int
         936            3926 : TypedArray::lengthOffset()
         937                 : {
         938            3926 :     return JSObject::getFixedSlotOffset(FIELD_LENGTH);
         939                 : }
         940                 :
         941                 : /* static */ int
         942            3258 : TypedArray::dataOffset()
         943                 : {
         944            3258 :     return JSObject::getPrivateDataOffset(NUM_FIXED_SLOTS);
         945                 : }
         946                 :
         947                 : /* Helper clamped uint8_t type */
         948                 :
         949                 : int32_t JS_FASTCALL
         950             992 : js_TypedArray_uint8_clamp_double(const double x)
         951                 : {
         952                 :     // Not < so that NaN coerces to 0
         953             992 :     if (!(x >= 0))
         954             308 :         return 0;
         955                 :
         956             684 :     if (x > 255)
         957             246 :         return 255;
         958                 :
         959             438 :     double toTruncate = x + 0.5;
         960             438 :     uint8_t y = uint8_t(toTruncate);
         961                 :
         962                 :     /*
         963                 :      * now val is rounded to nearest, ties rounded up.  We want
         964                 :      * rounded to nearest ties to even, so check whether we had a
         965                 :      * tie.
         966                 :      */
         967             438 :     if (y == toTruncate) {
         968                 :         /*
         969                 :          * It was a tie (since adding 0.5 gave us the exact integer
         970                 :          * we want).  Since we rounded up, we either already have an
         971                 :          * even number or we have an odd number but the number we
         972                 :          * want is one less.  So just unconditionally masking out the
         973                 :          * ones bit should do the trick to get us the value we
         974                 :          * want.
         975                 :          */
         976             104 :         return (y & ~1);
         977                 :     }
         978                 :
         979             334 :     return y;
         980                 : }
         981                 :
         982                 : struct uint8_clamped {
         983                 :     uint8_t val;
         984                 :
         985                 :     uint8_clamped() { }
         986            1288 :     uint8_clamped(const uint8_clamped& other) : val(other.val) { }
         987                 :
         988                 :     // invoke our assignment helpers for constructor conversion
         989               0 :     uint8_clamped(uint8_t x)    { *this = x; }
         990               0 :     uint8_clamped(uint16_t x)   { *this = x; }
         991               0 :     uint8_clamped(uint32_t x)   { *this = x; }
         992               0 :     uint8_clamped(int8_t x)     { *this = x; }
         993               0 :     uint8_clamped(int16_t x)    { *this = x; }
         994             773 :     uint8_clamped(int32_t x)    { *this = x; }
         995             887 :     uint8_clamped(double x)     { *this = x; }
         996                 :
         997            1660 :     inline uint8_clamped& operator= (const uint8_clamped& x) {
         998            1660 :         val = x.val;
         999            1660 :         return *this;
        1000                 :     }
        1001                 :
        1002               0 :     inline uint8_clamped& operator= (uint8_t x) {
        1003               0 :         val = x;
        1004               0 :         return *this;
        1005                 :     }
        1006                 :
        1007               0 :     inline uint8_clamped& operator= (uint16_t x) {
        1008               0 :         val = (x > 255) ? 255 : uint8_t(x);
        1009               0 :         return *this;
        1010                 :     }
        1011                 :
        1012               0 :     inline uint8_clamped& operator= (uint32_t x) {
        1013               0 :         val = (x > 255) ? 255 : uint8_t(x);
        1014               0 :         return *this;
        1015                 :     }
        1016                 :
        1017               0 :     inline uint8_clamped& operator= (int8_t x) {
        1018               0 :         val = (x >= 0) ? uint8_t(x) : 0;
        1019               0 :         return *this;
        1020                 :     }
        1021                 :
        1022               0 :     inline uint8_clamped& operator= (int16_t x) {
        1023                 :         val = (x >= 0)
        1024                 :               ? ((x < 255)
        1025                 :                  ? uint8_t(x)
        1026                 :                  : 255)
        1027               0 :               : 0;
        1028               0 :         return *this;
        1029                 :     }
        1030                 :
        1031             773 :     inline uint8_clamped& operator= (int32_t x) {
        1032                 :         val = (x >= 0)
        1033                 :               ? ((x < 255)
        1034                 :                  ? uint8_t(x)
        1035                 :                  : 255)
        1036             773 :               : 0;
        1037             773 :         return *this;
        1038                 :     }
        1039                 :
        1040             887 :     inline uint8_clamped& operator= (const double x) {
        1041             887 :         val = uint8_t(js_TypedArray_uint8_clamp_double(x));
        1042             887 :         return *this;
        1043                 :     }
        1044                 :
        1045            1288 :     inline operator uint8_t() const {
        1046            1288 :         return val;
        1047                 :     }
        1048                 : };
        1049                 :
        1050                 : /* Make sure the compiler isn't doing some funky stuff */
        1051                 : JS_STATIC_ASSERT(sizeof(uint8_clamped) == 1);
        1052                 :
        1053                 : template<typename NativeType> static inline const int TypeIDOfType();
        1054            6091 : template<> inline const int TypeIDOfType<int8_t>() { return TypedArray::TYPE_INT8; }
        1055            3792 : template<> inline const int TypeIDOfType<uint8_t>() { return TypedArray::TYPE_UINT8; }
        1056            4209 : template<> inline const int TypeIDOfType<int16_t>() { return TypedArray::TYPE_INT16; }
        1057            3027 : template<> inline const int TypeIDOfType<uint16_t>() { return TypedArray::TYPE_UINT16; }
        1058            4636 : template<> inline const int TypeIDOfType<int32_t>() { return TypedArray::TYPE_INT32; }
        1059            3342 : template<> inline const int TypeIDOfType<uint32_t>() { return TypedArray::TYPE_UINT32; }
        1060           11082 : template<> inline const int TypeIDOfType<float>() { return TypedArray::TYPE_FLOAT32; }
        1061            4062 : template<> inline const int TypeIDOfType<double>() { return TypedArray::TYPE_FLOAT64; }
        1062            4004 : template<> inline const int TypeIDOfType<uint8_clamped>() { return TypedArray::TYPE_UINT8_CLAMPED; }
        1063                 :
        1064            3889 : template<typename NativeType> static inline const bool TypeIsUnsigned() { return false; }
        1065             798 : template<> inline const bool TypeIsUnsigned<uint8_t>() { return true; }
        1066             966 : template<> inline const bool TypeIsUnsigned<uint16_t>() { return true; }
        1067            1217 : template<> inline const bool TypeIsUnsigned<uint32_t>() { return true; }
        1068                 :
        1069           24915 : template<typename NativeType> static inline const bool TypeIsFloatingPoint() { return false; }
        1070             854 : template<> inline const bool TypeIsFloatingPoint<float>() { return true; }
        1071           19063 : template<> inline const bool TypeIsFloatingPoint<double>() { return true; }
        1072                 :
        1073                 : template<typename NativeType> static inline const bool ElementTypeMayBeDouble() { return false; }
        1074                 : template<> inline const bool ElementTypeMayBeDouble<uint32_t>() { return true; }
        1075                 : template<> inline const bool ElementTypeMayBeDouble<float>() { return true; }
        1076                 : template<> inline const bool ElementTypeMayBeDouble<double>() { return true; }
        1077                 :
        1078                 : template<typename NativeType> class TypedArrayTemplate;
        1079                 :
        1080                 : template<typename NativeType>
        1081                 : class TypedArrayTemplate
        1082                 :   : public TypedArray
        1083                 : {
        1084                 :   public:
        1085                 :     typedef NativeType ThisType;
        1086                 :     typedef TypedArrayTemplate<NativeType> ThisTypeArray;
        1087           44245 :     static const int ArrayTypeID() { return TypeIDOfType<NativeType>(); }
        1088            6870 :     static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
        1089           44760 :     static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
        1090                 :     static const bool ArrayElementTypeMayBeDouble() { return ElementTypeMayBeDouble<NativeType>(); }
        1091                 :
        1092                 :     static const size_t BYTES_PER_ELEMENT = sizeof(ThisType);
        1093                 :
        1094           26514 :     static inline Class *slowClass()
        1095                 :     {
        1096           26514 :         return &TypedArray::slowClasses[ArrayTypeID()];
        1097                 :     }
        1098                 :
        1099            8145 :     static inline Class *fastClass()
        1100                 :     {
        1101            8145 :         return &TypedArray::fastClasses[ArrayTypeID()];
        1102                 :     }
        1103                 :
        1104                 :     static void
        1105              47 :     obj_trace(JSTracer *trc, JSObject *obj)
        1106                 :     {
        1107              47 :         MarkSlot(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
        1108              47 :     }
        1109                 :
        1110                 :     static JSBool
        1111             864 :     obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
        1112                 :                     Value *vp)
        1113                 :     {
        1114             864 :         JSObject *tarray = getTypedArray(obj);
        1115                 :
        1116             864 :         if (name == cx->runtime->atomState.lengthAtom) {
        1117             171 :             vp->setNumber(getLength(tarray));
        1118             171 :             return true;
        1119                 :         }
        1120                 :
        1121             693 :         JSObject *proto = obj->getProto();
        1122             693 :         if (!proto) {
        1123               0 :             vp->setUndefined();
        1124               0 :             return true;
        1125                 :         }
        1126                 :
        1127             693 :         return proto->getProperty(cx, receiver, name, vp);
        1128                 :     }
        1129                 :
        1130                 :     static JSBool
        1131           24676 :     obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
        1132                 :     {
        1133           24676 :         JSObject *tarray = getTypedArray(obj);
        1134                 :
        1135           24676 :         if (index < getLength(tarray)) {
        1136           19465 :             copyIndexToValue(cx, tarray, index, vp);
        1137           19465 :             return true;
        1138                 :         }
        1139                 :
        1140            5211 :         JSObject *proto = obj->getProto();
        1141            5211 :         if (!proto) {
        1142               0 :             vp->setUndefined();
        1143               0 :             return true;
        1144                 :         }
        1145                 :
        1146            5211 :         return proto->getElement(cx, receiver, index, vp);
        1147                 :     }
        1148                 :
        1149                 :     static JSBool
        1150               0 :     obj_getSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
        1151                 :     {
        1152               0 :         JSObject *proto = obj->getProto();
        1153               0 :         if (!proto) {
        1154               0 :             vp->setUndefined();
        1155               0 :             return true;
        1156                 :         }
        1157                 :
        1158               0 :         return proto->getSpecial(cx, receiver, sid, vp);
        1159                 :     }
        1160                 :
        1161                 :     static JSBool
        1162            2905 :     obj_getGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
        1163                 :     {
        1164            2905 :         Value idval = IdToValue(id);
        1165                 :
        1166                 :         uint32_t index;
        1167            2905 :         if (IsDefinitelyIndex(idval, &index))
        1168            2041 :             return obj_getElement(cx, obj, receiver, index, vp);
        1169                 :
        1170             864 :         SpecialId sid;
        1171             864 :         if (ValueIsSpecial(obj, &idval, &sid, cx))
        1172               0 :             return obj_getSpecial(cx, obj, receiver, sid, vp);
        1173                 :
        1174                 :         JSAtom *atom;
        1175             864 :         if (!js_ValueToAtom(cx, idval, &atom))
        1176               0 :             return false;
        1177                 :
        1178             864 :         if (atom->isIndex(&index))
        1179               0 :             return obj_getElement(cx, obj, receiver, index, vp);
        1180                 :
        1181             864 :         return obj_getProperty(cx, obj, receiver, atom->asPropertyName(), vp);
        1182                 :     }
        1183                 :
        1184                 :     static JSBool
        1185               0 :     obj_getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp, bool *present)
        1186                 :     {
        1187                 :         // Fast-path the common case of index < length
        1188               0 :         JSObject *tarray = getTypedArray(obj);
        1189                 :
        1190               0 :         if (index < getLength(tarray)) {
        1191                 :             // this inline function is specialized for each type
        1192               0 :             copyIndexToValue(cx, tarray, index, vp);
        1193               0 :             *present = true;
        1194               0 :             return true;
        1195                 :         }
        1196                 :
        1197               0 :         JSObject *proto = obj->getProto();
        1198               0 :         if (!proto) {
        1199               0 :             vp->setUndefined();
        1200               0 :             return true;
        1201                 :         }
        1202                 :
        1203               0 :         return proto->getElementIfPresent(cx, receiver, index, vp, present);
        1204                 :     }
        1205                 :
        1206                 :     static bool
        1207           20308 :     setElementTail(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp, JSBool strict)
        1208                 :     {
        1209           20308 :         JS_ASSERT(tarray);
        1210           20308 :         JS_ASSERT(index < getLength(tarray));
        1211                 :
        1212           20308 :         if (vp->isInt32()) {
        1213           11710 :             setIndex(tarray, index, NativeType(vp->toInt32()));
        1214           11710 :             return true;
        1215                 :         }
        1216                 :
        1217                 :         double d;
        1218            8598 :         if (vp->isDouble()) {
        1219            3161 :             d = vp->toDouble();
        1220            5437 :         } else if (vp->isNull()) {
        1221               0 :             d = 0.0;
        1222            5437 :         } else if (vp->isPrimitive()) {
        1223            3102 :             JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean());
        1224            3102 :             if (vp->isString()) {
        1225            1774 :                 JS_ALWAYS_TRUE(ToNumber(cx, *vp, &d));
        1226            1328 :             } else if (vp->isUndefined()) {
        1227              95 :                 d = js_NaN;
        1228                 :             } else {
        1229            1233 :                 d = double(vp->toBoolean());
        1230                 :             }
        1231                 :         } else {
        1232                 :             // non-primitive assignments become NaN or 0 (for float/int arrays)
        1233            2335 :             d = js_NaN;
        1234                 :         }
        1235                 :
        1236                 :         // If the array is an integer array, we only handle up to
        1237                 :         // 32-bit ints from this point on.  if we want to handle
        1238                 :         // 64-bit ints, we'll need some changes.
        1239                 :
        1240                 :         // Assign based on characteristics of the destination type
        1241            8598 :         if (ArrayTypeIsFloatingPoint()) {
        1242            1728 :             setIndex(tarray, index, NativeType(d));
        1243            6870 :         } else if (ArrayTypeIsUnsigned()) {
        1244               0 :             JS_ASSERT(sizeof(NativeType) <= 4);
        1245            2981 :             uint32_t n = js_DoubleToECMAUint32(d);
        1246            2981 :             setIndex(tarray, index, NativeType(n));
        1247            3889 :         } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) {
        1248                 :             // The uint8_clamped type has a special rounding converter
        1249                 :             // for doubles.
        1250             887 :             setIndex(tarray, index, NativeType(d));
        1251                 :         } else {
        1252               0 :             JS_ASSERT(sizeof(NativeType) <= 4);
        1253            3002 :             int32_t n = js_DoubleToECMAInt32(d);
        1254            3002 :             setIndex(tarray, index, NativeType(n));
        1255                 :         }
        1256                 :
        1257            8598 :         return true;
        1258                 :     }
        1259                 :
        1260                 :     static JSBool
        1261           22495 :     obj_setGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
        1262                 :     {
        1263           22495 :         JSObject *tarray = getTypedArray(obj);
        1264           22495 :         JS_ASSERT(tarray);
        1265                 :
        1266           22495 :         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
        1267               0 :             vp->setNumber(getLength(tarray));
        1268               0 :             return true;
        1269                 :         }
        1270                 :
        1271                 :         uint32_t index;
        1272                 :         // We can't just chain to js_SetPropertyHelper, because we're not a normal object.
        1273           22495 :         if (!isArrayIndex(cx, tarray, id, &index)) {
        1274                 :             // Silent ignore is better than an exception here, because
        1275                 :             // at some point we may want to support other properties on
        1276                 :             // these objects.  This is especially true when these arrays
        1277                 :             // are used to implement HTML Canvas 2D's PixelArray objects,
        1278                 :             // which used to be plain old arrays.
        1279            2187 :             vp->setUndefined();
        1280            2187 :             return true;
        1281                 :         }
        1282                 :
        1283           20308 :         return setElementTail(cx, tarray, index, vp, strict);
        1284                 :     }
        1285                 :
        1286                 :     static JSBool
        1287               0 :     obj_setProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
        1288                 :     {
        1289               0 :         return obj_setGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
        1290                 :     }
        1291                 :
        1292                 :     static JSBool
        1293               0 :     obj_setElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
        1294                 :     {
        1295               0 :         JSObject *tarray = getTypedArray(obj);
        1296               0 :         JS_ASSERT(tarray);
        1297                 :
        1298               0 :         if (index >= getLength(tarray)) {
        1299                 :             // Silent ignore is better than an exception here, because
        1300                 :             // at some point we may want to support other properties on
        1301                 :             // these objects.  This is especially true when these arrays
        1302                 :             // are used to implement HTML Canvas 2D's PixelArray objects,
        1303                 :             // which used to be plain old arrays.
        1304               0 :             vp->setUndefined();
        1305               0 :             return true;
        1306                 :         }
        1307                 :
        1308               0 :         return setElementTail(cx, tarray, index, vp, strict);
        1309                 :     }
        1310                 :
        1311                 :     static JSBool
        1312               0 :     obj_setSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
        1313                 :     {
        1314               0 :         return obj_setGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
        1315                 :     }
        1316                 :
        1317                 :     static JSBool
        1318               0 :     obj_defineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *v,
        1319                 :                       PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
        1320                 :     {
        1321               0 :         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
        1322               0 :             return true;
        1323                 :
        1324               0 :         Value tmp = *v;
        1325               0 :         return obj_setGeneric(cx, obj, id, &tmp, false);
        1326                 :     }
        1327                 :
        1328                 :     static JSBool
        1329               0 :     obj_defineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *v,
        1330                 :                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
        1331                 :     {
        1332               0 :         return obj_defineGeneric(cx, obj, ATOM_TO_JSID(name), v, getter, setter, attrs);
        1333                 :     }
        1334                 :
        1335                 :     static JSBool
        1336               0 :     obj_defineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *v,
        1337                 :                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
        1338                 :     {
        1339               0 :         Value tmp = *v;
        1340               0 :         return obj_setElement(cx, obj, index, &tmp, false);
        1341                 :     }
        1342                 :
        1343                 :     static JSBool
        1344               0 :     obj_defineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *v,
        1345                 :                       PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
        1346                 :     {
        1347               0 :         return obj_defineGeneric(cx, obj, SPECIALID_TO_JSID(sid), v, getter, setter, attrs);
        1348                 :     }
        1349                 :
        1350                 :     static JSBool
        1351               0 :     obj_deleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
        1352                 :     {
        1353               0 :         if (name == cx->runtime->atomState.lengthAtom) {
        1354               0 :             rval->setBoolean(false);
        1355               0 :             return true;
        1356                 :         }
        1357                 :
        1358               0 :         rval->setBoolean(true);
        1359               0 :         return true;
        1360                 :     }
        1361                 :
        1362                 :     static JSBool
        1363               0 :     obj_deleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
        1364                 :     {
        1365               0 :         JSObject *tarray = TypedArray::getTypedArray(obj);
        1366               0 :         JS_ASSERT(tarray);
        1367                 :
        1368               0 :         if (index < getLength(tarray)) {
        1369               0 :             rval->setBoolean(false);
        1370               0 :             return true;
        1371                 :         }
        1372                 :
        1373               0 :         rval->setBoolean(true);
        1374               0 :         return true;
        1375                 :     }
        1376                 :
        1377                 :     static JSBool
        1378               0 :     obj_deleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
        1379                 :     {
        1380               0 :         rval->setBoolean(true);
        1381               0 :         return true;
        1382                 :     }
        1383                 :
        1384                 :     static JSBool
        1385        38700180 :     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
        1386                 :                   Value *statep, jsid *idp)
        1387                 :     {
        1388        38700180 :         JSObject *tarray = getTypedArray(obj);
        1389        38700180 :         JS_ASSERT(tarray);
        1390                 :
        1391                 :         /*
        1392                 :          * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length).
        1393                 :          * *statep is JSVAL_TRUE if enumerating "length" and
        1394                 :          * JSVAL_TO_INT(index) when enumerating index.
        1395                 :          */
        1396        38700180 :         switch (enum_op) {
        1397                 :           case JSENUMERATE_INIT_ALL:
        1398               0 :             statep->setBoolean(true);
        1399               0 :             if (idp)
        1400               0 :                 *idp = ::INT_TO_JSID(getLength(tarray) + 1);
        1401               0 :             break;
        1402                 :
        1403                 :           case JSENUMERATE_INIT:
        1404               9 :             statep->setInt32(0);
        1405               9 :             if (idp)
        1406               0 :                 *idp = ::INT_TO_JSID(getLength(tarray));
        1407               9 :             break;
        1408                 :
        1409                 :           case JSENUMERATE_NEXT:
        1410        38700171 :             if (statep->isTrue()) {
        1411               0 :                 *idp = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
        1412               0 :                 statep->setInt32(0);
        1413                 :             } else {
        1414        38700171 :                 uint32_t index = statep->toInt32();
        1415        38700171 :                 if (index < getLength(tarray)) {
        1416        38700162 :                     *idp = ::INT_TO_JSID(index);
        1417        38700162 :                     statep->setInt32(index + 1);
        1418                 :                 } else {
        1419               9 :                     JS_ASSERT(index == getLength(tarray));
        1420               9 :                     statep->setNull();
        1421                 :                 }
        1422                 :             }
        1423        38700171 :             break;
        1424                 :
        1425                 :           case JSENUMERATE_DESTROY:
        1426               0 :             statep->setNull();
        1427               0 :             break;
        1428                 :         }
        1429                 :
        1430        38700180 :         return true;
        1431                 :     }
        1432                 :
        1433                 :     static JSType
        1434               0 :     obj_typeOf(JSContext *cx, JSObject *obj)
        1435                 :     {
        1436               0 :         return JSTYPE_OBJECT;
        1437                 :     }
        1438                 :
        1439                 :     static JSObject *
        1440            5697 :     createTypedArray(JSContext *cx, JSObject *bufobj, uint32_t byteOffset, uint32_t len)
        1441                 :     {
        1442            5697 :         JS_ASSERT(bufobj->isArrayBuffer());
        1443            5697 :         JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
        1444            5697 :         if (!obj)
        1445               0 :             return NULL;
        1446                 : #ifdef JS_THREADSAFE
        1447            5697 :         JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND);
        1448                 : #else
        1449                 :         JS_ASSERT(obj->getAllocKind() == gc::FINALIZE_OBJECT8);
        1450                 : #endif
        1451                 :
        1452                 :         /*
        1453                 :          * Specialize the type of the object on the current scripted location,
        1454                 :          * and mark the type as definitely a typed array.
        1455                 :          */
        1456            5697 :         JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(slowClass());
        1457            5697 :         types::TypeObject *type = types::GetTypeCallerInitObject(cx, key);
        1458            5697 :         if (!type)
        1459               0 :             return NULL;
        1460            5697 :         obj->setType(type);
        1461                 :
        1462            5697 :         obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
        1463            5697 :         obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
        1464                 :
        1465                 :         /*
        1466                 :          * N.B. The base of the array's data is stored in the object's
        1467                 :          * private data rather than a slot, to avoid alignment restrictions
        1468                 :          * on private Values.
        1469                 :          */
        1470            5697 :         obj->setPrivate(bufobj->arrayBufferDataOffset() + byteOffset);
        1471                 :
        1472            5697 :         obj->setSlot(FIELD_LENGTH, Int32Value(len));
        1473            5697 :         obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset));
        1474            5697 :         obj->setSlot(FIELD_BYTELENGTH, Int32Value(len * sizeof(NativeType)));
        1475                 :
        1476           11394 :         DebugOnly<uint32_t> bufferByteLength = getBuffer(obj)->arrayBufferByteLength();
        1477            5697 :         JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj));
        1478            5697 :         JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
        1479            5697 :         JS_ASSERT(getBuffer(obj)->arrayBufferDataOffset() <= getDataOffset(obj));
        1480            5697 :         JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
        1481                 :
        1482            5697 :         JS_ASSERT(obj->getClass() == slowClass());
        1483                 :
        1484                 :         js::Shape *empty = EmptyShape::getInitialShape(cx, fastClass(),
        1485                 :                                                        obj->getProto(), obj->getParent(),
        1486                 :                                                        gc::FINALIZE_OBJECT8,
        1487            5697 :                                                        BaseShape::NOT_EXTENSIBLE);
        1488            5697 :         if (!empty)
        1489               0 :             return NULL;
        1490            5697 :         obj->setLastPropertyInfallible(empty);
        1491                 :
        1492            5697 :         JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS);
        1493                 :
        1494            5697 :         return obj;
        1495                 :     }
        1496                 :
        1497                 :     /*
        1498                 :      * new [Type]Array(length)
        1499                 :      * new [Type]Array(otherTypedArray)
        1500                 :      * new [Type]Array(JSArray)
        1501                 :      * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
        1502                 :      */
        1503                 :     static JSBool
        1504            5148 :     class_constructor(JSContext *cx, unsigned argc, Value *vp)
        1505                 :     {
        1506                 :         /* N.B. this is a constructor for slowClass, not fastClass! */
        1507            5148 :         JSObject *obj = create(cx, argc, JS_ARGV(cx, vp));
        1508            5148 :         if (!obj)
        1509               0 :             return false;
        1510            5148 :         vp->setObject(*obj);
        1511            5148 :         return true;
        1512                 :     }
        1513                 :
        1514                 :     static JSObject *
        1515            5202 :     create(JSContext *cx, unsigned argc, Value *argv)
        1516                 :     {
        1517                 :         /* N.B. there may not be an argv[-2]/argv[-1]. */
        1518                 :
        1519                 :         /* () or (number) */
        1520            5202 :         uint32_t len = 0;
        1521            5202 :         if (argc == 0 || ValueIsLength(cx, argv[0], &len)) {
        1522            4626 :             JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
        1523            4626 :             if (!bufobj)
        1524               0 :                 return NULL;
        1525                 :
        1526            4626 :             return createTypedArray(cx, bufobj, 0, len);
        1527                 :         }
        1528                 :
        1529                 :         /* (not an object) */
        1530             576 :         if (!argv[0].isObject()) {
        1531               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1532                 :                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
        1533               0 :             return NULL;
        1534                 :         }
        1535                 :
        1536             576 :         JSObject *dataObj = &argv[0].toObject();
        1537                 :
        1538                 :         /* (typedArray) */
        1539             576 :         if (js_IsTypedArray(dataObj)) {
        1540               0 :             JSObject *otherTypedArray = getTypedArray(dataObj);
        1541               0 :             JS_ASSERT(otherTypedArray);
        1542                 :
        1543               0 :             uint32_t len = getLength(otherTypedArray);
        1544               0 :             JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
        1545               0 :             if (!bufobj)
        1546               0 :                 return NULL;
        1547                 :
        1548               0 :             JSObject *obj = createTypedArray(cx, bufobj, 0, len);
        1549               0 :             if (!obj || !copyFromTypedArray(cx, obj, otherTypedArray, 0))
        1550               0 :                 return NULL;
        1551               0 :             return obj;
        1552                 :         }
        1553                 :
        1554                 :         /* (obj, byteOffset, length). */
        1555             576 :         int32_t byteOffset = -1;
        1556             576 :         int32_t length = -1;
        1557                 :
        1558             576 :         if (argc > 1) {
        1559              18 :             if (!ToInt32(cx, argv[1], &byteOffset))
        1560               0 :                 return NULL;
        1561              18 :             if (byteOffset < 0) {
        1562               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1563                 :                                      JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "1");
        1564               0 :                 return NULL;
        1565                 :             }
        1566                 :
        1567              18 :             if (argc > 2) {
        1568              18 :                 if (!ToInt32(cx, argv[2], &length))
        1569               0 :                     return NULL;
        1570              18 :                 if (length < 0) {
        1571               0 :                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1572                 :                                          JSMSG_TYPED_ARRAY_NEGATIVE_ARG, "2");
        1573               0 :                     return NULL;
        1574                 :                 }
        1575                 :             }
        1576                 :         }
        1577                 :
        1578                 :         /* (obj, byteOffset, length) */
        1579             576 :         return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
        1580                 :     }
        1581                 :
        1582                 :     /* subarray(start[, end]) */
        1583                 :     static JSBool
        1584            1629 :     fun_subarray(JSContext *cx, unsigned argc, Value *vp)
        1585                 :     {
        1586            1629 :         CallArgs args = CallArgsFromVp(argc, vp);
        1587                 :
        1588                 :         bool ok;
        1589            1629 :         JSObject *obj = NonGenericMethodGuard(cx, args, fun_subarray, fastClass(), &ok);
        1590            1629 :         if (!obj)
        1591            1134 :             return ok;
        1592                 :
        1593             495 :         JSObject *tarray = getTypedArray(obj);
        1594             495 :         if (!tarray)
        1595               0 :             return true;
        1596                 :
        1597                 :         // these are the default values
        1598             495 :         int32_t begin = 0, end = getLength(tarray);
        1599             495 :         int32_t length = int32_t(getLength(tarray));
        1600                 :
        1601             495 :         if (args.length() > 0) {
        1602               9 :             if (!ToClampedIndex(cx, args[0], length, &begin))
        1603               0 :                 return false;
        1604                 :
        1605               9 :             if (args.length() > 1) {
        1606               9 :                 if (!ToClampedIndex(cx, args[1], length, &end))
        1607               0 :                     return false;
        1608                 :             }
        1609                 :         }
        1610                 :
        1611             495 :         if (begin > end)
        1612               0 :             begin = end;
        1613                 :
        1614             495 :         JSObject *nobj = createSubarray(cx, tarray, begin, end);
        1615             495 :         if (!nobj)
        1616               0 :             return false;
        1617             495 :         args.rval().setObject(*nobj);
        1618             495 :         return true;
        1619                 :     }
        1620                 :
        1621                 :     /* set(array[, offset]) */
        1622                 :     static JSBool
        1623             819 :     fun_set(JSContext *cx, unsigned argc, Value *vp)
        1624                 :     {
        1625             819 :         CallArgs args = CallArgsFromVp(argc, vp);
        1626                 :
        1627                 :         bool ok;
        1628             819 :         JSObject *obj = NonGenericMethodGuard(cx, args, fun_set, fastClass(), &ok);
        1629             819 :         if (!obj)
        1630             567 :             return ok;
        1631                 :
        1632             252 :         JSObject *tarray = getTypedArray(obj);
        1633             252 :         if (!tarray)
        1634               0 :             return true;
        1635                 :
        1636                 :         // these are the default values
        1637             252 :         int32_t off = 0;
        1638                 :
        1639             252 :         if (args.length() > 1) {
        1640               9 :             if (!ToInt32(cx, args[1], &off))
        1641               0 :                 return false;
        1642                 :
        1643               9 :             if (off < 0 || uint32_t(off) > getLength(tarray)) {
        1644                 :                 // the given offset is bogus
        1645               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1646                 :                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
        1647               0 :                 return false;
        1648                 :             }
        1649                 :         }
        1650                 :
        1651             252 :         uint32_t offset(off);
        1652                 :
        1653                 :         // first arg must be either a typed array or a JS array
        1654             252 :         if (args.length() == 0 || !args[0].isObject()) {
        1655               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1656                 :                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
        1657               0 :             return false;
        1658                 :         }
        1659                 :
        1660             252 :         JSObject *arg0 = args[0].toObjectOrNull();
        1661             252 :         if (js_IsTypedArray(arg0)) {
        1662               9 :             JSObject *src = TypedArray::getTypedArray(arg0);
        1663               9 :             if (!src ||
        1664                 :                 getLength(src) > getLength(tarray) - offset)
        1665                 :             {
        1666               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1667                 :                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
        1668               0 :                 return false;
        1669                 :             }
        1670                 :
        1671               9 :             if (!copyFromTypedArray(cx, obj, src, offset))
        1672               0 :                 return false;
        1673                 :         } else {
        1674                 :             uint32_t len;
        1675             243 :             if (!js_GetLengthProperty(cx, arg0, &len))
        1676               0 :                 return false;
        1677                 :
        1678                 :             // avoid overflow; we know that offset <= length
        1679             243 :             if (len > getLength(tarray) - offset) {
        1680               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1681                 :                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
        1682               0 :                 return false;
        1683                 :             }
        1684                 :
        1685             243 :             if (!copyFromArray(cx, obj, arg0, len, offset))
        1686               0 :                 return false;
        1687                 :         }
        1688                 :
        1689             252 :         args.rval().setUndefined();
        1690             252 :         return true;
        1691                 :     }
        1692                 :
        1693                 :   public:
        1694                 :     static JSObject *
        1695             576 :     createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
        1696                 :                                      int32_t byteOffsetInt, int32_t lengthInt)
        1697                 :     {
        1698             576 :         JS_ASSERT(!js_IsTypedArray(other));
        1699                 :
        1700                 :         /* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
        1701             576 :         if (other->isArrayBuffer()) {
        1702             459 :             uint32_t boffset = (byteOffsetInt < 0) ? 0 : uint32_t(byteOffsetInt);
        1703                 :
        1704             459 :             if (boffset > other->arrayBufferByteLength() || boffset % sizeof(NativeType) != 0) {
        1705               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1706                 :                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
        1707               0 :                 return NULL; // invalid byteOffset
        1708                 :             }
        1709                 :
        1710                 :             uint32_t len;
        1711             459 :             if (lengthInt < 0) {
        1712             441 :                 len = (other->arrayBufferByteLength() - boffset) / sizeof(NativeType);
        1713             441 :                 if (len * sizeof(NativeType) != (other->arrayBufferByteLength() - boffset)) {
        1714               0 :                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1715                 :                                          JSMSG_TYPED_ARRAY_BAD_ARGS);
        1716               0 :                     return NULL; // given byte array doesn't map exactly to sizeof(NativeType)*N
        1717                 :                 }
        1718                 :             } else {
        1719              18 :                 len = (uint32_t) lengthInt;
        1720                 :             }
        1721                 :
        1722                 :             // Go slowly and check for overflow.
        1723             459 :             uint32_t arrayByteLength = len*sizeof(NativeType);
        1724             459 :             if (uint32_t(len) >= INT32_MAX / sizeof(NativeType) ||
        1725                 :                 uint32_t(boffset) >= INT32_MAX - arrayByteLength)
        1726                 :             {
        1727               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1728                 :                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
        1729               0 :                 return NULL; // overflow occurred along the way when calculating boffset+len*sizeof(NativeType)
        1730                 :             }
        1731                 :
        1732             459 :             if (arrayByteLength + boffset > other->arrayBufferByteLength()) {
        1733               0 :                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        1734                 :                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
        1735               0 :                 return NULL; // boffset+len is too big for the arraybuffer
        1736                 :             }
        1737                 :
        1738             459 :             return createTypedArray(cx, other, boffset, len);
        1739                 :         }
        1740                 :
        1741                 :         /*
        1742                 :          * Otherwise create a new typed array and copy len properties from the
        1743                 :          * object.
        1744                 :          */
        1745                 :         uint32_t len;
        1746             117 :         if (!js_GetLengthProperty(cx, other, &len))
        1747               0 :             return NULL;
        1748                 :
        1749             117 :         JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
        1750             117 :         if (!bufobj)
        1751               0 :             return NULL;
        1752                 :
        1753             117 :         JSObject *obj = createTypedArray(cx, bufobj, 0, len);
        1754             117 :         if (!obj || !copyFromArray(cx, obj, other, len))
        1755               0 :             return NULL;
        1756             117 :         return obj;
        1757                 :     }
        1758                 :
        1759                 :     static const NativeType
        1760           19465 :     getIndex(JSObject *obj, uint32_t index)
        1761                 :     {
        1762           19465 :         return *(static_cast<const NativeType*>(getDataOffset(obj)) + index);
        1763                 :     }
        1764                 :
        1765                 :     static void
        1766           20308 :     setIndex(JSObject *obj, uint32_t index, NativeType val)
        1767                 :     {
        1768           20308 :         *(static_cast<NativeType*>(getDataOffset(obj)) + index) = val;
        1769           20308 :     }
        1770                 :
        1771            7819 :     static void copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp);
        1772                 :
        1773                 :     static JSObject *
        1774             495 :     createSubarray(JSContext *cx, JSObject *tarray, uint32_t begin, uint32_t end)
        1775                 :     {
        1776             495 :         JS_ASSERT(tarray);
        1777                 :
        1778             495 :         JS_ASSERT(begin <= getLength(tarray));
        1779             495 :         JS_ASSERT(end <= getLength(tarray));
        1780                 :
        1781             495 :         JSObject *bufobj = getBuffer(tarray);
        1782             495 :         JS_ASSERT(bufobj);
        1783                 :
        1784             495 :         JS_ASSERT(begin <= end);
        1785             495 :         uint32_t length = end - begin;
        1786                 :
        1787             495 :         JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
        1788             495 :         JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray));
        1789             495 :         uint32_t byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType);
        1790                 :
        1791             495 :         return createTypedArray(cx, bufobj, byteOffset, length);
        1792                 :     }
        1793                 :
        1794                 :   protected:
        1795                 :     static NativeType
        1796              72 :     nativeFromDouble(double d)
        1797                 :     {
        1798              72 :         if (!ArrayTypeIsFloatingPoint() && JS_UNLIKELY(JSDOUBLE_IS_NaN(d)))
        1799               0 :             return NativeType(int32_t(0));
        1800              72 :         if (TypeIsFloatingPoint<NativeType>())
        1801              72 :             return NativeType(d);
        1802               0 :         if (TypeIsUnsigned<NativeType>())
        1803               0 :             return NativeType(js_DoubleToECMAUint32(d));
        1804               0 :         return NativeType(js_DoubleToECMAInt32(d));
        1805                 :     }
        1806                 :
        1807                 :     static NativeType
        1808           36270 :     nativeFromValue(JSContext *cx, const Value &v)
        1809                 :     {
        1810           36270 :         if (v.isInt32())
        1811             108 :             return NativeType(v.toInt32());
        1812                 :
        1813           36162 :         if (v.isDouble())
        1814              72 :             return nativeFromDouble(v.toDouble());
        1815                 :
        1816                 :         /*
        1817                 :          * The condition guarantees that holes and undefined values
        1818                 :          * are treated identically.
        1819                 :          */
        1820           36090 :         if (v.isPrimitive() && !v.isMagic() && !v.isUndefined()) {
        1821                 :             double dval;
        1822               0 :             JS_ALWAYS_TRUE(ToNumber(cx, v, &dval));
        1823               0 :             return nativeFromDouble(dval);
        1824                 :         }
        1825                 :
        1826                 :         return ArrayTypeIsFloatingPoint()
        1827                 :                ? NativeType(js_NaN)
        1828           36090 :                : NativeType(int32_t(0));
        1829                 :     }
        1830                 :
        1831                 :     static bool
        1832             360 :     copyFromArray(JSContext *cx, JSObject *thisTypedArrayObj,
        1833                 :              JSObject *ar, uint32_t len, uint32_t offset = 0)
        1834                 :     {
        1835             360 :         thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
        1836             360 :         JS_ASSERT(thisTypedArrayObj);
        1837                 :
        1838             360 :         JS_ASSERT(offset <= getLength(thisTypedArrayObj));
        1839             360 :         JS_ASSERT(len <= getLength(thisTypedArrayObj) - offset);
        1840             360 :         NativeType *dest = static_cast<NativeType*>(getDataOffset(thisTypedArrayObj)) + offset;
        1841                 :
        1842             360 :         if (ar->isDenseArray() && ar->getDenseArrayInitializedLength() >= len) {
        1843             233 :             JS_ASSERT(ar->getArrayLength() == len);
        1844                 :
        1845             233 :             const Value *src = ar->getDenseArrayElements();
        1846                 :
        1847                 :             /*
        1848                 :              * It is valid to skip the hole check here because nativeFromValue
        1849                 :              * treats a hole as undefined.
        1850                 :              */
        1851             483 :             for (unsigned i = 0; i < len; ++i)
        1852             250 :                 *dest++ = nativeFromValue(cx, *src++);
        1853                 :         } else {
        1854                 :             Value v;
        1855                 :
        1856           36147 :             for (unsigned i = 0; i < len; ++i) {
        1857           36020 :                 if (!ar->getElement(cx, i, &v))
        1858               0 :                     return false;
        1859           36020 :                 *dest++ = nativeFromValue(cx, v);
        1860                 :             }
        1861                 :         }
        1862                 :
        1863             360 :         return true;
        1864                 :     }
        1865                 :
        1866                 :     static bool
        1867               9 :     copyFromTypedArray(JSContext *cx, JSObject *thisTypedArrayObj, JSObject *tarray, uint32_t offset)
        1868                 :     {
        1869               9 :         thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
        1870               9 :         JS_ASSERT(thisTypedArrayObj);
        1871                 :
        1872               9 :         JS_ASSERT(offset <= getLength(thisTypedArrayObj));
        1873               9 :         JS_ASSERT(getLength(tarray) <= getLength(thisTypedArrayObj) - offset);
        1874               9 :         if (getBuffer(tarray) == getBuffer(thisTypedArrayObj))
        1875               0 :             return copyFromWithOverlap(cx, thisTypedArrayObj, tarray, offset);
        1876                 :
        1877               9 :         NativeType *dest = static_cast<NativeType*>((void*)getDataOffset(thisTypedArrayObj)) + offset;
        1878                 :
        1879               9 :         if (getType(tarray) == getType(thisTypedArrayObj)) {
        1880               9 :             js_memcpy(dest, getDataOffset(tarray), getByteLength(tarray));
        1881               9 :             return true;
        1882                 :         }
        1883                 :
        1884               0 :         unsigned srclen = getLength(tarray);
        1885               0 :         switch (getType(tarray)) {
        1886                 :           case TypedArray::TYPE_INT8: {
        1887               0 :             int8_t *src = static_cast<int8_t*>(getDataOffset(tarray));
        1888               0 :             for (unsigned i = 0; i < srclen; ++i)
        1889               0 :                 *dest++ = NativeType(*src++);
        1890               0 :             break;
        1891                 :           }
        1892                 :           case TypedArray::TYPE_UINT8:
        1893                 :           case TypedArray::TYPE_UINT8_CLAMPED: {
        1894               0 :             uint8_t *src = static_cast<uint8_t*>(getDataOffset(tarray));
        1895               0 :             for (unsigned i = 0; i < srclen; ++i)
        1896               0 :                 *dest++ = NativeType(*src++);
        1897               0 :             break;
        1898                 :           }
        1899                 :           case TypedArray::TYPE_INT16: {
        1900               0 :             int16_t *src = static_cast<int16_t*>(getDataOffset(tarray));
        1901               0 :             for (unsigned i = 0; i < srclen; ++i)
        1902               0 :                 *dest++ = NativeType(*src++);
        1903               0 :             break;
        1904                 :           }
        1905                 :           case TypedArray::TYPE_UINT16: {
        1906               0 :             uint16_t *src = static_cast<uint16_t*>(getDataOffset(tarray));
        1907               0 :             for (unsigned i = 0; i < srclen; ++i)
        1908               0 :                 *dest++ = NativeType(*src++);
        1909               0 :             break;
        1910                 :           }
        1911                 :           case TypedArray::TYPE_INT32: {
        1912               0 :             int32_t *src = static_cast<int32_t*>(getDataOffset(tarray));
        1913               0 :             for (unsigned i = 0; i < srclen; ++i)
        1914               0 :                 *dest++ = NativeType(*src++);
        1915               0 :             break;
        1916                 :           }
        1917                 :           case TypedArray::TYPE_UINT32: {
        1918               0 :             uint32_t *src = static_cast<uint32_t*>(getDataOffset(tarray));
        1919               0 :             for (unsigned i = 0; i < srclen; ++i)
        1920               0 :                 *dest++ = NativeType(*src++);
        1921               0 :             break;
        1922                 :           }
        1923                 :           case TypedArray::TYPE_FLOAT32: {
        1924               0 :             float *src = static_cast<float*>(getDataOffset(tarray));
        1925               0 :             for (unsigned i = 0; i < srclen; ++i)
        1926               0 :                 *dest++ = NativeType(*src++);
        1927               0 :             break;
        1928                 :           }
        1929                 :           case TypedArray::TYPE_FLOAT64: {
        1930               0 :             double *src = static_cast<double*>(getDataOffset(tarray));
        1931               0 :             for (unsigned i = 0; i < srclen; ++i)
        1932               0 :                 *dest++ = NativeType(*src++);
        1933               0 :             break;
        1934                 :           }
        1935                 :           default:
        1936               0 :             JS_NOT_REACHED("copyFrom with a TypedArray of unknown type");
        1937                 :             break;
        1938                 :         }
        1939                 :
        1940               0 :         return true;
        1941                 :     }
        1942                 :
        1943                 :     static bool
        1944               0 :     copyFromWithOverlap(JSContext *cx, JSObject *self, JSObject *tarray, uint32_t offset)
        1945                 :     {
        1946               0 :         JS_ASSERT(offset <= getLength(self));
        1947                 :
        1948               0 :         NativeType *dest = static_cast<NativeType*>(getDataOffset(self)) + offset;
        1949                 :
        1950               0 :         if (getType(tarray) == getType(self)) {
        1951               0 :             memmove(dest, getDataOffset(tarray), getByteLength(tarray));
        1952               0 :             return true;
        1953                 :         }
        1954                 :
        1955                 :         // We have to make a copy of the source array here, since
        1956                 :         // there's overlap, and we have to convert types.
        1957               0 :         void *srcbuf = cx->malloc_(getLength(tarray));
        1958               0 :         if (!srcbuf)
        1959               0 :             return false;
        1960               0 :         js_memcpy(srcbuf, getDataOffset(tarray), getByteLength(tarray));
        1961                 :
        1962               0 :         switch (getType(tarray)) {
        1963                 :           case TypedArray::TYPE_INT8: {
        1964               0 :             int8_t *src = (int8_t*) srcbuf;
        1965               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        1966               0 :                 *dest++ = NativeType(*src++);
        1967               0 :             break;
        1968                 :           }
        1969                 :           case TypedArray::TYPE_UINT8:
        1970                 :           case TypedArray::TYPE_UINT8_CLAMPED: {
        1971               0 :             uint8_t *src = (uint8_t*) srcbuf;
        1972               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        1973               0 :                 *dest++ = NativeType(*src++);
        1974               0 :             break;
        1975                 :           }
        1976                 :           case TypedArray::TYPE_INT16: {
        1977               0 :             int16_t *src = (int16_t*) srcbuf;
        1978               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        1979               0 :                 *dest++ = NativeType(*src++);
        1980               0 :             break;
        1981                 :           }
        1982                 :           case TypedArray::TYPE_UINT16: {
        1983               0 :             uint16_t *src = (uint16_t*) srcbuf;
        1984               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        1985               0 :                 *dest++ = NativeType(*src++);
        1986               0 :             break;
        1987                 :           }
        1988                 :           case TypedArray::TYPE_INT32: {
        1989               0 :             int32_t *src = (int32_t*) srcbuf;
        1990               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        1991               0 :                 *dest++ = NativeType(*src++);
        1992               0 :             break;
        1993                 :           }
        1994                 :           case TypedArray::TYPE_UINT32: {
        1995               0 :             uint32_t *src = (uint32_t*) srcbuf;
        1996               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        1997               0 :                 *dest++ = NativeType(*src++);
        1998               0 :             break;
        1999                 :           }
        2000                 :           case TypedArray::TYPE_FLOAT32: {
        2001               0 :             float *src = (float*) srcbuf;
        2002               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        2003               0 :                 *dest++ = NativeType(*src++);
        2004               0 :             break;
        2005                 :           }
        2006                 :           case TypedArray::TYPE_FLOAT64: {
        2007               0 :             double *src = (double*) srcbuf;
        2008               0 :             for (unsigned i = 0; i < getLength(tarray); ++i)
        2009               0 :                 *dest++ = NativeType(*src++);
        2010               0 :             break;
        2011                 :           }
        2012                 :           default:
        2013               0 :             JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type");
        2014                 :             break;
        2015                 :         }
        2016                 :
        2017               0 :         UnwantedForeground::free_(srcbuf);
        2018               0 :         return true;
        2019                 :     }
        2020                 :
        2021                 :     static void *
        2022            5697 :     offsetData(JSObject *obj, uint32_t offs) {
        2023            5697 :         return (void*)(((uint8_t*)getDataOffset(obj)) + offs);
        2024                 :     }
        2025                 :
        2026                 :     static JSObject *
        2027            4743 :     createBufferWithSizeAndCount(JSContext *cx, uint32_t count)
        2028                 :     {
        2029            4743 :         size_t size = sizeof(NativeType);
        2030            4743 :         if (size != 0 && count >= INT32_MAX / size) {
        2031               0 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
        2032                 :                                  JSMSG_NEED_DIET, "size and count");
        2033               0 :             return NULL;
        2034                 :         }
        2035                 :
        2036            4743 :         int32_t bytelen = size * count;
        2037            4743 :         return ArrayBuffer::create(cx, bytelen);
        2038                 :     }
        2039                 : };
        2040                 :
        2041                 : class Int8Array : public TypedArrayTemplate<int8_t> {
        2042                 :   public:
        2043                 :     enum { ACTUAL_TYPE = TYPE_INT8 };
        2044                 :     static const JSProtoKey key = JSProto_Int8Array;
        2045                 :     static JSFunctionSpec jsfuncs[];
        2046                 : };
        2047                 : class Uint8Array : public TypedArrayTemplate<uint8_t> {
        2048                 :   public:
        2049                 :     enum { ACTUAL_TYPE = TYPE_UINT8 };
        2050                 :     static const JSProtoKey key = JSProto_Uint8Array;
        2051                 :     static JSFunctionSpec jsfuncs[];
        2052                 : };
        2053                 : class Int16Array : public TypedArrayTemplate<int16_t> {
        2054                 :   public:
        2055                 :     enum { ACTUAL_TYPE = TYPE_INT16 };
        2056                 :     static const JSProtoKey key = JSProto_Int16Array;
        2057                 :     static JSFunctionSpec jsfuncs[];
        2058                 : };
        2059                 : class Uint16Array : public TypedArrayTemplate<uint16_t> {
        2060                 :   public:
        2061                 :     enum { ACTUAL_TYPE = TYPE_UINT16 };
        2062                 :     static const JSProtoKey key = JSProto_Uint16Array;
        2063                 :     static JSFunctionSpec jsfuncs[];
        2064                 : };
        2065                 : class Int32Array : public TypedArrayTemplate<int32_t> {
        2066                 :   public:
        2067                 :     enum { ACTUAL_TYPE = TYPE_INT32 };
        2068                 :     static const JSProtoKey key = JSProto_Int32Array;
        2069                 :     static JSFunctionSpec jsfuncs[];
        2070                 : };
        2071                 : class Uint32Array : public TypedArrayTemplate<uint32_t> {
        2072                 :   public:
        2073                 :     enum { ACTUAL_TYPE = TYPE_UINT32 };
        2074                 :     static const JSProtoKey key = JSProto_Uint32Array;
        2075                 :     static JSFunctionSpec jsfuncs[];
        2076                 : };
        2077                 : class Float32Array : public TypedArrayTemplate<float> {
        2078                 :   public:
        2079                 :     enum { ACTUAL_TYPE = TYPE_FLOAT32 };
        2080                 :     static const JSProtoKey key = JSProto_Float32Array;
        2081                 :     static JSFunctionSpec jsfuncs[];
        2082                 : };
        2083                 : class Float64Array : public TypedArrayTemplate<double> {
        2084                 :   public:
        2085                 :     enum { ACTUAL_TYPE = TYPE_FLOAT64 };
        2086                 :     static const JSProtoKey key = JSProto_Float64Array;
        2087                 :     static JSFunctionSpec jsfuncs[];
        2088                 : };
        2089                 : class Uint8ClampedArray : public TypedArrayTemplate<uint8_clamped> {
        2090                 :   public:
        2091                 :     enum { ACTUAL_TYPE = TYPE_UINT8_CLAMPED };
        2092                 :     static const JSProtoKey key = JSProto_Uint8ClampedArray;
        2093                 :     static JSFunctionSpec jsfuncs[];
        2094                 : };
        2095                 :
        2096                 : // this default implementation is only valid for integer types
        2097                 : // less than 32-bits in size.
        2098                 : template<typename NativeType>
        2099                 : void
        2100                 : TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
        2101                 : {
        2102                 :     JS_STATIC_ASSERT(sizeof(NativeType) < 4);
        2103                 :
        2104            7819 :     vp->setInt32(getIndex(tarray, index));
        2105            7819 : }
        2106                 :
        2107                 : // and we need to specialize for 32-bit integers and floats
        2108                 : template<>
        2109                 : void
        2110            1774 : TypedArrayTemplate<int32_t>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
        2111                 : {
        2112            1774 :     int32_t val = getIndex(tarray, index);
        2113            1774 :     vp->setInt32(val);
        2114            1774 : }
        2115                 :
        2116                 : template<>
        2117                 : void
        2118            1370 : TypedArrayTemplate<uint32_t>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
        2119                 : {
        2120            1370 :     uint32_t val = getIndex(tarray, index);
        2121            1370 :     vp->setNumber(val);
        2122            1370 : }
        2123                 :
        2124                 : template<>
        2125                 : void
        2126            6963 : TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
        2127                 : {
        2128            6963 :     float val = getIndex(tarray, index);
        2129            6963 :     double dval = val;
        2130                 :
        2131                 :     /*
        2132                 :      * Doubles in typed arrays could be typed-punned arrays of integers. This
        2133                 :      * could allow user code to break the engine-wide invariant that only
        2134                 :      * canonical nans are stored into jsvals, which means user code could
        2135                 :      * confuse the engine into interpreting a double-typed jsval as an
        2136                 :      * object-typed jsval.
        2137                 :      *
        2138                 :      * This could be removed for platforms/compilers known to convert a 32-bit
        2139                 :      * non-canonical nan to a 64-bit canonical nan.
        2140                 :      */
        2141            6963 :     if (JS_UNLIKELY(JSDOUBLE_IS_NaN(dval)))
        2142             433 :         dval = js_NaN;
        2143                 :
        2144            6963 :     vp->setDouble(dval);
        2145            6963 : }
        2146                 :
        2147                 : template<>
        2148                 : void
        2149            1539 : TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32_t index, Value *vp)
        2150                 : {
        2151            1539 :     double val = getIndex(tarray, index);
        2152                 :
        2153                 :     /*
        2154                 :      * Doubles in typed arrays could be typed-punned arrays of integers. This
        2155                 :      * could allow user code to break the engine-wide invariant that only
        2156                 :      * canonical nans are stored into jsvals, which means user code could
        2157                 :      * confuse the engine into interpreting a double-typed jsval as an
        2158                 :      * object-typed jsval.
        2159                 :      */
        2160            1539 :     if (JS_UNLIKELY(JSDOUBLE_IS_NaN(val)))
        2161             421 :         val = js_NaN;
        2162                 :
        2163            1539 :     vp->setDouble(val);
        2164            1539 : }
        2165                 :
        2166                 : /***
        2167                 :  *** JS impl
        2168                 :  ***/
        2169                 :
        2170                 : /*
        2171                 :  * ArrayBuffer (base)
        2172                 :  */
        2173                 :
        2174                 : Class ArrayBuffer::slowClass = {
        2175                 :     "ArrayBuffer",
        2176                 :     JSCLASS_HAS_PRIVATE |
        2177                 :     JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
        2178                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
        2179                 :     JS_PropertyStub,         /* addProperty */
        2180                 :     JS_PropertyStub,         /* delProperty */
        2181                 :     JS_PropertyStub,         /* getProperty */
        2182                 :     JS_StrictPropertyStub,   /* setProperty */
        2183                 :     JS_EnumerateStub,
        2184                 :     JS_ResolveStub,
        2185                 :     JS_ConvertStub
        2186                 : };
        2187                 :
        2188                 : Class js::ArrayBufferClass = {
        2189                 :     "ArrayBuffer",
        2190                 :     JSCLASS_HAS_PRIVATE |
        2191                 :     JSCLASS_IMPLEMENTS_BARRIERS |
        2192                 :     Class::NON_NATIVE |
        2193                 :     JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
        2194                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
        2195                 :     JS_PropertyStub,         /* addProperty */
        2196                 :     JS_PropertyStub,         /* delProperty */
        2197                 :     JS_PropertyStub,         /* getProperty */
        2198                 :     JS_StrictPropertyStub,   /* setProperty */
        2199                 :     JS_EnumerateStub,
        2200                 :     JS_ResolveStub,
        2201                 :     JS_ConvertStub,
        2202                 :     NULL,           /* finalize    */
        2203                 :     NULL,           /* checkAccess */
        2204                 :     NULL,           /* call        */
        2205                 :     NULL,           /* construct   */
        2206                 :     NULL,           /* hasInstance */
        2207                 :     ArrayBuffer::obj_trace,
        2208                 :     JS_NULL_CLASS_EXT,
        2209                 :     {
        2210                 :         ArrayBuffer::obj_lookupGeneric,
        2211                 :         ArrayBuffer::obj_lookupProperty,
        2212                 :         ArrayBuffer::obj_lookupElement,
        2213                 :         ArrayBuffer::obj_lookupSpecial,
        2214                 :         ArrayBuffer::obj_defineGeneric,
        2215                 :         ArrayBuffer::obj_defineProperty,
        2216                 :         ArrayBuffer::obj_defineElement,
        2217                 :         ArrayBuffer::obj_defineSpecial,
        2218                 :         ArrayBuffer::obj_getGeneric,
        2219                 :         ArrayBuffer::obj_getProperty,
        2220                 :         ArrayBuffer::obj_getElement,
        2221                 :         ArrayBuffer::obj_getElementIfPresent,
        2222                 :         ArrayBuffer::obj_getSpecial,
        2223                 :         ArrayBuffer::obj_setGeneric,
        2224                 :         ArrayBuffer::obj_setProperty,
        2225                 :         ArrayBuffer::obj_setElement,
        2226                 :         ArrayBuffer::obj_setSpecial,
        2227                 :         ArrayBuffer::obj_getGenericAttributes,
        2228                 :         ArrayBuffer::obj_getPropertyAttributes,
        2229                 :         ArrayBuffer::obj_getElementAttributes,
        2230                 :         ArrayBuffer::obj_getSpecialAttributes,
        2231                 :         ArrayBuffer::obj_setGenericAttributes,
        2232                 :         ArrayBuffer::obj_setPropertyAttributes,
        2233                 :         ArrayBuffer::obj_setElementAttributes,
        2234                 :         ArrayBuffer::obj_setSpecialAttributes,
        2235                 :         ArrayBuffer::obj_deleteProperty,
        2236                 :         ArrayBuffer::obj_deleteElement,
        2237                 :         ArrayBuffer::obj_deleteSpecial,
        2238                 :         ArrayBuffer::obj_enumerate,
        2239                 :         ArrayBuffer::obj_typeOf,
        2240                 :         NULL,       /* thisObject      */
        2241                 :         NULL,       /* clear           */
        2242                 :     }
        2243                 : };
        2244                 :
        2245                 : JSPropertySpec ArrayBuffer::jsprops[] = {
        2246                 :     { "byteLength",
        2247                 :       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
        2248                 :       ArrayBuffer::prop_getByteLength, JS_StrictPropertyStub },
        2249                 :     {0,0,0,0,0}
        2250                 : };
        2251                 :
        2252                 : JSFunctionSpec ArrayBuffer::jsfuncs[] = {
        2253                 :     JS_FN("slice", ArrayBuffer::fun_slice, 2, JSFUN_GENERIC_NATIVE),
        2254                 :     JS_FS_END
        2255                 : };
        2256                 :
        2257                 : /*
        2258                 :  * shared TypedArray
        2259                 :  */
        2260                 :
        2261                 : JSPropertySpec TypedArray::jsprops[] = {
        2262                 :     { js_length_str,
        2263                 :       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
        2264                 :       TypedArray::prop_getLength, JS_StrictPropertyStub },
        2265                 :     { "byteLength",
        2266                 :       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
        2267                 :       TypedArray::prop_getByteLength, JS_StrictPropertyStub },
        2268                 :     { "byteOffset",
        2269                 :       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
        2270                 :       TypedArray::prop_getByteOffset, JS_StrictPropertyStub },
        2271                 :     { "buffer",
        2272                 :       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
        2273                 :       TypedArray::prop_getBuffer, JS_StrictPropertyStub },
        2274                 :     {0,0,0,0,0}
        2275                 : };
        2276                 :
        2277                 : /*
        2278                 :  * TypedArray boilerplate
        2279                 :  */
        2280                 :
        2281                 : #define IMPL_TYPED_ARRAY_STATICS(_typedArray)                                  \
        2282                 : JSFunctionSpec _typedArray::jsfuncs[] = {                                      \
        2283                 :     JS_FN("subarray", _typedArray::fun_subarray, 2, JSFUN_GENERIC_NATIVE),     \
        2284                 :     JS_FN("set", _typedArray::fun_set, 2, JSFUN_GENERIC_NATIVE),               \
        2285                 :     JS_FS_END                                                                  \
        2286                 : }
        2287                 :
        2288                 : #define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray)                               \
        2289                 : {                                                                              \
        2290                 :     #_typedArray,                                                              \
        2291                 :     JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
        2292                 :     JSCLASS_HAS_PRIVATE |                                                      \
        2293                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),                           \
        2294                 :     JS_PropertyStub,         /* addProperty */                                 \
        2295                 :     JS_PropertyStub,         /* delProperty */                                 \
        2296                 :     JS_PropertyStub,         /* getProperty */                                 \
        2297                 :     JS_StrictPropertyStub,   /* setProperty */                                 \
        2298                 :     JS_EnumerateStub,                                                          \
        2299                 :     JS_ResolveStub,                                                            \
        2300                 :     JS_ConvertStub                                                             \
        2301                 : }
        2302                 :
        2303                 : #define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray)                               \
        2304                 : {                                                                              \
        2305                 :     #_typedArray,                                                              \
        2306                 :     JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
        2307                 :     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |                        \
        2308                 :     JSCLASS_FOR_OF_ITERATION |                                                 \
        2309                 :     Class::NON_NATIVE,                                                         \
        2310                 :     JS_PropertyStub,         /* addProperty */                                 \
        2311                 :     JS_PropertyStub,         /* delProperty */                                 \
        2312                 :     JS_PropertyStub,         /* getProperty */                                 \
        2313                 :     JS_StrictPropertyStub,   /* setProperty */                                 \
        2314                 :     JS_EnumerateStub,                                                          \
        2315                 :     JS_ResolveStub,                                                            \
        2316                 :     JS_ConvertStub,                                                            \
        2317                 :     NULL,                    /* finalize    */                                 \
        2318                 :     NULL,                    /* checkAccess */                                 \
        2319                 :     NULL,                    /* call        */                                 \
        2320                 :     NULL,                    /* construct   */                                 \
        2321                 :     NULL,                    /* hasInstance */                                 \
        2322                 :     _typedArray::obj_trace,  /* trace       */                                 \
        2323                 :     {                                                                          \
        2324                 :         NULL,       /* equality    */                                          \
        2325                 :         NULL,       /* outerObject */                                          \
        2326                 :         NULL,       /* innerObject */                                          \
        2327                 :         JS_ElementIteratorStub,                                                \
        2328                 :         NULL,       /* unused      */                                          \
        2329                 :         false,      /* isWrappedNative */                                      \
        2330                 :     },                                                                         \
        2331                 :     {                                                                          \
        2332                 :         _typedArray::obj_lookupGeneric,                                        \
        2333                 :         _typedArray::obj_lookupProperty,                                       \
        2334                 :         _typedArray::obj_lookupElement,                                        \
        2335                 :         _typedArray::obj_lookupSpecial,                                        \
        2336                 :         _typedArray::obj_defineGeneric,                                        \
        2337                 :         _typedArray::obj_defineProperty,                                       \
        2338                 :         _typedArray::obj_defineElement,                                        \
        2339                 :         _typedArray::obj_defineSpecial,                                        \
        2340                 :         _typedArray::obj_getGeneric,                                           \
        2341                 :         _typedArray::obj_getProperty,                                          \
        2342                 :         _typedArray::obj_getElement,                                           \
        2343                 :         _typedArray::obj_getElementIfPresent,                                  \
        2344                 :         _typedArray::obj_getSpecial,                                           \
        2345                 :         _typedArray::obj_setGeneric,                                           \
        2346                 :         _typedArray::obj_setProperty,                                          \
        2347                 :         _typedArray::obj_setElement,                                           \
        2348                 :         _typedArray::obj_setSpecial,                                           \
        2349                 :         _typedArray::obj_getGenericAttributes,                                 \
        2350                 :         _typedArray::obj_getPropertyAttributes,                                \
        2351                 :         _typedArray::obj_getElementAttributes,                                 \
        2352                 :         _typedArray::obj_getSpecialAttributes,                                 \
        2353                 :         _typedArray::obj_setGenericAttributes,                                 \
        2354                 :         _typedArray::obj_setPropertyAttributes,                                \
        2355                 :         _typedArray::obj_setElementAttributes,                                 \
        2356                 :         _typedArray::obj_setSpecialAttributes,                                 \
        2357                 :         _typedArray::obj_deleteProperty,                                       \
        2358                 :         _typedArray::obj_deleteElement,                                        \
        2359                 :         _typedArray::obj_deleteSpecial,                                        \
        2360                 :         _typedArray::obj_enumerate,                                            \
        2361                 :         _typedArray::obj_typeOf,                                               \
        2362                 :         NULL,                /* thisObject  */                                 \
        2363                 :         NULL,                /* clear       */                                 \
        2364                 :     }                                                                          \
        2365                 : }
        2366                 :
        2367                 : template<class ArrayType>
        2368                 : static inline JSObject *
        2369            9423 : InitTypedArrayClass(JSContext *cx, GlobalObject *global)
        2370                 : {
        2371            9423 :     JSObject *proto = global->createBlankPrototype(cx, ArrayType::slowClass());
        2372            9423 :     if (!proto)
        2373               0 :         return NULL;
        2374                 :
        2375                 :     JSFunction *ctor =
        2376                 :         global->createConstructor(cx, ArrayType::class_constructor,
        2377            9423 :                                   cx->runtime->atomState.classAtoms[ArrayType::key], 3);
        2378            9423 :     if (!ctor)
        2379               0 :         return NULL;
        2380                 :
        2381            9423 :     if (!LinkConstructorAndPrototype(cx, ctor, proto))
        2382               0 :         return NULL;
        2383                 :
        2384            9423 :     if (!ctor->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom,
        2385                 :                               Int32Value(ArrayType::BYTES_PER_ELEMENT),
        2386                 :                               JS_PropertyStub, JS_StrictPropertyStub,
        2387                 :                               JSPROP_PERMANENT | JSPROP_READONLY) ||
        2388                 :         !proto->defineProperty(cx, cx->runtime->atomState.BYTES_PER_ELEMENTAtom,
        2389                 :                                Int32Value(ArrayType::BYTES_PER_ELEMENT),
        2390                 :                                JS_PropertyStub, JS_StrictPropertyStub,
        2391                 :                                JSPROP_PERMANENT | JSPROP_READONLY))
        2392                 :     {
        2393               0 :         return NULL;
        2394                 :     }
        2395                 :
        2396            9423 :     if (!DefinePropertiesAndBrand(cx, proto, ArrayType::jsprops, ArrayType::jsfuncs))
        2397               0 :         return NULL;
        2398                 :
        2399            9423 :     if (!DefineConstructorAndPrototype(cx, global, ArrayType::key, ctor, proto))
        2400               0 :         return NULL;
        2401                 :
        2402            9423 :     return proto;
        2403                 : }
        2404                 :
        2405                 : IMPL_TYPED_ARRAY_STATICS(Int8Array);
        2406                 : IMPL_TYPED_ARRAY_STATICS(Uint8Array);
        2407                 : IMPL_TYPED_ARRAY_STATICS(Int16Array);
        2408                 : IMPL_TYPED_ARRAY_STATICS(Uint16Array);
        2409                 : IMPL_TYPED_ARRAY_STATICS(Int32Array);
        2410                 : IMPL_TYPED_ARRAY_STATICS(Uint32Array);
        2411                 : IMPL_TYPED_ARRAY_STATICS(Float32Array);
        2412                 : IMPL_TYPED_ARRAY_STATICS(Float64Array);
        2413                 : IMPL_TYPED_ARRAY_STATICS(Uint8ClampedArray);
        2414                 :
        2415                 : Class TypedArray::fastClasses[TYPE_MAX] = {
        2416                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Int8Array),
        2417                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Uint8Array),
        2418                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Int16Array),
        2419                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Uint16Array),
        2420                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Int32Array),
        2421                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Uint32Array),
        2422                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Float32Array),
        2423                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Float64Array),
        2424                 :     IMPL_TYPED_ARRAY_FAST_CLASS(Uint8ClampedArray)
        2425                 : };
        2426                 :
        2427                 : Class TypedArray::slowClasses[TYPE_MAX] = {
        2428                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Int8Array),
        2429                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8Array),
        2430                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Int16Array),
        2431                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint16Array),
        2432                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Int32Array),
        2433                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint32Array),
        2434                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Float32Array),
        2435                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Float64Array),
        2436                 :     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8ClampedArray)
        2437                 : };
        2438                 :
        2439                 : static JSObject *
        2440            1047 : InitArrayBufferClass(JSContext *cx, GlobalObject *global)
        2441                 : {
        2442            1047 :     JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBuffer::slowClass);
        2443            1047 :     if (!arrayBufferProto)
        2444               0 :         return NULL;
        2445                 :
        2446                 :     JSFunction *ctor =
        2447                 :         global->createConstructor(cx, ArrayBuffer::class_constructor,
        2448            1047 :                                   CLASS_ATOM(cx, ArrayBuffer), 1);
        2449            1047 :     if (!ctor)
        2450               0 :         return NULL;
        2451                 :
        2452            1047 :     if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
        2453               0 :         return NULL;
        2454                 :
        2455            1047 :     if (!DefinePropertiesAndBrand(cx, arrayBufferProto, ArrayBuffer::jsprops, ArrayBuffer::jsfuncs))
        2456               0 :         return NULL;
        2457                 :
        2458            1047 :     if (!DefineConstructorAndPrototype(cx, global, JSProto_ArrayBuffer, ctor, arrayBufferProto))
        2459               0 :         return NULL;
        2460                 :
        2461            1047 :     return arrayBufferProto;
        2462                 : }
        2463                 :
        2464                 : JSObject *
        2465            2166 : js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
        2466                 : {
        2467            2166 :     JS_ASSERT(obj->isNative());
        2468                 :
        2469            2166 :     GlobalObject *global = &obj->asGlobal();
        2470                 :
        2471                 :     /* Idempotency required: we initialize several things, possibly lazily. */
        2472                 :     JSObject *stop;
        2473            2166 :     if (!js_GetClassObject(cx, global, JSProto_ArrayBuffer, &stop))
        2474               0 :         return NULL;
        2475            2166 :     if (stop)
        2476            1119 :         return stop;
        2477                 :
        2478            9423 :     if (!InitTypedArrayClass<Int8Array>(cx, global) ||
        2479            1047 :         !InitTypedArrayClass<Uint8Array>(cx, global) ||
        2480            1047 :         !InitTypedArrayClass<Int16Array>(cx, global) ||
        2481            1047 :         !InitTypedArrayClass<Uint16Array>(cx, global) ||
        2482            1047 :         !InitTypedArrayClass<Int32Array>(cx, global) ||
        2483            1047 :         !InitTypedArrayClass<Uint32Array>(cx, global) ||
        2484            1047 :         !InitTypedArrayClass<Float32Array>(cx, global) ||
        2485            1047 :         !InitTypedArrayClass<Float64Array>(cx, global) ||
        2486            1047 :         !InitTypedArrayClass<Uint8ClampedArray>(cx, global))
        2487                 :     {
        2488               0 :         return NULL;
        2489                 :     }
        2490                 :
        2491            1047 :     return InitArrayBufferClass(cx, global);
        2492                 : }
        2493                 :
        2494                 : JS_FRIEND_API(JSBool)
        2495             630 : js_IsArrayBuffer(JSObject *obj)
        2496                 : {
        2497             630 :     JS_ASSERT(obj);
        2498             630 :     obj = UnwrapObject(obj);
        2499             630 :     return obj->isArrayBuffer();
        2500                 : }
        2501                 :
        2502                 : JS_FRIEND_API(JSBool)
        2503               0 : JS_IsArrayBufferObject(JSObject *obj)
        2504                 : {
        2505               0 :     return js_IsArrayBuffer(obj);
        2506                 : }
        2507                 :
        2508                 : namespace js {
        2509                 :
        2510                 : bool
        2511        97737432 : IsFastTypedArrayClass(const Class *clasp)
        2512                 : {
        2513                 :     return &TypedArray::fastClasses[0] <= clasp &&
        2514        97737432 :            clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX];
        2515                 : }
        2516                 :
        2517                 : bool
        2518           45576 : IsSlowTypedArrayClass(const Class *clasp)
        2519                 : {
        2520                 :     return &TypedArray::slowClasses[0] <= clasp &&
        2521           45576 :            clasp < &TypedArray::slowClasses[TypedArray::TYPE_MAX];
        2522                 : }
        2523                 :
        2524        38867957 : bool IsFastOrSlowTypedArray(JSObject *obj)
        2525                 : {
        2526        38867957 :     Class *clasp = obj->getClass();
        2527        38867957 :     return IsFastTypedArrayClass(clasp) || IsSlowTypedArrayClass(clasp);
        2528                 : }
        2529                 :
        2530                 : } // namespace js
        2531                 :
        2532                 : uint32_t
        2533               0 : JS_GetArrayBufferByteLength(JSObject *obj)
        2534                 : {
        2535               0 :     obj = UnwrapObject(obj);
        2536               0 :     JS_ASSERT(obj->isArrayBuffer());
        2537               0 :     return obj->arrayBufferByteLength();
        2538                 : }
        2539                 :
        2540                 : uint8_t *
        2541               0 : JS_GetArrayBufferData(JSObject *obj)
        2542                 : {
        2543               0 :     obj = UnwrapObject(obj);
        2544               0 :     JS_ASSERT(obj->isArrayBuffer());
        2545               0 :     return obj->arrayBufferDataOffset();
        2546                 : }
        2547                 :
        2548                 : JS_FRIEND_API(JSBool)
        2549        58869475 : js_IsTypedArray(JSObject *obj)
        2550                 : {
        2551        58869475 :     JS_ASSERT(obj);
        2552        58869475 :     obj = UnwrapObject(obj);
        2553        58869475 :     Class *clasp = obj->getClass();
        2554        58869475 :     return IsFastTypedArrayClass(clasp);
        2555                 : }
        2556                 :
        2557                 : JS_FRIEND_API(JSObject *)
        2558               0 : js_CreateArrayBuffer(JSContext *cx, uint32_t nbytes)
        2559                 : {
        2560               0 :     return ArrayBuffer::create(cx, nbytes);
        2561                 : }
        2562                 :
        2563                 : JS_FRIEND_API(JSObject *)
        2564               0 : JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
        2565                 : {
        2566               0 :     return js_CreateArrayBuffer(cx, nbytes);
        2567                 : }
        2568                 :
        2569                 : static inline JSObject *
        2570              54 : TypedArrayConstruct(JSContext *cx, int atype, unsigned argc, Value *argv)
        2571                 : {
        2572              54 :     switch (atype) {
        2573                 :       case TypedArray::TYPE_INT8:
        2574               0 :         return Int8Array::create(cx, argc, argv);
        2575                 :
        2576                 :       case TypedArray::TYPE_UINT8:
        2577              54 :         return Uint8Array::create(cx, argc, argv);
        2578                 :
        2579                 :       case TypedArray::TYPE_INT16:
        2580               0 :         return Int16Array::create(cx, argc, argv);
        2581                 :
        2582                 :       case TypedArray::TYPE_UINT16:
        2583               0 :         return Uint16Array::create(cx, argc, argv);
        2584                 :
        2585                 :       case TypedArray::TYPE_INT32:
        2586               0 :         return Int32Array::create(cx, argc, argv);
        2587                 :
        2588                 :       case TypedArray::TYPE_UINT32:
        2589               0 :         return Uint32Array::create(cx, argc, argv);
        2590                 :
        2591                 :       case TypedArray::TYPE_FLOAT32:
        2592               0 :         return Float32Array::create(cx, argc, argv);
        2593                 :
        2594                 :       case TypedArray::TYPE_FLOAT64:
        2595               0 :         return Float64Array::create(cx, argc, argv);
        2596                 :
        2597                 :       case TypedArray::TYPE_UINT8_CLAMPED:
        2598               0 :         return Uint8ClampedArray::create(cx, argc, argv);
        2599                 :
        2600                 :       default:
        2601               0 :         JS_NOT_REACHED("shouldn't have gotten here");
        2602                 :         return NULL;
        2603                 :     }
        2604                 : }
        2605                 :
        2606                 : JS_FRIEND_API(JSObject *)
        2607              54 : js_CreateTypedArray(JSContext *cx, int atype, uint32_t nelements)
        2608                 : {
        2609              54 :     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
        2610                 :
        2611              54 :     Value nelems = Int32Value(nelements);
        2612              54 :     return TypedArrayConstruct(cx, atype, 1, &nelems);
        2613                 : }
        2614                 :
        2615                 : JS_FRIEND_API(JSObject *)
        2616               0 : js_CreateTypedArrayWithArray(JSContext *cx, int atype, JSObject *arrayArg)
        2617                 : {
        2618               0 :     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
        2619                 :
        2620               0 :     Value arrval = ObjectValue(*arrayArg);
        2621               0 :     return TypedArrayConstruct(cx, atype, 1, &arrval);
        2622                 : }
        2623                 :
        2624                 : JS_FRIEND_API(JSObject *)
        2625               0 : js_CreateTypedArrayWithBuffer(JSContext *cx, int atype, JSObject *bufArg,
        2626                 :                               int byteoffset, int length)
        2627                 : {
        2628               0 :     JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX);
        2629               0 :     JS_ASSERT(bufArg && js_IsArrayBuffer(bufArg));
        2630               0 :     JS_ASSERT_IF(byteoffset < 0, length < 0);
        2631                 :
        2632                 :     Value vals[4];
        2633                 :
        2634               0 :     int argc = 1;
        2635               0 :     vals[0].setObject(*bufArg);
        2636                 :
        2637               0 :     if (byteoffset >= 0) {
        2638               0 :         vals[argc].setInt32(byteoffset);
        2639               0 :         argc++;
        2640                 :     }
        2641                 :
        2642               0 :     if (length >= 0) {
        2643               0 :         vals[argc].setInt32(length);
        2644               0 :         argc++;
        2645                 :     }
        2646                 :
        2647               0 :     AutoArrayRooter tvr(cx, ArrayLength(vals), vals);
        2648               0 :     return TypedArrayConstruct(cx, atype, argc, &vals[0]);
        2649                 : }
        2650                 :
        2651                 : uint32_t
        2652               0 : JS_GetTypedArrayLength(JSObject *obj)
        2653                 : {
        2654               0 :     obj = UnwrapObject(obj);
        2655               0 :     JS_ASSERT(obj->isTypedArray());
        2656               0 :     return obj->getSlot(TypedArray::FIELD_LENGTH).toInt32();
        2657                 : }
        2658                 :
        2659                 : uint32_t
        2660               0 : JS_GetTypedArrayByteOffset(JSObject *obj)
        2661                 : {
        2662               0 :     obj = UnwrapObject(obj);
        2663               0 :     JS_ASSERT(obj->isTypedArray());
        2664               0 :     return obj->getSlot(TypedArray::FIELD_BYTEOFFSET).toInt32();
        2665                 : }
        2666                 :
        2667                 : uint32_t
        2668               0 : JS_GetTypedArrayByteLength(JSObject *obj)
        2669                 : {
        2670               0 :     obj = UnwrapObject(obj);
        2671               0 :     JS_ASSERT(obj->isTypedArray());
        2672               0 :     return obj->getSlot(TypedArray::FIELD_BYTELENGTH).toInt32();
        2673                 : }
        2674                 :
        2675                 : uint32_t
        2676               0 : JS_GetTypedArrayType(JSObject *obj)
        2677                 : {
        2678               0 :     obj = UnwrapObject(obj);
        2679               0 :     JS_ASSERT(obj->isTypedArray());
        2680               0 :     return obj->getSlot(TypedArray::FIELD_TYPE).toInt32();
        2681                 : }
        2682                 :
        2683                 : void *
        2684               0 : JS_GetTypedArrayData(JSObject *obj)
        2685                 : {
        2686               0 :     obj = UnwrapObject(obj);
        2687               0 :     JS_ASSERT(obj->isTypedArray());
        2688               0 :     return TypedArray::getDataOffset(obj);
        2689                 : }

Generated by: LCOV version 1.7