HandlerFunction-inl.h (3893B)
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/. */ 6 7 /* 8 * Handler for operations that act on a target object, and possibly upon 9 * an extra value. 10 */ 11 12 #ifndef builtin_HandlerFunction_inl_h 13 #define builtin_HandlerFunction_inl_h 14 15 #include <stddef.h> // size_t 16 17 #include "gc/AllocKind.h" // js::gc::AllocKind 18 #include "js/CallArgs.h" // JS::CallArgs 19 #include "js/RootingAPI.h" // JS::Handle 20 #include "js/Value.h" // JS::ObjectValue 21 #include "vm/JSContext.h" // JSContext 22 #include "vm/JSFunction.h" // JSFunction, js::Native, js::NewNativeFunction 23 #include "vm/JSObject.h" // JSObject, js::GenericObject 24 #include "vm/StringType.h" // js::PropertyName 25 26 #include "vm/JSContext-inl.h" // JSContext::check 27 28 namespace js { 29 30 // Handler functions are extended functions, that close over a target object and 31 // (optionally) over an extra object, storing those objects in the function's 32 // extended slots. 33 constexpr size_t HandlerFunctionSlot_Target = 0; 34 constexpr size_t HandlerFunctionSlot_Extra = 1; 35 36 static_assert(HandlerFunctionSlot_Extra < FunctionExtended::NUM_EXTENDED_SLOTS, 37 "handler function slots shouldn't exceed available extended " 38 "slots"); 39 40 [[nodiscard]] inline JSFunction* NewHandler(JSContext* cx, Native handler, 41 JS::Handle<JSObject*> target) { 42 cx->check(target); 43 44 JS::Handle<PropertyName*> funName = cx->names().empty_; 45 JSFunction* handlerFun = NewNativeFunction( 46 cx, handler, 0, funName, gc::AllocKind::FUNCTION_EXTENDED, GenericObject); 47 if (!handlerFun) { 48 return nullptr; 49 } 50 handlerFun->setExtendedSlot(HandlerFunctionSlot_Target, 51 JS::ObjectValue(*target)); 52 return handlerFun; 53 } 54 55 [[nodiscard]] inline JSFunction* NewHandlerWithExtra( 56 JSContext* cx, Native handler, JS::Handle<JSObject*> target, 57 JS::Handle<JSObject*> extra) { 58 cx->check(extra); 59 JSFunction* handlerFun = NewHandler(cx, handler, target); 60 if (handlerFun) { 61 handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra, 62 JS::ObjectValue(*extra)); 63 } 64 return handlerFun; 65 } 66 67 [[nodiscard]] inline JSFunction* NewHandlerWithExtraValue( 68 JSContext* cx, Native handler, JS::Handle<JSObject*> target, 69 JS::Handle<JS::Value> extra) { 70 cx->check(extra); 71 JSFunction* handlerFun = NewHandler(cx, handler, target); 72 if (handlerFun) { 73 handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra, extra); 74 } 75 return handlerFun; 76 } 77 78 /** 79 * Within the call of a handler function that "closes over" a target value that 80 * is always a |T*| object (and never a wrapper around one), return that |T*|. 81 */ 82 template <class T> 83 [[nodiscard]] inline T* TargetFromHandler(const JS::CallArgs& args) { 84 JSFunction& func = args.callee().as<JSFunction>(); 85 return &func.getExtendedSlot(HandlerFunctionSlot_Target).toObject().as<T>(); 86 } 87 88 /** 89 * Within the call of a handler function that "closes over" a target value and 90 * an extra value, return that extra value. 91 */ 92 [[nodiscard]] inline JS::Value ExtraValueFromHandler(const JS::CallArgs& args) { 93 JSFunction& func = args.callee().as<JSFunction>(); 94 return func.getExtendedSlot(HandlerFunctionSlot_Extra); 95 } 96 97 /** 98 * Within the call of a handler function that "closes over" a target value and 99 * an extra value, where that extra value is always a |T*| object (and never a 100 * wrapper around one), return that |T*|. 101 */ 102 template <class T> 103 [[nodiscard]] inline T* ExtraFromHandler(const JS::CallArgs& args) { 104 return &ExtraValueFromHandler(args).toObject().as<T>(); 105 } 106 107 } // namespace js 108 109 #endif // builtin_HandlerFunction_inl_h