Skip to content

Commit 2bec236

Browse files
ADKasterlinusg
authored andcommitted
LibJS: Use the EnumerateObjectProperties AO to print objects
Instead of just iterating indexed properties and direct properties on the object's shape, let's walk the prototype chain and grab every non-symbol property by re-using the AO for for-in statements. We'll probably want to move this to a custom algorithm just for pretty printing that doesn't skip some property types, but this already gives a major improvement when printing LegacyPlatformObjects from LibWeb to the console.
1 parent f40094d commit 2bec236

File tree

1 file changed

+34
-18
lines changed

1 file changed

+34
-18
lines changed

Userland/Libraries/LibJS/Print.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -188,29 +188,45 @@ ErrorOr<void> print_array(JS::PrintContext& print_context, JS::Array const& arra
188188

189189
ErrorOr<void> print_object(JS::PrintContext& print_context, JS::Object const& object, HashTable<JS::Object*>& seen_objects)
190190
{
191-
TRY(js_out(print_context, "{{"));
191+
TRY(js_out(print_context, "{}{{", object.class_name()));
192192
bool first = true;
193-
for (auto& entry : object.indexed_properties()) {
194-
TRY(print_separator(print_context, first));
195-
TRY(js_out(print_context, "\"\033[33;1m{}\033[0m\": ", entry.index()));
196-
auto value_or_error = object.get(entry.index());
197-
// The V8 repl doesn't throw an exception here, and instead just
193+
static constexpr size_t max_number_of_new_objects = 20; // Arbitrary limit
194+
size_t original_num_seen_objects = seen_objects.size();
195+
196+
auto maybe_completion = object.enumerate_object_properties([&](JS::Value property_key) -> Optional<JS::Completion> {
197+
// The V8 repl doesn't throw an exception on accessing properties, and instead just
198198
// prints 'undefined'. We may choose to replicate that behavior in
199199
// the future, but for now lets just catch the error
200+
auto error = print_separator(print_context, first);
201+
if (error.is_error())
202+
return JS::js_undefined();
203+
error = js_out(print_context, "\033[33;1m");
204+
if (error.is_error())
205+
return JS::js_undefined();
206+
error = print_value(print_context, property_key, seen_objects);
207+
// NOTE: Ignore this error to always print out "reset" ANSI sequence
208+
error = js_out(print_context, "\033[0m: ");
209+
if (error.is_error())
210+
return JS::js_undefined();
211+
auto maybe_property_key = JS::PropertyKey::from_value(print_context.vm, property_key);
212+
if (maybe_property_key.is_error())
213+
return JS::js_undefined();
214+
auto value_or_error = object.get(maybe_property_key.value());
200215
if (value_or_error.is_error())
201-
return {};
216+
return JS::js_undefined();
202217
auto value = value_or_error.release_value();
203-
TRY(print_value(print_context, value, seen_objects));
204-
}
205-
for (auto& it : object.shape().property_table_ordered()) {
206-
TRY(print_separator(print_context, first));
207-
if (it.key.is_string()) {
208-
TRY(js_out(print_context, "\"\033[33;1m{}\033[0m\": ", it.key.to_display_string()));
209-
} else {
210-
TRY(js_out(print_context, "[\033[33;1m{}\033[0m]: ", it.key.to_display_string()));
211-
}
212-
TRY(print_value(print_context, object.get_direct(it.value.offset), seen_objects));
213-
}
218+
error = print_value(print_context, value, seen_objects);
219+
// FIXME: Come up with a better way to structure the data so that we don't care about this limit
220+
if (seen_objects.size() > original_num_seen_objects + max_number_of_new_objects)
221+
return JS::js_undefined(); // Stop once we've seen a ton of objects, to prevent spamming the console.
222+
if (error.is_error())
223+
return JS::js_undefined();
224+
return {};
225+
});
226+
// Swallow Error/undefined from printing properties
227+
if (maybe_completion.has_value())
228+
return {};
229+
214230
if (!first)
215231
TRY(js_out(print_context, " "));
216232
TRY(js_out(print_context, "}}"));

0 commit comments

Comments
 (0)