mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 903193 - Part 6: Add ParallelExecution path to ArraySetLength. (r=bhackett)
This commit is contained in:
parent
c3d9c59198
commit
b0abb42ae8
@ -399,7 +399,7 @@ array_length_setter(JSContext *cx, HandleObject obj, HandleId id, bool strict, M
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
MOZ_ASSERT(arr->lengthIsWritable(),
|
||||
"setter shouldn't be called if property is non-writable");
|
||||
return ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, strict);
|
||||
return ArraySetLength<SequentialExecution>(cx, arr, id, JSPROP_PERMANENT, vp, strict);
|
||||
}
|
||||
|
||||
struct ReverseIndexComparator
|
||||
@ -411,15 +411,30 @@ struct ReverseIndexComparator
|
||||
}
|
||||
};
|
||||
|
||||
template <ExecutionMode mode>
|
||||
bool
|
||||
js::CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *newLen)
|
||||
js::CanonicalizeArrayLengthValue(typename ExecutionModeTraits<mode>::ContextType cx,
|
||||
HandleValue v, uint32_t *newLen)
|
||||
{
|
||||
if (!ToUint32(cx, v, newLen))
|
||||
return false;
|
||||
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
|
||||
if (mode == ParallelExecution) {
|
||||
if (v.isObject())
|
||||
return false;
|
||||
|
||||
if (!NonObjectToUint32(cx, v, newLen))
|
||||
return false;
|
||||
|
||||
if (!NonObjectToNumber(cx, v, &d))
|
||||
return false;
|
||||
} else {
|
||||
if (!ToUint32(cx->asJSContext(), v, newLen))
|
||||
return false;
|
||||
|
||||
if (!ToNumber(cx->asJSContext(), v, &d))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d == *newLen)
|
||||
return true;
|
||||
|
||||
@ -429,18 +444,28 @@ js::CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *newLen)
|
||||
return false;
|
||||
}
|
||||
|
||||
template bool
|
||||
js::CanonicalizeArrayLengthValue<SequentialExecution>(JSContext *cx,
|
||||
HandleValue v, uint32_t *newLen);
|
||||
template bool
|
||||
js::CanonicalizeArrayLengthValue<ParallelExecution>(ForkJoinSlice *slice,
|
||||
HandleValue v, uint32_t *newLen);
|
||||
|
||||
/* ES6 20130308 draft 8.4.2.4 ArraySetLength */
|
||||
template <ExecutionMode mode>
|
||||
bool
|
||||
js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigned attrs,
|
||||
HandleValue value, bool setterIsStrict)
|
||||
js::ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cxArg,
|
||||
Handle<ArrayObject*> arr, HandleId id,
|
||||
unsigned attrs, HandleValue value, bool setterIsStrict)
|
||||
{
|
||||
MOZ_ASSERT(id == NameToId(cx->names().length));
|
||||
MOZ_ASSERT(cxArg->isThreadLocal(arr));
|
||||
MOZ_ASSERT(id == NameToId(cxArg->names().length));
|
||||
|
||||
/* Steps 1-2 are irrelevant in our implementation. */
|
||||
|
||||
/* Steps 3-5. */
|
||||
uint32_t newLen;
|
||||
if (!CanonicalizeArrayLengthValue(cx, value, &newLen))
|
||||
if (!CanonicalizeArrayLengthValue<mode>(cxArg, value, &newLen))
|
||||
return false;
|
||||
|
||||
// Abort if we're being asked to change enumerability or configurability.
|
||||
@ -455,14 +480,18 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
if (!(attrs & JSPROP_PERMANENT) || (attrs & JSPROP_ENUMERATE)) {
|
||||
if (!setterIsStrict)
|
||||
return true;
|
||||
return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
|
||||
// Bail for strict mode in parallel execution, as we need to go back
|
||||
// to sequential mode to throw the error.
|
||||
if (mode == ParallelExecution)
|
||||
return false;
|
||||
return Throw(cxArg->asJSContext(), id, JSMSG_CANT_REDEFINE_PROP);
|
||||
}
|
||||
|
||||
/* Steps 6-7. */
|
||||
bool lengthIsWritable = arr->lengthIsWritable();
|
||||
#ifdef DEBUG
|
||||
{
|
||||
RootedShape lengthShape(cx, arr->nativeLookup(cx, id));
|
||||
RootedShape lengthShape(cxArg, arr->nativeLookupPure(id));
|
||||
MOZ_ASSERT(lengthShape);
|
||||
MOZ_ASSERT(lengthShape->writable() == lengthIsWritable);
|
||||
}
|
||||
@ -475,16 +504,17 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
if (newLen == oldLen)
|
||||
return true;
|
||||
|
||||
if (!cx->isJSContext())
|
||||
if (!cxArg->isJSContext())
|
||||
return false;
|
||||
|
||||
if (setterIsStrict) {
|
||||
return JS_ReportErrorFlagsAndNumber(cx->asJSContext(),
|
||||
return JS_ReportErrorFlagsAndNumber(cxArg->asJSContext(),
|
||||
JSREPORT_ERROR, js_GetErrorMessage, nullptr,
|
||||
JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
|
||||
}
|
||||
|
||||
return JSObject::reportReadOnly(cx->asJSContext(), id, JSREPORT_STRICT | JSREPORT_WARNING);
|
||||
return JSObject::reportReadOnly(cxArg->asJSContext(), id,
|
||||
JSREPORT_STRICT | JSREPORT_WARNING);
|
||||
}
|
||||
|
||||
/* Step 8. */
|
||||
@ -512,7 +542,7 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
if (oldInitializedLength > newLen)
|
||||
arr->setDenseInitializedLength(newLen);
|
||||
if (oldCapacity > newLen)
|
||||
arr->shrinkElements(cx, newLen);
|
||||
arr->shrinkElements(cxArg, newLen);
|
||||
|
||||
// We've done the work of deleting any dense elements needing
|
||||
// deletion, and there are no sparse elements. Thus we can skip
|
||||
@ -520,6 +550,13 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
break;
|
||||
}
|
||||
|
||||
// Bail from parallel execution if need to perform step 15, which is
|
||||
// unsafe and isn't a common case.
|
||||
if (mode == ParallelExecution)
|
||||
return false;
|
||||
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
|
||||
// Step 15.
|
||||
//
|
||||
// Attempt to delete all elements above the new length, from greatest
|
||||
@ -628,17 +665,29 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
// API call on the floor here. Given that getter/setter will go away in
|
||||
// the long run, with accessors replacing them both internally and at the
|
||||
// API level, just run with this.
|
||||
RootedShape lengthShape(cx, arr->nativeLookup(cx, id));
|
||||
if (!JSObject::changeProperty(cx, arr, lengthShape, attrs,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED,
|
||||
array_length_getter, array_length_setter))
|
||||
RootedShape lengthShape(cxArg, mode == ParallelExecution
|
||||
? arr->nativeLookupPure(id)
|
||||
: arr->nativeLookup(cxArg->asJSContext(), id));
|
||||
if (!JSObject::changeProperty<mode>(cxArg, arr, lengthShape, attrs,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED,
|
||||
array_length_getter, array_length_setter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue v(cx, NumberValue(newLen));
|
||||
AddTypePropertyId(cx, arr, id, v);
|
||||
ArrayObject::setLength(cx, arr, newLen);
|
||||
RootedValue v(cxArg, NumberValue(newLen));
|
||||
if (mode == ParallelExecution) {
|
||||
// Adding the property type or overflowing int32 requires changing TI
|
||||
// state.
|
||||
if (!HasTypePropertyId(arr, id, v) || newLen > INT32_MAX)
|
||||
return false;
|
||||
arr->setLengthInt32(newLen);
|
||||
} else {
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
AddTypePropertyId(cx, arr, id, v);
|
||||
ArrayObject::setLength(cx, arr, newLen);
|
||||
}
|
||||
|
||||
|
||||
// All operations past here until the |!succeeded| code must be infallible,
|
||||
// so that all element fields remain properly synchronized.
|
||||
@ -659,12 +708,15 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
// the already-required range check for |index < capacity| by making
|
||||
// capacity of arrays with non-writable length never exceed the length.
|
||||
if (arr->getDenseCapacity() > newLen) {
|
||||
arr->shrinkElements(cx, newLen);
|
||||
arr->shrinkElements(cxArg, newLen);
|
||||
arr->getElementsHeader()->capacity = newLen;
|
||||
}
|
||||
}
|
||||
|
||||
if (setterIsStrict && !succeeded) {
|
||||
// We can't have arrived here under ParallelExecution, as we have
|
||||
// returned from the function before step 15 above.
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
RootedId elementId(cx);
|
||||
if (!IndexToId(cx, newLen - 1, &elementId))
|
||||
return false;
|
||||
@ -674,6 +726,15 @@ js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigne
|
||||
return true;
|
||||
}
|
||||
|
||||
template bool
|
||||
js::ArraySetLength<SequentialExecution>(JSContext *cx, Handle<ArrayObject*> arr,
|
||||
HandleId id, unsigned attrs, HandleValue value,
|
||||
bool setterIsStrict);
|
||||
template bool
|
||||
js::ArraySetLength<ParallelExecution>(ForkJoinSlice *slice, Handle<ArrayObject*> arr,
|
||||
HandleId id, unsigned attrs, HandleValue value,
|
||||
bool setterIsStrict);
|
||||
|
||||
bool
|
||||
js::WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
|
||||
HandleObject obj, uint32_t index, bool strict,
|
||||
|
@ -83,9 +83,13 @@ WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
|
||||
/*
|
||||
* Canonicalize |vp| to a uint32_t value potentially suitable for use as an
|
||||
* array length.
|
||||
*
|
||||
* For parallel execution we can only canonicalize non-object values.
|
||||
*/
|
||||
template <ExecutionMode mode>
|
||||
extern bool
|
||||
CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *canonicalized);
|
||||
CanonicalizeArrayLengthValue(typename ExecutionModeTraits<mode>::ContextType cx,
|
||||
HandleValue v, uint32_t *canonicalized);
|
||||
|
||||
extern bool
|
||||
GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp);
|
||||
|
@ -2517,6 +2517,15 @@ TypeObject::markPropertyConfigured(ExclusiveContext *cx, jsid id)
|
||||
types->setConfiguredProperty(cx);
|
||||
}
|
||||
|
||||
bool
|
||||
TypeObject::isPropertyConfigured(jsid id)
|
||||
{
|
||||
TypeSet *types = maybeGetProperty(id);
|
||||
if (types)
|
||||
return types->configuredProperty();
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TypeObject::markStateChange(ExclusiveContext *cxArg)
|
||||
{
|
||||
|
@ -1064,6 +1064,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
|
||||
void clearAddendum(ExclusiveContext *cx);
|
||||
void clearNewScriptAddendum(ExclusiveContext *cx);
|
||||
void clearTypedObjectAddendum(ExclusiveContext *cx);
|
||||
bool isPropertyConfigured(jsid id);
|
||||
|
||||
void print();
|
||||
|
||||
|
@ -533,6 +533,12 @@ MarkTypePropertyConfigured(ExclusiveContext *cx, HandleObject obj, jsid id)
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsTypePropertyIdMarkedConfigured(JSObject *obj, jsid id)
|
||||
{
|
||||
return obj->type()->isPropertyConfigured(id);
|
||||
}
|
||||
|
||||
/* Mark a state change on a particular object. */
|
||||
inline void
|
||||
MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj)
|
||||
|
@ -884,7 +884,7 @@ DefinePropertyOnArray(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, cons
|
||||
RootedValue v(cx);
|
||||
if (desc.hasValue()) {
|
||||
uint32_t newLen;
|
||||
if (!CanonicalizeArrayLengthValue(cx, desc.value(), &newLen))
|
||||
if (!CanonicalizeArrayLengthValue<SequentialExecution>(cx, desc.value(), &newLen))
|
||||
return false;
|
||||
v.setNumber(newLen);
|
||||
} else {
|
||||
@ -908,7 +908,7 @@ DefinePropertyOnArray(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, cons
|
||||
attrs = attrs | JSPROP_READONLY;
|
||||
}
|
||||
|
||||
return ArraySetLength(cx, arr, id, attrs, v, throwError);
|
||||
return ArraySetLength<SequentialExecution>(cx, arr, id, attrs, v, throwError);
|
||||
}
|
||||
|
||||
/* Step 3. */
|
||||
@ -3532,12 +3532,10 @@ DefinePropertyOrElement(typename ExecutionModeTraits<mode>::ExclusiveContextType
|
||||
if (obj->is<ArrayObject>()) {
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
if (id == NameToId(cx->names().length)) {
|
||||
if (mode == ParallelExecution)
|
||||
if (mode == SequentialExecution && !cx->shouldBeJSContext())
|
||||
return false;
|
||||
|
||||
if (!cx->shouldBeJSContext())
|
||||
return false;
|
||||
return ArraySetLength(cx->asJSContext(), arr, id, attrs, value, setterIsStrict);
|
||||
return ArraySetLength<mode>(ExecutionModeTraits<mode>::toContextType(cx), arr, id,
|
||||
attrs, value, setterIsStrict);
|
||||
}
|
||||
|
||||
uint32_t index;
|
||||
@ -3634,14 +3632,14 @@ js::DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, Ha
|
||||
shape = obj->nativeLookup(cx, id);
|
||||
}
|
||||
if (shape->isAccessorDescriptor()) {
|
||||
shape = JSObject::changeProperty(cx, obj, shape, attrs,
|
||||
JSPROP_GETTER | JSPROP_SETTER,
|
||||
(attrs & JSPROP_GETTER)
|
||||
? getter
|
||||
: shape->getter(),
|
||||
(attrs & JSPROP_SETTER)
|
||||
? setter
|
||||
: shape->setter());
|
||||
shape = JSObject::changeProperty<SequentialExecution>(cx, obj, shape, attrs,
|
||||
JSPROP_GETTER | JSPROP_SETTER,
|
||||
(attrs & JSPROP_GETTER)
|
||||
? getter
|
||||
: shape->getter(),
|
||||
(attrs & JSPROP_SETTER)
|
||||
? setter
|
||||
: shape->setter());
|
||||
if (!shape)
|
||||
return false;
|
||||
} else {
|
||||
@ -4813,12 +4811,8 @@ baseops::SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cxArg
|
||||
}
|
||||
|
||||
if (obj->is<ArrayObject>() && id == NameToId(cxArg->names().length)) {
|
||||
if (mode == ParallelExecution)
|
||||
return false;
|
||||
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
|
||||
return ArraySetLength(cx, arr, id, attrs, vp, strict);
|
||||
Rooted<ArrayObject*> arr(cxArg, &obj->as<ArrayObject>());
|
||||
return ArraySetLength<mode>(cxArg, arr, id, attrs, vp, strict);
|
||||
}
|
||||
|
||||
if (!shape) {
|
||||
|
@ -899,9 +899,11 @@ class JSObject : public js::ObjectImpl
|
||||
unsigned flags, int shortid);
|
||||
|
||||
/* Change the given property into a sibling with the same id in this scope. */
|
||||
static js::Shape *changeProperty(js::ExclusiveContext *cx, js::HandleObject obj,
|
||||
js::HandleShape shape, unsigned attrs, unsigned mask,
|
||||
JSPropertyOp getter, JSStrictPropertyOp setter);
|
||||
template <js::ExecutionMode mode>
|
||||
static js::Shape *
|
||||
changeProperty(typename js::ExecutionModeTraits<mode>::ExclusiveContextType cx,
|
||||
js::HandleObject obj, js::HandleShape shape, unsigned attrs, unsigned mask,
|
||||
JSPropertyOp getter, JSStrictPropertyOp setter);
|
||||
|
||||
static inline bool changePropertyAttributes(JSContext *cx, js::HandleObject obj,
|
||||
js::HandleShape shape, unsigned attrs);
|
||||
|
@ -34,7 +34,8 @@ JSObject::setGenericAttributes(JSContext *cx, js::HandleObject obj,
|
||||
JSObject::changePropertyAttributes(JSContext *cx, js::HandleObject obj,
|
||||
js::HandleShape shape, unsigned attrs)
|
||||
{
|
||||
return !!changeProperty(cx, obj, shape, attrs, 0, shape->getter(), shape->setter());
|
||||
return !!changeProperty<js::SequentialExecution>(cx, obj, shape, attrs, 0,
|
||||
shape->getter(), shape->setter());
|
||||
}
|
||||
|
||||
/* static */ inline bool
|
||||
|
@ -676,9 +676,11 @@ class ArrayBufferObject;
|
||||
* |setterIsStrict| indicates whether invalid changes will cause a TypeError
|
||||
* to be thrown.
|
||||
*/
|
||||
template <ExecutionMode mode>
|
||||
extern bool
|
||||
ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id, unsigned attrs,
|
||||
HandleValue value, bool setterIsStrict);
|
||||
ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
|
||||
Handle<ArrayObject*> obj, HandleId id,
|
||||
unsigned attrs, HandleValue value, bool setterIsStrict);
|
||||
|
||||
/*
|
||||
* Elements header used for all native objects. The elements component of such
|
||||
@ -768,9 +770,11 @@ class ObjectElements
|
||||
friend class ArrayBufferObject;
|
||||
friend class Nursery;
|
||||
|
||||
template <ExecutionMode mode>
|
||||
friend bool
|
||||
ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id, unsigned attrs,
|
||||
HandleValue value, bool setterIsStrict);
|
||||
ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
|
||||
Handle<ArrayObject*> obj, HandleId id,
|
||||
unsigned attrs, HandleValue value, bool setterIsStrict);
|
||||
|
||||
/* See Flags enum above. */
|
||||
uint32_t flags;
|
||||
|
@ -904,11 +904,14 @@ JSObject::putProperty<ParallelExecution>(ForkJoinSlice *cx,
|
||||
uint32_t slot, unsigned attrs,
|
||||
unsigned flags, int shortid);
|
||||
|
||||
template <ExecutionMode mode>
|
||||
/* static */ Shape *
|
||||
JSObject::changeProperty(ExclusiveContext *cx, HandleObject obj, HandleShape shape, unsigned attrs,
|
||||
JSObject::changeProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
|
||||
HandleObject obj, HandleShape shape, unsigned attrs,
|
||||
unsigned mask, PropertyOp getter, StrictPropertyOp setter)
|
||||
{
|
||||
JS_ASSERT(obj->nativeContains(cx, shape));
|
||||
JS_ASSERT(cx->isThreadLocal(obj));
|
||||
JS_ASSERT(obj->nativeContainsPure(shape));
|
||||
|
||||
attrs |= shape->attrs & mask;
|
||||
|
||||
@ -916,9 +919,22 @@ JSObject::changeProperty(ExclusiveContext *cx, HandleObject obj, HandleShape sha
|
||||
JS_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
|
||||
!(attrs & JSPROP_SHARED));
|
||||
|
||||
types::MarkTypePropertyConfigured(cx, obj, shape->propid());
|
||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
|
||||
types::AddTypePropertyId(cx, obj, shape->propid(), types::Type::UnknownType());
|
||||
if (mode == ParallelExecution) {
|
||||
if (!types::IsTypePropertyIdMarkedConfigured(obj, shape->propid()))
|
||||
return nullptr;
|
||||
} else {
|
||||
types::MarkTypePropertyConfigured(cx->asExclusiveContext(), obj, shape->propid());
|
||||
}
|
||||
|
||||
if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
|
||||
if (mode == ParallelExecution) {
|
||||
if (!types::HasTypePropertyId(obj, shape->propid(), types::Type::UnknownType()))
|
||||
return nullptr;
|
||||
} else {
|
||||
types::AddTypePropertyId(cx->asExclusiveContext(), obj, shape->propid(),
|
||||
types::Type::UnknownType());
|
||||
}
|
||||
}
|
||||
|
||||
if (getter == JS_PropertyStub)
|
||||
getter = nullptr;
|
||||
@ -938,14 +954,25 @@ JSObject::changeProperty(ExclusiveContext *cx, HandleObject obj, HandleShape sha
|
||||
* putProperty won't re-allocate it.
|
||||
*/
|
||||
RootedId propid(cx, shape->propid());
|
||||
Shape *newShape = putProperty<SequentialExecution>(cx, obj, propid, getter, setter,
|
||||
shape->maybeSlot(), attrs, shape->flags,
|
||||
shape->maybeShortid());
|
||||
Shape *newShape = putProperty<mode>(cx, obj, propid, getter, setter,
|
||||
shape->maybeSlot(), attrs, shape->flags,
|
||||
shape->maybeShortid());
|
||||
|
||||
obj->checkShapeConsistency();
|
||||
return newShape;
|
||||
}
|
||||
|
||||
template /* static */ Shape *
|
||||
JSObject::changeProperty<SequentialExecution>(ExclusiveContext *cx,
|
||||
HandleObject obj, HandleShape shape,
|
||||
unsigned attrs, unsigned mask,
|
||||
PropertyOp getter, StrictPropertyOp setter);
|
||||
template /* static */ Shape *
|
||||
JSObject::changeProperty<ParallelExecution>(ForkJoinSlice *slice,
|
||||
HandleObject obj, HandleShape shape,
|
||||
unsigned attrs, unsigned mask,
|
||||
PropertyOp getter, StrictPropertyOp setter);
|
||||
|
||||
bool
|
||||
JSObject::removeProperty(ExclusiveContext *cx, jsid id_)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user