diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 41162acd5e7..0184bd47b42 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -703,14 +703,6 @@ MagicValue(JSWhyMagic why) return v; } -static JS_ALWAYS_INLINE Value -NumberValue(float f) -{ - Value v; - v.setNumber(f); - return v; -} - static JS_ALWAYS_INLINE Value NumberValue(double dbl) { @@ -719,56 +711,6 @@ NumberValue(double dbl) return v; } -static JS_ALWAYS_INLINE Value -NumberValue(int8_t i) -{ - return Int32Value(i); -} - -static JS_ALWAYS_INLINE Value -NumberValue(uint8_t i) -{ - return Int32Value(i); -} - -static JS_ALWAYS_INLINE Value -NumberValue(int16_t i) -{ - return Int32Value(i); -} - -static JS_ALWAYS_INLINE Value -NumberValue(uint16_t i) -{ - return Int32Value(i); -} - -static JS_ALWAYS_INLINE Value -NumberValue(int32_t i) -{ - return Int32Value(i); -} - -static JS_ALWAYS_INLINE Value -NumberValue(uint32_t i) -{ - Value v; - v.setNumber(i); - return v; -} - -static JS_ALWAYS_INLINE Value -NumberValue(uint64_t i) -{ - MOZ_ASSERT(uint64_t(double(i)) == i, "value creation from uint64_t was lossy"); - Value v; - if (i > JSVAL_INT_MAX) - v.setDouble(i); - else - v.setInt32(int32_t(i)); - return v; -} - static JS_ALWAYS_INLINE Value ObjectOrNullValue(JSObject *obj) { diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 933272a028e..64dd1952dc6 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -11,8 +11,6 @@ #include "jsscope.h" #include "jsobjinlines.h" -#include "js/TemplateLib.h" - #include "Debugger.h" #include "ObjectImpl.h" @@ -290,63 +288,6 @@ js::ObjectImpl::markChildren(JSTracer *trc) MarkObjectSlots(trc, obj, 0, obj->slotSpan()); } -bool -DenseElementsHeader::getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - uint32_t len = initializedLength(); - if (index >= len) { - *desc = PropDesc::undefined(); - return true; - } - - HeapSlot &slot = obj->elements[index]; - if (slot.isMagic(JS_ARRAY_HOLE)) { - *desc = PropDesc::undefined(); - return true; - } - - *desc = PropDesc(slot, PropDesc::Writable, PropDesc::Enumerable, PropDesc::Configurable); - return true; -} - -bool -SparseElementsHeader::getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - MOZ_NOT_REACHED("NYI"); - return false; -} - -template -bool -TypedElementsHeader::getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, - PropDesc *desc) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - if (index >= length()) { - *desc = PropDesc::undefined(); - return true; - } - - *desc = PropDesc(NumberValue(getElement(index)), PropDesc::Writable, - PropDesc::Enumerable, PropDesc::Configurable); - return false; -} - -bool -ArrayBufferElementsHeader::getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, - PropDesc *desc) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - MOZ_NOT_REACHED("NYI"); - return false; -} - bool SparseElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded) @@ -404,7 +345,7 @@ DenseElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj, uint32_t inde return true; MOZ_ALWAYS_FALSE(js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE, JSDVG_IGNORE_STACK, - ObjectValue(*obj), + ObjectValue(*obj->asObjectPtr()), NULL, NULL, NULL)); return false; } @@ -452,7 +393,7 @@ TypedElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj, *succeeded = false; js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE, JSDVG_IGNORE_STACK, - ObjectValue(*obj), + ObjectValue(*(JSObject*)obj), // XXX jwalden dodgy cast NULL, NULL, NULL); return false; } @@ -470,133 +411,6 @@ ArrayBufferElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj, return DefineElement(cx, delegate, index, desc, shouldThrow, succeeded); } -bool -js::GetOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc) -{ - ElementsHeader &header = obj->elementsHeader(); - switch (header.kind()) { - case DenseElements: - return header.asDenseElements().getOwnElement(cx, obj, index, desc); - case SparseElements: - return header.asSparseElements().getOwnElement(cx, obj, index, desc); - case Uint8Elements: - return header.asUint8Elements().getOwnElement(cx, obj, index, desc); - case Int8Elements: - return header.asInt8Elements().getOwnElement(cx, obj, index, desc); - case Uint16Elements: - return header.asUint16Elements().getOwnElement(cx, obj, index, desc); - case Int16Elements: - return header.asInt16Elements().getOwnElement(cx, obj, index, desc); - case Uint32Elements: - return header.asUint32Elements().getOwnElement(cx, obj, index, desc); - case Int32Elements: - return header.asInt32Elements().getOwnElement(cx, obj, index, desc); - case Uint8ClampedElements: - return header.asUint8ClampedElements().getOwnElement(cx, obj, index, desc); - case Float32Elements: - return header.asFloat32Elements().getOwnElement(cx, obj, index, desc); - case Float64Elements: - return header.asFloat64Elements().getOwnElement(cx, obj, index, desc); - case ArrayBufferElements: - return header.asArrayBufferElements().getOwnElement(cx, obj, index, desc); - } - - MOZ_NOT_REACHED("bad elements kind!"); - return false; -} - -bool -js::GetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, - Value *vp) -{ - NEW_OBJECT_REPRESENTATION_ONLY(); - - do { - MOZ_ASSERT(obj); - - if (static_cast(obj)->isProxy()) { // XXX - MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); - return false; - } - - PropDesc desc; - if (!GetOwnElement(cx, obj, index, &desc)) - return false; - - /* No property? Recur or bottom out. */ - if (desc.isUndefined()) { - obj = obj->getProto(); - if (obj) - continue; - - vp->setUndefined(); - return true; - } - - /* If it's a data property, return the value. */ - if (desc.isDataDescriptor()) { - *vp = desc.value(); - return true; - } - - /* If it's an accessor property, call its [[Get]] with the receiver. */ - if (desc.isAccessorDescriptor()) { - Value get = desc.getterValue(); - if (get.isUndefined()) { - vp->setUndefined(); - return true; - } - - InvokeArgsGuard args; - if (!cx->stack.pushInvokeArgs(cx, 0, &args)) - return false; - - /* Push get, receiver, and no args. */ - args.calleev() = get; - args.thisv() = ObjectValue(*receiver); - - bool ok = Invoke(cx, args); - *vp = args.rval(); - return ok; - } - - /* Otherwise it's a PropertyOp-based property. XXX handle this! */ - MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); - return false; - } while (false); -} - -bool -js::HasElement(JSContext *cx, ObjectImpl *obj, uint32_t index, bool *found) -{ - NEW_OBJECT_REPRESENTATION_ONLY(); - - do { - MOZ_ASSERT(obj); - - if (static_cast(obj)->isProxy()) { // XXX - MOZ_NOT_REACHED("NYI: proxy [[HasProperty]]"); - return false; - } - - PropDesc prop; - if (!GetOwnElement(cx, obj, index, &prop)) - return false; - - if (!prop.isUndefined()) { - *found = true; - return true; - } - - obj = obj->getProto(); - if (obj) - continue; - - *found = false; - return true; - } while (false); -} - bool js::DefineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded) @@ -647,144 +461,3 @@ js::DefineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc MOZ_NOT_REACHED("bad elements kind!"); return false; } - -bool -SparseElementsHeader::setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, - uint32_t index, const Value &v, bool *succeeded) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - MOZ_NOT_REACHED("NYI"); - return false; -} - -bool -DenseElementsHeader::setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, - uint32_t index, const Value &v, bool *succeeded) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - MOZ_NOT_REACHED("NYI"); - return false; -} - -template -bool -TypedElementsHeader::setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, - uint32_t index, const Value &v, bool *succeeded) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - uint32_t len = length(); - if (index >= len) { - /* - * Silent ignore is better than an exception here, because at some - * point we may want to support other properties on these objects. - */ - *succeeded = true; - return true; - } - - /* Convert the value being set to the element type. */ - double d; - if (v.isNumber()) { - d = v.toNumber(); - } else if (v.isNull()) { - d = 0.0; - } else if (v.isPrimitive()) { - if (v.isString()) { - if (!ToNumber(cx, v, &d)) - return false; - } else if (v.isUndefined()) { - d = js_NaN; - } else { - d = double(v.toBoolean()); - } - } else { - // non-primitive assignments become NaN or 0 (for float/int arrays) - d = js_NaN; - } - - assign(index, d); - *succeeded = true; - return true; -} - -bool -ArrayBufferElementsHeader::setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, - uint32_t index, const Value &v, bool *succeeded) -{ - MOZ_ASSERT(this == &obj->elementsHeader()); - - JSObject *delegate = ArrayBufferDelegate(cx, obj); - if (!delegate) - return false; - return SetElement(cx, obj, receiver, index, v, succeeded); -} - -bool -js::SetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, - const Value &v, bool *succeeded) -{ - NEW_OBJECT_REPRESENTATION_ONLY(); - - do { - MOZ_ASSERT(obj); - - if (static_cast(obj)->isProxy()) { // XXX - MOZ_NOT_REACHED("NYI: proxy [[SetP]]"); - return false; - } - - PropDesc ownDesc; - if (!GetOwnElement(cx, obj, index, &ownDesc)) - return false; - - if (!ownDesc.isUndefined()) { - if (ownDesc.isDataDescriptor()) { - if (!ownDesc.writable()) { - *succeeded = false; - return true; - } - - if (receiver == obj) { - PropDesc updateDesc = PropDesc::valueOnly(v); - return DefineElement(cx, receiver, index, updateDesc, false, succeeded); - } - - PropDesc newDesc; - return DefineElement(cx, receiver, index, newDesc, false, succeeded); - } - - if (ownDesc.isAccessorDescriptor()) { - Value setter = ownDesc.setterValue(); - if (setter.isUndefined()) { - *succeeded = false; - return true; - } - - InvokeArgsGuard args; - if (!cx->stack.pushInvokeArgs(cx, 1, &args)) - return false; - - /* Push set, receiver, and v as the sole argument. */ - args.calleev() = setter; - args.thisv() = ObjectValue(*receiver); - args[0] = v; - - *succeeded = true; - return Invoke(cx, args); - } - - MOZ_NOT_REACHED("NYI: setting PropertyOp-based property"); - return false; - } - - obj = obj->getProto(); - if (obj) - continue; - - PropDesc newDesc(v, PropDesc::Writable, PropDesc::Enumerable, PropDesc::Configurable); - return DefineElement(cx, receiver, index, newDesc, false, succeeded); - } while (false); -} diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index c69f50f37cb..d29190b3897 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -16,7 +16,6 @@ #include "jsval.h" #include "gc/Barrier.h" -#include "vm/NumericConversions.h" namespace js { @@ -65,43 +64,12 @@ struct PropDesc { /* Or maybe this represents a property's absence, and it's undefined. */ bool isUndefined_ : 1; - PropDesc(const Value &v) - : pd_(UndefinedValue()), - value_(v), - get_(UndefinedValue()), set_(UndefinedValue()), - attrs(0), - hasGet_(false), hasSet_(false), - hasValue_(true), hasWritable_(false), hasEnumerable_(false), hasConfigurable_(false), - isUndefined_(false) - { - } - public: friend class AutoPropDescArrayRooter; friend void JS::AutoGCRooter::trace(JSTracer *trc); - enum Enumerability { Enumerable = true, NonEnumerable = false }; - enum Configurability { Configurable = true, NonConfigurable = false }; - enum Writability { Writable = true, NonWritable = false }; - PropDesc(); - static PropDesc undefined() { return PropDesc(); } - static PropDesc valueOnly(const Value &v) { return PropDesc(v); } - - PropDesc(const Value &v, Writability writable, - Enumerability enumerable, Configurability configurable) - : pd_(UndefinedValue()), - value_(v), - get_(UndefinedValue()), set_(UndefinedValue()), - attrs((writable ? 0 : JSPROP_READONLY) | - (enumerable ? JSPROP_ENUMERATE : 0) | - (configurable ? 0 : JSPROP_PERMANENT)), - hasGet_(false), hasSet_(false), - hasValue_(true), hasWritable_(true), hasEnumerable_(true), hasConfigurable_(true), - isUndefined_(false) - {} - /* * 8.10.5 ToPropertyDescriptor(Obj) * @@ -126,6 +94,8 @@ struct PropDesc { void initFromPropertyDescriptor(const PropertyDescriptor &desc); bool makeObject(JSContext *cx); + void setUndefined() { isUndefined_ = true; } + bool isUndefined() const { return isUndefined_; } bool hasGet() const { MOZ_ASSERT(!isUndefined()); return hasGet_; } @@ -237,16 +207,11 @@ class Int32ElementsHeader; class Uint8ClampedElementsHeader; class Float32ElementsHeader; class Float64ElementsHeader; -class Uint8ClampedElementsHeader; class ArrayBufferElementsHeader; enum ElementsKind { DenseElements, SparseElements, - - ArrayBufferElements, - - /* These typed element types must remain contiguous. */ Uint8Elements, Int8Elements, Uint16Elements, @@ -255,14 +220,15 @@ enum ElementsKind { Int32Elements, Uint8ClampedElements, Float32Elements, - Float64Elements + Float64Elements, + ArrayBufferElements }; class ElementsHeader { protected: uint32_t type; - uint32_t length; /* Array length, ArrayBuffer length, typed array length */ + uint32_t length; /* Array length, byte length of ArrayBuffer */ union { class { @@ -289,7 +255,6 @@ class ElementsHeader inline bool isDenseElements() const { return kind() == DenseElements; } inline bool isSparseElements() const { return kind() == SparseElements; } - inline bool isArrayBufferElements() const { return kind() == ArrayBufferElements; } inline bool isUint8Elements() const { return kind() == Uint8Elements; } inline bool isInt8Elements() const { return kind() == Int8Elements; } inline bool isUint16Elements() const { return kind() == Uint16Elements; } @@ -299,10 +264,10 @@ class ElementsHeader inline bool isUint8ClampedElements() const { return kind() == Uint8ClampedElements; } inline bool isFloat32Elements() const { return kind() == Float32Elements; } inline bool isFloat64Elements() const { return kind() == Float64Elements; } + inline bool isArrayBufferElements() const { return kind() == ArrayBufferElements; } inline DenseElementsHeader & asDenseElements(); inline SparseElementsHeader & asSparseElements(); - inline ArrayBufferElementsHeader & asArrayBufferElements(); inline Uint8ElementsHeader & asUint8Elements(); inline Int8ElementsHeader & asInt8Elements(); inline Uint16ElementsHeader & asUint16Elements(); @@ -312,6 +277,7 @@ class ElementsHeader inline Uint8ClampedElementsHeader & asUint8ClampedElements(); inline Float32ElementsHeader & asFloat32Elements(); inline Float64ElementsHeader & asFloat64Elements(); + inline ArrayBufferElementsHeader & asArrayBufferElements(); static ElementsHeader * fromElements(HeapSlot *elems) { return reinterpret_cast(uintptr_t(elems) - sizeof(ElementsHeader)); @@ -338,14 +304,9 @@ class DenseElementsHeader : public ElementsHeader return ElementsHeader::length; } - bool getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc); - bool defineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded); - bool setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, - const Value &v, bool *succeeded); - private: inline bool isDenseElements() const MOZ_DELETE; inline DenseElementsHeader & asDenseElements() MOZ_DELETE; @@ -367,14 +328,9 @@ class SparseElementsHeader : public ElementsHeader return ElementsHeader::length; } - bool getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc); - bool defineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded); - bool setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, - const Value &v, bool *succeeded); - private: inline bool isSparseElements() const MOZ_DELETE; inline SparseElementsHeader & asSparseElements() MOZ_DELETE; @@ -475,107 +431,19 @@ template<> inline const bool TypeIsUint8Clamped() { return true; template class TypedElementsHeader : public ElementsHeader { - T getElement(uint32_t index) { - MOZ_ASSERT(index < length()); - return reinterpret_cast(this + 1)[index]; - } - - inline void assign(uint32_t index, double d); - - void setElement(uint32_t index, T value) { - MOZ_ASSERT(index < length()); - reinterpret_cast(this + 1)[index] = value; - } - public: - uint32_t length() const { - MOZ_ASSERT(Uint8Elements <= kind()); - MOZ_ASSERT(kind() <= Float64Elements); + uint32_t byteLength() const { return ElementsHeader::length; } - bool getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc); - bool defineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded); - bool setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, - const Value &v, bool *succeeded); - private: TypedElementsHeader(const TypedElementsHeader &other) MOZ_DELETE; void operator=(const TypedElementsHeader &other) MOZ_DELETE; }; -template inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - MOZ_NOT_REACHED("didn't specialize for this element type"); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - double i = ToInteger(d); - uint8_t u = (i <= 0) - ? 0 - : (i >= 255) - ? 255 - : uint8_t(i); - setElement(index, uint8_clamped(u)); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - setElement(index, uint8_t(ToUint32(d))); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - /* FIXME: Casting out-of-range signed integers has undefined behavior! */ - setElement(index, int8_t(ToInt32(d))); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - setElement(index, uint16_t(ToUint32(d))); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - /* FIXME: Casting out-of-range signed integers has undefined behavior! */ - setElement(index, int16_t(ToInt32(d))); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - setElement(index, ToUint32(d)); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - /* FIXME: Casting out-of-range signed integers has undefined behavior! */ - setElement(index, int32_t(ToInt32(d))); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - setElement(index, float(d)); -} - -template<> inline void -TypedElementsHeader::assign(uint32_t index, double d) -{ - setElement(index, d); -} - class Uint8ElementsHeader : public TypedElementsHeader { private: @@ -653,14 +521,9 @@ class Uint8ClampedElementsHeader : public TypedElementsHeader class ArrayBufferElementsHeader : public ElementsHeader { public: - bool getOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc); - bool defineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded); - bool setElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, - const Value &v, bool *succeeded); - private: inline bool isArrayBufferElements() const MOZ_DELETE; inline ArrayBufferElementsHeader & asArrayBufferElements() MOZ_DELETE; @@ -823,9 +686,6 @@ struct Shape; class NewObjectCache; -inline Value -ObjectValue(ObjectImpl &obj); - /* * ObjectImpl specifies the internal implementation of an object. (In contrast * JSObject specifies an "external" interface, at the conceptual level of that @@ -912,8 +772,6 @@ class ObjectImpl : public gc::Cell JSObject * asObjectPtr() { return reinterpret_cast(this); } - friend inline Value ObjectValue(ObjectImpl &obj); - /* These functions are public, and they should remain public. */ public: @@ -1224,33 +1082,10 @@ class ObjectImpl : public gc::Cell static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); } }; -inline Value -ObjectValue(ObjectImpl &obj) -{ - Value v; - v.setObject(*obj.asObjectPtr()); - return v; -} - -bool -GetOwnElement(JSContext *cx, ObjectImpl *obj, uint32_t index, PropDesc *desc); - -/* Proposed default [[GetP]](Receiver, P) method. */ -extern bool -GetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, Value *vp); - extern bool DefineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc, bool shouldThrow, bool *succeeded); -/* Proposed default [[SetP]](Receiver, P, V) method. */ -extern bool -SetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, const Value &v, - bool *succeeded); - -extern bool -HasElement(JSContext *cx, ObjectImpl *obj, uint32_t index, bool *found); - } /* namespace js */ #endif /* ObjectImpl_h__ */