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