mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 22:53:28 +00:00
replace calloc with mimalloc
This commit is contained in:
@@ -134,6 +134,9 @@ pub const Page = struct {
|
||||
self.session.env.stop();
|
||||
// TODO unload document: https://html.spec.whatwg.org/#unloading-documents
|
||||
|
||||
// clear netsurf memory arena.
|
||||
parser.deinit();
|
||||
|
||||
_ = self.arena.reset(.free_all);
|
||||
}
|
||||
|
||||
@@ -211,6 +214,9 @@ pub const Page = struct {
|
||||
fn loadHTMLDoc(self: *Page, reader: anytype, charset: []const u8) !void {
|
||||
const alloc = self.arena.allocator();
|
||||
|
||||
// start netsurf memory arena.
|
||||
try parser.init();
|
||||
|
||||
log.debug("parse html with charset {s}", .{charset});
|
||||
|
||||
const ccharset = try alloc.dupeZ(u8, charset);
|
||||
|
||||
164
src/calloc.zig
164
src/calloc.zig
@@ -1,164 +0,0 @@
|
||||
// MIT License
|
||||
// Copyright 2024 Lightpanda
|
||||
// Original copyright 2021 pfg and marler8997
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
// associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
// portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// ---------------------------
|
||||
|
||||
// This file is a mix between:
|
||||
// - malloc functions of ziglibc (https://github.com/marler8997/ziglibc/blob/main/src/cstd.zig)
|
||||
// for the general logic
|
||||
// - this gist https://gist.github.com/pfgithub/65c13d7dc889a4b2ba25131994be0d20
|
||||
// for the header "magic" validator
|
||||
// + some refacto and comments to make the code more clear
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
// TODO: this uses a global variable
|
||||
// it does not allow to set a context-based allocator
|
||||
var alloc: std.mem.Allocator = undefined;
|
||||
|
||||
pub fn setCAllocator(allocator: std.mem.Allocator) void {
|
||||
alloc = allocator;
|
||||
}
|
||||
|
||||
// Alloc mechanism
|
||||
// ---------------
|
||||
|
||||
// C malloc does not know the type of the buffer allocated,
|
||||
// instead it uses a metadata header at the begining of the buffer to store the allocated size.
|
||||
// We copy this behavior by allocating in Zig the size requested + the size of the header.
|
||||
// On this header we store not only the size allocated but also a "magic" validator
|
||||
// to check if the C pointer as been allocated through those cutom malloc functions.
|
||||
|
||||
// The total buffer looks like that:
|
||||
// [Zig buf] = [header][C pointer]
|
||||
|
||||
const al = @alignOf(std.c.max_align_t);
|
||||
|
||||
const Header = struct {
|
||||
comptime {
|
||||
if (@alignOf(Header) > al) @compileError("oops");
|
||||
}
|
||||
|
||||
const len = std.mem.alignForward(usize, al, @sizeOf(Header));
|
||||
|
||||
const MAGIC = 0xABCDEF;
|
||||
const NOMAGIC = 0;
|
||||
|
||||
magic: usize = MAGIC,
|
||||
size: usize,
|
||||
};
|
||||
|
||||
// Buffer manipulation functions
|
||||
|
||||
// setHeader on a buffer allocated in Zig
|
||||
inline fn setHeader(buf: anytype, size: usize) void {
|
||||
// cast buffer to an header
|
||||
const header = @as(*Header, @ptrCast(buf));
|
||||
// and set the relevant information on it (size and "magic" validator)
|
||||
header.* = .{ .size = size };
|
||||
}
|
||||
|
||||
// getHeader from a C pointer
|
||||
fn getHeader(ptr: [*]u8) *Header {
|
||||
// use arithmetic to get (ie. backward) the buffer pointer from the C pointer
|
||||
const buf = ptr - Header.len;
|
||||
// convert many-item pointer to single pointer and cast to an header
|
||||
// return @ptrFromInt(@intFromPtr(buf));
|
||||
// and cast it to an header pointer
|
||||
return @ptrCast(@as([*]align(@alignOf(*Header)) u8, @alignCast(buf)));
|
||||
}
|
||||
|
||||
// getBuf from an header
|
||||
fn getBuf(header: *Header) []align(al) u8 {
|
||||
// cast header pointer to a many-item buffer pointer
|
||||
const buf_ptr = @as([*]u8, @ptrCast(header));
|
||||
// return the buffer with corresponding length
|
||||
const buf = buf_ptr[0..header.size];
|
||||
return @alignCast(buf);
|
||||
}
|
||||
|
||||
inline fn cPtr(buf: [*]align(al) u8) [*]align(al) u8 {
|
||||
// use arithmetic to get (ie. forward) the C pointer from the buffer pointer
|
||||
return buf + Header.len;
|
||||
}
|
||||
|
||||
// Custom malloc functions
|
||||
|
||||
pub export fn m_alloc(size: usize) callconv(.C) ?[*]align(al) u8 {
|
||||
std.debug.assert(size > 0); // TODO: what should we do in this case?
|
||||
const buf_len = Header.len + size;
|
||||
const buf = alloc.alignedAlloc(u8, al, buf_len) catch |err| switch (err) {
|
||||
error.OutOfMemory => return null,
|
||||
};
|
||||
setHeader(buf, buf_len);
|
||||
return cPtr(buf.ptr);
|
||||
}
|
||||
|
||||
pub export fn re_alloc(ptr: ?[*]align(al) u8, size: usize) callconv(.C) ?[*]align(al) u8 {
|
||||
if (ptr == null) return m_alloc(size);
|
||||
const header = getHeader(ptr.?);
|
||||
const buf = getBuf(header);
|
||||
if (size == 0) {
|
||||
alloc.free(buf);
|
||||
return null;
|
||||
}
|
||||
|
||||
const buf_len = Header.len + size;
|
||||
if (alloc.rawResize(buf, std.math.log2(al), buf_len, @returnAddress())) {
|
||||
setHeader(buf.ptr, buf_len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const new_buf = alloc.reallocAdvanced(
|
||||
buf,
|
||||
buf_len,
|
||||
@returnAddress(),
|
||||
) catch |e| switch (e) {
|
||||
error.OutOfMemory => return null,
|
||||
};
|
||||
setHeader(new_buf.ptr, buf_len);
|
||||
return cPtr(new_buf.ptr);
|
||||
}
|
||||
|
||||
export fn c_alloc(nmemb: usize, size: usize) callconv(.C) ?[*]align(al) u8 {
|
||||
const total = std.math.mul(usize, nmemb, size) catch {
|
||||
// TODO: set errno
|
||||
// errno = c.ENOMEM;
|
||||
return null;
|
||||
};
|
||||
const ptr = m_alloc(total) orelse return null;
|
||||
@memset(ptr[0..total], 0);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub export fn f_ree(ptr: ?[*]align(al) u8) callconv(.C) void {
|
||||
if (ptr == null) return;
|
||||
|
||||
// check header
|
||||
const header = getHeader(ptr.?);
|
||||
if (header.magic != Header.MAGIC) {
|
||||
// either doble-free or allocated outside those custom mallocs
|
||||
// TODO: why?
|
||||
return;
|
||||
}
|
||||
header.magic = Header.NOMAGIC; // prevent double free
|
||||
|
||||
const buf = getBuf(header);
|
||||
alloc.free(buf);
|
||||
}
|
||||
@@ -73,9 +73,7 @@ pub fn testExecFn(
|
||||
.{ .src = "a.item(1)", .ex = "null" },
|
||||
.{ .src = "a.getNamedItem('id')", .ex = "[object Attr]" },
|
||||
.{ .src = "a.getNamedItem('foo')", .ex = "null" },
|
||||
// TODO: with setCAllocator this test fails with a segfault
|
||||
// see https://github.com/lightpanda-io/browsercore/issues/197
|
||||
// .{ .src = "a.setNamedItem(a.getNamedItem('id'))", .ex = "[object Attr]" },
|
||||
.{ .src = "a.setNamedItem(a.getNamedItem('id'))", .ex = "[object Attr]" },
|
||||
};
|
||||
try checkCases(js_env, &setItem);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,9 @@ pub fn main() !void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
try parser.init();
|
||||
defer parser.deinit();
|
||||
|
||||
// document
|
||||
const file = try std.fs.cwd().openFile("test.html", .{});
|
||||
defer file.close();
|
||||
|
||||
@@ -2,7 +2,6 @@ const std = @import("std");
|
||||
const Browser = @import("browser/browser.zig").Browser;
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const setCAllocator = @import("calloc.zig").setCAllocator;
|
||||
const apiweb = @import("apiweb.zig");
|
||||
|
||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||
@@ -30,10 +29,6 @@ pub fn main() !void {
|
||||
}
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var c_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer c_arena.deinit();
|
||||
setCAllocator(c_arena.allocator());
|
||||
|
||||
var args = try std.process.argsWithAllocator(allocator);
|
||||
defer args.deinit();
|
||||
|
||||
@@ -70,9 +65,10 @@ pub fn main() !void {
|
||||
defer browser.deinit();
|
||||
|
||||
var page = try browser.currentSession().createPage();
|
||||
defer page.end();
|
||||
defer page.deinit();
|
||||
|
||||
try page.navigate(url);
|
||||
defer page.end();
|
||||
|
||||
if (dump) {
|
||||
try page.dump(std.io.getStdOut());
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const setCAllocator = @import("calloc.zig").setCAllocator;
|
||||
|
||||
const parser = @import("netsurf.zig");
|
||||
const apiweb = @import("apiweb.zig");
|
||||
@@ -38,9 +37,8 @@ pub fn main() !void {
|
||||
var arena = std.heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var c_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer c_arena.deinit();
|
||||
setCAllocator(c_arena.allocator());
|
||||
try parser.init();
|
||||
defer parser.deinit();
|
||||
|
||||
// document
|
||||
const file = try std.fs.cwd().openFile("test.html", .{});
|
||||
|
||||
@@ -5,7 +5,6 @@ const jsruntime = @import("jsruntime");
|
||||
const generate = @import("generate.zig");
|
||||
const pretty = @import("pretty");
|
||||
|
||||
const setCAllocator = @import("calloc.zig").setCAllocator;
|
||||
const parser = @import("netsurf.zig");
|
||||
const apiweb = @import("apiweb.zig");
|
||||
const Window = @import("html/window.zig").Window;
|
||||
@@ -39,6 +38,9 @@ fn testExecFn(
|
||||
js_env: *jsruntime.Env,
|
||||
comptime execFn: jsruntime.ContextExecFn,
|
||||
) anyerror!void {
|
||||
try parser.init();
|
||||
defer parser.deinit();
|
||||
|
||||
// start JS env
|
||||
try js_env.start(alloc);
|
||||
defer js_env.stop();
|
||||
@@ -88,7 +90,6 @@ fn testsAllExecFn(
|
||||
|
||||
inline for (testFns) |testFn| {
|
||||
try testExecFn(alloc, js_env, testFn);
|
||||
_ = c_arena.reset(.retain_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +118,6 @@ const Run = enum {
|
||||
unit,
|
||||
};
|
||||
|
||||
var c_arena: std.heap.ArenaAllocator = undefined;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
@@ -152,10 +151,6 @@ pub fn main() !void {
|
||||
}
|
||||
}
|
||||
|
||||
c_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer c_arena.deinit();
|
||||
setCAllocator(c_arena.allocator());
|
||||
|
||||
// run js tests
|
||||
if (run == .all or run == .browser) try run_js(out);
|
||||
|
||||
@@ -163,6 +158,9 @@ pub fn main() !void {
|
||||
if (run == .all or run == .unit) {
|
||||
std.debug.print("\n", .{});
|
||||
for (builtin.test_functions) |test_fn| {
|
||||
try parser.init();
|
||||
defer parser.deinit();
|
||||
|
||||
try test_fn.func();
|
||||
std.debug.print("{s}\tOK\n", .{test_fn.name});
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ const Types = @import("../main_wpt.zig").Types;
|
||||
// It loads first the js libs files.
|
||||
pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const u8, loader: *FileLoader) !jsruntime.JSResult {
|
||||
const alloc = arena.allocator();
|
||||
try parser.init();
|
||||
defer parser.deinit();
|
||||
|
||||
// document
|
||||
const file = try std.fs.cwd().openFile(f, .{});
|
||||
|
||||
Reference in New Issue
Block a user