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 : :
5 : : #include <config.h>
6 : :
7 : : #include <iterator> // for size
8 : : #include <span>
9 : :
10 : : #include <girepository/girepository.h>
11 : : #include <glib-object.h>
12 : : #include <glib.h>
13 : :
14 : : #include <mozilla/CheckedInt.h>
15 : : #include <mozilla/Maybe.h>
16 : : #include <mozilla/Result.h>
17 : :
18 : : #include "gi/arg-inl.h"
19 : : #include "gi/info.h"
20 : : #include "gjs/mem-private.h" // IWYU pragma: associated
21 : : #include "gjs/mem.h"
22 : : #include "util/log.h"
23 : :
24 : : namespace Gjs::Memory::Counters {
25 : : #define GJS_DEFINE_COUNTER(name, ix) Counter name(#name);
26 : :
27 : : GJS_DEFINE_COUNTER(everything, -1)
28 : : GJS_FOR_EACH_COUNTER(GJS_DEFINE_COUNTER)
29 : : } // namespace Gjs::Memory::Counters
30 : :
31 : : #define GJS_LIST_COUNTER(name, ix) &Gjs::Memory::Counters::name,
32 : :
33 : : static Gjs::Memory::Counter* counters[] = {
34 : : GJS_FOR_EACH_COUNTER(GJS_LIST_COUNTER)};
35 : :
36 : 102 : void gjs_memory_report(const char* where, bool die_if_leaks) {
37 : 102 : gjs_debug(GJS_DEBUG_MEMORY, "Memory report: {}", where);
38 : :
39 : 102 : size_t n_counters = std::size(counters);
40 : :
41 : 102 : int64_t total_objects = 0;
42 [ + + ]: 1734 : for (size_t i = 0; i < n_counters; ++i) {
43 : 1632 : total_objects += counters[i]->value;
44 : : }
45 : :
46 [ - + ]: 102 : if (total_objects != GJS_GET_COUNTER(everything)) {
47 : 0 : gjs_debug(GJS_DEBUG_MEMORY,
48 : : "Object counts don't add up!");
49 : : }
50 : :
51 : 204 : gjs_debug(GJS_DEBUG_MEMORY, " {} objects currently alive",
52 : 102 : GJS_GET_COUNTER(everything));
53 : :
54 [ + + ]: 102 : if (GJS_GET_COUNTER(everything) != 0) {
55 [ + + ]: 867 : for (size_t i = 0; i < n_counters; ++i) {
56 : 1632 : gjs_debug(GJS_DEBUG_MEMORY, " {:>24} = {}", counters[i]->name,
57 : 1632 : counters[i]->value.load());
58 : : }
59 : :
60 [ - + ]: 51 : if (die_if_leaks)
61 : 0 : gjs_error("{}: JavaScript objects were leaked", where);
62 : : }
63 : 102 : }
64 : :
65 : 1 : int32_t estimate_size_of_gdkpixbuf(GObject* wrapped) {
66 : 1 : GI::Repository repo;
67 : 1 : GI::AutoObjectInfo gdkpixbuf_info{
68 : 2 : repo.find_by_name<GI::InfoTag::OBJECT>("GdkPixbuf", "Pixbuf")
69 : 1 : .value()};
70 : 1 : GI::AutoFunctionInfo get_width_func{
71 : 1 : gdkpixbuf_info.method("get_width").value()};
72 : 1 : GI::AutoFunctionInfo get_height_func{
73 : 1 : gdkpixbuf_info.method("get_height").value()};
74 : 1 : GI::AutoFunctionInfo get_bits_per_sample_func{
75 : 1 : gdkpixbuf_info.method("get_bits_per_sample").value()};
76 : : GIArgument args;
77 : 1 : gjs_arg_set(&args, wrapped);
78 : : GIArgument width, height, bits_per_sample;
79 : 1 : auto result_width = get_width_func.invoke({{args}}, {}, &width);
80 : 1 : auto result_height = get_height_func.invoke({{args}}, {}, &height);
81 : 1 : auto result_bits_per_sample =
82 : 1 : get_bits_per_sample_func.invoke({{args}}, {}, &bits_per_sample);
83 [ + - + - : 2 : if (result_width.isErr() || result_height.isErr() ||
- + - + ]
84 : 1 : result_bits_per_sample.isErr()) {
85 : 0 : gjs_debug(GJS_DEBUG_MEMORY, "Failed to estimate GdkPixbuf size");
86 : 0 : return 0;
87 : : }
88 : 1 : int width_int = gjs_arg_get<int>(&width);
89 : 1 : int height_int = gjs_arg_get<int>(&height);
90 : 1 : int bits_per_sample_int = gjs_arg_get<int>(&bits_per_sample);
91 : 1 : mozilla::CheckedInt32 estimated_size =
92 : 1 : mozilla::CheckedInt32{width_int} * height_int * bits_per_sample_int;
93 [ - + ]: 1 : if (!estimated_size.isValid())
94 : 0 : return INT32_MAX;
95 : 1 : return estimated_size.value();
96 : 1 : }
|