@next2d/builder 0.1.8 → 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.
- package/dist/cli.d.ts +59 -0
- package/dist/cli.js +141 -0
- package/dist/constants.d.ts +53 -0
- package/dist/constants.js +64 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.js +19 -0
- package/dist/electron.d.ts +10 -0
- package/dist/electron.js +142 -0
- package/dist/index.js +18 -790
- package/dist/native.d.ts +27 -0
- package/dist/native.js +123 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.js +40 -0
- package/dist/web.d.ts +18 -0
- package/dist/web.js +70 -0
- package/dist/xbox.d.ts +62 -0
- package/dist/xbox.js +426 -0
- package/package.json +11 -9
- package/templates/xbox/CMakeLists.txt +47 -11
- package/templates/xbox/README.md +18 -0
- package/templates/xbox/js/bootstrap.js +120 -0
- package/templates/xbox/src/AssetLoader.cpp +115 -12
- package/templates/xbox/src/AssetLoader.h +4 -0
- package/templates/xbox/src/EmbeddedAssets.cpp +149 -0
- package/templates/xbox/src/EmbeddedAssets.h +60 -0
- package/templates/xbox/src/EventLoop.cpp +0 -15
- package/templates/xbox/src/bindings/Audio.cpp +118 -22
- package/templates/xbox/src/bindings/Canvas.cpp +32 -2
- package/templates/xbox/src/bindings/Canvas2D.cpp +495 -39
- package/templates/xbox/src/bindings/Console.cpp +6 -1
- package/templates/xbox/src/bindings/DomShims.cpp +18 -2
- package/templates/xbox/src/bindings/EventTarget.cpp +9 -0
- package/templates/xbox/src/bindings/Image.cpp +83 -57
- package/templates/xbox/src/bindings/Polyfills.cpp +671 -236
- package/templates/xbox/src/bindings/RasterCore.h +105 -1
- package/templates/xbox/src/bindings/Video.cpp +57 -3
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +29 -3
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +4 -1
- package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
- package/templates/xbox/src/gpu/DawnContext.cpp +167 -16
- package/templates/xbox/src/main.cpp +385 -16
- package/templates/xbox/src/platform/AudioDecoder.cpp +121 -0
- package/templates/xbox/src/platform/AudioDecoder.h +18 -0
- package/templates/xbox/src/platform/AudioEngine.cpp +28 -3
- package/templates/xbox/src/platform/DecodeQueue.cpp +136 -0
- package/templates/xbox/src/platform/DecodeQueue.h +27 -0
- package/templates/xbox/src/platform/ImageDecoder.cpp +44 -0
- package/templates/xbox/src/platform/ImageDecoder.h +18 -0
- package/templates/xbox/src/platform/StbTextRasterizer.cpp +324 -0
- package/templates/xbox/src/platform/StbTextRasterizer.h +37 -0
- package/templates/xbox/src/platform/TextRasterizer.cpp +32 -0
- package/templates/xbox/src/platform/WicDecoder.cpp +19 -0
- package/templates/xbox/src/v8/CodeCache.h +223 -0
- package/templates/xbox/src/v8/V8Runtime.cpp +34 -33
- package/templates/xbox/src/v8/V8Util.h +54 -4
- package/templates/xbox/src/worker/WorkerRuntime.cpp +165 -65
- package/templates/xbox/src/worker/WorkerRuntime.h +23 -3
- package/templates/xbox/tests/check_local.sh +5 -1
- package/templates/xbox/tests/gamecore_api_probe.cpp +172 -0
- package/templates/xbox/tests/raster_test.cpp +50 -0
- package/templates/xbox/tests/windows_platform_test.cpp +75 -3
- package/templates/xbox/third_party/LICENSES.md +14 -0
- package/templates/xbox/third_party/dr_mp3.h +5412 -0
- package/templates/xbox/third_party/dr_wav.h +9131 -0
- package/templates/xbox/third_party/stb_image.h +7988 -0
- package/templates/xbox/third_party/stb_truetype.h +5079 -0
- package/templates/xbox/third_party/stb_vorbis.c +5584 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
#include "TextRasterizer.h"
|
|
2
2
|
|
|
3
|
+
// DirectWrite / Direct2D / WIC はコンソール (Game Core OS) に存在しない
|
|
4
|
+
// デスクトップ専用 API。コンソールでは false を返し、呼び出し側
|
|
5
|
+
// (Canvas2D の fillText/measureText) が近似値へフォールバックする
|
|
6
|
+
// (契約は TextRasterizer.h に明記済み)。
|
|
7
|
+
// 実機でのテキスト描画品質は devkit 段階の課題 (stb_truetype + フォント同梱)。
|
|
8
|
+
#if !NEXT2D_XBOX_CONSOLE
|
|
9
|
+
|
|
3
10
|
#include "../bindings/RasterCore.h"
|
|
4
11
|
|
|
5
12
|
#include <algorithm>
|
|
@@ -181,3 +188,28 @@ bool RasterizeTextWithDWrite(const std::string& css_font, const std::wstring& te
|
|
|
181
188
|
}
|
|
182
189
|
|
|
183
190
|
} // namespace next2d
|
|
191
|
+
|
|
192
|
+
#else // NEXT2D_XBOX_CONSOLE
|
|
193
|
+
|
|
194
|
+
// コンソール: stb_truetype 実装へ委譲する。フォントは main.cpp が起動時に
|
|
195
|
+
// 埋め込み資材 (*.ttf/*.otf) から登録する。未登録なら false を返し、
|
|
196
|
+
// 呼び出し側 (Canvas2D) が近似値へフォールバックする。
|
|
197
|
+
#include "StbTextRasterizer.h"
|
|
198
|
+
|
|
199
|
+
namespace next2d {
|
|
200
|
+
|
|
201
|
+
bool MeasureTextWithDWrite(const std::string& css_font, const std::wstring& text,
|
|
202
|
+
TextMetricsInfo& out)
|
|
203
|
+
{
|
|
204
|
+
return stbtext::MeasureText(css_font, text, out);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
bool RasterizeTextWithDWrite(const std::string& css_font, const std::wstring& text,
|
|
208
|
+
uint8_t r, uint8_t g, uint8_t b, TextBitmap& out)
|
|
209
|
+
{
|
|
210
|
+
return stbtext::RasterizeText(css_font, text, r, g, b, out);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
} // namespace next2d
|
|
214
|
+
|
|
215
|
+
#endif // !NEXT2D_XBOX_CONSOLE
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#include "WicDecoder.h"
|
|
2
2
|
|
|
3
|
+
// WIC はコンソール (Game Core OS) に存在しないデスクトップ専用 API。
|
|
4
|
+
// 第一経路は ImageDecoder (stb_image) で、本ファイルはデスクトップの
|
|
5
|
+
// フォールバック (TIFF/HEIF 等 stb 非対応形式) のみを担う。
|
|
6
|
+
#if !NEXT2D_XBOX_CONSOLE
|
|
7
|
+
|
|
3
8
|
#include <wincodec.h>
|
|
4
9
|
#include <wrl/client.h>
|
|
5
10
|
|
|
@@ -61,3 +66,17 @@ bool DecodeImageWithWIC(const std::vector<uint8_t>& input, DecodedImage& out)
|
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
} // namespace next2d
|
|
69
|
+
|
|
70
|
+
#else // NEXT2D_XBOX_CONSOLE
|
|
71
|
+
|
|
72
|
+
namespace next2d {
|
|
73
|
+
|
|
74
|
+
// コンソール: WIC 無し。ImageDecoder (stb_image) が全デコードを担う。
|
|
75
|
+
bool DecodeImageWithWIC(const std::vector<uint8_t>&, DecodedImage&)
|
|
76
|
+
{
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
} // namespace next2d
|
|
81
|
+
|
|
82
|
+
#endif // !NEXT2D_XBOX_CONSOLE
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// V8 バイトコードキャッシュ。
|
|
2
|
+
//
|
|
3
|
+
// player+framework のバンドル (数 MB) は毎起動フルパースがかかり、jitless
|
|
4
|
+
// (Ignition) では起動時間の主要因になる。初回起動時に eager コンパイルして
|
|
5
|
+
// バイトコードをディスクへ保存し、2 回目以降はそれを消費してパースを省略する。
|
|
6
|
+
// 生成物はデータであり動的コード生成ではないため、コンソール (JIT 禁止) でも使える。
|
|
7
|
+
//
|
|
8
|
+
// - 保存先: %LOCALAPPDATA%\Next2D\codecache\<hash>.v8bc
|
|
9
|
+
// (DomShims の localStorage バックエンドと同じ配置方針。環境変数が無ければ無効化)
|
|
10
|
+
// - キー: スクリプト名 + ソース内容の FNV-1a。ソースが変われば別ファイルになる。
|
|
11
|
+
// - V8 のバージョン/フラグ不一致は V8 自身が検出して reject する (その場で作り直す)。
|
|
12
|
+
// - すべてのエラーは graceful degrade (キャッシュ無しの通常コンパイルに落ちる)。
|
|
13
|
+
// - 小さいスクリプトはパースが安く I/O の方が高いため対象外 (kMinSourceSize)。
|
|
14
|
+
#pragma once
|
|
15
|
+
|
|
16
|
+
#include <v8.h>
|
|
17
|
+
|
|
18
|
+
#include <chrono>
|
|
19
|
+
#include <cstdint>
|
|
20
|
+
#include <cstdio>
|
|
21
|
+
#include <cstdlib>
|
|
22
|
+
#include <cstring>
|
|
23
|
+
#include <filesystem>
|
|
24
|
+
#include <fstream>
|
|
25
|
+
#include <memory>
|
|
26
|
+
#include <string>
|
|
27
|
+
#include <vector>
|
|
28
|
+
|
|
29
|
+
namespace next2d::codecache {
|
|
30
|
+
|
|
31
|
+
// キャッシュ対象の最小ソースサイズ。bootstrap.js (十数 KB) は対象外、
|
|
32
|
+
// ゲーム/player バンドル (数百 KB〜数 MB) が対象になる境界。
|
|
33
|
+
inline constexpr size_t kMinSourceSize = 64 * 1024;
|
|
34
|
+
|
|
35
|
+
inline const std::filesystem::path& CacheDir()
|
|
36
|
+
{
|
|
37
|
+
static const std::filesystem::path dir = []() -> std::filesystem::path {
|
|
38
|
+
const char* base = std::getenv("LOCALAPPDATA");
|
|
39
|
+
if (!base || !*base) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
std::error_code ec;
|
|
43
|
+
std::filesystem::path d = std::filesystem::path(base) / "Next2D" / "codecache";
|
|
44
|
+
std::filesystem::create_directories(d, ec);
|
|
45
|
+
if (ec) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
// ゲーム更新でソースが変わるとキャッシュはファイル名ごと変わり、旧ファイルは
|
|
49
|
+
// 参照されない孤児になる。30 日アクセスの無い .v8bc を起動時に掃除する
|
|
50
|
+
// (Load が使用時に write time を touch するため実質 LRU)。
|
|
51
|
+
const auto now = std::filesystem::file_time_type::clock::now();
|
|
52
|
+
std::error_code iter_ec;
|
|
53
|
+
for (const auto& entry : std::filesystem::directory_iterator(d, iter_ec)) {
|
|
54
|
+
std::error_code e2;
|
|
55
|
+
if (entry.path().extension() != ".v8bc") {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const auto t = std::filesystem::last_write_time(entry.path(), e2);
|
|
59
|
+
if (!e2 && now - t > std::chrono::hours(24 * 30)) {
|
|
60
|
+
std::filesystem::remove(entry.path(), e2);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return d;
|
|
64
|
+
}();
|
|
65
|
+
return dir;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
inline uint64_t Fnv1a(const void* data, size_t size, uint64_t hash = 1469598103934665603ull)
|
|
69
|
+
{
|
|
70
|
+
const auto* p = static_cast<const unsigned char*>(data);
|
|
71
|
+
for (size_t i = 0; i < size; ++i) {
|
|
72
|
+
hash ^= p[i];
|
|
73
|
+
hash *= 1099511628211ull;
|
|
74
|
+
}
|
|
75
|
+
return hash;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
inline std::filesystem::path CacheFileFor(const std::string& name, const std::string& source)
|
|
79
|
+
{
|
|
80
|
+
const std::filesystem::path& dir = CacheDir();
|
|
81
|
+
if (dir.empty()) {
|
|
82
|
+
return {};
|
|
83
|
+
}
|
|
84
|
+
uint64_t h = Fnv1a(name.data(), name.size());
|
|
85
|
+
h = Fnv1a(source.data(), source.size(), h);
|
|
86
|
+
char buf[17] = {};
|
|
87
|
+
std::snprintf(buf, sizeof(buf), "%016llx", static_cast<unsigned long long>(h));
|
|
88
|
+
return dir / (std::string(buf) + ".v8bc");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
inline bool Eligible(const std::string& source)
|
|
92
|
+
{
|
|
93
|
+
return source.size() >= kMinSourceSize && !CacheDir().empty();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// キャッシュファイルを読む。戻り値の所有権は ScriptCompiler::Source が取る
|
|
97
|
+
// (BufferOwned なので CachedData 破棄時に delete[] される)。無ければ nullptr。
|
|
98
|
+
inline v8::ScriptCompiler::CachedData* Load(const std::string& name, const std::string& source)
|
|
99
|
+
{
|
|
100
|
+
const std::filesystem::path file = CacheFileFor(name, source);
|
|
101
|
+
if (file.empty()) {
|
|
102
|
+
return nullptr;
|
|
103
|
+
}
|
|
104
|
+
std::ifstream ifs(file, std::ios::binary);
|
|
105
|
+
if (!ifs) {
|
|
106
|
+
return nullptr;
|
|
107
|
+
}
|
|
108
|
+
std::vector<char> buf(
|
|
109
|
+
(std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
|
110
|
+
if (buf.empty()) {
|
|
111
|
+
return nullptr;
|
|
112
|
+
}
|
|
113
|
+
// 使用時に write time を更新し、CacheDir の 30 日掃除を LRU として機能させる
|
|
114
|
+
std::error_code ec;
|
|
115
|
+
std::filesystem::last_write_time(
|
|
116
|
+
file, std::filesystem::file_time_type::clock::now(), ec);
|
|
117
|
+
|
|
118
|
+
auto* data = new uint8_t[buf.size()];
|
|
119
|
+
std::memcpy(data, buf.data(), buf.size());
|
|
120
|
+
return new v8::ScriptCompiler::CachedData(
|
|
121
|
+
data, static_cast<int>(buf.size()),
|
|
122
|
+
v8::ScriptCompiler::CachedData::BufferOwned);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
inline void Store(const std::string& name, const std::string& source,
|
|
126
|
+
const v8::ScriptCompiler::CachedData* data)
|
|
127
|
+
{
|
|
128
|
+
if (!data || !data->data || data->length <= 0) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const std::filesystem::path file = CacheFileFor(name, source);
|
|
132
|
+
if (file.empty()) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
std::ofstream ofs(file, std::ios::binary | std::ios::trunc);
|
|
136
|
+
if (ofs) {
|
|
137
|
+
ofs.write(reinterpret_cast<const char*>(data->data), data->length);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// classic script をキャッシュ込みでコンパイルする。
|
|
142
|
+
// - キャッシュ有り: kConsumeCodeCache で消費 (V8 が reject したら作り直して保存)
|
|
143
|
+
// - キャッシュ無し: kEagerCompile で全関数を一括コンパイルして保存
|
|
144
|
+
// (初回はその分遅いが、以降の起動は lazy compile も含めて丸ごと省ける)
|
|
145
|
+
// - 対象外サイズ: 従来どおりの lazy コンパイル
|
|
146
|
+
inline v8::MaybeLocal<v8::Script> Compile(v8::Local<v8::Context> ctx,
|
|
147
|
+
v8::Local<v8::String> src,
|
|
148
|
+
v8::ScriptOrigin& origin,
|
|
149
|
+
const std::string& name,
|
|
150
|
+
const std::string& source_str)
|
|
151
|
+
{
|
|
152
|
+
if (!Eligible(source_str)) {
|
|
153
|
+
v8::ScriptCompiler::Source source(src, origin);
|
|
154
|
+
return v8::ScriptCompiler::Compile(ctx, &source);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (v8::ScriptCompiler::CachedData* cached = Load(name, source_str)) {
|
|
158
|
+
v8::ScriptCompiler::Source source(src, origin, cached);
|
|
159
|
+
v8::Local<v8::Script> script;
|
|
160
|
+
if (!v8::ScriptCompiler::Compile(
|
|
161
|
+
ctx, &source, v8::ScriptCompiler::kConsumeCodeCache).ToLocal(&script)) {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
if (source.GetCachedData() && source.GetCachedData()->rejected) {
|
|
165
|
+
std::unique_ptr<v8::ScriptCompiler::CachedData> fresh(
|
|
166
|
+
v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript()));
|
|
167
|
+
Store(name, source_str, fresh.get());
|
|
168
|
+
}
|
|
169
|
+
return script;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
v8::ScriptCompiler::Source source(src, origin);
|
|
173
|
+
v8::Local<v8::Script> script;
|
|
174
|
+
if (!v8::ScriptCompiler::Compile(
|
|
175
|
+
ctx, &source, v8::ScriptCompiler::kEagerCompile).ToLocal(&script)) {
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
std::unique_ptr<v8::ScriptCompiler::CachedData> fresh(
|
|
179
|
+
v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript()));
|
|
180
|
+
Store(name, source_str, fresh.get());
|
|
181
|
+
return script;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ES module 版。規約は Compile と同じ。
|
|
185
|
+
inline v8::MaybeLocal<v8::Module> CompileModule(v8::Isolate* isolate,
|
|
186
|
+
v8::Local<v8::String> src,
|
|
187
|
+
v8::ScriptOrigin& origin,
|
|
188
|
+
const std::string& name,
|
|
189
|
+
const std::string& source_str)
|
|
190
|
+
{
|
|
191
|
+
if (!Eligible(source_str)) {
|
|
192
|
+
v8::ScriptCompiler::Source source(src, origin);
|
|
193
|
+
return v8::ScriptCompiler::CompileModule(isolate, &source);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (v8::ScriptCompiler::CachedData* cached = Load(name, source_str)) {
|
|
197
|
+
v8::ScriptCompiler::Source source(src, origin, cached);
|
|
198
|
+
v8::Local<v8::Module> module;
|
|
199
|
+
if (!v8::ScriptCompiler::CompileModule(
|
|
200
|
+
isolate, &source, v8::ScriptCompiler::kConsumeCodeCache).ToLocal(&module)) {
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
if (source.GetCachedData() && source.GetCachedData()->rejected) {
|
|
204
|
+
std::unique_ptr<v8::ScriptCompiler::CachedData> fresh(
|
|
205
|
+
v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript()));
|
|
206
|
+
Store(name, source_str, fresh.get());
|
|
207
|
+
}
|
|
208
|
+
return module;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
v8::ScriptCompiler::Source source(src, origin);
|
|
212
|
+
v8::Local<v8::Module> module;
|
|
213
|
+
if (!v8::ScriptCompiler::CompileModule(
|
|
214
|
+
isolate, &source, v8::ScriptCompiler::kEagerCompile).ToLocal(&module)) {
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
std::unique_ptr<v8::ScriptCompiler::CachedData> fresh(
|
|
218
|
+
v8::ScriptCompiler::CreateCodeCache(module->GetUnboundModuleScript()));
|
|
219
|
+
Store(name, source_str, fresh.get());
|
|
220
|
+
return module;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
} // namespace next2d::codecache
|
|
@@ -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>
|
|
@@ -46,7 +48,14 @@ void V8Runtime::InitializeProcess(const char* exec_path)
|
|
|
46
48
|
// - JS: --jitless (Ignition インタプリタのみ・RWX ページ無し)
|
|
47
49
|
// - WebAssembly: --wasm-jitless (DrumBrake = V8 の wasm インタープリタ。
|
|
48
50
|
// prebuilt V8 r2 は v8_enable_drumbrake=true でビルドされている)
|
|
49
|
-
|
|
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);
|
|
@@ -79,6 +88,14 @@ bool V8Runtime::Initialize(HostContext* host)
|
|
|
79
88
|
create_params_.array_buffer_allocator =
|
|
80
89
|
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
|
81
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
|
+
|
|
82
99
|
isolate_ = v8::Isolate::New(create_params_);
|
|
83
100
|
isolate_->SetData(kHostContextSlot, host);
|
|
84
101
|
isolate_->SetData(kRuntimeSlot, this);
|
|
@@ -162,8 +179,9 @@ bool V8Runtime::RunScript(const std::string& source, const std::string& name)
|
|
|
162
179
|
v8::ScriptOrigin origin(v8util::Str(isolate_, name));
|
|
163
180
|
v8::Local<v8::String> src = v8util::Str(isolate_, source);
|
|
164
181
|
|
|
182
|
+
// バイトコードキャッシュ込みでコンパイル (2回目以降の起動でパースを省略)
|
|
165
183
|
v8::Local<v8::Script> script;
|
|
166
|
-
if (!
|
|
184
|
+
if (!codecache::Compile(ctx, src, origin, name, source).ToLocal(&script)) {
|
|
167
185
|
ReportException(&try_catch);
|
|
168
186
|
return false;
|
|
169
187
|
}
|
|
@@ -188,35 +206,17 @@ v8::MaybeLocal<v8::Module> V8Runtime::LoadModule(const std::string& path,
|
|
|
188
206
|
return cached->second.Get(isolate_);
|
|
189
207
|
}
|
|
190
208
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const auto pos = source.find(from);
|
|
203
|
-
if (pos != std::string::npos) {
|
|
204
|
-
source.replace(pos, from.size(), to);
|
|
205
|
-
} else {
|
|
206
|
-
std::cerr << "[V8] job trace patch not applied: "
|
|
207
|
-
<< from.substr(0, 40) << std::endl;
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
patch("(e.currentTime=(t-e.startTime)/1e3,",
|
|
211
|
-
"(e.currentTime=(t-e.startTime)/1e3,"
|
|
212
|
-
"((globalThis.__jt=(globalThis.__jt||0)+1)<=60||globalThis.__jt%600===0)&&"
|
|
213
|
-
"console.info(\"[jobtrace] #\"+globalThis.__jt,"
|
|
214
|
-
"\"ct=\"+e.currentTime.toFixed(3),\"dur=\"+e.duration,"
|
|
215
|
-
"\"t=\"+t.toFixed(1),\"st=\"+e.startTime.toFixed(1)),");
|
|
216
|
-
patch("e.currentTime>=e.duration?(",
|
|
217
|
-
"e.currentTime>=e.duration?("
|
|
218
|
-
"console.info(\"[jobtrace] COMPLETE dur=\"+e.duration),");
|
|
219
|
-
std::cerr << "[V8] job trace patch applied to " << abs << std::endl;
|
|
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
|
+
}
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
v8::Local<v8::String> src = v8util::Str(isolate_, source);
|
|
@@ -227,9 +227,10 @@ v8::MaybeLocal<v8::Module> V8Runtime::LoadModule(const std::string& path,
|
|
|
227
227
|
false, false, /*is_module*/ true
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
// バイトコードキャッシュ込みでコンパイル。アプリ本体 (数 MB の ESM バンドル) の
|
|
231
|
+
// 毎起動フルパースを 2 回目以降省略する (起動時間の主要因)。
|
|
231
232
|
v8::Local<v8::Module> module;
|
|
232
|
-
if (!
|
|
233
|
+
if (!codecache::CompileModule(isolate_, src, origin, abs, source).ToLocal(&module)) {
|
|
233
234
|
return v8::MaybeLocal<v8::Module>();
|
|
234
235
|
}
|
|
235
236
|
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
#include <v8.h>
|
|
5
5
|
#include <iostream>
|
|
6
|
+
#include <fstream>
|
|
6
7
|
#include <string>
|
|
7
8
|
#include <string_view>
|
|
9
|
+
#include <unordered_map>
|
|
8
10
|
|
|
9
11
|
namespace next2d::v8util {
|
|
10
12
|
|
|
@@ -17,6 +19,32 @@ inline v8::Local<v8::String> Str(v8::Isolate* isolate, std::string_view s)
|
|
|
17
19
|
).ToLocalChecked();
|
|
18
20
|
}
|
|
19
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
|
+
|
|
20
48
|
// v8::Value -> std::string (UTF-8)
|
|
21
49
|
inline std::string ToStdString(v8::Isolate* isolate, v8::Local<v8::Value> value)
|
|
22
50
|
{
|
|
@@ -58,6 +86,23 @@ inline void ThrowTypeError(v8::Isolate* isolate, std::string_view message)
|
|
|
58
86
|
// rAF / タイマー / onmessage / イベントリスナーのコールバックは TryCatch で
|
|
59
87
|
// 保護されるが、報告しないと例外が無音で消えて原因究明が不可能になる
|
|
60
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
|
+
|
|
61
106
|
inline void ReportCaught(v8::Isolate* isolate, v8::TryCatch* tc, const char* where)
|
|
62
107
|
{
|
|
63
108
|
if (!tc->HasCaught()) {
|
|
@@ -66,19 +111,24 @@ inline void ReportCaught(v8::Isolate* isolate, v8::TryCatch* tc, const char* whe
|
|
|
66
111
|
v8::HandleScope hs(isolate);
|
|
67
112
|
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
68
113
|
const std::string text = ToStdString(isolate, tc->Exception());
|
|
69
|
-
std::
|
|
114
|
+
const std::string head = std::string("[JS] exception in ") + where + ": " + text;
|
|
115
|
+
std::cerr << head << std::endl;
|
|
116
|
+
AppendErrorLog(head);
|
|
70
117
|
v8::Local<v8::Value> stack;
|
|
71
118
|
if (!ctx.IsEmpty() && tc->StackTrace(ctx).ToLocal(&stack)) {
|
|
72
119
|
const std::string s = ToStdString(isolate, stack);
|
|
73
120
|
if (!s.empty() && s != text) {
|
|
74
121
|
std::cerr << s << std::endl;
|
|
122
|
+
AppendErrorLog(s);
|
|
75
123
|
}
|
|
76
124
|
}
|
|
77
125
|
v8::Local<v8::Message> message = tc->Message();
|
|
78
126
|
if (!message.IsEmpty() && !ctx.IsEmpty()) {
|
|
79
|
-
std::
|
|
80
|
-
|
|
81
|
-
|
|
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);
|
|
82
132
|
}
|
|
83
133
|
}
|
|
84
134
|
|