bool WatchpointMap::triggerWatchpoint(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) { Map::Ptr p = map.lookup(WatchKey(obj, id)); if (!p || p->value().held) return true; AutoEntryHolder holder(cx, map, p); /* Copy the entry, since GC would invalidate p. */ JSWatchPointHandler handler = p->value().handler; RootedObject closure(cx, p->value().closure); /* Determine the property's old value. */ Value old; old.setUndefined(); if (obj->isNative()) { NativeObject* nobj = &obj->as<NativeObject>(); if (Shape* shape = nobj->lookup(cx, id)) { if (shape->hasSlot()) old = nobj->getSlot(shape->slot()); } } // Read barrier to prevent an incorrectly gray closure from escaping the // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp JS::ExposeObjectToActiveJS(closure); /* Call the handler. */ return handler(cx, obj, id, old, vp.address(), closure); }
bool WatchpointMap::triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, Value *vp) { Map::Ptr p = map.lookup(WatchKey(obj, id)); if (!p || p->value.held) return true; AutoEntryHolder holder(cx, map, p); /* Copy the entry, since GC would invalidate p. */ JSWatchPointHandler handler = p->value.handler; RootedObject closure(cx, p->value.closure); /* Determine the property's old value. */ Value old; old.setUndefined(); if (obj->isNative()) { if (const Shape *shape = obj->nativeLookup(cx, id)) { if (shape->hasSlot()) old = obj->nativeGetSlot(shape->slot()); } } /* Call the handler. */ return handler(cx, obj, id, old, vp, closure); }
static RawObject CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects) { CloneMemory::AddPtr p = clonedObjects.lookupForAdd(srcObj.get()); if (p) return p->value; RootedObject clone(cx); if (srcObj->isFunction()) { RootedFunction fun(cx, srcObj->toFunction()); clone = CloneFunctionObject(cx, fun, cx->global(), fun->getAllocKind()); } else if (srcObj->isRegExp()) { RegExpObject &reobj = srcObj->asRegExp(); RootedAtom source(cx, reobj.getSource()); clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), NULL); } else if (srcObj->isDate()) { clone = JS_NewDateObjectMsec(cx, srcObj->getDateUTCTime().toNumber()); } else if (srcObj->isBoolean()) { clone = BooleanObject::create(cx, srcObj->asBoolean().unbox()); } else if (srcObj->isNumber()) { clone = NumberObject::create(cx, srcObj->asNumber().unbox()); } else if (srcObj->isString()) { Rooted<JSStableString*> str(cx, srcObj->asString().unbox()->ensureStable(cx)); if (!str) return NULL; str = js_NewStringCopyN(cx, str->chars().get(), str->length())->ensureStable(cx); if (!str) return NULL; clone = StringObject::create(cx, str); } else if (srcObj->isDenseArray()) { return CloneDenseArray(cx, srcObj, clonedObjects); } else { if (srcObj->isArray()) { clone = NewDenseEmptyArray(cx); } else { JS_ASSERT(srcObj->isNative()); clone = NewObjectWithClassProto(cx, srcObj->getClass(), NULL, cx->global(), srcObj->getAllocKind()); } } if (!clone || !clonedObjects.relookupOrAdd(p, srcObj.get(), clone.get()) || !CloneProperties(cx, srcObj, clone, clonedObjects)) { return NULL; } return clone; }
bool GetPropIRGenerator::tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId, ValOperandId indexId) { MOZ_ASSERT(idVal_.isInt32()); if (idVal_.toInt32() < 0) return false; if (!obj->isNative() || !CanAttachDenseElementHole(obj)) return false; // Guard on the shape, to prevent non-dense elements from appearing. writer.guardShape(objId, obj->as<NativeObject>().lastProperty()); if (obj->hasUncacheableProto()) { // If the shape does not imply the proto, emit an explicit proto guard. writer.guardProto(objId, obj->staticPrototype()); } JSObject* pobj = obj->staticPrototype(); while (pobj) { ObjOperandId protoId = writer.loadObject(pobj); // Non-singletons with uncacheable protos can change their proto // without a shape change, so also guard on the group (which determines // the proto) in this case. if (pobj->hasUncacheableProto() && !pobj->isSingleton()) writer.guardGroup(protoId, pobj->group()); // Make sure the shape matches, to avoid non-dense elements or anything // else that is being checked by CanAttachDenseElementHole. writer.guardShape(protoId, pobj->as<NativeObject>().lastProperty()); // Also make sure there are no dense elements. writer.guardNoDenseElements(protoId); pobj = pobj->staticPrototype(); } Int32OperandId int32IndexId = writer.guardIsInt32(indexId); writer.loadDenseElementHoleResult(objId, int32IndexId); writer.typeMonitorResult(); return true; }
bool GetPropIRGenerator::tryAttachDenseElement(HandleObject obj, ObjOperandId objId, ValOperandId indexId) { MOZ_ASSERT(idVal_.isInt32()); if (!obj->isNative()) return false; if (!obj->as<NativeObject>().containsDenseElement(uint32_t(idVal_.toInt32()))) return false; writer.guardShape(objId, obj->as<NativeObject>().lastProperty()); Int32OperandId int32IndexId = writer.guardIsInt32(indexId); writer.loadDenseElementResult(objId, int32IndexId); writer.typeMonitorResult(); return true; }
bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value, bool strict) { // This function is called from Ion code for StoreElementHole's OOL path. // In this case we know the object is native, has no indexed properties // and we can use setDenseElement instead of setDenseElementWithType. MOZ_ASSERT(obj->isNative()); MOZ_ASSERT(!obj->isIndexed()); JSObject::EnsureDenseResult result = JSObject::ED_SPARSE; do { if (index < 0) break; bool isArray = obj->is<ArrayObject>(); if (isArray && !obj->as<ArrayObject>().lengthIsWritable()) break; uint32_t idx = uint32_t(index); result = obj->ensureDenseElements(cx, idx, 1); if (result != JSObject::ED_OK) break; if (isArray) { ArrayObject &arr = obj->as<ArrayObject>(); if (idx >= arr.length()) arr.setLengthInt32(idx + 1); } obj->setDenseElement(idx, value); return true; } while (false); if (result == JSObject::ED_FAILED) return false; MOZ_ASSERT(result == JSObject::ED_SPARSE); RootedValue indexVal(cx, Int32Value(index)); return SetObjectElement(cx, obj, indexVal, value, strict); }