Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,12 @@ def default_setting(name, new_default):
settings.FETCH = 1
settings.JS_LIBRARIES.append((0, 'library_asmfs.js'))

if settings.WASMFS:
state.forced_stdlibs.append('libwasmfs')
settings.FILESYSTEM = 0
settings.SYSCALLS_REQUIRE_FILESYSTEM = 0
settings.JS_LIBRARIES.append((0, 'library_wasmfs.js'))

# Explicitly drop linking in a malloc implementation if program is not using any dynamic allocation calls.
if not settings.USES_DYNAMIC_ALLOC:
settings.MALLOC = 'none'
Expand Down
17 changes: 17 additions & 0 deletions src/library_wasmfs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var WasmfsLibrary = {
$wasmfsBuffers: [null, [], []],
emscripten_wasmfs_printbuffer__deps: ['$wasmfsBuffers'],
emscripten_wasmfs_printbuffer: function(stream, ptr, len) {
for (var j = 0; j < len; j++) {
if (HEAPU8[ptr+j] === 0 || HEAPU8[ptr+j] === 10) {
(stream === 1 ? out : err)(UTF8ArrayToString(wasmfsBuffers[stream], 0));
wasmfsBuffers[stream].length = 0;
} else {
wasmfsBuffers[stream].push(HEAPU8[ptr+j]);
}
}

}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend implementing this whole function in C/C++. That way the state will be multithreading safe from the get-go (e.g. for behavior like fflush()ing stdout/stderr from another thread than the one(s) that have done partial printing). That method could use e.g. emscripten_console_log() and emscripten_console_error() for the printing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the general case I agree, but for stdout I think we need to proxy to the main thread anyhow - so that we can print it out on the page? If so, then I'm not sure how to make that multithreaded?


mergeInto(LibraryManager.library, WasmfsLibrary);
2 changes: 2 additions & 0 deletions src/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ var LibraryManager = {
}
libraries.push('library_noderawfs.js');
}
} else {
libraries.push('library_wasmfs.js');
}

// Additional JS libraries (without AUTO_JS_LIBRARIES, link to these explicitly via -lxxx.js)
Expand Down
2 changes: 1 addition & 1 deletion src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ function abort(what) {

#include "memoryprofiler.js"

#if ASSERTIONS && !('$FS' in addedLibraryItems) && !ASMFS
#if ASSERTIONS && !('$FS' in addedLibraryItems) && !ASMFS && !WASMFS
Comment thread
ethanalee marked this conversation as resolved.
// show errors on likely calls to FS when it was not included
var FS = {
error: function() {
Expand Down
6 changes: 6 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,12 @@ var FETCH = 0;
// [link]
var ASMFS = 0;

// ATTENTION [WIP]: Experimental feature. Please use at your own risk.
// This will eventually replace the current JS file system implementation.
// If set to 1, uses new filesystem implementation.
// [link]
var WASMFS = 0;

// If set to 1, embeds all subresources in the emitted file as base64 string
// literals. Embedded subresources may include (but aren't limited to) wasm,
// asm.js, and static memory initialization code.
Expand Down
54 changes: 54 additions & 0 deletions system/lib/wasmfs/wasmfs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2021 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
// wasmfs.cpp will implement a new file system that replaces the existing JS filesystem.
// Current Status: Work in Progress.
// See https://github.com/emscripten-core/emscripten/issues/15041.

#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <stdlib.h>
#include <wasi/api.h>

extern "C" {

int emscripten_wasmfs_printbuffer(__wasi_fd_t fd, const uint8_t* ptr, __wasi_size_t len);

__wasi_errno_t __wasi_fd_write(
__wasi_fd_t fd, const __wasi_ciovec_t* iovs, size_t iovs_len, __wasi_size_t* nwritten) {
// FD 1 = STDOUT and FD 2 = STDERR.
// Temporary hardcoding of filedescriptor values.
// TODO: May not want to proxy stderr (fd == 2) to the main thread.
// This will not not show in HTML, a console.warn in a worker is suffficient.
// This would be a change from the current FS.
if (fd == 1 || fd == 2) {
Comment thread
kripken marked this conversation as resolved.
__wasi_size_t num = 0;
for (size_t i = 0; i < iovs_len; i++) {
const uint8_t* ptr = iovs[i].buf;
__wasi_size_t len = iovs[i].buf_len;
emscripten_wasmfs_printbuffer(fd, ptr, len);
num += len;
}
*nwritten = num;
}
return 0;
}

__wasi_errno_t __wasi_fd_seek(
__wasi_fd_t fd, __wasi_filedelta_t offset, __wasi_whence_t whence, __wasi_filesize_t* newoffset) {
emscripten_console_log("__wasi_fd_seek has been temporarily stubbed and is inert");
abort();
Comment thread
ethanalee marked this conversation as resolved.
}

__wasi_errno_t __wasi_fd_close(__wasi_fd_t fd) {
emscripten_console_log("__wasi_fd_close has been temporarily stubbed and is inert");
abort();
}

__wasi_errno_t __wasi_fd_read(
__wasi_fd_t fd, const __wasi_iovec_t* iovs, size_t iovs_len, __wasi_size_t* nread) {
emscripten_console_log("__wasi_fd_read has been temporarily stubbed and is inert");
abort();
}
}
1 change: 1 addition & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ def verify_es5(self, filename):
es_check_env = os.environ.copy()
es_check_env['PATH'] = os.path.dirname(config.NODE_JS[0]) + os.pathsep + es_check_env['PATH']
try:
# Comment out --quiet if more detailed error logging is needed
shared.run_process(es_check + ['es5', os.path.abspath(filename), '--quiet'], stderr=PIPE, env=es_check_env)
except subprocess.CalledProcessError as e:
print(e.stderr)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ def can_do_standalone(self):
'-fsanitize=address' not in self.emcc_args


def also_with_wasmfs(func):
def decorated(self):
func(self)
print('wasmfs')
if self.get_setting('STANDALONE_WASM'):
self.skipTest("test currently cannot run both with WASMFS and STANDALONE_WASM")
self.set_setting('WASMFS')
func(self)
return decorated
Comment thread
kripken marked this conversation as resolved.


# Impure means a test that cannot run in a wasm VM yet, as it is not 100%
# standalone. We can still run them with the JS code though.
def also_with_standalone_wasm(wasm2c=False, impure=False):
Expand Down Expand Up @@ -308,6 +319,7 @@ def get_bullet_library(self, use_cmake):
cache_name_extra=configure_commands[0])

@also_with_standalone_wasm()
@also_with_wasmfs
def test_hello_world(self):
self.do_core_test('test_hello_world.c')
# must not emit this unneeded internal thing
Expand Down
10 changes: 10 additions & 0 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,16 @@ def can_build(self):
return True


class libwasmfs(MTLibrary):
name = 'libwasmfs'

def get_files(self):
return [utils.path_from_root('system/lib/wasmfs/wasmfs.cpp')]

def can_build(self):
return settings.WASMFS


class libhtml5(Library):
name = 'libhtml5'

Expand Down