From 4d482e823abb7b1dcd1638e1b2cba3b247fb0647 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Aug 2014 15:27:27 -0700 Subject: [PATCH 01/37] Fix some potential undefined or implementation-specified behavior and simplify code at the same time :) --- system/include/emscripten/bind.h | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index aabcf93674860..dfba112b71240 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -375,27 +375,10 @@ namespace emscripten { } }; - template - struct SignatureString; - - template<> - struct SignatureString<> { - char c = 0; - }; - - template - struct SignatureString { - constexpr SignatureString() - : c(SignatureCode::get()) - {} - char c; - SignatureString rest; - }; - template const char* getSignature(Return (*)(Args...)) { - static constexpr SignatureString sig; - return &sig.c; + static constexpr char str[] = { SignatureCode::get(), SignatureCode::get()..., 0 }; + return str; } } From d98989b9de25f81e1d3f16e3b63190aaf3990589 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 21 Aug 2014 14:22:34 -0700 Subject: [PATCH 02/37] simplify select_overload --- system/include/emscripten/bind.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index dfba112b71240..368bd99f0f320 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -262,19 +262,12 @@ namespace emscripten { //////////////////////////////////////////////////////////////////////////////// template - typename std::add_pointer::type select_overload(typename std::add_pointer::type fn) { + Signature* select_overload(Signature* fn) { return fn; } - namespace internal { - template - struct MemberFunctionType { - typedef Signature (ClassType::*type); - }; - } - template - typename internal::MemberFunctionType::type select_overload(Signature (ClassType::*fn)) { + auto select_overload(Signature (ClassType::*fn)) -> decltype(fn) { return fn; } From 896b0134d062bbfc028844a4ce2c17412fd15f86 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 23 Aug 2014 12:13:10 -0700 Subject: [PATCH 03/37] more template simplification --- system/include/emscripten/bind.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 368bd99f0f320..0cf5ac16981b6 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -289,17 +289,14 @@ namespace emscripten { struct remove_class { using type = R(A...); }; template - struct CalculateLambdaSignature { - using type = typename std::add_pointer< - typename remove_class< - decltype(&LambdaType::operator()) - >::type - >::type; - }; + using LambdaSignature = typename remove_class< + decltype(&LambdaType::operator()) + >::type; } + // requires captureless lambda because implicitly coerces to function pointer template - typename internal::CalculateLambdaSignature::type optional_override(const LambdaType& fp) { + internal::LambdaSignature* optional_override(const LambdaType& fp) { return fp; } From d76cbcaad8c347482243e3a48a1c050670bd3e04 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 30 Aug 2014 05:35:04 +0700 Subject: [PATCH 04/37] Remove scons-tools for now since it doesn't work outside of IMVU. --- scons-tools/closure.py | 28 --- scons-tools/emscripten.py | 496 -------------------------------------- scons-tools/llvm.py | 34 --- 3 files changed, 558 deletions(-) delete mode 100644 scons-tools/closure.py delete mode 100755 scons-tools/emscripten.py delete mode 100755 scons-tools/llvm.py diff --git a/scons-tools/closure.py b/scons-tools/closure.py deleted file mode 100644 index 8f53e507f873d..0000000000000 --- a/scons-tools/closure.py +++ /dev/null @@ -1,28 +0,0 @@ -import os.path -from SCons.Builder import Builder - -def generate(env): - def depend_on_closure_compiler(target, source, env): - env.Depends(target, env['CLOSURE_COMPILER']) - return target, source - - ClosureCompiler = Builder( - action='$JAVA $JAVAFLAGS -jar $CLOSURE_COMPILER $CLOSURE_FLAGS --js_output_file $TARGET $SOURCES', - emitter=depend_on_closure_compiler - ) - - closure = os.path.join( - os.path.dirname(__file__), - '..', - 'third_party', - 'closure-compiler', - 'compiler.jar') - closure = env.File(closure) - - env['JAVA'] = 'java' - env['CLOSURE_COMPILER'] = closure - env.Append( - BUILDERS={'ClosureCompiler':ClosureCompiler}) - -def exists(_env): - return True diff --git a/scons-tools/emscripten.py b/scons-tools/emscripten.py deleted file mode 100755 index 67410ed5f71d8..0000000000000 --- a/scons-tools/emscripten.py +++ /dev/null @@ -1,496 +0,0 @@ -import hashlib -import json -import sys -import os -from SCons.Defaults import Delete -from SCons.Builder import Builder -from SCons.Scanner import Scanner - -def exists(env): - return True - -emscripten_version_files = {} - -def build_version_file(env): - if not env.subst('$EMSCRIPTEN_VERSION_FILE'): - raise AssertionError('Must set EMSCRIPTEN_VERSION_FILE in environment') - if not env.subst('$EMSCRIPTEN_TEMP_DIR'): - raise AssertionError('Must set EMSCRIPTEN_TEMP_DIR in environment') - - EMSCRIPTEN_DEPENDENCIES = [ - env.Glob('${EMSCRIPTEN_HOME}/src/*.js'), - env.Glob('${EMSCRIPTEN_HOME}/src/embind/*.js'), - env.Glob('${EMSCRIPTEN_HOME}/tools/*.js'), - env.Glob('${EMSCRIPTEN_HOME}/tools/*.py'), - '${EMSCRIPTEN_HOME}/emcc', - '${EMSCRIPTEN_HOME}/emscripten.py', - ] - if env.subst('$EMSCRIPTEN_SHELL'): - EMSCRIPTEN_DEPENDENCIES.append('$EMSCRIPTEN_SHELL') - - def touch_file(target, source, env): - m = hashlib.md5() - for s in source: - m.update(file(s.abspath, 'rb').read()) - for t in target: - file(t.abspath, 'wb').write(m.hexdigest()) - - [emscripten_version_file] = env.Command( - '$EMSCRIPTEN_VERSION_FILE', - EMSCRIPTEN_DEPENDENCIES, - touch_file) - - env.AddPostAction( - emscripten_version_file, - Delete(env.Dir('$EMSCRIPTEN_TEMP_DIR/cache/jcache').abspath)) - - return emscripten_version_file - -def get_emscripten_version_file(env): - EMSCRIPTEN_HOME = env.Dir('$EMSCRIPTEN_HOME').abspath - try: - version_file = emscripten_version_files[EMSCRIPTEN_HOME] - except KeyError: - version_file = build_version_file(env) - emscripten_version_files[EMSCRIPTEN_HOME] = version_file - return version_file - -def depend_on_emscripten(node, env, path): - return [get_emscripten_version_file(env)] - -EmscriptenScanner = Scanner( - name='emscripten', - function=depend_on_emscripten) - -def setExtension(filename, extension): - return os.path.splitext(filename)[0] + '.' + extension - -def emscripten(env, target_js, source_bc): - env = env.Clone() - def buildName(extension): - return setExtension(target_js, extension) - - # for debugging and reading generated code. - # not in critical path, uses spare cores. - env.LLVMDis(buildName('ll'), source_bc) - - [opt_ll] = env.LLVMOpt( - buildName('opt.ll'), - source_bc, - LLVM_OPT_FLAGS=['-S']) - - [raw_emscripten_js] = env.Emscripten( - buildName('raw.js'), - [opt_ll]) - - [concatenated_js] = env.Concatenate( - buildName('concat.js'), - [ env['EMSCRIPTEN_PREJS'], - raw_emscripten_js, - env['EMSCRIPTEN_POSTJS'] ]) - - DISABLE_EMSCRIPTEN_WARNINGS = [ - '--jscomp_error', 'ambiguousFunctionDecl', - '--jscomp_error', 'checkDebuggerStatement', - '--jscomp_off', 'checkTypes', - '--jscomp_off', 'checkVars', - '--jscomp_error', 'deprecated', - '--jscomp_off', 'duplicate', - #'--jscomp_error', 'es5strict', - '--jscomp_off', 'missingProperties', # TODO: fix emscripten and turn this one on - '--jscomp_error', 'undefinedNames', - '--jscomp_off', 'undefinedVars', # TODO: fix emscripten and turn this one on - '--jscomp_off', 'uselessCode', - '--jscomp_off', 'globalThis', - ] - - [iter_global_emscripten_js] = env.Concatenate( - buildName('iter.js'), - [ env['EMSCRIPTEN_PREJS'], - raw_emscripten_js, - env['EMSCRIPTEN_POSTJS'] ]) - - [global_cc_emscripten_js] = env.ClosureCompiler( - buildName('global.closure.js'), - concatenated_js, - CLOSURE_FLAGS=['--language_in', 'ECMASCRIPT5']+DISABLE_EMSCRIPTEN_WARNINGS+['--formatting', 'PRETTY_PRINT', '--compilation_level', 'SIMPLE_OPTIMIZATIONS']) - - #env.Append( - # NODEJSFLAGS=['--max-stack-size=1000000000'], - # UGLIFYJSFLAGS=['--stats', '-c', 'warnings=false', '-b']) - #env.UglifyJS( - # buildName('global.uglify.js'), - # concatenated_js) - - [closure_js] = env.ClosureCompiler( - buildName('closure.js'), - concatenated_js, - CLOSURE_FLAGS=['--language_in', 'ECMASCRIPT5']+DISABLE_EMSCRIPTEN_WARNINGS+['--formatting', 'PRETTY_PRINT', '--compilation_level', 'ADVANCED_OPTIMIZATIONS']) - - [emscripten_iteration_js] = env.WrapInModule( - buildName('iteration.js'), - iter_global_emscripten_js) - - [emscripten_js] = env.WrapInModule( - buildName('debug.js'), - global_cc_emscripten_js) - - [emscripten_min_js] = env.WrapInModule( - buildName('min.js'), - closure_js) - - return [emscripten_iteration_js, emscripten_js, emscripten_min_js] - -LIBC_SOURCES = [ - 'system/lib/dlmalloc.c', - 'system/lib/libc/musl/src/internal/floatscan.c', - 'system/lib/libc/musl/src/internal/shgetc.c', - 'system/lib/libc/musl/src/ctype/isalnum.c', - 'system/lib/libc/musl/src/ctype/isalpha.c', - 'system/lib/libc/musl/src/ctype/isascii.c', - 'system/lib/libc/musl/src/ctype/isblank.c', - 'system/lib/libc/musl/src/ctype/iscntrl.c', - 'system/lib/libc/musl/src/ctype/isdigit.c', - 'system/lib/libc/musl/src/ctype/isgraph.c', - 'system/lib/libc/musl/src/ctype/islower.c', - 'system/lib/libc/musl/src/ctype/isprint.c', - 'system/lib/libc/musl/src/ctype/ispunct.c', - 'system/lib/libc/musl/src/ctype/isspace.c', - 'system/lib/libc/musl/src/ctype/isupper.c', - 'system/lib/libc/musl/src/ctype/iswalnum.c', - 'system/lib/libc/musl/src/ctype/iswalpha.c', - 'system/lib/libc/musl/src/ctype/iswblank.c', - 'system/lib/libc/musl/src/ctype/iswcntrl.c', - 'system/lib/libc/musl/src/ctype/iswctype.c', - 'system/lib/libc/musl/src/ctype/iswdigit.c', - 'system/lib/libc/musl/src/ctype/iswgraph.c', - 'system/lib/libc/musl/src/ctype/iswlower.c', - 'system/lib/libc/musl/src/ctype/iswprint.c', - 'system/lib/libc/musl/src/ctype/iswpunct.c', - 'system/lib/libc/musl/src/ctype/iswspace.c', - 'system/lib/libc/musl/src/ctype/iswupper.c', - 'system/lib/libc/musl/src/ctype/iswxdigit.c', - 'system/lib/libc/musl/src/ctype/isxdigit.c', - 'system/lib/libc/musl/src/ctype/toascii.c', - 'system/lib/libc/musl/src/ctype/toupper.c', - 'system/lib/libc/musl/src/ctype/towctrans.c', - 'system/lib/libc/musl/src/ctype/wcswidth.c', - 'system/lib/libc/musl/src/ctype/wctrans.c', - 'system/lib/libc/musl/src/ctype/wcwidth.c', - 'system/lib/libc/musl/src/ctype/tolower.c', - - 'system/lib/libc/musl/src/stdio/__overflow.c', - 'system/lib/libc/musl/src/stdio/__string_read.c', - 'system/lib/libc/musl/src/stdio/__toread.c', - 'system/lib/libc/musl/src/stdio/__towrite.c', - 'system/lib/libc/musl/src/stdio/__uflow.c', - 'system/lib/libc/musl/src/stdio/asprintf.c', - 'system/lib/libc/musl/src/stdio/fputwc.c', - 'system/lib/libc/musl/src/stdio/fputws.c', - 'system/lib/libc/musl/src/stdio/fwprintf.c', - 'system/lib/libc/musl/src/stdio/fwrite.c', - 'system/lib/libc/musl/src/stdio/snprintf.c', - 'system/lib/libc/musl/src/stdio/sprintf.c', - 'system/lib/libc/musl/src/stdio/sscanf.c', - 'system/lib/libc/musl/src/stdio/swprintf.c', - 'system/lib/libc/musl/src/stdio/vasprintf.c', - 'system/lib/libc/musl/src/stdio/vfprintf.c', - 'system/lib/libc/musl/src/stdio/vfscanf.c', - 'system/lib/libc/musl/src/stdio/vfwprintf.c', - 'system/lib/libc/musl/src/stdio/vsnprintf.c', - 'system/lib/libc/musl/src/stdio/vsprintf.c', - 'system/lib/libc/musl/src/stdio/vsscanf.c', - 'system/lib/libc/musl/src/stdio/vswprintf.c', - 'system/lib/libc/musl/src/stdio/vwprintf.c', - 'system/lib/libc/musl/src/stdio/wprintf.c', - - 'system/lib/libc/musl/src/stdlib/atof.c', - 'system/lib/libc/musl/src/stdlib/strtod.c', - - 'system/lib/libc/musl/src/string/bcmp.c', - 'system/lib/libc/musl/src/string/bcopy.c', - 'system/lib/libc/musl/src/string/bzero.c', - 'system/lib/libc/musl/src/string/index.c', - 'system/lib/libc/musl/src/string/memccpy.c', - 'system/lib/libc/musl/src/string/memchr.c', - 'system/lib/libc/musl/src/string/memcmp.c', - 'system/lib/libc/musl/src/string/memmem.c', - 'system/lib/libc/musl/src/string/mempcpy.c', - 'system/lib/libc/musl/src/string/memrchr.c', - 'system/lib/libc/musl/src/string/rindex.c', - 'system/lib/libc/musl/src/string/stpcpy.c', - 'system/lib/libc/musl/src/string/strcasecmp.c', - 'system/lib/libc/musl/src/string/strcasestr.c', - 'system/lib/libc/musl/src/string/strchr.c', - 'system/lib/libc/musl/src/string/strchrnul.c', - 'system/lib/libc/musl/src/string/strcmp.c', - 'system/lib/libc/musl/src/string/strcspn.c', - 'system/lib/libc/musl/src/string/strdup.c', - 'system/lib/libc/musl/src/string/strlcat.c', - 'system/lib/libc/musl/src/string/strlcpy.c', - 'system/lib/libc/musl/src/string/strncasecmp.c', - 'system/lib/libc/musl/src/string/strncat.c', - 'system/lib/libc/musl/src/string/strncmp.c', - 'system/lib/libc/musl/src/string/strndup.c', - 'system/lib/libc/musl/src/string/strnlen.c', - 'system/lib/libc/musl/src/string/strpbrk.c', - 'system/lib/libc/musl/src/string/strrchr.c', - 'system/lib/libc/musl/src/string/strsep.c', - 'system/lib/libc/musl/src/string/strspn.c', - 'system/lib/libc/musl/src/string/strstr.c', - 'system/lib/libc/musl/src/string/strtok.c', - 'system/lib/libc/musl/src/string/strtok_r.c', - 'system/lib/libc/musl/src/string/strverscmp.c', - 'system/lib/libc/musl/src/string/wcpcpy.c', - 'system/lib/libc/musl/src/string/wcpncpy.c', - 'system/lib/libc/musl/src/string/wcscasecmp.c', - 'system/lib/libc/musl/src/string/wcscasecmp_l.c', - 'system/lib/libc/musl/src/string/wcscat.c', - 'system/lib/libc/musl/src/string/wcschr.c', - 'system/lib/libc/musl/src/string/wcscmp.c', - 'system/lib/libc/musl/src/string/wcscpy.c', - 'system/lib/libc/musl/src/string/wcscspn.c', - 'system/lib/libc/musl/src/string/wcsdup.c', - 'system/lib/libc/musl/src/string/wcslen.c', - 'system/lib/libc/musl/src/string/wcsncasecmp.c', - 'system/lib/libc/musl/src/string/wcsncasecmp_l.c', - 'system/lib/libc/musl/src/string/wcsncat.c', - 'system/lib/libc/musl/src/string/wcsncmp.c', - 'system/lib/libc/musl/src/string/wcsncpy.c', - 'system/lib/libc/musl/src/string/wcsnlen.c', - 'system/lib/libc/musl/src/string/wcspbrk.c', - 'system/lib/libc/musl/src/string/wcsrchr.c', - 'system/lib/libc/musl/src/string/wcsspn.c', - 'system/lib/libc/musl/src/string/wcsstr.c', - 'system/lib/libc/musl/src/string/wcstok.c', - 'system/lib/libc/musl/src/string/wcswcs.c', - 'system/lib/libc/musl/src/string/wmemchr.c', - 'system/lib/libc/musl/src/string/wmemcmp.c', - 'system/lib/libc/musl/src/string/wmemcpy.c', - 'system/lib/libc/musl/src/string/wmemmove.c', - 'system/lib/libc/musl/src/string/wmemset.c', - - 'system/lib/libc/musl/src/math/__cos.c', - 'system/lib/libc/musl/src/math/__cosdf.c', - 'system/lib/libc/musl/src/math/__sin.c', - 'system/lib/libc/musl/src/math/__sindf.c', - 'system/lib/libc/musl/src/math/frexp.c', - 'system/lib/libc/musl/src/math/frexpf.c', - 'system/lib/libc/musl/src/math/frexpl.c', - 'system/lib/libc/musl/src/math/ilogb.c', - 'system/lib/libc/musl/src/math/ilogbf.c', - 'system/lib/libc/musl/src/math/ilogbl.c', - 'system/lib/libc/musl/src/math/ldexp.c', - 'system/lib/libc/musl/src/math/ldexpf.c', - 'system/lib/libc/musl/src/math/ldexpl.c', - 'system/lib/libc/musl/src/math/lgamma.c', - 'system/lib/libc/musl/src/math/lgamma_r.c', - 'system/lib/libc/musl/src/math/lgammaf.c', - 'system/lib/libc/musl/src/math/lgammaf_r.c', - 'system/lib/libc/musl/src/math/lgammal.c', - 'system/lib/libc/musl/src/math/logb.c', - 'system/lib/libc/musl/src/math/logbf.c', - 'system/lib/libc/musl/src/math/logbl.c', - 'system/lib/libc/musl/src/math/scalbn.c', - 'system/lib/libc/musl/src/math/scalbnf.c', - 'system/lib/libc/musl/src/math/scalbnl.c', - 'system/lib/libc/musl/src/math/signgam.c', - 'system/lib/libc/musl/src/math/tgamma.c', - 'system/lib/libc/musl/src/math/tgammaf.c', - 'system/lib/libc/musl/src/math/tgammal.c', -] - -LIBCXX_SOURCES = [os.path.join('system/lib/libcxx', x) for x in [ - 'algorithm.cpp', - 'bind.cpp', - #'chrono.cpp', - #'condition_variable.cpp', - #'debug.cpp', - #'exception.cpp', - 'future.cpp', - 'hash.cpp', - #'ios.cpp', - #'iostream.cpp', - 'memory.cpp', - 'mutex.cpp', - 'new.cpp', - 'random.cpp', - 'regex.cpp', - 'stdexcept.cpp', - 'string.cpp', - 'strstream.cpp', - 'system_error.cpp', - #'thread.cpp', - #'typeinfo.cpp', - 'utility.cpp', - 'valarray.cpp', -]] - -LIBCXXABI_SOURCES = [os.path.join('system/lib/libcxxabi/src', x) for x in [ - 'private_typeinfo.cpp', - 'typeinfo.cpp' -]] - -# MAJOR HACK ALERT -# ugh, SCons imports tool .py files multiple times, meaning that global variables aren't really global -# store our "globals" "privately" on the SCons object :( -import SCons - -def build_libembind(env): - emscripten_temp_dir = env.Dir('$EMSCRIPTEN_TEMP_DIR').abspath - try: - libembind_cache = SCons.__emscripten_libembind_cache - except AttributeError: - libembind_cache = {} - SCons.__emscripten_libembind_cache = libembind_cache - try: - return libembind_cache[emscripten_temp_dir] - except KeyError: - pass - - libembind = env.Object( - '$EMSCRIPTEN_TEMP_DIR/internal_libs/bind', - '$EMSCRIPTEN_HOME/system/lib/embind/bind.cpp') - env.Depends(libembind, get_emscripten_version_file(env)) - libembind_cache[emscripten_temp_dir] = libembind - return libembind - -def build_libcxx(env): - emscripten_temp_dir = env.Dir('$EMSCRIPTEN_TEMP_DIR').abspath - try: - libcxx_cache = SCons.__emscripten_libcxx_cache - except AttributeError: - libcxx_cache = {} - SCons.__emscripten_libcxx_cache = libcxx_cache - try: - return libcxx_cache[emscripten_temp_dir] - except KeyError: - pass - - env = env.Clone() - env['CXXFLAGS'] = filter(lambda e: e not in ('-Werror', '-Wall'), env['CXXFLAGS']) - env['CCFLAGS'] = filter(lambda e: e not in ('-Werror', '-Wall'), env['CCFLAGS']) - env['CCFLAGS'] = env['CCFLAGS'] + ['-isystem${EMSCRIPTEN_HOME}/system/lib/libc/musl/src/internal/'] - - objs = [ - env.Object( - '${EMSCRIPTEN_TEMP_DIR}/libcxx_objects/' + os.path.splitext(o)[0] + '.bc', - '${EMSCRIPTEN_HOME}/' + o) - for o in LIBC_SOURCES + LIBCXXABI_SOURCES + LIBCXX_SOURCES] - env.Depends(objs, get_emscripten_version_file(env)) - - libcxx = env.Library('${EMSCRIPTEN_TEMP_DIR}/internal_libs/libcxx', objs) - libcxx_cache[emscripten_temp_dir] = libcxx - return libcxx - -def generate(env): - env.SetDefault( - PYTHON=sys.executable, - EMSCRIPTEN_FLAGS=[], - EMSCRIPTEN_TEMP_DIR=env.Dir('#/emscripten.tmp'), - EMSCRIPTEN_PREJS=[], - EMSCRIPTEN_POSTJS=[], - LLVM_OPT_PASSES=['-std-compile-opts', '-std-link-opts'], - - EMSCRIPTEN_HOME=env.Dir(os.path.join(os.path.dirname(__file__), '..')), - ) - - env.Replace( - CC=os.path.join('${LLVM_ROOT}', '${CLANG}'), - CXX=os.path.join('${LLVM_ROOT}', '${CLANGXX}'), - AR=os.path.join('${LLVM_ROOT}', '${LLVM_LINK}'), - ARCOM='$AR -o $TARGET $SOURCES', - OBJSUFFIX='.bc', - LIBPREFIX='', - LIBSUFFIX='.bc', - RANLIBCOM='', - CCFLAGS=[ - '-U__STRICT_ANSI__', - '-target', 'le32-unknown-nacl', - '-nostdinc', - '-Wno-#warnings', - '-Wno-error=unused-variable', - '-Werror', - '-Os', - '-fno-threadsafe-statics', - '-fvisibility=hidden', - '-fvisibility-inlines-hidden', - '-Xclang', '-nostdinc++', - '-Xclang', '-nobuiltininc', - '-Xclang', '-nostdsysteminc', - '-Xclang', '-isystem$EMSCRIPTEN_HOME/system/include/compat', - '-Xclang', '-isystem$EMSCRIPTEN_HOME/system/include/libc', - '-Xclang', '-isystem$EMSCRIPTEN_HOME/system/include/libcxx', - '-emit-llvm'], - CXXFLAGS=['-std=c++11', '-fno-exceptions'], - ) - env.Append(CPPDEFINES=[ - 'EMSCRIPTEN', - '__EMSCRIPTEN__', - '__STDC__', - '__IEEE_LITTLE_ENDIAN', - ]) - - env.Append( - CPPPATH=[ - env.Dir('${EMSCRIPTEN_HOME}/system/include'), - ] - ) - - env['BUILDERS']['Emscripten'] = Builder( - action='$PYTHON ${EMSCRIPTEN_HOME}/emcc ${EMSCRIPTEN_FLAGS} $SOURCE -o $TARGET', - target_scanner=EmscriptenScanner) - - def depend_on_embedder(target, source, env): - env.Depends(target, env['JS_EMBEDDER']) - files = [] - for src in source: - for dirpath, dirnames, filenames in os.walk(str(src.srcnode())): - files.extend(map(lambda p: os.path.join(dirpath, p), filenames)) - env.Depends(target, env.Value(sorted(files))) - return target, source - - def embed_files_in_js(target, source, env, for_signature): - return '$PYTHON $JS_EMBEDDER $SOURCE.srcpath > $TARGET' - - def get_files_in_tree(node, env, path): - tree_paths = [] - for root, dirs, files in os.walk(str(node)): - tree_paths += [os.path.join(root, f) for f in files] - return [env.File(p) for p in tree_paths] - - env.SetDefault( - JS_EMBEDDER=env.File('#/bin/embed_files_in_js.py')) - - FileTreeScanner = Scanner( - function=get_files_in_tree, - name='FileTreeScanner', - recursive=False) - - env['BUILDERS']['EmbedFilesInJS'] = Builder( - generator=embed_files_in_js, - emitter=depend_on_embedder, - source_scanner=FileTreeScanner) - - env.AddMethod(emscripten) - - def ConcatenateAction(target, source, env): - [target] = target - total = ''.join(file(str(s), 'rb').read() for s in source) - file(str(target), 'wb').write(total) - env['BUILDERS']['Concatenate'] = Builder(action=ConcatenateAction) - - libembind = build_libembind(env) - libcxx = build_libcxx(env) - - # should embind be its own tool? - env.Append( - CPPPATH=[ - '${EMSCRIPTEN_HOME}/system/include' ], - LIBPATH=['$EMSCRIPTEN_TEMP_DIR/internal_libs'], - LIBS=[ - libembind, - libcxx, - ], - ) - diff --git a/scons-tools/llvm.py b/scons-tools/llvm.py deleted file mode 100755 index 8fecb40a159b2..0000000000000 --- a/scons-tools/llvm.py +++ /dev/null @@ -1,34 +0,0 @@ -from SCons.Scanner.Prog import scan -from SCons.Builder import Builder -import os - -def exists(env): - return True - -def add_libraries(target, source, env): - unique = [] - lib_nodes = set() - for x in scan(None, env, tuple(map(env.Dir, env['LIBPATH']))): - if x in lib_nodes: - continue - lib_nodes.add(x) - unique.append(x) - return (target, source + unique) - -def generate(env): - env.SetDefault( - CLANG='clang', - CLANGXX='clang++', - LLVM_DIS='llvm-dis', - LLVM_OPT='opt', - LLVM_LINK='llvm-link') - - env['BUILDERS']['LLVMDis'] = Builder( - action=os.path.join('${LLVM_ROOT}', '$LLVM_DIS') + ' -o $TARGET $SOURCE') - - env['BUILDERS']['LLVMOpt'] = Builder( - action=os.path.join('${LLVM_ROOT}', '$LLVM_OPT') + ' $LLVM_OPT_FLAGS $LLVM_OPT_PASSES -o $TARGET $SOURCE') - - env['BUILDERS']['LLVMLink'] = Builder( - action=os.path.join('${LLVM_ROOT}', '$LLVM_LINK') + ' -o $TARGET $SOURCES', - emitter=add_libraries) From e32ad9796b5c7c99e73ee1122961dd73ba5f4525 Mon Sep 17 00:00:00 2001 From: Charlie Birks Date: Sat, 30 Aug 2014 11:33:31 +0100 Subject: [PATCH 05/37] Check if context creation was successful before accessing it --- src/library_browser.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/library_browser.js b/src/library_browser.js index 95cb803b4304d..ab8418ed00ace 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -277,7 +277,9 @@ mergeInto(LibraryManager.library, { #endif contextHandle = GL.createContext(canvas, contextAttributes); - ctx = GL.getContext(contextHandle).GLctx; + if (contextHandle) { + ctx = GL.getContext(contextHandle).GLctx; + } // Set the background of the WebGL canvas to black canvas.style.backgroundColor = "black"; } else { From 8208fb54e379df5db50f296e605e7f208f0fee1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20Goretity=20=EF=A3=BF?= Date: Tue, 2 Sep 2014 20:10:37 +0200 Subject: [PATCH 06/37] Update preamble.js --- src/preamble.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/preamble.js b/src/preamble.js index 0c0811e3948d0..45e474c2c4960 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -357,7 +357,8 @@ var cwrap, ccall; 'stringToC' : function(str) { var ret = 0; if (str !== null && str !== undefined && str !== 0) { // null string - ret = Runtime.stackAlloc(str.length + 1); // +1 for the trailing '\0' + // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' + ret = Runtime.stackAlloc(str.length * 4 + 1); writeStringToMemory(str, ret); } return ret; From 0fddc76727c16c8fa115ce826342df37e474cd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81rp=C3=A1d=20Goretity=20=EF=A3=BF?= Date: Tue, 2 Sep 2014 21:08:17 +0200 Subject: [PATCH 07/37] Update AUTHORS --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 08c16ced4a134..dcfb699234d09 100644 --- a/AUTHORS +++ b/AUTHORS @@ -156,4 +156,4 @@ a license to everyone to use it as detailed in LICENSE.) * Boris Tsarev * Mark Logan (copyright owned by Artillery Games, Inc.) * Коренберг Марк - +* Árpád Goretity From 803ded0847bd91ddac6da818a0678639a4540807 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 2 Sep 2014 14:32:13 -0700 Subject: [PATCH 08/37] clarify SIMD option --- src/settings.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/settings.js b/src/settings.js index b6fa5f32b4c13..6f88b3fb04a8b 100644 --- a/src/settings.js +++ b/src/settings.js @@ -138,7 +138,13 @@ var PRECISE_F32 = 0; // 0: Use JS numbers for floating-point values. These are 6 // all modern browsers, including Firefox, Chrome and Safari, but in IE is only // present in IE11 and above. Therefore if you need to support legacy versions of // IE, you should not enable PRECISE_F32 1 or 2. -var SIMD = 0; // Whether to emit SIMD code ( https://github.com/johnmccutchan/ecmascript_simd ) +var SIMD = 0; // Whether to allow autovectorized SIMD code ( https://github.com/johnmccutchan/ecmascript_simd ). + // SIMD intrinsics are always compiled to SIMD code, so you only need this option if you + // also want the autovectorizer to run. + // Note that SIMD support in browsers is not yet there (as of Sep 2, 2014), so you will be + // running in a polyfill, which is not fast. + // (In older versions of emscripten, in particular pre-fastcomp, SIMD=1 was needed to get + // any SIMD output at all.) var CLOSURE_COMPILER = 0; // Whether closure compiling is being run on this output var CLOSURE_ANNOTATIONS = 0; // If set, the generated code will be annotated for the closure From d1fc0b645060c32681d9a1bec169c39a9f3e2a5c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 1 Sep 2014 16:30:46 +0700 Subject: [PATCH 09/37] Remove a weak_alias that results in a build error in some configs. Notably, this was a build error for IMVU. --- system/lib/libc/musl/src/stdio/vfscanf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/lib/libc/musl/src/stdio/vfscanf.c b/system/lib/libc/musl/src/stdio/vfscanf.c index 653d2316c67bf..3795b1505de1a 100644 --- a/system/lib/libc/musl/src/stdio/vfscanf.c +++ b/system/lib/libc/musl/src/stdio/vfscanf.c @@ -330,4 +330,8 @@ int MUSL_vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) // XXX return matches; } +#ifndef __EMSCRIPTEN__ +// XXX: EMSCRIPTEN: We don't need this alias. +// Keeping it would have it aliasing to the C code when we typically use the JS version. weak_alias(vfscanf,__isoc99_vfscanf); +#endif From 9cdbfca84cd5e722fad9d352a224892c241fbd3c Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Wed, 3 Sep 2014 18:06:13 +1000 Subject: [PATCH 10/37] Update indexes (and associated changes) for most of remaining sections --- .../docs/api_reference/emscripten.h.rst | 25 +-- site/source/docs/api_reference/index.rst | 36 ++-- site/source/docs/api_reference/val.h.rst | 4 +- ...building_fastcomp_manually_from_source.rst | 2 +- .../docs/compiling/Code-Generation-Modes.rst | 94 ++------- site/source/docs/compiling/index.rst | 11 +- .../contributing/LLVM-Types-in-JavaScript.rst | 63 ------ site/source/docs/contributing/index.rst | 9 +- .../about_emscripten.rst | 5 +- .../docs/optimizing/Optimizing-Code.rst | 8 +- .../optimizing/Optimizing-the-source-code.rst | 5 +- site/source/docs/optimizing/index.rst | 14 +- .../docs/porting/debugging/Debugging.rst | 191 +++++++++--------- .../porting/files/file_systems_overview.rst | 1 + site/source/docs/porting/files/index.rst | 20 +- .../docs/porting/files/packaging_files.rst | 2 +- site/source/docs/porting/index.rst | 1 + .../porting/multimedia_and_graphics/index.rst | 11 +- site/source/docs/site/glossary.rst | 5 +- site/source/docs/tools_reference/emcc.rst | 2 +- site/source/docs/tools_reference/emsdk.rst | 24 ++- site/source/docs/tools_reference/index.rst | 20 +- 22 files changed, 234 insertions(+), 319 deletions(-) delete mode 100644 site/source/docs/contributing/LLVM-Types-in-JavaScript.rst diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index 6ec6a84637df4..f21cbe162c6cb 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -17,11 +17,11 @@ Emscripten uses existing/familiar APIs where possible (for example: :term:`SDL`) Inline assembly/JavaScript ========================== +Guide material for the following APIs can be found in :ref:`interacting-with-code-call-javascript-from-native`. + Defines ------- -.. todo:: **HamishW** This should be linked to section "Calling JavaScript From C/C++" when it exists. - .. c:macro:: EM_ASM(...) Convenient syntax for inline assembly/JavaScript. @@ -67,6 +67,8 @@ Defines Calling JavaScript From C/C++ ============================= +Guide material for the following APIs can be found in :ref:`interacting-with-code-call-javascript-from-native`. + Function pointer types for callbacks ------------------------------------ @@ -106,7 +108,6 @@ The following types are used to define function callback signatures used in a nu Functions --------- - .. c:function:: void emscripten_run_script(const char *script) Interface to the underlying JavaScript engine. This function will ``eval()`` the given script. @@ -163,11 +164,13 @@ Functions Browser Execution Environment ============================= + +Guide material for the following APIs can be found in :ref:`Emscripten-browser-environment`. + Functions --------- - .. c:function:: void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop) Set a C function as the main event loop. @@ -185,8 +188,6 @@ Functions :param em_callback_func func: C function to set as main event loop. :param int fps: Number of frames per second that the JavaScript will call the function. Setting ``int <=0`` (recommended) uses the browser’s ``requestAnimationFrame`` mechanism to call the function. :param int simulate_infinite_loop: If true, this function will throw an exception in order to stop execution of the caller. - - .. todo:: **HamishW** link to "Emscripten Browser Environment" doc when imported. .. c:function:: void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop) @@ -199,8 +200,6 @@ Functions :param void* arg: User-defined data passed to the main loop function, untouched by the API itself. :param int fps: Number of frames per second at which the JavaScript will call the function. Setting ``int <=0`` (recommended) uses the browser’s ``requestAnimationFrame`` mechanism to call the function. :param int simulate_infinite_loop: If true, this function will throw an exception in order to stop execution of the caller. - - .. todo:: **HamishW** link to "Emscripten Browser Environment" doc when imported. .. c:function:: void emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg) @@ -211,8 +210,7 @@ Functions The function is added to the back of a queue of events to be blocked; the main loop will not run until all blockers in the queue complete. In the "counted" version, blockers are counted (internally) and ``Module.setStatus`` is called with some text to report progress (``setStatus`` is a general hook that a program can define in order to show processing updates). - - .. todo:: **HamishW** Remember to cross link to "browser execution environment doc or similar when it exists". + .. note:: - Main loop blockers block the main loop from running, and can be counted to show progress. In contrast, ``emscripten_async_calls`` are not counted, do not block the main loop, and can fire at specific time in the future. @@ -396,7 +394,6 @@ Typedefs - Functions --------- @@ -598,7 +595,7 @@ Compiling Forces LLVM to not dead-code-eliminate a function. - This also exports the function, as if you added it to ``EXPORTED_FUNCTIONS``. + This also exports the function, as if you added it to :ref:`EXPORTED_FUNCTIONS `. For example: :: @@ -664,7 +661,7 @@ Functions The called worker function can return data, by calling :c:func:`emscripten_worker_respond`. When the worker is called, if a callback was given it will be called with three arguments: a data pointer, a size, and an argument that was provided when calling :c:func:`emscripten_call_worker` (to more easily associate callbacks to calls). The data block defined by the data pointer and size behave like the data block in the worker function — it exists only during the callback. :param worker_handle worker: A handle to the worker to be called. - :param funcname: The name of the function in the worker. The function must be a C function (so no C++ name mangling), and must be exported (EXPORTED_FUNCTIONS). + :param funcname: The name of the function in the worker. The function must be a C function (so no C++ name mangling), and must be exported (:ref:`EXPORTED_FUNCTIONS `). :type funcname: const char* :param char* data: The address of a block of memory to copy over. :param int size: The size of the block of memory. @@ -676,8 +673,6 @@ Functions :param void* arg: An argument (user data) to be passed to the callback - .. todo:: **HamishW** — need to add link to ``EXPORTED_FUNCTIONS`` information. There are some links on this around. - .. c:function:: void emscripten_worker_respond(char *data, int size) void emscripten_worker_respond_provisionally(char *data, int size) diff --git a/site/source/docs/api_reference/index.rst b/site/source/docs/api_reference/index.rst index d4c24d4124b92..7b28a682d9eff 100644 --- a/site/source/docs/api_reference/index.rst +++ b/site/source/docs/api_reference/index.rst @@ -1,30 +1,32 @@ -================================== -API Reference (under-construction) -================================== +================================ +API Reference (ready-for-review) +================================ This section lists Emscripten's public API, organised by header file. At very high level it consists of: -- :ref:`emscripten-h`: *APIs for integrating with the browser environment.* - - This includes APIs for: controlling application execution, calling JavaScript from C code, loading files, logging etc. +- :ref:`emscripten-h`: + APIs for integrating with the browser environment. -- :ref:`html5-h`: *Low level glue bindings for interfacing with HTML5 APIs from native code.* - - This includes APIs for registering event callbacks for all types of HTML5 events, ranging from key, mouse and touch events, through to screen and device orientation events, through to WebGL context events etc. +- :ref:`html5-h`: + Low level glue bindings for interfacing with HTML5 APIs from native code. -- :ref:`preamble-js`: *APIs for working with compiled code.* +- :ref:`preamble-js`: + APIs for working with compiled code from JavaScript. - This includes APIs for calling compiled C functions, accessing memory, converting pointers to JavaScript ``Strings`` and ``Strings`` to pointers (with different encodings/formats), and other convenience functions. - -- :ref:`Filesystem-API` (library_fs.js): *APIs for (primarily) synchronous File I/O.* +- :ref:`Filesystem-API` (**library_fs.js**): + APIs for managing file systems and synchronous file operations. -- :ref:`Module`: *User-populated global JavaScript object, with attributes that Emscripten-generated code calls at various points in its execution.* +- :ref:`Module`: + Global JavaScript object that can be used to control code execution and access exported methods. -- :ref:`val-h`: *Embind API to support transliteration of JavaScript code to C++.* +- :ref:`val-h`: + Embind API to support transliteration of JavaScript code to C++. -- :ref:`bind-h`: *Embind APIs for* **HamishW** - add description +- :ref:`bind-h`: + Embind API for binding C++ functions and classes so that they can be called from JavaScript in a natural way. -- :ref:`api-reference-advanced-apis`: *APIs for advanced users/core developers* +- :ref:`api-reference-advanced-apis`: + APIs for advanced users/core developers. .. toctree:: diff --git a/site/source/docs/api_reference/val.h.rst b/site/source/docs/api_reference/val.h.rst index 3eb66a1d28580..5857a75135577 100644 --- a/site/source/docs/api_reference/val.h.rst +++ b/site/source/docs/api_reference/val.h.rst @@ -6,7 +6,9 @@ val.h (under-construction) .. COMMENT (Not rendered) : This created from val.h header file on 10 Aug 2014-03 -The C++ class :cpp:class:`emscripten::val` (defined in `val.h `_) is used to *transliterate* JavaScript code to C++. +The *Embind* C++ class :cpp:class:`emscripten::val` (defined in `val.h `_) is used to *transliterate* JavaScript code to C++. + +Guide material for this class can be found in :ref:`embind-val-guide`. .. cpp:namespace:: emscripten diff --git a/site/source/docs/building_from_source/building_fastcomp_manually_from_source.rst b/site/source/docs/building_from_source/building_fastcomp_manually_from_source.rst index f940a13c1d944..bad9c17ace108 100644 --- a/site/source/docs/building_from_source/building_fastcomp_manually_from_source.rst +++ b/site/source/docs/building_from_source/building_fastcomp_manually_from_source.rst @@ -87,8 +87,8 @@ To build the Fastcomp code from source: make -j4 + .. note:: If the build completes successfully, *clang*, *clang++*, and a number of other files will be created in the release directory (**/build/Release/bin**). - .. _llvm-update-compiler-configuration-file: diff --git a/site/source/docs/compiling/Code-Generation-Modes.rst b/site/source/docs/compiling/Code-Generation-Modes.rst index bf695341c0a36..c6cd8cdd9a8be 100644 --- a/site/source/docs/compiling/Code-Generation-Modes.rst +++ b/site/source/docs/compiling/Code-Generation-Modes.rst @@ -1,97 +1,35 @@ -.. _Code-Generation-Modes: - -=================================== -Code Generation Modes (wiki-import) -=================================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! +.. _emscripten-runtime-environment: -Code Generation Modes -===================== +=================================================== +Emscripten Runtime Environment (under-construction) +=================================================== -One of the reasons for writing Emscripten itself in JavaScript was to be able to easily test different methods of generating code. As a consequence, Emscripten currently supports various code generation modes, each with different features. - -.. _typed-arrays: -Typed Arrays ------------- -Typed arrays are currently enabled by default (in mode 2, see below), because that has the greatest support for arbitrary code. - -There are two modes for typed arrays in Emscripten, 1 and 2. To explain them, first recall how Emscripten manages memory **without** typed arrays: It uses ``HEAP`` to represent memory, where ``HEAP`` is a normal JavaScript array. We write to the first address of multi-byte values to keep things fast, so writing a 32-bit integer will end up as ``[value, 0, 0, 0]`` - we do not write anything to the upper 3 bytes. We will also read just from the first location. This is much faster than splitting things up into bytes and vice versa, but requires that we have "load-store consistency", which is that if we read a value, we wrote the same type there. (Otherwise, if we write a 32-bit int and read the second byte, we won't get what we expect.) ``SAFE_HEAP`` when enabled will check for violations of load-store consistency. - -Disabling typed arrays can be done with ``USE_TYPED_ARRAYS=0``. This is safer in the sense that not all browsers support typed arrays. However, typed arrays can be optimized very well in some cases, and can support code that does not have load-store consistency. +.. _Code-Generation-Modes: -Typed Arrays Mode 1 -+++++++++++++++++++ +.. _typed-arrays: -With ``USE_TYPED_ARRAYS=1``, two typed arrays will represent memory. One will contain integer values, the other float values. When we write an integer to memory, we write to the first, and when we write a float, we write to the second. (LLVM is typed, so we always know what values we are writing/reading.) Otherwise, this mode is identical to without typed arrays: We still require load-store consistency and so forth. +.. _emscripten-memory-model: -The benefit of this mode is that memory is implemented as two typed arrays, which JavaScript engines can often optimize very well. The downsides, though are -- In things like memcpy, where we don't know the types, we must copy **both** arrays. -- We can take more memory than without typed arrays, since we have two arrays now for memory, one of which uses 32 bits for each memory address, and one of which uses 64. -- We cannot dynamically resize these arrays in an easy way. If you try to use more memory than was originally set up, we need to create new typed arrays and copy everything into them, which is slow. Setting the total size of memory (``TOTAL_MEMORY``) can avoid this, but only if you know in advance the maximum you will need. -- Not all LLVM optimizations are possible, and not all C/C++ code is compatible with this mode. +Emscripten Memory Model +======================= -This mode is generally much faster than mode 0, but often slower then mode 2. +Emscripten's memory model is known as :term:`Typed Arrays Mode 2`. It represents memory using a single `typed array `_, with different *views* providing access to different types (:js:data:`HEAPU32` for 32-bit unsigned integers, etc.) .. _typed-arrays-mode-2: -Typed Arrays Mode 2 -+++++++++++++++++++ - -This is the default mode. - -With ``USE_TYPED_ARRAYS=2``, one typed array buffer will represent memory, while different views into it will allow us to access different types (:js:data:`HEAPU32` for 32-bit unsigned integers, for example). Because of that, it is possible to violate the load-store consistency assumption: The different views show the same data. You can write a 32-bit integer, then read a byte from the middle, and it will work just like in C or C++. - -The main benefit of this mode is that it uses as much memory on the heap as C and C++ normally do. We are literally laying things out in memory as they do. This mode is also quite fast in many cases. Also, you can successfully run code that does not have load-store consistency. There are two downsides though, - -- Because of how typed array views work, we must do pointer shifts: To access a 32-bit value at memory location X, we need to read from the 32-bit view at index X divided by 4 (since it looks like an array, whose indexes each represent 4 bytes). So the code ends up filled with ``<<2``, ``>>2`` and so forth. We can optimize this some more, but it will remain an overhead. (However, other binary data APIs are coming to JavaScript which can help here.) -- We currently align the stack and so forth to 4-byte boundaries. This means that reading 8-byte values is slower (we must read them in two parts, and combine them, see ``I64_MODE`` and ``DOUBLE_MODE``, below). - -Note that ``SAFE_HEAP``, in this mode, will ignore load-store consistency violations, since they don't matter. Alignment of reads and writes, though, will be checked, which is important since reading unaligned values will fail as mentioned earlier. - -64-bit Integer Modes --------------------- - -As mentioned earlier, 64-bit integers cannot be represented directly in JavaScript, whose numbers are doubles, which cannot contain all 64-bit integer values. In typed arrays mode 2, we implement 64-bit integers as pairs of 32-bit values, but we do not emulate addition and multiplication, instead we perform that as doubles - which is faster. Bit operations like and and or, however, are done with full precision. - -Note that in modes other than typed arrays mode 2, we implement 64-bit integers entirely as doubles. If you need 64-bit integers to work, use typed arrays mode 2. - -Double Mode ------------ - -In every mode but typed arrays mode 2, doubles work fine in a simple manner. However, in typed arrays mode 2 we cannot read unaligned doubles, because of the typed array API. Therefore the default behavior here is ``DOUBLE_MODE=1``, in which we carefully read doubles as two 32-bit values, to not hit alignment problems. This is slower than mode 0, obviously. - -It should be possible to modify clang to always align doubles to 64-bit boundaries (gcc has ``-malign-double``), this should be investigated - it would mean we no longer need mode 1 here. - -Exceptions ----------- - -Exceptions can work in code compiled by emscripten, however due to how JS engines work they are typically very slow (all JS engines currently disable most optimizations inside ``try {} catch() {}`` blocks...). For that reason, in ``-O1`` and above emscripten disables exception catching by default, because often LLVM generates code that can catch exceptions even when it isn't needed (in C++, exception catching often has zero cost unless an exception actually happens, so there is little downside there, but in JS there is). - -To get full exception handling support in ``-O1`` and above, run emcc with ``-s DISABLE_EXCEPTION_CATCHING=0``. Note that enabling exceptions will make the code larger due to the additional try-catch blocks (which cannot be minified very well). - -.. _code-generation-modes-quantum-size: - -Memory Compression (a.k.a QUANTUM_SIZE == 1) ---------------------------------------------- - -By default, Emscripten sets ``QUANTUM_SIZE`` to 4, which means that a 'normal' element - like an int or a pointer - takes 4 'bytes'. That is the normal behavior on 32-bit systems, and allows Emscripten to properly compile a great deal of C/C++ code. However, the downside is that each int or pointer takes 4 places in the HEAP array, which is how Emscripten models the normal C/C++ memory space. This makes HEAP much bigger than it needs to be, which takes more memory, and also slows things down (for example, memset ends up clearing larger areas of memory). - -By setting QUANTUM_SIZE to 1, memory is 'compressed' - it is not longer isomorphic to normal C/C++ memory. So for example a structure with an int, a double, and a pointer would have a size of 3 (one for each variable), instead of the normal 16 (4 for the int and pointer, 8 for the double). This leads to significantly more optimized code, both in terms of speed and memory use. - -However, this is risky, since with QUANTUM\_SIZE of 1, Emscripten rewrites the .ll, trying to fix all the hard-coded places where it assumes the normal memory space. So consider this experimental for now. +.. note:: *Typed Arrays Mode 2* is the *only* memory model supported by the :ref:`Fastcomp ` compiler, and it is the *default* memory model for the :ref:`old compiler `. -Notes: + Compared to other models tried by the project, it can be used for a broad range of arbitrary compiled code, and is relatively fast. -- With QUANTUM_SIZE == 1, Emscripten will warn you about ``ptrtoint`` and ``inttoptr`` operations (in the generated .js file). You should make sure there are no problems in each of those cases, and perhaps modify the original C/C++ to avoid generating that kind of code (the changes are often simple). -- You can **not** use ``QUANTUM_SIZE == 1`` with typed arrays mode 2. The reason is that typed arrays mode 2 is C-like memory layout, whereas in ``QUANTUM_SIZE == 1`` we radically change the layout (ints take 1 memory address instead of 4, etc.), and the two can't be mixed. +The model lays out items in memory in the same way as with normal C and C++, and as a result it uses the same amount of memory. -The second version of the Bullet demo in Emscripten uses ``QUANTUM_SIZE == 1``. It appears to give a speedup of around 25%. +We currently align the stack to 4-byte boundaries (this means that reading 8-byte values is slower as they must be read in two parts and then combined). +This model allows you to use code that violates the load-store consistency assumption. Since the different views show the same data, you can (say) write a 32-bit integer, then read a byte from the middle, and it will work just like in C or C++. -.. todo:: **HamishW** In :ref:`CodeGuidelinesAndLimitations` it mentions a code generation mode UNALIGNED_MEMORY - perhaps add? +.. note:: ``SAFE_HEAP`` ignores load-store consistency violations, since they don't matter. Alignment of reads and writes will be checked, which is important since reading unaligned values can fail. -.. todo:: **HamishW** SAFE_HEAP gets mentioned. Anything we can link to? diff --git a/site/source/docs/compiling/index.rst b/site/source/docs/compiling/index.rst index 89d6315a64e96..6e9c2646ce60a 100644 --- a/site/source/docs/compiling/index.rst +++ b/site/source/docs/compiling/index.rst @@ -1,17 +1,18 @@ .. _compiling-and-running-projects-index: -====================================================================================== -Compiling and running projects (under-construction) -====================================================================================== +================================================= +Compiling and Running Projects (ready-for-review) +================================================= -This section is for articles about compiling and building code. +This section contains topics about building projects and running the output. + +:ref:`Building-Projects` shows how to use :ref:`emccdoc` as a drop in replacement for *gcc* in your existing project. :ref:`Running-html-files-with-emrun` explains how to use *emrun* to run generated HTML pages in a locally launched web server. .. toctree:: :maxdepth: 1 Building-Projects - Code-Generation-Modes Running-html-files-with-emrun diff --git a/site/source/docs/contributing/LLVM-Types-in-JavaScript.rst b/site/source/docs/contributing/LLVM-Types-in-JavaScript.rst deleted file mode 100644 index 93f0457715eb2..0000000000000 --- a/site/source/docs/contributing/LLVM-Types-in-JavaScript.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. _LLVM-Types-in-JavaScript: - -====================================== -LLVM Types in JavaScript (wiki-import) -====================================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! - -This is an overview of how LLVM types are implemented in JS by -Emscripten. This stuff has changed quite a bit over time (if you read -this and it has not been updated in a while, better to check the -source). - -Overflow corrections: - -:: - - i32: | 0 - less: & (2^bits-1) - -Sign corrections (done right before a math operation if necessary, and -to extend): - -:: - - i32 signed: | 0 - i32 unsigned: >>> 0 - less signed: << (32-bits) >> (32-bits) - less unsigned: & (2^bits-1) - -Truncate: - -:: - - & (2&bits-1) - -Rounding the output of a division: - -:: - - i32 or less, signed: & -1 (could be |0 as well) - unsigned: Math.floor(.) - >i32 or float-to-int: x >= 0 ? Math.floor(x) : Math.ceil(x) - -Bitwise cast of float to int and vice versa: - -:: - - Write to heap as int, read as float (and vice versa) - -Note that there are some ugly optimizations for i64s as emulated -doubles, e.g. a sign correction could look like - -:: - - (x >= 0 ? x : (2^64)+x) - -Also, if we do precise i64 (not with emulated doubles), we use -[low,high] (i.e. a js array) as the representation in some cases. - -LLVM has "non-C struct" types, that we implement as JS objects with -fields. These are typically used only in odd things like exception -handling, checking for explicit overflows, etc., so not usually -performance sensitive. diff --git a/site/source/docs/contributing/index.rst b/site/source/docs/contributing/index.rst index 006382523c32a..0517a2628066c 100644 --- a/site/source/docs/contributing/index.rst +++ b/site/source/docs/contributing/index.rst @@ -1,15 +1,18 @@ -================================================== +=============================================== Contributing to Emscripten (under-construction) -================================================== +=============================================== +This section contains articles that are relevant to anyone who wants to contribute to Emscripten and help improve the project. +The :ref:`contribution overview ` provides a few ideas for how you can help, and where (and how) code should be submitted. The :ref:`Developer's-Guide` includes other useful information, including a brief discussion about compiler operation and the test suite. + +:ref:`emscripten-authors` is a list of all Emscripten contributors. If you contribute you must accept the project’s :ref:`open source licenses (MIT/LLVM) ` and add yourself to the list! .. toctree:: :maxdepth: 1 contributing developers_guide - LLVM-Types-in-JavaScript AUTHORS diff --git a/site/source/docs/introducing_emscripten/about_emscripten.rst b/site/source/docs/introducing_emscripten/about_emscripten.rst index 2c7c612373dc0..0fe9076baf06e 100644 --- a/site/source/docs/introducing_emscripten/about_emscripten.rst +++ b/site/source/docs/introducing_emscripten/about_emscripten.rst @@ -38,9 +38,10 @@ Emscripten generates fast code! Its default output format is `asm.js `_ and `Angrybots `_ demos above. +.. _about-emscripten-toolchain: Emscripten Toolchain -================================== +==================== A high level view of the Emscripten toolchain is given below. The main tool is the :ref:`emccdoc`. This is a drop-in replacement for a standard compiler like *gcc*. @@ -59,7 +60,7 @@ The whole toolchain is delivered in the :ref:`Emscripten SDK `_ support is sufficient to run quite a lot of code. :ref:`OpenGL-support` support is excellent for OpenGL ES 2.0-type code, and acceptable for other types. diff --git a/site/source/docs/optimizing/Optimizing-Code.rst b/site/source/docs/optimizing/Optimizing-Code.rst index 14427137684ae..4f75b93ffe1ff 100644 --- a/site/source/docs/optimizing/Optimizing-Code.rst +++ b/site/source/docs/optimizing/Optimizing-Code.rst @@ -1,12 +1,10 @@ .. _Optimizing-Code: -============================= -Optimizing Code (wiki-import) -============================= +============================================ +Optimizing Generated Code (wiki-import) +============================================ .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Optimizing the Generated Code -============================= By default Emscripten will compile code in a fairly safe way, and without all the possible optimizations. You should generally try this diff --git a/site/source/docs/optimizing/Optimizing-the-source-code.rst b/site/source/docs/optimizing/Optimizing-the-source-code.rst index 868f9b4c4473f..5c1f0ef0ff871 100644 --- a/site/source/docs/optimizing/Optimizing-the-source-code.rst +++ b/site/source/docs/optimizing/Optimizing-the-source-code.rst @@ -1,13 +1,10 @@ .. _Optimizing-the-source-code: ======================================== -Optimizing the source code (wiki-import) +Optimizing Source Code (wiki-import) ======================================== .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Optimizing the source code -========================== - In general, normal C and C++ code will compile and run at good speeds. However, there are some fundamental differences between JavaScript and native code, that make certain types of source code much faster in one diff --git a/site/source/docs/optimizing/index.rst b/site/source/docs/optimizing/index.rst index 4a179cbc450c6..f9ff6df57dd37 100644 --- a/site/source/docs/optimizing/index.rst +++ b/site/source/docs/optimizing/index.rst @@ -1,8 +1,12 @@ -================================================== -Optimization (under-construction) -================================================== +.. _optimizing-index: -This section is for articles about optimization: both optimisations that developers can perform in their own code, and also by using the different Emscripten compiler options. +=============================== +Optimization (ready-for-review) +=============================== + +The topics in this section explain how to optimize compiled code. + +:ref:`Optimizing-Code` covers the various *compiler settings* you can use to reduce code size and get it to run faster. :ref:`Optimizing-the-source-code` describes source code changes that can improve the performance of Emscripten-compiled JavaScript. .. toctree:: @@ -12,5 +16,3 @@ This section is for articles about optimization: both optimisations that develop Optimizing-the-source-code - - diff --git a/site/source/docs/porting/debugging/Debugging.rst b/site/source/docs/porting/debugging/Debugging.rst index 6144c66881fd3..e719359b0bf99 100644 --- a/site/source/docs/porting/debugging/Debugging.rst +++ b/site/source/docs/porting/debugging/Debugging.rst @@ -5,14 +5,14 @@ Debugging (wiki-import) ======================= .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Debugging -========= For a quick overview of debugging Emscripten-generated code, see `these slides `__ +.. comment:: Pulled from below, might be useful: If you think you may have hit an Emscripten codegen bug, there are a few tools to help you. + Limitation or Bug? ------------------- +================== Emscripten can compile almost but not all C/C++ code out there. Some limitations exist, see :ref:`CodeGuidelinesAndLimitations`. @@ -27,7 +27,7 @@ Emscripten, such as: - An actual mistake in Emscripten. Please report it! Optimizations -------------- +============= Try to build without optimizations (no ``-O1`` etc.). If that has an effect, you can try to disable LLVM optimizations specifically using @@ -38,7 +38,7 @@ various stages (output to ``/tmp/emscripten_temp``). ``EMCC_DEBUG=2`` will emit more intermediate files (one for each JS optimizer pass). Useful Compilation Settings ---------------------------- +=========================== As already mentioned, some useful settings appear in ``src/settings.js``. Change the settings there and then recompile the @@ -48,6 +48,94 @@ then ``SAFE_HEAP``. ``ASSERTIONS`` adds various runtime checks, and ``SAFE_HEAP`` adds even more (slow) memory access checks like dereferencing 0 and memory alignment issues. +Inspecting the Generated Code +============================= + +See the slides linked to before for the ``-g`` options. + +Another thing you might find useful is to not run JS optimizations, to +leave inline source code hints. You can try something like + +:: + + /emcc -O2 --js-opts 0 -g4 tests/hello_world_loop.cpp + +which applies only LLVM opts, and basic JS opts but not the JS +optimizer, which retains debug info, giving + +:: + + function _main() { + var label = 0; + var $puts=_puts(((8)|0)); //@line 4 "tests/hello_world.c" + return 1; //@line 5 "tests/hello_world.c" + } + +Debug Info +========== + +It can be very useful to compile the C/C++ files with ``-g`` flag to get +debugging into - Emscripten will add source file and line number to each +line in the generated code. Note, however, that attempting to interpret +code compiled with ``-g`` using ``lli`` may cause crashes. So you may +need to build once without ``-g`` for ``lli``, then build again with +``-g``. Or, use ``tools/exec_llvm.py`` in Emscripten, which will run lli +after cleaning out debug info. + +The AutoDebugger +=========================== + +The 'nuclear option' when debugging is to use the **autodebugger tool**. +The autodebugger will rewrite the LLVM bitcode so it prints out each +store to memory. You can then run the exact same LLVM bitcode in the +LLVM interpreter (lli) and JavaScript, and compare the output (``diff`` +is useful if the output is large). For how to use the autodebugger tool, +see the ``autodebug`` test. + +The autodebugger can potentially find **any** problem in the generated +code, so it is strictly more powerful than the ``CHECK_*`` settings and +``SAFE_HEAP``. However, it has some limitations: + +- The autodebugger generates a lot of output. Using ``diff`` can be + very helpful here. +- The autodebugger doesn't print out pointer values, just simple + numerical values. The reason is that pointer values change from run + to run, so you can't compare them. However, on the one hand this may + miss potential problems, and on the other, a pointer may be converted + into an integer and stored, in which case it would be shown but it + should be ignored. (You can modify this, look in + ``tools/autodebugger.py``.) + +One use of the autodebugger is to quickly emit lots of logging output. +You can then take a look and see if something weird pops up. Another use +is for regressions, see below. + +AutoDebugger Regression Workflow +--------------------------------- + +Fixing regressions is pretty easy with the autodebugger, using the +following workflow: + +- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment. +- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment, + again, but with a difference emcc setting etc., so that you now have + one build before the regression and one after. +- Run both versions, saving their output, then do a diff and + investigate that. Any difference is likely the bug (other false + positives could be things like the time, if something like + ``clock()`` is called, which differs slightly between runs). + +(You can also make the second build a native one using the llvm +nativizer tool mentioned above - run it on the autodebugged .ll file, +which EMCC\_DEBUG=1 will emit in ``/tmp/emscripten_temp``. This helps +find bugs in general and not just regressions, but has the same issues +with the nativizer tool mentioned earlier.) + + + +Specific Issues +======================= + Memory Alignment Issues ----------------------- @@ -112,29 +200,6 @@ Another possible problem with function pointers is that what appears to be the wrong function is called. Again, ``SAFE_HEAP`` can help with this as it detects some possible errors with function table accesses. -Inspecting the Generated Code ------------------------------ - -See the slides linked to before for the ``-g`` options. - -Another thing you might find useful is to not run JS optimizations, to -leave inline source code hints. You can try something like - -:: - - /emcc -O2 --js-opts 0 -g4 tests/hello_world_loop.cpp - -which applies only LLVM opts, and basic JS opts but not the JS -optimizer, which retains debug info, giving - -:: - - function _main() { - var label = 0; - var $puts=_puts(((8)|0)); //@line 4 "tests/hello_world.c" - return 1; //@line 5 "tests/hello_world.c" - } - Infinite loops -------------- @@ -145,74 +210,10 @@ infinite loop for a while (before the browser shows the slow script dialog and you quit it), you will see a block of code doing the same thing near the end of the profile. -Debugging Emscripten Issues -=========================== - -If you think you may have hit an Emscripten codegen bug, there are a few -tools to help you. -The AutoDebugger ----------------- - -The 'nuclear option' when debugging is to use the **autodebugger tool**. -The autodebugger will rewrite the LLVM bitcode so it prints out each -store to memory. You can then run the exact same LLVM bitcode in the -LLVM interpreter (lli) and JavaScript, and compare the output (``diff`` -is useful if the output is large). For how to use the autodebugger tool, -see the ``autodebug`` test. - -The autodebugger can potentially find **any** problem in the generated -code, so it is strictly more powerful than the ``CHECK_*`` settings and -``SAFE_HEAP``. However, it has some limitations: - -- The autodebugger generates a lot of output. Using ``diff`` can be - very helpful here. -- The autodebugger doesn't print out pointer values, just simple - numerical values. The reason is that pointer values change from run - to run, so you can't compare them. However, on the one hand this may - miss potential problems, and on the other, a pointer may be converted - into an integer and stored, in which case it would be shown but it - should be ignored. (You can modify this, look in - ``tools/autodebugger.py``.) - -One use of the autodebugger is to quickly emit lots of logging output. -You can then take a look and see if something weird pops up. Another use -is for regressions, see below. - -AutoDebugger Regression Workflow -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Fixing regressions is pretty easy with the autodebugger, using the -following workflow: - -- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment. -- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment, - again, but with a difference emcc setting etc., so that you now have - one build before the regression and one after. -- Run both versions, saving their output, then do a diff and - investigate that. Any difference is likely the bug (other false - positives could be things like the time, if something like - ``clock()`` is called, which differs slightly between runs). - -(You can also make the second build a native one using the llvm -nativizer tool mentioned above - run it on the autodebugged .ll file, -which EMCC\_DEBUG=1 will emit in ``/tmp/emscripten_temp``. This helps -find bugs in general and not just regressions, but has the same issues -with the nativizer tool mentioned earlier.) - -Debug Info ----------- - -It can be very useful to compile the C/C++ files with ``-g`` flag to get -debugging into - Emscripten will add source file and line number to each -line in the generated code. Note, however, that attempting to interpret -code compiled with ``-g`` using ``lli`` may cause crashes. So you may -need to build once without ``-g`` for ``lli``, then build again with -``-g``. Or, use ``tools/exec_llvm.py`` in Emscripten, which will run lli -after cleaning out debug info. Additional Tips ---------------- +=========================== You can also do something similar to what the autodebugger does, manually - modify the original source code with some ``printf()``\ s, @@ -224,13 +225,13 @@ to get a stack trace there. There is also :js:func:`stackTrace` which emits a stack trace and also tries to demangle C++ function names. Useful Links ------------- +=========================== `Blogpost about reading compiler output `__ Additional Help ---------------- +=========================== Of course, you can also ask the Emscripten devs for help. :) See links to IRC and the Google Group on the main project page. diff --git a/site/source/docs/porting/files/file_systems_overview.rst b/site/source/docs/porting/files/file_systems_overview.rst index 0f03dc46a92cb..d55e0bad37829 100644 --- a/site/source/docs/porting/files/file_systems_overview.rst +++ b/site/source/docs/porting/files/file_systems_overview.rst @@ -5,6 +5,7 @@ File System Overview (wiki-import) =================================== .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! +.. comment Perhaps integrate this: "Native code and JavaScript have significantly expectations with respect to file handling — native code expects to be able to access files on the local machine using synchronous APIs, while JavaScript provides asynchronous file system APIs (outside of web workers) and does not have direct access to the host file system when running in a browser." Emscripten allows you to set up a virtual filesystem that points to preloaded data, as well as virtual devices that can read and write data. diff --git a/site/source/docs/porting/files/index.rst b/site/source/docs/porting/files/index.rst index 52d6ec24a25cf..dde707da04719 100644 --- a/site/source/docs/porting/files/index.rst +++ b/site/source/docs/porting/files/index.rst @@ -1,13 +1,19 @@ .. _packaging-code-index: -============================================= -Files and File Systems (under-construction) -============================================= +========================================= +Files and File Systems (ready-for-review) +========================================= + +This section contains articles related to using files in Emscripten-compiled code. + +The :ref:`Filesystem-Guide` provides a high level overview of how file operations are supported by Emscripten. :ref:`packaging-files` shows how to use :ref:`emcc ` to package the files needed by compiled code. .. toctree:: - :maxdepth: 2 + :maxdepth: 1 - file_systems_overview - packaging_files - Synchronous-Virtual-XHR-Backed-File-System-Usage + file_systems_overview + packaging_files + Synchronous-Virtual-XHR-Backed-File-System-Usage + +.. seealso:: :ref:`Filesystem-API`. This is discussed in the :ref:`Filesystem-Guide`. \ No newline at end of file diff --git a/site/source/docs/porting/files/packaging_files.rst b/site/source/docs/porting/files/packaging_files.rst index 81f1eb0441d06..f244a27ffe243 100644 --- a/site/source/docs/porting/files/packaging_files.rst +++ b/site/source/docs/porting/files/packaging_files.rst @@ -1,7 +1,7 @@ .. _packaging-files: ============================== -Packaging files (wiki-import) +Packaging Files (wiki-import) ============================== The simplest thing to do is just tell emcc to package files for you, diff --git a/site/source/docs/porting/index.rst b/site/source/docs/porting/index.rst index dfd971d75432f..9567950ec2883 100644 --- a/site/source/docs/porting/index.rst +++ b/site/source/docs/porting/index.rst @@ -11,6 +11,7 @@ The topics in this section cover the main integration points that you need to co guidelines/index Emscripten-browser-environment + ../compiling/Code-Generation-Modes connecting_cpp_and_javascript/index files/index multimedia_and_graphics/index diff --git a/site/source/docs/porting/multimedia_and_graphics/index.rst b/site/source/docs/porting/multimedia_and_graphics/index.rst index b103d7f08c1ad..790f89c4bfaf9 100644 --- a/site/source/docs/porting/multimedia_and_graphics/index.rst +++ b/site/source/docs/porting/multimedia_and_graphics/index.rst @@ -1,11 +1,14 @@ -======================================================== -Multimedia and Graphics (under-construction) -======================================================== +.. _multimedia-and-graphics-index: + +========================================== +Multimedia and Graphics (ready-for-review) +========================================== This section is for articles about integrating graphics and audio with the Emscripten browser environment. + .. toctree:: - :maxdepth: 2 + :maxdepth: 1 EGL-Support-in-Emscripten OpenGL-support diff --git a/site/source/docs/site/glossary.rst b/site/source/docs/site/glossary.rst index 0790f5a99bcf8..2066d2d31438e 100644 --- a/site/source/docs/site/glossary.rst +++ b/site/source/docs/site/glossary.rst @@ -21,7 +21,10 @@ Glossary (under-construction) SDL `Simple DirectMedia Layer `_ (SDL) is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D. - + Typed Arrays Mode 2 + *Typed Arrays Mode 2* is the name of the approach used for the current :ref:`emscripten-memory-model`. This is the only memory model supported by the (current) :ref:`Fastcomp ` compiler and it is the default memory model for the :ref:`old compiler `. + + The original compiler supported a number of other memory models and compilation modes (see `wiki here `_) but *Typed Arrays Mode 2* proved to have, among other benefits, the greatest support for arbitrary code. diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index 22a32b50b40f8..71e301b21bc6e 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -8,7 +8,7 @@ The Emscripten Compiler Frontend (``emcc``) is used to call the Emscripten compi Command line syntax -============================================ +=================== :: diff --git a/site/source/docs/tools_reference/emsdk.rst b/site/source/docs/tools_reference/emsdk.rst index 153ee0de0640e..22d7e3503d9d1 100644 --- a/site/source/docs/tools_reference/emsdk.rst +++ b/site/source/docs/tools_reference/emsdk.rst @@ -6,7 +6,7 @@ Emscripten SDK Manager (emsdk) **The Emscripten SDK management script (** ``emsdk`` **) is used to perform all SDK maintenance. You only need to install the SDK once; after that emsdk can do all further updates!** -With *emsdk* you can download, install or remove *any* :term:`SDK` or :term:`Tool`, and even use the :ref:`bleeding edge versions ` in development on Github. To access the *emsdk*, first launch the :ref:`Emscripten Command Prompt `. Most operations are of the form ``./emsdk command``. +With *emsdk* you can download, install or remove *any* :term:`SDK` or :term:`Tool`, and even use the :ref:`bleeding edge versions ` in development on Github. To access the *emsdk* on Windows, first launch the :ref:`Emscripten Command Prompt `. Most operations are of the form ``./emsdk command``. This document provides the command syntax, and a :ref:`set of guides ` explaining how to perform both common and advanced maintenance operations. @@ -77,7 +77,7 @@ A particular installed SDK (or tool) can then be set as :term:`active ` configuration on behalf of the *emsdk*. The active configuration defines the specific set of tools that are used by default if Emscripten in called on the :ref:`Emscripten Command Prompt `. @@ -85,12 +85,12 @@ The configuration file is named **.emscripten**. It is user-specific, and is loc The file should generally not be updated directly unless you're :ref:`building Emscripten from source `. Instead use the *emsdk* to activate specific SDKs and tools as needed (``emsdk activate ``). -Below is a typical **.emscripten** file (created by *emsdk*), taken from a user's root directory on Windows. Note the variable names used to point to the different tools: - -.. todo:: **HamishW** When I've fully tested on ubuntu perhaps include the file from there (since Linux is the most used platform). +Below are typical **.emscripten** files created by *emsdk*. Note the variable names used to point to the different tools: :: + # .emscripten file from Windows SDK + import os SPIDERMONKEY_ENGINE = '' NODE_JS = 'node' @@ -105,6 +105,20 @@ Below is a typical **.emscripten** file (created by *emsdk*), taken from a user' JS_ENGINES = [NODE_JS] +:: + + # .emscripten file from Linux SDK + + import os + SPIDERMONKEY_ENGINE = '' + NODE_JS = 'nodejs' + LLVM_ROOT='/home/ubuntu/emsdk_portable/clang/fastcomp/build_incoming_64/bin' + EMSCRIPTEN_ROOT='/home/ubuntu/emsdk_portable/emscripten/incoming' + V8_ENGINE = '' + TEMP_DIR = '/tmp' + COMPILER_ENGINE = NODE_JS + JS_ENGINES = [NODE_JS] + .. _emsdk_howto: diff --git a/site/source/docs/tools_reference/index.rst b/site/source/docs/tools_reference/index.rst index 4845649562cfb..ba25c91528771 100644 --- a/site/source/docs/tools_reference/index.rst +++ b/site/source/docs/tools_reference/index.rst @@ -1,14 +1,24 @@ .. _tools-reference: -======================================= -Tools Reference (under-construction) -======================================= +================================== +Tools Reference (ready-for-review) +================================== + +This section provides command line reference for the main tools in the :ref:`Emscripten toolchain `: + +- :ref:`emccdoc` + *Emcc* is used to call the Emscripten compiler from the command line. It is effectively a drop-in replacement for a standard compiler like *gcc* or *clang*. + +- :ref:`emsdk`: + *Emsdk* is used to perform all SDK maintenance. You can use it to download, install, activate, and remove SDKs and tools, and even to build and use the latest compiler from source on Github. + +- :ref:`emcmdprompt` + This prompt is used to call *Emscripten* from the command line on Windows. It is configured with the correct system paths and settings to point to the active Emscripten SDK/tools. -This section provides reference for the main :term:`tools ` in the Emscripten toolchain. .. toctree:: - :maxdepth: 1 + :hidden: emsdk emcc From da1c1e16ffb1b9530769955bee6bc8d1e2993db6 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Wed, 3 Sep 2014 18:07:21 +1000 Subject: [PATCH 11/37] Remove temporary scratchpad files --- site/source/docs/index.rst | 2 +- ...g-started-emscripten-wikiEmscriptenSDK.rst | 152 ------------------ 2 files changed, 1 insertion(+), 153 deletions(-) delete mode 100644 site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst diff --git a/site/source/docs/index.rst b/site/source/docs/index.rst index 756b0c7285c32..e3c9b9bd10b9e 100644 --- a/site/source/docs/index.rst +++ b/site/source/docs/index.rst @@ -16,6 +16,6 @@ Documentation Home (under-construction) api_reference/index tools_reference/index site/index - temp-fragments/getting-started-emscripten-wikiEmscriptenSDK + diff --git a/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst b/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst deleted file mode 100644 index 66cc46b5c24fa..0000000000000 --- a/site/source/docs/temp-fragments/getting-started-emscripten-wikiEmscriptenSDK.rst +++ /dev/null @@ -1,152 +0,0 @@ -================================ -Test page -================================ - - - -Getting Started with Emscripten -================================ - - -.. note:: This is fragment from the wiki topic Emscripten SDK. Not yet got a home. - -The tools in the Emscripten toolchain can be accessed in various ways. - -Which one you use depends on your preference. - -Command line usage -------------------- - -The Emscripten compiler is available on the command line by invoking -``emcc`` or ``em++``. They are located in the folder -``emsdk/emscripten//`` in the SDK. - -The root directory of the Emscripten SDK contains scripts -``emsdk_env.bat`` (Windows) and ``emsdk_env.sh`` (Linux, OSX) which set -up ``PATH`` and other environment variables for the current terminal. -After calling these scripts, ``emcc``, ``clang``, etc. are all -accessible from the command line. - -Check out the tutorial! See the Emscripten `Tutorial `__ page for help on how to get going with the tools from command line. - -Windows: Emscripten Command Prompt --------------------------------------- - -Start the Emscripten Command Prompt from Start Menu -> All Programs -> Emscripten -> Emscripten Command Prompt. This will spawn a new command prompt that has all the tools for the currently activated SDK version set to PATH. The Emscripten Command Prompt is analogous to the Visual Studio Command Prompt that ships with installations of Visual Studio. - -Windows: Use Visual Studio 2010 --------------------------------------- - -After installing the vs-tool plugin, a new 'Emscripten' platform will appear to the list of all Solution Platforms in Visual Studio. To activate the Emscripten platform, right-click on the solution in the Solution Explorer, choose Configuration Manager... -> Active solution platform... -> New... -> Emscripten. After that, activating the Emscripten platform for the solution will make Visual Studio run the project build through Emscripten, producing .html or .js output, depending on the project properties you set up. - -Note: If you copied the Emscripten platform properties from the Win32 platform, be sure to go and clean up any leftover Win32-specific #defines and other configuration from the Emscripten platform! - - -Raw HTML for toggle text -========================= - -There is also a good example of a Sphinx plugin that could add this directive: http://scopatz.github.io/hiddencode/ - -.. raw:: html - - Installation instructions1 - - - -.. raw:: html - - -Some text that probably belongs in installing SDK from source. -======================================================================== - -This was cut from an SDK installation topic: - -"Run ``emsdk_env.bat`` (Windows) or ``source ./emsdk_env.sh`` (Linux and OSX) to set up the environment for the calling terminal." from topic "How do I check the installation status and version of the SDK and tools?". I think this is part of manual setup and doesn't belong here. - - - - - -Text from tutorial that might belong in "introducting emscripten" and troubleshooting -=========================================================================================================== - - -Cross-compiling ---------------------------- - -The main 'under the hood' topic to be aware of is that **emcc is a cross-compiler**: You are on a 'normal' OS, running native code, but using emcc you are building for a different environment, JavaScript. - -Other examples of cross-compiling are building for an ARM phone on an x86 desktop, etc. When cross-compiling, the thing to keep in mind is that you need to build with settings for the target platform, not the one you are currently on. For that reason, Emscripten (and other cross-compilers) ship with a complete build environment, including system headers and so forth. When you run emcc, it does **not** use your /usr/include directory, instead it uses the system headers bundled with Emscripten (in system/include). One thing to be aware of is if you build a project that has hardcoded includes, for example -``-I/usr/include/something``: Using system headers that way is dangerous when you are cross-compiling, since the headers are meant for your local system, not for the platform you are actually building for. - -Emscripten options ---------------------------- - -The Emscripten compiler (the core code called by emcc that translates LLVM assembly to JavaScript) has various options, which sometimes are useful to modify. To see the options look in ``src/settings.js``, they appear there with descriptions of what they do in comments. To modify a setting, use the ``-s`` option to emcc, for example - -:: - - emcc source.cpp -s TOTAL_STACK=10000000 - -This invocation of emcc will generate JavaScript that sets aside a lot of space for the stack. - - - - ------ - -Section below some temp test - ------ - -Section below some temp test - -======================================================== -Emscripten Compiler Frontend (emcc) (import as code) -======================================================== - -**This document provides the command syntax for the Emscription Compiler Frontend.** - -.. note:: The information in this page was output by running ``emcc --help`` on the version of *emcc* in the Emscripten 1.20.0 SDK. The most recent version is `emcc (master) `_ - -Purpose -============================================ - -The Emscripten Compiler Frontend (``emcc``) is used to call the Emscripten compiler from the command line. It is effectively a drop-in replacement for a standard compiler like *gcc*. - - -Command line syntax -============================================ - -:: - - emcc [options] file... - -The input file(s) can be either source code files that *Clang* can handle (C or C++), LLVM bitcode in binary form, or LLVM assembly files in human-readable form. - -Most normal gcc/g++ options will work, for example: - - --help Display this information - --version Display compiler version information - -Options that are modified or new in *emcc* are listed below (imported from latest version of emcc) - -.. include:: ../../../../emcc - :start-after: Options that are modified or new in %s include: - :end-before: (autoconf likes to see elf above to enable shared object support) - :code: - - - From 25f1d63c12cef1efc027158f7ee46c0841c13651 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Wed, 3 Sep 2014 18:10:00 +1000 Subject: [PATCH 12/37] move Debugging topic up level (no longer in index) --- site/source/docs/porting/{debugging => }/Debugging.rst | 0 site/source/docs/porting/debugging/index.rst | 9 --------- site/source/docs/porting/index.rst | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) rename site/source/docs/porting/{debugging => }/Debugging.rst (100%) delete mode 100644 site/source/docs/porting/debugging/index.rst diff --git a/site/source/docs/porting/debugging/Debugging.rst b/site/source/docs/porting/Debugging.rst similarity index 100% rename from site/source/docs/porting/debugging/Debugging.rst rename to site/source/docs/porting/Debugging.rst diff --git a/site/source/docs/porting/debugging/index.rst b/site/source/docs/porting/debugging/index.rst deleted file mode 100644 index 7d3349263ef0d..0000000000000 --- a/site/source/docs/porting/debugging/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -===================================== -Debugging (under-construction) -===================================== - - -.. toctree:: - :maxdepth: 2 - - Debugging diff --git a/site/source/docs/porting/index.rst b/site/source/docs/porting/index.rst index 9567950ec2883..97e9a3c2d31d0 100644 --- a/site/source/docs/porting/index.rst +++ b/site/source/docs/porting/index.rst @@ -15,7 +15,7 @@ The topics in this section cover the main integration points that you need to co connecting_cpp_and_javascript/index files/index multimedia_and_graphics/index - debugging/index + Debugging From 7a55bc26312dc4be139b3a7564b18f387b2f1a0e Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Wed, 3 Sep 2014 21:14:09 +1000 Subject: [PATCH 13/37] Remove ready-to-review on checked index documents. --- site/source/docs/api_reference/index.rst | 8 +- site/source/docs/compiling/index.rst | 11 +- site/source/docs/contributing/index.rst | 14 +- site/source/docs/optimizing/index.rst | 13 +- ...s-Virtual-XHR-Backed-File-System-Usage.rst | 37 +-- site/source/docs/porting/files/index.rst | 14 +- .../EGL-Support-in-Emscripten.rst | 221 +++++------------- .../porting/multimedia_and_graphics/index.rst | 8 +- site/source/docs/site/about.rst | 5 +- site/source/docs/tools_reference/index.rst | 8 +- 10 files changed, 116 insertions(+), 223 deletions(-) diff --git a/site/source/docs/api_reference/index.rst b/site/source/docs/api_reference/index.rst index 7b28a682d9eff..b72b91c7a4fcf 100644 --- a/site/source/docs/api_reference/index.rst +++ b/site/source/docs/api_reference/index.rst @@ -1,8 +1,8 @@ -================================ -API Reference (ready-for-review) -================================ +============= +API Reference +============= -This section lists Emscripten's public API, organised by header file. At very high level it consists of: +This section lists Emscripten's public API, organised by header file. At a very high level it consists of: - :ref:`emscripten-h`: APIs for integrating with the browser environment. diff --git a/site/source/docs/compiling/index.rst b/site/source/docs/compiling/index.rst index 6e9c2646ce60a..633db10aefee7 100644 --- a/site/source/docs/compiling/index.rst +++ b/site/source/docs/compiling/index.rst @@ -1,16 +1,17 @@ .. _compiling-and-running-projects-index: -================================================= -Compiling and Running Projects (ready-for-review) -================================================= +============================== +Compiling and Running Projects +============================== This section contains topics about building projects and running the output. -:ref:`Building-Projects` shows how to use :ref:`emccdoc` as a drop in replacement for *gcc* in your existing project. :ref:`Running-html-files-with-emrun` explains how to use *emrun* to run generated HTML pages in a locally launched web server. +- :ref:`Building-Projects` shows how to use :ref:`emccdoc` as a drop in replacement for *gcc* in your existing project. +- :ref:`Running-html-files-with-emrun` explains how to use *emrun* to run generated HTML pages in a locally launched web server. .. toctree:: - :maxdepth: 1 + :hidden: Building-Projects Running-html-files-with-emrun diff --git a/site/source/docs/contributing/index.rst b/site/source/docs/contributing/index.rst index 0517a2628066c..a5fd7e41421bc 100644 --- a/site/source/docs/contributing/index.rst +++ b/site/source/docs/contributing/index.rst @@ -1,15 +1,15 @@ -=============================================== -Contributing to Emscripten (under-construction) -=============================================== +========================== +Contributing to Emscripten +========================== This section contains articles that are relevant to anyone who wants to contribute to Emscripten and help improve the project. -The :ref:`contribution overview ` provides a few ideas for how you can help, and where (and how) code should be submitted. The :ref:`Developer's-Guide` includes other useful information, including a brief discussion about compiler operation and the test suite. - -:ref:`emscripten-authors` is a list of all Emscripten contributors. If you contribute you must accept the project’s :ref:`open source licenses (MIT/LLVM) ` and add yourself to the list! +- :ref:`contributing` provides a few ideas for how you can help, and where (and how) code should be submitted. +- The :ref:`Developer's-Guide` includes other useful information, including a brief discussion about compiler operation and the test suite. +- :ref:`emscripten-authors` is a list of all Emscripten contributors. If you contribute you must accept the project’s :ref:`open source licenses (MIT/LLVM) ` and add yourself to the list! .. toctree:: - :maxdepth: 1 + :hidden: contributing developers_guide diff --git a/site/source/docs/optimizing/index.rst b/site/source/docs/optimizing/index.rst index f9ff6df57dd37..bc8e23c8fdd72 100644 --- a/site/source/docs/optimizing/index.rst +++ b/site/source/docs/optimizing/index.rst @@ -1,16 +1,17 @@ .. _optimizing-index: -=============================== -Optimization (ready-for-review) -=============================== +========== +Optimizing +========== -The topics in this section explain how to optimize compiled code. +The topics in this section explain how to optimize compiled code. -:ref:`Optimizing-Code` covers the various *compiler settings* you can use to reduce code size and get it to run faster. :ref:`Optimizing-the-source-code` describes source code changes that can improve the performance of Emscripten-compiled JavaScript. +- :ref:`Optimizing-Code` covers the various *compiler settings* you can use to reduce code size and get it to run faster. +- :ref:`Optimizing-the-source-code` describes source code changes that can improve the performance of Emscripten-compiled JavaScript. .. toctree:: - :maxdepth: 1 + :hidden: Optimizing-Code Optimizing-the-source-code diff --git a/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst b/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst index d54e9a4b0ff07..a77d28b7af36e 100644 --- a/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst +++ b/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst @@ -3,38 +3,19 @@ ============================================================== Synchronous Virtual XHR Backed File System Usage (wiki-import) ============================================================== + .. note:: This article was migrated from the wiki (Mon, 04 Aug 2014 23:20) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Emscripten supports lazily loading binary data from HTTP servers using -XHR's (ala AJAX but no XML or JSON). +Emscripten supports lazily loading binary data from HTTP servers using XHR's (ala AJAX but no XML or JSON). -**Restriction: only possible in Web Workers** (due to browser -limitations) +**Restriction: only possible in Web Workers** (due to browser limitations) -It is recommended to use a web server with `byte -serving `__ support. This -will enable Emscripten to only load the parts of the file that are -actually read. If it is not available, the runtime will of course be -forced to load the whole file, even if you only read a single byte from -a 100 MB file. +It is recommended to use a web server with `byte serving `_ support. This will enable Emscripten to only load the parts of the file that are actually read. If it is not available, the runtime will of course be forced to load the whole file, even if you only read a single byte from a 100 MB file. Instructions for use --------------------- - -1. You will need a page that spawns the web worker. See the page inlined - in ``tests/runner.py/test_chunked_synchronous_xhr``. The ``prejs`` we - use below will cause the program running in the Web Worker to - ``postMessage`` it's stdout back. If you use that solution, the - mother page should probably contain your handwritten glue code (not - Emscriptened) to handle the stdout data. -2. The tests use ``checksummer.c`` as the actual Emscriptened program. - As you can see, it is simply a vanilla C program using - ``fopen``/``fread``/``fclose`` and no Emscripten specific code at - all. -3. You will need at ``prejs`` that sets up the mapping between the file - path in your equivalent of ``checksummer.c`` and the server to - download from. Remember CORS! The test case also contains an HTTP - server that shows some CORS headers that might need to be set. Of - course, if the resources are hosted from the same domain Emscripten - runs from, there is no issue. +==================== + +#. You will need a page that spawns the web worker. See the page inlined in ``tests/runner.py/test_chunked_synchronous_xhr``. The ``prejs`` we use below will cause the program running in the Web Worker to ``postMessage`` it's stdout back. If you use that solution, the mother page should probably contain your handwritten glue code (not Emscriptened) to handle the stdout data. +#. The tests use ``checksummer.c`` as the actual Emscriptened program. As you can see, it is simply a vanilla C program using ``fopen``/``fread``/``fclose`` and no Emscripten specific code at all. +#. You will need at ``prejs`` that sets up the mapping between the file path in your equivalent of ``checksummer.c`` and the server to download from. Remember CORS! The test case also contains an HTTP server that shows some CORS headers that might need to be set. Of course, if the resources are hosted from the same domain Emscripten runs from, there is no issue. diff --git a/site/source/docs/porting/files/index.rst b/site/source/docs/porting/files/index.rst index dde707da04719..7c4cc03a8c89b 100644 --- a/site/source/docs/porting/files/index.rst +++ b/site/source/docs/porting/files/index.rst @@ -1,19 +1,21 @@ .. _packaging-code-index: -========================================= -Files and File Systems (ready-for-review) -========================================= +====================== +Files and File Systems +====================== This section contains articles related to using files in Emscripten-compiled code. -The :ref:`Filesystem-Guide` provides a high level overview of how file operations are supported by Emscripten. :ref:`packaging-files` shows how to use :ref:`emcc ` to package the files needed by compiled code. +- The :ref:`Filesystem-Guide` provides a high level overview of how file operations are supported by Emscripten. +- :ref:`packaging-files` shows how to use :ref:`emcc ` to package the files needed by compiled code. +- :ref:`Synchronous-Virtual-XHR-Backed-File-System-Usage` explains how to setup lazy loading of binary data from HTTP servers using XHR’s. +.. seealso:: :ref:`Filesystem-API`. This is discussed in the :ref:`Filesystem-Guide`. .. toctree:: - :maxdepth: 1 + :hidden: file_systems_overview packaging_files Synchronous-Virtual-XHR-Backed-File-System-Usage -.. seealso:: :ref:`Filesystem-API`. This is discussed in the :ref:`Filesystem-Guide`. \ No newline at end of file diff --git a/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst b/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst index 8a4b09354230b..afb9c2c9dcc9c 100644 --- a/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst +++ b/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst @@ -3,209 +3,114 @@ ======================================= EGL Support in Emscripten (wiki-import) ======================================= + .. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Khronos Group publishes a specification called EGL, which is an API that -handles (among other tasks) graphics context creation, rendering surface -management, and interop between different Khronos Group graphics APIs -(OpenGL, OpenGL ES, OpenVG). For detailed information, see the `Khronos -EGL webpage `__. - -Currently, EGL is not very widely used across operating systems/graphics -driver vendors. The most notable adoption is in the Android -architecture, where EGL is the primary method for creating rendering -contexts for OpenGL ES 1&2 when using the Android NDK. Also, Mesa has an -implementation of the EGL specification in its `graphics -driver `__. - -Emscripten also supplies an implementation of the EGL v1.4 -specification. This allows C/C++ client code to use a (nearly) unified -codebase for creating a GLES2 (WebGL) rendering context across web, -linux (with Mesa) and Android NDK. The implementation of the EGL -specification in Emscripten is not perfect, see the end of this page for -a status chart. +Khronos Group publishes a specification called EGL, which is an API that handles (among other tasks) graphics context creation, rendering surface management, and interop between different Khronos Group graphics APIs (OpenGL, OpenGL ES, OpenVG). For detailed information, see the `Khronos EGL webpage `_. + +Currently, EGL is not very widely used across operating systems/graphics driver vendors. The most notable adoption is in the Android architecture, where EGL is the primary method for creating rendering contexts for OpenGL ES 1&2 when using the Android NDK. Also, Mesa has an implementation of the EGL specification in its `graphics driver `_. + +Emscripten also supplies an implementation of the EGL v1.4 specification. This allows C/C++ client code to use a (nearly) unified codebase for creating a GLES2 (WebGL) rendering context across Web, Linux (with Mesa) and Android NDK. The implementation of the EGL specification in Emscripten is not perfect, see the end of this page for a status chart. What EGL is not? ----------------- - -Somewhat disappointingly, EGL is not a self-sufficient complete solution -for initializing GLES2 graphics rendering (on any platform, not just -Emscripten) and overseeing various associated tasks. The specification -is limited in its scope and lacks some features. In particular, EGL -cannot help with the following tasks: - Creating a render window. The -EGL specification does not specify how a target window is created to -which to render to. One must use platform-specific native window system -functions (X11, Win32 API, ANativeWindow\_..) to first create a render -window. - Specifying render window size in arbitrary pixel increments. -EGL does not have any functionality to request a desired size for the -main render window, or to resize it. - Specifying a fullscreen video -mode/screen resolution. EGL cannot be used to control whether to render -in a windowed or fullscreen mode, or to toggle between these at runtime. - -Therefore, for each platform, including Emscripten, there exists -platform-specific means to perform these tasks. +======================================= + +Somewhat disappointingly, EGL is not a self-sufficient complete solution for initializing GLES2 graphics rendering (on any platform, not just Emscripten) and overseeing various associated tasks. The specification is limited in its scope and lacks some features. In particular, EGL cannot help with the following tasks: + +- Creating a render window. The EGL specification does not specify how a target window is created to which to render to. One must use platform-specific native window system functions (X11, Win32 API, ANativeWindow_..) to first create a render window. +- Specifying render window size in arbitrary pixel increments. EGL does not have any functionality to request a desired size for the main render window, or to resize it. +- Specifying a fullscreen video mode/screen resolution. EGL cannot be used to control whether to render in a windowed or fullscreen mode, or to toggle between these at runtime. + +Therefore, for each platform, including Emscripten, there exists platform-specific means to perform these tasks. How to create a WebGL context using EGL? ----------------------------------------- +========================================= -In the web environment, WebGL is the technology used for 3D-accelerated -rendering. WebGL is almost identical to GLES2, and because EGL does not -apply at all for WebGL, for all purposes in this page, the terms WebGL -and GLES2 are used interchangeably. Therefore to create a WebGL context, +In the web environment, WebGL is the technology used for 3D-accelerated rendering. WebGL is almost identical to GLES2, and because EGL does not apply at all for WebGL, for all purposes in this page, the terms WebGL and GLES2 are used interchangeably. Therefore to create a WebGL context, one uses EGL, and according to its wording, creates a GLES2 context. Initialization -~~~~~~~~~~~~~~ +-------------- Perform the following steps to create a GLES2 context using EGL: -1. Obtain a handle to an **EGLDisplay** object by calling - **eglGetDisplay**. -2. Initialize EGL on that display by calling **eglInitialize**. -3. Call **eglGetConfigs** and/or **eglChooseConfig** one or multiple - times to find the **EGLConfig** that represents the desired main - render target parameters. To examine the attributes of an - **EGLConfig**, call **eglGetConfigAttrib**. -4. At this point, one would use whatever platform-specific functions - available (X11, Win32 API, ANativeWindow) to set up a native window - to render to. For Emscripten, this step does not apply, and can be - skipped. -5. Create a main render target surface (**EGLSurface**) by calling - **eglCreateWindowSurface** with a valid display and config - parameters. Set window and attribute list parameters to null. -6. Create a GLES2 rendering context (**EGLContext**) by calling - **eglCreateContext**, followed by a call to **eglMakeCurrent** to - activate the rendering context. When creating the context, specify - the context attribute **EGL\_CONTEXT\_CLIENT\_VERSION == 2**. - -After these steps, you have a set of EGL objects **EGLDisplay**, -**EGLConfig**, **EGLSurface** and **EGLContext** that represent the main -GLES2 rendering context. +#. Obtain a handle to an ``EGLDisplay`` object by calling ``eglGetDisplay``. +#. Initialize EGL on that display by calling ``eglInitialize``. +#. Call ``eglGetConfigs`` and/or ``eglChooseConfig`` one or multiple times to find the ``EGLConfig`` that represents the desired main render target parameters. To examine the attributes of an ``EGLConfig``, call ``eglGetConfigAttrib``. +#. At this point, one would use whatever platform-specific functions available (X11, Win32 API, ANativeWindow) to set up a native window to render to. For Emscripten, this step does not apply, and can be skipped. +#. Create a main render target surface (``EGLSurface``) by calling ``eglCreateWindowSurface`` with a valid display and config parameters. Set window and attribute list parameters to null. +#. Create a GLES2 rendering context (``EGLContext``) by calling ``eglCreateContext``, followed by a call to ``eglMakeCurrent`` to activate the rendering context. When creating the context, specify the context attribute ``EGL_CONTEXT_CLIENT_VERSION == 2``. + +After these steps, you have a set of EGL objects ``EGLDisplay``, ``EGLConfig``, ``EGLSurface`` and ``EGLContext`` that represent the main GLES2 rendering context. Cleanup -~~~~~~~ +-------------- The sequence to clean up at deinitialization is as follows: -1. Free up the currently active rendering context by calling - **eglMakeCurrent(display, EGL\_NO\_SURFACE, EGL\_NO\_SURFACE, - EGL\_NO\_CONTEXT)**. -2. Deinitialize the **EGLContext** object by calling - **eglDestroyContext** on it. -3. Destroy all initialized **EGLSurface** objects by calling - **eglDestroySurface** on them. -4. Deinitialize EGL altogether by calling **eglTerminate(display)**. -5. Delete the native rendering window. This step does not apply for - Emscripten. +#. Free up the currently active rendering context by calling ``eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)``. +#. Deinitialize the ``EGLContext`` object by calling ``eglDestroyContext`` on it. +#. Destroy all initialized ``EGLSurface`` objects by calling ``eglDestroySurface`` on them. +#. Deinitialize EGL altogether by calling ``eglTerminate(display)``. +#. Delete the native rendering window. This step does not apply for Emscripten. Sample Code -~~~~~~~~~~~ +-------------- -Example code for using EGL to initialize a WebGL context can be found in -the sample applications in the -`emscripten/test/glbook `__ -directory, more specifically in the file -`esUtil.c `__. +Example code for using EGL to initialize a WebGL context can be found in the sample applications in the `emscripten/test/glbook `_ directory, more specifically in the file `esUtil.c `_. Implementation Status and Notes -------------------------------- +======================================= -This section lists all EGL v1.4 functions and describes their current -implementation status in Emscripten. +This section lists all EGL v1.4 functions and describes their current implementation status in Emscripten. Fully Implemented -~~~~~~~~~~~~~~~~~ - -- **eglInitialize, eglGetConfigs, eglQueryContext, eglQueryString, - eglQuerySurface, eglGetCurrentContext, glGetCurrentSurface, - eglGetCurrentDisplay, eglReleaseThread, eglDestroySurface, - eglDestroyContext**: Implemented and should work according to the EGL - v1.4 specification. - -- **eglSwapBuffers**: Implemented, but this function cannot really - control the swap behavior under WebGL. Calling this function is - optional under Emscripten. In WebGL, the contents of the display are - always presented to the screen only after the code yields its - execution back to the browser, that is, when you return from the tick - callback handler you passed to emscripten\_set\_main\_loop. The - ``eglSwapBuffers`` function can however still be used to detect when - a GL context loss event occurs. - -- **eglGetDisplay**: Implemented according to the spec. Emscripten does - not utilize multiple EGLNativeDisplayType objects, so pass in - EGL\_DEFAULT\_DISPLAY here. Emscripten currently actually ignores any - value passed in here for linux emulation purposes, but you should not - rely on this in the future. - -- **eglGetError**: Implemented according to the spec. Important! - According to the spec, eglGetError only reports the single most - recent error, and not list of previous errors, so don't call this - function in a loop like glGetError is called! +------------------ + +- ``eglInitialize``, ``eglGetConfigs``, ``eglQueryContext``, ``eglQueryString``, ``eglQuerySurface``, ``eglGetCurrentContext``, ``glGetCurrentSurface``, ``eglGetCurrentDisplay``, ``eglReleaseThread``, ``eglDestroySurface``, ``eglDestroyContext``: Implemented and should work according to the EGL v1.4 specification. + +- ``eglSwapBuffers``: Implemented, but this function cannot really control the swap behavior under WebGL. Calling this function is optional under Emscripten. In WebGL, the contents of the display are always presented to the screen only after the code yields its execution back to the browser, that is, when you return from the tick callback handler you passed to :c:func:`emscripten_set_main_loop`. The ``eglSwapBuffers`` function can however still be used to detect when a GL context loss event occurs. + +- ``eglGetDisplay``: Implemented according to the spec. Emscripten does not utilize multiple EGLNativeDisplayType objects, so pass in EGL_DEFAULT_DISPLAY here. Emscripten currently actually ignores any value passed in here for linux emulation purposes, but you should not rely on this in the future. + +- ``eglGetError``: Implemented according to the spec. Important! According to the spec, eglGetError only reports the single most recent error, and not list of previous errors, so don't call this function in a loop like glGetError is called! Partially Implemented -~~~~~~~~~~~~~~~~~~~~~ +---------------------- -- **eglChooseConfig**: Implemented as a stub, but this function does - not do searching/filtering, and is at the moment identical to - eglGetConfigs (`issue - #643 `__). +- ``eglChooseConfig``: Implemented as a stub, but this function does not do searching/filtering, and is at the moment identical to eglGetConfigs (`issue #643 `_). -- **eglGetConfigAttrib**: Implemented. Querying for the attributes - EGL\_BUFFER\_SIZE, EGL\_ALPHA\_SIZE, EGL\_BLUE\_SIZE, - EGL\_GREEN\_SIZE, EGL\_RED\_SIZE, EGL\_DEPTH\_SIZE and - EGL\_STENCIL\_SIZE currently return hardcoded default values (`issue - #644 `__). The - attributes EGL\_MIN\_SWAP\_INTERVAL and EGL\_MAX\_SWAP\_INTERVAL - don't currently have any function. Instead, call - emscripten\_set\_main\_loop to specify the main loop update rate. +- ``eglGetConfigAttrib``: Implemented. Querying for the attributes ``EGL_BUFFER_SIZE``, ``EGL_ALPHA_SIZE``, ``EGL_BLUE_SIZE``, ``EGL_GREEN_SIZE``, ``EGL_RED_SIZE``, ``EGL_DEPTH_SIZE`` and ``EGL_STENCIL_SIZE`` currently return hardcoded default values (`issue #644 `_). The attributes ``EGL_MIN_SWAP_INTERVAL`` and ``EGL_MAX_SWAP_INTERVAL`` don't currently have any function. Instead, call :c:func:`emscripten_set_main_loop` to specify the main loop update rate. -- **eglCreateWindowSurface**: Implemented, except it is not possible to - call this function multiple times to create multiple render windows. +- ``eglCreateWindowSurface``: Implemented, except it is not possible to call this function multiple times to create multiple render windows. -- **eglCreateContext**: Implemented as a stub. It is not possible to - call this function multiple times to create multiple contexts. +- ``eglCreateContext``: Implemented as a stub. It is not possible to call this function multiple times to create multiple contexts. -- **eglBindAPI, eglQueryAPI**: Implemented, although these functions - have little utility on Emscripten, since only the GLES2 client API is - supported. +- ``eglBindAPI``, ``eglQueryAPI``: Implemented, although these functions have little utility on Emscripten, since only the GLES2 client API is supported. -- **eglWaitClient, eglWaitNative**: Implemented as no-op functions. - These have no meaning on Emscripten. +- ``eglWaitClient``, ``eglWaitNative``: Implemented as no-op functions. These have no meaning on Emscripten. -- **eglSwapInterval**: Implemented as a no-op stub. Currently this - function cannot set the vsync interval, or enable/disable it. +- ``eglSwapInterval``: Implemented as a no-op stub. Currently this function cannot set the vsync interval, or enable/disable it. -- **eglMakeCurrent**: Implemented as a no-op stub. +- ``eglMakeCurrent``: Implemented as a no-op stub. -- **eglTerminate**: Implemented as a no-op function stub. JS apps are - not often shut down manually, but when closing the browser or - switching the web page, the browser manages all teardown - automatically. Therefore this function does not have a critical - importance in emscripten. +- ``eglTerminate``: Implemented as a no-op function stub. JavaScript apps are not often shut down manually, but when closing the browser or switching the web page, the browser manages all teardown automatically. Therefore this function does not have a critical importance in Emscripten. -- **eglGetProcAddress**: Implemented, experimental. +- ``eglGetProcAddress``: Implemented, experimental. Missing Functionality -~~~~~~~~~~~~~~~~~~~~~ +---------------------- -The following functions are currently completely unimplemented. \ **Do -not call**\ these functions in Emscripten code, or the application will -halt on trying to execute an undefined function: +The following functions are currently completely unimplemented. \ **Do not call**\ these functions in Emscripten code, or the application will halt on trying to execute an undefined function: -- **eglCreatePbufferSurface, eglCreatePixmapSurface, - eglCreatePbufferFromClientBuffer, eglSurfaceAttrib, eglBindTexImage, - eglReleaseTexImage, eglWaitGL, eglCopyBuffers**. +- ``eglCreatePbufferSurface``, ``eglCreatePixmapSurface``, ``eglCreatePbufferFromClientBuffer``, ``eglSurfaceAttrib``, ``eglBindTexImage``, ``eglReleaseTexImage``, ``eglWaitGL``, ``eglCopyBuffers``. EGL Extensions -~~~~~~~~~~~~~~ +--------------- -Currently, Emscripten does not implement any extensions in the `EGL -Extension Registry `__. +Currently, Emscripten does not implement any extensions in the `EGL Extension Registry `_. EGL-Related Bugs and Todos -~~~~~~~~~~~~~~~~~~~~~~~~~~ +--------------------------- -The `Emscripten issue -tracker `__ -lists EGL-relates issues using the label EGL. Check that page to report -or find issues in Emscripten related to EGL. +The `Emscripten issue tracker `_ lists EGL-relates issues using the label EGL. Check that page to report or find issues in Emscripten related to EGL. diff --git a/site/source/docs/porting/multimedia_and_graphics/index.rst b/site/source/docs/porting/multimedia_and_graphics/index.rst index 790f89c4bfaf9..9974be3239606 100644 --- a/site/source/docs/porting/multimedia_and_graphics/index.rst +++ b/site/source/docs/porting/multimedia_and_graphics/index.rst @@ -1,10 +1,10 @@ .. _multimedia-and-graphics-index: -========================================== -Multimedia and Graphics (ready-for-review) -========================================== +======================= +Multimedia and Graphics +======================= -This section is for articles about integrating graphics and audio with the Emscripten browser environment. +This section contains articles about integrating graphics and audio with the Emscripten browser environment. .. toctree:: diff --git a/site/source/docs/site/about.rst b/site/source/docs/site/about.rst index 9a9bb2c89051a..d097b9790758d 100644 --- a/site/source/docs/site/about.rst +++ b/site/source/docs/site/about.rst @@ -1,3 +1,5 @@ +.. _about-this-site: + =============== About this site =============== @@ -28,11 +30,12 @@ By the end of the project all articles should be published and all of this page .. todo:: **HamishW** Delete this whole section at the end of the project. At that point there should only be HamishW markup for possible Todos. Note the search link immediately above too - this is to the kripken site and may need to change if the site moves. +.. _about-this-site-search: Searching the site ================== -Searching returns only topics that contain **all** the specified keywords. +Searching returns topics that contain **all** the specified keywords. .. tip:: Always start by searching for *single* words like "interacting" or "compiling". Generally this will be enough to find the relevant document. If not, you can refine the search by adding additional terms. diff --git a/site/source/docs/tools_reference/index.rst b/site/source/docs/tools_reference/index.rst index ba25c91528771..fdb6fb403c18d 100644 --- a/site/source/docs/tools_reference/index.rst +++ b/site/source/docs/tools_reference/index.rst @@ -1,10 +1,10 @@ .. _tools-reference: -================================== -Tools Reference (ready-for-review) -================================== +=============== +Tools Reference +=============== -This section provides command line reference for the main tools in the :ref:`Emscripten toolchain `: +This section provides reference for the main tools in the :ref:`Emscripten toolchain `: - :ref:`emccdoc` *Emcc* is used to call the Emscripten compiler from the command line. It is effectively a drop-in replacement for a standard compiler like *gcc* or *clang*. From 714f6fa560ae94d0a43e7b2b7f9557457f67b383 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Sep 2014 11:00:39 -0700 Subject: [PATCH 14/37] fix stringToC so it is parseable again --- src/preamble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preamble.js b/src/preamble.js index 45e474c2c4960..a1b9befb2c2b6 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -358,7 +358,7 @@ var cwrap, ccall; var ret = 0; if (str !== null && str !== undefined && str !== 0) { // null string // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' - ret = Runtime.stackAlloc(str.length * 4 + 1); + ret = Runtime.stackAlloc((str.length << 2) + 1); writeStringToMemory(str, ret); } return ret; From e8783b3bce59aeaadaf3191daf6dcd1fc3e717a5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Sep 2014 11:52:32 -0700 Subject: [PATCH 15/37] default emcc help to mention emcc, mention ./emcc just once --- site/source/docs/tools_reference/emcc.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index 22a32b50b40f8..3751a6ef91c0c 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -12,7 +12,9 @@ Command line syntax :: - ./emcc [options] file... + emcc [options] file... + +(Note that you will need ``./emcc`` if you want to run emcc from your current directory.) The input file(s) can be either source code files that *Clang* can handle (C or C++), LLVM bitcode in binary form, or LLVM assembly files in human-readable form. @@ -23,10 +25,10 @@ Arguments Most `clang options `_ will work, as will `gcc options `_, for example: :: # Display this information - ./emcc --help + emcc --help Display compiler version information - ./emcc --version + emcc --version To see the full list of *Clang* options supported on the version of *Clang* used by Emscripten, run ``clang --help``. @@ -267,7 +269,7 @@ Options that are modified or new in *emcc* are listed below: This will pass ``-v`` to *Clang*, and also enable ``EMCC_DEBUG`` (this gets intermediate files for the compiler’s various stages). It will also run Emscripten's internal sanity checks on the toolchain, etc. - .. tip:: ``./emcc -v`` is a useful tool for diagnosing errors. It works with or without other arguments. + .. tip:: ``emcc -v`` is a useful tool for diagnosing errors. It works with or without other arguments. .. _emcc-clear-cache: @@ -308,7 +310,7 @@ Options that are modified or new in *emcc* are listed below: :: - ./emcc -c a.c -o dir/ + emcc -c a.c -o dir/ ``--valid_abspath path`` From b3a24174a6370270124bb60e103ebd671db24d4c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Sep 2014 11:52:37 -0700 Subject: [PATCH 16/37] text update --- site/build/text/docs/tools_reference/emcc.txt | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/site/build/text/docs/tools_reference/emcc.txt b/site/build/text/docs/tools_reference/emcc.txt index efcbfaa4253af..60d080ad48a6b 100644 --- a/site/build/text/docs/tools_reference/emcc.txt +++ b/site/build/text/docs/tools_reference/emcc.txt @@ -1,13 +1,6 @@ -Emscripten Compiler Frontend (emcc) (ready-for-review) -****************************************************** - -**This document provides the command syntax for the Emscription -Compiler Frontend.** - - -Purpose -======= +Emscripten Compiler Frontend (emcc) +*********************************** The Emscripten Compiler Frontend ("emcc") is used to call the Emscripten compiler from the command line. It is effectively a drop-in @@ -19,6 +12,9 @@ Command line syntax emcc [options] file... +(Note that you will need "./emcc" if you want to run emcc from your +current directory.) + The input file(s) can be either source code files that *Clang* can handle (C or C++), LLVM bitcode in binary form, or LLVM assembly files in human-readable form. @@ -97,14 +93,19 @@ Options that are modified or new in *emcc* are listed below: -s RUNTIME_LINKED_LIBS="['liblib.so']" -s "RUNTIME_LINKED_LIBS=['liblib.so']" - You can also specify a file from which the value would be read, for - example, + You can also specify that the value of an option will be read from + a specified JSON-formatted file. For example, the following option + sets the "DEAD_FUNCTIONS" option with the contents of the file at + **path/to/file**. -s DEAD_FUNCTIONS=@/path/to/file - The contents of **/path/to/file** will be read, JSON.parsed and set - into "DEAD_FUNCTIONS" (so the file could contain ["_func1", - "func2"] ). Note that the path must be absolute, not relative. + Note: * In this case the file might contain a JSON-formatted list + of + + functions: "["_func1", "func2"]". + + * The specified file path must be absolute, not relative. "-g" Use debug info. @@ -166,14 +167,14 @@ Options that are modified or new in *emcc* are listed below: * "2": Shared (C-like) typed arrays (default). "--js-opts " - Possible "level" values are: + Enables JavaScript optimizations. Possible "level" values are: * "0": Prevent JavaScript optimizer from running. * "1": Use JavaScript optimizer (default). "--llvm-opts " - Possible "level" values are: + Enables LLVM optimizations. Possible "level" values are: * "0": No LLVM optimizations (default in -O0). @@ -188,7 +189,8 @@ Options that are modified or new in *emcc* are listed below: --llvm-opts "['-O3', '-somethingelse']" "--llvm-lto " - Possible "level" values are: + Enables LLVM link-time optimizations (LTO). Possible "level" values + are: * "0": No LLVM LTO (default). @@ -205,8 +207,8 @@ Options that are modified or new in *emcc* are listed below: setting has no effect. - * LLVM LTO is not perfectly stable yet, and can can cause code - to behave incorrectly. + * LLVM LTO is not perfectly stable yet, and can cause code to + behave incorrectly. "--closure " Runs the *Closure Compiler*. Possible "on" values are: @@ -256,8 +258,8 @@ Options that are modified or new in *emcc* are listed below: run *emcc*. Note: Embedding files is much less efficient than *preloading* - them. You should only use it for small amounts of small files. - Instead, use "--preload-file" which emits efficient binary data. + them. You should only use it for small files, in small numbers. + Instead use "--preload-file", which emits efficient binary data. "--preload-file " Specify a file to preload before running the compiled code @@ -347,10 +349,10 @@ Options that are modified or new in *emcc* are listed below: .js"). Files with function declarations must be loaded before main file upon execution. - * Without "-g" option this creates files with function + * Without the "-g" option this creates files with function declarations up to the given size with the suffix **_functions.partxxx.js** and a main file with the suffix - ".js". + **.js**. * With the "-g" option this recreates the directory structure of the C source files and stores function declarations in @@ -360,8 +362,8 @@ Options that are modified or new in *emcc* are listed below: has the suffix ".js". "--bind" - Compiles the source code using the *embind (wiki-import)* bindings - approach, which connects C/C++ and JavaScript. + Compiles the source code using the *Embind (under-construction)* + bindings to connect C/C++ and JavaScript. "--ignore-dynamic-linking" Tells the compiler to ignore dynamic linking (the user will need to @@ -380,9 +382,9 @@ Options that are modified or new in *emcc* are listed below: "-v" Turns on verbose output. - This will pass "-v" to *Clang*, and also enable "EMCC_DEBUG" (gets - intermediate files for the compiler’s various stages). It will also - run Emscripten's internal sanity checks on the toolchain, etc. + This will pass "-v" to *Clang*, and also enable "EMCC_DEBUG" (this + gets intermediate files for the compiler’s various stages). It will + also run Emscripten's internal sanity checks on the toolchain, etc. Tip: "emcc -v" is a useful tool for diagnosing errors. It works with or without other arguments. @@ -431,11 +433,11 @@ Options that are modified or new in *emcc* are listed below: "--proxy-to-worker" Runs the main application code in a worker, proxying events to it - and output from it. If emitting HTML, this emits a **.html** and a - **.js** file, with the JavaScript to be run in a worker. If - emitting JavaScript, the target file name contains the part to be - run on the main thread, while a second **.js** file with suffix - ".worker.js" will contain the worker portion. + and output from it. If emitting HTML, this emits a **.html** file, + and a separate **.js** file containing the JavaScript to be run in + a worker. If emitting JavaScript, the target file name contains the + part to be run on the main thread, while a second **.js** file with + suffix ".worker.js" will contain the worker portion. "--emrun" Enables the generated output to be aware of the *emrun* command @@ -452,7 +454,7 @@ Options that are modified or new in *emcc* are listed below: Specifies the file suffix to generate if the location of a directory name is passed to the "-o" directive. - For example, consider the following command which will by default + For example, consider the following command, which will by default generate an output name **dir/a.o**. With "--default-obj-ext .ext" the generated file has the custom suffix *dir/a.ext*. @@ -463,7 +465,7 @@ Options that are modified or new in *emcc* are listed below: include paths. "-o " - The "target" file name extension defines what type of output be + The "target" file name extension defines the output type to be generated: * **.js** : JavaScript. @@ -476,9 +478,9 @@ Options that are modified or new in *emcc* are listed below: * **.o** : LLVM bitcode (same as .bc). - Note: If "--memory-init-file" is used, then in addition to the - **.js** or **.html** file which is generated, a **.mem** file - will also be created. + Note: If "--memory-init-file" is used, a **.mem** file will be + created in addition to the generated **.js** and/or **.html** + file. "-c" Tells *emcc* to generate LLVM bitcode (which can then be linked From b1ef4b0b12739843ce7175e3874d394f5ceea28e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Sep 2014 14:14:23 -0700 Subject: [PATCH 17/37] fix emscripten ifdef --- system/lib/libc/musl/src/stdio/vfscanf.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/system/lib/libc/musl/src/stdio/vfscanf.c b/system/lib/libc/musl/src/stdio/vfscanf.c index 3795b1505de1a..21292c055dea4 100644 --- a/system/lib/libc/musl/src/stdio/vfscanf.c +++ b/system/lib/libc/musl/src/stdio/vfscanf.c @@ -53,8 +53,12 @@ static void *arg_n(va_list ap, unsigned int n) return p; } -//int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) -int MUSL_vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) // XXX Emscripten: Only use musl-specific vfscanf when called from within sscanf. +#ifndef __EMSCRIPTEN__ +int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) +#else +// XXX Emscripten: Only use musl-specific vfscanf when called from within sscanf. +int MUSL_vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) +#endif { int width; int size; @@ -331,7 +335,8 @@ int MUSL_vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) // XXX } #ifndef __EMSCRIPTEN__ -// XXX: EMSCRIPTEN: We don't need this alias. +// XXX EMSCRIPTEN: We don't need this alias. // Keeping it would have it aliasing to the C code when we typically use the JS version. weak_alias(vfscanf,__isoc99_vfscanf); #endif + From edee72103925caa2e2988a76d27b84dc96d17952 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Sep 2014 14:26:13 -0700 Subject: [PATCH 18/37] text update --- site/build/text/docs/api_reference/emscripten.h.txt | 13 +++++++++++-- site/build/text/docs/tools_reference/emcc.txt | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/site/build/text/docs/api_reference/emscripten.h.txt b/site/build/text/docs/api_reference/emscripten.h.txt index b1a74ccb419eb..7af72fc63771a 100644 --- a/site/build/text/docs/api_reference/emscripten.h.txt +++ b/site/build/text/docs/api_reference/emscripten.h.txt @@ -39,6 +39,9 @@ Table of Contents Inline assembly/JavaScript ========================== +Guide material for the following APIs can be found in *Calling +JavaScript from C/C++*. + Defines ------- @@ -106,6 +109,9 @@ EM_ASM_DOUBLE_V(code) Calling JavaScript From C/C++ ============================= +Guide material for the following APIs can be found in *Calling +JavaScript from C/C++*. + Function pointer types for callbacks ------------------------------------ @@ -235,6 +241,9 @@ void emscripten_async_load_script(const char *script, em_callback_func onload, Browser Execution Environment ============================= +Guide material for the following APIs can be found in *Emscripten +browser environment (wiki-import)*. + Functions --------- @@ -919,7 +928,7 @@ EMSCRIPTEN_KEEPALIVE Forces LLVM to not dead-code-eliminate a function. This also exports the function, as if you added it to - "EXPORTED_FUNCTIONS". + *EXPORTED_FUNCTIONS*. For example: @@ -1006,7 +1015,7 @@ void emscripten_call_worker(worker_handle worker, const char *funcname, char  * **funcname** (*const char**) -- The name of the function in the worker. The function must be a C function (so no C++ name - mangling), and must be exported (EXPORTED_FUNCTIONS). + mangling), and must be exported (*EXPORTED_FUNCTIONS*). * **data** (*char**) -- The address of a block of memory to copy over. diff --git a/site/build/text/docs/tools_reference/emcc.txt b/site/build/text/docs/tools_reference/emcc.txt index 60d080ad48a6b..0ea966ec6a461 100644 --- a/site/build/text/docs/tools_reference/emcc.txt +++ b/site/build/text/docs/tools_reference/emcc.txt @@ -79,8 +79,8 @@ Options that are modified or new in *emcc* are listed below: JavaScript (final link and JavaScript generation) stage. It is JavaScript- specific, so you can run "-Os" on your source files for example, and "-O3" during JavaScript generation if you want. - For more tips on optimizing your code, see *Optimizing Code - (wiki-import)*. + For more tips on optimizing your code, see *Optimizing Generated + Code (wiki- import)*. "-s OPTION=VALUE" JavaScript code generation option passed into the Emscripten From f3d0b1353f5a7c78dd22ff4466f2f438a7437dec Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 09:49:35 +1000 Subject: [PATCH 19/37] Update Documentation Home index - ready for review. Changes to other docs to support linking from this index. --- site/source/docs/api_reference/index.rst | 2 ++ site/source/docs/contributing/index.rst | 2 ++ site/source/docs/index.rst | 22 ++++++++++++++++--- .../docs/introducing_emscripten/index.rst | 2 ++ site/source/docs/site/index.rst | 11 ++++++++-- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/site/source/docs/api_reference/index.rst b/site/source/docs/api_reference/index.rst index b72b91c7a4fcf..da1d3d31ff5eb 100644 --- a/site/source/docs/api_reference/index.rst +++ b/site/source/docs/api_reference/index.rst @@ -1,3 +1,5 @@ +.. _api-reference-index: + ============= API Reference ============= diff --git a/site/source/docs/contributing/index.rst b/site/source/docs/contributing/index.rst index a5fd7e41421bc..8e9bc84117465 100644 --- a/site/source/docs/contributing/index.rst +++ b/site/source/docs/contributing/index.rst @@ -1,3 +1,5 @@ +.. _contributing-to-emscripten-index: + ========================== Contributing to Emscripten ========================== diff --git a/site/source/docs/index.rst b/site/source/docs/index.rst index e3c9b9bd10b9e..b09c0ec58ad11 100644 --- a/site/source/docs/index.rst +++ b/site/source/docs/index.rst @@ -1,7 +1,23 @@ -========================================== -Documentation Home (under-construction) -========================================== +.. _documentation-home: +===================================== +Documentation Home (ready-for-review) +===================================== + +This comprehensive documentation set contains everything you need to use Emscripten: + +- :ref:`introducting-emscripten-index` explains what Emscripten does, why it is needed, its limitations and its licensing. It will help you understand whether Emscripten is the right tool for you. +- :ref:`getting-started-index` walks you through downloading, installing and using the Emscripten SDK. +- :ref:`integrating-porting-index` illustrates the main differences between the native and Emscripten runtime environments, and explains the changes you need to make to prepare your code for the Web. +- :ref:`optimizing-index` shows how to optimise your code for size and performance. +- :ref:`compiling-and-running-projects-index` demonstrates how to integrate Emscripten into your existing project build system. +- :ref:`contributing-to-emscripten-index` explains how you can contribute to the project. +- :ref:`installing-from-source` explains how to build Emscripten from sources on Github (this is useful for contributors). +- :ref:`about-this-site` describes the documentation tools and writing conventions used to create this site. +- :ref:`api-reference-index` contains reference for the Emscripten toolchain. +- :ref:`tools-reference` contains reference for the Emscripten integration APIs. + +The full hierarchy of articles, opened to the second level, is shown below. .. toctree:: :maxdepth: 2 diff --git a/site/source/docs/introducing_emscripten/index.rst b/site/source/docs/introducing_emscripten/index.rst index 174f6efcd991b..cb614769e74cc 100644 --- a/site/source/docs/introducing_emscripten/index.rst +++ b/site/source/docs/introducing_emscripten/index.rst @@ -1,3 +1,5 @@ +.. _introducting-emscripten-index: + ====================== Introducing Emscripten ====================== diff --git a/site/source/docs/site/index.rst b/site/source/docs/site/index.rst index dbcb41cb7c2c9..93ed8f813fa7c 100644 --- a/site/source/docs/site/index.rst +++ b/site/source/docs/site/index.rst @@ -1,5 +1,12 @@ -Site Links (under-construction) -=================================================== +.. _site-links-index: + +========== +Site Links +========== + +This section contains articles that are specific to the site, or which do not belong in any other category. + +.. COMMENT (not rendered):: This isn't actually displayed anywhere, except on the documentation home. In the main sidebar the link is to the "About" document below (which is most important) and the glossary is not shown. This is intentional. .. toctree:: From e83ec5f897af39ca9d22547ad8a193e0a35147be Mon Sep 17 00:00:00 2001 From: Ningxin Hu Date: Wed, 3 Sep 2014 17:04:02 -0700 Subject: [PATCH 20/37] Add SIMD shuffle test cases. --- tests/core/test_simd5.in | 21 +++++++++++++++++++++ tests/core/test_simd5.out | 6 ++++++ tests/test_core.py | 9 +++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/core/test_simd5.in create mode 100644 tests/core/test_simd5.out diff --git a/tests/core/test_simd5.in b/tests/core/test_simd5.in new file mode 100644 index 0000000000000..f69b5813a7b2b --- /dev/null +++ b/tests/core/test_simd5.in @@ -0,0 +1,21 @@ +#include + +typedef float float32x4 __attribute__((__vector_size__(16))); + +int main(int argc, char **argv) { + float32x4 a = {1.0, 2.0, 3.0, 4.0}; + float32x4 b = {5.0, 6.0, 7.0, 8.0}; + float32x4 r = __builtin_shufflevector(a, b, 3, 1, 2, 0); + printf("%.1f %.1f %.1f %.1f\n", r[0], r[1], r[2], r[3]); + r = __builtin_shufflevector(a, b, 7, 5, 6, 4); + printf("%.1f %.1f %.1f %.1f\n", r[0], r[1], r[2], r[3]); + r = __builtin_shufflevector(a, b, 1, 2, 5, 4); + printf("%.1f %.1f %.1f %.1f\n", r[0], r[1], r[2], r[3]); + r = __builtin_shufflevector(a, b, 5, 4, 1, 2); + printf("%.1f %.1f %.1f %.1f\n", r[0], r[1], r[2], r[3]); + r = __builtin_shufflevector(a, b, 4, 1, 0, 5); + printf("%.1f %.1f %.1f %.1f\n", r[0], r[1], r[2], r[3]); + r = __builtin_shufflevector(a, b, 0, 7, 2, 3); + printf("%.1f %.1f %.1f %.1f\n", r[0], r[1], r[2], r[3]); + return 0; +} \ No newline at end of file diff --git a/tests/core/test_simd5.out b/tests/core/test_simd5.out new file mode 100644 index 0000000000000..738295bc2517c --- /dev/null +++ b/tests/core/test_simd5.out @@ -0,0 +1,6 @@ +4.0 2.0 3.0 1.0 +8.0 6.0 7.0 5.0 +2.0 3.0 6.0 5.0 +6.0 5.0 2.0 3.0 +5.0 2.0 1.0 6.0 +1.0 8.0 3.0 4.0 \ No newline at end of file diff --git a/tests/test_core.py b/tests/test_core.py index 2b6eeda3f3c2a..c2341ac6fbc68 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5125,6 +5125,15 @@ def test_simd4(self): self.do_run_from_file(src, output) + def test_simd5(self): + # test_simd5 is to test shufflevector of SIMD path + if Settings.ASM_JS: Settings.ASM_JS = 2 # does not validate + + test_path = path_from_root('tests', 'core', 'test_simd5') + src, output = (test_path + s for s in ('.in', '.out')) + + self.do_run_from_file(src, output) + def test_gcc_unmangler(self): if os.environ.get('EMCC_FAST_COMPILER') == '0': Settings.NAMED_GLOBALS = 1 # test coverage for this; fastcomp never names globals From 93e571410361f09fc8e556f3f39abe7e239c99c7 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 10:15:00 +1000 Subject: [PATCH 21/37] Rename the Emscripten Browers Env. To Emscripten Runtime env. Put memory model doc into that doc. Update links to typed arrays mode 2 to point to the same place --- .../source/docs/api_reference/preamble.js.rst | 6 ++-- .../docs/compiling/Code-Generation-Modes.rst | 35 ------------------- .../Emscripten-browser-environment.rst | 26 ++++++++++++-- site/source/docs/porting/index.rst | 1 - site/source/docs/tools_reference/emcc.rst | 8 +---- 5 files changed, 28 insertions(+), 48 deletions(-) delete mode 100644 site/source/docs/compiling/Code-Generation-Modes.rst diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index c4c3d679e9f22..3d83b0bb03e68 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -312,10 +312,10 @@ Stack trace -Type accessors for Typed Arrays Mode 2 -========================================== +Type accessors for the memory model +=================================== -When using :ref:`typed-arrays-mode-2` a typed array buffer (``ArrayBuffer``) is used to represent memory, with different views into it giving access to the different types. The views for accessing different types of memory are listed below. +The :ref:`emscripten-memory-model` uses a typed array buffer (``ArrayBuffer``) to represent memory, with different views into it giving access to the different types. The views for accessing different types of memory are listed below. .. js:data:: HEAP8 diff --git a/site/source/docs/compiling/Code-Generation-Modes.rst b/site/source/docs/compiling/Code-Generation-Modes.rst deleted file mode 100644 index c6cd8cdd9a8be..0000000000000 --- a/site/source/docs/compiling/Code-Generation-Modes.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _emscripten-runtime-environment: - -=================================================== -Emscripten Runtime Environment (under-construction) -=================================================== - - - -.. _Code-Generation-Modes: - -.. _typed-arrays: - -.. _emscripten-memory-model: - - -Emscripten Memory Model -======================= - -Emscripten's memory model is known as :term:`Typed Arrays Mode 2`. It represents memory using a single `typed array `_, with different *views* providing access to different types (:js:data:`HEAPU32` for 32-bit unsigned integers, etc.) - -.. _typed-arrays-mode-2: - -.. note:: *Typed Arrays Mode 2* is the *only* memory model supported by the :ref:`Fastcomp ` compiler, and it is the *default* memory model for the :ref:`old compiler `. - - Compared to other models tried by the project, it can be used for a broad range of arbitrary compiled code, and is relatively fast. - -The model lays out items in memory in the same way as with normal C and C++, and as a result it uses the same amount of memory. - -We currently align the stack to 4-byte boundaries (this means that reading 8-byte values is slower as they must be read in two parts and then combined). - -This model allows you to use code that violates the load-store consistency assumption. Since the different views show the same data, you can (say) write a 32-bit integer, then read a byte from the middle, and it will work just like in C or C++. - - -.. note:: ``SAFE_HEAP`` ignores load-store consistency violations, since they don't matter. Alignment of reads and writes will be checked, which is important since reading unaligned values can fail. - diff --git a/site/source/docs/porting/Emscripten-browser-environment.rst b/site/source/docs/porting/Emscripten-browser-environment.rst index 75344e75ca464..33bfce263034e 100644 --- a/site/source/docs/porting/Emscripten-browser-environment.rst +++ b/site/source/docs/porting/Emscripten-browser-environment.rst @@ -1,9 +1,10 @@ .. _Emscripten-browser-environment: +.. _emscripten-runtime-environment: + ============================================ -Emscripten browser environment (wiki-import) +Emscripten Runtime Environment (wiki-import) ============================================ -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! The browser environment is different than the environment a normal C/C++ application expects. The main differences are how input and output work, and the fact that the main loop must be asynchronous. @@ -65,3 +66,24 @@ Notes - ``SDL_QUIT`` is tricky to implement in browsers. The current Emscripten implementation of it will work if you use :c:func:`emscripten_set_main_loop`: As the page is shut, it will force a final direct call to the main loop, giving it a chance to notice the ``SDL_QUIT`` event. So if you do not use a main loop, you will not notice it - your app will close before your next event handling. Note also that there are limitations on what you can do as the page shuts (in onunload), some actions like showing alerts are banned by browsers. + +.. _emscripten-memory-model: + +Emscripten memory model +======================= + +Emscripten's memory model is known as :term:`Typed Arrays Mode 2`. It represents memory using a single `typed array `_, with different *views* providing access to different types (:js:data:`HEAPU32` for 32-bit unsigned integers, etc.) + +.. note:: *Typed Arrays Mode 2* is the *only* memory model supported by the :ref:`Fastcomp ` compiler, and it is the *default* memory model for the :ref:`old compiler `. + + Compared to other models tried by the project, it can be used for a broad range of arbitrary compiled code, and is relatively fast. + +The model lays out items in memory in the same way as with normal C and C++, and as a result it uses the same amount of memory. + +We currently align the stack to 4-byte boundaries (this means that reading 8-byte values is slower as they must be read in two parts and then combined). + +This model allows you to use code that violates the load-store consistency assumption. Since the different views show the same data, you can (say) write a 32-bit integer, then read a byte from the middle, and it will work just like in C or C++. + + +.. note:: ``SAFE_HEAP`` ignores load-store consistency violations, since they don't matter. Alignment of reads and writes will be checked, which is important since reading unaligned values can fail. + diff --git a/site/source/docs/porting/index.rst b/site/source/docs/porting/index.rst index 97e9a3c2d31d0..8736394e56b79 100644 --- a/site/source/docs/porting/index.rst +++ b/site/source/docs/porting/index.rst @@ -11,7 +11,6 @@ The topics in this section cover the main integration points that you need to co guidelines/index Emscripten-browser-environment - ../compiling/Code-Generation-Modes connecting_cpp_and_javascript/index files/index multimedia_and_graphics/index diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index c4bc8c172d912..cde1766ab066b 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -120,13 +120,7 @@ Options that are modified or new in *emcc* are listed below: .. note:: This is only relevant when :term:`minifying` global names, which happens in ``-O2`` and above, and when no ``-g`` option was specified to prevent minification. -``--typed-arrays `` - Set the :ref:`typed array mode `. Possible values are: - - - ``0``: No typed arrays. - - ``1``: Parallel typed arrays. - - ``2``: Shared (C-like) typed arrays (default). - + ``--js-opts `` Enables JavaScript optimizations. Possible ``level`` values are: From f080f76b8fb41e0a89e3e013ee322d11b75f843f Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 10:28:21 +1000 Subject: [PATCH 22/37] Renamed file for browser env to runtime env. Fixes to links to support this --- site/source/docs/api_reference/emscripten.h.rst | 2 +- site/source/docs/getting_started/FAQ.rst | 4 ++-- site/source/docs/introducing_emscripten/about_emscripten.rst | 2 +- .../connecting_cpp_and_javascript/Interacting-with-code.rst | 2 +- .../docs/porting/connecting_cpp_and_javascript/index.rst | 4 +++- ...ser-environment.rst => emscripten-runtime-environment.rst} | 2 -- site/source/docs/porting/guidelines/api_limitations.rst | 4 ++-- site/source/docs/porting/index.rst | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) rename site/source/docs/porting/{Emscripten-browser-environment.rst => emscripten-runtime-environment.rst} (99%) diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index f21cbe162c6cb..294c03b9feb31 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -165,7 +165,7 @@ Functions Browser Execution Environment ============================= -Guide material for the following APIs can be found in :ref:`Emscripten-browser-environment`. +Guide material for the following APIs can be found in :ref:`emscripten-runtime-environment`. Functions diff --git a/site/source/docs/getting_started/FAQ.rst b/site/source/docs/getting_started/FAQ.rst index f10d0c907cf6f..bfef47f0fff17 100644 --- a/site/source/docs/getting_started/FAQ.rst +++ b/site/source/docs/getting_started/FAQ.rst @@ -119,7 +119,7 @@ Graphical C++ apps typically have an infinite main loop in which event handling, Apps that use an infinite main loop should be re-coded to put the actions for a single iteration of the loop into a single "finite" function. In the native build this function can be run in an infinite loop as before. In the Emscripten build it is set as the :ref:`main loop function ` and will be called by the browser at a specified frequency. -There is more information on this topic in :ref:`Emscripten-Browser-Environment`. +There is more information on this topic in :ref:`emscripten-runtime-environment`. .. _faq-how-run-event-loop: @@ -127,7 +127,7 @@ There is more information on this topic in :ref:`Emscripten-Browser-Environment` How do I run an event loop? =========================== -To run a C function repeatedly, use :c:func:`emscripten_set_main_loop` (this is discussed in :ref:`Emscripten-browser-environment`). The related functions in :ref:`emscripten.h ` are also useful, allowing you to add events that block the main loop, etc. +To run a C function repeatedly, use :c:func:`emscripten_set_main_loop` (this is discussed in :ref:`emscripten-runtime-environment`). The related functions in :ref:`emscripten.h ` are also useful, allowing you to add events that block the main loop, etc. To respond to browser events use the SDL API in the normal way. There are examples in the SDL tests (search for SDL in **tests/runner.py**). diff --git a/site/source/docs/introducing_emscripten/about_emscripten.rst b/site/source/docs/introducing_emscripten/about_emscripten.rst index 0fe9076baf06e..39a5d96c72217 100644 --- a/site/source/docs/introducing_emscripten/about_emscripten.rst +++ b/site/source/docs/introducing_emscripten/about_emscripten.rst @@ -64,7 +64,7 @@ Porting code to use Emscripten Emscripten support for **portable** C/C++ code is fairly comprehensive. Support for the C standard library, C++ standard library, C++ exceptions, etc. is very good. `SDL `_ support is sufficient to run quite a lot of code. :ref:`OpenGL-support` support is excellent for OpenGL ES 2.0-type code, and acceptable for other types. -There are differences between the native and `browser environments `_, which mean some changes usually need to be made to the native code. That said, many applications will only need to change the way they define their main loop, and also modify their :ref:`file handling ` to adapt to the limitations of the browser/JavaScript. +There are differences between the native and `browser environments `_, which mean some changes usually need to be made to the native code. That said, many applications will only need to change the way they define their main loop, and also modify their :ref:`file handling ` to adapt to the limitations of the browser/JavaScript. There are also limitations that can make some code easier to port — read :ref:`CodeGuidelinesAndLimitations` to determine where you may need to spend more effort. diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst index c1803d68afcbf..964cdf06d6420 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst @@ -33,7 +33,7 @@ The JavaScript methods for calling compiled C functions are efficient, but canno This article explains each of the methods listed above, or provides links to more detailed information. -.. note:: For information on how compiled code interacts with the browser environment, see :ref:`Emscripten-Browser-Environment`. For file system related manners, see the :ref:`Filesystem-Guide`. +.. note:: For information on how compiled code interacts with the browser environment, see :ref:`emscripten-runtime-environment`. For file system related manners, see the :ref:`Filesystem-Guide`. .. _interacting-with-code-ccall-cwrap: diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/index.rst b/site/source/docs/porting/connecting_cpp_and_javascript/index.rst index 405611c7d8f30..15dc24570acbc 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/index.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/index.rst @@ -1,3 +1,5 @@ +.. _connecting-cpp-and-javascript-index: + ============================= Connecting C++ and JavaScript ============================= @@ -6,7 +8,7 @@ Emscripten provides various options for connecting "normal" JavaScript and compi The topic :ref:`Interacting-with-code` provides an overview of all the methods. The other two topics provide additional detail on the :ref:`Embind` and :ref:`WebIDL-Binder` tools. -.. note:: For information on how compiled code interacts with the browser environment, see :ref:`Emscripten-Browser-Environment`. For file system-related manners, see the :ref:`Filesystem-Guide`. +.. note:: For information on how compiled code interacts with the browser environment, see :ref:`emscripten-runtime-environment`. For file system-related manners, see the :ref:`Filesystem-Guide`. .. toctree:: :maxdepth: 1 diff --git a/site/source/docs/porting/Emscripten-browser-environment.rst b/site/source/docs/porting/emscripten-runtime-environment.rst similarity index 99% rename from site/source/docs/porting/Emscripten-browser-environment.rst rename to site/source/docs/porting/emscripten-runtime-environment.rst index 33bfce263034e..39e06eefd8e92 100644 --- a/site/source/docs/porting/Emscripten-browser-environment.rst +++ b/site/source/docs/porting/emscripten-runtime-environment.rst @@ -1,5 +1,3 @@ -.. _Emscripten-browser-environment: - .. _emscripten-runtime-environment: ============================================ diff --git a/site/source/docs/porting/guidelines/api_limitations.rst b/site/source/docs/porting/guidelines/api_limitations.rst index e727046e4da01..544e010f8b4ef 100644 --- a/site/source/docs/porting/guidelines/api_limitations.rst +++ b/site/source/docs/porting/guidelines/api_limitations.rst @@ -16,7 +16,7 @@ File Systems Emscripten supports *libc* file system functions and C/C++ code can be written in the normal way. -Code run in a :ref:`browser environment ` is sandboxed, and does not have direct access to the local file system. Instead, Emscripten creates a virtual file system that may be preloaded with data or linked to URLs for lazy loading. This affects when synchronous file system functions can be called and how a project is compiled. See the :ref:`Filesystem-Guide` for more information. +Code run in a :ref:`browser environment ` is sandboxed, and does not have direct access to the local file system. Instead, Emscripten creates a virtual file system that may be preloaded with data or linked to URLs for lazy loading. This affects when synchronous file system functions can be called and how a project is compiled. See the :ref:`Filesystem-Guide` for more information. Application Main Loop @@ -24,7 +24,7 @@ Application Main Loop The browser event model uses *co-operative multitasking* — each event has a "turn" to run, and must then return control to the browser event loop so that other events can be processed. A common cause of HTML pages hanging is JavaScript that does not complete and return control to the browser. -This can affect how an application using an infinite main loop is written. See :ref:`Emscripten-Browser-Environment` for more information. +This can affect how an application using an infinite main loop is written. See :ref:`emscripten-runtime-environment` for more information. Other APIs ========== diff --git a/site/source/docs/porting/index.rst b/site/source/docs/porting/index.rst index 8736394e56b79..cdbc326fbb6ea 100644 --- a/site/source/docs/porting/index.rst +++ b/site/source/docs/porting/index.rst @@ -10,7 +10,7 @@ The topics in this section cover the main integration points that you need to co :maxdepth: 1 guidelines/index - Emscripten-browser-environment + emscripten-runtime-environment connecting_cpp_and_javascript/index files/index multimedia_and_graphics/index From df2e367618790c2d2b7f638515359598efc1f5a1 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 12:16:20 +1000 Subject: [PATCH 23/37] Integrated review comments for Module and File System API --- .../docs/api_reference/Filesystem-API.rst | 89 ++++++++++--------- .../docs/api_reference/emscripten.h.rst | 6 +- site/source/docs/api_reference/module.rst | 33 ++++--- 3 files changed, 63 insertions(+), 65 deletions(-) diff --git a/site/source/docs/api_reference/Filesystem-API.rst b/site/source/docs/api_reference/Filesystem-API.rst index d19f53c387575..58e5b724760d0 100644 --- a/site/source/docs/api_reference/Filesystem-API.rst +++ b/site/source/docs/api_reference/Filesystem-API.rst @@ -1,12 +1,12 @@ .. _Filesystem-API: -===================================== -File System API (under-construction) -===================================== +=============== +File System API +=============== File operations in Emscripten are provided by the `FS `_ library. It is used internally for all of Emscripten's **libc** and **libcxx** file I/O. -.. note:: The API is *inspired* by the Linux/POSIX `File System API `_, and the APIs present a very similar interface. +.. note:: The API is *inspired* by the Linux/POSIX `File System API `_, with each presenting a very similar interface. The underlying behaviour is also similar, except where differences between the native and browser environments make this unreasonable. For example, user and group permissions are defined but ignored in :js:func:`FS.open`. @@ -29,23 +29,23 @@ However, due to JavaScript's event-driven nature, most *persistent* storage opti .. _filesystem-api-filesystems: File systems -=============== +============ .. _filesystem-api-memfs: MEMFS ----- -This is the default file system mounted at ``/`` when the runtime is initialized. All files exist strictly in-memory, and any data written to it is lost when the page is reloaded. +This is the default file system mounted at ``/`` when the runtime is initialized. All files exist strictly in-memory, and any data written to them is lost when the page is reloaded. .. _filesystem-api-nodefs: NODEFS ------ -.. note:: This file system is only for use when running inside of :term:`node.js`. +.. note:: This file system is only for use when running inside :term:`node.js`. -This file system lets a program in *node* directly access files on the local file system, as if the program were running normally. It uses node's synchronous FS API to immediately persist any data written to the Emscripten file system to your local disk. +This file system lets a program in *node* directly access files on the local file system, as if the program were running normally. It uses node's synchronous `FS API `_ to immediately persist any data written to the Emscripten file system to your local disk. See `this test `_ for an example. @@ -55,11 +55,11 @@ See `this test `: ``MEMFS``, ``NODEFS``, or ``IDBFS``. :param object opts: A generic settings object used by the underlying file system. - ``NODFES`` uses the `root` parameter to map the Emscripten directory to physical directory. For example, to mount the current folder as a NODEFS instance: + ``NODFES`` uses the `root` parameter to map the Emscripten directory to the physical directory. For example, to mount the current folder as a NODEFS instance: :: @@ -146,7 +146,7 @@ File system API Responsible for iterating and synchronizing all mounted file systems in an asynchronous fashion. - .. note:: Currently, only the :ref:`filesystem-api-idbfs` file system implements the interfaces needed by for synchronisation. All other file systems are completely synchronous and don't require synchronization. + .. note:: Currently, only the :ref:`filesystem-api-idbfs` file system implements the interfaces needed for synchronization. All other file systems are completely synchronous and don't require synchronization. The ``populate`` flag is used to control the intended direction of the underlying synchronization between Emscripten`s internal data, and the file system's persistent data. @@ -286,14 +286,14 @@ File system API file - :param string path: Path of the target file. + :param string path: Path to the target file. :returns: The string value stored in the symbolic link at ``path``. .. js:function:: FS.stat(path) - Gets a JavaScript object of stats for the node at ``path``. For example: + Gets a JavaScript object containing statistics about the node at ``path``. For example: .. code:: c @@ -328,14 +328,14 @@ File system API blocks: 1 } - :param string path: Path of the target file. + :param string path: Path to the target file. .. js:function:: FS.lstat(path) Identical to :js:func:`FS.stat`, However, if ``path`` is a symbolic link then the returned stats will be for the link itself, not the file that it links to. - :param string path: Path of the target file. + :param string path: Path to the target file. .. js:function:: FS.chmod(path, mode) @@ -351,7 +351,7 @@ File system API FS.writeFile('forbidden', 'can\'t touch this'); FS.chmod('forbidden', 0000); - :param string path: Path of the target file. + :param string path: Path to the target file. :param int mode: The new :ref:`file permissions ` for ``path``, `in octal numeric notation `_. @@ -360,7 +360,7 @@ File system API Identical to :js:func:`FS.chmod`. However, if ``path`` is a symbolic link then the mode will be set on the link itself, not the file that it links to. - :param string path: Path of the target file. + :param string path: Path to the target file. :param int mode: The new :ref:`file permissions ` for ``path``, `in octal numeric notation `_. @@ -379,7 +379,7 @@ File system API .. note:: |note-completeness| - :param string path: Path of the target file. + :param string path: Path to the target file. :param int uid: The id of the user to take ownership of the file. :param int gid: The id of the group to take ownership of the file. @@ -387,11 +387,11 @@ File system API .. js:function:: FS.lchown(path, uid, gid) - Identical to Identical to :js:func:`FS.chown`. However, if path is a symbolic link then the properties will be set on the link itself, not the file that it links to. + Identical to :js:func:`FS.chown`. However, if ``path`` is a symbolic link then the properties will be set on the link itself, not the file that it links to. .. note:: |note-completeness| - :param string path: Path of the target file. + :param string path: Path to the target file. :param int uid: The id of the user to take ownership of the file. :param int gid: The id of the group to take ownership of the file. @@ -495,9 +495,11 @@ File system API .. js:function:: FS.llseek(stream, offset, whence) - Repositions the offset of the stream ``offset`` bytes, relative to the beginning, current position, or end of the file, depending on the ``whence`` parameter. + Repositions the offset of the stream ``offset`` bytes relative to the beginning, current position, or end of the file, depending on the ``whence`` parameter. - The _llseek() function repositions the offset of the open file associated with the file descriptor fd to (offset_high<<32) | offset_low bytes relative to the beginning of the file, the current position in the file, or the end of the file, depending on whether whence is SEEK_SET, SEEK_CUR, or SEEK_END, respectively. It returns the resulting file position in the argument result. + The ``_llseek()`` function repositions the ``offset`` of the open file associated with the file descriptor ``fd`` to ``(offset_high<<32) | offset_low`` bytes relative to the beginning of the file, the current position in the file, or the end of the file, depending on whether whence is ``SEEK_SET``, ``SEEK_CUR``, or ``SEEK_END``, respectively. It returns the resulting file position in the argument result. + + .. todo:: **HamishW** Above sentence does not make sense. Have requested feedback. :param object stream: The stream for which the offset is to be repositioned. :param int offset: The offset (in bytes) relative to ``whence``. @@ -549,13 +551,13 @@ File system API .. js:function:: FS.readFile(path, opts) - Reads the entire file at ``path`` and returns it as a ``string`` (encoding is 'utf8'), or as a new ``Uint8Array`` buffer (encoding is 'binary'). + Reads the entire file at ``path`` and returns it as a ``string`` (encoding is ``utf8``), or as a new ``Uint8Array`` buffer (encoding is ``binary``). :param string path: The file to read. :param object opts: - **encoding** (*string*) - Defines the encoding used to return the file contents: 'binary' | 'utf8' . The default is 'binary' + Defines the encoding used to return the file contents: ``binary`` | ``utf8`` . The default is ``binary`` - **flags** (*string*) Read flags, as defined in :js:func:`FS.open`. The default is 'r'. @@ -567,19 +569,19 @@ File system API Writes the entire contents of ``data`` to the file at ``path``. - The value of ``opts`` determines whether ``data`` is treated either as a string (``encoding`` = 'utf8'), or as an ``ArrayBufferView`` (``encoding`` = 'binary'). For example: + The value of ``opts`` determines whether ``data`` is treated either as a string (``encoding`` = ``utf8``), or as an ``ArrayBufferView`` (``encoding`` = ``binary``). For example: .. code:: javascript FS.writeFile('file', 'foobar'); - var contents = FS.readFile('file', { encoding: 'utf8' }); + var contents = FS.readFile('file', { encoding: ``utf8`` }); :param string path: The file to which to write ``data``. :param ArrayBufferView data: The data to write. :param object opts: - **encoding** (*string*) - 'binary' | 'utf8' . The default is 'utf8' + ``binary`` | ``utf8``. The default is ``utf8`` - **flags** (*string*) Write flags, as defined in :js:func:`FS.open`. The default is 'w'. @@ -589,7 +591,7 @@ File system API Creates a file that will be loaded lazily on first access from a given URL or local file system path, and returns a reference to it. - .. warning:: Firefox and Chrome have recently disabled synchronous binary XHRs, which means this cannot work for JavaScript in regular HTML pages (but it works within WebWorkers). + .. warning:: Firefox and Chrome have recently disabled synchronous binary XHRs, which means this cannot work for JavaScript in regular HTML pages (but it works within Web Workers). Example @@ -611,12 +613,12 @@ File system API .. js:function:: FS.createPreloadedFile(parent, name, url, canRead, canWrite) - Preloads a file asynchronously. You should call this in ``preRun``, and then ``run()`` will be delayed until all preloaded files are ready. This is how ``--preload-file`` works in *emcc*. + Preloads a file asynchronously. You should call this in ``preRun``, ``run()`` will be delayed until all preloaded files are ready. This is how ``--preload-file`` works in *emcc*. :param parent: The parent folder, either as a path (e.g. `'/usr/lib'`) or an object previously returned from a `FS.createFolder()` or `FS.createPath()` call. :type parent: string/object :param string name: The name of the new file. - :param string url: In the browser, this is the URL whose contents will be returned when this file is accessed. In a command line engine, this will be the local (real) file system path from where the contents will be loaded. Note that writes to this file are virtual. + :param string url: In the browser, this is the URL whose contents will be returned when the file is accessed. In a command line engine, this will be the local (real) file system path the contents will be loaded from. Note that writes to this file are virtual. :param bool canRead: Whether the file should have read permissions set from the program's point of view. :param bool canWrite: Whether the file should have write permissions set from the program's point of view. @@ -696,9 +698,9 @@ Paths .. js:function:: FS.lookupPath(path, opts) - Lookups up the incoming path and returns an object containing both the resolved path and node. + Looks up the incoming path and returns an object containing both the resolved path and node. - The ``opts`` allow you to specify whether the object or it's parent component, and whether a symlink or the item it points to are returned. For example: :: + The options (``opts``) allow you to specify whether the object, it’s parent component, a symlink, or the item the symlink points to are returned. For example: :: var lookup = FS.lookupPath(path, { parent: true }); @@ -706,13 +708,13 @@ Paths :param object opts: Options for the path: - **parent** (*bool*) - If true, stop resolving the path once the next to the last component is reached. - For example, for the path ``/foo/bar`` with ``{ parent: true }``, would return receive back an object representing ``/foo``. The default is ``false``. + If true, stop resolving the path once the penultimate component is reached. + For example, the path ``/foo/bar`` with ``{ parent: true }`` would return return an object representing ``/foo``. The default is ``false``. - **follow** (*bool*) If true, follow the last component if it is a symlink. - For example, consider a symlink ``/foo/symlink`` that links to ``/foo/notes.txt``. if ``{ follow: true }``, an object representing ``/foo/notes.txt`` would be returned. If ``{ follow: false }`` an object representing the symlink file would be returned. The default is ``false``. + For example, consider a symlink ``/foo/symlink`` that links to ``/foo/notes.txt``. if ``{ follow: true }``, an object representing ``/foo/notes.txt`` would be returned. If ``{ follow: false }``, an object representing the symlink file would be returned. The default is ``false``. - :returns: an object with the the format: + :returns: an object with the format: .. code-block:: javascript @@ -720,7 +722,6 @@ Paths path: resolved_path, node: resolved_node } - :throws ERRNO_CODES.ELOOP: Lookup caught in a loop (recursive lookup is too deep or there are too many consecutive symlinks). diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index 294c03b9feb31..381d3b7b52190 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -151,7 +151,7 @@ Functions Asynchronously loads a script from a URL. - This integrates with the run dependencies system, so your script can call ``addRunDependency`` multiple times, prepare various asynchronous tasks, and call ``removeRunDependency`` on them; when all are complete (or there were no run dependencies to begin with), ``onload`` is called. An example use for this is to load an asset module, that is, the output of the file packager. + This integrates with the run dependencies system, so your script can call ``addRunDependency`` multiple times, prepare various asynchronous tasks, and call ``removeRunDependency`` on them; when all are complete (or if there were no run dependencies to begin with), ``onload`` is called. An example use for this is to load an asset module, that is, the output of the file packager. :param script: The script to evaluate. :type script: const char* @@ -177,9 +177,9 @@ Functions If the main loop function needs to receive user-defined data, use :c:func:`emscripten_set_main_loop_arg` instead. - The JavaScript environment will call that function at a specified number of frames per second. Setting 0 or a negative value as the ``fps`` will instead use the browser’s ``requestAnimationFrame`` mechanism to call the main loop function. This is **HIGHLY** recommended if you are doing rendering, as the browser’s ``requestAnimationFrame`` will make sure you render at a proper smooth rate that lines up with the the browser and monitor in a proper way. (If you do not render at all in your application, then you should pick a specific frame rate that makes sense for your code.) + The JavaScript environment will call that function at a specified number of frames per second. Setting 0 or a negative value as the ``fps`` will instead use the browser’s ``requestAnimationFrame`` mechanism to call the main loop function. This is **HIGHLY** recommended if you are doing rendering, as the browser’s ``requestAnimationFrame`` will make sure you render at a proper smooth rate that lines up properly with the the browser and monitor. If you do not render at all in your application, then you should pick a specific frame rate that makes sense for your code. - If ``simulate_infinite_loop`` is true, the function will throw an exception in order to stop execution of the caller. This will lead to the main loop being entered instead of code after the call to :c:func:`emscripten_set_main_loop` being run, which is the closest we can get to simulating an infinite loop (we do something similar in ``glutMainLoop`` in GLUT). If this parameter is ``false``, then the behavior is the same as it was before this parameter was added to the API, which is that execution continues normally. Note that in both cases we do not run global destructors, ``atexit``, etc., since we know the main loop will still be running, but if we do not simulate an infinite loop then the stack will be unwound. That means that if ``simulate_infinite_loop`` is ``false``, and you created an object on the stack, it will be cleaned up before the main loop is called for the first time. + If ``simulate_infinite_loop`` is true, the function will throw an exception in order to stop execution of the caller. This will lead to the main loop being entered instead of code after the call to :c:func:`emscripten_set_main_loop` being run, which is the closest we can get to simulating an infinite loop (we do something similar in `glutMainLoop `_ in `GLUT `_). If this parameter is ``false``, then the behavior is the same as it was before this parameter was added to the API, which is that execution continues normally. Note that in both cases we do not run global destructors, ``atexit``, etc., since we know the main loop will still be running, but if we do not simulate an infinite loop then the stack will be unwound. That means that if ``simulate_infinite_loop`` is ``false``, and you created an object on the stack, it will be cleaned up before the main loop is called for the first time. .. tip:: There can be only *one* main loop function at a time. To change the main loop function, first :c:func:`cancel ` the current loop, and then call this function to set another. diff --git a/site/source/docs/api_reference/module.rst b/site/source/docs/api_reference/module.rst index 9b82084cbb974..c63063d5dfc13 100644 --- a/site/source/docs/api_reference/module.rst +++ b/site/source/docs/api_reference/module.rst @@ -1,14 +1,14 @@ .. _module: -==================================== -Module object (ready-for-review) -==================================== +============= +Module object +============= -``Module`` is a global JavaScript object, with attributes that Emscripten-generated code calls at various points in its execution. +``Module`` is a global JavaScript object with attributes that Emscripten-generated code calls at various points in its execution. Developers can provide an implementation of ``Module`` to control the execution of code. For example, to define how notification messages from Emscripten are displayed, developers implement the :js:attr:`Module.print` attribute. -.. note:: ``Module`` is also used to provide access functions (see :js:func:`ccall`) in a way that avoids issues with function name minification at higher optimisation levels. These functions are documented as part of their own APIs. +.. note:: ``Module`` is also used to provide access to all Emscripten API functions (for example :js:func:`ccall`) in a way that avoids issues with function name minification at higher optimisation levels. These functions are documented as part of their own APIs. .. contents:: Table of Contents :local: @@ -17,10 +17,10 @@ Developers can provide an implementation of ``Module`` to control the execution .. _module-creating: -Creating Module -================ +Creating the Module object +========================== -Use :ref:`emcc's ` ``--pre-js`` option to add JavaScript code that defines (or extends) the ``Module`` object with the behaviour you need. +Use emcc's :ref:`pre-js option` to add JavaScript code that defines (or extends) the ``Module`` object with the behaviour you need. When generating only JavaScript (as opposed to HTML), no ``Module`` object is created by default, and the behaviour is entirely defined by the developer. For example, creating a ``Module`` object with the following code will cause all notifications from the program to be calls to ``alert()``. @@ -31,9 +31,9 @@ When generating only JavaScript (as opposed to HTML), no ``Module`` object is cr 'printErr': function(text) { alert('stderr: ' + text) } }; -.. important:: If you run closure compiler on your code (which is optional, and can be done by ``--closure 1``), you will need quotation marks around the properties of ``Module`` as in the example above (and you need to run closure on the compiled code together with the declaration of ``Module``, which is done automatically for a ``-pre-js`` file). +.. important:: If you run the :term:`Closure Compiler` on your code (which is optional, and can be done by ``--closure 1``), you will need quotation marks around the properties of ``Module`` as in the example above. In addition, you need to run closure on the compiled code together with the declaration of ``Module`` — this is done automatically for a ``-pre-js`` file. -When generating HTML, Emscripten creates a ``Module`` object with default methods (see `src/shell.html `_). In this case you should again use ``--pre-js``, but this time to add properties to the existing ``Module`` object, for example +When generating HTML, Emscripten creates a ``Module`` object with default methods (see `src/shell.html `_). In this case you should again use ``--pre-js``, but this time you add properties to the *existing* ``Module`` object, for example :: @@ -57,30 +57,27 @@ The following ``Module`` attributes affect code execution. .. js:attribute:: Module.arguments - The commandline arguments. The value of ``arguments`` is what is returned if compiled code checks ``argc`` and ``argv``. + The commandline arguments. The value of ``arguments`` contains the values returned if compiled code checks ``argc`` and ``argv``. .. js:attribute:: Module.preInit - A function (or array of functions) that must be called before global initializers run, but after basic initialization of the JavaScript runtime. This is typically used for :ref:`File System operations ` and is called before C++ initializers have been run. + A function (or array of functions) that must be called before global initializers run, but after basic initialization of the JavaScript runtime. This is typically used for :ref:`File System operations `. .. js:attribute:: Module.preRun - An array of functions to call right before calling ``run()``, but after defining and setting up the environment, including global initializers. This is useful, for example, to set up directories and files using the :ref:`Filesystem-API` (since that needs the FileSystem API to be defined and loaded, but also needs to be done before the program starts to run). + An array of functions to call right before calling ``run()``, but after defining and setting up the environment, including global initializers. This is useful, for example, to set up directories and files using the :ref:`Filesystem-API` — as this needs to happen after the FileSystem API has been loaded, but before the program starts to run. .. note:: If code needs to affect global initializers, it should instead be run using :js:attr:`preInit`. .. js:attribute:: Module.noInitialRun - If set to ``true``, ``main()`` will not be automatically called (you can do so yourself later). The program will still call global initializers, set up memory initialization, and so forth. + If ``noInitialRun`` is set to ``true``, ``main()`` will not be automatically called (you can do so yourself later). The program will still call global initializers, set up memory initialization, and so forth. .. js:attribute:: Module.noExitRuntime - If set to ``true``, the runtime is not shut down after ``run`` completes. Shutting down the runtime calls shutdown callbacks, for example ``atexit`` calls. If you want to be able to continue to use the code after ``run()`` finishes, it is necessary to set this. This is automatically set for you if you use an API command that implies that you want the runtime to not be shut down, for example ``emscripten_set_main_loop``. - - - + If ``noExitRuntime`` is set to ``true``, the runtime is not shut down after ``run`` completes. Shutting down the runtime calls shutdown callbacks, for example ``atexit`` calls. If you want to continue using the code after ``run()`` finishes, it is necessary to set this. This is automatically set for you if you use an API command that implies that you want the runtime to not be shut down, for example ``emscripten_set_main_loop``. From 923938ecedb54210f92be224e8cf8fc4f767339a Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 12:17:13 +1000 Subject: [PATCH 24/37] Make side backgrounds light greyish rather than bright red. --- .../emscripten_sphinx_rtd_theme/static/css/theme.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css b/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css index 394f0a8760ad2..90d729cde171f 100644 --- a/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css +++ b/site/source/_themes/emscripten_sphinx_rtd_theme/static/css/theme.css @@ -168,9 +168,12 @@ code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rs .wy-body-for-nav{ /* background:left repeat-y #F1F0F0; */ - background:left repeat-y rgb(97, 6, 6); - /* background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC); */ + /* + background:left repeat-y rgb(97, 6, 6); background-size:300px 1px + */ /* This is deep red colour - removed */ + /* background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC); */ + } .wy-grid-for-nav { From 082b447acf850fe2f808b2043de66484c99e7bf8 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 14:26:48 +1000 Subject: [PATCH 25/37] Minor updates to all articles remaining wiki-import articles to fix obvious errors --- .../docs/compiling/Building-Projects.rst | 273 ++++-------------- .../Running-html-files-with-emrun.rst | 20 +- .../docs/contributing/developers_guide.rst | 79 ++--- .../about_emscripten.rst | 2 +- .../docs/optimizing/Optimizing-Code.rst | 199 +++---------- .../optimizing/Optimizing-the-source-code.rst | 25 +- site/source/docs/porting/Debugging.rst | 196 +++---------- ...s-Virtual-XHR-Backed-File-System-Usage.rst | 6 +- .../porting/files/file_systems_overview.rst | 1 - .../docs/porting/files/packaging_files.rst | 6 +- .../guidelines/portability_guidelines.rst | 2 +- .../EGL-Support-in-Emscripten.rst | 10 +- .../OpenGL-support.rst | 11 +- 13 files changed, 204 insertions(+), 626 deletions(-) diff --git a/site/source/docs/compiling/Building-Projects.rst b/site/source/docs/compiling/Building-Projects.rst index f3ae3317a6dc4..93abbc439bba6 100644 --- a/site/source/docs/compiling/Building-Projects.rst +++ b/site/source/docs/compiling/Building-Projects.rst @@ -3,17 +3,10 @@ =============================== Building Projects (wiki-import) =============================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -Building Projects -================= +The :ref:`Tutorial` shows how :ref:`emcc `, the drop-in replacement for *gcc*, can be used to compile single files very easily into JavaScript. -The :ref:`Tutorial` shows how **emcc**, the drop-in replacement for gcc, -can be used to compile single files very easily into JavaScript. -Building large projects with Emscripten is also very simple: You -basically use **emcc** instead of gcc in your makefiles. This can -usually be done by setting CC to emcc, or with a flag to configure, but -it can be even easier than that: For example, if you normally build with +Building large projects with Emscripten is also very simple: You basically use **emcc** instead of *gcc* in your makefiles. This can usually be done by setting CC to *emcc*, or with a flag to configure, but it can be even easier than that: For example, if you normally build with :: @@ -28,64 +21,21 @@ then the process with Emscripten looks like emmake make emcc [-Ox] project.bc -o project.js -where ``project.bc`` is the linked bitcode that was generated by make, -so change that to the name generated by the project (note that the -output bitcode might have suffix ``.o`` or ``.so`` depending on the -details of the build system). - -- The first change is to run **emconfigure**, with the normal configure - command as an argument. emconfigure runs configure but tells it to - use emcc instead of gcc, and a few other useful things (for details, - see the docs inside ``emcc``). Similarly, **emmake** does some - helpful environment var settings and so forth (typically if you use - configure or cmake or such, you don't need emmake - all the info is - in the configure-generated files - but if not, emmake will set - default env vars for the compiler to point to emscripten and so - forth). -- The second change is, once the project is built, to add a command to - convert the compiled project into JavaScript: emcc is run on the - compiled project bitcode, and told to generate JavaScript output (we - will see later down why [-Ox] appears there). This additional command - is necessary for two main reasons: first, because emcc, when called - from the makefile, will not automatically generate JavaScript during - linking (if it did, there would be a lot of JavaScript generated in - intermediary steps in many projects, which is unnecessary and - inefficient to link and so forth), and second, because we have - various options and optimizations that must apply to the entire - program being compiled (we cannot compile file A with options X and - file B with options Y and link them into one program - they can - literally have different memory structures, for example, different - typed array modes etc., so therefore all these options and - optimizations are done on the final conversion from bitcode to - JavaScript). So, when called from the makefile emcc will generate - bitcode. A single line, as shown above, then converts the bitcode - into JavaScript. -- In other words, a conventional native code build system will generate - native code in object files as an intermediate form, while building - with Emscripten uses LLVM bitcode as an intermediate form. -- In general you don't need to care about this, except for needing one - extra line for the last transformation to JavaScript. However, one - potentially confusing situation can occur with optimization, see the - subsection below. -- Note that the output of the build system can be a static library - (.a), shared library (.so) or just object files (.o or .bc). In all - of these cases using emcc in the build system will cause these files - to contain LLVM bitcode, even though the suffix looks the same as if - gcc ran. emcc can then be used to compile the .a, .so, .o or .bc file - into JavaScript. +where ``project.bc`` is the linked bitcode that was generated by make, so change that to the name generated by the project (note that the output bitcode might have suffix ``.o`` or ``.so`` depending on the details of the build system). + +- The first change is to run **emconfigure**, with the normal configure command as an argument. *emconfigure* runs configure but tells it to use *emcc* instead of *gcc*, and a few other useful things (for details, see the docs inside *emcc*). Similarly, **emmake** does some helpful environment var settings and so forth (typically if you use configure or *cmake* or such, you don't need emmake - all the info is in the configure-generated files - but if not, *emmake* will set default env vars for the compiler to point to Emscripten and so forth). +- The second change is, once the project is built, to add a command to convert the compiled project into JavaScript: *emcc* is run on the compiled project bitcode, and told to generate JavaScript output (we will see later down why [-Ox] appears there). This additional command is necessary for two main reasons: first, because *emcc*, when called from the makefile, will not automatically generate JavaScript during linking (if it did, there would be a lot of JavaScript generated in intermediary steps in many projects, which is unnecessary and inefficient to link and so forth), and second, because we have various options and optimizations that must apply to the entire program being compiled (we cannot compile file A with options X and file B with options Y and link them into one program — they can literally have different memory structures, for example, different typed array modes etc., so therefore all these options and optimizations are done on the final conversion from bitcode to JavaScript). So, when called from the makefile *emcc* will generate bitcode. A single line, as shown above, then converts the bitcode into JavaScript. +- In other words, a conventional native code build system will generate native code in object files as an intermediate form, while building with Emscripten uses LLVM bitcode as an intermediate form. +- In general you don't need to care about this, except for needing one extra line for the last transformation to JavaScript. However, one potentially confusing situation can occur with optimization, see the subsection below. +- Note that the output of the build system can be a static library (.a), shared library (.so) or just object files (.o or .bc). In all of these cases using *emcc* in the build system will cause these files to contain LLVM bitcode, even though the suffix looks the same as if *gcc* ran. *emcc* can then be used to compile the .a, .so, .o or .bc file into JavaScript. Optimizations -~~~~~~~~~~~~~ +============= + +As mentioned above, the intermediate format is LLVM bitcode - object files contain that and not JavaScript. We do optimize like a normal compiler does, however: Each source file is optimized by LLVM as it is compiled into an object file. And, we perform additional optimizations when converting object files into JavaScript (optimizations that make sense only for JavaScript). -As mentioned above, the intermediate format is LLVM bitcode - object -files contain that and not JavaScript. We do optimize like a normal -compiler does, however: Each source file is optimized by LLVM as it is -compiled into an object file. And, we perform additional optimizations -when converting object files into JavaScript (optimizations that make -sense only for JavaScript). +As a consequence, **you should provide the same optimization flags both when compiling source to object and object to JavaScript (or HTML)**. -As a consequence, **you should provide the same optimization flags both -when compiling source to object and object to JavaScript (or HTML)**. For example :: @@ -95,8 +45,7 @@ For example emcc -O2 b.cpp -o b.bc emcc a.bc b.bc -o project.js -will not generate the best results, because no JS-level optimizations -were performed. Likewise, +will not generate the best results, because no JS-level optimizations were performed. Likewise, :: @@ -105,8 +54,7 @@ were performed. Likewise, emcc b.cpp -o b.bc emcc -O2 a.bc b.bc -o project.js -will also not be optimal, because no LLVM optimizations are done. The -proper way would be to do +will also not be optimal, because no LLVM optimizations are done. The proper way would be to do :: @@ -115,50 +63,26 @@ proper way would be to do emcc -O2 b.cpp -o b.bc emcc -O2 a.bc b.bc -o project.js -By passing the same optimization flags during all stages, code will be -properly optimized. Note that this goes not just for ``-O2`` and ``-O1`` -but also for things like ``-s OPTION=VALUE`` which can affect -optimization. Again, just pass the same flags during all compilation -stages. +By passing the same optimization flags during all stages, code will be properly optimized. Note that this goes not just for ``-O2`` and ``-O1`` but also for things like ``-s OPTION=VALUE`` which can affect optimization. Again, just pass the same flags during all compilation stages. -- You can control whether LLVM optimizations are run using - ``--llvm-opts N`` where N is in 0-3. Sending ``-O2 --llvm-opts 0`` to - emcc during all compilation stages will disable LLVM optimizations - but utilize JS optimizations. This can be useful when debugging a - build failure. +- You can control whether LLVM optimizations are run using ``--llvm-opts N`` where N is in 0-3. Sending ``-O2 --llvm-opts 0`` to *emcc* during all compilation stages will disable LLVM optimizations but utilize JavaScript optimizations. This can be useful when debugging a build failure. Debug info -~~~~~~~~~~ +================== -If you want debug info, you need to compile the individual sources with -``-g``, exactly the same as with clang or gcc normally. This makes clang -and llvm emit debug info in the bitcode files. You must then tell emcc -during the bitcode to JS stage to utilize that debug info, using ``-g`` -or one of the specific ``-gN`` options (e.g. ``-g4`` for source maps -support). +If you want debug info, you need to compile the individual sources with ``-g``, exactly the same as with clang or *gcc* normally. This makes clang and llvm emit debug info in the bitcode files. You must then tell *emcc* during the bitcode to JavaScript stage to utilize that debug info, using ``-g`` or one of the specific ``-gN`` options (e.g. ``-g4`` for source maps support). Notes -~~~~~ - -- It is better to generate .so files and not .a. Archives (.a) have - some odd behaviors when linked with other files, the linker tries to - be 'clever' and discard stuff it thinks is not needed. Shared - libraries (.so) are simpler, and we do elimination of unneeded code - later anyhow, so they are recommended. This is generally a simple - change in your project's build system. -- Make sure to use bitcode-aware llvm-ar instead of ar. ar may discard - code. -- If you get multiply defined symbol errors, use ``llvm-nm`` to see - which symbols are defined in each bitcode file being linked, in the - link command where the error occurs. You may need to change how your - project links libraries (e.g. from static to dynamic) or to avoid - linking in a library more than once before the final link. +================== + +- It is better to generate .so files and not .a. Archives (.a) have some odd behaviors when linked with other files, the linker tries to be 'clever' and discard stuff it thinks is not needed. Shared libraries (.so) are simpler, and we do elimination of unneeded code later anyhow, so they are recommended. This is generally a simple change in your project's build system. +- Make sure to use bitcode-aware llvm-ar instead of ar. ar may discard code. +- If you get multiply defined symbol errors, use ``llvm-nm`` to see which symbols are defined in each bitcode file being linked, in the link command where the error occurs. You may need to change how your project links libraries (e.g. from static to dynamic) or to avoid linking in a library more than once before the final link. Manually Using emcc -------------------- +==================== -As a drop-in replacement for gcc, emcc can be used in all the normal -ways you would expect: +As a drop-in replacement for *gcc*, *emcc* can be used in all the normal ways you would expect: :: @@ -186,140 +110,65 @@ ways you would expect: emcc src1.o src2.o -o combined.o # Combine two LLVM bitcode files into another LLVM bitcode file -For more on emcc's capabilites, do ``emcc --help`` (it can also -optimize, change parameters to how Emscripten generates code, generate -HTML instead of JavaScript, etc.). +For more on *emcc*'s capabilites, do ``emcc --help`` (it can also optimize, change parameters to how Emscripten generates code, generate HTML instead of JavaScript, etc.). System Libraries ----------------- +================ -An ``sdl-config`` replacement is present in system/bin. Pointing -configure scripts to system or system/bin should get them to use SDL -properly. +An ``sdl-config`` replacement is present in system/bin. Pointing configure scripts to system or system/bin should get them to use SDL properly. Using Libraries ---------------- +================ -If your project needs a standard system library, like for example zlib -or glib, then if there is not built-in support in emscripten for it, you -will need to link it in manually. Built-in support exists for libc, -libc++ and SDL, and for those you do not even need to add ``-lSDL`` or -such - they will just work. But for other libraries, you need to build -and link them. - -- To build them, you would build them normally using emcc. Build them - into bitcode, not JavaScript - which is easier, basically just run - make using emcc as described above, and do not do anything additional - to generate JavaScript from the bitcode. -- In your main project, as mentioned earlier in this document you need - to add a command to go from bitcode to JavaScript. You should tell - that command to also link in the library you built into bitcode. For - example, if you built ``libstuff.bc``, and your final build command - was ``emcc project.bc -o final.html``, then you should write - ``emcc project.bc libstuff.bc -o final.html``. (Alternatively, you - could use llvm-link to link the library with your other bitcode, - etc.) +If your project needs a standard system library, like for example zlib or glib, then if there is not built-in support in Emscripten for it, you will need to link it in manually. Built-in support exists for libc, libc++ and SDL, and for those you do not even need to add ``-lSDL`` or such - they will just work. But for other libraries, you need to build and link them. + +- To build them, you would build them normally using *emcc*. Build them into bitcode, not JavaScript - which is easier, basically just run make using *emcc* as described above, and do not do anything additional to generate JavaScript from the bitcode. +- In your main project, as mentioned earlier in this document you need to add a command to go from bitcode to JavaScript. You should tell that command to also link in the library you built into bitcode. For example, if you built ``libstuff.bc``, and your final build command was ``emcc project.bc -o final.html``, then you should write ``emcc project.bc libstuff.bc -o final.html``. (Alternatively, you could use llvm-link to link the library with your other bitcode, etc.) Issues ------- +====== Build System Self-Execution -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Some large projects, as part of their build procedure, generate -executables and run them in order to generate input for later parts of -the build system (for example, a parser may be built and then run on a -grammar, which generates C/C++ code that implements that grammar). This -is a problem when cross-compiling, including with Emscripten, since you -cannot directly run the code you are generating. - -The simplest solution is usually to build the project twice: Once -natively, and once to JavaScript. When the JavaScript build procedure -then fails on not being able to run a generated executable, you then -copy that executable from the native build, and continue to build -normally. This works for Python, for example (for more details, see -``tests/python/readme.txt``). - -Another possible solution that makes sense in some cases is to modify -the build scripts so that they build the generated executable natively. -For example, this can be done by specifying two compilers in the build -scripts, emcc and gcc, and using gcc just for generated executables. -However, this can be more complicated than the previous solution because -you need to modify the project build scripts, and also you need to work -around cases where code is compiled and used both for the final result -and for a generated executable (so you need to make sure it is built -both natively and for JS). +---------------------------- + +Some large projects, as part of their build procedure, generate executables and run them in order to generate input for later parts of the build system (for example, a parser may be built and then run on a grammar, which generates C/C++ code that implements that grammar). This is a problem when cross-compiling, including with Emscripten, since you cannot directly run the code you are generating. + +The simplest solution is usually to build the project twice: Once natively, and once to JavaScript. When the JavaScript build procedure then fails on not being able to run a generated executable, you then copy that executable from the native build, and continue to build normally. This works for Python, for example (for more details, see ``tests/python/readme.txt``). + +Another possible solution that makes sense in some cases is to modify the build scripts so that they build the generated executable natively. For example, this can be done by specifying two compilers in the build scripts, *emcc* and *gcc*, and using *gcc* just for generated executables. However, this can be more complicated than the previous solution because you need to modify the project build scripts, and also you need to work around cases where code is compiled and used both for the final result and for a generated executable (so you need to make sure it is built both natively and for JavaScript). Dynamic Linking -~~~~~~~~~~~~~~~ +--------------- -Emscripten's goal is to generate the fastest and smallest possible code, -and for that reason it focuses on generating a single JavaScript file -for an entire project. It is possible to link files at runtime (see -:ref:`Linking`), but it isn't recommended. +Emscripten's goal is to generate the fastest and smallest possible code, and for that reason it focuses on generating a single JavaScript file for an entire project. It is possible to link files at runtime (see :ref:`Linking`), but it isn't recommended. Linking in libraries -~~~~~~~~~~~~~~~~~~~~ - -Since emscripten does not have true dynamic linking - we won't link in -code from some system location as we load an app - we approximate it to -the best of our abilities. When you specify a dynamic library in a call -to ``emcc``, then it will be linked in as a static library, when you are -building the final "executable", that is, JS or HTML file. However, if -you are linking together to bitcode, then dynamic libraries are -**ignored**. The reason is you could link them twice to two libraries, -then link those together. This works natively since actual linking will -occur during startup, but for us, we use static linking, so had we -linked them in, we would get an error on duplicate symbols. - -The solution is to specify dynamic libraries once, in the command that -builds to JS or HTML. It's ok if you specify them elsewhere as well, but -they will be ignored; the important thing is to not forget them during -the final build stage. +-------------------- + +Since Emscripten does not have true dynamic linking - we won't link in code from some system location as we load an app - we approximate it to the best of our abilities. When you specify a dynamic library in a call to *emcc*, then it will be linked in as a static library, when you are building the final "executable", that is, JavaScript or HTML file. However, if you are linking together to bitcode, then dynamic libraries are **ignored**. The reason is you could link them twice to two libraries, then link those together. This works natively since actual linking will occur during startup, but for us, we use static linking, so had we linked them in, we would get an error on duplicate symbols. + +The solution is to specify dynamic libraries once, in the command that builds to JavaScript or HTML. It's ok if you specify them elsewhere as well, but they will be ignored; the important thing is to not forget them during the final build stage. Configure -~~~~~~~~~ - -If your project uses ``configure``, ``cmake`` or some other portable -configuration method, it may do a lot of checks during the configure -phase. ``emcc`` tries to get those to pass as much as it can, but in -general it may not succeed. If you encounter such a case, you may need -to disable checks in configure. Often the checks are just to verify that -things will work, but things will actually work even though the checks -fail. - -If configure does checks that help determine important paths etc. for -later in the build system, you may need to manually add those paths -later and so forth. - -Note that in general something like ``configure`` is not a good match -for a cross-compiler like Emscripten. ``configure`` works very hard to -get code to build natively for whatever local setup you have. With a -cross-compiler, you are *ignoring* the native build system and the local -system headers, and instead targeting a single standard target, so just -writing out the values relevant for that target makes sense. +---------- + +If your project uses *configure*, *cmake* or some other portable configuration method, it may do a lot of checks during the configure phase. *emcc* tries to get those to pass as much as it can, but in general it may not succeed. If you encounter such a case, you may need to disable checks in configure. Often the checks are just to verify that things will work, but things will actually work even though the checks fail. + +If configure does checks that help determine important paths etc. for later in the build system, you may need to manually add those paths later and so forth. + +Note that in general something like ``configure`` is not a good match for a cross-compiler like Emscripten. ``configure`` works very hard to get code to build natively for whatever local setup you have. With a cross-compiler, you are *ignoring* the native build system and the local system headers, and instead targeting a single standard target, so just writing out the values relevant for that target makes sense. Alternatives to emcc --------------------- +==================== -You can in theory call clang, llvm-ld, etc. yourself. However, not using -emcc is dangerous. One reason is that emcc will use the Emscripten -bundled headers, while using Clang by itself will not, by default. This -can lead to various errors. Also, using things like llvm-ld will result -in unsafe/unportable LLVM optimizations being done by default. When you -use emcc, it automatically handles all of that for you so that things -work properly. +You can in theory call clang, llvm-ld, etc. yourself. However, not using *emcc* is dangerous. One reason is that *emcc* will use the Emscripten bundled headers, while using Clang by itself will not, by default. This can lead to various errors. Also, using things like llvm-ld will result in unsafe/unportable LLVM optimizations being done by default. When you use *emcc*, it automatically handles all of that for you so that things work properly. Examples --------- +======== -You can see how the large tests in ``tests/runner.py`` are built - the -C/C++ projects there are built using their normal build systems, using -emcc as detailed on this page. Specifically, the large tests include: -``freetype``, ``openjpeg``, ``zlib``, ``bullet`` and ``poppler``. +You can see how the large tests in ``tests/runner.py`` are built - the C/C++ projects there are built using their normal build systems, using *emcc* as detailed on this page. Specifically, the large tests include: ``freetype``, ``openjpeg``, ``zlib``, ``bullet`` and ``poppler``. -Also worth looking at the build scripts in the following projects, -although several are not yet updated to use the new emcc tool: +Also worth looking at the build scripts in the following projects, although several are not yet updated to use the new *emcc* tool: - https://github.com/kripken/ammo.js/blob/master/make.py - https://github.com/mbebenita/Broadway/blob/master/Avc/make.py diff --git a/site/source/docs/compiling/Running-html-files-with-emrun.rst b/site/source/docs/compiling/Running-html-files-with-emrun.rst index b7a910956a608..1fcb4269a8a0c 100644 --- a/site/source/docs/compiling/Running-html-files-with-emrun.rst +++ b/site/source/docs/compiling/Running-html-files-with-emrun.rst @@ -4,12 +4,10 @@ Running html files with emrun (wiki-import) =========================================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! - -When you target the web with emscripten via the ``-o out.html`` directive to emcc, emscripten will generate one or more outfiles with suffixes ``.html, .js, and .data``. Not all web browsers can run the .html file via a ``file://`` URL by double-clicking the html file because of default browser CORS rules (in Chrome, Opera and IE), but you need to deploy the files to a web server first. To solve this, you can use the ``emrun`` command line tool to run your page in a locally launched web server. +When you target the web with Emscripten via the ``-o out.html`` directive to emcc, Emscripten will generate one or more outfiles with suffixes ``.html, .js, and .data``. Not all web browsers can run the .html file via a ``file://`` URL by double-clicking the html file because of default browser CORS rules (in Chrome, Opera and IE), but you need to deploy the files to a web server first. To solve this, you can use the ``emrun`` command line tool to run your page in a locally launched web server. Features --------- +======== ``emrun`` enables the following uses: @@ -22,18 +20,18 @@ Features To summarize, ``emrun`` is the tool to use for all kinds of command-line automation needs, for example when integrating your unit tests to run in an Emscripten environment in your project build farm. Quick how-to ------------- +============ Using ``emrun`` is simple. Here is how: -1. Rebuild your emscripten application and add the ``--emrun`` linker flag. This flag injects a piece of code in the generated ``Module`` that is needed to enable the ``stdout``, ``stderr`` and ``exit()`` capture to work. If you skip this step, you can still run any .html file with ``emrun``, but then the capture will just not work. +1. Rebuild your Emscripten application and add the ``--emrun`` linker flag. This flag injects a piece of code in the generated ``Module`` that is needed to enable the ``stdout``, ``stderr`` and ``exit()`` capture to work. If you skip this step, you can still run any .html file with ``emrun``, but then the capture will just not work. 2. Open a terminal, navigate to the build output directory, and run ``emrun page.html``. This will spawn a new web server to host the page and launch your default system browser to visit that page. ``emrun`` will block until the page calls ``exit(returncode);``, after which it will quit back to shell with the provided process exit code. That's all! Choosing the browser to run ---------------------------- +=========================== ``emrun`` provides the ``--browser `` command line option that allows specifying which browser to run. If that flag is not specified, the default system browser is launched. If the parameter to ``--browser`` points to an existing file, then that file is spawned as the browser process to run. Additionally, to simplify setup, one can pass predefined alias names of known browsers to ``--browser`` to launch a specific browser. To enumerate the list of detected browser aliases on your system, run the ``--list_browsers`` command, like follows: @@ -62,7 +60,7 @@ Then for example to run Firefox Nightly, you would launch ``emrun --browser fire If you just want to launch a web server, similar to how ``python -m SimpleHTTPServer`` operates, you can pass the ``--no_browser`` command line flag, in which case ``emrun`` will not spawn a browser at all, but simply runs a web server. Controlling web server operation --------------------------------- +================================ ``emrun`` spawns its own web server to host the target html file. You should note the following security implications: @@ -81,7 +79,7 @@ The following command line flags control how ``emrun`` spawns the web server: - ``--timeout_returncode ``: Specifies the process return code that ``emrun`` quits with if a page run timeout occurs. By default ``99999``. Controlling log output ----------------------- +====================== The following command line flags affect messaging to logs: @@ -94,7 +92,7 @@ The following command line flags affect messaging to logs: - ``--no_emrun_detect``: Hides the friendly reminder message that warns if target .html file is detected to not have been built with ``--emrun``. Cleaning up after the run -------------------------- +========================= Especially when automating operation for build servers, it is important to be able to clean up properly after each run. The following command line flags enable this: @@ -104,7 +102,7 @@ Especially when automating operation for build servers, it is important to be ab It is important to understand that these operations can cause data loss, since these actions cause processes to be forcibly terminated. Do not pass these flags when running a browser that could have multiple tabs or windows open that you do other work in, since they will all be wiped out. You were warned. Running web pages on an Android device --------------------------------------- +====================================== It is also possible to use ``emrun`` to automate web browser runs on Android. For that to work, you need diff --git a/site/source/docs/contributing/developers_guide.rst b/site/source/docs/contributing/developers_guide.rst index 83fb3ba746275..3ab9b78f9b5e3 100644 --- a/site/source/docs/contributing/developers_guide.rst +++ b/site/source/docs/contributing/developers_guide.rst @@ -3,18 +3,13 @@ =============================== Developer's Guide (wiki-import) =============================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! -This page is for people working on Emscripten itself, as opposed to -those that use Emscripten on their own projects. If you are just using -Emscripten, you probably don't need to know this stuff (but it might -help out sometime too). +This page is for people working on Emscripten itself, as opposed to those that use Emscripten on their own projects. If you are just using Emscripten, you probably don't need to know this stuff (but it might help out sometime too). Basic useful stuff ================== -Here are some example commands for the test suite, with comments -explaining what they do +Here are some example commands for the test suite, with comments explaining what they do :: @@ -40,8 +35,7 @@ Running a specific test ======================= - Check for the test name in tests/test\_core.py -- Then, run it using the test runner like this - - ``python tests/runner.py test_name`` +- Then, run it using the test runner like this — ``python tests/runner.py test_name`` Test failures ============= @@ -52,56 +46,36 @@ To debug a test failure, the following might help: EMCC_DEBUG=1 ./tests/runner.py test_hello_world -will make emcc emit debug output, and also store its temp files in -``/tmp/emscripten_temp/``. emcc-\* will contain, in order, the files it -emits. ``EMCC_DEBUG=2`` will emit even more files. Note that -``EMCC_DEBUG`` works on emcc in general, not just in the test suite. +will make emcc emit debug output, and also store its temp files in **/tmp/emscripten_temp/**. emcc-\* will contain, in order, the files it +emits. ``EMCC_DEBUG=2`` will emit even more files. Note that ``EMCC_DEBUG`` works on emcc in general, not just in the test suite. -``EM_SAVE_DIR=1`` is a test suite specific command that uses -``/tmp/emscripten_temp/`` as the test dir, so that all the files created -by the test are retained (note that the dir is not cleaned out -beforehand). +``EM_SAVE_DIR=1`` is a test suite specific command that uses **/tmp/emscripten_temp/** as the test dir, so that all the files created by the test are retained (note that the dir is not cleaned out beforehand). General compiler overview ========================= -- emcc is a python script that manages the entire compilation process. -- emcc will call clang to convert C++ to bitcode, llvm opt to optimize - it, llvm-link to link, etc. etc. -- emcc calls emscripten.py which does the LLVM IR to JS conversion - process. - - - emscripten.py is a python script that runs the core compiler, - either src/compiler.js (old compiler) or the LLVM backend (new - fastcomp). - - emscripten.py receives the core compiler output, modifies it - slightly (some regexps) and then adds some necessary code around - it, generating the basic emitted JS. This is called - emcc-2-original when running EMCC\_DEBUG=1 and saving the temp - files. - -- emcc will run tools/js\_optimizer.py to further process and optimize - the generated JS. - - - js\_optimizer.py is a python script that breaks up a JS file into - the relevant parts for optimization (the generated code, as - opposed to glue code) and calls js-optimizer.js to actually - optimize it. - - js-optimizer.js is a node script using UglifyJS which parses and - transforms JS into better JS. - -Wiki pages you should read +- emcc is a python script that manages the entire compilation process. +- emcc will call clang to convert C++ to bitcode, llvm opt to optimize it, llvm-link to link, etc. etc. +- emcc calls emscripten.py which does the LLVM IR to JavaScript conversion process. + + - emscripten.py is a python script that runs the core compiler, either src/compiler.js (old compiler) or the LLVM backend (new fastcomp). + - emscripten.py receives the core compiler output, modifies it slightly (some regexps) and then adds some necessary code around it, generating the basic emitted JavaScript. This is called emcc-2-original when running EMCC\_DEBUG=1 and saving the temp files. + +- emcc will run tools/js_optimizer.py to further process and optimize the generated JavaScript. + + - js\_optimizer.py is a python script that breaks up a JavaScript file into the relevant parts for optimization (the generated code, as opposed to glue code) and calls js-optimizer.js to actually optimize it. + - js-optimizer.js is a node script using UglifyJS which parses and transforms JavaScript into better JavaScript. + +Articles you should read ========================== -- :ref:`Debugging` -- :ref:`Building-Projects` +- :ref:`Debugging` +- :ref:`Building-Projects` Bisection ========= -As of fastcomp, version numbers should help bisect across the 3 repos we -now have. See the :ref:`LLVM-Backend` page for details on how version -numbers are used and where they are found. +As of fastcomp, version numbers should help bisect across the 3 repos we now have. See the :ref:`LLVM-Backend` page for details on how version numbers are used and where they are found. Debugging tricks ================ @@ -112,12 +86,7 @@ Debugging tricks python tools/js_optimizer.py FILENAME PASSES.. -on JS output from emscripten. For example, ``asm safeHeap`` will apply -safe heap annotations to the code; you can then manually add the -``SAFE_HEAP_LOAD`` and STORE methods from src/preamble.js, and now all -your loads and stores are instrumented into calls. +on JavaScript output from emscripten. For example, ``asm safeHeap`` will apply safe heap annotations to the code; you can then manually add the ``SAFE_HEAP_LOAD`` and STORE methods from src/preamble.js, and now all your loads and stores are instrumented into calls. -- You can make a program's execution 100% deterministic (not rely on - Math.random or Date.now or anything like that) by including the - src/deterministic.js file. +- You can make a program's execution 100% deterministic (not rely on ``Math.random`` or ``Date.now`` or anything like that) by including the src/deterministic.js file. diff --git a/site/source/docs/introducing_emscripten/about_emscripten.rst b/site/source/docs/introducing_emscripten/about_emscripten.rst index 39a5d96c72217..5464a114eacc2 100644 --- a/site/source/docs/introducing_emscripten/about_emscripten.rst +++ b/site/source/docs/introducing_emscripten/about_emscripten.rst @@ -66,6 +66,6 @@ Emscripten support for **portable** C/C++ code is fairly comprehensive. Support There are differences between the native and `browser environments `_, which mean some changes usually need to be made to the native code. That said, many applications will only need to change the way they define their main loop, and also modify their :ref:`file handling ` to adapt to the limitations of the browser/JavaScript. -There are also limitations that can make some code easier to port — read :ref:`CodeGuidelinesAndLimitations` to determine where you may need to spend more effort. +There are also limitations that can make some code easier to port — read :ref:`code-portability-guidelines` to determine where you may need to spend more effort. diff --git a/site/source/docs/optimizing/Optimizing-Code.rst b/site/source/docs/optimizing/Optimizing-Code.rst index 4f75b93ffe1ff..6f736325726e8 100644 --- a/site/source/docs/optimizing/Optimizing-Code.rst +++ b/site/source/docs/optimizing/Optimizing-Code.rst @@ -1,26 +1,17 @@ .. _Optimizing-Code: -============================================ +======================================= Optimizing Generated Code (wiki-import) -============================================ -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! +======================================= +By default Emscripten will compile code in a fairly safe way, and without all the possible optimizations. You should generally try this first, to make sure things work properly (if not, see the :ref:`Debugging` page). Afterwards, you may want to compile your code so it runs faster. This page explains how. -By default Emscripten will compile code in a fairly safe way, and -without all the possible optimizations. You should generally try this -first, to make sure things work properly (if not, see the :ref:`Debugging` -page). Afterwards, you may want to compile your code so it runs faster. -This page explains how. - -Note: You can also optimize the source code you are compiling into -JavaScript, see :ref:`Optimizing-the-source-code`. +.. note:: You can also optimize the source code you are compiling into JavaScript, see :ref:`Optimizing-the-source-code`. Using emcc ========== -The recommended way to optimize code is with **emcc**. emcc works like -gcc, and basic usage is presented in the Emscripten :ref:`Tutorial`. As -mentioned there, you can use emcc to optimize, for example +The recommended way to optimize code is with :ref:`emcc `. *Emcc* works like *gcc*, and basic usage is presented in the Emscripten :ref:`Tutorial`. As mentioned there, you can use *emcc* to optimize, for example :: @@ -32,91 +23,47 @@ To see what the different optimizations levels do, run emcc --help -- The meaning of ``-O1, -O2`` etc. in emcc are not identical to - gcc/clang/other compilers, even though they have been chosen to be as - familiar. They can't be, because optimizing JavaScript is very - different than optimizing native code. See the ``--help`` as - mentioned before for details. -- If you compile several files into a single JavaScript output, be sure - to specify the same optimization flags during all invocations of emcc - - both when compiling sources into objects, and objects into - JavaScript or HTML. See :ref:`Building-Projects` for more details. -- Aside from ``-Ox`` options, there are ``--llvm-lto`` options that you - can read about in ``emcc --help``. +- The meaning of ``-O1, -O2`` etc. in *emcc* are not identical to gcc/clang/other compilers, even though they have been chosen to be as familiar. They can't be, because optimizing JavaScript is very different than optimizing native code. See the ``--help`` as mentioned before for details. +- If you compile several files into a single JavaScript output, be sure to specify the same optimization flags during all invocations of *emcc* — both when compiling sources into objects, and objects into JavaScript or HTML. See :ref:`Building-Projects` for more details. +- Aside from ``-Ox`` options, there are ``--llvm-lto`` options that you can read about in ``emcc --help``. How to optimize code ==================== -The following procedure is how you should normally optimize your code. -Note that all the flags here are for the link stage (when compiling -bitcode to JS), not to optimizing source files. +The following procedure is how you should normally optimize your code. Note that all the flags here are for the link stage (when compiling bitcode to JavaScript), not to optimizing source files. -- First, run emcc on your code without optimization. The default - settings are set to be safe. Check that your code works (if not, see - the :ref:`Debugging` page) before continuing. +- First, run emcc on your code without optimization. The default settings are set to be safe. Check that your code works (if not, see the :ref:`Debugging` page) before continuing. - Build with ``-O2`` to get an optimized build. -- Build with ``-O0`` or ``-O1`` if you want faster iteration times, 0 - is the fastest to build but slowest to run, while 1 is in the middle. -- If you want an even more optimized build than ``-O2``, see the rest - of this page. +- Build with ``-O0`` or ``-O1`` if you want faster iteration times, 0 is the fastest to build but slowest to run, while 1 is in the middle. +- If you want an even more optimized build than ``-O2``, see the rest of this page. Advanced compiler settings ========================== -There are several flags you can pass to the compiler to affect code -generation, many of which can affect performance. Look in -``src/settings.js`` for which options are available and what they mean -(and if you want to look under the hood, see ``apply_opt_level`` in -``tools/shared.py`` for how -O1,2,3 affect them), as well as -``emcc --help``. A few useful ones are: - -- ``NO_EXIT_RUNTIME`` - When set, code can run but we never "shut down" - the runtime environment, in the sense that no global destructors are - run, no atexit calls are executed, etc. This is useful if your main() - function finishes but you still want to execute code, and in fact - necessary otherwise if you depend on a global structure it may have - gone away - and for that reason, at runtime if we see that you call - something like :c:func:`emscripten_set_main_loop` then we will never shut - down the runtime. However, if you build with ``-s NO_EXIT_RUNTIME=1`` - then we know at **compile** time that you want that, which lets the - compiler statically get rid of atexit calls and global destructors, - which can improve code size and startup speed. +There are several flags you can pass to the compiler to affect code generation, many of which can affect performance. Look in ``src/settings.js`` for which options are available and what they mean (and if you want to look under the hood, see ``apply_opt_level`` in ``tools/shared.py`` for how -O1,2,3 affect them), as well as ``emcc --help``. A few useful ones are: + +- ``NO_EXIT_RUNTIME`` - When set, code can run but we never "shut down" the runtime environment, in the sense that no global destructors are run, no atexit calls are executed, etc. This is useful if your ``main()`` function finishes but you still want to execute code, and in fact necessary otherwise if you depend on a global structure it may have gone away - and for that reason, at runtime if we see that you call something like :c:func:`emscripten_set_main_loop` then we will never shut down the runtime. However, if you build with ``-s NO_EXIT_RUNTIME=1`` then we know at **compile** time that you want that, which lets the compiler statically get rid of atexit calls and global destructors, which can improve code size and startup speed. Very large projects =================== -Very large projects can hit some issues that smaller ones will never -see: +Very large projects can hit some issues that smaller ones will never see: Memory initialization --------------------- -By default emscripten emits the static memory initialization inside the -js file, for simplicity. If it is very large, it can slow down startup, -or even cause issues in JS engines with limits on array sizes (you may -see ``Array initializer too large`` or ``Too much recursion`` for -example), and it also leads to very large js files. To avoid that, -emscripten can emit a binary file on the side by running emcc with +By default Emscripten emits the static memory initialization inside the **.js** file, for simplicity. If it is very large, it can slow down startup, or even cause issues in JavaScript engines with limits on array sizes (you may see ``Array initializer too large`` or ``Too much recursion`` for example), and it also leads to very large JavaScript files. To avoid that, Emscripten can emit a binary file on the side by running emcc with ``--memory-init-file 1`` -This is the default in ``-O2`` and above in emscripten 1.21.1 and above; -in earlier versions, you can enable it manually. When utilized, a file -with suffix ``.mem`` should appear, and it will be loaded by the JS. See -``emcc --help`` for more details. +This is the default in ``-O2`` and above in Emscripten 1.21.1 and above; in earlier versions, you can enable it manually. When utilized, a file with suffix ``.mem`` should appear, and it will be loaded by the JavaScript. See ``emcc --help`` for more details. Optimization levels ------------------- -You might want to build some source files in your project with ``-Os`` -or ``-Oz`` to reduce code size, and the rest using ``-O2`` which gives -better performance (but increases code size). This allows you to keep -files you know are less performance-sensitive at a minimal size, while -keeping the files that need to be fast at maximal speed. +You might want to build some source files in your project with ``-Os`` or ``-Oz`` to reduce code size, and the rest using ``-O2`` which gives better performance (but increases code size). This allows you to keep files you know are less performance-sensitive at a minimal size, while keeping the files that need to be fast at maximal speed. -(Note that this only matters during the source to bitcode phase: during -bitcode to JS, ``-Os`` and ``-Oz`` are the same as ``-O2`` as there are -currently no JS specific optimization flags for ``-Os`` or ``-Oz``.) +(Note that this only matters during the source to bitcode phase: during bitcode to JavaScript, ``-Os`` and ``-Oz`` are the same as ``-O2`` as there are currently no JavaScript specific optimization flags for ``-Os`` or ``-Oz``.) Code size --------- @@ -125,37 +72,20 @@ Tips for reducing code size include: - Memory init file as mentioned above. - Using -Os or -Oz, as also mentioned above. -- Build bitcode to JS with -O3 which runs the expensive variable reuse - pass (registerizeHarder) -- Use llvm LTO during bitcode to JS - ``-s INLINING_LIMIT=1 --llvm-lto 1`` (can break some code as the LTO - code path is less tested) -- That command also disables inlining. If sources were built with -Os - or -Oz, it will avoid inlining anyhow for the most part, and you can - try just ``--llvm-lto 1`` -- Use closure on the outside non-asm.js code ``--closure 1`` (can break - some code) +- Build bitcode to JavaScript with -O3 which runs the expensive variable reuse pass (registerizeHarder) +- Use llvm LTO during bitcode to JavaScript ``-s INLINING_LIMIT=1 --llvm-lto 1`` (can break some code as the LTO code path is less tested) +- That command also disables inlining. If sources were built with -Os or -Oz, it will avoid inlining anyhow for the most part, and you can try just ``--llvm-lto 1`` +- Use closure on the outside non-asm.js code ``--closure 1`` (can break some code) Outlining --------- -``OUTLINING_LIMIT`` breaks up large functions into smaller ones, by -"outlining" code. This helps startup speed as well as runtime speed in -some cases, particularly when a codebase has huge functions, which -confuse JS engines. For more details see `this -blogpost `__. +``OUTLINING_LIMIT`` breaks up large functions into smaller ones, by "outlining" code. This helps startup speed as well as runtime speed in some cases, particularly when a codebase has huge functions, which confuse JavaScript engines. For more details see `this blog post `_. Aggressive Variable Elimination ------------------------------- -You can enable aggressive variable elimination with -``-s AGGRESSIVE_VARIABLE_ELIMINATION=1``. This will then attempt to -remove variables whenever possible, even at the cost of increasing code -size by duplicating expressions. This can improve speed in some cases -where you have extremely large functions, for example it can make sqlite -7% faster (which has a huge interpreter loop with thousands of lines in -it). However it can also he harmful in some cases, so test before using -it. +You can enable aggressive variable elimination with ``-s AGGRESSIVE_VARIABLE_ELIMINATION=1``. This will then attempt to remove variables whenever possible, even at the cost of increasing code size by duplicating expressions. This can improve speed in some cases where you have extremely large functions, for example it can make sqlite 7% faster (which has a huge interpreter loop with thousands of lines in it). However it can also he harmful in some cases, so test before using it. Other optimization issues ========================= @@ -163,90 +93,43 @@ Other optimization issues Exception Catching ------------------ -In ``-O1`` and above exception catching is disabled. This prevents the -generation of try-catch blocks, which lets the code run much faster, and -also makes the code smaller. To re-enable them, run emcc with -``-s DISABLE_EXCEPTION_CATCHING=0``. +In ``-O1`` and above exception catching is disabled. This prevents the generation of try-catch blocks, which lets the code run much faster, and also makes the code smaller. To re-enable them, run emcc with ``-s DISABLE_EXCEPTION_CATCHING=0``. Viewing code optimization passes -------------------------------- -If you run emcc with ``EMCC_DEBUG=1`` (so, something like -``EMCC_DEBUG=1 emcc``), then it will output all the intermediate steps -after each optimization pass. The output will be in -``TEMP_DIR/emscripten_temp``, where ``TEMP_DIR`` is by default ``/tmp`` -(and can be modified in ``~/.emscripten``). ``EMCC_DEBUG=2`` will output -even more information, a separate file will be saved for each JS -optimization pass. +If you run emcc with ``EMCC_DEBUG=1`` (so, something like ``EMCC_DEBUG=1 emcc``), then it will output all the intermediate steps after each optimization pass. The output will be in ``TEMP_DIR/emscripten_temp``, where ``TEMP_DIR`` is by default ``/tmp`` (and can be modified in ``~/.emscripten``). ``EMCC_DEBUG=2`` will output even more information, a separate file will be saved for each JavaScript optimization pass. Inlining -------- -Inlining often generates large functions. These allow the compiler's -optimizations to be more effective, but have downsides for JS engines: -They often do not try to optimize big functions for fear or long JIT -times, or they do JIT them and it causes noticeable pauses. So -ironically (or paradoxically) using -O1 or -O2, which inline by default, -can actually decrease performance in some cases. +Inlining often generates large functions. These allow the compiler's optimizations to be more effective, but have downsides for JavaScript engines: They often do not try to optimize big functions for fear or long JIT times, or they do JIT them and it causes noticeable pauses. So ironically (or paradoxically) using -O1 or -O2, which inline by default, can actually decrease performance in some cases. -You can try to avoid this issue by disabling inlining (in specific files -or everywhere), or by using the outliner feature, see `this blog -post `__. +You can try to avoid this issue by disabling inlining (in specific files or everywhere), or by using the outliner feature, see `this blog post `_. Unsafe optimizations -------------------- A few **UNSAFE** optimizations you might want to try are: -- ``-s FORCE_ALIGNED_MEMORY=1``: Makes all memory accesses fully - aligned. This can break on code that actually requires unaligned - accesses. -- ``-s PRECISE_I64_MATH=1``: When disabled, does shortcuts when - implementing 64-bit addition etc., using doubles instead of full - emulation. This will break on code that uses the full range of 64-bit - numbers. -- ``--llvm-lto 1``: This enables LLVM's link-time opts, which can help - in some cases but there are known issues with them as well, so use at - your own risk. (There are btw a few modes aside from ``1``, see - ``emcc --help``.) -- ``--closure 1``: This can help with reducing the size of the - non-generated (support/glue) code, and with startup. However it can - break if you do not do proper closure compiler annotations and - exports. +- ``-s FORCE_ALIGNED_MEMORY=1``: Makes all memory accesses fully aligned. This can break on code that actually requires unaligned accesses. +- ``-s PRECISE_I64_MATH=1``: When disabled, does shortcuts when implementing 64-bit addition etc., using doubles instead of full emulation. This will break on code that uses the full range of 64-bit numbers. +- ``--llvm-lto 1``: This enables LLVM's link-time opts, which can help in some cases but there are known issues with them as well, so use at your own risk. (There are btw a few modes aside from ``1``, see ``emcc --help``.) +- ``--closure 1``: This can help with reducing the size of the non-generated (support/glue) code, and with startup. However it can break if you do not do proper closure compiler annotations and exports. Profiling ========= -Modern browsers have JavaScript profilers, which can help find the -slower parts in your code. You should build your project with -``-profiling`` for this, that flag will leave the code in a -readable-enough state for profiling purposes (``-profiling`` should be -added in addition to your other optimization flags like ``-O1``, ``-O2`` -or ``-O3``). +Modern browsers have JavaScript profilers, which can help find the slower parts in your code. You should build your project with ``-profiling`` for this, that flag will leave the code in a readable-enough state for profiling purposes (``-profiling`` should be added in addition to your other optimization flags like ``-O1``, ``-O2`` or ``-O3``). -As each browser's profiler has limitations, it is highly recommended to -profile in multiple browsers in order to get the best information. Also, -in Firefox it is a good idea to profile both with and without asm.js -optimizations enabled (can remove the ``'use asm'`` string to disable). +As each browser's profiler has limitations, it is highly recommended to profile in multiple browsers in order to get the best information. Also, in Firefox it is a good idea to profile both with and without asm.js optimizations enabled (can remove the ``'use asm'`` string to disable). Troubleshooting Slowness ======================== -If you get worse performance than you expect - you should get about 1/2 -the speed of a native build - then aside from the tips above, here is a -list of things to check: - -- Did you build with -O2 or -O3, **both** when compiling source code - files **and** when generating JavaScript? The first is needed for - LLVM optimizations, the latter for JS optimizations, all of which are - crucial (see :ref:`Building-Projects`). -- Is performance ok on one browser, but not in another? Testing on - multiple browsers is always good to understand where a bug or - performance issue lies. Please file a bug on the browser where things - are slow. -- In firefox, does the code validate? Look for "Successfully compiled - asm.js code in the web console. If instead you see a validation - error, make sure you are running an up-to-date version of firefox, - and are building using an up-to-date version of emscripten. If the - problem exists with those, please file a bug on emscripten. +If you get worse performance than you expect - you should get about 1/2 the speed of a native build - then aside from the tips above, here is a list of things to check: + +- Did you build with -O2 or -O3, **both** when compiling source code files **and** when generating JavaScript? The first is needed for LLVM optimizations, the latter for JavaScript optimizations, all of which are crucial (see :ref:`Building-Projects`). +- Is performance ok on one browser, but not in another? Testing on multiple browsers is always good to understand where a bug or performance issue lies. Please file a bug on the browser where things are slow. +- In firefox, does the code validate? Look for "Successfully compiled asm.js code in the web console. If instead you see a validation error, make sure you are running an up-to-date version of Firefox, and are building using an up-to-date version of Emscripten. If the problem exists with those, please file a bug on Emscripten. diff --git a/site/source/docs/optimizing/Optimizing-the-source-code.rst b/site/source/docs/optimizing/Optimizing-the-source-code.rst index 5c1f0ef0ff871..bbbd2184d7e3f 100644 --- a/site/source/docs/optimizing/Optimizing-the-source-code.rst +++ b/site/source/docs/optimizing/Optimizing-the-source-code.rst @@ -1,27 +1,12 @@ .. _Optimizing-the-source-code: -======================================== +==================================== Optimizing Source Code (wiki-import) -======================================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! +==================================== In general, normal C and C++ code will compile and run at good speeds. -However, there are some fundamental differences between JavaScript and -native code, that make certain types of source code much faster in one -or the other. Typical C and C++ code has been optimized for native code -obviously, so some tweaking might help for compiling to JavaScript. -- ``#define ABS(x) (x > 0 ? x : -x)`` and similar things are common - macros in C and C++ code. The assumption is that using ``math.h``'s - abs/fabs etc. will not be faster. However, when compiling to - JavaScript, the condition in this macro will be much slower: Doing - ``define ABS(x) abs(x)``, that is, using ``math.h``, would be faster, - since then it will be compiled by Emscripten into a single operation, - a call to ``Math.abs``. ``Math.abs`` has been optimized by JS - engines, and will run faster than any JavaScript code that emulates - the same behavior, whereas in native code, the conditional macro - might be just as fast, or faster, and simpler in that ``math.h`` is - not needed - so what makes sense in native code makes less sense for - JavaScript. In this case, the solution is simple, just switch the - macro to use ``abs()``. +However, there are some fundamental differences between JavaScript and native code, that make certain types of source code much faster in one or the other. Typical C and C++ code has been optimized for native code obviously, so some tweaking might help for compiling to JavaScript. + +- ``#define ABS(x) (x > 0 ? x : -x)`` and similar things are common macros in C and C++ code. The assumption is that using ``math.h``'s abs/fabs etc. will not be faster. However, when compiling to JavaScript, the condition in this macro will be much slower: Doing ``define ABS(x) abs(x)``, that is, using ``math.h``, would be faster, since then it will be compiled by Emscripten into a single operation, a call to ``Math.abs``. ``Math.abs`` has been optimized by JavaScript engines, and will run faster than any JavaScript code that emulates the same behavior, whereas in native code, the conditional macro might be just as fast, or faster, and simpler in that ``math.h`` is not needed - so what makes sense in native code makes less sense for JavaScript. In this case, the solution is simple, just switch the macro to use ``abs()``. diff --git a/site/source/docs/porting/Debugging.rst b/site/source/docs/porting/Debugging.rst index e719359b0bf99..83de880eab494 100644 --- a/site/source/docs/porting/Debugging.rst +++ b/site/source/docs/porting/Debugging.rst @@ -3,65 +3,45 @@ ======================= Debugging (wiki-import) ======================= -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! - -For a quick overview of debugging Emscripten-generated code, see `these -slides `__ +For a quick overview of debugging Emscripten-generated code, see `these slides `_. .. comment:: Pulled from below, might be useful: If you think you may have hit an Emscripten codegen bug, there are a few tools to help you. Limitation or Bug? ================== -Emscripten can compile almost but not all C/C++ code out there. Some -limitations exist, see :ref:`CodeGuidelinesAndLimitations`. +Emscripten can compile almost but not all C/C++ code out there. Some limitations exist, see :ref:`code-portability-guidelines`. -Aside from these limitations, it's possible you ran into a bug in -Emscripten, such as: +Aside from these limitations, it's possible you ran into a bug in Emscripten, such as: -- Missing functionality. For example, a library function which hasn't - yet been implemented in Emscripten. Possible solutions here are to - implement the function (see ``library.js``) or to compile it from - C++. +- Missing functionality. For example, a library function which hasn't yet been implemented in Emscripten. Possible solutions here are to implement the function (see ``library.js``) or to compile it from C++. - An actual mistake in Emscripten. Please report it! Optimizations ============= -Try to build without optimizations (no ``-O1`` etc.). If that has an -effect, you can try to disable LLVM optimizations specifically using -``--llvm-opts 0``, see ``emcc --help``. +Try to build without optimizations (no ``-O1`` etc.). If that has an effect, you can try to disable LLVM optimizations specifically using ``--llvm-opts 0``, see ``emcc --help``. -Build with ``EMCC_DEBUG=1`` to get intermediate files for the compiler's -various stages (output to ``/tmp/emscripten_temp``). ``EMCC_DEBUG=2`` -will emit more intermediate files (one for each JS optimizer pass). +Build with ``EMCC_DEBUG=1`` to get intermediate files for the compiler's various stages (output to ``/tmp/emscripten_temp``). ``EMCC_DEBUG=2`` will emit more intermediate files (one for each JavaScript optimizer pass). Useful Compilation Settings =========================== -As already mentioned, some useful settings appear in -``src/settings.js``. Change the settings there and then recompile the -code to have them take effect. When code isn't running properly, you -should compile with ``ASSERTIONS``, and if that doesn't clear things up, -then ``SAFE_HEAP``. ``ASSERTIONS`` adds various runtime checks, and -``SAFE_HEAP`` adds even more (slow) memory access checks like -dereferencing 0 and memory alignment issues. +As already mentioned, some useful settings appear in `src/settings.js `_. Change the settings there and then recompile the code to have them take effect. When code isn't running properly, you should compile with ``ASSERTIONS``, and if that doesn't clear things up, then ``SAFE_HEAP``. ``ASSERTIONS`` adds various runtime checks, and ``SAFE_HEAP`` adds even more (slow) memory access checks like dereferencing 0 and memory alignment issues. Inspecting the Generated Code ============================= See the slides linked to before for the ``-g`` options. -Another thing you might find useful is to not run JS optimizations, to -leave inline source code hints. You can try something like +Another thing you might find useful is to not run JavaScript optimizations, to leave inline source code hints. You can try something like :: /emcc -O2 --js-opts 0 -g4 tests/hello_world_loop.cpp -which applies only LLVM opts, and basic JS opts but not the JS -optimizer, which retains debug info, giving +which applies only LLVM opts, and basic JavaScript opts but not the JavaScript optimizer, which retains debug info, giving :: @@ -74,62 +54,32 @@ optimizer, which retains debug info, giving Debug Info ========== -It can be very useful to compile the C/C++ files with ``-g`` flag to get -debugging into - Emscripten will add source file and line number to each -line in the generated code. Note, however, that attempting to interpret -code compiled with ``-g`` using ``lli`` may cause crashes. So you may -need to build once without ``-g`` for ``lli``, then build again with -``-g``. Or, use ``tools/exec_llvm.py`` in Emscripten, which will run lli -after cleaning out debug info. +It can be very useful to compile the C/C++ files with ``-g`` flag to get debugging into - Emscripten will add source file and line number to each line in the generated code. Note, however, that attempting to interpret code compiled with ``-g`` using ``lli`` may cause crashes. So you may need to build once without ``-g`` for ``lli``, then build again with ``-g``. Or, use ``tools/exec_llvm.py`` in Emscripten, which will run lli after cleaning out debug info. The AutoDebugger =========================== -The 'nuclear option' when debugging is to use the **autodebugger tool**. -The autodebugger will rewrite the LLVM bitcode so it prints out each -store to memory. You can then run the exact same LLVM bitcode in the -LLVM interpreter (lli) and JavaScript, and compare the output (``diff`` -is useful if the output is large). For how to use the autodebugger tool, -see the ``autodebug`` test. - -The autodebugger can potentially find **any** problem in the generated -code, so it is strictly more powerful than the ``CHECK_*`` settings and -``SAFE_HEAP``. However, it has some limitations: - -- The autodebugger generates a lot of output. Using ``diff`` can be - very helpful here. -- The autodebugger doesn't print out pointer values, just simple - numerical values. The reason is that pointer values change from run - to run, so you can't compare them. However, on the one hand this may - miss potential problems, and on the other, a pointer may be converted - into an integer and stored, in which case it would be shown but it - should be ignored. (You can modify this, look in - ``tools/autodebugger.py``.) - -One use of the autodebugger is to quickly emit lots of logging output. -You can then take a look and see if something weird pops up. Another use -is for regressions, see below. +The 'nuclear option' when debugging is to use the **autodebugger tool**. + +The autodebugger will rewrite the LLVM bitcode so it prints out each store to memory. You can then run the exact same LLVM bitcode in the LLVM interpreter (lli) and JavaScript, and compare the output (``diff`` is useful if the output is large). For how to use the autodebugger tool, see the ``autodebug`` test. + +The autodebugger can potentially find **any** problem in the generated code, so it is strictly more powerful than the ``CHECK_*`` settings and ``SAFE_HEAP``. However, it has some limitations: + +- The autodebugger generates a lot of output. Using ``diff`` can be very helpful here. +- The autodebugger doesn't print out pointer values, just simple numerical values. The reason is that pointer values change from run to run, so you can't compare them. However, on the one hand this may miss potential problems, and on the other, a pointer may be converted into an integer and stored, in which case it would be shown but it should be ignored. (You can modify this, look in ``tools/autodebugger.py``.) + +One use of the autodebugger is to quickly emit lots of logging output. You can then take a look and see if something weird pops up. Another use is for regressions, see below. AutoDebugger Regression Workflow --------------------------------- -Fixing regressions is pretty easy with the autodebugger, using the -following workflow: +Fixing regressions is pretty easy with the autodebugger, using the following workflow: -- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment. -- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment, - again, but with a difference emcc setting etc., so that you now have - one build before the regression and one after. -- Run both versions, saving their output, then do a diff and - investigate that. Any difference is likely the bug (other false - positives could be things like the time, if something like - ``clock()`` is called, which differs slightly between runs). +- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment. +- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment, again, but with a difference emcc setting etc., so that you now have one build before the regression and one after. +- Run both versions, saving their output, then do a diff and investigate that. Any difference is likely the bug (other false positives could be things like the time, if something like ``clock()`` is called, which differs slightly between runs). -(You can also make the second build a native one using the llvm -nativizer tool mentioned above - run it on the autodebugged .ll file, -which EMCC\_DEBUG=1 will emit in ``/tmp/emscripten_temp``. This helps -find bugs in general and not just regressions, but has the same issues -with the nativizer tool mentioned earlier.) +(You can also make the second build a native one using the llvm nativizer tool mentioned above - run it on the autodebugged .ll file, which EMCC_DEBUG=1 will emit in ``/tmp/emscripten_temp``. This helps find bugs in general and not just regressions, but has the same issues with the nativizer tool mentioned earlier.) @@ -139,101 +89,51 @@ Specific Issues Memory Alignment Issues ----------------------- -``SAFE_HEAP`` will reveal memory alignment issues - where your code is -assuming a higher alignment than appears in practice. Unaligned reads -and writes can lead to incorrect results, as our typed array model of -memory does not support them. - -The best solution is to avoid unaligned reads and writes. Generally they -occur as the result of undefined behavior. - -In some cases, however, you may need unaligned reads and writes, for -example to read an int from a packed structure in some pre-existing data -format. To force an unaligned read or write (which will be slower, but -work properly), you can either manually read individual bytes and -reconstruct the full value, or use the ``emscripten_align*`` typedefs in -``emscripten.h``, which define unaligned versions of the basic types -(short, int, float, double). All operations on those types are not fully -aligned (use the ``1`` variants in most cases, which mean no alignment -whatsoever). They are slower due to lack of alignment, though, so be -sure to only use them when absolutely necessary. +``SAFE_HEAP`` will reveal memory alignment issues - where your code is assuming a higher alignment than appears in practice. Unaligned reads and writes can lead to incorrect results, as our typed array model of memory does not support them. + +The best solution is to avoid unaligned reads and writes. Generally they occur as the result of undefined behavior. + +In some cases, however, you may need unaligned reads and writes, for example to read an int from a packed structure in some pre-existing data format. To force an unaligned read or write (which will be slower, but work properly), you can either manually read individual bytes and reconstruct the full value, or use the ``emscripten_align*`` typedefs in ``emscripten.h``, which define unaligned versions of the basic types (short, int, float, double). All operations on those types are not fully aligned (use the ``1`` variants in most cases, which mean no alignment whatsoever). They are slower due to lack of alignment, though, so be sure to only use them when absolutely necessary. Function Pointer Issues ----------------------- -If you get an abort() from a function pointer call (nullFunc or b0 or b1 -or such, possibly with an error message saying "incorrect function -pointer"), the issue is that a function pointer was called but it is -invalid in that type. - -It is undefined behavior to cast a function pointer to another type and -call that (e.g., cast away the last parameter), but this does happen in -real-world code, and is one possible cause for this error. In optimized -emscripten output, each function pointer type has a different table of -entries, so you must call with the correct type to get the right -behavior. - -Another possible cause is a dereference of 0, like calling a method on a -NULL pointer or such. That can be a bug in the code caused by any -reason, but shows itself as a function pointer error (as just reading or -writing to a NULL pointer will work, unlike in native builds - it is -just function pointers that will always fail when NULL). - -Building with ``-Werror`` (turn warnings into errors) can help here, as -some cases of undefined behavior show warnings. If you can get your -codebase to build with ``-Werror`` that might help. - -Use ``-s ASSERTIONS=2`` to get some useful information about the -function pointer being called, and its type. Also useful is to look at -the stack trace (may want to disable asm.js optimizations in firefox to -see the best trace information) to see where in your code the error -happens, then see which function should be called but isn't. - -SAFE\_HEAP is also useful when debugging issues like this, as is -disabling function pointer aliasing using -ALIASING\_FUNCTION\_POINTERS=0. When you build with -``-s SAFE_HEAP=1 -s ALIASING_FUNCTION_POINTERS=0`` then it should be -impossible for a function pointer to be called with the wrong type -without an error showing up. - -Another possible problem with function pointers is that what appears to -be the wrong function is called. Again, ``SAFE_HEAP`` can help with this -as it detects some possible errors with function table accesses. +If you get an ``abort()`` from a function pointer call (``nullFunc`` or ``b0`` or ``b1`` or such, possibly with an error message saying "incorrect function pointer"), the issue is that a function pointer was called but it is invalid in that type. + +It is undefined behavior to cast a function pointer to another type and call that (e.g., cast away the last parameter), but this does happen in real-world code, and is one possible cause for this error. In optimized Emscripten output, each function pointer type has a different table of entries, so you must call with the correct type to get the right behavior. + +Another possible cause is a dereference of 0, like calling a method on a NULL pointer or such. That can be a bug in the code caused by any reason, but shows itself as a function pointer error (as just reading or writing to a NULL pointer will work, unlike in native builds - it is just function pointers that will always fail when NULL). + +Building with ``-Werror`` (turn warnings into errors) can help here, as some cases of undefined behavior show warnings. If you can get your codebase to build with ``-Werror`` that might help. + +Use ``-s ASSERTIONS=2`` to get some useful information about the function pointer being called, and its type. Also useful is to look at the stack trace (may want to disable asm.js optimizations in Mozilla Firefox to see the best trace information) to see where in your code the error happens, then see which function should be called but isn't. + +SAFE_HEAP is also useful when debugging issues like this, as is disabling function pointer aliasing using ``ALIASING_FUNCTION_POINTERS=0``. When you build with ``-s SAFE_HEAP=1 -s ALIASING_FUNCTION_POINTERS=0`` then it should be impossible for a function pointer to be called with the wrong type without an error showing up. + +Another possible problem with function pointers is that what appears to be the wrong function is called. Again, ``SAFE_HEAP`` can help with this as it detects some possible errors with function table accesses. Infinite loops -------------- -If your code hits an infinite loop, one easy way to see where that -happens is to use a JS profiler. In the Firefox profiler for example it -is easy to see which code ran at what time, so if the code enters an -infinite loop for a while (before the browser shows the slow script -dialog and you quit it), you will see a block of code doing the same -thing near the end of the profile. +If your code hits an infinite loop, one easy way to see where that happens is to use a JavaScript profiler. In the Firefox profiler for example it is easy to see which code ran at what time, so if the code enters an infinite loop for a while (before the browser shows the slow script dialog and you quit it), you will see a block of code doing the same thing near the end of the profile. Additional Tips =========================== -You can also do something similar to what the autodebugger does, -manually - modify the original source code with some ``printf()``\ s, -then compile and run that, to investigate issues. +You can also do something similar to what the autodebugger does, manually - modify the original source code with some ``printf()``\ s, then compile and run that, to investigate issues. -Another useful tip is if you have a good idea of what line is -problematic in generated .js, you can add ``print(new Error().stack)`` -to get a stack trace there. There is also :js:func:`stackTrace` which emits a -stack trace and also tries to demangle C++ function names. +Another useful tip is if you have a good idea of what line is problematic in generated .js, you can add ``print(new Error().stack)`` to get a stack trace there. There is also :js:func:`stackTrace` which emits a stack trace and also tries to demangle C++ function names. Useful Links =========================== -`Blogpost about reading compiler -output `__ +`Blogpost about reading compiler output `_. Additional Help =========================== -Of course, you can also ask the Emscripten devs for help. :) See links -to IRC and the Google Group on the main project page. +Of course, you can also ask the Emscripten devs for help. :) See links to IRC and the Google Group on the main project page. .. todo:: **HamishW** Make sure that SAFE_HEAP is clearly documented, and ideally has a section we can link to from the rest of the document. \ No newline at end of file diff --git a/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst b/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst index a77d28b7af36e..52ba57b0aa75a 100644 --- a/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst +++ b/site/source/docs/porting/files/Synchronous-Virtual-XHR-Backed-File-System-Usage.rst @@ -4,8 +4,6 @@ Synchronous Virtual XHR Backed File System Usage (wiki-import) ============================================================== -.. note:: This article was migrated from the wiki (Mon, 04 Aug 2014 23:20) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! - Emscripten supports lazily loading binary data from HTTP servers using XHR's (ala AJAX but no XML or JSON). **Restriction: only possible in Web Workers** (due to browser limitations) @@ -16,6 +14,6 @@ Instructions for use ==================== #. You will need a page that spawns the web worker. See the page inlined in ``tests/runner.py/test_chunked_synchronous_xhr``. The ``prejs`` we use below will cause the program running in the Web Worker to ``postMessage`` it's stdout back. If you use that solution, the mother page should probably contain your handwritten glue code (not Emscriptened) to handle the stdout data. -#. The tests use ``checksummer.c`` as the actual Emscriptened program. As you can see, it is simply a vanilla C program using ``fopen``/``fread``/``fclose`` and no Emscripten specific code at all. -#. You will need at ``prejs`` that sets up the mapping between the file path in your equivalent of ``checksummer.c`` and the server to download from. Remember CORS! The test case also contains an HTTP server that shows some CORS headers that might need to be set. Of course, if the resources are hosted from the same domain Emscripten runs from, there is no issue. +#. The tests use **checksummer.c** as the actual Emscriptened program. As you can see, it is simply a vanilla C program using ``fopen``/``fread``/``fclose`` and no Emscripten specific code at all. +#. You will need at ``prejs`` that sets up the mapping between the file path in your equivalent of **checksummer.c** and the server to download from. Remember CORS! The test case also contains an HTTP server that shows some CORS headers that might need to be set. Of course, if the resources are hosted from the same domain Emscripten runs from, there is no issue. diff --git a/site/source/docs/porting/files/file_systems_overview.rst b/site/source/docs/porting/files/file_systems_overview.rst index d55e0bad37829..225f2d9277202 100644 --- a/site/source/docs/porting/files/file_systems_overview.rst +++ b/site/source/docs/porting/files/file_systems_overview.rst @@ -3,7 +3,6 @@ =================================== File System Overview (wiki-import) =================================== -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! .. comment Perhaps integrate this: "Native code and JavaScript have significantly expectations with respect to file handling — native code expects to be able to access files on the local machine using synchronous APIs, while JavaScript provides asynchronous file system APIs (outside of web workers) and does not have direct access to the host file system when running in a browser." diff --git a/site/source/docs/porting/files/packaging_files.rst b/site/source/docs/porting/files/packaging_files.rst index f244a27ffe243..6742e45407ec1 100644 --- a/site/source/docs/porting/files/packaging_files.rst +++ b/site/source/docs/porting/files/packaging_files.rst @@ -4,13 +4,13 @@ Packaging Files (wiki-import) ============================== -The simplest thing to do is just tell emcc to package files for you, +The simplest thing to do is just tell :ref:`emcc ` to package files for you, :: emcc file.cpp -o file.html --preload-file asset_dir -That command will generate file.html, and alongside it file.data which will contain all the files in ``asset_dir/``. You can then distribute your application with just those two files. +That command will generate file.html, and alongside it file.data which will contain all the files in **asset_dir/**. You can then distribute your application with just those two files. Assets can also be embedded directly into the html file: @@ -57,7 +57,7 @@ This will make **../res/gen123.png** available as **/main.png** in Javascript. Monitoring Read Files ===================== -It is important to only preload the files your app actually needs, to reduce download size and improve startup speed. There is an option to log all the actually used files during runtime, which you can use to figure out which files your app actually needs. To use it, define ``logReadFiles`` on the Module object. ``Module.printErr`` will then be called on each file that is read from, so you can define that function to log to a convenient place. +It is important to only preload the files your app actually needs, to reduce download size and improve startup speed. There is an option to log all the actually used files during runtime, which you can use to figure out which files your app actually needs. To use it, define ``logReadFiles`` on the ``Module`` object. ``Module.printErr`` will then be called on each file that is read from, so you can define that function to log to a convenient place. You can also look at ``FS.readFiles``, which will be an object whose keys are all the files that were read from. This might be easier to use than logging. Note that you can also modify the object, even remove it entirely. This can be useful in order to see which files are read between two points in time in your app, for example. diff --git a/site/source/docs/porting/guidelines/portability_guidelines.rst b/site/source/docs/porting/guidelines/portability_guidelines.rst index c52adbc918df6..453fd65df69f5 100644 --- a/site/source/docs/porting/guidelines/portability_guidelines.rst +++ b/site/source/docs/porting/guidelines/portability_guidelines.rst @@ -1,4 +1,4 @@ -.. _CodeGuidelinesAndLimitations: +.. _code-portability-guidelines: ====================== Portability Guidelines diff --git a/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst b/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst index afb9c2c9dcc9c..b06686fbbbe84 100644 --- a/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst +++ b/site/source/docs/porting/multimedia_and_graphics/EGL-Support-in-Emscripten.rst @@ -4,8 +4,6 @@ EGL Support in Emscripten (wiki-import) ======================================= -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! - Khronos Group publishes a specification called EGL, which is an API that handles (among other tasks) graphics context creation, rendering surface management, and interop between different Khronos Group graphics APIs (OpenGL, OpenGL ES, OpenVG). For detailed information, see the `Khronos EGL webpage `_. Currently, EGL is not very widely used across operating systems/graphics driver vendors. The most notable adoption is in the Android architecture, where EGL is the primary method for creating rendering contexts for OpenGL ES 1&2 when using the Android NDK. Also, Mesa has an implementation of the EGL specification in its `graphics driver `_. @@ -44,7 +42,7 @@ Perform the following steps to create a GLES2 context using EGL: After these steps, you have a set of EGL objects ``EGLDisplay``, ``EGLConfig``, ``EGLSurface`` and ``EGLContext`` that represent the main GLES2 rendering context. Cleanup --------------- +------- The sequence to clean up at deinitialization is as follows: @@ -55,7 +53,7 @@ The sequence to clean up at deinitialization is as follows: #. Delete the native rendering window. This step does not apply for Emscripten. Sample Code --------------- +------------ Example code for using EGL to initialize a WebGL context can be found in the sample applications in the `emscripten/test/glbook `_ directory, more specifically in the file `esUtil.c `_. @@ -71,14 +69,14 @@ Fully Implemented - ``eglSwapBuffers``: Implemented, but this function cannot really control the swap behavior under WebGL. Calling this function is optional under Emscripten. In WebGL, the contents of the display are always presented to the screen only after the code yields its execution back to the browser, that is, when you return from the tick callback handler you passed to :c:func:`emscripten_set_main_loop`. The ``eglSwapBuffers`` function can however still be used to detect when a GL context loss event occurs. -- ``eglGetDisplay``: Implemented according to the spec. Emscripten does not utilize multiple EGLNativeDisplayType objects, so pass in EGL_DEFAULT_DISPLAY here. Emscripten currently actually ignores any value passed in here for linux emulation purposes, but you should not rely on this in the future. +- ``eglGetDisplay``: Implemented according to the spec. Emscripten does not utilize multiple EGLNativeDisplayType objects, so pass in ``EGL_DEFAULT_DISPLAY`` here. Emscripten currently actually ignores any value passed in here for Linux emulation purposes, but you should not rely on this in the future. - ``eglGetError``: Implemented according to the spec. Important! According to the spec, eglGetError only reports the single most recent error, and not list of previous errors, so don't call this function in a loop like glGetError is called! Partially Implemented ---------------------- -- ``eglChooseConfig``: Implemented as a stub, but this function does not do searching/filtering, and is at the moment identical to eglGetConfigs (`issue #643 `_). +- ``eglChooseConfig``: Implemented as a stub, but this function does not do searching/filtering, and is at the moment identical to ``eglGetConfigs`` (`issue #643 `_). - ``eglGetConfigAttrib``: Implemented. Querying for the attributes ``EGL_BUFFER_SIZE``, ``EGL_ALPHA_SIZE``, ``EGL_BLUE_SIZE``, ``EGL_GREEN_SIZE``, ``EGL_RED_SIZE``, ``EGL_DEPTH_SIZE`` and ``EGL_STENCIL_SIZE`` currently return hardcoded default values (`issue #644 `_). The attributes ``EGL_MIN_SWAP_INTERVAL`` and ``EGL_MAX_SWAP_INTERVAL`` don't currently have any function. Instead, call :c:func:`emscripten_set_main_loop` to specify the main loop update rate. diff --git a/site/source/docs/porting/multimedia_and_graphics/OpenGL-support.rst b/site/source/docs/porting/multimedia_and_graphics/OpenGL-support.rst index 1fa89c8e6065f..ec3919b12d107 100644 --- a/site/source/docs/porting/multimedia_and_graphics/OpenGL-support.rst +++ b/site/source/docs/porting/multimedia_and_graphics/OpenGL-support.rst @@ -3,7 +3,6 @@ ============================ OpenGL support (wiki-import) ============================ -.. note:: This article was migrated from the wiki (Fri, 25 Jul 2014 04:21) and is now the "master copy" (the version in the wiki will be deleted). It may not be a perfect rendering of the original but we hope to fix that soon! Emscripten supports GL in three ways: @@ -12,7 +11,7 @@ Emscripten supports GL in three ways: - **OpenGL emulation of older desktop and mobile versions**. This includes support for GL 1.x features like immediate mode and various commands like ``glNormalPointer`` etc. Emscripten support for such emulation is sufficient to run Sauerbraten (BananaBread project) and several other real-world codebases, but is definitely not complete in the sense of supporting all older GL features (which would be an enormous task). It also adds significant emulation overhead, so this is not recommended (but you might want to try it if your codebase currently requires GL 1.x). To enable it, compile with ``-s LEGACY_GL_EMULATION=1``. Emulation levels ----------------- +============================ As mentioned above, we can directly support a subset of ES2 (the "WebGL-friendly subset"), and have emulation for the rest of ES2, as well as emulation for various desktop GL features. @@ -21,7 +20,7 @@ By default we assume the WebGL-friendly subset. If you want ES2 emulation, use ` The desktop GL emulation can be enabled with ``-s LEGACY_GL_EMULATION=1``. Settings for optimizing emulation code -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------------------------------------------------------- When specifying ``-s LEGACY_GL_EMULATION=1``, there are a few extra flags that can be used to tune the performance of the GL emulation layer. @@ -30,18 +29,18 @@ When specifying ``-s LEGACY_GL_EMULATION=1``, there are a few extra flags that c - You can add an int parameter ``Module.GL_MAX_TEXTURE_IMAGE_UNITS`` to your shell **.html** file to signal the GL emulation layer how many texture units your code is using at maximum. This avoids wasting clock cycles on iterating over unused texture units when examining which FFP emulation shader to run. What is the "WebGL-friendly subset of OpenGL"? ----------------------------------------------- +============================================== The WebGL-friendly subset of OpenGL is basically what maps directly to WebGL, call to call. That includes almost all of OpenGL ES 2.0, except for client-side arrays. The reason they are missing from WebGL is because they are less efficient than properly using GPU-side data. Similarly, if we emulated client-side arrays here, we would end up with very bad performance, since we would need to upload the data on each call to glDrawArrays etc. (Even if there are two calls one after the other, we can't know the data did not change!) So in practical terms full OpenGL ES 2.0 emulation would be convenient, but lead to bad performance so in practice you would need to properly rewrite your code to a WebGL-friendly subset anyhow. Writing for the WebGL-friendly subset of OpenGL ------------------------------------------------ +=============================================== See the files in tests/glbook and their git history for some simple examples ported to that subset. A very useful tool is the ``webgl.verbose`` option in Firefox. If you compile code that uses clientside arrays, that option will give you a warning when there isn't a bound buffer and so forth. It will also warn you of other differences between OpenGL and WebGL. What if I need additional GL features not supported yet? --------------------------------------------------------- +======================================================== Feel free to file issues with testcases that do not work, and we will look into them. From c3f152dfe2527fea6cb723370c3eef44e07a9837 Mon Sep 17 00:00:00 2001 From: hamishwillee Date: Thu, 4 Sep 2014 17:35:21 +1000 Subject: [PATCH 26/37] Update the home page call to action box --- site/source/home_page_layout.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/site/source/home_page_layout.html b/site/source/home_page_layout.html index 98502d6fc6b87..c03f6246bfe27 100644 --- a/site/source/home_page_layout.html +++ b/site/source/home_page_layout.html @@ -24,10 +24,6 @@

Emscripten is an LLVM-based project that compiles C/C++ into h -
+

Ready to get started? Download and install the SDK and then proceed to the Tutorial!

- - - - From b0d12cc455128ddaf13c922c74334b28dd77722d Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Thu, 4 Sep 2014 10:09:58 +0100 Subject: [PATCH 27/37] tell cmake that there is no library for dlopen on emscripten (shuts up warnings "emcc: cannot find library "dl"" for projects that add CMAKE_DL_LIBS to the link line) --- cmake/Modules/Platform/Emscripten.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/Modules/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake index acfa31837577c..3aa7da2d7bc83 100644 --- a/cmake/Modules/Platform/Emscripten.cmake +++ b/cmake/Modules/Platform/Emscripten.cmake @@ -149,6 +149,7 @@ set(CMAKE_HAVE_UNISTD_H 1) set(CMAKE_HAVE_PTHREAD_H 1) set(CMAKE_HAVE_SYS_PRCTL_H 1) set(CMAKE_WORDS_BIGENDIAN 0) +set(CMAKE_DL_LIBS) set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O2" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE") set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL") From 7eab43d564851bddfb48d3fae7192626dbf63274 Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Thu, 4 Sep 2014 10:11:56 +0100 Subject: [PATCH 28/37] Fix returning uninitialised memory to C code. flowinfo is a dead field that's unused, scope_id is actually useful but browsers have terrible support for link-local IPv6 addresses so we needn't support it now. --- AUTHORS | 1 + src/library.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index 3524458dc105d..6d8817dbc71a7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -158,4 +158,5 @@ a license to everyone to use it as detailed in LICENSE.) * Коренберг Марк * Gauthier Billot * Árpád Goretity +* Nicholas Wilson diff --git a/src/library.js b/src/library.js index 6822e69f9e728..0fd5099429b39 100644 --- a/src/library.js +++ b/src/library.js @@ -7871,6 +7871,8 @@ LibraryManager.library = { {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'addr[2]', 'i32') }}}; {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'addr[3]', 'i32') }}}; {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_port, '_htons(port)', 'i16') }}}; + {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_flowinfo, '0', 'i32') }}}; + {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_scope_id, '0', 'i32') }}}; break; default: return { errno: ERRNO_CODES.EAFNOSUPPORT }; From 1a3212c6ffd87d15fb9c1391cd8a0eaa6b053186 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Sep 2014 11:58:51 -0700 Subject: [PATCH 29/37] refactor parseHeapTemp to be useful in more places --- tools/js-optimizer.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 566f5ed293b42..6b79bc42b87f6 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -364,6 +364,13 @@ function removeUnneededLabelSettings(ast) { // Various expression simplifications. Happens after elimination, which opens up many of these simplification opportunities. +function parseHeap(name, out) { + if (name.substr(0, 4) != 'HEAP') return false; + out.unsigned = name[4] === 'U'; + out.bits = parseInt(name.substr(out.unsigned ? 5 : 4)); + return true; +} + var USEFUL_BINARY_OPS = set('<<', '>>', '|', '&', '^'); var COMPARE_OPS = set('<', '<=', '>', '>=', '==', '===', '!=', '!=='); @@ -485,14 +492,7 @@ function simplifyExpressions(ast) { // & and heap-related optimizations - var heapBits, heapUnsigned; - function parseHeap(name) { - if (name.substr(0, 4) != 'HEAP') return false; - heapUnsigned = name[4] === 'U'; - heapBits = parseInt(name.substr(heapUnsigned ? 5 : 4)); - return true; - } - + var parseHeapTemp = { unsigned: false, bits: 0 }; var hasTempDoublePtr = false, rerunOrZeroPass = false; traverse(ast, function(node, type) { @@ -518,10 +518,10 @@ function simplifyExpressions(ast) { } else if (input[0] === 'sub' && input[1][0] === 'name') { // HEAP8[..] & 255 => HEAPU8[..] var name = input[1][1]; - if (parseHeap(name)) { - if (amount === Math.pow(2, heapBits)-1) { - if (!heapUnsigned) { - input[1][1] = 'HEAPU' + heapBits; // make unsigned + if (parseHeap(name, parseHeapTemp)) { + if (amount === Math.pow(2, parseHeapTemp.bits)-1) { + if (!parseHeapTemp.unsigned) { + input[1][1] = 'HEAPU' + parseHeapTemp.bits; // make unsigned } if (asm) { // we cannot return HEAPU8 without a coercion, but at least we do HEAP8 & 255 => HEAPU8 | 0 @@ -546,9 +546,9 @@ function simplifyExpressions(ast) { // collapse HEAPU?8[..] << 24 >> 24 etc. into HEAP8[..] | 0 var amount = node[3][1]; var name = node[2][2][1][1]; - if (amount === node[2][3][1] && parseHeap(name)) { - if (heapBits === 32 - amount) { - node[2][2][1][1] = 'HEAP' + heapBits; + if (amount === node[2][3][1] && parseHeap(name, parseHeapTemp)) { + if (parseHeapTemp.bits === 32 - amount) { + node[2][2][1][1] = 'HEAP' + parseHeapTemp.bits; node[1] = '|'; node[2] = node[2][2]; node[3][1] = 0; From 8baf8346fdf2f2c23fc8561d4f01efd03e95c891 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Sep 2014 13:48:30 -0700 Subject: [PATCH 30/37] experimental POINTER_MASKING option --- emcc | 8 ++ emscripten.py | 4 + src/settings.js | 2 + tests/test_core.py | 28 +++++-- tests/test_other.py | 2 + tools/js-optimizer.js | 48 +++++++++++- tools/test-js-optimizer-pointerMask-output.js | 72 ++++++++++++++++++ tools/test-js-optimizer-pointerMask.js | 73 +++++++++++++++++++ 8 files changed, 228 insertions(+), 9 deletions(-) create mode 100644 tools/test-js-optimizer-pointerMask-output.js create mode 100644 tools/test-js-optimizer-pointerMask.js diff --git a/emcc b/emcc index bd9886ca71a76..1c0a0201f3700 100755 --- a/emcc +++ b/emcc @@ -930,6 +930,12 @@ try: logging.warning('not all asm.js optimizations are possible with --closure 2, disabling those - your code will be run more slowly') shared.Settings.ASM_JS = 2 + if shared.Settings.POINTER_MASKING: + logging.warning('POINTER_MASKING is experimental') + size = shared.Settings.POINTER_MASKING + 1 # size plus 1 should be a power of 2 + if size & (size-1) != 0: + raise Exception('POINTER_MASKING value must be a power of 2 minus 1') + assert shared.LLVM_TARGET in shared.COMPILER_OPTS if shared.LLVM_TARGET == 'i386-pc-linux-gnu': shared.Settings.TARGET_X86 = 1 @@ -1416,6 +1422,8 @@ try: else: js_optimizer_queue += ['registerize'] + if shared.Settings.POINTER_MASKING and shared.Settings.ASM_JS: js_optimizer_queue += ['pointerMasking'] + if opt_level >= 2: if debug_level < 2 and shared.Settings.ASM_JS and not closure == 2: js_optimizer_queue += ['minifyNames'] diff --git a/emscripten.py b/emscripten.py index 5dfacd8a69fd9..98a9e6ae85cbb 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1159,6 +1159,10 @@ def math_fix(g): if settings.get('SIDE_MODULE'): init = '(H_BASE+' + str(init) + ')|0' asm_global_vars += ' var %s=%s;\n' % (key, str(init)) + if settings['POINTER_MASKING']: + for i in [0, 1, 2, 3]: + asm_global_vars += ' var MASK%d=%d;\n' % (i, (settings['TOTAL_MEMORY']-1) & (~((2**i)-1))); + # sent data the_global = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in fundamentals]) + ' }' sending = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in basic_funcs + global_funcs + basic_vars + basic_float_vars + global_vars]) + ' }' diff --git a/src/settings.js b/src/settings.js index 6f88b3fb04a8b..256ab5ed694b8 100644 --- a/src/settings.js +++ b/src/settings.js @@ -186,6 +186,8 @@ var OUTLINING_LIMIT = 0; // A function size above which we try to automatically var AGGRESSIVE_VARIABLE_ELIMINATION = 0; // Run aggressiveVariableElimination in js-optimizer.js var SIMPLIFY_IFS = 1; // Whether to simplify ifs in js-optimizer.js +var POINTER_MASKING = 0; // Whether to mask pointers (experimental optimization trying to reduce VM bounds checks). + // When using this option, TOTAL_MEMORY must be a power of 2. // Generated code debugging options var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give a clear diff --git a/tests/test_core.py b/tests/test_core.py index c68b040e90727..a1fad006f0e13 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5139,15 +5139,27 @@ def test_lua(self): if self.emcc_args is None: return self.skip('requires emcc') if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work') + if self.emcc_args: self.emcc_args = ['-g1'] + self.emcc_args + + total_memory = Settings.TOTAL_MEMORY + for aggro in ([0, 1] if Settings.ASM_JS and '-O2' in self.emcc_args else [0]): - print aggro - Settings.AGGRESSIVE_VARIABLE_ELIMINATION = aggro - self.do_run('', - 'hello lua world!\n17\n1\n2\n3\n4\n7', - args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], - libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None), - includes=[path_from_root('tests', 'lua')], - output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n')) + for masking in ([0, 1] if Settings.ASM_JS and '-O2' in self.emcc_args and os.environ.get('EMCC_FAST_COMPILER') != '0' else [0]): + Settings.AGGRESSIVE_VARIABLE_ELIMINATION = aggro + Settings.POINTER_MASKING = masking + Settings.TOTAL_MEMORY = total_memory + if masking: + total = 2 + while 2*total <= total_memory: + total *= 2 + Settings.TOTAL_MEMORY = total + print aggro, masking + self.do_run('', + 'hello lua world!\n17\n1\n2\n3\n4\n7', + args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''], + libraries=self.get_library('lua', [os.path.join('src', 'lua'), os.path.join('src', 'liblua.a')], make=['make', 'generic'], configure=None), + includes=[path_from_root('tests', 'lua')], + output_nicerizer=lambda string, err: (string + err).replace('\n\n', '\n').replace('\n\n', '\n')) def get_freetype(self): Settings.DEAD_FUNCTIONS += ['_inflateEnd', '_inflate', '_inflateReset', '_inflateInit2_'] diff --git a/tests/test_other.py b/tests/test_other.py index a1d83d43bb3f1..d1e54fb8c6f46 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1893,6 +1893,8 @@ def test_js_optimizer(self): ['asm', 'minifyWhitespace', 'last']), (path_from_root('tools', 'test-js-optimizer-shiftsAggressive.js'), open(path_from_root('tools', 'test-js-optimizer-shiftsAggressive-output.js')).read(), ['asm', 'aggressiveVariableElimination']), + (path_from_root('tools', 'test-js-optimizer-pointerMask.js'), open(path_from_root('tools', 'test-js-optimizer-pointerMask-output.js')).read(), + ['pointerMasking']), ]: print input output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 6b79bc42b87f6..66ffef75f3ad2 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -367,7 +367,7 @@ function removeUnneededLabelSettings(ast) { function parseHeap(name, out) { if (name.substr(0, 4) != 'HEAP') return false; out.unsigned = name[4] === 'U'; - out.bits = parseInt(name.substr(out.unsigned ? 5 : 4)); + out.bits = parseInt(name.substr(out.unsigned || name[4] === 'F' ? 5 : 4)); return true; } @@ -5540,6 +5540,51 @@ function optimizeFrounds(ast) { traverseChildren(ast, fix); } +// Optimize heap expressions into HEAP32[(x&m)+c>>2] where c is a small aligned constant, and m guarantees the pointer is without range+aligned +function pointerMasking(ast) { + var MAX_SMALL_OFFSET = 32; + var parseHeapTemp = { unsigned: false, bits: 0 }; + + traverse(ast, function(node, type) { + if (type === 'sub' && node[1][0] === 'name' && node[1][1][0] === 'H' && node[2][0] === 'binary' && node[2][1] === '>>' && node[2][3][0] === 'num') { + var addee = node[2][2]; + if (!(addee[0] === 'binary' && addee[1] === '+')) return; + var shifts = node[2][3][1]; + if (!parseHeap(node[1][1], parseHeapTemp)) return; + if (parseHeapTemp.bits !== 8*Math.pow(2, shifts)) return; + // this is an HEAP[U]N[x + y >> n] expression. gather up all the top-level added items, seek a small constant amongst them + var addedElements = []; + function addElements(node) { + if (node[0] === 'binary' && node[1] === '+') { + addElements(node[2]); + addElements(node[3]); + } else { + addedElements.push(node); + } + } + addElements(addee); + assert(addedElements.length >= 2); + for (var i = 0; i < addedElements.length; i++) { + var element = addedElements[i]; + if (element[0] === 'num') { + var c = element[1]; + if (c < MAX_SMALL_OFFSET && ((c >> shifts) << shifts) === c) { + // this is a small aligned offset, we are good to go. gather the others, and finalize + addedElements.splice(i, 1); + var others = addedElements[0]; + for (var j = 1; j < addedElements.length; j++) { + others = ['binary', '+', others, addedElements[j]]; + } + others = ['binary', '&', others, ['name', 'MASK' + shifts]]; + node[2][2] = ['binary', '+', others, element]; + return; + } + } + } + } + }); +} + // Last pass utilities // Change +5 to DOT$ZERO(5). We then textually change 5 to 5.0 (uglify's ast cannot differentiate between 5 and 5.0 directly) @@ -5687,6 +5732,7 @@ var passes = { outline: outline, safeHeap: safeHeap, optimizeFrounds: optimizeFrounds, + pointerMasking: pointerMasking, // flags minifyWhitespace: function() { minifyWhitespace = true }, diff --git a/tools/test-js-optimizer-pointerMask-output.js b/tools/test-js-optimizer-pointerMask-output.js new file mode 100644 index 0000000000000..7f8445a55ec0f --- /dev/null +++ b/tools/test-js-optimizer-pointerMask-output.js @@ -0,0 +1,72 @@ +function f() { + HEAP8[x >> 0]; + HEAP8[(x & MASK0) + 1 >> 0]; + HEAP8[(x & MASK0) + 2 >> 0]; + HEAP8[(x + 1 & MASK0) + 2 >> 0]; + HEAP8[(x + 2 & MASK0) + 2 >> 0]; + HEAP8[(x + 1 + y & MASK0) + 2 >> 0]; + HEAP8[(x + 2 + y & MASK0) + 2 >> 0]; + x(); + HEAP16[x >> 1]; + HEAP16[x + 1 >> 1]; + HEAP16[(x & MASK1) + 2 >> 1]; + HEAP16[(x + 1 & MASK1) + 2 >> 1]; + HEAP16[(x + 2 & MASK1) + 2 >> 1]; + HEAP16[(x + 1 + y & MASK1) + 2 >> 1]; + HEAP16[(x + 2 + y & MASK1) + 2 >> 1]; + HEAP16[(x + 1 + y & MASK1) + 4 >> 1]; + HEAP16[(x + 2 + y & MASK1) + 4 >> 1]; + HEAP16[(x + 1 + y & MASK1) + 4 >> 1]; + HEAP16[(x + 4 + y & MASK1) + 2 >> 1]; + x(); + HEAP32[x >> 2]; + HEAP32[x + 1 >> 2]; + HEAP32[x + 2 >> 2]; + HEAP32[x + 3 >> 2]; + HEAP32[(x & MASK2) + 4 >> 2]; + HEAP32[(x + 1 & MASK2) + 4 >> 2]; + HEAP32[(x + 4 & MASK2) + 4 >> 2]; + HEAP32[(x + 1 + y & MASK2) + 4 >> 2]; + HEAP32[(x + 4 + y & MASK2) + 4 >> 2]; + HEAP32[(x + 1 + y & MASK2) + 8 >> 2]; + HEAP32[(x + 4 + y & MASK2) + 8 >> 2]; + HEAP32[(x + 1 + y & MASK2) + 8 >> 2]; + HEAP32[(x + 8 + y & MASK2) + 4 >> 2]; + x(); + HEAPU32[x >> 2]; + HEAPU32[x + 1 >> 2]; + HEAPU32[(x & MASK2) + 4 >> 2]; + HEAPU32[(x + 1 & MASK2) + 4 >> 2]; + HEAPU32[(x + 4 & MASK2) + 4 >> 2]; + HEAPU32[(x + 1 + y & MASK2) + 4 >> 2]; + HEAPU32[(x + 4 + y & MASK2) + 4 >> 2]; + HEAPU32[(x + 1 + y & MASK2) + 8 >> 2]; + HEAPU32[(x + 4 + y & MASK2) + 8 >> 2]; + HEAPU32[(x + 1 + y & MASK2) + 8 >> 2]; + HEAPU32[(x + 8 + y & MASK2) + 4 >> 2]; + x(); + HEAPF32[x >> 2]; + HEAPF32[x + 1 >> 2]; + HEAPF32[(x & MASK2) + 4 >> 2]; + HEAPF32[(x + 1 & MASK2) + 4 >> 2]; + HEAPF32[(x + 4 & MASK2) + 4 >> 2]; + HEAPF32[(x + 1 + y & MASK2) + 4 >> 2]; + HEAPF32[(x + 4 + y & MASK2) + 4 >> 2]; + HEAPF32[(x + 1 + y & MASK2) + 8 >> 2]; + HEAPF32[(x + 4 + y & MASK2) + 8 >> 2]; + HEAPF32[(x + 1 + y & MASK2) + 8 >> 2]; + HEAPF32[(x + 8 + y & MASK2) + 4 >> 2]; + x(); + HEAPF64[x >> 3]; + HEAPF64[x + 1 >> 3]; + HEAPF64[(x & MASK3) + 8 >> 3]; + HEAPF64[(x + 1 & MASK3) + 8 >> 3]; + HEAPF64[(x + 8 & MASK3) + 8 >> 3]; + HEAPF64[(x + 1 + y & MASK3) + 8 >> 3]; + HEAPF64[(x + 8 + y & MASK3) + 8 >> 3]; + HEAPF64[(x + 1 + y & MASK3) + 16 >> 3]; + HEAPF64[(x + 8 + y & MASK3) + 16 >> 3]; + HEAPF64[(x + 1 + y & MASK3) + 16 >> 3]; + HEAPF64[(x + 16 + y & MASK3) + 8 >> 3]; +} + diff --git a/tools/test-js-optimizer-pointerMask.js b/tools/test-js-optimizer-pointerMask.js new file mode 100644 index 0000000000000..de5179bd0eeb3 --- /dev/null +++ b/tools/test-js-optimizer-pointerMask.js @@ -0,0 +1,73 @@ +function f() { + HEAP8[x >> 0]; + HEAP8[x + 1 >> 0]; + HEAP8[x + 2 >> 0]; + HEAP8[x + 2 + 1 >> 0]; + HEAP8[x + 2 + 2 >> 0]; + HEAP8[x + 2 + 1 + y >> 0]; + HEAP8[x + 2 + 2 + y >> 0]; + x(); + HEAP16[x >> 1]; + HEAP16[x + 1 >> 1]; + HEAP16[x + 2 >> 1]; + HEAP16[x + 2 + 1 >> 1]; + HEAP16[x + 2 + 2 >> 1]; + HEAP16[x + 2 + 1 + y >> 1]; + HEAP16[x + 2 + 2 + y >> 1]; + HEAP16[x + 4 + 1 + y >> 1]; + HEAP16[x + 4 + 2 + y >> 1]; + HEAP16[x + 1 + 4 + y >> 1]; + HEAP16[x + 2 + 4 + y >> 1]; + x(); + HEAP32[x >> 2]; + HEAP32[x + 1 >> 2]; + HEAP32[x + 2 >> 2]; + HEAP32[x + 3 >> 2]; + HEAP32[x + 4 >> 2]; + HEAP32[x + 4 + 1 >> 2]; + HEAP32[x + 4 + 4 >> 2]; + HEAP32[x + 4 + 1 + y >> 2]; + HEAP32[x + 4 + 4 + y >> 2]; + HEAP32[x + 8 + 1 + y >> 2]; + HEAP32[x + 8 + 4 + y >> 2]; + HEAP32[x + 1 + 8 + y >> 2]; + HEAP32[x + 4 + 8 + y >> 2]; + x(); + HEAPU32[x >> 2]; + HEAPU32[x + 1 >> 2]; + HEAPU32[x + 4 >> 2]; + HEAPU32[x + 4 + 1 >> 2]; + HEAPU32[x + 4 + 4 >> 2]; + HEAPU32[x + 4 + 1 + y >> 2]; + HEAPU32[x + 4 + 4 + y >> 2]; + HEAPU32[x + 8 + 1 + y >> 2]; + HEAPU32[x + 8 + 4 + y >> 2]; + HEAPU32[x + 1 + 8 + y >> 2]; + HEAPU32[x + 4 + 8 + y >> 2]; + x(); + HEAPF32[x >> 2]; + HEAPF32[x + 1 >> 2]; + HEAPF32[x + 4 >> 2]; + HEAPF32[x + 4 + 1 >> 2]; + HEAPF32[x + 4 + 4 >> 2]; + HEAPF32[x + 4 + 1 + y >> 2]; + HEAPF32[x + 4 + 4 + y >> 2]; + HEAPF32[x + 8 + 1 + y >> 2]; + HEAPF32[x + 8 + 4 + y >> 2]; + HEAPF32[x + 1 + 8 + y >> 2]; + HEAPF32[x + 4 + 8 + y >> 2]; + x(); + HEAPF64[x >> 3]; + HEAPF64[x + 1 >> 3]; + HEAPF64[x + 8 >> 3]; + HEAPF64[x + 8 + 1 >> 3]; + HEAPF64[x + 8 + 8 >> 3]; + HEAPF64[x + 8 + 1 + y >> 3]; + HEAPF64[x + 8 + 8 + y >> 3]; + HEAPF64[x + 16 + 1 + y >> 3]; + HEAPF64[x + 16 + 8 + y >> 3]; + HEAPF64[x + 1 + 16 + y >> 3]; + HEAPF64[x + 8 + 16 + y >> 3]; +} +// EMSCRIPTEN_GENERATED_FUNCTIONS + From 31e854935145e157424bdbbbb4fdae96c3c59fb3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 4 Sep 2014 15:04:05 -0700 Subject: [PATCH 31/37] text update --- .../text/docs/api_reference/emscripten.h.txt | 17 ++++++++--------- .../text/docs/api_reference/preamble.js.txt | 14 +++++++------- site/build/text/docs/tools_reference/emcc.txt | 9 --------- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/site/build/text/docs/api_reference/emscripten.h.txt b/site/build/text/docs/api_reference/emscripten.h.txt index 7af72fc63771a..3f440ff15d4fb 100644 --- a/site/build/text/docs/api_reference/emscripten.h.txt +++ b/site/build/text/docs/api_reference/emscripten.h.txt @@ -219,9 +219,9 @@ void emscripten_async_load_script(const char *script, em_callback_func onload, This integrates with the run dependencies system, so your script can call "addRunDependency" multiple times, prepare various asynchronous tasks, and call "removeRunDependency" on them; when - all are complete (or there were no run dependencies to begin with), - "onload" is called. An example use for this is to load an asset - module, that is, the output of the file packager. + all are complete (or if there were no run dependencies to begin + with), "onload" is called. An example use for this is to load an + asset module, that is, the output of the file packager. Parameters: * **script** (*const char**) -- The script to evaluate. @@ -242,7 +242,7 @@ Browser Execution Environment ============================= Guide material for the following APIs can be found in *Emscripten -browser environment (wiki-import)*. +Runtime Environment (wiki-import)*. Functions @@ -261,17 +261,16 @@ void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_in mechanism to call the main loop function. This is **HIGHLY** recommended if you are doing rendering, as the browser’s "requestAnimationFrame" will make sure you render at a proper - smooth rate that lines up with the the browser and monitor in a - proper way. (If you do not render at all in your application, then - you should pick a specific frame rate that makes sense for your - code.) + smooth rate that lines up properly with the the browser and + monitor. If you do not render at all in your application, then you + should pick a specific frame rate that makes sense for your code. If "simulate_infinite_loop" is true, the function will throw an exception in order to stop execution of the caller. This will lead to the main loop being entered instead of code after the call to "emscripten_set_main_loop()" being run, which is the closest we can get to simulating an infinite loop (we do something similar in - "glutMainLoop" in GLUT). If this parameter is "false", then the + glutMainLoop in GLUT). If this parameter is "false", then the behavior is the same as it was before this parameter was added to the API, which is that execution continues normally. Note that in both cases we do not run global destructors, "atexit", etc., since diff --git a/site/build/text/docs/api_reference/preamble.js.txt b/site/build/text/docs/api_reference/preamble.js.txt index 6e7f203a35bca..e11f74c0aa1b1 100644 --- a/site/build/text/docs/api_reference/preamble.js.txt +++ b/site/build/text/docs/api_reference/preamble.js.txt @@ -27,7 +27,7 @@ Table of Contents * Stack trace -* Type accessors for Typed Arrays Mode 2 +* Type accessors for the memory model Calling compiled C functions from JavaScript @@ -424,13 +424,13 @@ stackTrace() The current stack trace, if available. -Type accessors for Typed Arrays Mode 2 -====================================== +Type accessors for the memory model +=================================== -When using *Typed Arrays Mode 2* a typed array buffer ("ArrayBuffer") -is used to represent memory, with different views into it giving -access to the different types. The views for accessing different types -of memory are listed below. +The *Emscripten memory model* uses a typed array buffer +("ArrayBuffer") to represent memory, with different views into it +giving access to the different types. The views for accessing +different types of memory are listed below. HEAP8 diff --git a/site/build/text/docs/tools_reference/emcc.txt b/site/build/text/docs/tools_reference/emcc.txt index 0ea966ec6a461..19f49d6ce9c82 100644 --- a/site/build/text/docs/tools_reference/emcc.txt +++ b/site/build/text/docs/tools_reference/emcc.txt @@ -157,15 +157,6 @@ Options that are modified or new in *emcc* are listed below: happens in "-O2" and above, and when no "-g" option was specified to prevent minification. -"--typed-arrays " - Set the *typed array mode*. Possible values are: - - * "0": No typed arrays. - - * "1": Parallel typed arrays. - - * "2": Shared (C-like) typed arrays (default). - "--js-opts " Enables JavaScript optimizations. Possible "level" values are: From 3df4f884526bf92d7d11457de9b62772b2e62ac1 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 5 Sep 2014 10:37:44 -0700 Subject: [PATCH 32/37] fix bad comparison in shell code, when Module.load is not present but Module.read is --- src/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell.js b/src/shell.js index b21331848e540..e536359199059 100644 --- a/src/shell.js +++ b/src/shell.js @@ -162,7 +162,7 @@ function globalEval(x) { throw 'NO_DYNAMIC_EXECUTION was set, cannot eval'; #endif } -if (!Module['load'] == 'undefined' && Module['read']) { +if (!Module['load'] && Module['read']) { Module['load'] = function load(f) { globalEval(Module['read'](f)); }; From fd1ce7035fa7f1af357b7edde5234d2b0c918fd6 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 Jul 2014 20:53:15 +0700 Subject: [PATCH 33/37] [tracing] Initial tracing API. This is used in conjunction with a collection & analysis server to analyze memory usage and other aspects of a program running under emscripten. --- site/source/docs/api_reference/index.rst | 4 + site/source/docs/api_reference/trace.h.rst | 396 +++++++++++++++++++++ src/library_trace.js | 255 +++++++++++++ system/include/emscripten/trace.h | 73 ++++ tests/core/test_tracing.in | 15 + tests/core/test_tracing.out | 5 + tests/test_core.py | 9 + 7 files changed, 757 insertions(+) create mode 100644 site/source/docs/api_reference/trace.h.rst create mode 100644 src/library_trace.js create mode 100644 system/include/emscripten/trace.h create mode 100644 tests/core/test_tracing.in create mode 100644 tests/core/test_tracing.out diff --git a/site/source/docs/api_reference/index.rst b/site/source/docs/api_reference/index.rst index da1d3d31ff5eb..d6ce62834c6d0 100644 --- a/site/source/docs/api_reference/index.rst +++ b/site/source/docs/api_reference/index.rst @@ -27,6 +27,9 @@ This section lists Emscripten's public API, organised by header file. At a very - :ref:`bind-h`: Embind API for binding C++ functions and classes so that they can be called from JavaScript in a natural way. +- :ref:`trace-h`: + A tracing API for doing memory usage analysis. + - :ref:`api-reference-advanced-apis`: APIs for advanced users/core developers. @@ -41,6 +44,7 @@ This section lists Emscripten's public API, organised by header file. At a very module val.h bind.h + trace.h advanced-apis diff --git a/site/source/docs/api_reference/trace.h.rst b/site/source/docs/api_reference/trace.h.rst new file mode 100644 index 0000000000000..c72f5615cbf64 --- /dev/null +++ b/site/source/docs/api_reference/trace.h.rst @@ -0,0 +1,396 @@ +.. _trace-h: + +======= +trace.h +======= + +The Emscripten tracing API provides some useful capabilities to better see +what is going on inside of your application, in particular with respect to +memory usage (which is otherwise not available to traditional browser +performance tools). + + +.. contents:: table of contents + :local: + :depth: 2 + +Usage +===== + +Initialization and Teardown +--------------------------- + +To initialize the tracing API, you call :c:func:`emscripten_trace_configure`: + +.. code-block:: c + + emscripten_trace_configure("http://127.0.0.1:5000/", "MyApplication"); + +If you have the concept of a username or have some other way to identify +a given user of the application, then passing that to the tracing API +can make it easier to identify sessions in the collector server: + +.. code-block:: c + + emscripten_trace_set_session_username(username); + +To shut it down at application exit, you simply call +:c:func:`emscripten_trace_close`: + +.. code-block:: c + + emscripten_trace_close(); + +Contexts +-------- + +Contexts are a way to tell the tracing API what part of your application +is currently running. Contexts are effectively maintained as a stack of +current contexts. + +A context might be something as big as "running physics" or as small +as "updating animations on entity X". + +The granularity of the context stack is up to the team instrumenting +their application. Some applications may find fine-grained contexts +more useful, while others are more comfortable with larger contexts. + +Rather than getting a stack trace on every tracing call, we can often +look at the current context stack and record that instead, which is +much cheaper. + +When contexts are fully implemented by the server, they will also be +used to track how much time is spent in each context (a primitive +profiling mechanism), as well as how much memory has been allocated +and freed while the context was active. This should help give a good +idea of which parts of your application are using more memory or +creating a lot of churn (and possibly heap fragmentation). + +Recording context entry and exit is simple: + +.. code-block:: c + + emscripten_trace_enter_context("Physics Update"); + ... + emscripten_trace_exit_context(); + +Frames +------ + +It is important to record where your frame or event loop begins +and ends. This allows the tracing API to perform useful additional +analysis. + +Noting the start of an event loop is as easy as: + +.. code-block:: c + + emscripten_trace_record_frame_start(); + +And noting the end of the event loop is just as easy: + +.. code-block:: c + + emscripten_trace_record_frame_end(); + +Annotating Allocations +---------------------- + +Each allocation and free operation should be recorded. Ideally, +the data type name will also be recorded. + +The easiest route to recording all allocation and free operations +will be to modify ``dlmalloc``. + +As for recording the data type name, after you've allocated the +memory, you can annotate the address: + +.. code-block:: c + + emscripten_trace_annotate_address_type(model, "UI::Model"); + +Overall Memory Usage +-------------------- + +Periodically, the overall heap layout and memory usage should +be reported to the trace API. + +This is done with 2 calls: + +.. code-block:: c + + emscripten_trace_report_memory_layout(); + emscripten_trace_report_off_heap_data(); + +Logging Messages +---------------- + +Messages can be logged and recorded via the Emscripten tracing API. +These messages can have both a channel and the actual message. The +channel name will help to categorize and filter messages within +the visualization interface. You should avoid allocating memory +on the heap while logging a message. + +.. code-block:: c + + emscripten_trace_log_message("Application", "Started"); + +Over time, the visualization interface will improve to help you +better correlate these log messages with other views, such as +memory usage over time. Logging messages for things that may +cause large amounts of memory activity, like loading a new +model or game asset, is very useful when analyzing memory +usage behavior patterns. + +Reporting Errors +---------------- + +Errors encountered by the application can be reported to the tracing +API as an ancillary service: + +.. code-block:: c + + emscripten_trace_report_error("Assertion failed: ..."); + +This feature is included as an indication of the future direction +of the Emscripten tracing API. + +Running the Server +================== + +... + +Design Notes +============ + +Client / Server Design +---------------------- + +The Emscripten tracing API gathers data from instrumented code and transmits +it to a collector server. The server also performs data analysis and +provides a web interface for viewing the collected data. + +This client / server design is intended to allow the tool to run without +interfering with the browser on lower-end hardware where memory might +be at a premium, like 32 bit Windows machines. + +This design also allows for a single server to be run to collect data +from a variety of clients. + +Data Batching +------------- + +Data is batched and sent to the server in chunks, roughly once or twice +per second. This avoids having to open a new connection to the server +for every single event being recorded. + +Do Not Perturb The Heap +----------------------- + +When using the Emscripten tracing API, you should be careful that you do +not perform operations that would perturb the heap. For example, you shouldn't +allocate a string to pass to :c:func:`emscripten_trace_log_message` as +that would result in the allocation being tracked and possibly +disturbing the behavior or results that you are trying to analyze. + +For this reason, the Emscripten tracing API also keeps all of its own +data off of the Emscripten heap and performs no writes to the Emscripten +heap. + +Functions +========= + +.. c:function:: void emscripten_trace_configure(const char *collector_url, const char *application) + + :param collector_url: The base URL for the collector server. + :type collector_url: const char* + :param application: The name of the application being traced. + :type application: const char* + :rtype: void + + Configure the connection to the collector server. + + This should be one of the very first things that is done after the + application has started. + + In most cases, the ``collector_url`` will be ``http://127.0.0.1:5000/``. + +.. c:function:: void emscripten_trace_set_enabled(bool enabled) + + :param enabled: Whether or not tracing is enabled. + :type enabled: bool + :rtype: void + + Set whether or not tracing is enabled. Using this option to disable + tracing will likely result in inaccurate data being collected about + memory usage. + +.. c:function:: void emscripten_trace_set_session_username(const char *username) + + :param username: The username of the person running the application. + :type username: const char* + :rtype: void + + This is useful when a collector server is being used by multiple + people and you want to be able to identify individual sessions + by a means other than their timestamped session ID. + + This can be set after tracing has already started, so it is fine + to set this after the user has gone through a login or authentication + process. + +.. c:function:: void emscripten_trace_record_frame_start(void) + + :rtype: void + + This should be called at the start of the frame / event loop. + + The current timestamp is associated with this data. + + The server uses this to track frame times (and therefore frames + per second), as well as accounting for memory operations that + happen during the frame processing. + +.. c:function:: void emscripten_trace_record_frame_end(void) + + :rtype: void + + This should be called at the end of the frame / event loop. + + The current timestamp is associated with this data. + + The server uses this to stop accruing memory operations and + elapsed time to the frame. + +.. c:function:: void emscripten_trace_log_message(const char *channel, const char *message) + + :param channel: The category of the timeline event being emitted. + :type channel: const char* + :param message: The description for the timeline event being emitted. + :type message: const char* + :rtype: void + + Record a log message. This is useful for noting events or actions + which have occurred which might be advantageous to have correlated + against memory usage or changes in frame rate. + + The current timestamp is associated with this data. + + *The server doesn't yet do enough with this data. This will improve + in the future.* + +.. c:function:: void emscripten_trace_report_error(const char *error) + + :param error: The error message being reported. + :type error: const char* + :rtype: void + + The API will obtain the current callstack and include that in the report + to the server. + + The current timestamp is associated with this data. + + This could be used for various things including capturing JavaScript and + web-worker errors, as well as failed assertions or other run-time errors + from within the C/C++ code. + +.. c:function:: void emscripten_trace_record_allocation(const void *address, int32_t size) + + :param address: Memory address which has been allocated. + :type address: void* + :param size: Size of the memory block allocated. + :type size: int32_t + :rtype: void + + This must be called for each and every memory allocation. The best place to + do this is within the ``dlmalloc`` implementation in Emscripten. + + The current timestamp is associated with this data. + +.. c:function:: void emscripten_trace_record_reallocation(const void *old_address, const void *new_address, int32_t size) + + :param old_address: Old address of the memory block which has been reallocated. + :type old_address: void* + :param new_address: New address of the memory block which has been reallocated. + :type new_address: void* + :param size: New size of the memory block reallocated. + :type size: int32_t + :rtype: void + + This must be called for each and every memory re-allocation. The best place to + do this is within the ``dlmalloc`` implementation in Emscripten. + + The current timestamp is associated with this data. + +.. c:function:: void emscripten_trace_record_free(const void *address) + + :param address: Memory address which is being freed. + :type address: void* + :rtype: void + + This must be called for each and every ``free`` operation. The best place + to do this is within the ``dlmalloc`` implementation in Emscripten. + + The current timestamp is associated with this data. + + It is also important that this not be called multiple times for a single + ``free`` operation. + +.. c:function:: void emscripten_trace_annotate_address_type(const void *address, const char *type) + + :param address: Memory address which should be annotated. + :type address: void* + :param type: The name of the data type being allocated. + :type type: const char* + :rtype: void + + Annotate an address with the name of the data type that is + stored there. This is used by the server to help breakdown + what is in memory. + +.. c:function:: void emscripten_trace_report_memory_layout(void) + + :rtype: void + + This should be called periodically to report the usage of the + normal Emscripten heap. This provides details of both the stack + and the dynamic memory usage as well as the total memory size. + + The current timestamp is associated with this data. + +.. c:function:: void emscripten_trace_report_off_heap_data(void) + + :rtype: void + + This should be called periodically to report memory usage that is + not part of the normal Emscripten heap. This is currently used + to report OpenAL memory usage. + + The current timestamp is associated with this data. + + *The server does not yet display this data.* + +.. c:function:: void emscripten_trace_enter_context(const char *name) + + :param name: Context name. + :type name: const char* + :rtype: void + + The current timestamp is associated with this data. + + *This is not yet used on the server side.* + +.. c:function:: void emscripten_trace_exit_context(void) + + :rtype: void + + The current timestamp is associated with this data. + + *This is not yet used on the server side.* + +.. c:function:: void emscripten_trace_close(void) + + :rtype: void + + This should be closed during application termination. It helps ensure + is flushed to the server and terminates the tracing code. diff --git a/src/library_trace.js b/src/library_trace.js new file mode 100644 index 0000000000000..791f99afd120a --- /dev/null +++ b/src/library_trace.js @@ -0,0 +1,255 @@ +var LibraryTracing = { + $EmscriptenTrace__deps: [ + 'emscripten_trace_js_configure', 'emscripten_trace_js_log_message', + 'emscripten_trace_js_enter_context', 'emscripten_trace_exit_context', + 'emscripten_get_now' + ], + $EmscriptenTrace__postset: 'EmscriptenTrace.init()', + $EmscriptenTrace: { + configured: false, + testing: false, + worker: null, + enabled: false, + + DATA_VERSION: 1, + + EVENT_ALLOCATE: 'allocate', + EVENT_ANNOTATE_TYPE: 'annotate-type', + EVENT_APPLICATION_NAME: 'application-name', + EVENT_ENTER_CONTEXT: 'enter-context', + EVENT_EXIT_CONTEXT: 'exit-context', + EVENT_FRAME_END: 'frame-end', + EVENT_FRAME_RATE: 'frame-rate', + EVENT_FRAME_START: 'frame-start', + EVENT_FREE: 'free', + EVENT_LOG_MESSAGE: 'log-message', + EVENT_MEMORY_LAYOUT: 'memory-layout', + EVENT_OFF_HEAP: 'off-heap', + EVENT_REALLOCATE: 'reallocate', + EVENT_REPORT_ERROR: 'report-error', + EVENT_SESSION_NAME: 'session-name', + EVENT_USER_NAME: 'user-name', + + init: function() { + Module['emscripten_trace_configure'] = _emscripten_trace_js_configure; + Module['emscripten_trace_log_message'] = _emscripten_trace_js_log_message; + Module['emscripten_trace_enter_context'] = _emscripten_trace_js_enter_context; + Module['emscripten_trace_exit_context'] = _emscripten_trace_exit_context; + }, + + // Work around CORS issues ... + loadWorkerViaXHR: function(url, ready, scope) { + var req = new XMLHttpRequest(); + req.addEventListener('load', function() { + var blob = new Blob([this.responseText], { type: 'text/javascript' }); + var worker = new Worker(window.URL.createObjectURL(blob)); + if (ready) { + ready.call(scope, worker); + } + }, req); + req.open("get", url, false); + req.send(); + }, + + configure: function(collector_url, application) { + EmscriptenTrace.now = _emscripten_get_now; + var now = new Date(); + var session_id = now.getTime().toString() + '_' + + Math.floor((Math.random() * 100) + 1).toString(); + EmscriptenTrace.loadWorkerViaXHR(collector_url + 'worker.js', function (worker) { + EmscriptenTrace.worker = worker; + EmscriptenTrace.worker.addEventListener('error', function (e) { + console.log('TRACE WORKER ERROR:'); + console.log(e); + }, false); + EmscriptenTrace.worker.postMessage({ 'cmd': 'configure', + 'data_version': EmscriptenTrace.DATA_VERSION, + 'session_id': session_id, + 'url': collector_url }); + EmscriptenTrace.configured = true; + EmscriptenTrace.enabled = true; + }); + EmscriptenTrace.post([EmscriptenTrace.EVENT_APPLICATION_NAME, application]); + EmscriptenTrace.post([EmscriptenTrace.EVENT_SESSION_NAME, now.toISOString()]); + }, + + configureForTest: function() { + EmscriptenTrace.testing = true; + EmscriptenTrace.enabled = true; + EmscriptenTrace.now = function() { return 0.0; }; + }, + + post: function(entry) { + if (EmscriptenTrace.configured && EmscriptenTrace.enabled) { + EmscriptenTrace.worker.postMessage({ 'cmd': 'post', + 'entry': entry }); + } else if (EmscriptenTrace.testing && EmscriptenTrace.enabled) { + Module.print('Tracing ' + entry); + } + }, + }, + + emscripten_trace_js_configure: function(collector_url, application) { + EmscriptenTrace.configure(collector_url, application); + }, + + emscripten_trace_configure: function(collector_url, application) { + EmscriptenTrace.configure(Pointer_stringify(collector_url), + Pointer_stringify(application)); + }, + + emscripten_trace_configure_for_test: function() { + EmscriptenTrace.configureForTest(); + }, + + emscripten_trace_set_enabled: function(enabled) { + EmscriptenTrace.enabled = !!enabled; + }, + + emscripten_trace_set_session_username: function(username) { + EmscriptenTrace.post(EmscriptenTrace.EVENT_USER_NAME, Pointer_stringify(username)); + }, + + emscripten_trace_record_frame_start: function() { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_FRAME_START, now]); + } + }, + + emscripten_trace_record_frame_end: function() { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_FRAME_END, now]); + } + }, + + emscripten_trace_js_log_message: function(channel, message) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_LOG_MESSAGE, now, + channel, message]); + } + }, + + emscripten_trace_log_message: function(channel, message) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_LOG_MESSAGE, now, + Pointer_stringify(channel), + Pointer_stringify(message)]); + } + }, + + emscripten_trace_report_error: function(error) { + var now = EmscriptenTrace.now(); + var callstack = (new Error).stack; + EmscriptenTrace.post([EmscriptenTrace.EVENT_REPORT_ERROR, now, + Pointer_stringify(error), callstack]); + }, + + emscripten_trace_record_allocation: function(address, size) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_ALLOCATE, + now, address, size]); + } + }, + + emscripten_trace_record_reallocation: function(old_address, new_address, size) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_REALLOCATE, + now, old_address, new_address, size]); + } + }, + + emscripten_trace_record_free: function(address) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_FREE, + now, address]); + } + }, + + emscripten_trace_annotate_address_type: function(address, type_name) { + if (EmscriptenTrace.enabled) { + EmscriptenTrace.post([EmscriptenTrace.EVENT_ANNOTATE_TYPE, address, + Pointer_stringify(type_name)]); + } + }, + + emscripten_trace_report_memory_layout: function() { + if (EmscriptenTrace.enabled) { + var memory_layout = { + 'static_base': STATIC_BASE, + 'static_top': STATICTOP, + 'stack_base': STACK_BASE, + 'stack_top': STACKTOP, + 'stack_max': STACK_MAX, + 'dynamic_base': DYNAMIC_BASE, + 'dynamic_top': DYNAMICTOP, + 'total_memory': TOTAL_MEMORY + }; + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_MEMORY_LAYOUT, + now, memory_layout]); + } + }, + + emscripten_trace_report_off_heap_data: function () { + function openal_audiodata_size() { + if (typeof AL == 'undefined' || !AL.currentContext) { + return 0; + } + var totalMemory = 0; + for (var i in AL.currentContext.buf) { + var buffer = AL.currentContext.buf[i]; + for (var channel = 0; channel < buffer.numberOfChannels; ++channel) { + totalMemory += buffer.getChannelData(channel).length * 4; + } + } + return totalMemory; + } + if (EmscriptenTrace.enabled) { + var off_heap_data = { + 'openal': openal_audiodata_size() + } + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_OFF_HEAP, now, off_heap_data]); + } + }, + + emscripten_trace_js_enter_context: function(name) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_ENTER_CONTEXT, + now, name]); + } + }, + + emscripten_trace_enter_context: function(name) { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_ENTER_CONTEXT, + now, Pointer_stringify(name)]); + } + }, + + emscripten_trace_exit_context: function() { + if (EmscriptenTrace.enabled) { + var now = EmscriptenTrace.now(); + EmscriptenTrace.post([EmscriptenTrace.EVENT_EXIT_CONTEXT, now]); + } + }, + + emscripten_trace_close: function() { + EmscriptenTrace.configured = false; + EmscriptenTrace.enabled = false; + EmscriptenTrace.worker.postMessage({ 'cmd': 'close' }); + EmscriptenTrace.worker = null; + }, +}; + +autoAddDeps(LibraryTracing, '$EmscriptenTrace'); +mergeInto(LibraryManager.library, LibraryTracing); diff --git a/system/include/emscripten/trace.h b/system/include/emscripten/trace.h new file mode 100644 index 0000000000000..e99294c158498 --- /dev/null +++ b/system/include/emscripten/trace.h @@ -0,0 +1,73 @@ +#ifndef __emscripten_trace__h__ +#define __emscripten_trace__h__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __EMSCRIPTEN_TRACING__ + +void emscripten_trace_configure(const char *collector_url, const char *application); + +void emscripten_trace_configure_for_test(void); + +void emscripten_trace_set_enabled(bool enabled); + +void emscripten_trace_set_session_username(const char *username); + +void emscripten_trace_record_frame_start(void); + +void emscripten_trace_record_frame_end(void); + +void emscripten_trace_log_message(const char *channel, const char *message); + +void emscripten_trace_report_error(const char *error); + +void emscripten_trace_record_allocation(const void *address, int32_t size); + +void emscripten_trace_record_reallocation(const void *old_address, const void *new_address, int32_t size); + +void emscripten_trace_record_free(const void *address); + +void emscripten_trace_annotate_address_type(const void *address, const char *type); + +void emscripten_trace_report_memory_layout(void); + +void emscripten_trace_report_off_heap_data(void); + +void emscripten_trace_enter_context(const char *name); + +void emscripten_trace_exit_context(void); + +void emscripten_trace_close(void); + +#else + +#define emscripten_trace_configure(collector_url, application) +#define emscripten_trace_configure_for_test() +#define emscripten_trace_set_enabled(enabled) +#define emscripten_trace_set_session_username(username) +#define emscripten_trace_record_frame_start() +#define emscripten_trace_record_frame_end() +#define emscripten_trace_log_message(channel, message) +#define emscripten_trace_report_error(error) +#define emscripten_trace_record_allocation(address, size) +#define emscripten_trace_record_reallocation(old_address, new_address, size) +#define emscripten_trace_record_free(address) +#define emscripten_trace_annotate_address_type(address, type) +#define emscripten_trace_report_memory_layout() +#define emscripten_trace_report_off_heap_data() +#define emscripten_trace_enter_context(name) +#define emscripten_trace_exit_context() +#define emscripten_trace_close() + +#endif + +#ifdef __cplusplus +} // ~extern "C" +#endif + +#endif // __emscripten_trace__h__ diff --git a/tests/core/test_tracing.in b/tests/core/test_tracing.in new file mode 100644 index 0000000000000..ef8fbe161ce85 --- /dev/null +++ b/tests/core/test_tracing.in @@ -0,0 +1,15 @@ +#include + +int main(int argc, const char* argv[]) { + + emscripten_trace_configure_for_test(); + + emscripten_trace_enter_context("Application Startup"); + emscripten_trace_log_message("Application", "starting up"); + emscripten_trace_exit_context(); + + emscripten_trace_record_frame_start(); + emscripten_trace_record_frame_end(); + + return 0; +} diff --git a/tests/core/test_tracing.out b/tests/core/test_tracing.out new file mode 100644 index 0000000000000..654cf7cd7f579 --- /dev/null +++ b/tests/core/test_tracing.out @@ -0,0 +1,5 @@ +Tracing enter-context,0,Application Startup +Tracing log-message,0,Application,starting up +Tracing exit-context,0 +Tracing frame-start,0 +Tracing frame-end,0 diff --git a/tests/test_core.py b/tests/test_core.py index e3f219a3cd8b2..b1a07bedd3fdc 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6023,6 +6023,15 @@ def test_demangle_stacks(self): self.do_run_from_file(src, output) + def test_tracing(self): + if self.emcc_args is None: return self.skip('requires emcc') + Building.COMPILER_TEST_OPTS += ['--tracing'] + + test_path = path_from_root('tests', 'core', 'test_tracing') + src, output = (test_path + s for s in ('.in', '.out')) + + self.do_run_from_file(src, output) + def test_embind(self): if self.emcc_args is None: return self.skip('requires emcc') Building.COMPILER_TEST_OPTS += ['--bind'] From 466e8715e7067ad90810f6afbcf13ddad14f365e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 15 Aug 2014 08:50:18 +0700 Subject: [PATCH 34/37] [tracing] Integrate the tracing stuff. --- emcc | 7 ++++++ site/source/docs/api_reference/trace.h.rst | 27 +++++++++++++++++++--- site/source/docs/tools_reference/emcc.rst | 3 +++ src/preamble.js | 13 +++++++++++ src/settings.js | 2 ++ tools/system_libs.py | 9 ++++++-- 6 files changed, 56 insertions(+), 5 deletions(-) diff --git a/emcc b/emcc index 1c0a0201f3700..f189374e801cd 100755 --- a/emcc +++ b/emcc @@ -391,6 +391,7 @@ try: debug_level = 0 requested_debug = '' profiling = False + tracing = False emit_symbol_map = False js_opts = None llvm_opts = None @@ -529,6 +530,12 @@ try: debug_level = 2 profiling = True newargs[i] = '' + elif newargs[i] == '--tracing': + tracing = True + newargs[i] = '' + newargs.append('-D__EMSCRIPTEN_TRACING__=1') + settings_changes.append("EMSCRIPTEN_TRACING=1") + js_libraries.append(shared.path_from_root('src', 'library_trace.js')) elif newargs[i] == '--emit-symbol-map': emit_symbol_map = True newargs[i] = '' diff --git a/site/source/docs/api_reference/trace.h.rst b/site/source/docs/api_reference/trace.h.rst index c72f5615cbf64..8cfe043adde46 100644 --- a/site/source/docs/api_reference/trace.h.rst +++ b/site/source/docs/api_reference/trace.h.rst @@ -17,6 +17,25 @@ performance tools). Usage ===== +Compiler Interaction +-------------------- + +When using the tracing API, you should pass ``--tracing`` to ``emcc``. This +will automatically include the ``library_trace.js`` library file as well as +set the preprocessor flag ``__EMSCRIPTEN_TRACING__``. If you are invoking +``clang`` directly to build your C / C++ code, then you will want to pass +``-D__EMSCRIPTEN_TRACING__`` when building code. When the preprocessor +flag ``__EMSCRIPTEN_TRACING__`` is not defined, the tracing API implementation +will be provided by inlined empty stubs. + +Also, since enabling tracing modifies the implementation of ``dlmalloc.c`` +in the ``libc`` implementation, it is advised that you manually clear your +cache before switching to using the tracing API. If you do not do this, then +you will not get full allocation details recorded. You can clear the cache +with this ``emcc`` command:: + + emcc --clear-cache + Initialization and Teardown --------------------------- @@ -97,10 +116,12 @@ Annotating Allocations ---------------------- Each allocation and free operation should be recorded. Ideally, -the data type name will also be recorded. +the data type name will also be recorded, but this must currently +be done manually. -The easiest route to recording all allocation and free operations -will be to modify ``dlmalloc``. +When building with ``--tracing`` and a cleared cache, the ``libc`` +that Emscripten builds will automatically record all calls to +``malloc``, ``realloc`` and ``free``. As for recording the data type name, after you've allocated the memory, you can annotate the address: diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index cde1766ab066b..a1b4b4877ab5e 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -115,6 +115,9 @@ Options that are modified or new in *emcc* are listed below: ``-profiling`` Use reasonable defaults when emitting JavaScript to make the build useful for profiling. This sets ``-g2`` (preserve function names) and may also enable optimizations that affect performance and otherwise might not be performed in ``-g2``. +``--tracing`` + Enable the Emscripten Tracing API. + ``--emit-symbol-map`` Save a map file between the minified global names and the original function names. This allows you, for example, to reconstruct meaningful stack traces. diff --git a/src/preamble.js b/src/preamble.js index a1b9befb2c2b6..1f8c1b2b0f28b 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -980,9 +980,22 @@ function enlargeMemory() { assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite #endif +#if EMSCRIPTEN_TRACING + var OLD_TOTAL_MEMORY = TOTAL_MEMORY; + // Report old layout one last time + _emscripten_trace_report_memory_layout(); +#endif + while (TOTAL_MEMORY <= DYNAMICTOP) { // Simple heuristic. TOTAL_MEMORY = alignMemoryPage(2*TOTAL_MEMORY); } + +#if EMSCRIPTEN_TRACING + _emscripten_trace_js_log_message("Emscripten", "Enlarging memory arrays from " + OLD_TOTAL_MEMORY + " to " + TOTAL_MEMORY); + // And now report the new layout + _emscripten_trace_report_memory_layout(); +#endif + assert(TOTAL_MEMORY <= Math.pow(2, 30)); // 2^30==1GB is a practical maximum - 2^31 is already close to possible negative numbers etc. #if USE_TYPED_ARRAYS == 2 var oldHEAP8 = HEAP8; diff --git a/src/settings.js b/src/settings.js index 256ab5ed694b8..1933561ede60b 100644 --- a/src/settings.js +++ b/src/settings.js @@ -562,6 +562,8 @@ var RUNNING_FASTCOMP = 1; // whether we are running the fastcomp backend var COMPILER_ASSERTIONS = 0; // costly (slow) compile-time assertions var COMPILER_FASTPATHS = 1; // use fast-paths to speed up compilation +var EMSCRIPTEN_TRACING = 0; // Add some calls to emscripten tracing APIs + // Compiler debugging options var DEBUG_TAGS_SHOWING = []; // Some useful items: diff --git a/tools/system_libs.py b/tools/system_libs.py index 53b77e3cfdced..dc90c2b5a04a1 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -27,6 +27,11 @@ def read_symbols(path, exclude=None): symbols = filter(lambda symbol: symbol not in exclude, symbols) return set(symbols) + default_opts = [] + # If we're building tracing, we should build the system libraries that way too. + if shared.Settings.EMSCRIPTEN_TRACING: + default_opts.append('--tracing') + # XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not # a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible. libc_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libc.symbols')) @@ -55,7 +60,7 @@ def build_libc(lib_filename, files, lib_opts): commands = [] for src in files: o = in_temp(os.path.basename(src) + '.o') - commands.append([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o] + musl_internal_includes + lib_opts) + commands.append([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o] + musl_internal_includes + default_opts + lib_opts) o_s.append(o) run_commands(commands) if prev_cxx: os.environ['EMMAKEN_CXX'] = prev_cxx @@ -68,7 +73,7 @@ def build_libcxx(src_dirname, lib_filename, files, lib_opts): for src in files: o = in_temp(src + '.o') srcfile = shared.path_from_root(src_dirname, src) - commands.append([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + lib_opts) + commands.append([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + default_opts + lib_opts) o_s.append(o) run_commands(commands) shared.Building.link(o_s, in_temp(lib_filename)) From 06606f99b3479d55c001d536a439fa50ef0f2731 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 15 Aug 2014 18:47:13 +0700 Subject: [PATCH 35/37] [tracing] Instrument dlmalloc.c These changes compile out entirely if tracing is not enabled. --- system/lib/dlmalloc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/system/lib/dlmalloc.c b/system/lib/dlmalloc.c index 04e9e47b60c23..86ea4156fbdb3 100644 --- a/system/lib/dlmalloc.c +++ b/system/lib/dlmalloc.c @@ -6,6 +6,8 @@ #define HAVE_MMAP 0 /* we can only grow the heap up anyhow, so don't try to trim */ #define MORECORE_CANNOT_TRIM 1 +/* XXX Emscripten Tracing API. This defines away the code if tracing is disabled. */ +#include #endif @@ -4683,6 +4685,10 @@ void* dlmalloc(size_t bytes) { postaction: POSTACTION(gm); +#if __EMSCRIPTEN__ + /* XXX Emscripten Tracing API. */ + emscripten_trace_record_allocation(mem, bytes); +#endif return mem; } @@ -4699,6 +4705,10 @@ void dlfree(void* mem) { */ if (mem != 0) { +#if __EMSCRIPTEN__ + /* XXX Emscripten Tracing API. */ + emscripten_trace_record_free(mem); +#endif mchunkptr p = mem2chunk(mem); #if FOOTERS mstate fm = get_mstate_for(p); @@ -5235,6 +5245,10 @@ void* dlrealloc(void* oldmem, size_t bytes) { } } } +#if __EMSCRIPTEN__ + /* XXX Emscripten Tracing API. */ + emscripten_trace_record_reallocation(oldmem, mem, bytes); +#endif } return mem; } From 5915cda1ca25b52bb4544c62887defcc12296098 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 5 Sep 2014 12:31:43 +0700 Subject: [PATCH 36/37] [trace] Point to the server's git repository. --- site/source/docs/api_reference/trace.h.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/site/source/docs/api_reference/trace.h.rst b/site/source/docs/api_reference/trace.h.rst index 8cfe043adde46..8b5ef38dc0b03 100644 --- a/site/source/docs/api_reference/trace.h.rst +++ b/site/source/docs/api_reference/trace.h.rst @@ -179,7 +179,8 @@ of the Emscripten tracing API. Running the Server ================== -... +* Obtain a copy of the `emscripten-trace-collector`_ server. +* Follow the directions in the `README.rst`. Design Notes ============ @@ -415,3 +416,6 @@ Functions This should be closed during application termination. It helps ensure is flushed to the server and terminates the tracing code. + +.. _emscripten-trace-collector: https://github.com/waywardmonkeys/emscripten-trace-collector +.. _README.rst: https://github.com/waywardmonkeys/emscripten-trace-collector/blob/master/README.rst From eff15fba84ccf37a5430e6c842f8bdc19d5ad842 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 6 Sep 2014 19:24:56 -0700 Subject: [PATCH 37/37] add glob, globfree in musl; 1.23.3 --- emscripten-version.txt | 2 +- system/lib/libc/musl/src/regex/glob.c | 238 ++++++++++++++++++++++++++ system/lib/libcextra.symbols | 2 + tools/system_libs.py | 1 + 4 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 system/lib/libc/musl/src/regex/glob.c diff --git a/emscripten-version.txt b/emscripten-version.txt index 1a90c51133d32..14094f3776cc6 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.23.2 +1.23.3 diff --git a/system/lib/libc/musl/src/regex/glob.c b/system/lib/libc/musl/src/regex/glob.c new file mode 100644 index 0000000000000..6affee040c310 --- /dev/null +++ b/system/lib/libc/musl/src/regex/glob.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libc.h" + +struct match +{ + struct match *next; + char name[1]; +}; + +static int is_literal(const char *p, int useesc) +{ + int bracket = 0; + for (; *p; p++) { + switch (*p) { + case '\\': + if (!useesc) break; + case '?': + case '*': + return 0; + case '[': + bracket = 1; + break; + case ']': + if (bracket) return 0; + break; + } + } + return 1; +} + +static int append(struct match **tail, const char *name, size_t len, int mark) +{ + struct match *new = malloc(sizeof(struct match) + len + 1); + if (!new) return -1; + (*tail)->next = new; + new->next = NULL; + strcpy(new->name, name); + if (mark) strcat(new->name, "/"); + *tail = new; + return 0; +} + +static int match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail) +{ + DIR *dir; + struct dirent de_buf, *de; + char pat[strlen(p)+1]; + char *p2; + size_t l = strlen(d); + int literal; + int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) + | ((!(flags & GLOB_PERIOD)) ? FNM_PERIOD : 0); + int error; + + if ((p2 = strchr(p, '/'))) { + strcpy(pat, p); + pat[p2-p] = 0; + for (; *p2 == '/'; p2++); + p = pat; + } + literal = is_literal(p, !(flags & GLOB_NOESCAPE)); + if (*d == '/' && !*(d+1)) l = 0; + + /* rely on opendir failing for nondirectory objects */ + dir = opendir(*d ? d : "."); + error = errno; + if (!dir) { + /* this is not an error -- we let opendir call stat for us */ + if (error == ENOTDIR) return 0; + if (error == EACCES && !*p) { + struct stat st; + if (!stat(d, &st) && S_ISDIR(st.st_mode)) { + if (append(tail, d, l, l)) + return GLOB_NOSPACE; + return 0; + } + } + if (errfunc(d, error) || (flags & GLOB_ERR)) + return GLOB_ABORTED; + return 0; + } + if (!*p) { + error = append(tail, d, l, l) ? GLOB_NOSPACE : 0; + closedir(dir); + return error; + } + while (!(error = readdir_r(dir, &de_buf, &de)) && de) { + char namebuf[l+de->d_reclen+2], *name = namebuf; + if (!literal && fnmatch(p, de->d_name, fnm_flags)) + continue; + if (literal && strcmp(p, de->d_name)) + continue; + if (p2 && de->d_type && !S_ISDIR(de->d_type<<12) && !S_ISLNK(de->d_type<<12)) + continue; + if (*d) { + memcpy(name, d, l); + name[l] = '/'; + strcpy(name+l+1, de->d_name); + } else { + name = de->d_name; + } + if (p2) { + if ((error = match_in_dir(name, p2, flags, errfunc, tail))) { + closedir(dir); + return error; + } + } else { + int mark = 0; + if (flags & GLOB_MARK) { + if (de->d_type && !S_ISLNK(de->d_type<<12)) + mark = S_ISDIR(de->d_type<<12); + else { + struct stat st; + stat(name, &st); + mark = S_ISDIR(st.st_mode); + } + } + if (append(tail, name, l+de->d_reclen+1, mark)) { + closedir(dir); + return GLOB_NOSPACE; + } + } + } + closedir(dir); + if (error && (errfunc(d, error) || (flags & GLOB_ERR))) + return GLOB_ABORTED; + return 0; +} + +static int ignore_err(const char *path, int err) +{ + return 0; +} + +static void freelist(struct match *head) +{ + struct match *match, *next; + for (match=head->next; match; match=next) { + next = match->next; + free(match); + } +} + +static int sort(const void *a, const void *b) +{ + return strcmp(*(const char **)a, *(const char **)b); +} + +int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, int err), glob_t *restrict g) +{ + const char *p=pat, *d; + struct match head = { .next = NULL }, *tail = &head; + size_t cnt, i; + size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0; + int error = 0; + + if (*p == '/') { + for (; *p == '/'; p++); + d = "/"; + } else { + d = ""; + } + + if (strlen(p) > PATH_MAX) return GLOB_NOSPACE; + + if (!errfunc) errfunc = ignore_err; + + if (!(flags & GLOB_APPEND)) { + g->gl_offs = offs; + g->gl_pathc = 0; + g->gl_pathv = NULL; + } + + if (*p) error = match_in_dir(d, p, flags, errfunc, &tail); + if (error == GLOB_NOSPACE) { + freelist(&head); + return error; + } + + for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++); + if (!cnt) { + if (flags & GLOB_NOCHECK) { + tail = &head; + if (append(&tail, pat, strlen(pat), 0)) + return GLOB_NOSPACE; + cnt++; + } else + return GLOB_NOMATCH; + } + + if (flags & GLOB_APPEND) { + char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *)); + if (!pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + g->gl_pathv = pathv; + offs += g->gl_pathc; + } else { + g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *)); + if (!g->gl_pathv) { + freelist(&head); + return GLOB_NOSPACE; + } + for (i=0; igl_pathv[i] = NULL; + } + for (i=0, tail=head.next; inext, i++) + g->gl_pathv[offs + i] = tail->name; + g->gl_pathv[offs + i] = NULL; + g->gl_pathc += cnt; + + if (!(flags & GLOB_NOSORT)) + qsort(g->gl_pathv+offs, cnt, sizeof(char *), sort); + + return error; +} + +void globfree(glob_t *g) +{ + size_t i; + for (i=0; igl_pathc; i++) + free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name)); + free(g->gl_pathv); + g->gl_pathc = 0; + g->gl_pathv = NULL; +} + +LFS64(glob); +LFS64(globfree); diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols index 0567848e0388d..15983edf3f54c 100644 --- a/system/lib/libcextra.symbols +++ b/system/lib/libcextra.symbols @@ -39,6 +39,8 @@ T getopt T getopt_long T getopt_long_only + T glob + T globfree T iconv T iconv_close T iconv_open diff --git a/tools/system_libs.py b/tools/system_libs.py index dc90c2b5a04a1..67e2f76dde09f 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -306,6 +306,7 @@ def create_libcextra(): ]], ['regex', [ 'fnmatch.c', + 'glob.c', 'regcomp.c', 'regerror.c', 'regexec.c',