diff options
Diffstat (limited to 'js/src/vm/BoundFunctionObject.h')
-rw-r--r-- | js/src/vm/BoundFunctionObject.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/js/src/vm/BoundFunctionObject.h b/js/src/vm/BoundFunctionObject.h new file mode 100644 index 0000000000..566bdc0bed --- /dev/null +++ b/js/src/vm/BoundFunctionObject.h @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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 vm_BoundFunctionObject_h +#define vm_BoundFunctionObject_h + +#include "jstypes.h" + +#include "gc/Policy.h" +#include "vm/ArrayObject.h" +#include "vm/JSAtom.h" +#include "vm/JSObject.h" + +namespace js { + +// Implementation of Bound Function Exotic Objects. +// ES2023 10.4.1 +// https://tc39.es/ecma262/#sec-bound-function-exotic-objects +class BoundFunctionObject : public NativeObject { + public: + static const JSClass class_; + + // FlagsSlot uses the low bit for the is-constructor flag and the other bits + // for the number of arguments. + static constexpr size_t IsConstructorFlag = 0b1; + static constexpr size_t NumBoundArgsShift = 1; + + // The maximum number of bound arguments that can be stored inline in + // BoundArg*Slot. + static constexpr size_t MaxInlineBoundArgs = 3; + + private: + enum { + // The [[BoundTargetFunction]] (a callable object). + TargetSlot, + + // The number of arguments + the is-constructor flag, stored as Int32Value. + FlagsSlot, + + // The [[BoundThis]] Value. + BoundThisSlot, + + // The [[BoundArguments]]. If numBoundArgs exceeds MaxInlineBoundArgs, + // BoundArg0Slot will contain an array object that stores the values and the + // other two slots will be unused. + BoundArg0Slot, + BoundArg1Slot, + BoundArg2Slot, + + // Initial slots for the `length` and `name` own data properties. Note that + // these properties are configurable, so these slots can be mutated when the + // object is exposed to JS. + LengthSlot, + NameSlot, + + SlotCount + }; + + // The AllocKind should match SlotCount. See assertion in functionBindImpl. + static constexpr gc::AllocKind allocKind = gc::AllocKind::OBJECT8_BACKGROUND; + + void initFlags(size_t numBoundArgs, bool isConstructor) { + int32_t val = (numBoundArgs << NumBoundArgsShift) | isConstructor; + initReservedSlot(FlagsSlot, Int32Value(val)); + } + + public: + size_t numBoundArgs() const { + int32_t v = getReservedSlot(FlagsSlot).toInt32(); + MOZ_ASSERT(v >= 0); + return v >> NumBoundArgsShift; + } + bool isConstructor() const { + int32_t v = getReservedSlot(FlagsSlot).toInt32(); + return v & IsConstructorFlag; + } + + Value getTargetVal() const { return getReservedSlot(TargetSlot); } + JSObject* getTarget() const { return &getTargetVal().toObject(); } + + Value getBoundThis() const { return getReservedSlot(BoundThisSlot); } + + Value getInlineBoundArg(size_t i) const { + MOZ_ASSERT(i < numBoundArgs()); + MOZ_ASSERT(numBoundArgs() <= MaxInlineBoundArgs); + return getReservedSlot(BoundArg0Slot + i); + } + ArrayObject* getBoundArgsArray() const { + MOZ_ASSERT(numBoundArgs() > MaxInlineBoundArgs); + return &getReservedSlot(BoundArg0Slot).toObject().as<ArrayObject>(); + } + Value getBoundArg(size_t i) const { + MOZ_ASSERT(i < numBoundArgs()); + if (numBoundArgs() <= MaxInlineBoundArgs) { + return getInlineBoundArg(i); + } + return getBoundArgsArray()->getDenseElement(i); + } + + void initLength(double len) { + MOZ_ASSERT(getReservedSlot(LengthSlot).isUndefined()); + initReservedSlot(LengthSlot, NumberValue(len)); + } + void initName(JSAtom* name) { + MOZ_ASSERT(getReservedSlot(NameSlot).isUndefined()); + initReservedSlot(NameSlot, StringValue(name)); + } + + // Get the `length` and `name` property values when the object has the + // original shape. See comment for LengthSlot and NameSlot. + Value getLengthForInitialShape() const { return getReservedSlot(LengthSlot); } + Value getNameForInitialShape() const { return getReservedSlot(NameSlot); } + + // The [[Call]] and [[Construct]] hooks. + static bool call(JSContext* cx, unsigned argc, Value* vp); + static bool construct(JSContext* cx, unsigned argc, Value* vp); + + // The JSFunToStringOp implementation for Function.prototype.toString. + static JSString* funToString(JSContext* cx, Handle<JSObject*> obj, + bool isToSource); + + // Implementation of Function.prototype.bind. + static bool functionBind(JSContext* cx, unsigned argc, Value* vp); + + static SharedShape* assignInitialShape(JSContext* cx, + Handle<BoundFunctionObject*> obj); + + static BoundFunctionObject* functionBindImpl( + JSContext* cx, Handle<JSObject*> target, Value* args, uint32_t argc, + Handle<BoundFunctionObject*> maybeBound); + + static BoundFunctionObject* createWithTemplate( + JSContext* cx, Handle<BoundFunctionObject*> templateObj); + static BoundFunctionObject* functionBindSpecializedBaseline( + JSContext* cx, Handle<JSObject*> target, Value* args, uint32_t argc, + Handle<BoundFunctionObject*> templateObj); + + static BoundFunctionObject* createTemplateObject(JSContext* cx); + + bool initTemplateSlotsForSpecializedBind(JSContext* cx, uint32_t numBoundArgs, + bool targetIsConstructor, + uint32_t targetLength, + JSAtom* targetName); + + static constexpr size_t offsetOfTargetSlot() { + return getFixedSlotOffset(TargetSlot); + } + static constexpr size_t offsetOfFlagsSlot() { + return getFixedSlotOffset(FlagsSlot); + } + static constexpr size_t offsetOfBoundThisSlot() { + return getFixedSlotOffset(BoundThisSlot); + } + static constexpr size_t offsetOfFirstInlineBoundArg() { + return getFixedSlotOffset(BoundArg0Slot); + } + static constexpr size_t offsetOfLengthSlot() { + return getFixedSlotOffset(LengthSlot); + } + static constexpr size_t offsetOfNameSlot() { + return getFixedSlotOffset(NameSlot); + } + + static constexpr size_t targetSlot() { return TargetSlot; } + static constexpr size_t boundThisSlot() { return BoundThisSlot; } + static constexpr size_t firstInlineBoundArgSlot() { return BoundArg0Slot; } +}; + +}; // namespace js + +#endif /* vm_BoundFunctionObject_h */ |