2010-01-26 22:50:17 -08:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2009-10-26 13:39:39 -07:00
|
|
|
*
|
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
|
|
* March 31, 1998.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#ifndef jsscopeinlines_h___
|
|
|
|
#define jsscopeinlines_h___
|
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
#include <new>
|
|
|
|
#include "jsbool.h"
|
2009-10-26 13:39:39 -07:00
|
|
|
#include "jscntxt.h"
|
2009-12-01 12:49:15 -08:00
|
|
|
#include "jsdbgapi.h"
|
2009-10-26 13:39:39 -07:00
|
|
|
#include "jsfun.h"
|
|
|
|
#include "jsobj.h"
|
|
|
|
#include "jsscope.h"
|
|
|
|
|
2010-06-16 14:13:28 -07:00
|
|
|
#include "jscntxtinlines.h"
|
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
inline void
|
|
|
|
js::Shape::freeTable(JSContext *cx)
|
2010-01-26 22:50:17 -08:00
|
|
|
{
|
2011-02-09 15:18:03 -08:00
|
|
|
if (hasTable()) {
|
|
|
|
cx->destroy(getTable());
|
|
|
|
setTable(NULL);
|
2010-08-29 11:57:08 -07:00
|
|
|
}
|
2010-01-26 22:50:17 -08:00
|
|
|
}
|
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
inline js::EmptyShape *
|
2010-10-13 11:49:22 -07:00
|
|
|
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
|
|
|
|
/* gc::FinalizeKind */ unsigned kind)
|
2010-01-26 22:50:17 -08:00
|
|
|
{
|
2010-10-13 11:49:22 -07:00
|
|
|
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
|
|
|
|
int i = kind - js::gc::FINALIZE_OBJECT0;
|
|
|
|
|
|
|
|
if (!emptyShapes) {
|
|
|
|
emptyShapes = (js::EmptyShape**)
|
|
|
|
cx->calloc(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
|
|
|
|
if (!emptyShapes)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Always fill in emptyShapes[0], so canProvideEmptyShape works.
|
|
|
|
* Other empty shapes are filled in lazily.
|
|
|
|
*/
|
|
|
|
emptyShapes[0] = js::EmptyShape::create(cx, aclasp);
|
|
|
|
if (!emptyShapes[0]) {
|
|
|
|
cx->free(emptyShapes);
|
|
|
|
emptyShapes = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_ASSERT(aclasp == emptyShapes[0]->getClass());
|
|
|
|
|
|
|
|
if (!emptyShapes[i]) {
|
|
|
|
emptyShapes[i] = js::EmptyShape::create(cx, aclasp);
|
|
|
|
if (!emptyShapes[i])
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return emptyShapes[i];
|
2010-01-26 22:50:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
2010-08-29 11:57:08 -07:00
|
|
|
JSObject::canProvideEmptyShape(js::Class *aclasp)
|
2010-01-26 22:50:17 -08:00
|
|
|
{
|
2010-10-13 11:49:22 -07:00
|
|
|
return !emptyShapes || emptyShapes[0]->getClass() == aclasp;
|
2010-01-26 22:50:17 -08:00
|
|
|
}
|
|
|
|
|
2009-11-20 16:14:42 -08:00
|
|
|
inline void
|
2010-08-29 11:57:08 -07:00
|
|
|
JSObject::updateShape(JSContext *cx)
|
2009-11-20 16:14:42 -08:00
|
|
|
{
|
2010-08-29 11:57:08 -07:00
|
|
|
JS_ASSERT(isNative());
|
|
|
|
js::LeaveTraceIfGlobalObject(cx, this);
|
|
|
|
if (hasOwnShape())
|
2011-02-04 10:59:07 -08:00
|
|
|
setOwnShape(js_GenerateShape(cx));
|
2010-08-29 11:57:08 -07:00
|
|
|
else
|
|
|
|
objShape = lastProp->shape;
|
2009-12-01 12:49:15 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2010-08-29 11:57:08 -07:00
|
|
|
JSObject::updateFlags(const js::Shape *shape, bool isDefinitelyAtom)
|
2009-12-01 12:49:15 -08:00
|
|
|
{
|
2009-10-26 13:39:39 -07:00
|
|
|
jsuint index;
|
2010-08-29 11:57:08 -07:00
|
|
|
if (!isDefinitelyAtom && js_IdIsIndex(shape->id, &index))
|
|
|
|
setIndexed();
|
2009-10-26 13:39:39 -07:00
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
if (shape->isMethod())
|
2009-10-26 13:39:39 -07:00
|
|
|
setMethodBarrier();
|
|
|
|
}
|
|
|
|
|
2010-01-07 10:01:01 -08:00
|
|
|
inline void
|
2010-08-29 11:57:08 -07:00
|
|
|
JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom)
|
2010-01-07 10:01:01 -08:00
|
|
|
{
|
2010-08-29 11:57:08 -07:00
|
|
|
setLastProperty(shape);
|
|
|
|
updateFlags(shape, isDefinitelyAtom);
|
2010-01-07 10:01:01 -08:00
|
|
|
updateShape(cx);
|
|
|
|
}
|
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
inline void
|
|
|
|
JSObject::trace(JSTracer *trc)
|
2010-07-14 23:19:36 -07:00
|
|
|
{
|
2010-08-29 11:57:08 -07:00
|
|
|
if (!isNative())
|
|
|
|
return;
|
2009-10-26 13:39:39 -07:00
|
|
|
|
|
|
|
JSContext *cx = trc->context;
|
2010-08-29 11:57:08 -07:00
|
|
|
js::Shape *shape = lastProp;
|
2010-03-22 11:11:44 -07:00
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes) {
|
2009-10-26 13:39:39 -07:00
|
|
|
/*
|
2010-08-29 11:57:08 -07:00
|
|
|
* Either this object has its own shape, which must be regenerated, or
|
2009-10-26 13:39:39 -07:00
|
|
|
* it must have the same shape as lastProp.
|
|
|
|
*/
|
2010-08-29 11:57:08 -07:00
|
|
|
if (!shape->hasRegenFlag()) {
|
2011-02-04 10:59:07 -08:00
|
|
|
shape->shape = js_RegenerateShapeForGC(cx->runtime);
|
2010-08-29 11:57:08 -07:00
|
|
|
shape->setRegenFlag();
|
2009-10-26 13:39:39 -07:00
|
|
|
}
|
2010-08-29 11:57:08 -07:00
|
|
|
|
|
|
|
uint32 newShape = shape->shape;
|
|
|
|
if (hasOwnShape()) {
|
2011-02-04 10:59:07 -08:00
|
|
|
newShape = js_RegenerateShapeForGC(cx->runtime);
|
2010-08-29 11:57:08 -07:00
|
|
|
JS_ASSERT(newShape != shape->shape);
|
2009-10-26 13:39:39 -07:00
|
|
|
}
|
2010-08-29 11:57:08 -07:00
|
|
|
objShape = newShape;
|
2009-10-26 13:39:39 -07:00
|
|
|
}
|
2010-03-22 11:11:44 -07:00
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
/* Trace our property tree or dictionary ancestor line. */
|
|
|
|
do {
|
|
|
|
shape->trace(trc);
|
|
|
|
} while ((shape = shape->parent) != NULL);
|
2009-10-26 13:39:39 -07:00
|
|
|
}
|
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
namespace js {
|
|
|
|
|
2010-05-18 19:21:43 -07:00
|
|
|
inline
|
2011-02-09 11:31:40 -08:00
|
|
|
Shape::Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs,
|
2010-09-03 11:05:43 -07:00
|
|
|
uintN flags, intN shortid, uint32 shape, uint32 slotSpan)
|
2010-12-29 17:46:14 -08:00
|
|
|
: JSObjectMap(shape, slotSpan),
|
2011-02-09 15:18:03 -08:00
|
|
|
numLinearSearches(0), id(id), rawGetter(getter), rawSetter(setter), slot(slot),
|
2011-01-03 17:14:55 -08:00
|
|
|
attrs(uint8(attrs)), flags(uint8(flags)), shortid(int16(shortid)), parent(NULL)
|
2010-05-18 19:21:43 -07:00
|
|
|
{
|
2010-09-03 11:05:43 -07:00
|
|
|
JS_ASSERT_IF(slotSpan != SHAPE_INVALID_SLOT, slotSpan < JSObject::NSLOTS_LIMIT);
|
2010-05-18 19:21:43 -07:00
|
|
|
JS_ASSERT_IF(getter && (attrs & JSPROP_GETTER), getterObj->isCallable());
|
|
|
|
JS_ASSERT_IF(setter && (attrs & JSPROP_SETTER), setterObj->isCallable());
|
2010-08-29 11:57:08 -07:00
|
|
|
kids.setNull();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2011-02-04 10:59:07 -08:00
|
|
|
Shape::Shape(JSCompartment *comp, Class *aclasp)
|
|
|
|
: JSObjectMap(js_GenerateShape(comp->rt), JSSLOT_FREE(aclasp)),
|
2011-02-09 15:18:03 -08:00
|
|
|
numLinearSearches(0),
|
2011-02-04 10:59:07 -08:00
|
|
|
id(JSID_EMPTY),
|
|
|
|
clasp(aclasp),
|
|
|
|
rawSetter(NULL),
|
|
|
|
slot(SHAPE_INVALID_SLOT),
|
|
|
|
attrs(0),
|
|
|
|
flags(SHARED_EMPTY),
|
|
|
|
shortid(0),
|
|
|
|
parent(NULL)
|
2010-08-29 11:57:08 -07:00
|
|
|
{
|
|
|
|
kids.setNull();
|
2010-05-18 19:21:43 -07:00
|
|
|
}
|
|
|
|
|
2010-02-05 16:11:13 -08:00
|
|
|
inline JSDHashNumber
|
2010-08-29 11:57:08 -07:00
|
|
|
Shape::hash() const
|
2010-02-05 16:11:13 -08:00
|
|
|
{
|
|
|
|
JSDHashNumber hash = 0;
|
|
|
|
|
|
|
|
/* Accumulate from least to most random so the low bits are most random. */
|
2010-02-24 17:40:28 -08:00
|
|
|
JS_ASSERT_IF(isMethod(), !rawSetter || rawSetter == js_watch_set);
|
|
|
|
if (rawGetter)
|
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(rawGetter);
|
|
|
|
if (rawSetter)
|
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(rawSetter);
|
2010-02-05 16:11:13 -08:00
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & PUBLIC_FLAGS);
|
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs;
|
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid;
|
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ slot;
|
2010-07-14 23:19:36 -07:00
|
|
|
hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(id);
|
2010-02-05 16:11:13 -08:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
2010-08-29 11:57:08 -07:00
|
|
|
Shape::matches(const js::Shape *other) const
|
2010-02-05 16:11:13 -08:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_ASSERT(!JSID_IS_VOID(id));
|
2010-08-29 11:57:08 -07:00
|
|
|
JS_ASSERT(!JSID_IS_VOID(other->id));
|
|
|
|
return id == other->id &&
|
|
|
|
matchesParamsAfterId(other->rawGetter, other->rawSetter, other->slot, other->attrs,
|
|
|
|
other->flags, other->shortid);
|
2010-02-05 16:11:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
2011-02-09 11:31:40 -08:00
|
|
|
Shape::matchesParamsAfterId(js::PropertyOp agetter, js::StrictPropertyOp asetter, uint32 aslot,
|
2010-08-29 11:57:08 -07:00
|
|
|
uintN aattrs, uintN aflags, intN ashortid) const
|
2010-02-05 16:11:13 -08:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_ASSERT(!JSID_IS_VOID(id));
|
2010-02-24 17:40:28 -08:00
|
|
|
return rawGetter == agetter &&
|
|
|
|
rawSetter == asetter &&
|
2010-02-05 16:11:13 -08:00
|
|
|
slot == aslot &&
|
|
|
|
attrs == aattrs &&
|
|
|
|
((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
|
|
|
|
shortid == ashortid;
|
|
|
|
}
|
|
|
|
|
2010-06-16 14:13:01 -07:00
|
|
|
inline bool
|
2010-11-04 15:53:50 -07:00
|
|
|
Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js::Value* vp) const
|
2010-06-16 14:13:01 -07:00
|
|
|
{
|
2010-07-14 23:19:36 -07:00
|
|
|
JS_ASSERT(!JSID_IS_VOID(this->id));
|
2010-06-16 14:13:01 -07:00
|
|
|
JS_ASSERT(!hasDefaultGetter());
|
|
|
|
|
|
|
|
if (hasGetterValue()) {
|
|
|
|
JS_ASSERT(!isMethod());
|
2010-07-14 23:19:36 -07:00
|
|
|
js::Value fval = getterValue();
|
2010-11-04 15:53:50 -07:00
|
|
|
return js::ExternalGetOrSet(cx, receiver, id, fval, JSACC_READ, 0, 0, vp);
|
2010-06-16 14:13:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isMethod()) {
|
2010-07-14 23:19:36 -07:00
|
|
|
vp->setObject(methodObject());
|
2010-08-29 11:57:08 -07:00
|
|
|
return pobj->methodReadBarrier(cx, *this, vp);
|
2010-06-16 14:13:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* |with (it) color;| ends up here, as do XML filter-expressions.
|
|
|
|
* Avoid exposing the With object to native getters.
|
|
|
|
*/
|
|
|
|
if (obj->getClass() == &js_WithClass)
|
|
|
|
obj = js_UnwrapWithObject(cx, obj);
|
2010-08-29 11:57:08 -07:00
|
|
|
return js::CallJSPropertyOp(cx, getterOp(), obj, SHAPE_USERID(this), vp);
|
2010-06-16 14:13:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
2011-02-09 11:31:40 -08:00
|
|
|
Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const
|
2010-06-16 14:13:01 -07:00
|
|
|
{
|
|
|
|
JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
|
|
|
|
|
|
|
|
if (attrs & JSPROP_SETTER) {
|
2010-07-14 23:19:36 -07:00
|
|
|
js::Value fval = setterValue();
|
2010-08-16 12:35:04 -07:00
|
|
|
return js::ExternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp);
|
2010-06-16 14:13:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (attrs & JSPROP_GETTER)
|
2010-07-14 23:19:36 -07:00
|
|
|
return js_ReportGetterOnlyAssignment(cx);
|
2010-06-16 14:13:01 -07:00
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
/* See the comment in js::Shape::get as to why we check for With. */
|
2010-06-16 14:13:01 -07:00
|
|
|
if (obj->getClass() == &js_WithClass)
|
|
|
|
obj = js_UnwrapWithObject(cx, obj);
|
2011-02-09 11:31:40 -08:00
|
|
|
return js::CallJSPropertyOpSetter(cx, setterOp(), obj, SHAPE_USERID(this), strict, vp);
|
2010-08-29 11:57:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
2011-02-04 10:59:07 -08:00
|
|
|
EmptyShape::EmptyShape(JSCompartment *comp, js::Class *aclasp)
|
|
|
|
: js::Shape(comp, aclasp)
|
2010-08-29 11:57:08 -07:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2011-02-04 10:59:07 -08:00
|
|
|
if (comp->rt->meterEmptyShapes())
|
|
|
|
comp->emptyShapes.put(this);
|
2010-08-29 11:57:08 -07:00
|
|
|
#endif
|
2010-06-16 14:13:01 -07:00
|
|
|
}
|
|
|
|
|
2010-08-29 11:57:08 -07:00
|
|
|
} /* namespace js */
|
|
|
|
|
2009-10-26 13:39:39 -07:00
|
|
|
#endif /* jsscopeinlines_h___ */
|