Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged blaugold's WASM branch, plus fixes #232

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion API/fleece/InstanceCounted.hh
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ namespace fleece {

protected:
InstanceCounted(size_t offset) {track(offset);}
void untrack() const;
private:
void track(size_t offset =0) const;
void untrack() const;
static void dumpInstances(function_ref<void(const InstanceCounted*)>*);

#else
Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ elseif(APPLE)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_apple.cmake")
elseif(ANDROID OR "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_linux.cmake")
elseif(EMSCRIPTEN)
# Emscripten does not actually support shared libraries and instead
# just builds a static library for compatibility with existing
# build setups. We just set this property to suppress a CMake warning.
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)

include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform_emscripten.cmake")
else()
message(FATAL_ERROR "Unsupported platform ${CMAKE_SYSTEM_NAME}!")
endif()
Expand Down Expand Up @@ -54,6 +61,8 @@ add_library(FleeceBase STATIC ${FLEECE_BASE_SRC})
add_executable(fleeceTool Tool/fleece_tool.cc)
target_link_libraries(fleeceTool FleeceObjects)

setup_build()

# Fleece Tests
set_test_source_files(RESULT FLEECE_TEST_SRC)
add_executable(FleeceTests EXCLUDE_FROM_ALL ${FLEECE_TEST_SRC})
Expand Down
2 changes: 2 additions & 0 deletions Fleece.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@
279AC5311C096872002C80DB /* fleece */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fleece; sourceTree = BUILT_PRODUCTS_DIR; };
279AC5331C096872002C80DB /* fleece_tool.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = fleece_tool.cc; sourceTree = "<group>"; };
279AC53B1C097941002C80DB /* Value+Dump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "Value+Dump.cc"; sourceTree = "<group>"; };
27A0B3652C1B89120053B941 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
27A0E3DD24DCD86900380563 /* ConcurrentArena.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ConcurrentArena.hh; sourceTree = "<group>"; };
27A0E3DE24DCD86900380563 /* ConcurrentArena.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ConcurrentArena.cc; sourceTree = "<group>"; };
27A2F73A21248DA40081927B /* FLSlice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLSlice.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -562,6 +563,7 @@
2776AA43208A6C5A004ACE85 /* xcconfigs */,
27298E3E1C00F8A9000CFBA8 /* vendor */,
270FA25D1BF53CAD005DCB13 /* Products */,
27A0B3652C1B89120053B941 /* Makefile */,
2750735D1F4B5F0F003D2CCE /* CMakeLists.txt */,
275B35A2234E4D3C00FE9CF0 /* cmake */,
27DE2EE22125FAC600123597 /* Frameworks */,
Expand Down
2 changes: 1 addition & 1 deletion Fleece/Integration/ObjC/MTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ static void verifyDictIterator(NSDictionary *dict) {
NSUInteger i = 0;
for (id o in array) {
NSLog(@"item #%zu: %@", i, o);
CHECK([o isEqualTo: orig[i]]);
CHECK([o isEqual: orig[i]]);
++i;
}
}
Expand Down
75 changes: 66 additions & 9 deletions Fleece/Support/Backtrace.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#include <dlfcn.h> // dladdr()

#ifndef __ANDROID__
#if !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
#define HAVE_EXECINFO
#include <execinfo.h> // backtrace(), backtrace_symbols()
#else
Expand All @@ -39,12 +39,16 @@
#define HAVE_UNMANGLE
#endif

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif


namespace fleece {
using namespace std;


#ifndef HAVE_EXECINFO
#if !defined(HAVE_EXECINFO) && !defined(__EMSCRIPTEN__)
// Use libunwind to emulate backtrace(). This is limited in that it won't traverse any stack
// frames before a signal handler, so it's not useful for logging the stack upon a crash.
// Adapted from https://stackoverflow.com/a/28858941
Expand Down Expand Up @@ -91,8 +95,11 @@ namespace fleece {


Backtrace::frameInfo Backtrace::getFrame(unsigned i) const {
precondition(i < _addrs.size());
frameInfo frame = { };
#ifdef __EMSCRIPTEN__
precondition(i < _frames.size());
#else
precondition(i < _addrs.size());
Dl_info info;
if (dladdr(_addrs[i], &info)) {
frame.pc = _addrs[i];
Expand All @@ -103,11 +110,10 @@ namespace fleece {
if (slash)
frame.library = slash + 1;
}

#endif
return frame;
}


// If any of these strings occur in a backtrace, suppress further frames.
static constexpr const char* kTerminalFunctions[] = {
"_C_A_T_C_H____T_E_S_T_",
Expand All @@ -132,8 +138,34 @@ namespace fleece {
}
}


bool Backtrace::writeTo(ostream &out) const {
#ifdef __EMSCRIPTEN__
int i = 0;
for (auto &frameRef : _frames) {
if (i++ > 0)
out << "\n";
out << '\t';

string frame(frameRef);

bool stop = false;
for (auto fn : kTerminalFunctions) {
if (frame.find(fn) != string::npos)
stop = true;
}

for (auto &abbrev : kAbbreviations)
replace(frame, abbrev.old, abbrev.nuu);

out << frame;

if (stop) {
out << "\n\t... (more suppressed) ...";
break;
}
}
return true;
#else
for (decltype(_addrs.size()) i = 0; i < _addrs.size(); ++i) {
if (i > 0)
out << '\n';
Expand Down Expand Up @@ -179,6 +211,7 @@ namespace fleece {
}
}
return true;
#endif
}


Expand Down Expand Up @@ -318,7 +351,9 @@ namespace fleece {
namespace fleece {

Backtrace::~Backtrace() {
#ifndef __EMSCRIPTEN__
free(_symbols);
#endif
}

std::string Unmangle(const char *name NONNULL) {
Expand All @@ -344,23 +379,45 @@ namespace fleece {

Backtrace::Backtrace(unsigned skipFrames, unsigned maxFrames) {
if (maxFrames > 0)
capture(skipFrames + 1, maxFrames);
_capture(skipFrames + 1, maxFrames);
}


void Backtrace::_capture(unsigned skipFrames, unsigned maxFrames) {
#ifdef __EMSCRIPTEN__
auto callstackSize = emscripten_get_callstack(EM_LOG_JS_STACK | EM_LOG_C_STACK, nullptr, 0);
if (callstackSize > 0) {
auto buffer = (char*)malloc(callstackSize + 128);
emscripten_get_callstack(EM_LOG_JS_STACK | EM_LOG_C_STACK, buffer, callstackSize);;
istringstream frames(buffer);
string frame;
int i = 0;
while (i < maxFrames && getline(frames, frame, '\n')) {
i++;
// Remove the " at " prefix before each frame.
replace(frame, " at ", "");
_frames.push_back(frame);
}
skip(skipFrames);
}
#else
_addrs.resize(++skipFrames + maxFrames); // skip this frame
auto n = backtrace(&_addrs[0], skipFrames + maxFrames);
_addrs.resize(n);
skip(skipFrames);
#if !defined(_MSC_VER) && !defined(__ANDROID__)
#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__EMSCRIPTEN__)
_symbols = backtrace_symbols(_addrs.data(), int(_addrs.size()));
#endif
#endif
}


void Backtrace::skip(unsigned nFrames) {
#ifdef __EMSCRIPTEN__
_frames.erase(_frames.begin(),_frames.begin() + min(size_t(nFrames), _frames.size()));
#else
_addrs.erase(_addrs.begin(), _addrs.begin() + min(size_t(nFrames), _addrs.size()));
#endif
}


Expand Down Expand Up @@ -388,7 +445,7 @@ namespace fleece {
out << "unknown exception type\n";
}
}
out << "Backtrace:";
out << "Backtrace:" << endl;
bt.writeTo(out);
}

Expand Down
12 changes: 11 additions & 1 deletion Fleece/Support/Backtrace.hh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ namespace fleece {
};

/// The number of stack frames captured.
unsigned size() const {return (unsigned)_addrs.size();}
unsigned size() const {
#ifdef __EMSCRIPTEN__
return (unsigned)_frames.size();
#else
return (unsigned)_addrs.size();
#endif
}

/// Returns info about a stack frame. 0 is the top.
frameInfo getFrame(unsigned) const;
Expand All @@ -74,8 +80,12 @@ namespace fleece {
char* printFrame(unsigned i) const;
static void writeCrashLog(std::ostream&);

#ifdef __EMSCRIPTEN__
std::vector<std::string> _frames;
#else
std::vector<void*> _addrs; // Array of PCs in backtrace, top first
char** _symbols { nullptr };
#endif
};


Expand Down
2 changes: 1 addition & 1 deletion Fleece/Support/NumConversion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#if !defined(_MSC_VER) && !defined(__GLIBC__)
#if !defined(_MSC_VER) && !defined(__GLIBC__) && !defined(__EMSCRIPTEN__)
#include <xlocale.h>
#endif

Expand Down
2 changes: 2 additions & 0 deletions Fleece/Support/ParseDate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ namespace fleece {
auto offset = seconds(-s);
#elif defined(__DARWIN_UNIX03) || defined(__ANDROID__) || defined(_XOPEN_SOURCE) || defined(_SVID_SOURCE)
auto offset = seconds(-timezone);
#elif defined(__EMSCRIPTEN__)
auto offset = seconds(timezone);
Copy link
Member

Choose a reason for hiding this comment

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

Is this negated on purpose? Does ECMAScript somehow change the functionality here?

Copy link
Contributor

Choose a reason for hiding this comment

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

It was necessary to make the tests pass, but it seems like a bug in Emscripten which implements all these UNIX APIs. Not sure what the current behavior is, though.

#else
# error Unimplemented GetLocalTZOffset
#endif
Expand Down
43 changes: 43 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Fleece makefile ... just to kick off CMake builds

native: OUT = build_cmake/native
native:
mkdir -p $(OUT)
cmake -S . -B $(OUT) -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build $(OUT) -j

test: OUT = build_cmake/test
test:
mkdir -p $(OUT)
cmake -S . -B $(OUT) -DCMAKE_BUILD_TYPE=Debug
cmake --build $(OUT) -j --target FleeceTests
$(OUT)/FleeceTests -r list

tests: test


# WASM build requires Emscripten <https://emscripten.org>
wasm: OUT = build_cmake/wasm
wasm:
mkdir -p $(OUT)
emcmake cmake -S . -B $(OUT) -DCMAKE_BUILD_TYPE=RelWithDebInfo
cd $(OUT) && emmake make -j

test_wasm: OUT = build_cmake/test_wasm
test_wasm:
mkdir -p $(OUT)
emcmake cmake -S . -B $(OUT) -DCMAKE_BUILD_TYPE=Debug
cd $(OUT) && emmake make -j FleeceTests
node $(OUT)/FleeceTests.js -r list

wasm_test: test_wasm
wasm_tests: test_wasm


docs:
doxygen Documentation/Doxyfile
doxygen Documentation/Doxyfile_C++


clean:
rm -rf build_cmake/{native,test,wasm,test_wasm}
3 changes: 3 additions & 0 deletions Tests/EncoderTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,8 @@ class EncoderTests {
CHECK(ParseDouble(floatBuf, recovered));
CHECK(FloatEquals(float(recovered), 2.71828f));

// Emscripten does not come with locales for different languages.
#ifndef __EMSCRIPTEN__
#ifdef _MSC_VER
setlocale(LC_ALL, "fr-FR");
#else
Expand Down Expand Up @@ -1094,6 +1096,7 @@ class EncoderTests {
CHECK(FloatEquals(recovered_f, 2.71828f));

setlocale(LC_ALL, "C");
#endif
}


Expand Down
2 changes: 1 addition & 1 deletion Tests/PerfTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ TEST_CASE("GetUVarint performance", "[.Perf]") {
uint8_t buf[100];
fprintf(stderr, "buf = %p\n", &buf);
double d = 1.0;
while (d <= UINT64_MAX) {
while (d <= (double)UINT64_MAX) {
auto n = (uint64_t)d;
size_t nBytes = PutUVarInt(buf, n);
uint64_t result = 0;
Expand Down
4 changes: 2 additions & 2 deletions Tests/ValueTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace fleece {
TEST_CASE("VarInt read") {
uint8_t buf[100];
uint64_t result;
for (double d = 0.0; d <= UINT64_MAX; d = std::max(d, 1.0) * 1.5) {
for (double d = 0.0; d <= (double)UINT64_MAX; d = std::max(d, 1.0) * 1.5) {
auto n = (uint64_t)d;
std::cerr << std::hex << n << std::dec << ", ";
size_t nBytes = PutUVarInt(buf, n);
Expand All @@ -75,7 +75,7 @@ namespace fleece {

TEST_CASE("VarInt32 read") {
uint8_t buf[100];
for (double d = 0.0; d <= UINT64_MAX; d = std::max(d, 1.0) * 1.5) {
for (double d = 0.0; d <= (double)UINT64_MAX; d = std::max(d, 1.0) * 1.5) {
auto n = (uint64_t)d;
std::cerr << std::hex << n << std::dec << ", ";
size_t nBytes = PutUVarInt(buf, n);
Expand Down
2 changes: 1 addition & 1 deletion Tool/fleece_tool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static void usage(void) {
}


#if defined(__ANDROID__) || defined(__GLIBC__) || defined(_MSC_VER)
#if defined(__ANDROID__) || defined(__GLIBC__) || defined(_MSC_VER) || defined(__EMSCRIPTEN__)
// digittoint is a BSD function, not available on Android, Linux, etc.
static int digittoint(char ch) {
int d = ch - '0';
Expand Down
19 changes: 0 additions & 19 deletions build_cmake/build.sh

This file was deleted.

Loading
Loading