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
llvm and binaryen now default to enabling sign-ext and mutable-globals
by default. See https://reviews.llvm.org/D125728.

In order to allow users to continue to target older browsers we will
now lower sign-ext operations in a binaryen pass if the target browsers
don't support it.
  • Loading branch information
sbc100 committed Nov 15, 2022
1 parent 20d8117 commit c530c66
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
8 changes: 8 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from tools import wasm2c
from tools import webassembly
from tools import config
from tools import feature_matrix
from tools.settings import user_settings, settings, MEM_SIZE_SETTINGS, COMPILE_TIME_SETTINGS
from tools.utils import read_file, write_file, read_binary, delete_file

Expand Down Expand Up @@ -613,6 +614,13 @@ def get_binaryen_passes():
passes += ['--safe-heap']
if settings.MEMORY64 == 2:
passes += ['--memory64-lowering']
# sign-ext is enabled by default by llvm. If the target browser settings don't support
# this we lower it away here using a binaryen pass.
if not feature_matrix.caniuse(feature_matrix.Feature.SIGN_EXT):
logger.debug('lowering sign-ext proposal due to incompatiable target browser engines')
passes += ['--signext-lowering']
if settings.MEMORY64 == 2:
passes += ['--memory64-lowering']
if optimizing:
passes += ['--post-emscripten']
if optimizing:
Expand Down
6 changes: 6 additions & 0 deletions test/other/test_signext_lowering.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>
#include <stdint.h>

int main(int argc, char* argv[]) {
printf("%lld\n", (int64_t)argc);
}
19 changes: 19 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -12724,3 +12724,22 @@ def test_reproduce(self):
response = response.replace('\\', '/')
response = response.replace(root, '<root>')
self.assertTextDataIdentical(expected, response)

def test_signext_lowering(self):
cmd = [EMCC, test_file('other/test_signext_lowering.c'), '-sWASM_BIGINT', '-sMIN_EDGE_VERSION=0x7fffffff']

# We expect ERROR_ON_WASM_CHANGES_AFTER_LINK to fail due lowering of sign-ext being
# required for safary 12.
output = self.expect_fail(cmd + ['-sERROR_ON_WASM_CHANGES_AFTER_LINK', '-sMIN_SAFARI_VERSION=120000'])
self.assertContained('error: changes to the wasm are required after link, but disallowed by ERROR_ON_WASM_CHANGES_AFTER_LINK', output)
self.assertContained('--signext-lowering', output)

# Running the same command with safary 14.1 should succeed because no lowering
# is required.
self.run_process(cmd + ['-sERROR_ON_WASM_CHANGES_AFTER_LINK', '-sMIN_SAFARI_VERSION=140100'])
self.assertEqual('1\n', self.run_js('a.out.js'))

# Running without ERROR_ON_WASM_CHANGES_AFTER_LINK but with safari 12
# should successfully lower sign-ext.
self.run_process(cmd + ['-sMIN_SAFARI_VERSION=120000', '-o', 'lowered.js'])
self.assertEqual('1\n', self.run_js('lowered.js'))
60 changes: 60 additions & 0 deletions tools/feature_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 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 webassembly features."""

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()


default_features = {Feature.SIGN_EXT, Feature.MUTABLE_GLOBALS}

min_browser_versions = {
Feature.NON_TRAPPING_FPTOINT: {
'chrome': 75,
'firefox': 65,
'safari': 150000,
},
Feature.SIGN_EXT: {
'chrome': 74,
'firefox': 62,
'safari': 140100,
},
Feature.BULK_MEMORY: {
'chrome': 75,
'firefox': 79,
'safari': 150000,
},
Feature.MUTABLE_GLOBALS: {
'chrome': 74,
'firefox': 61,
'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

0 comments on commit c530c66

Please sign in to comment.