@next2d/builder 0.1.7 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/cli.d.ts +59 -0
  2. package/dist/cli.js +141 -0
  3. package/dist/constants.d.ts +53 -0
  4. package/dist/constants.js +64 -0
  5. package/dist/context.d.ts +29 -0
  6. package/dist/context.js +19 -0
  7. package/dist/electron.d.ts +10 -0
  8. package/dist/electron.js +142 -0
  9. package/dist/index.js +18 -754
  10. package/dist/native.d.ts +27 -0
  11. package/dist/native.js +123 -0
  12. package/dist/utils.d.ts +27 -0
  13. package/dist/utils.js +40 -0
  14. package/dist/web.d.ts +18 -0
  15. package/dist/web.js +70 -0
  16. package/dist/xbox.d.ts +62 -0
  17. package/dist/xbox.js +426 -0
  18. package/package.json +12 -9
  19. package/templates/xbox/CMakeLists.txt +116 -11
  20. package/templates/xbox/README.md +34 -8
  21. package/templates/xbox/cmake/FetchDawn.cmake +47 -6
  22. package/templates/xbox/cmake/FindV8.cmake +15 -0
  23. package/templates/xbox/js/bootstrap.js +151 -28
  24. package/templates/xbox/js/selftest.js +740 -90
  25. package/templates/xbox/src/AssetLoader.cpp +115 -12
  26. package/templates/xbox/src/AssetLoader.h +4 -0
  27. package/templates/xbox/src/EmbeddedAssets.cpp +149 -0
  28. package/templates/xbox/src/EmbeddedAssets.h +60 -0
  29. package/templates/xbox/src/EventLoop.cpp +13 -1
  30. package/templates/xbox/src/EventLoop.h +12 -0
  31. package/templates/xbox/src/bindings/Audio.cpp +211 -31
  32. package/templates/xbox/src/bindings/Bindings.h +10 -0
  33. package/templates/xbox/src/bindings/Canvas.cpp +77 -2
  34. package/templates/xbox/src/bindings/Canvas2D.cpp +496 -43
  35. package/templates/xbox/src/bindings/Console.cpp +6 -1
  36. package/templates/xbox/src/bindings/DomShims.cpp +143 -0
  37. package/templates/xbox/src/bindings/EventTarget.cpp +11 -0
  38. package/templates/xbox/src/bindings/Fetch.cpp +2 -8
  39. package/templates/xbox/src/bindings/Image.cpp +243 -15
  40. package/templates/xbox/src/bindings/Polyfills.cpp +1226 -0
  41. package/templates/xbox/src/bindings/RasterCore.h +105 -1
  42. package/templates/xbox/src/bindings/Video.cpp +153 -10
  43. package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +844 -18
  44. package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +7 -9
  45. package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
  46. package/templates/xbox/src/gpu/DawnContext.cpp +245 -7
  47. package/templates/xbox/src/gpu/DawnContext.h +18 -0
  48. package/templates/xbox/src/main.cpp +459 -8
  49. package/templates/xbox/src/platform/AudioDecoder.cpp +121 -0
  50. package/templates/xbox/src/platform/AudioDecoder.h +18 -0
  51. package/templates/xbox/src/platform/AudioEngine.cpp +37 -6
  52. package/templates/xbox/src/platform/DecodeQueue.cpp +136 -0
  53. package/templates/xbox/src/platform/DecodeQueue.h +27 -0
  54. package/templates/xbox/src/platform/ImageDecoder.cpp +44 -0
  55. package/templates/xbox/src/platform/ImageDecoder.h +18 -0
  56. package/templates/xbox/src/platform/StbTextRasterizer.cpp +324 -0
  57. package/templates/xbox/src/platform/StbTextRasterizer.h +37 -0
  58. package/templates/xbox/src/platform/TextRasterizer.cpp +32 -0
  59. package/templates/xbox/src/platform/WicDecoder.cpp +19 -0
  60. package/templates/xbox/src/v8/CodeCache.h +223 -0
  61. package/templates/xbox/src/v8/V8Runtime.cpp +76 -11
  62. package/templates/xbox/src/v8/V8Util.h +79 -0
  63. package/templates/xbox/src/v8/WeakHandle.h +45 -0
  64. package/templates/xbox/src/worker/WorkerRuntime.cpp +432 -48
  65. package/templates/xbox/src/worker/WorkerRuntime.h +43 -13
  66. package/templates/xbox/tests/check_local.sh +7 -2
  67. package/templates/xbox/tests/gamecore_api_probe.cpp +172 -0
  68. package/templates/xbox/tests/raster_test.cpp +50 -0
  69. package/templates/xbox/tests/windows_platform_test.cpp +75 -3
  70. package/templates/xbox/third_party/LICENSES.md +14 -0
  71. package/templates/xbox/third_party/dr_mp3.h +5412 -0
  72. package/templates/xbox/third_party/dr_wav.h +9131 -0
  73. package/templates/xbox/third_party/stb_image.h +7988 -0
  74. package/templates/xbox/third_party/stb_truetype.h +5079 -0
  75. package/templates/xbox/third_party/stb_vorbis.c +5584 -0
@@ -1,7 +1,9 @@
1
1
  #include "V8Runtime.h"
2
2
 
3
3
  #include "V8Util.h"
4
+ #include "CodeCache.h"
4
5
  #include "HostContext.h"
6
+ #include "EmbeddedAssets.h"
5
7
  #include "bindings/Bindings.h"
6
8
 
7
9
  #include <filesystem>
@@ -43,16 +45,33 @@ V8Runtime::~V8Runtime()
43
45
  void V8Runtime::InitializeProcess(const char* exec_path)
44
46
  {
45
47
  // Xbox(GDK) / Nintendo Switch のリテール環境は動的コード生成(JIT)を禁止する。
46
- // V8 を jitless (Ignition インタプリタのみ・TurboFan/Sparkplug/RWXページ無し) で動かす。
47
- // prebuilt V8 (build-v8.yml) は v8_jitless=true + turbofan/wasm 無効でビルドされる。
48
- // wasm/opt 系フラグはそのビルドに存在しないため渡さない (未知フラグ警告を避ける)。
49
- v8::V8::SetFlagsFromString("--jitless");
48
+ // - JS: --jitless (Ignition インタプリタのみ・RWX ページ無し)
49
+ // - WebAssembly: --wasm-jitless (DrumBrake = V8 の wasm インタープリタ。
50
+ // prebuilt V8 r2 は v8_enable_drumbrake=true でビルドされている)
51
+ // - --no-flush-bytecode: V8 は既定でしばらく実行されない関数のバイトコードを
52
+ // 破棄し、次回実行時に再パースする (メモリ最適化)。ゲームでは画面遷移で
53
+ // 久々に呼ばれる関数の再パースがフレームヒッチになるため無効化する
54
+ // (ゲームバンドル数 MB 程度ならバイトコード常駐のメモリ増は許容範囲)。
55
+ // 注: PC ビルドも意図的に jitless で統一する。コンソール実機の性能を PC 検証で
56
+ // 忠実に再現するため (PC だけ JIT で速くするとレギュレーション下の実機で
57
+ // 性能問題が再発する)。
58
+ v8::V8::SetFlagsFromString("--jitless --wasm-jitless --no-flush-bytecode");
50
59
 
51
60
  v8::V8::InitializeICUDefaultLocation(exec_path);
52
61
  v8::V8::InitializeExternalStartupData(exec_path);
53
62
  platform_ = v8::platform::NewDefaultPlatform();
54
63
  v8::V8::InitializePlatform(platform_.get());
55
64
  v8::V8::Initialize();
65
+
66
+ // WebAssembly (DrumBrake) はメモリ境界検査を guard page + trap handler で行うため、
67
+ // embedder が trap handler を有効化する必要がある (d8/Chrome も起動時に行う)。
68
+ // 未設定のまま wasm を実行するとインタープリタ初期化で fail-fast する。
69
+ // コンソール実機で VEH が使えない場合は、V8 を v8_drumbrake_bounds_checks=true
70
+ // (明示境界チェック) でビルドし直すこと。
71
+ if (!v8::V8::EnableWebAssemblyTrapHandler(true)) {
72
+ std::cerr << "warning: EnableWebAssemblyTrapHandler failed"
73
+ << " - WebAssembly may not work" << std::endl;
74
+ }
56
75
  }
57
76
 
58
77
  void V8Runtime::ShutdownProcess()
@@ -69,6 +88,14 @@ bool V8Runtime::Initialize(HostContext* host)
69
88
  create_params_.array_buffer_allocator =
70
89
  v8::ArrayBuffer::Allocator::NewDefaultAllocator();
71
90
 
91
+ // 60fps のゲームはフレーム毎に短命オブジェクト (ディスクリプタ/一時配列) を
92
+ // 大量生成する。young generation を既定 (十数 MB) から 64MB へ拡大して
93
+ // scavenge (minor GC) の頻度を下げ、マイクロヒッチを減らす。
94
+ // scavenge の停止時間は生存オブジェクト量に比例し空間サイズには比例しないため、
95
+ // 拡大はほぼ純粋に頻度低減として効く。
96
+ create_params_.constraints.set_max_young_generation_size_in_bytes(
97
+ 64 * 1024 * 1024);
98
+
72
99
  isolate_ = v8::Isolate::New(create_params_);
73
100
  isolate_->SetData(kHostContextSlot, host);
74
101
  isolate_->SetData(kRuntimeSlot, this);
@@ -76,6 +103,35 @@ bool V8Runtime::Initialize(HostContext* host)
76
103
  // 例外時に未処理を潰さないよう、明示的に MicrotasksPolicy を制御する
77
104
  isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
78
105
 
106
+ // 未処理の Promise 拒否を stderr へ報告する。framework の boot は async のため、
107
+ // この報告が無いと例外がどこにも出ずゲームが無音で停止する (実際に発生した)。
108
+ isolate_->SetPromiseRejectCallback([](v8::PromiseRejectMessage message) {
109
+ if (message.GetEvent() != v8::kPromiseRejectWithNoHandler) {
110
+ return; // 後からハンドラが付く分などは報告しない
111
+ }
112
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
113
+ v8::HandleScope hs(isolate);
114
+ v8::Local<v8::Value> value = message.GetValue();
115
+ std::string text = "(no value)";
116
+ std::string stack;
117
+ if (!value.IsEmpty()) {
118
+ text = v8util::ToStdString(isolate, value);
119
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
120
+ if (!ctx.IsEmpty() && value->IsObject()) {
121
+ v8::Local<v8::Value> s;
122
+ if (value.As<v8::Object>()
123
+ ->Get(ctx, v8util::Str(isolate, "stack")).ToLocal(&s) &&
124
+ s->IsString()) {
125
+ stack = v8util::ToStdString(isolate, s);
126
+ }
127
+ }
128
+ }
129
+ std::cerr << "[V8] Unhandled promise rejection: " << text << std::endl;
130
+ if (!stack.empty() && stack != text) {
131
+ std::cerr << stack << std::endl;
132
+ }
133
+ });
134
+
79
135
  v8::Isolate::Scope isolate_scope(isolate_);
80
136
  v8::HandleScope handle_scope(isolate_);
81
137
 
@@ -123,8 +179,9 @@ bool V8Runtime::RunScript(const std::string& source, const std::string& name)
123
179
  v8::ScriptOrigin origin(v8util::Str(isolate_, name));
124
180
  v8::Local<v8::String> src = v8util::Str(isolate_, source);
125
181
 
182
+ // バイトコードキャッシュ込みでコンパイル (2回目以降の起動でパースを省略)
126
183
  v8::Local<v8::Script> script;
127
- if (!v8::Script::Compile(ctx, src, &origin).ToLocal(&script)) {
184
+ if (!codecache::Compile(ctx, src, origin, name, source).ToLocal(&script)) {
128
185
  ReportException(&try_catch);
129
186
  return false;
130
187
  }
@@ -149,10 +206,17 @@ v8::MaybeLocal<v8::Module> V8Runtime::LoadModule(const std::string& path,
149
206
  return cached->second.Get(isolate_);
150
207
  }
151
208
 
152
- const std::string source = ReadTextFile(abs);
153
- if (source.empty() && !fs::exists(abs)) {
154
- v8util::ThrowTypeError(isolate_, "Module not found: " + abs);
155
- return v8::MaybeLocal<v8::Module>();
209
+ // 埋め込みモード優先: exe 内に格納された assets/app を先に探す (平文 JS を置かない)。
210
+ // 埋め込みが無い開発ビルドでは nullptr が返り、従来どおりファイルから読む。
211
+ std::string source;
212
+ if (const auto* embedded = GetEmbeddedAssetByAbsPath(abs)) {
213
+ source.assign(embedded->begin(), embedded->end());
214
+ } else {
215
+ source = ReadTextFile(abs);
216
+ if (source.empty() && !fs::exists(abs)) {
217
+ v8util::ThrowTypeError(isolate_, "Module not found: " + abs);
218
+ return v8::MaybeLocal<v8::Module>();
219
+ }
156
220
  }
157
221
 
158
222
  v8::Local<v8::String> src = v8util::Str(isolate_, source);
@@ -163,9 +227,10 @@ v8::MaybeLocal<v8::Module> V8Runtime::LoadModule(const std::string& path,
163
227
  false, false, /*is_module*/ true
164
228
  );
165
229
 
166
- v8::ScriptCompiler::Source compiler_source(src, origin);
230
+ // バイトコードキャッシュ込みでコンパイル。アプリ本体 (数 MB の ESM バンドル) の
231
+ // 毎起動フルパースを 2 回目以降省略する (起動時間の主要因)。
167
232
  v8::Local<v8::Module> module;
168
- if (!v8::ScriptCompiler::CompileModule(isolate_, &compiler_source).ToLocal(&module)) {
233
+ if (!codecache::CompileModule(isolate_, src, origin, abs, source).ToLocal(&module)) {
169
234
  return v8::MaybeLocal<v8::Module>();
170
235
  }
171
236
 
@@ -2,8 +2,11 @@
2
2
  #pragma once
3
3
 
4
4
  #include <v8.h>
5
+ #include <iostream>
6
+ #include <fstream>
5
7
  #include <string>
6
8
  #include <string_view>
9
+ #include <unordered_map>
7
10
 
8
11
  namespace next2d::v8util {
9
12
 
@@ -16,6 +19,32 @@ inline v8::Local<v8::String> Str(v8::Isolate* isolate, std::string_view s)
16
19
  ).ToLocalChecked();
17
20
  }
18
21
 
22
+ // プロパティ名 v8::String のキャッシュ。
23
+ // バインディングのディスクリプタ解析 (webgpu::Prop/HasProp/U32 等) は毎フレーム
24
+ // 数千回呼ばれ、その度に NewFromUtf8 が JS ヒープ確保 + ハッシュ計算をしていた。
25
+ // internalized string (isolate 内で重複排除され、プロパティ検索がポインタ比較で済む)
26
+ // を v8::Eternal で保持し、2 回目以降はハッシュマップ参照のみにする。
27
+ // jitless では JS↔C++ 境界のコストが相対的に重いため、ここの削減が全体に効く。
28
+ // キーは内容比較 (std::string) なので呼び出し元がリテラル以外を渡しても安全。
29
+ // ホストは単一 Isolate 運用 (worker も同一 Isolate の別 Context) だが、
30
+ // 念のため isolate が変わったらキャッシュを破棄する (Eternal は isolate 寿命に紐づく)。
31
+ inline v8::Local<v8::String> PropName(v8::Isolate* isolate, const char* key)
32
+ {
33
+ static v8::Isolate* cached_isolate = nullptr;
34
+ static std::unordered_map<std::string, v8::Eternal<v8::String>> cache;
35
+ if (cached_isolate != isolate) {
36
+ cache.clear();
37
+ cached_isolate = isolate;
38
+ }
39
+ auto it = cache.find(key);
40
+ if (it == cache.end()) {
41
+ v8::Local<v8::String> s = v8::String::NewFromUtf8(
42
+ isolate, key, v8::NewStringType::kInternalized).ToLocalChecked();
43
+ it = cache.emplace(key, v8::Eternal<v8::String>(isolate, s)).first;
44
+ }
45
+ return it->second.Get(isolate);
46
+ }
47
+
19
48
  // v8::Value -> std::string (UTF-8)
20
49
  inline std::string ToStdString(v8::Isolate* isolate, v8::Local<v8::Value> value)
21
50
  {
@@ -53,4 +82,54 @@ inline void ThrowTypeError(v8::Isolate* isolate, std::string_view message)
53
82
  isolate->ThrowException(v8::Exception::TypeError(Str(isolate, message)));
54
83
  }
55
84
 
85
+ // TryCatch が例外を保持していれば stderr へ報告する。
86
+ // rAF / タイマー / onmessage / イベントリスナーのコールバックは TryCatch で
87
+ // 保護されるが、報告しないと例外が無音で消えて原因究明が不可能になる
88
+ // (レンダラ worker が毎フレーム throw していても黒画面にしか見えない)。
89
+ // 例外を stderr に加えてログファイルにも残す。GUI 実行(ダブルクリック)では stderr が
90
+ // 捨てられて例外が見えないため、rAF/タイマー/リスナーで無音死する不具合(例: Tween の
91
+ // rAF チェーンが UPDATE リスナの throw で再登録されず停止)を実行後に追跡できるように
92
+ // する。暴走ログ防止に先頭 200 件までに制限。ファイルは実行ディレクトリの next2d-error.log。
93
+ inline void AppendErrorLog(const std::string& line)
94
+ {
95
+ static int written = 0;
96
+ if (written >= 200) {
97
+ return;
98
+ }
99
+ ++written;
100
+ std::ofstream ofs("next2d-error.log", std::ios::app);
101
+ if (ofs) {
102
+ ofs << line << std::endl;
103
+ }
104
+ }
105
+
106
+ inline void ReportCaught(v8::Isolate* isolate, v8::TryCatch* tc, const char* where)
107
+ {
108
+ if (!tc->HasCaught()) {
109
+ return;
110
+ }
111
+ v8::HandleScope hs(isolate);
112
+ v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
113
+ const std::string text = ToStdString(isolate, tc->Exception());
114
+ const std::string head = std::string("[JS] exception in ") + where + ": " + text;
115
+ std::cerr << head << std::endl;
116
+ AppendErrorLog(head);
117
+ v8::Local<v8::Value> stack;
118
+ if (!ctx.IsEmpty() && tc->StackTrace(ctx).ToLocal(&stack)) {
119
+ const std::string s = ToStdString(isolate, stack);
120
+ if (!s.empty() && s != text) {
121
+ std::cerr << s << std::endl;
122
+ AppendErrorLog(s);
123
+ }
124
+ }
125
+ v8::Local<v8::Message> message = tc->Message();
126
+ if (!message.IsEmpty() && !ctx.IsEmpty()) {
127
+ const std::string loc = std::string(" at ")
128
+ + ToStdString(isolate, message->GetScriptOrigin().ResourceName())
129
+ + ":" + std::to_string(message->GetLineNumber(ctx).FromMaybe(0));
130
+ std::cerr << loc << std::endl;
131
+ AppendErrorLog(loc);
132
+ }
133
+ }
134
+
56
135
  } // namespace next2d::v8util
@@ -0,0 +1,45 @@
1
+ // SetWeak (GC 連動の解放) の正しい運用ヘルパー。
2
+ //
3
+ // V8 の規約では、第一パスの weak callback 内で対応する v8::Global を必ず
4
+ // Reset しなければならない。違反すると GC 時に fatal
5
+ // 「Check failed: Handle not reset in first callback.」で落ちる。
6
+ // payload と Global を束ねて所有し、GC で Reset + delete の両方を行う。
7
+ #pragma once
8
+
9
+ #include <v8.h>
10
+
11
+ namespace next2d::v8util {
12
+
13
+ template <typename T>
14
+ class WeakHandle {
15
+ public:
16
+ static void Attach(v8::Isolate* isolate, v8::Local<v8::Object> obj, T* payload)
17
+ {
18
+ auto* w = new WeakHandle<T>(payload);
19
+ w->handle_.Reset(isolate, obj);
20
+ w->handle_.SetWeak(w, &WeakHandle::OnGC, v8::WeakCallbackType::kParameter);
21
+ }
22
+
23
+ private:
24
+ explicit WeakHandle(T* payload) : payload_(payload) {}
25
+
26
+ static void OnGC(const v8::WeakCallbackInfo<WeakHandle<T>>& info)
27
+ {
28
+ WeakHandle<T>* w = info.GetParameter();
29
+ w->handle_.Reset(); // 第一パスでの Reset (V8 の必須要件)
30
+ delete w->payload_;
31
+ delete w;
32
+ }
33
+
34
+ v8::Global<v8::Object> handle_;
35
+ T* payload_;
36
+ };
37
+
38
+ // オブジェクトが GC されたときに `delete payload` する弱参照を張る。
39
+ template <typename T>
40
+ inline void AttachWeak(v8::Isolate* isolate, v8::Local<v8::Object> obj, T* payload)
41
+ {
42
+ WeakHandle<T>::Attach(isolate, obj, payload);
43
+ }
44
+
45
+ } // namespace next2d::v8util