LCOV - code coverage report
Current view: directory - js/src - jstypedarray.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1069 542 50.7 %
Date: 2012-06-02 Functions: 522 304 58.2 %

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

Generated by: LCOV version 1.7