Bug 725907 - for-of improvements, part 1: minor C++ refactoring, rename Iterator to PropertyIteratorObject. r=Waldo.

--HG--
extra : rebase_source : 22a88c4169eba37b61a96dd1ff8507b82765b53e
This commit is contained in:
Jason Orendorff 2012-07-03 16:34:40 -05:00
Родитель b8e78daacd
Коммит af800ae65c
11 изменённых файлов: 161 добавлений и 118 удалений

Просмотреть файл

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef Iterator_inl_h_
#define Iterator_inl_h_
#include "jsiter.h"
#include "jsobjinlines.h"
inline bool
JSObject::isPropertyIterator() const
{
return hasClass(&js::PropertyIteratorObject::class_);
}
inline js::PropertyIteratorObject &
JSObject::asPropertyIterator()
{
JS_ASSERT(isPropertyIterator());
return *static_cast<js::PropertyIteratorObject *>(this);
}
js::NativeIterator *
js::PropertyIteratorObject::getNativeIterator() const
{
JS_ASSERT(isPropertyIterator());
return static_cast<js::NativeIterator *>(getPrivate());
}
inline void
js::PropertyIteratorObject::setNativeIterator(js::NativeIterator *ni)
{
setPrivate(ni);
}
#endif // Iterator_inl_h_

Просмотреть файл

@ -36,8 +36,8 @@
* MarkString, etc. These functions check if an object is in the compartment
* currently being GCed. If it is, they call PushMarkStack. Roots are pushed
* this way as well as pointers traversed inside trace hooks (for things like
* IteratorClass). It it always valid to call a MarkX function instead of
* PushMarkStack, although it may be slower.
* PropertyIteratorObjects). It is always valid to call a MarkX function
* instead of PushMarkStack, although it may be slower.
*
* The MarkX functions also handle non-GC object traversal. In this case, they
* call a callback for each object visited. This is a recursive process; the

Просмотреть файл

@ -1868,7 +1868,7 @@ static JSStdName standard_class_names[] = {
#endif
#if JS_HAS_GENERATORS
{js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(Iterator)},
{js_InitIteratorClasses, EAGER_CLASS_ATOM(Iterator), &PropertyIteratorObject::class_},
#endif
/* Typed Arrays */

Просмотреть файл

@ -189,7 +189,7 @@ class NativeIterCache
static const size_t SIZE = size_t(1) << 8;
/* Cached native iterators. */
JSObject *data[SIZE];
PropertyIteratorObject *data[SIZE];
static size_t getIndex(uint32_t key) {
return size_t(key) % SIZE;
@ -197,7 +197,7 @@ class NativeIterCache
public:
/* Native iterator most recently started. */
JSObject *last;
PropertyIteratorObject *last;
NativeIterCache()
: last(NULL) {
@ -209,11 +209,11 @@ class NativeIterCache
PodArrayZero(data);
}
JSObject *get(uint32_t key) const {
PropertyIteratorObject *get(uint32_t key) const {
return data[getIndex(key)];
}
void set(uint32_t key, JSObject *iterobj) {
void set(uint32_t key, PropertyIteratorObject *iterobj) {
data[getIndex(key)] = iterobj;
}
};
@ -1256,7 +1256,7 @@ struct JSContext : js::ContextFriendFields
DSTOffsetCache dstOffsetCache;
/* List of currently active non-escaping enumerators (for-in). */
JSObject *enumerators;
js::PropertyIteratorObject *enumerators;
private:
/* Innermost-executing generator or null if no generator are executing. */

Просмотреть файл

@ -57,6 +57,7 @@
#include "jsscriptinlines.h"
#include "jstypedarrayinlines.h"
#include "builtin/Iterator-inl.h"
#include "vm/Stack-inl.h"
#include "vm/String-inl.h"
@ -1001,8 +1002,8 @@ JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH);
static inline bool
IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval)
{
if (iterobj->isIterator()) {
NativeIterator *ni = iterobj->getNativeIterator();
if (iterobj->isPropertyIterator()) {
NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
if (ni->isKeyIter()) {
*cond = (ni->props_cursor < ni->props_end);
return true;
@ -1018,8 +1019,8 @@ IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval)
static inline bool
IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
{
if (iterobj->isIterator()) {
NativeIterator *ni = iterobj->getNativeIterator();
if (iterobj->isPropertyIterator()) {
NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
if (ni->isKeyIter()) {
JS_ASSERT(ni->props_cursor < ni->props_end);
rval->setString(*ni->current());

Просмотреть файл

@ -43,6 +43,7 @@
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "builtin/Iterator-inl.h"
#include "vm/MethodGuard-inl.h"
#include "vm/Stack-inl.h"
#include "vm/String-inl.h"
@ -51,36 +52,8 @@ using namespace mozilla;
using namespace js;
using namespace js::gc;
static void iterator_finalize(FreeOp *fop, JSObject *obj);
static void iterator_trace(JSTracer *trc, JSObject *obj);
static JSObject *iterator_iterator(JSContext *cx, HandleObject obj, JSBool keysonly);
Class js::IteratorClass = {
"Iterator",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator),
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
iterator_finalize,
NULL, /* checkAccess */
NULL, /* call */
NULL, /* construct */
NULL, /* hasInstance */
iterator_trace,
{
NULL, /* equality */
NULL, /* outerObject */
NULL, /* innerObject */
iterator_iterator,
NULL /* unused */
}
};
Class js::ElementIteratorClass = {
"ElementIterator",
JSCLASS_HAS_RESERVED_SLOTS(ElementIteratorObject::NumSlots),
@ -117,27 +90,6 @@ NativeIterator::mark(JSTracer *trc)
MarkObject(trc, &obj, "obj");
}
static void
iterator_finalize(FreeOp *fop, JSObject *obj)
{
JS_ASSERT(obj->isIterator());
NativeIterator *ni = obj->getNativeIterator();
if (ni) {
obj->setPrivate(NULL);
fop->free_(ni);
}
}
static void
iterator_trace(JSTracer *trc, JSObject *obj)
{
NativeIterator *ni = obj->getNativeIterator();
if (ni)
ni->mark(trc);
}
struct IdHashPolicy {
typedef jsid Lookup;
static HashNumber hash(jsid id) {
@ -479,8 +431,8 @@ Compare(T *a, T *b, size_t c)
return true;
}
static inline JSObject *
NewIteratorObject(JSContext *cx, unsigned flags)
static inline PropertyIteratorObject *
NewPropertyIteratorObject(JSContext *cx, unsigned flags)
{
if (flags & JSITER_ENUMERATE) {
RootedTypeObject type(cx);
@ -489,8 +441,8 @@ NewIteratorObject(JSContext *cx, unsigned flags)
return NULL;
RootedShape emptyEnumeratorShape(cx);
emptyEnumeratorShape = EmptyShape::getInitialShape(cx, &IteratorClass, NULL, NULL,
ITERATOR_FINALIZE_KIND);
emptyEnumeratorShape = EmptyShape::getInitialShape(cx, &PropertyIteratorObject::class_,
NULL, NULL, ITERATOR_FINALIZE_KIND);
if (!emptyEnumeratorShape)
return NULL;
@ -500,10 +452,10 @@ NewIteratorObject(JSContext *cx, unsigned flags)
return NULL;
JS_ASSERT(obj->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
return obj;
return &obj->asPropertyIterator();
}
return NewBuiltinClassInstance(cx, &IteratorClass);
return &NewBuiltinClassInstance(cx, &PropertyIteratorObject::class_)->asPropertyIterator();
}
NativeIterator *
@ -541,7 +493,7 @@ NativeIterator::init(JSObject *obj, unsigned flags, uint32_t slength, uint32_t k
}
static inline void
RegisterEnumerator(JSContext *cx, JSObject *iterobj, NativeIterator *ni)
RegisterEnumerator(JSContext *cx, PropertyIteratorObject *iterobj, NativeIterator *ni)
{
/* Register non-escaping native enumerators (for-in) with the current context. */
if (ni->flags & JSITER_ENUMERATE) {
@ -565,7 +517,7 @@ VectorToKeyIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVecto
types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
}
RootedObject iterobj(cx, NewIteratorObject(cx, flags));
Rooted<PropertyIteratorObject *> iterobj(cx, NewPropertyIteratorObject(cx, flags));
if (!iterobj)
return false;
@ -618,7 +570,7 @@ VectorToValueIterator(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVec
types::MarkTypeObjectFlags(cx, obj, types::OBJECT_FLAG_ITERATED);
}
JSObject *iterobj = NewIteratorObject(cx, flags);
PropertyIteratorObject *iterobj = NewPropertyIteratorObject(cx, flags);
if (!iterobj)
return false;
@ -687,7 +639,7 @@ GetIterator(JSContext *cx, HandleObject obj, unsigned flags, Value *vp)
* objects here, as they are not inserted into the cache and
* will result in a miss.
*/
JSObject *last = cx->runtime->nativeIterCache.last;
PropertyIteratorObject *last = cx->runtime->nativeIterCache.last;
JSObject *proto = obj->getProto();
if (last) {
NativeIterator *lastni = last->getNativeIterator();
@ -726,7 +678,7 @@ GetIterator(JSContext *cx, HandleObject obj, unsigned flags, Value *vp)
pobj = pobj->getProto();
} while (pobj);
JSObject *iterobj = cx->runtime->nativeIterCache.get(key);
PropertyIteratorObject *iterobj = cx->runtime->nativeIterCache.get(key);
if (iterobj) {
NativeIterator *ni = iterobj->getNativeIterator();
if (!(ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
@ -773,7 +725,7 @@ GetIterator(JSContext *cx, HandleObject obj, unsigned flags, Value *vp)
return false;
}
JSObject *iterobj = &vp->toObject();
PropertyIteratorObject *iterobj = &vp->toObject().asPropertyIterator();
/* Cache the iterator object if possible. */
if (shapes.length())
@ -829,8 +781,11 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp)
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject thisObj(cx);
if (!NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, thisObj.address()))
if (!NonGenericMethodGuard(cx, args, iterator_next, &PropertyIteratorObject::class_,
thisObj.address()))
{
return false;
}
if (!thisObj)
return true;
@ -852,6 +807,49 @@ static JSFunctionSpec iterator_methods[] = {
JS_FS_END
};
void
PropertyIteratorObject::trace(JSTracer *trc, JSObject *obj)
{
if (NativeIterator *ni = obj->asPropertyIterator().getNativeIterator())
ni->mark(trc);
}
void
PropertyIteratorObject::finalize(FreeOp *fop, JSObject *obj)
{
if (NativeIterator *ni = obj->asPropertyIterator().getNativeIterator()) {
obj->asPropertyIterator().setNativeIterator(NULL);
fop->free_(ni);
}
}
Class PropertyIteratorObject::class_ = {
"Iterator",
JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, /* addProperty */
JS_PropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
finalize,
NULL, /* checkAccess */
NULL, /* call */
NULL, /* construct */
NULL, /* hasInstance */
trace,
{
NULL, /* equality */
NULL, /* outerObject */
NULL, /* innerObject */
iterator_iterator,
NULL /* unused */
}
};
#if JS_HAS_GENERATORS
static JSBool
CloseGenerator(JSContext *cx, JSObject *genobj);
@ -905,9 +903,9 @@ js::CloseIterator(JSContext *cx, JSObject *obj)
{
cx->iterValue.setMagic(JS_NO_ITER_VALUE);
if (obj->isIterator()) {
if (obj->isPropertyIterator()) {
/* Remove enumerators from the active list, which is a stack. */
NativeIterator *ni = obj->getNativeIterator();
NativeIterator *ni = obj->asPropertyIterator().getNativeIterator();
if (ni->flags & JSITER_ENUMERATE) {
JS_ASSERT(cx->enumerators == obj);
@ -945,8 +943,8 @@ js::UnwindIteratorForException(JSContext *cx, JSObject *obj)
void
js::UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj)
{
if (obj->isIterator()) {
NativeIterator *ni = obj->getNativeIterator();
if (obj->isPropertyIterator()) {
NativeIterator *ni = obj->asPropertyIterator().getNativeIterator();
if (ni->flags & JSITER_ENUMERATE) {
JS_ASSERT(cx->enumerators == obj);
cx->enumerators = ni->next;
@ -975,7 +973,7 @@ template<typename StringPredicate>
static bool
SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate predicate)
{
JSObject *iterobj = cx->enumerators;
PropertyIteratorObject *iterobj = cx->enumerators;
while (iterobj) {
again:
NativeIterator *ni = iterobj->getNativeIterator();
@ -1172,9 +1170,9 @@ js_IteratorMore(JSContext *cx, HandleObject iterobj, Value *rval)
{
/* Fast path for native iterators */
NativeIterator *ni = NULL;
if (iterobj->isIterator()) {
if (iterobj->isPropertyIterator()) {
/* Key iterators are handled by fast-paths. */
ni = iterobj->getNativeIterator();
ni = iterobj->asPropertyIterator().getNativeIterator();
bool more = ni->props_cursor < ni->props_end;
if (ni->isKeyIter() || !more) {
rval->setBoolean(more);
@ -1248,12 +1246,12 @@ JSBool
js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
{
/* Fast path for native iterators */
if (iterobj->isIterator()) {
if (iterobj->isPropertyIterator()) {
/*
* Implement next directly as all the methods of the native iterator are
* read-only and permanent.
*/
NativeIterator *ni = iterobj->getNativeIterator();
NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
if (ni->isKeyIter()) {
JS_ASSERT(ni->props_cursor < ni->props_end);
*rval = StringValue(*ni->current());
@ -1548,7 +1546,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
gen->regs = cx->regs();
cx->enterGenerator(gen); /* OOM check above. */
JSObject *enumerators = cx->enumerators;
PropertyIteratorObject *enumerators = cx->enumerators;
cx->enumerators = gen->enumerators;
ok = RunScript(cx, fp->script(), fp);
@ -1703,7 +1701,8 @@ static JSFunctionSpec generator_methods[] = {
static bool
InitIteratorClass(JSContext *cx, Handle<GlobalObject*> global)
{
RootedObject iteratorProto(cx, global->createBlankPrototype(cx, &IteratorClass));
Rooted<JSObject*> iteratorProto(cx,
global->createBlankPrototype(cx, &PropertyIteratorObject::class_));
if (!iteratorProto)
return false;
@ -1713,7 +1712,7 @@ InitIteratorClass(JSContext *cx, Handle<GlobalObject*> global)
return false;
ni->init(NULL, 0 /* flags */, 0, 0);
iteratorProto->setNativeIterator(ni);
iteratorProto->asPropertyIterator().setNativeIterator(ni);
RootedFunction ctor(cx);
ctor = global->createConstructor(cx, Iterator, CLASS_NAME(cx, Iterator), 2);

Просмотреть файл

@ -28,16 +28,17 @@
namespace js {
struct NativeIterator {
struct NativeIterator
{
HeapPtrObject obj;
HeapPtr<JSFlatString> *props_array;
HeapPtr<JSFlatString> *props_cursor;
HeapPtr<JSFlatString> *props_end;
const Shape **shapes_array;
uint32_t shapes_length;
uint32_t shapes_key;
uint32_t flags;
JSObject *next; /* Forms cx->enumerators list, garbage otherwise. */
uint32_t shapes_length;
uint32_t shapes_key;
uint32_t flags;
PropertyIteratorObject *next; /* Forms cx->enumerators list, garbage otherwise. */
bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; }
@ -69,7 +70,21 @@ struct NativeIterator {
void mark(JSTracer *trc);
};
class ElementIteratorObject : public JSObject {
class PropertyIteratorObject : public JSObject
{
public:
static Class class_;
inline NativeIterator *getNativeIterator() const;
inline void setNativeIterator(js::NativeIterator *ni);
private:
static void trace(JSTracer *trc, JSObject *obj);
static void finalize(FreeOp *fop, JSObject *obj);
};
class ElementIteratorObject : public JSObject
{
public:
enum {
TargetSlot,
@ -229,7 +244,8 @@ Next(JSContext *cx, HandleObject iter, Value *vp)
* and the failure is allowed to propagate on cx, as in this example if DoStuff
* fails. In that case, ForOfIterator's destructor does all necessary cleanup.
*/
class ForOfIterator {
class ForOfIterator
{
private:
JSContext *cx;
RootedObject iterator;
@ -305,7 +321,7 @@ struct JSGenerator
js::HeapPtrObject obj;
JSGeneratorState state;
js::FrameRegs regs;
JSObject *enumerators;
js::PropertyIteratorObject *enumerators;
JSGenerator *prevGenerator;
js::StackFrame *fp;
js::HeapValue stackSnapshot[1];

Просмотреть файл

@ -209,7 +209,6 @@ extern Class DateClass;
extern Class ErrorClass;
extern Class ElementIteratorClass;
extern Class GeneratorClass;
extern Class IteratorClass;
extern Class JSONClass;
extern Class MathClass;
extern Class NumberClass;
@ -240,6 +239,7 @@ class NestedScopeObject;
class NewObjectCache;
class NormalArgumentsObject;
class NumberObject;
class PropertyIteratorObject;
class ScopeObject;
class StaticBlockObject;
class StrictArgumentsObject;
@ -646,9 +646,6 @@ struct JSObject : public js::ObjectImpl
static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
inline js::NativeIterator *getNativeIterator() const;
inline void setNativeIterator(js::NativeIterator *);
/*
* XML-related getters and setters.
*/
@ -901,9 +898,9 @@ struct JSObject : public js::ObjectImpl
inline bool isFunction() const;
inline bool isGenerator() const;
inline bool isGlobal() const;
inline bool isIterator() const;
inline bool isObject() const;
inline bool isPrimitive() const;
inline bool isPropertyIterator() const;
inline bool isProxy() const;
inline bool isRegExp() const;
inline bool isRegExpStatics() const;
@ -957,6 +954,7 @@ struct JSObject : public js::ObjectImpl
inline js::NestedScopeObject &asNestedScope();
inline js::NormalArgumentsObject &asNormalArguments();
inline js::NumberObject &asNumber();
inline js::PropertyIteratorObject &asPropertyIterator();
inline js::RegExpObject &asRegExp();
inline js::ScopeObject &asScope();
inline js::StrictArgumentsObject &asStrictArguments();

Просмотреть файл

@ -561,18 +561,6 @@ JSObject::setDateUTCTime(const js::Value &time)
setFixedSlot(JSSLOT_DATE_UTC_TIME, time);
}
inline js::NativeIterator *
JSObject::getNativeIterator() const
{
return (js::NativeIterator *) getPrivate();
}
inline void
JSObject::setNativeIterator(js::NativeIterator *ni)
{
setPrivate(ni);
}
#if JS_HAS_XML_SUPPORT
inline JSLinearString *
@ -799,7 +787,6 @@ inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); }
inline bool JSObject::isFunction() const { return hasClass(&js::FunctionClass); }
inline bool JSObject::isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
inline bool JSObject::isGenerator() const { return hasClass(&js::GeneratorClass); }
inline bool JSObject::isIterator() const { return hasClass(&js::IteratorClass); }
inline bool JSObject::isNestedScope() const { return isBlock() || isWith(); }
inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); }

Просмотреть файл

@ -23,6 +23,7 @@
#include "jsobjinlines.h"
#include "builtin/Iterator-inl.h"
#include "vm/RegExpObject-inl.h"
using namespace js;
@ -610,8 +611,8 @@ CanReify(Value *vp)
{
JSObject *obj;
return vp->isObject() &&
(obj = &vp->toObject())->getClass() == &IteratorClass &&
(obj->getNativeIterator()->flags & JSITER_ENUMERATE);
(obj = &vp->toObject())->isPropertyIterator() &&
(obj->asPropertyIterator().getNativeIterator()->flags & JSITER_ENUMERATE);
}
struct AutoCloseIterator
@ -630,7 +631,7 @@ struct AutoCloseIterator
static bool
Reify(JSContext *cx, JSCompartment *origin, Value *vp)
{
JSObject *iterObj = &vp->toObject();
PropertyIteratorObject *iterObj = &vp->toObject().asPropertyIterator();
NativeIterator *ni = iterObj->getNativeIterator();
AutoCloseIterator close(cx, iterObj);

Просмотреть файл

@ -6090,7 +6090,8 @@ mjit::Compiler::iterNext(ptrdiff_t offset)
frame.unpinReg(reg);
/* Test clasp */
Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass);
Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, T1,
&PropertyIteratorObject::class_);
stubcc.linkExit(notFast, Uses(1));
/* Get private from iter obj. */
@ -6141,7 +6142,8 @@ mjit::Compiler::iterMore(jsbytecode *target)
RegisterID tempreg = frame.allocReg();
/* Test clasp */
Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, tempreg, &IteratorClass);
Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, tempreg,
&PropertyIteratorObject::class_);
stubcc.linkExitForBranch(notFast);
/* Get private from iter obj. */
@ -6180,7 +6182,8 @@ mjit::Compiler::iterEnd()
frame.unpinReg(reg);
/* Test clasp */
Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass);
Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, T1,
&PropertyIteratorObject::class_);
stubcc.linkExit(notIterator, Uses(1));
/* Get private from iter obj. */