mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 00:08:59 +00:00
replace calloc with mimalloc
This commit is contained in:
@@ -134,6 +134,9 @@ pub const Page = struct {
|
|||||||
self.session.env.stop();
|
self.session.env.stop();
|
||||||
// TODO unload document: https://html.spec.whatwg.org/#unloading-documents
|
// TODO unload document: https://html.spec.whatwg.org/#unloading-documents
|
||||||
|
|
||||||
|
// clear netsurf memory arena.
|
||||||
|
parser.deinit();
|
||||||
|
|
||||||
_ = self.arena.reset(.free_all);
|
_ = self.arena.reset(.free_all);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,6 +214,9 @@ pub const Page = struct {
|
|||||||
fn loadHTMLDoc(self: *Page, reader: anytype, charset: []const u8) !void {
|
fn loadHTMLDoc(self: *Page, reader: anytype, charset: []const u8) !void {
|
||||||
const alloc = self.arena.allocator();
|
const alloc = self.arena.allocator();
|
||||||
|
|
||||||
|
// start netsurf memory arena.
|
||||||
|
try parser.init();
|
||||||
|
|
||||||
log.debug("parse html with charset {s}", .{charset});
|
log.debug("parse html with charset {s}", .{charset});
|
||||||
|
|
||||||
const ccharset = try alloc.dupeZ(u8, 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.item(1)", .ex = "null" },
|
||||||
.{ .src = "a.getNamedItem('id')", .ex = "[object Attr]" },
|
.{ .src = "a.getNamedItem('id')", .ex = "[object Attr]" },
|
||||||
.{ .src = "a.getNamedItem('foo')", .ex = "null" },
|
.{ .src = "a.getNamedItem('foo')", .ex = "null" },
|
||||||
// TODO: with setCAllocator this test fails with a segfault
|
.{ .src = "a.setNamedItem(a.getNamedItem('id'))", .ex = "[object Attr]" },
|
||||||
// see https://github.com/lightpanda-io/browsercore/issues/197
|
|
||||||
// .{ .src = "a.setNamedItem(a.getNamedItem('id'))", .ex = "[object Attr]" },
|
|
||||||
};
|
};
|
||||||
try checkCases(js_env, &setItem);
|
try checkCases(js_env, &setItem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ pub fn main() !void {
|
|||||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|
||||||
|
try parser.init();
|
||||||
|
defer parser.deinit();
|
||||||
|
|
||||||
// document
|
// document
|
||||||
const file = try std.fs.cwd().openFile("test.html", .{});
|
const file = try std.fs.cwd().openFile("test.html", .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ const std = @import("std");
|
|||||||
const Browser = @import("browser/browser.zig").Browser;
|
const Browser = @import("browser/browser.zig").Browser;
|
||||||
|
|
||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const setCAllocator = @import("calloc.zig").setCAllocator;
|
|
||||||
const apiweb = @import("apiweb.zig");
|
const apiweb = @import("apiweb.zig");
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
@@ -30,10 +29,6 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
const allocator = gpa.allocator();
|
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);
|
var args = try std.process.argsWithAllocator(allocator);
|
||||||
defer args.deinit();
|
defer args.deinit();
|
||||||
|
|
||||||
@@ -70,9 +65,10 @@ pub fn main() !void {
|
|||||||
defer browser.deinit();
|
defer browser.deinit();
|
||||||
|
|
||||||
var page = try browser.currentSession().createPage();
|
var page = try browser.currentSession().createPage();
|
||||||
defer page.end();
|
defer page.deinit();
|
||||||
|
|
||||||
try page.navigate(url);
|
try page.navigate(url);
|
||||||
|
defer page.end();
|
||||||
|
|
||||||
if (dump) {
|
if (dump) {
|
||||||
try page.dump(std.io.getStdOut());
|
try page.dump(std.io.getStdOut());
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const setCAllocator = @import("calloc.zig").setCAllocator;
|
|
||||||
|
|
||||||
const parser = @import("netsurf.zig");
|
const parser = @import("netsurf.zig");
|
||||||
const apiweb = @import("apiweb.zig");
|
const apiweb = @import("apiweb.zig");
|
||||||
@@ -38,9 +37,8 @@ pub fn main() !void {
|
|||||||
var arena = std.heap.ArenaAllocator.init(gpa.allocator());
|
var arena = std.heap.ArenaAllocator.init(gpa.allocator());
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|
||||||
var c_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
try parser.init();
|
||||||
defer c_arena.deinit();
|
defer parser.deinit();
|
||||||
setCAllocator(c_arena.allocator());
|
|
||||||
|
|
||||||
// document
|
// document
|
||||||
const file = try std.fs.cwd().openFile("test.html", .{});
|
const file = try std.fs.cwd().openFile("test.html", .{});
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const jsruntime = @import("jsruntime");
|
|||||||
const generate = @import("generate.zig");
|
const generate = @import("generate.zig");
|
||||||
const pretty = @import("pretty");
|
const pretty = @import("pretty");
|
||||||
|
|
||||||
const setCAllocator = @import("calloc.zig").setCAllocator;
|
|
||||||
const parser = @import("netsurf.zig");
|
const parser = @import("netsurf.zig");
|
||||||
const apiweb = @import("apiweb.zig");
|
const apiweb = @import("apiweb.zig");
|
||||||
const Window = @import("html/window.zig").Window;
|
const Window = @import("html/window.zig").Window;
|
||||||
@@ -39,6 +38,9 @@ fn testExecFn(
|
|||||||
js_env: *jsruntime.Env,
|
js_env: *jsruntime.Env,
|
||||||
comptime execFn: jsruntime.ContextExecFn,
|
comptime execFn: jsruntime.ContextExecFn,
|
||||||
) anyerror!void {
|
) anyerror!void {
|
||||||
|
try parser.init();
|
||||||
|
defer parser.deinit();
|
||||||
|
|
||||||
// start JS env
|
// start JS env
|
||||||
try js_env.start(alloc);
|
try js_env.start(alloc);
|
||||||
defer js_env.stop();
|
defer js_env.stop();
|
||||||
@@ -88,7 +90,6 @@ fn testsAllExecFn(
|
|||||||
|
|
||||||
inline for (testFns) |testFn| {
|
inline for (testFns) |testFn| {
|
||||||
try testExecFn(alloc, js_env, testFn);
|
try testExecFn(alloc, js_env, testFn);
|
||||||
_ = c_arena.reset(.retain_capacity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,8 +118,6 @@ const Run = enum {
|
|||||||
unit,
|
unit,
|
||||||
};
|
};
|
||||||
|
|
||||||
var c_arena: std.heap.ArenaAllocator = undefined;
|
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
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
|
// run js tests
|
||||||
if (run == .all or run == .browser) try run_js(out);
|
if (run == .all or run == .browser) try run_js(out);
|
||||||
|
|
||||||
@@ -163,6 +158,9 @@ pub fn main() !void {
|
|||||||
if (run == .all or run == .unit) {
|
if (run == .all or run == .unit) {
|
||||||
std.debug.print("\n", .{});
|
std.debug.print("\n", .{});
|
||||||
for (builtin.test_functions) |test_fn| {
|
for (builtin.test_functions) |test_fn| {
|
||||||
|
try parser.init();
|
||||||
|
defer parser.deinit();
|
||||||
|
|
||||||
try test_fn.func();
|
try test_fn.func();
|
||||||
std.debug.print("{s}\tOK\n", .{test_fn.name});
|
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.
|
// 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 {
|
pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const u8, loader: *FileLoader) !jsruntime.JSResult {
|
||||||
const alloc = arena.allocator();
|
const alloc = arena.allocator();
|
||||||
|
try parser.init();
|
||||||
|
defer parser.deinit();
|
||||||
|
|
||||||
// document
|
// document
|
||||||
const file = try std.fs.cwd().openFile(f, .{});
|
const file = try std.fs.cwd().openFile(f, .{});
|
||||||
|
|||||||
Reference in New Issue
Block a user