Skip to content

Commit

Permalink
Add implicit wasm feature disabling based on min browser versions
Browse files Browse the repository at this point in the history
With https://reviews.llvm.org/D125728 about to land in LLVM we have four
features which will be enabled by default.  In order to allow users to
continue to target older browsers we want to turn these features off by
default when users opt into older browser support.
  • Loading branch information
sbc100 committed Aug 19, 2022
1 parent 3a32a77 commit 722187e
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 2 deletions.
3 changes: 2 additions & 1 deletion emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from tools import wasm2c
from tools import webassembly
from tools import config
from tools import feature_matrix
from tools.settings import settings, MEM_SIZE_SETTINGS, COMPILE_TIME_SETTINGS
from tools.utils import read_file, write_file, read_binary

Expand Down Expand Up @@ -829,7 +830,7 @@ def get_target_flags():


def get_clang_flags(user_args):
flags = get_target_flags()
flags = get_target_flags() + feature_matrix.get_feature_flags()

# if exception catching is disabled, we can prevent that code from being
# generated in the frontend
Expand Down
26 changes: 25 additions & 1 deletion test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -10612,14 +10612,38 @@ def fail(args, details):
def test_output_to_nowhere(self):
self.run_process([EMXX, test_file('hello_world.cpp'), '-o', os.devnull, '-c'])

# Test that passing -sMIN_X_VERSION=-1 on the command line will result in browser X being not supported at all.
# Test that passing -sMIN_X_VERSION=-1 on the command line will result in browser X being not
# supported at all.
# I.e. -sMIN_X_VERSION=-1 is equal to -sMIN_X_VERSION=Infinity
def test_drop_support_for_browser(self):
# Test that -1 means "not supported"
self.run_process([EMCC, test_file('test_html5_core.c'), '-sMIN_IE_VERSION=-1'])
self.assertContained('allowsDeferredCalls: true', read_file('a.out.js'))
self.assertNotContained('allowsDeferredCalls: JSEvents.isInternetExplorer()', read_file('a.out.js'))

def test_browser_version_auto_features(self):
def get_enabled_features(filename):
with webassembly.Module(filename) as o:
features = o.parse_features_section()
return [x[1] for x in features if x[0] == '+']

# By default we expect to see some features disabled since our min browser versions
# don't allow them.
self.run_process([EMCC, '-mcpu=bleeding-edge', '-c', test_file('hello_world.c')])
enabled = get_enabled_features('hello_world.o')
self.assertNotContained('nontrapping-fptoint', enabled)
self.assertNotContained('mutable-globals', enabled)

# If we not disable all support for Edge/Safari/Firefox those feature should now be
# enabled by the -mcpu=bleeding-edge.
self.run_process([EMCC, '-mcpu=bleeding-edge', '-c', test_file('hello_world.c'),
'-sMIN_EDGE_VERSION=-1',
'-sMIN_SAFARI_VERSION=-1',
'-sMIN_FIREFOX_VERSION=-1'])
enabled = get_enabled_features('hello_world.o')
self.assertContained('nontrapping-fptoint', enabled)
self.assertContained('mutable-globals', enabled)

def test_errno_type(self):
create_file('errno_type.c', '''
#include <errno.h>
Expand Down
80 changes: 80 additions & 0 deletions tools/feature_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright 2022 The Emscripten Authors. All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License. Both these licenses can be
# found in the LICENSE file.

"""Utilities for mapping browser versions to llvm feature flags."""

import logging
from enum import IntEnum, auto

from .settings import settings

logger = logging.getLogger('feature_matrix')


class Feature(IntEnum):
NON_TRAPPING_FPTOINT = auto()
SIGN_EXT = auto()
BULK_MEMORY = auto()
MUTABLE_GLOBALS = auto()


min_browser_versions = {
Feature.NON_TRAPPING_FPTOINT: {
'chrome': 75,
'firefox': 65,
'safari': 150000,
},
Feature.SIGN_EXT: {
'chrome': 74,
'firefox': 62,
'safari': 141000,
},
Feature.BULK_MEMORY: {
'chrome': 75,
'firefox': 79,
'safari': 150000,
},
Feature.MUTABLE_GLOBALS: {
'chrome': 74,
'firefox': -1, # Firefox has always supported mutable globals apparently
'safari': 120000,
},
}


def caniuse(feature):
min_versions = min_browser_versions[feature]
if settings.MIN_CHROME_VERSION < min_versions['chrome']:
return False
if settings.MIN_FIREFOX_VERSION < min_versions['firefox']:
return False
if settings.MIN_SAFARI_VERSION < min_versions['safari']:
return False
# IE and Edge don't support any non-MVP features
if settings.MIN_IE_VERSION != 0x7FFFFFFF or settings.MIN_EDGE_VERSION != 0x7FFFFFFF:
return False
return True


def get_feature_flags():
flags = []

if not caniuse(Feature.NON_TRAPPING_FPTOINT):
logger.debug('adding -mno-nontrapping-fptoint due to target browser selection')
flags.append('-mno-nontrapping-fptoint')

if not caniuse(Feature.SIGN_EXT):
logger.debug('adding -mnosign-ext due to target browser selection')
flags.append('-mno-sign-ext')

if not caniuse(Feature.BULK_MEMORY):
logger.debug('adding -mnobulk-memory due to target browser selection')
flags.append('-mno-bulk-memory')

if not caniuse(Feature.MUTABLE_GLOBALS):
logger.debug('adding -mnomutable-globals due to target browser selection')
flags.append('-mno-mutable-globals')

return flags
7 changes: 7 additions & 0 deletions tools/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
'WASM_OBJECT_FILES',
'WASM_WORKERS',

# These are needed at compile time to calulate feature flags
'MIN_CHROME_VERSION',
'MIN_FIREFOX_VERSION',
'MIN_SAFARI_VERSION',
'MIN_IE_VERSION',
'MIN_EDGE_VERSION',

# Internal settings used during compilation
'EXCEPTION_CATCHING_ALLOWED',
'WASM_EXCEPTIONS',
Expand Down

0 comments on commit 722187e

Please sign in to comment.