Bug 739380 - Start to implement the default [[GetP]] hook from the proto-climbing refactoring for the various element types. r=bhackett

--HG--
extra : rebase_source : 0270610c88d3315023a4cc582abbaf62dcf8a1cc
This commit is contained in:
Jeff Walden 2012-04-10 16:33:44 -07:00
parent 3518781dd9
commit e07abf10ae
3 changed files with 272 additions and 5 deletions

View File

@ -703,6 +703,14 @@ 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)
{
@ -711,6 +719,55 @@ NumberValue(double dbl)
return v;
}
static JS_ALWAYS_INLINE Value
NumberValue(size_t s)
{
Value v;
if (s > JSVAL_INT_MAX)
v.setDouble(s);
else
v.setInt32(int32_t(s));
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
ObjectOrNullValue(JSObject *obj)
{

View File

@ -11,6 +11,8 @@
#include "jsscope.h"
#include "jsobjinlines.h"
#include "js/TemplateLib.h"
#include "Debugger.h"
#include "ObjectImpl.h"
@ -288,6 +290,63 @@ 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<typename T>
bool
TypedElementsHeader<T>::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)
@ -345,7 +404,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->asObjectPtr()),
ObjectValue(*obj),
NULL, NULL, NULL));
return false;
}
@ -393,7 +452,7 @@ TypedElementsHeader<T>::defineElement(JSContext *cx, ObjectImpl *obj,
*succeeded = false;
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE,
JSDVG_IGNORE_STACK,
ObjectValue(*(JSObject*)obj), // XXX jwalden dodgy cast
ObjectValue(*obj),
NULL, NULL, NULL);
return false;
}
@ -411,6 +470,108 @@ ArrayBufferElementsHeader::defineElement(JSContext *cx, ObjectImpl *obj,
return DefineElement(cx, delegate, index, desc, shouldThrow, succeeded);
}
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<JSObject *>(obj)->isProxy()) { // XXX
MOZ_NOT_REACHED("NYI: proxy [[GetP]]");
return false;
}
ElementsHeader &header = obj->elementsHeader();
bool res;
PropDesc desc;
switch (header.kind()) {
case DenseElements:
res = header.asDenseElements().getOwnElement(cx, obj, index, &desc);
break;
case SparseElements:
res = header.asSparseElements().getOwnElement(cx, obj, index, &desc);
break;
case Uint8Elements:
res = header.asUint8Elements().getOwnElement(cx, obj, index, &desc);
break;
case Int8Elements:
res = header.asInt8Elements().getOwnElement(cx, obj, index, &desc);
break;
case Uint16Elements:
res = header.asUint16Elements().getOwnElement(cx, obj, index, &desc);
break;
case Int16Elements:
res = header.asInt16Elements().getOwnElement(cx, obj, index, &desc);
break;
case Uint32Elements:
res = header.asUint32Elements().getOwnElement(cx, obj, index, &desc);
break;
case Int32Elements:
res = header.asInt32Elements().getOwnElement(cx, obj, index, &desc);
break;
case Uint8ClampedElements:
res = header.asUint8ClampedElements().getOwnElement(cx, obj, index, &desc);
break;
case Float32Elements:
res = header.asFloat32Elements().getOwnElement(cx, obj, index, &desc);
break;
case Float64Elements:
res = header.asFloat64Elements().getOwnElement(cx, obj, index, &desc);
break;
case ArrayBufferElements:
res = header.asArrayBufferElements().getOwnElement(cx, obj, index, &desc);
break;
}
if (!res)
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 fval, thisv, and the 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::DefineElement(JSContext *cx, ObjectImpl *obj, uint32_t index, const PropDesc &desc,
bool shouldThrow, bool *succeeded)

View File

@ -68,8 +68,27 @@ struct PropDesc {
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(); }
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)
*
@ -94,8 +113,6 @@ 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_; }
@ -304,6 +321,8 @@ 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);
@ -328,6 +347,8 @@ 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);
@ -431,11 +452,20 @@ template<> inline const bool TypeIsUint8Clamped<uint8_clamped>() { return true;
template <typename T>
class TypedElementsHeader : public ElementsHeader
{
T getElement(uint32_t index) {
MOZ_ASSERT(index < length());
return reinterpret_cast<T *>(this + 1)[index];
}
public:
uint32_t byteLength() const {
uint32_t length() const {
MOZ_ASSERT(Uint8Elements <= kind());
MOZ_ASSERT(kind() <= Float64Elements);
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);
@ -521,6 +551,8 @@ class Uint8ClampedElementsHeader : public TypedElementsHeader<uint8_clamped>
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);
@ -686,6 +718,9 @@ 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
@ -772,6 +807,8 @@ class ObjectImpl : public gc::Cell
JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
friend inline Value ObjectValue(ObjectImpl &obj);
/* These functions are public, and they should remain public. */
public:
@ -1082,6 +1119,18 @@ 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;
}
/* 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);