From c237ac8e23307eecf781feb8c2feefb633f48ef4 Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Mon, 4 Aug 2025 10:23:41 -0700 Subject: [PATCH] [vm] Extract runtime offsets as JSON Print constants as JSON in runtime/vm/compiler/offsets_extractor.cc instead of generating C++ declarations. tools/run_offsets_extractor.dart reads JSON and generates C++ declarations (runtime/vm/compiler/runtime_offsets_extracted.h). This would allow us to have different output formats in future (e.g. C++ and Dart). TEST=dart tools/run_offsets_extractor.dart Change-Id: Ib8576766ae8cc21583b5a7b27998fd88b733b3a1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/443140 Reviewed-by: Ryan Macnak Commit-Queue: Alexander Markov --- runtime/vm/compiler/offsets_extractor.cc | 133 ++++++++--------------- tools/run_offsets_extractor.dart | 117 ++++++++++++++++---- 2 files changed, 142 insertions(+), 108 deletions(-) diff --git a/runtime/vm/compiler/offsets_extractor.cc b/runtime/vm/compiler/offsets_extractor.cc index 728f744658b..41ab5025701 100644 --- a/runtime/vm/compiler/offsets_extractor.cc +++ b/runtime/vm/compiler/offsets_extractor.cc @@ -18,39 +18,38 @@ #include "vm/timeline.h" #if defined(PRODUCT) -#define PRODUCT_DEF "defined(PRODUCT)" +#define PRODUCT_DEF "true" #else -#define PRODUCT_DEF "!defined(PRODUCT)" +#define PRODUCT_DEF "false" #endif #if defined(TARGET_ARCH_ARM) -#define ARCH_DEF_CPU "defined(TARGET_ARCH_ARM)" +#define ARCH_DEF_CPU "arm" #elif defined(TARGET_ARCH_X64) -#define ARCH_DEF_CPU "defined(TARGET_ARCH_X64)" +#define ARCH_DEF_CPU "x64" #elif defined(TARGET_ARCH_IA32) -#define ARCH_DEF_CPU "defined(TARGET_ARCH_IA32)" +#define ARCH_DEF_CPU "ia32" #elif defined(TARGET_ARCH_ARM64) -#define ARCH_DEF_CPU "defined(TARGET_ARCH_ARM64)" +#define ARCH_DEF_CPU "arm64" #elif defined(TARGET_ARCH_RISCV32) -#define ARCH_DEF_CPU "defined(TARGET_ARCH_RISCV32)" +#define ARCH_DEF_CPU "riscv32" #elif defined(TARGET_ARCH_RISCV64) -#define ARCH_DEF_CPU "defined(TARGET_ARCH_RISCV64)" +#define ARCH_DEF_CPU "riscv64" #else #error Unknown architecture #endif #if defined(DART_COMPRESSED_POINTERS) -#define COMPRESSED_DEF "defined(DART_COMPRESSED_POINTERS)" +#define COMPRESSED_DEF "true" #else -#define COMPRESSED_DEF "!defined(DART_COMPRESSED_POINTERS)" +#define COMPRESSED_DEF "false" #endif -#define PREPROCESSOR_CONDITION \ - "#if " PRODUCT_DEF " && " ARCH_DEF_CPU " && " COMPRESSED_DEF - -#define PREPROCESSOR_CONDITION_END \ - "#endif // " PRODUCT_DEF " && \n // " ARCH_DEF_CPU \ - " && \n // " COMPRESSED_DEF +#if defined(DART_PRECOMPILED_RUNTIME) +#define AOT_DEF "true" +#else +#define AOT_DEF "false" +#endif namespace dart { @@ -73,100 +72,57 @@ class OffsetsExtractor : public AllStatic { #define PRINT_ARRAY_SIZEOF(Class, Name, ElementOffset) #define PRINT_PAYLOAD_SIZEOF(Class, Name, HeaderSize) -#if defined(DART_PRECOMPILED_RUNTIME) - #define PRINT_FIELD_OFFSET(Class, Name) \ - std::cout << "static constexpr dart::compiler::target::word AOT_" #Class \ - "_" #Name " = 0x" \ - << Class::Name() << ";\n"; + std::cout << "{\"kind\": \"value\"," \ + " \"class\": \"" #Class "\", \"name\": \"" #Name \ + "\", \"value\": \"" \ + << Class::Name() << "\"},\n"; #define PRINT_ARRAY_LAYOUT(Class, Name) \ - std::cout << "static constexpr dart::compiler::target::word AOT_" #Class \ - "_elements_start_offset = 0x" \ - << Class::ArrayTraits::elements_start_offset() << ";\n"; \ - std::cout << "static constexpr dart::compiler::target::word AOT_" #Class \ - "_element_size = 0x" \ - << Class::ArrayTraits::kElementSize << ";\n"; + std::cout << "{\"kind\": \"array\"," \ + " \"class\": \"" #Class "\", \"startOffset\": \"" \ + << Class::ArrayTraits::elements_start_offset() \ + << "\", \"elemSize\": \"" << Class::ArrayTraits::kElementSize \ + << "\"},\n"; #define PRINT_SIZEOF(Class, Name, What) \ - std::cout << "static constexpr dart::compiler::target::word AOT_" #Class \ - "_" #Name " = 0x" \ - << sizeof(What) << ";\n"; + std::cout << "{\"kind\": \"value\"," \ + " \"class\": \"" #Class "\", \"name\": \"" #Name \ + "\", \"value\": \"" \ + << sizeof(What) << "\"},\n"; #define PRINT_RANGE(Class, Name, Type, First, Last, Filter) \ { \ auto filter = Filter; \ bool comma = false; \ - std::cout << "static constexpr dart::compiler::target::word AOT_" #Class \ - "_" #Name "[] = {"; \ + std::cout << "{\"kind\": \"range\"," \ + " \"class\": \"" #Class "\", \"name\": \"" #Name \ + "\", \"values\": ["; \ for (intptr_t i = static_cast(First); \ i <= static_cast(Last); i++) { \ auto v = static_cast(i); \ std::cout << (comma ? ", " : ""); \ if (filter(v)) { \ - std::cout << "0x" << Class::Name(v); \ + std::cout << "\"" << Class::Name(v) << "\""; \ } else { \ - std::cout << "-1"; \ + std::cout << "\"-1\""; \ } \ comma = true; \ } \ - std::cout << "};\n"; \ + std::cout << "]},\n"; \ } #define PRINT_CONSTANT(Class, Name) \ - std::cout << "static constexpr dart::compiler::target::word AOT_" #Class \ - "_" #Name " = 0x" \ - << Class::Name << ";\n"; + std::cout << "{\"kind\": \"value\"," \ + " \"class\": \"" #Class "\", \"name\": \"" #Name \ + "\", \"value\": \"" \ + << Class::Name << "\"},\n"; +#if defined(DART_PRECOMPILED_RUNTIME) AOT_OFFSETS_LIST(PRINT_FIELD_OFFSET, PRINT_ARRAY_LAYOUT, PRINT_SIZEOF, PRINT_ARRAY_SIZEOF, PRINT_PAYLOAD_SIZEOF, PRINT_RANGE, PRINT_CONSTANT) - #else // defined(DART_PRECOMPILED_RUNTIME) - -#define PRINT_FIELD_OFFSET(Class, Name) \ - std::cout << "static constexpr dart::compiler::target::word " #Class \ - "_" #Name " = 0x" \ - << Class::Name() << ";\n"; - -#define PRINT_ARRAY_LAYOUT(Class, Name) \ - std::cout << "static constexpr dart::compiler::target::word " #Class \ - "_elements_start_offset = 0x" \ - << Class::ArrayTraits::elements_start_offset() << ";\n"; \ - std::cout << "static constexpr dart::compiler::target::word " #Class \ - "_element_size = 0x" \ - << Class::ArrayTraits::kElementSize << ";\n"; - -#define PRINT_SIZEOF(Class, Name, What) \ - std::cout << "static constexpr dart::compiler::target::word " #Class \ - "_" #Name " = 0x" \ - << sizeof(What) << ";\n"; - -#define PRINT_RANGE(Class, Name, Type, First, Last, Filter) \ - { \ - auto filter = Filter; \ - bool comma = false; \ - std::cout << "static constexpr dart::compiler::target::word " #Class \ - "_" #Name "[] = {"; \ - for (intptr_t i = static_cast(First); \ - i <= static_cast(Last); i++) { \ - auto v = static_cast(i); \ - std::cout << (comma ? ", " : ""); \ - if (filter(v)) { \ - std::cout << "0x" << Class::Name(v); \ - } else { \ - std::cout << "-1"; \ - } \ - comma = true; \ - } \ - std::cout << "};\n"; \ - } - -#define PRINT_CONSTANT(Class, Name) \ - std::cout << "static constexpr dart::compiler::target::word " #Class \ - "_" #Name " = 0x" \ - << Class::Name << ";\n"; - JIT_OFFSETS_LIST(PRINT_FIELD_OFFSET, PRINT_ARRAY_LAYOUT, PRINT_SIZEOF, PRINT_ARRAY_SIZEOF, PRINT_PAYLOAD_SIZEOF, PRINT_RANGE, PRINT_CONSTANT) @@ -190,10 +146,17 @@ class OffsetsExtractor : public AllStatic { } // namespace dart int main(int argc, char* argv[]) { - std::cout << std::hex << PREPROCESSOR_CONDITION << std::endl; + std::cout << "{\n"; + std::cout << "\"product\": " PRODUCT_DEF ",\n"; + std::cout << "\"arch\": \"" ARCH_DEF_CPU "\",\n"; + std::cout << "\"compressed\": " COMPRESSED_DEF ",\n"; + std::cout << "\"aot\": " AOT_DEF ",\n"; + std::cout << "\"offsets\": [\n"; #if !defined(TARGET_ARCH_IA32) || !defined(DART_PRECOMPILED_RUNTIME) dart::OffsetsExtractor::DumpOffsets(); #endif - std::cout << PREPROCESSOR_CONDITION_END << std::endl; + std::cout << "{\"kind\": \"\"}\n"; // Terminate the list after comma. + std::cout << "]\n"; + std::cout << "}\n"; return 0; } diff --git a/tools/run_offsets_extractor.dart b/tools/run_offsets_extractor.dart index 375d29d1f28..077d48f306f 100755 --- a/tools/run_offsets_extractor.dart +++ b/tools/run_offsets_extractor.dart @@ -3,23 +3,14 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:convert' as convert show json; import 'dart:io'; import 'package:pool/pool.dart'; final pool = Pool(Platform.numberOfProcessors); -void main(List args) async { - final sdkRoot = Platform.script.resolve('../').toFilePath(); - Directory.current = Directory(sdkRoot); - - final extractedOffsetsFile = - 'runtime/vm/compiler/runtime_offsets_extracted.h'; - - final old = File(extractedOffsetsFile).readAsStringSync(); - final header = old.substring(0, old.indexOf('\n#if ')); - final footer = old.substring(old.lastIndexOf('\n#endif ')); - +Future buildOffsetsExtractor(List args) async { // Build all configurations await forAllConfigurationsMode(( String buildDir, @@ -38,27 +29,88 @@ void main(List args) async { ]); print('Building $buildDir - done'); }); +} +Future runOffsetsExtractor() async { final (jit, aot) = await ( forAllConfigurationsMode((String buildDir, _, __) async { return await run(['$buildDir/offsets_extractor']); - }).then((lines) => lines.join('\n')), + }).then((lines) => lines.join(',\n')), forAllConfigurationsMode((String buildDir, _, __) async { return await run(['$buildDir/offsets_extractor_aotruntime']); - }).then((lines) => lines.join('\n')), + }).then((lines) => lines.join(',\n')), ).wait; - if (exitCode == 0) { - final output = StringBuffer(); - output.writeln(header); - output.writeln(jit); - output.writeln(aot); - output.writeln(footer); - File(extractedOffsetsFile).writeAsStringSync(output.toString()); - print('Written $extractedOffsetsFile'); - print('Running `git cl format $extractedOffsetsFile'); - await run(['git', 'cl', 'format', extractedOffsetsFile]); + final buf = StringBuffer(); + buf.writeln('['); + buf.writeln(jit); + buf.writeln(','); + buf.writeln(aot); + buf.writeln(']'); + return buf.toString(); +} + +String toCValue(Object? value) { + final intValue = int.parse(value as String); + if (intValue == -1) return '-1'; + return '0x${intValue.toRadixString(16)}'; +} + +Future writeCHeaderFile(List json) async { + final extractedOffsetsFile = + 'runtime/vm/compiler/runtime_offsets_extracted.h'; + + final old = File(extractedOffsetsFile).readAsStringSync(); + final header = old.substring(0, old.indexOf('\n#if ')); + final footer = old.substring(old.lastIndexOf('\n#endif ')); + + final output = StringBuffer(); + output.writeln(header); + for (final config in json) { + final product = (config['product'] as bool) ? '' : '!'; + final productDef = '${product}defined(PRODUCT)'; + final arch = (config['arch'] as String).toUpperCase(); + final archDef = 'defined(TARGET_ARCH_$arch)'; + final compressed = (config['compressed'] as bool) ? '' : '!'; + final compressedDef = '${compressed}defined(DART_COMPRESSED_POINTERS)'; + final aot = (config['aot'] as bool) ? 'AOT_' : ''; + final prefix = 'static constexpr dart::compiler::target::word $aot'; + final offsets = config['offsets'] as List; + output.writeln('#if $productDef && $archDef && $compressedDef'); + for (final offset in offsets) { + final kind = offset['kind'] as String; + switch (kind) { + case 'value': + final cls = offset['class'] as String; + final name = offset['name'] as String; + final value = toCValue(offset['value']); + output.writeln('$prefix${cls}_$name = $value;'); + break; + case 'array': + final cls = offset['class'] as String; + final startOffset = toCValue(offset['startOffset']); + final elemSize = toCValue(offset['elemSize']); + output.writeln('$prefix${cls}_elements_start_offset = $startOffset;'); + output.writeln('$prefix${cls}_element_size = $elemSize;'); + break; + case 'range': + final cls = offset['class'] as String; + final name = offset['name'] as String; + final values = (offset['values'] as List).map(toCValue).toList(); + output.writeln('$prefix${cls}_$name[] = {${values.join(', ')}};'); + break; + } + } + output.writeln('#endif // $productDef &&'); + output.writeln(' // $archDef &&'); + output.writeln(' // $compressedDef'); + output.writeln(); } + output.writeln(footer); + File(extractedOffsetsFile).writeAsStringSync(output.toString()); + print('Written $extractedOffsetsFile'); + print('Running `git cl format $extractedOffsetsFile'); + await run(['git', 'cl', 'format', extractedOffsetsFile]); } Future> forAllConfigurationsMode( @@ -103,3 +155,22 @@ extension on String { String get capitalized => substring(0, 1).toUpperCase() + substring(1); String get upper => toUpperCase(); } + +void main(List args) async { + final sdkRoot = Platform.script.resolve('../').toFilePath(); + Directory.current = Directory(sdkRoot); + + await buildOffsetsExtractor(args); + if (exitCode != 0) { + return; + } + + final text = await runOffsetsExtractor(); + if (exitCode != 0) { + return; + } + + final json = convert.json.decode(text) as List; + + await writeCHeaderFile(json); +}