LCOV - code coverage report
Current view: top level - gjs - jsapi-util.h (source / functions) Coverage Total Hit
Test: gjs-1.87.2 Code Coverage Lines: 100.0 % 9 9
Test Date: 2026-02-01 01:33:28 Functions: 100.0 % 2 2
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 100.0 % 4 4

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2008 litl, LLC
       4                 :             : // SPDX-FileCopyrightText: 2018-2020  Canonical, Ltd
       5                 :             : 
       6                 :             : #pragma once
       7                 :             : 
       8                 :             : #include <config.h>
       9                 :             : 
      10                 :             : #include <stdint.h>
      11                 :             : #include <stdlib.h>     // for free
      12                 :             : #include <sys/types.h>  // for ssize_t
      13                 :             : 
      14                 :             : #include <limits>
      15                 :             : #include <string>  // for string, u16string
      16                 :             : #include <type_traits>  // for enable_if_t, add_pointer_t, add_const_t
      17                 :             : #include <vector>
      18                 :             : 
      19                 :             : #include <glib-object.h>
      20                 :             : #include <glib.h>
      21                 :             : 
      22                 :             : #include <js/BigInt.h>
      23                 :             : #include <js/ErrorReport.h>  // for JSExnType
      24                 :             : #include <js/GCAPI.h>
      25                 :             : #include <js/GCPolicyAPI.h>  // for IgnoreGCPolicy
      26                 :             : #include <js/Id.h>
      27                 :             : #include <js/TypeDecls.h>
      28                 :             : #include <js/Utility.h>  // for UniqueChars
      29                 :             : 
      30                 :             : #include "gjs/auto.h"
      31                 :             : #include "gjs/gerror-result.h"
      32                 :             : #include "gjs/macros.h"
      33                 :             : #include "util/log.h"
      34                 :             : 
      35                 :             : #if GJS_VERBOSE_ENABLE_MARSHAL
      36                 :             : #    include "gi/arg-types-inl.h"  // for static_type_name
      37                 :             : #endif
      38                 :             : 
      39                 :             : namespace JS {
      40                 :             : class CallArgs;
      41                 :             : 
      42                 :             : struct Dummy {};
      43                 :             : using GTypeNotUint64 =
      44                 :             :     std::conditional_t<!std::is_same_v<GType, uint64_t>, GType, Dummy>;
      45                 :             : 
      46                 :             : // The GC sweep method should ignore FundamentalTable and GTypeTable's key types
      47                 :             : // Forward declarations
      48                 :             : template <>
      49                 :             : struct GCPolicy<void*> : public IgnoreGCPolicy<void*> {};
      50                 :             : // We need GCPolicy<GType> for GTypeTable. SpiderMonkey already defines
      51                 :             : // GCPolicy<uint64_t> which is equal to GType on some systems; for others we
      52                 :             : // need to define it. (macOS's uint64_t is unsigned long long, which is a
      53                 :             : // different type from unsigned long, even if they are the same width)
      54                 :             : template <>
      55                 :             : struct GCPolicy<GTypeNotUint64> : public IgnoreGCPolicy<GTypeNotUint64> {};
      56                 :             : }  // namespace JS
      57                 :             : 
      58                 :             : /* Flags that should be set on properties exported from native code modules.
      59                 :             :  * Basically set these on API, but do NOT set them on data.
      60                 :             :  *
      61                 :             :  * PERMANENT: forbid deleting the prop
      62                 :             :  * ENUMERATE: allows copyProperties to work among other reasons to have it
      63                 :             :  */
      64                 :             : #define GJS_MODULE_PROP_FLAGS (JSPROP_PERMANENT | JSPROP_ENUMERATE)
      65                 :             : 
      66                 :             : /**
      67                 :             :  * GJS_GET_THIS:
      68                 :             :  * @cx: JSContext pointer passed into JSNative function
      69                 :             :  * @argc: Number of arguments passed into JSNative function
      70                 :             :  * @vp: Argument value array passed into JSNative function
      71                 :             :  * @args: Name for JS::CallArgs variable defined by this code snippet
      72                 :             :  * @to: Name for JS::RootedObject variable referring to function's this
      73                 :             :  *
      74                 :             :  * A convenience macro for getting the 'this' object a function was called with.
      75                 :             :  * Use in any JSNative function.
      76                 :             :  */
      77                 :             : #define GJS_GET_THIS(cx, argc, vp, args, to)          \
      78                 :             :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
      79                 :             :     JS::RootedObject to(cx);                          \
      80                 :             :     if (!(args).computeThis(cx, &(to)))               \
      81                 :             :         return false;
      82                 :             : 
      83                 :             : void gjs_throw_constructor_error(JSContext*);
      84                 :             : 
      85                 :             : void gjs_throw_abstract_constructor_error(JSContext*, const JS::CallArgs&);
      86                 :             : 
      87                 :             : GJS_JSAPI_RETURN_CONVENTION
      88                 :             : JSObject* gjs_build_string_array(JSContext*, const std::vector<std::string>&);
      89                 :             : 
      90                 :             : GJS_JSAPI_RETURN_CONVENTION
      91                 :             : JSObject* gjs_define_string_array(JSContext*, JS::HandleObject,
      92                 :             :                                   const char* array_name,
      93                 :             :                                   const std::vector<std::string>&,
      94                 :             :                                   unsigned attrs);
      95                 :             : 
      96                 :             : [[gnu::format(printf, 2, 3)]]
      97                 :             : void gjs_throw(JSContext*, const char* format, ...);
      98                 :             : [[gnu::format(printf, 4, 5)]]
      99                 :             : void gjs_throw_custom(JSContext*, JSExnType, const char* error_name,
     100                 :             :                       const char* format, ...);
     101                 :             : void gjs_throw_literal(JSContext*, const char* string);
     102                 :             : bool gjs_throw_gerror_message(JSContext*, Gjs::AutoError const&);
     103                 :             : 
     104                 :             : bool gjs_log_exception(JSContext*);
     105                 :             : 
     106                 :             : bool gjs_log_exception_uncaught(JSContext*);
     107                 :             : 
     108                 :             : void gjs_log_exception_full(JSContext*, JS::HandleValue exc,
     109                 :             :                             JS::HandleString message, GLogLevelFlags);
     110                 :             : 
     111                 :             : void gjs_warning_reporter(JSContext*, JSErrorReport*);
     112                 :             : 
     113                 :             : GJS_JSAPI_RETURN_CONVENTION
     114                 :             : JS::UniqueChars gjs_string_to_utf8(JSContext*, const JS::Value string_val);
     115                 :             : GJS_JSAPI_RETURN_CONVENTION
     116                 :             : bool gjs_string_to_utf8_n(JSContext*, JS::HandleString str,
     117                 :             :                           JS::UniqueChars* output, size_t* output_len);
     118                 :             : GJS_JSAPI_RETURN_CONVENTION
     119                 :             : JSString* gjs_lossy_string_from_utf8(JSContext*, const char* utf8_string);
     120                 :             : GJS_JSAPI_RETURN_CONVENTION
     121                 :             : JSString* gjs_lossy_string_from_utf8_n(JSContext*, const char* utf8_string,
     122                 :             :                                        size_t len);
     123                 :             : GJS_JSAPI_RETURN_CONVENTION
     124                 :             : bool gjs_string_from_utf8(JSContext*, const char* utf8_string,
     125                 :             :                           JS::MutableHandleValue);
     126                 :             : GJS_JSAPI_RETURN_CONVENTION
     127                 :             : bool gjs_string_from_utf8_n(JSContext*, const char* utf8_chars, size_t len,
     128                 :             :                             JS::MutableHandleValue);
     129                 :             : 
     130                 :             : GJS_JSAPI_RETURN_CONVENTION
     131                 :             : bool gjs_string_to_filename(JSContext*, const JS::Value,
     132                 :             :                             Gjs::AutoChar* filename_string);
     133                 :             : 
     134                 :             : GJS_JSAPI_RETURN_CONVENTION
     135                 :             : bool gjs_string_from_filename(JSContext*, const char* filename_string,
     136                 :             :                               ssize_t n_bytes, JS::MutableHandleValue);
     137                 :             : 
     138                 :             : GJS_JSAPI_RETURN_CONVENTION
     139                 :             : bool gjs_string_get_char16_data(JSContext*, JS::HandleString, char16_t** data_p,
     140                 :             :                                 size_t* len_p);
     141                 :             : 
     142                 :             : GJS_JSAPI_RETURN_CONVENTION
     143                 :             : bool gjs_string_to_ucs4(JSContext*, JS::HandleString, gunichar** ucs4_string_p,
     144                 :             :                         size_t* len_p);
     145                 :             : GJS_JSAPI_RETURN_CONVENTION
     146                 :             : bool gjs_string_from_ucs4(JSContext*, const gunichar* ucs4_string,
     147                 :             :                           ssize_t n_chars, JS::MutableHandleValue);
     148                 :             : 
     149                 :             : GJS_JSAPI_RETURN_CONVENTION
     150                 :             : bool gjs_get_string_id(JSContext*, jsid, JS::UniqueChars* name_p);
     151                 :             : GJS_JSAPI_RETURN_CONVENTION
     152                 :             : jsid gjs_intern_string_to_id(JSContext*, const char* string);
     153                 :             : 
     154                 :             : GJS_JSAPI_RETURN_CONVENTION
     155                 :             : bool gjs_unichar_from_string(JSContext*, JS::Value string, gunichar* result);
     156                 :             : 
     157                 :             : // Functions intended for more "internal" use
     158                 :             : 
     159                 :             : void gjs_maybe_gc(JSContext*);
     160                 :             : void gjs_gc_if_needed(JSContext*);
     161                 :             : 
     162                 :             : GJS_JSAPI_RETURN_CONVENTION
     163                 :             : JS::UniqueChars format_saved_frame(JSContext*, JS::HandleObject saved_frame,
     164                 :             :                                    size_t indent = 0);
     165                 :             : 
     166                 :             : /* Overloaded functions. More types are intended to be added as the opportunity
     167                 :             :  * arises. */
     168                 :             : 
     169                 :             : GJS_JSAPI_RETURN_CONVENTION
     170                 :             : bool gjs_object_require_property(JSContext*, JS::HandleObject,
     171                 :             :                                  const char* obj_description,
     172                 :             :                                  JS::HandleId property_name,
     173                 :             :                                  JS::MutableHandleValue);
     174                 :             : 
     175                 :             : GJS_JSAPI_RETURN_CONVENTION
     176                 :             : bool gjs_object_require_property(JSContext*, JS::HandleObject,
     177                 :             :                                  const char* description,
     178                 :             :                                  JS::HandleId property_name, bool* value);
     179                 :             : 
     180                 :             : GJS_JSAPI_RETURN_CONVENTION
     181                 :             : bool gjs_object_require_property(JSContext*, JS::HandleObject,
     182                 :             :                                  const char* description,
     183                 :             :                                  JS::HandleId property_name, int32_t* value);
     184                 :             : 
     185                 :             : GJS_JSAPI_RETURN_CONVENTION
     186                 :             : bool gjs_object_require_property(JSContext*, JS::HandleObject,
     187                 :             :                                  const char* description,
     188                 :             :                                  JS::HandleId property_name,
     189                 :             :                                  JS::UniqueChars* value);
     190                 :             : 
     191                 :             : GJS_JSAPI_RETURN_CONVENTION
     192                 :             : bool gjs_object_require_property(JSContext*, JS::HandleObject,
     193                 :             :                                  const char* description,
     194                 :             :                                  JS::HandleId property_name,
     195                 :             :                                  JS::MutableHandleObject value);
     196                 :             : 
     197                 :             : GJS_JSAPI_RETURN_CONVENTION
     198                 :             : bool gjs_object_require_converted_property(JSContext*, JS::HandleObject,
     199                 :             :                                            const char* description,
     200                 :             :                                            JS::HandleId property_name,
     201                 :             :                                            uint32_t*);
     202                 :             : 
     203                 :             : [[nodiscard]] std::string gjs_debug_bigint(JS::BigInt*);
     204                 :             : [[nodiscard]] std::string gjs_debug_string(JSString*);
     205                 :             : [[nodiscard]] std::string gjs_debug_symbol(JS::Symbol* const);
     206                 :             : [[nodiscard]] std::string gjs_debug_object(JSObject*);
     207                 :             : [[nodiscard]] std::string gjs_debug_callable(JSObject* callable);
     208                 :             : [[nodiscard]] std::string gjs_debug_value(JS::Value);
     209                 :             : [[nodiscard]] std::string gjs_debug_id(jsid);
     210                 :             : 
     211                 :             : [[nodiscard]] Gjs::AutoChar gjs_hyphen_to_underscore(const char*);
     212                 :             : [[nodiscard]] Gjs::AutoChar gjs_hyphen_to_camel(const char*);
     213                 :             : 
     214                 :             : #if defined(G_OS_WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1900))
     215                 :             : [[nodiscard]] std::wstring gjs_win32_vc140_utf8_to_utf16(const char*);
     216                 :             : #endif
     217                 :             : 
     218                 :             : // Custom GC reasons; SpiderMonkey includes a bunch of "Firefox reasons" which
     219                 :             : // don't apply when embedding the JS engine, so we repurpose them for our own
     220                 :             : // reasons.
     221                 :             : 
     222                 :             : // clang-format off
     223                 :             : #define FOREACH_GC_REASON(macro)  \
     224                 :             :     macro(LINUX_RSS_TRIGGER, 0)   \
     225                 :             :     macro(GJS_CONTEXT_DISPOSE, 1) \
     226                 :             :     macro(BIG_HAMMER, 2)          \
     227                 :             :     macro(GJS_API_CALL, 3)        \
     228                 :             :     macro(LOW_MEMORY, 4)
     229                 :             : // clang-format on
     230                 :             : 
     231                 :             : namespace Gjs {
     232                 :             : 
     233                 :             : struct GCReason {
     234                 :             : #define DEFINE_GC_REASON(name, ix)                     \
     235                 :             :     static constexpr JS::GCReason name = JS::GCReason( \
     236                 :             :         static_cast<int>(JS::GCReason::FIRST_FIREFOX_REASON) + (ix));
     237                 :             : FOREACH_GC_REASON(DEFINE_GC_REASON);
     238                 :             : #undef DEFINE_GC_REASON
     239                 :             : 
     240                 :             : #define COUNT_GC_REASON(name, ix) +1  // NOLINT(bugprone-macro-parentheses)
     241                 :             : static constexpr size_t N_REASONS = 0 FOREACH_GC_REASON(COUNT_GC_REASON);
     242                 :             : #undef COUNT_GC_REASON
     243                 :             : };
     244                 :             : 
     245                 :             : template <typename T>
     246                 :             : [[nodiscard]]
     247                 :        1703 : bool bigint_is_out_of_range(JS::BigInt* bi, T* clamped) {
     248                 :             :     static_assert(sizeof(T) == 8, "64-bit types only");
     249                 :        1703 :     g_assert(bi && "bigint cannot be null");
     250                 :        1703 :     g_assert(clamped && "forgot out parameter");
     251                 :             : 
     252                 :             :     gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
     253                 :             :                       "Checking if BigInt %s is out of range for type %s",
     254                 :             :                       gjs_debug_bigint(bi).c_str(), Gjs::static_type_name<T>());
     255                 :             : 
     256         [ +  + ]:        1703 :     if (JS::BigIntFits(bi, clamped)) {
     257                 :             :         gjs_debug_marshal(
     258                 :             :             GJS_DEBUG_GFUNCTION, "BigInt %s is in the range of type %s",
     259                 :             :             std::to_string(*clamped).c_str(), Gjs::static_type_name<T>());
     260                 :        1685 :         return false;
     261                 :             :     }
     262                 :             : 
     263         [ +  + ]:          18 :     if (JS::BigIntIsNegative(bi)) {
     264                 :          10 :         *clamped = std::numeric_limits<T>::min();
     265                 :             :     } else {
     266                 :           8 :         *clamped = std::numeric_limits<T>::max();
     267                 :             :     }
     268                 :             : 
     269                 :             :     gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
     270                 :             :                       "BigInt %s is not in the range of type %s, clamped to %s",
     271                 :             :                       gjs_debug_bigint(bi).c_str(), Gjs::static_type_name<T>(),
     272                 :             :                       std::to_string(*clamped).c_str());
     273                 :          18 :     return true;
     274                 :             : }
     275                 :             : 
     276                 :             : }  // namespace Gjs
     277                 :             : 
     278                 :             : [[nodiscard]] const char* gjs_explain_gc_reason(JS::GCReason);
        

Generated by: LCOV version 2.0-1