Bug 1842773 - Part 32: Allow constructing growable SharedArrayBuffers. r=sfink
[gecko.git] / js / src / vm / BoundFunctionObject.h
blobbf0a423ee92e248cae60036191ff04a9e902ad99
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_BoundFunctionObject_h
8 #define vm_BoundFunctionObject_h
10 #include "jstypes.h"
12 #include "gc/Policy.h"
13 #include "vm/ArrayObject.h"
14 #include "vm/JSObject.h"
16 namespace js {
18 // Implementation of Bound Function Exotic Objects.
19 // ES2023 10.4.1
20 // https://tc39.es/ecma262/#sec-bound-function-exotic-objects
21 class BoundFunctionObject : public NativeObject {
22 public:
23 static const JSClass class_;
25 // FlagsSlot uses the low bit for the is-constructor flag and the other bits
26 // for the number of arguments.
27 static constexpr size_t IsConstructorFlag = 0b1;
28 static constexpr size_t NumBoundArgsShift = 1;
30 // The maximum number of bound arguments that can be stored inline in
31 // BoundArg*Slot.
32 static constexpr size_t MaxInlineBoundArgs = 3;
34 private:
35 enum {
36 // The [[BoundTargetFunction]] (a callable object).
37 TargetSlot,
39 // The number of arguments + the is-constructor flag, stored as Int32Value.
40 FlagsSlot,
42 // The [[BoundThis]] Value.
43 BoundThisSlot,
45 // The [[BoundArguments]]. If numBoundArgs exceeds MaxInlineBoundArgs,
46 // BoundArg0Slot will contain an array object that stores the values and the
47 // other two slots will be unused.
48 BoundArg0Slot,
49 BoundArg1Slot,
50 BoundArg2Slot,
52 // Initial slots for the `length` and `name` own data properties. Note that
53 // these properties are configurable, so these slots can be mutated when the
54 // object is exposed to JS.
55 LengthSlot,
56 NameSlot,
58 SlotCount
61 // The AllocKind should match SlotCount. See assertion in functionBindImpl.
62 static constexpr gc::AllocKind allocKind = gc::AllocKind::OBJECT8_BACKGROUND;
64 void initFlags(size_t numBoundArgs, bool isConstructor) {
65 int32_t val = (numBoundArgs << NumBoundArgsShift) | isConstructor;
66 initReservedSlot(FlagsSlot, Int32Value(val));
69 public:
70 size_t numBoundArgs() const {
71 int32_t v = getReservedSlot(FlagsSlot).toInt32();
72 MOZ_ASSERT(v >= 0);
73 return v >> NumBoundArgsShift;
75 bool isConstructor() const {
76 int32_t v = getReservedSlot(FlagsSlot).toInt32();
77 return v & IsConstructorFlag;
80 Value getTargetVal() const { return getReservedSlot(TargetSlot); }
81 JSObject* getTarget() const { return &getTargetVal().toObject(); }
83 Value getBoundThis() const { return getReservedSlot(BoundThisSlot); }
85 Value getInlineBoundArg(size_t i) const {
86 MOZ_ASSERT(i < numBoundArgs());
87 MOZ_ASSERT(numBoundArgs() <= MaxInlineBoundArgs);
88 return getReservedSlot(BoundArg0Slot + i);
90 ArrayObject* getBoundArgsArray() const {
91 MOZ_ASSERT(numBoundArgs() > MaxInlineBoundArgs);
92 return &getReservedSlot(BoundArg0Slot).toObject().as<ArrayObject>();
94 Value getBoundArg(size_t i) const {
95 MOZ_ASSERT(i < numBoundArgs());
96 if (numBoundArgs() <= MaxInlineBoundArgs) {
97 return getInlineBoundArg(i);
99 return getBoundArgsArray()->getDenseElement(i);
102 void initLength(double len) {
103 MOZ_ASSERT(getReservedSlot(LengthSlot).isUndefined());
104 initReservedSlot(LengthSlot, NumberValue(len));
106 void initName(JSAtom* name) {
107 MOZ_ASSERT(getReservedSlot(NameSlot).isUndefined());
108 initReservedSlot(NameSlot, StringValue(name));
111 // Get the `length` and `name` property values when the object has the
112 // original shape. See comment for LengthSlot and NameSlot.
113 Value getLengthForInitialShape() const { return getReservedSlot(LengthSlot); }
114 Value getNameForInitialShape() const { return getReservedSlot(NameSlot); }
116 // The [[Call]] and [[Construct]] hooks.
117 static bool call(JSContext* cx, unsigned argc, Value* vp);
118 static bool construct(JSContext* cx, unsigned argc, Value* vp);
120 // The JSFunToStringOp implementation for Function.prototype.toString.
121 static JSString* funToString(JSContext* cx, Handle<JSObject*> obj,
122 bool isToSource);
124 // Implementation of Function.prototype.bind.
125 static bool functionBind(JSContext* cx, unsigned argc, Value* vp);
127 static SharedShape* assignInitialShape(JSContext* cx,
128 Handle<BoundFunctionObject*> obj);
130 static BoundFunctionObject* functionBindImpl(
131 JSContext* cx, Handle<JSObject*> target, Value* args, uint32_t argc,
132 Handle<BoundFunctionObject*> maybeBound);
134 static BoundFunctionObject* createWithTemplate(
135 JSContext* cx, Handle<BoundFunctionObject*> templateObj);
136 static BoundFunctionObject* functionBindSpecializedBaseline(
137 JSContext* cx, Handle<JSObject*> target, Value* args, uint32_t argc,
138 Handle<BoundFunctionObject*> templateObj);
140 static BoundFunctionObject* createTemplateObject(JSContext* cx);
142 bool initTemplateSlotsForSpecializedBind(JSContext* cx, uint32_t numBoundArgs,
143 bool targetIsConstructor,
144 uint32_t targetLength,
145 JSAtom* targetName);
147 static constexpr size_t offsetOfTargetSlot() {
148 return getFixedSlotOffset(TargetSlot);
150 static constexpr size_t offsetOfFlagsSlot() {
151 return getFixedSlotOffset(FlagsSlot);
153 static constexpr size_t offsetOfBoundThisSlot() {
154 return getFixedSlotOffset(BoundThisSlot);
156 static constexpr size_t offsetOfFirstInlineBoundArg() {
157 return getFixedSlotOffset(BoundArg0Slot);
159 static constexpr size_t offsetOfLengthSlot() {
160 return getFixedSlotOffset(LengthSlot);
162 static constexpr size_t offsetOfNameSlot() {
163 return getFixedSlotOffset(NameSlot);
166 static constexpr size_t targetSlot() { return TargetSlot; }
167 static constexpr size_t boundThisSlot() { return BoundThisSlot; }
168 static constexpr size_t firstInlineBoundArgSlot() { return BoundArg0Slot; }
171 }; // namespace js
173 #endif /* vm_BoundFunctionObject_h */