ArgumentsObject* ArgumentsObject::createTemplateObject(JSContext* cx, bool mapped) { const Class* clasp = mapped ? &MappedArgumentsObject::class_ : &UnmappedArgumentsObject::class_; RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); if (!proto) return nullptr; RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, TaggedProto(proto.get()))); if (!group) return nullptr; RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto), FINALIZE_KIND, BaseShape::INDEXED)); if (!shape) return nullptr; AutoSetNewObjectMetadata metadata(cx); JSObject* base = JSObject::create(cx, FINALIZE_KIND, gc::TenuredHeap, shape, group); if (!base) return nullptr; ArgumentsObject* obj = &base->as<js::ArgumentsObject>(); obj->initFixedSlot(ArgumentsObject::DATA_SLOT, PrivateValue(nullptr)); return obj; }
/* static */ ArgumentsObject* ArgumentsObject::create(JSContext* cx, HandleFunction callee, unsigned numActuals, CopyArgs& copy) { bool mapped = callee->nonLazyScript()->hasMappedArgsObj(); ArgumentsObject* templateObj = cx->compartment()->getOrCreateArgumentsTemplateObject(cx, mapped); if (!templateObj) return nullptr; RootedShape shape(cx, templateObj->lastProperty()); RootedObjectGroup group(cx, templateObj->group()); unsigned numFormals = callee->nargs(); unsigned numArgs = Max(numActuals, numFormals); unsigned numBytes = ArgumentsData::bytesRequired(numArgs); Rooted<ArgumentsObject*> obj(cx); ArgumentsData* data = nullptr; { // The copyArgs call below can allocate objects, so add this block scope // to make sure we set the metadata for this arguments object first. AutoSetNewObjectMetadata metadata(cx); JSObject* base = JSObject::create(cx, FINALIZE_KIND, gc::DefaultHeap, shape, group); if (!base) return nullptr; obj = &base->as<ArgumentsObject>(); data = reinterpret_cast<ArgumentsData*>(AllocateObjectBuffer<uint8_t>(cx, obj, numBytes)); if (!data) { // Make the object safe for GC. obj->initFixedSlot(DATA_SLOT, PrivateValue(nullptr)); return nullptr; } data->numArgs = numArgs; data->rareData = nullptr; // Zero the argument Values. This sets each value to DoubleValue(0), which // is safe for GC tracing. memset(data->args, 0, numArgs * sizeof(Value)); MOZ_ASSERT(DoubleValue(0).asRawBits() == 0x0); MOZ_ASSERT_IF(numArgs > 0, data->args[0].asRawBits() == 0x0); obj->initFixedSlot(DATA_SLOT, PrivateValue(data)); obj->initFixedSlot(CALLEE_SLOT, ObjectValue(*callee)); } MOZ_ASSERT(data != nullptr); /* Copy [0, numArgs) into data->slots. */ copy.copyArgs(cx, data->args, numArgs); obj->initFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(numActuals << PACKED_BITS_COUNT)); copy.maybeForwardToCallObject(obj, data); MOZ_ASSERT(obj->initialLength() == numActuals); MOZ_ASSERT(!obj->hasOverriddenLength()); return obj; }
/* static */ size_t ArgumentsObject::objectMoved(JSObject* dst, JSObject* src) { ArgumentsObject* ndst = &dst->as<ArgumentsObject>(); const ArgumentsObject* nsrc = &src->as<ArgumentsObject>(); MOZ_ASSERT(ndst->data() == nsrc->data()); if (!IsInsideNursery(src)) return 0; Nursery& nursery = dst->zone()->group()->nursery(); size_t nbytesTotal = 0; if (!nursery.isInside(nsrc->data())) { nursery.removeMallocedBuffer(nsrc->data()); } else { AutoEnterOOMUnsafeRegion oomUnsafe; uint32_t nbytes = ArgumentsData::bytesRequired(nsrc->data()->numArgs); uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes); if (!data) oomUnsafe.crash("Failed to allocate ArgumentsObject data while tenuring."); ndst->initFixedSlot(DATA_SLOT, PrivateValue(data)); mozilla::PodCopy(data, reinterpret_cast<uint8_t*>(nsrc->data()), nbytes); nbytesTotal += nbytes; } if (RareArgumentsData* srcRareData = nsrc->maybeRareData()) { if (!nursery.isInside(srcRareData)) { nursery.removeMallocedBuffer(srcRareData); } else { AutoEnterOOMUnsafeRegion oomUnsafe; uint32_t nbytes = RareArgumentsData::bytesRequired(nsrc->initialLength()); uint8_t* dstRareData = nsrc->zone()->pod_malloc<uint8_t>(nbytes); if (!dstRareData) oomUnsafe.crash("Failed to allocate RareArgumentsData data while tenuring."); ndst->data()->rareData = (RareArgumentsData*)dstRareData; mozilla::PodCopy(dstRareData, reinterpret_cast<uint8_t*>(srcRareData), nbytes); nbytesTotal += nbytes; } } return nbytesTotal; }
ArgumentsObject * ArgumentsObject::create(JSContext *cx, StackFrame *fp) { JS_ASSERT(fp->script()->needsArgsObj()); ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), RootedVarObject(cx, &fp->callee())); if (!argsobj) return NULL; /* * Strict mode functions have arguments objects that copy the initial * actual parameter values. Non-strict mode arguments use the frame pointer * to retrieve up-to-date parameter values. */ if (argsobj->isStrictArguments()) fp->forEachCanonicalActualArg(PutArg(cx->compartment, *argsobj)); else argsobj->setStackFrame(fp); fp->initArgsObj(*argsobj); return argsobj; }
/* static */ size_t ArgumentsObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src) { ArgumentsObject* ndst = &dst->as<ArgumentsObject>(); ArgumentsObject* nsrc = &src->as<ArgumentsObject>(); MOZ_ASSERT(ndst->data() == nsrc->data()); Nursery& nursery = trc->runtime()->gc.nursery; if (!nursery.isInside(nsrc->data())) { nursery.removeMallocedBuffer(nsrc->data()); return 0; } AutoEnterOOMUnsafeRegion oomUnsafe; uint32_t nbytes = nsrc->data()->dataBytes; uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes); if (!data) oomUnsafe.crash("Failed to allocate ArgumentsObject data while tenuring."); ndst->initFixedSlot(DATA_SLOT, PrivateValue(data)); mozilla::PodCopy(data, reinterpret_cast<uint8_t*>(nsrc->data()), nbytes); ArgumentsData* dstData = ndst->data(); dstData->deletedBits = reinterpret_cast<size_t*>(dstData->args + dstData->numArgs); return nbytes; }
PutArg(JSCompartment *comp, ArgumentsObject &argsobj) : compartment(comp), argsobj(argsobj), dst(argsobj.data()->slots) {}