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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 8 additions & 29 deletions src/ir/module-splitting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@
// 2. It assumes that either all table segment offsets are constants or there
// is exactly one segment that may have a non-constant offset. It also
// assumes that all segments are active segments.

//
// 3. It assumes that if exact function references are required for validity
// (because they are stored in a local with an exact function type, for
// example), then custom descriptors are allowed so primary functions can
// be imported exactly. This could be worked around by removing exactness
// from the IR before splitting.
//
#include "ir/module-splitting.h"
#include "asmjs/shared-constants.h"
#include "ir/export-utils.h"
Expand Down Expand Up @@ -341,7 +347,6 @@ struct ModuleSplitter {
void setupTablePatching();
void shareImportableItems();
void removeUnusedSecondaryElements();
void updateIR();

ModuleSplitter(Module& primary, const Config& config)
: config(config), primary(primary), tableManager(primary),
Expand All @@ -358,7 +363,6 @@ struct ModuleSplitter {
setupTablePatching();
shareImportableItems();
removeUnusedSecondaryElements();
updateIR();
}
};

Expand Down Expand Up @@ -520,7 +524,7 @@ void ModuleSplitter::exportImportFunction(Name funcName,
func->hasExplicitName = primaryFunc->hasExplicitName;
func->module = config.importNamespace;
func->base = exportName;
func->type = func->type.with(Inexact);
func->type = func->type.withInexactIfNoCustomDescs(secondary->features);
secondary->addFunction(std::move(func));
}
}
Expand Down Expand Up @@ -981,31 +985,6 @@ void ModuleSplitter::removeUnusedSecondaryElements() {
}
}

void ModuleSplitter::updateIR() {
// Imported functions may need type updates.
struct Fixer : public PostWalker<Fixer> {
void visitRefFunc(RefFunc* curr) {
auto& wasm = *getModule();
auto* func = wasm.getFunction(curr->func);
if (func->type != curr->type) {
// This became an import, and lost exactness.
assert(!func->type.isExact());
assert(curr->type.isExact());
if (wasm.features.hasCustomDescriptors()) {
// Add a cast, as the parent may depend on the exactness to validate.
// TODO: The cast may be needed even without CD enabled
replaceCurrent(Builder(wasm).makeRefCast(curr, curr->type));
}
curr->type = curr->type.with(Inexact);
}
}
} fixer;
fixer.walkModule(&primary);
for (auto& secondaryPtr : secondaries) {
fixer.walkModule(secondaryPtr.get());
}
}

} // anonymous namespace

Results splitFunctions(Module& primary, const Config& config) {
Expand Down
6 changes: 5 additions & 1 deletion src/ir/module-splitting.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@
// functions. The secondary module imports all of its dependencies from the
// primary module.
//
// This code currently makes a couple assumptions about the modules that will be
// This code currently makes a few assumptions about the modules that will be
// split and will fail assertions if those assumptions are not true.
//
// 1) It assumes that mutable-globals are allowed.
//
// 2) It assumes that either all segment offsets are constants or there is
// exactly one segment that may have a non-constant offset.
//
// 3) It assumes that exact function references are only required for validity
// if custom descriptors (and its exact function import feature) are
// allowed.
//
// These requirements will be relaxed as necessary in the future, but for now
// this code should be considered experimental and used with care.

Expand Down
6 changes: 3 additions & 3 deletions test/example/module-splitting.txt
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ Secondary:
(module
(type $0 (func))
(import "primary" "%table" (table $0 1 funcref))
(import "primary" "%foo_1" (func $foo (type $0)))
(import "primary" "%foo_1" (func $foo (exact (type $0))))
(elem $0 (i32.const 0) $bar)
(func $bar (type $0)
(call $foo)
Expand Down Expand Up @@ -1055,7 +1055,7 @@ Secondary:
(module
(type $0 (func))
(import "primary" "%table_2" (table $0 1 funcref))
(import "primary" "%foo" (func $foo (type $0)))
(import "primary" "%foo" (func $foo (exact (type $0))))
(elem $0 (i32.const 0) $bar)
(func $bar (type $0)
(call $foo)
Expand Down Expand Up @@ -1102,7 +1102,7 @@ Secondary:
(module
(type $0 (func (param i32) (result i32)))
(import "primary" "%table_2" (table $0 1 funcref))
(import "primary" "%foo" (func $foo (type $0) (param i32) (result i32)))
(import "primary" "%foo" (func $foo (exact (type $0) (param i32) (result i32))))
(elem $0 (i32.const 0) $bar)
(func $bar (type $0) (param $0 i32) (result i32)
(call $foo
Expand Down
6 changes: 2 additions & 4 deletions test/lit/wasm-split/exact.wast
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@

;; SECONDARY: (import "primary" "table" (table $timport$0 1 funcref))

;; SECONDARY: (import "primary" "foo" (func $foo (type $0)))
;; SECONDARY: (import "primary" "foo" (func $foo (exact (type $0))))

;; SECONDARY: (elem $0 (i32.const 0) $bar)

Expand All @@ -82,9 +82,7 @@
;; SECONDARY: (func $bar (type $0)
;; SECONDARY-NEXT: (local $exact (ref (exact $0)))
;; SECONDARY-NEXT: (local.set $exact
;; SECONDARY-NEXT: (ref.cast (ref (exact $0))
;; SECONDARY-NEXT: (ref.func $foo)
;; SECONDARY-NEXT: )
;; SECONDARY-NEXT: (ref.func $foo)
;; SECONDARY-NEXT: )
;; SECONDARY-NEXT: (local.set $exact
;; SECONDARY-NEXT: (ref.func $bar)
Expand Down
36 changes: 12 additions & 24 deletions test/lit/wasm-split/multi-split-escape-names.wast
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@

;; MOD1: (import "primary" "table" (table $timport$0 3 funcref))

;; MOD1: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (result f32)))
;; MOD1: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (exact (result f32))))

;; MOD1: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (result i64)))
;; MOD1: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (exact (result i64))))

;; MOD1: (elem $0 (i32.const 2) $wasm::Type::getFeatures\28\29\20const)

Expand All @@ -38,16 +38,12 @@
;; MOD1-NEXT: )
;; MOD1-NEXT: (drop
;; MOD1-NEXT: (call_ref $1
;; MOD1-NEXT: (ref.cast (ref (exact $1))
;; MOD1-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
;; MOD1-NEXT: )
;; MOD1-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
;; MOD1-NEXT: )
;; MOD1-NEXT: )
;; MOD1-NEXT: (drop
;; MOD1-NEXT: (call_ref $0
;; MOD1-NEXT: (ref.cast (ref (exact $0))
;; MOD1-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
;; MOD1-NEXT: )
;; MOD1-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
;; MOD1-NEXT: )
;; MOD1-NEXT: )
;; MOD1-NEXT: (i32.const 0)
Expand Down Expand Up @@ -79,18 +75,16 @@

;; MOD2: (import "primary" "table" (table $timport$0 3 funcref))

;; MOD2: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (result f32)))
;; MOD2: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (exact (result f32))))

;; MOD2: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (result i32)))
;; MOD2: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (exact (result i32))))

;; MOD2: (elem $0 (i32.const 0) $wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)

;; MOD2: (func $wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (result i64)
;; MOD2-NEXT: (drop
;; MOD2-NEXT: (call_ref $1
;; MOD2-NEXT: (ref.cast (ref (exact $1))
;; MOD2-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
;; MOD2-NEXT: )
;; MOD2-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
;; MOD2-NEXT: )
;; MOD2-NEXT: )
;; MOD2-NEXT: (drop
Expand All @@ -100,9 +94,7 @@
;; MOD2-NEXT: )
;; MOD2-NEXT: (drop
;; MOD2-NEXT: (call_ref $0
;; MOD2-NEXT: (ref.cast (ref (exact $0))
;; MOD2-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
;; MOD2-NEXT: )
;; MOD2-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
;; MOD2-NEXT: )
;; MOD2-NEXT: )
;; MOD2-NEXT: (i64.const 0)
Expand Down Expand Up @@ -134,25 +126,21 @@

;; MOD3: (import "primary" "table" (table $timport$0 3 funcref))

;; MOD3: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (result i64)))
;; MOD3: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (exact (result i64))))

;; MOD3: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (result i32)))
;; MOD3: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (exact (result i32))))

;; MOD3: (elem $0 (i32.const 1) $std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)

;; MOD3: (func $std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (result f32)
;; MOD3-NEXT: (drop
;; MOD3-NEXT: (call_ref $1
;; MOD3-NEXT: (ref.cast (ref (exact $1))
;; MOD3-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
;; MOD3-NEXT: )
;; MOD3-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
;; MOD3-NEXT: )
;; MOD3-NEXT: )
;; MOD3-NEXT: (drop
;; MOD3-NEXT: (call_ref $0
;; MOD3-NEXT: (ref.cast (ref (exact $0))
;; MOD3-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
;; MOD3-NEXT: )
;; MOD3-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
;; MOD3-NEXT: )
;; MOD3-NEXT: )
;; MOD3-NEXT: (drop
Expand Down
Loading
Loading