Executable.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright (c) 2021-2024, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Bytecode/BasicBlock.h>
  7. #include <LibJS/Bytecode/Executable.h>
  8. #include <LibJS/Bytecode/Instruction.h>
  9. #include <LibJS/Bytecode/RegexTable.h>
  10. #include <LibJS/SourceCode.h>
  11. namespace JS::Bytecode {
  12. JS_DEFINE_ALLOCATOR(Executable);
  13. Executable::Executable(
  14. Vector<u8> bytecode,
  15. NonnullOwnPtr<IdentifierTable> identifier_table,
  16. NonnullOwnPtr<StringTable> string_table,
  17. NonnullOwnPtr<RegexTable> regex_table,
  18. Vector<Value> constants,
  19. NonnullRefPtr<SourceCode const> source_code,
  20. size_t number_of_property_lookup_caches,
  21. size_t number_of_global_variable_caches,
  22. size_t number_of_environment_variable_caches,
  23. size_t number_of_registers,
  24. bool is_strict_mode)
  25. : bytecode(move(bytecode))
  26. , string_table(move(string_table))
  27. , identifier_table(move(identifier_table))
  28. , regex_table(move(regex_table))
  29. , constants(move(constants))
  30. , source_code(move(source_code))
  31. , number_of_registers(number_of_registers)
  32. , is_strict_mode(is_strict_mode)
  33. {
  34. property_lookup_caches.resize(number_of_property_lookup_caches);
  35. global_variable_caches.resize(number_of_global_variable_caches);
  36. environment_variable_caches.resize(number_of_environment_variable_caches);
  37. }
  38. Executable::~Executable() = default;
  39. void Executable::dump() const
  40. {
  41. warnln("\033[37;1mJS bytecode executable\033[0m \"{}\"", name);
  42. InstructionStreamIterator it(bytecode, this);
  43. size_t basic_block_offset_index = 0;
  44. while (!it.at_end()) {
  45. bool print_basic_block_marker = false;
  46. if (basic_block_offset_index < basic_block_start_offsets.size()
  47. && it.offset() == basic_block_start_offsets[basic_block_offset_index]) {
  48. ++basic_block_offset_index;
  49. print_basic_block_marker = true;
  50. }
  51. StringBuilder builder;
  52. builder.appendff("[{:4x}] ", it.offset());
  53. if (print_basic_block_marker)
  54. builder.appendff("{:4}: ", basic_block_offset_index - 1);
  55. else
  56. builder.append(" "sv);
  57. builder.append((*it).to_byte_string(*this));
  58. warnln("{}", builder.string_view());
  59. ++it;
  60. }
  61. if (!exception_handlers.is_empty()) {
  62. warnln("");
  63. warnln("Exception handlers:");
  64. for (auto& handlers : exception_handlers) {
  65. warnln(" from {:4x} to {:4x} handler {:4x} finalizer {:4x}",
  66. handlers.start_offset,
  67. handlers.end_offset,
  68. handlers.handler_offset.value_or(0),
  69. handlers.finalizer_offset.value_or(0));
  70. }
  71. }
  72. warnln("");
  73. }
  74. void Executable::visit_edges(Visitor& visitor)
  75. {
  76. Base::visit_edges(visitor);
  77. visitor.visit(constants);
  78. }
  79. Optional<Executable::ExceptionHandlers const&> Executable::exception_handlers_for_offset(size_t offset) const
  80. {
  81. for (auto& handlers : exception_handlers) {
  82. if (handlers.start_offset <= offset && offset < handlers.end_offset)
  83. return handlers;
  84. }
  85. return {};
  86. }
  87. UnrealizedSourceRange Executable::source_range_at(size_t offset) const
  88. {
  89. if (offset >= bytecode.size())
  90. return {};
  91. auto it = InstructionStreamIterator(bytecode.span().slice(offset), this);
  92. VERIFY(!it.at_end());
  93. auto mapping = source_map.get(offset);
  94. if (!mapping.has_value())
  95. return {};
  96. return UnrealizedSourceRange {
  97. .source_code = source_code,
  98. .start_offset = mapping->source_start_offset,
  99. .end_offset = mapping->source_end_offset,
  100. };
  101. }
  102. }