Skip to content

Commit

Permalink
Fix a bug that the font cache causes serious memory pressure.
Browse files Browse the repository at this point in the history
- Apply 2 deserialization modes to CkPicture class.
- We are using a custom canvaskit.wasm now and the patch file to Skia needs to be made.
    - Documentations of building the required WASM canvaskit should also be updated.
  • Loading branch information
wait1210day committed Oct 1, 2022
1 parent b74c6f1 commit 87b0433
Show file tree
Hide file tree
Showing 83 changed files with 1,515 additions and 7,412 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/cmake-build-*
/build
/typescript/out
/typescript/experimental

/tools

Expand Down
Binary file removed qresource/compiled/org.cocoa.internal.v8.crpkg
Binary file not shown.
62 changes: 0 additions & 62 deletions qresource/org.cocoa.internal.v8/canvaskit.js

This file was deleted.

5 changes: 0 additions & 5 deletions qresource/org.cocoa.internal.v8/tests/hello_world.js

This file was deleted.

File renamed without changes.
131 changes: 131 additions & 0 deletions qresource/packages/internal_v8/canvaskit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// %scope UserExecute:forbidden UserImport:allowed SysExecute:allowed

import * as std from 'core';

async function loadCanvasKitWASMWithPolyfill() {
// Polyfill the `window` object to cheat the WASM loader that we are
// in the web environment.
global.window = {};

// Polyfill the `document` object since the WASM loader requires
// `document.currentScript.src` to locate itself.
global.document = {
currentScript: {
// We just provide a fake source location here because the
// WASM loader will not actually use it to locate files.
src: '<fake-url>'
}
};

const PATH_PLACEHOLDER = "internal:unused-path";

// Polyfill the `fetch` function by which the WASM loader reads the
// filesystem. Although the specification says that the `fetch` function
// should not be used to fetch filesystem data, we still use it as
// a simpler replacement of `XMLHttpRequest`.
global.fetch = (url) => {
if (url !== PATH_PLACEHOLDER) {
return Promise.reject("Invalid path for polyfill implementation. " +
"This is an internal error and should be reported to the developers.");
}

// Load the WASM file from the crpkg package
let buffer = std.Buffer.MakeFromPackageFile("org.cocoa.internal.v8", "/canvaskit/canvaskit.wasm");

// Resolve the promise with an emulated `Response` object.
return Promise.resolve({
ok: true,
arrayBuffer: () => {
return buffer.byteArray;
}
});
};

global.exports = {};

await import('internal:///canvaskit/canvaskit.js');
const initializer = global.exports["CanvasKitInit"];

const result = await initializer({
locateFile: (file) => {
return PATH_PLACEHOLDER;
}
});

// Delete our polyfills
delete global.exports;
delete global.window;
delete global.document;
delete global.fetch;

return result;
}

// An instance of `CanvasKit` interface. Constructors and factories of other
// objects are accessible through this instance.
export const canvaskit = await loadCanvasKitWASMWithPolyfill();

const typefaceCacheMap = [];

canvaskit.registerRenderableTypeface = function(face) {
if (!face) {
throw new TypeError('Invalid Typeface object');
}

const key = {
family: face._getFamilyName(),
weight: face._getWeightInfo(),
width: face._getWidthInfo(),
slant: face._getSlantInfo(),
_equal(other) {
return (other.family === this.family &&
other.weight === this.weight &&
other.width === this.width &&
other.slant === this.slant);
}
};

const faceWidthSerialized = {
typeface: face,
serialized: null
};

typefaceCacheMap.push({ key: key, value: faceWidthSerialized });
return key;
};

canvaskit.getRenderableTypeface = function (key) {
for (let pair of typefaceCacheMap) {
if (pair.key._equal(key)) {
return pair.value.typeface;
}
}
return null;
};

canvaskit.bindWithInitializedRenderHost = function(renderHost) {
renderHost.SetTypefaceTransferCallback((info) => {
if (typeof info.family != 'string' || typeof info.weight != 'number' ||
typeof info.width != 'number' || typeof info.slant != 'string')
{
throw new TypeError('Invalid TypefaceInfo object');
}

let foundFace = null;
for (let pair of typefaceCacheMap) {
if (pair.key._equal(info)) {
foundFace = pair.value;
break;
}
}
if (!foundFace) {
throw new Error(`Failed to find typeface '${info.family}' in cache map`);
}

if (!foundFace.serialized) {
foundFace.serialized = foundFace.typeface.serialize();
}

return foundFace.serialized;
});
};
Binary file not shown.
11 changes: 7 additions & 4 deletions script/deploy-v8-skia-artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ function copy_file() {
cp $src_file $dst_file
}

lib_directory='./build/lib'
build_directory='./build'
lib_directory="${build_directory}/lib"

v8_build_type='release.shared'
skia_build_type='release.shared'
Expand Down Expand Up @@ -46,15 +47,17 @@ so_library_files=(
"skia/out/${skia_build_type}/libskunicode.so"
)

v8_resource_files=(
resource_files=(
"v8/out/${v8_build_type}/snapshot_blob.bin"
"skia/out/canvaskit_wasm/canvaskit.js"
"skia/out/canvaskit_wasm/canvaskit.wasm"
)

for so_file in ${so_library_files[@]}; do
copy_file ${so_file} ${lib_directory}
done

for res_file in ${v8_resource_files}; do
copy_file ${res_file} ../qresource/org.cocoa.internal.v8
for res_file in ${resource_files[@]}; do
copy_file ${res_file} ${build_directory}
done

20 changes: 13 additions & 7 deletions src/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
enable_language(C ASM CXX)
set(BINARY_QRES_DIR ${CMAKE_BINARY_DIR}/qresource)
file(MAKE_DIRECTORY ${BINARY_QRES_DIR})
file(MAKE_DIRECTORY ${BINARY_QRES_DIR}/packages)

set(
QRESOURCE_AUTOLOAD_IMAGES
${QRESOURCE_COMPILED_DIR}/org.cocoa.internal.v8.crpkg
set(CRPKG_INTERNAL_V8 ${BINARY_QRES_DIR}/packages/org.cocoa.internal.v8.crpkg)

file(GLOB CRPKG_INTERNAL_V8_FILES ${QRESOURCE_DIR}/packages/internal_v8/*)
add_custom_command(
OUTPUT ${CRPKG_INTERNAL_V8}
COMMAND ${CMAKE_BINARY_DIR}/cocoa-qresc ${QRESOURCE_DIR}/packages/internal_v8 ${BINARY_QRES_DIR}/packages
DEPENDS cocoa-qresc ${CRPKG_INTERNAL_V8_FILES}
)

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/QResourceAutoloadTbl.cc
COMMAND ${CMAKE_HOME_DIRECTORY}/script/intern-crpkgs.py
${QRESOURCE_AUTOLOAD_IMAGES} >${CMAKE_CURRENT_BINARY_DIR}/QResourceAutoloadTbl.cc
DEPENDS ${QRESOURCE_AUTOLOAD_IMAGES}
COMMAND ${CMAKE_HOME_DIRECTORY}/script/intern-crpkgs.py ${CRPKG_INTERNAL_V8}
>${CMAKE_CURRENT_BINARY_DIR}/QResourceAutoloadTbl.cc
DEPENDS ${CRPKG_INTERNAL_V8}
)

add_library(
Expand Down
15 changes: 14 additions & 1 deletion src/Core/ProcessSignalHandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

#include <csignal>
#include <cxxabi.h>

#define UNW_LOCAL_ONLY
#include "libunwind.h"
Expand All @@ -33,6 +34,17 @@ namespace cocoa {

namespace {

std::string demangle_cpp_symbol(char const *sym)
{
char *demangled = abi::__cxa_demangle(sym, nullptr, nullptr, nullptr);
if (demangled == nullptr)
return sym;

std::string ret(demangled);
std::free(demangled);
return ret;
}

void primary_signal_handler_entrypoint(int signum, ::siginfo_t *siginfo, void *data)
{
auto *ucontext = reinterpret_cast<::ucontext_t*>(data);
Expand All @@ -50,7 +62,8 @@ void primary_signal_handler_entrypoint(int signum, ::siginfo_t *siginfo, void *d
{
unw_word_t poff;
unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &poff);
fmt::print(stderr, "[interrupt] #{} {} <+{}>\n", d, proc_name, poff);
fmt::print(stderr, "[interrupt] #{} {} <+{}>\n",
d, demangle_cpp_symbol(proc_name), poff);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/Gallium/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ add_library(Gallium STATIC
bindings/core/Exports.cc
bindings/core/Property.cc
bindings/core/Filesystem.cc
bindings/core/FileSyncOperations.cc
bindings/core/Buffer.cc
bindings/core/Process.cc
bindings/core/Stream.cc
Expand All @@ -77,7 +78,6 @@ add_library(Gallium STATIC
bindings/glamor/DisplayWrap.cc
bindings/glamor/SurfaceWrap.cc
bindings/glamor/BlenderWrap.cc
bindings/glamor/MoeTranslationToolchainWrap.cc
bindings/glamor/CkPictureWrap.cc
bindings/glamor/CkImageWrap.cc
bindings/glamor/CkBitmapWrap.cc
Expand All @@ -87,6 +87,8 @@ add_library(Gallium STATIC
bindings/glamor/SceneBuilder.h
bindings/glamor/SceneBuilder.cc
bindings/glamor/CursorWrap.cc
bindings/glamor/CanvasKitTransferContext.h
bindings/glamor/CanvasKitTransferContext.cc
)
target_include_directories(Gallium PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

Expand Down
2 changes: 1 addition & 1 deletion src/Gallium/Runtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ void Runtime::RunWithMainLoop()
{
v8::HandleScope handle_scope(isolate_);

EvaluateModule("internal:///gallium/bootstrap.js", nullptr, nullptr, false, true);
EvaluateModule("internal:///bootstrap.js", nullptr, nullptr, false, true);

if (!options_.start_with_inspector)
{
Expand Down
Loading

0 comments on commit 87b0433

Please sign in to comment.