2017-08-29 13:53:48 +00:00
|
|
|
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
// Flags: --expose-wasm
|
|
|
|
|
|
|
|
load('test/mjsunit/wasm/wasm-module-builder.js');
|
|
|
|
|
|
|
|
let initialMemoryPages = 1;
|
|
|
|
let maximumMemoryPages = 5;
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
let other_fn_idx = 0;
|
2017-08-29 13:53:48 +00:00
|
|
|
|
|
|
|
// This builder can be used to generate a module with memory + load/store
|
|
|
|
// functions and/or an additional imported function.
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
function generateBuilder(add_memory, import_sig) {
|
2017-08-29 13:53:48 +00:00
|
|
|
let builder = new WasmModuleBuilder();
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
if (import_sig) {
|
2017-08-29 13:53:48 +00:00
|
|
|
// Add the import if we expect a module builder with imported functions.
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
let idx = builder.addImport('import_module', 'other_module_fn', import_sig);
|
2017-08-29 13:53:48 +00:00
|
|
|
// The imported function should always have index 0. With this assertion we
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
// verify that we can use other_fn_idx to refer to this function.
|
|
|
|
assertEquals(idx, other_fn_idx)
|
2017-08-29 13:53:48 +00:00
|
|
|
}
|
|
|
|
if (add_memory) {
|
|
|
|
// Add the memory if we expect a module builder with memory and load/store.
|
|
|
|
builder.addMemory(initialMemoryPages, maximumMemoryPages, true);
|
|
|
|
builder.addFunction('load', kSig_i_i)
|
|
|
|
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
|
|
|
|
.exportFunc();
|
|
|
|
builder.addFunction('store', kSig_i_ii)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, kExprGetLocal, 1, kExprI32StoreMem, 0, 0,
|
|
|
|
kExprGetLocal, 1
|
|
|
|
])
|
|
|
|
.exportFunc();
|
|
|
|
}
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
2017-10-16 08:49:45 +00:00
|
|
|
function assertMemoryIndependence(load_a, store_a, load_b, store_b) {
|
|
|
|
|
|
|
|
assertEquals(0, load_a(0));
|
|
|
|
assertEquals(0, load_b(0));
|
|
|
|
assertEquals(0, load_a(4));
|
|
|
|
assertEquals(0, load_b(4));
|
|
|
|
|
|
|
|
store_a(0, 101);
|
|
|
|
assertEquals(101, load_a(0));
|
|
|
|
assertEquals(0, load_b(0));
|
|
|
|
assertEquals(0, load_a(4));
|
|
|
|
assertEquals(0, load_b(4));
|
|
|
|
|
|
|
|
store_a(4, 102);
|
|
|
|
assertEquals(101, load_a(0));
|
|
|
|
assertEquals(0, load_b(0));
|
|
|
|
assertEquals(102, load_a(4));
|
|
|
|
assertEquals(0, load_b(4));
|
|
|
|
|
|
|
|
store_b(0, 103);
|
|
|
|
assertEquals(101, load_a(0));
|
|
|
|
assertEquals(103, load_b(0));
|
|
|
|
assertEquals(102, load_a(4));
|
|
|
|
assertEquals(0, load_b(4));
|
|
|
|
|
|
|
|
store_b(4, 107);
|
|
|
|
assertEquals(101, load_a(0));
|
|
|
|
assertEquals(103, load_b(0));
|
|
|
|
assertEquals(102, load_a(4));
|
|
|
|
assertEquals(107, load_b(4));
|
|
|
|
|
|
|
|
store_a(0, 0);
|
|
|
|
store_a(4, 0);
|
|
|
|
store_b(0, 0);
|
|
|
|
store_b(4, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// A simple test for memory-independence between modules.
|
|
|
|
(function SimpleMemoryIndependenceTest() {
|
|
|
|
print("SimpleMemoryIndependenceTest");
|
|
|
|
let kPages = 1;
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
|
|
|
|
builder.addMemory(kPages, kPages, true);
|
|
|
|
builder.addFunction("store", kSig_v_ii)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // --
|
|
|
|
kExprGetLocal, 1, // --
|
|
|
|
kExprI32StoreMem, 0, 0, // --
|
|
|
|
]) // --
|
|
|
|
.exportFunc();
|
|
|
|
builder.addFunction("load", kSig_i_i)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // --
|
|
|
|
kExprI32LoadMem, 0, 0, // --
|
|
|
|
]) // --
|
|
|
|
.exportFunc();
|
|
|
|
|
|
|
|
var a = builder.instantiate();
|
|
|
|
|
|
|
|
// The {b} instance forwards all {store} calls to the imported function.
|
|
|
|
builder = new WasmModuleBuilder();
|
|
|
|
builder.addImport("mod", "store", kSig_v_ii);
|
|
|
|
builder.addMemory(kPages, kPages, true);
|
|
|
|
builder.addFunction("store", kSig_v_ii)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // --
|
|
|
|
kExprGetLocal, 1, // --
|
|
|
|
kExprCallFunction, 0, // --
|
|
|
|
]) // --
|
|
|
|
.exportFunc();
|
|
|
|
builder.addFunction("load", kSig_i_i)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // --
|
|
|
|
kExprI32LoadMem, 0, 0, // --
|
|
|
|
]) // --
|
|
|
|
.exportFunc();
|
|
|
|
|
|
|
|
var b = builder.instantiate({mod: {store: a.exports.store}});
|
|
|
|
|
|
|
|
assertEquals(0, a.exports.load(0));
|
|
|
|
assertEquals(0, b.exports.load(0));
|
|
|
|
assertEquals(0, a.exports.load(4));
|
|
|
|
assertEquals(0, b.exports.load(4));
|
|
|
|
|
|
|
|
a.exports.store(0, 101);
|
|
|
|
assertEquals(101, a.exports.load(0));
|
|
|
|
assertEquals(0, b.exports.load(0));
|
|
|
|
assertEquals(0, a.exports.load(4));
|
|
|
|
assertEquals(0, b.exports.load(4));
|
|
|
|
|
|
|
|
a.exports.store(4, 102);
|
|
|
|
assertEquals(101, a.exports.load(0));
|
|
|
|
assertEquals(0, b.exports.load(0));
|
|
|
|
assertEquals(102, a.exports.load(4));
|
|
|
|
assertEquals(0, b.exports.load(4));
|
|
|
|
|
|
|
|
b.exports.store(4, 107); // should forward to {a}.
|
|
|
|
assertEquals(101, a.exports.load(0));
|
|
|
|
assertEquals(0, b.exports.load(0));
|
|
|
|
assertEquals(107, a.exports.load(4));
|
|
|
|
assertEquals(0, b.exports.load(4));
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
2017-08-29 13:53:48 +00:00
|
|
|
// This test verifies that when a Wasm module without memory invokes a function
|
|
|
|
// imported from another module that has memory, the second module reads its own
|
|
|
|
// memory and returns the expected value.
|
|
|
|
(function TestExternalCallBetweenTwoWasmModulesWithoutAndWithMemory() {
|
|
|
|
print('TestExternalCallBetweenTwoWasmModulesWithoutAndWithMemory');
|
|
|
|
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
let first_module = generateBuilder(add_memory = false, import_sig = kSig_i_i);
|
2017-08-29 13:53:48 +00:00
|
|
|
// Function to invoke the imported function and add 1 to the result.
|
|
|
|
first_module.addFunction('plus_one', kSig_i_i)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // -
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
kExprCallFunction, other_fn_idx, // call the imported function
|
2017-08-29 13:53:48 +00:00
|
|
|
kExprI32Const, 1, // -
|
|
|
|
kExprI32Add, // add 1 to the result
|
|
|
|
kExprReturn // -
|
|
|
|
])
|
|
|
|
.exportFunc();
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
let second_module =
|
|
|
|
generateBuilder(add_memory = true, import_sig = undefined);
|
2017-08-29 13:53:48 +00:00
|
|
|
|
|
|
|
let index = kPageSize - 4;
|
|
|
|
let second_value = 2222;
|
|
|
|
// Instantiate the instances.
|
|
|
|
let second_instance = second_module.instantiate();
|
|
|
|
let first_instance = first_module.instantiate(
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
{import_module: {other_module_fn: second_instance.exports.load}});
|
2017-08-29 13:53:48 +00:00
|
|
|
// Write the values in the second instance.
|
|
|
|
second_instance.exports.store(index, second_value);
|
|
|
|
assertEquals(second_value, second_instance.exports.load(index));
|
|
|
|
// Verify that the value is correct when passing from the imported function.
|
|
|
|
assertEquals(second_value + 1, first_instance.exports.plus_one(index));
|
|
|
|
})();
|
|
|
|
|
|
|
|
// This test verifies that when a Wasm module with memory invokes a function
|
|
|
|
// imported from another module that also has memory, the second module reads
|
|
|
|
// its own memory and returns the expected value.
|
|
|
|
(function TestExternalCallBetweenTwoWasmModulesWithMemory() {
|
|
|
|
print('TestExternalCallBetweenTwoWasmModulesWithMemory');
|
|
|
|
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
let first_module = generateBuilder(add_memory = true, import_sig = kSig_i_i);
|
2017-08-29 13:53:48 +00:00
|
|
|
// Function to invoke the imported function and add 1 to the result.
|
|
|
|
first_module.addFunction('plus_one', kSig_i_i)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // -
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
kExprCallFunction, other_fn_idx, // call the imported function
|
2017-08-29 13:53:48 +00:00
|
|
|
kExprI32Const, 1, // -
|
|
|
|
kExprI32Add, // add 1 to the result
|
|
|
|
kExprReturn // -
|
|
|
|
])
|
|
|
|
.exportFunc();
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
let second_module =
|
|
|
|
generateBuilder(add_memory = true, import_sig = undefined);
|
2017-08-29 13:53:48 +00:00
|
|
|
|
|
|
|
let index = kPageSize - 4;
|
|
|
|
let first_value = 1111;
|
|
|
|
let second_value = 2222;
|
|
|
|
// Instantiate the instances.
|
|
|
|
let second_instance = second_module.instantiate();
|
|
|
|
let first_instance = first_module.instantiate(
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
{import_module: {other_module_fn: second_instance.exports.load}});
|
2017-08-29 13:53:48 +00:00
|
|
|
// Write the values in the two instances.
|
|
|
|
first_instance.exports.store(index, first_value);
|
|
|
|
second_instance.exports.store(index, second_value);
|
|
|
|
// Verify that the values were stored to memory.
|
|
|
|
assertEquals(first_value, first_instance.exports.load(index));
|
|
|
|
assertEquals(second_value, second_instance.exports.load(index));
|
|
|
|
// Verify that the value is correct when passing from the imported function.
|
|
|
|
assertEquals(second_value + 1, first_instance.exports.plus_one(index));
|
|
|
|
})();
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
|
|
|
|
// This test verifies that the correct memory is accessed after returning
|
|
|
|
// from a function imported from another module that also has memory.
|
|
|
|
(function TestCorrectMemoryAccessedAfterReturningFromExternalCall() {
|
|
|
|
print('TestCorrectMemoryAccessedAfterReturningFromExternalCall');
|
|
|
|
|
|
|
|
let first_module = generateBuilder(add_memory = true, import_sig = kSig_i_ii);
|
|
|
|
// Function to invoke the imported function and add 1 to the result.
|
|
|
|
first_module.addFunction('sandwich', kSig_i_iii)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // param0 (index)
|
|
|
|
kExprGetLocal, 1, // param1 (first_value)
|
|
|
|
kExprI32StoreMem, 0, 0, // store value in first_instance
|
|
|
|
kExprGetLocal, 0, // param0 (index)
|
|
|
|
kExprGetLocal, 2, // param2 (second_value)
|
|
|
|
kExprCallFunction, other_fn_idx, // call the imported function
|
|
|
|
kExprDrop, // drop the return value
|
|
|
|
kExprGetLocal, 0, // param0 (index)
|
|
|
|
kExprI32LoadMem, 0, 0, // load from first_instance
|
|
|
|
kExprReturn // -
|
|
|
|
])
|
|
|
|
.exportFunc();
|
|
|
|
let second_module =
|
|
|
|
generateBuilder(add_memory = true, import_sig = undefined);
|
|
|
|
|
|
|
|
let index = kPageSize - 4;
|
|
|
|
let first_value = 1111;
|
|
|
|
let second_value = 2222;
|
|
|
|
// Instantiate the instances.
|
|
|
|
let second_instance = second_module.instantiate();
|
|
|
|
let first_instance = first_module.instantiate(
|
|
|
|
{import_module: {other_module_fn: second_instance.exports.store}});
|
|
|
|
// Call the sandwich function and check that it returns the correct value.
|
|
|
|
assertEquals(
|
|
|
|
first_value,
|
|
|
|
first_instance.exports.sandwich(index, first_value, second_value));
|
|
|
|
// Verify that the values are correct in both memories.
|
|
|
|
assertEquals(first_value, first_instance.exports.load(index));
|
|
|
|
assertEquals(second_value, second_instance.exports.load(index));
|
|
|
|
})();
|
2017-10-16 08:49:45 +00:00
|
|
|
|
|
|
|
// A test for memory-independence between modules when calling through
|
|
|
|
// imported tables.
|
|
|
|
(function CallThroughTableMemoryIndependenceTest() {
|
|
|
|
print("CallThroughTableIndependenceTest");
|
|
|
|
let kTableSize = 2;
|
|
|
|
let kPages = 1;
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
|
|
|
|
builder.addMemory(kPages, kPages, true);
|
|
|
|
builder.addFunction("store", kSig_v_ii)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // --
|
|
|
|
kExprGetLocal, 1, // --
|
|
|
|
kExprI32StoreMem, 0, 0, // --
|
|
|
|
]) // --
|
|
|
|
.exportFunc();
|
|
|
|
builder.addFunction("load", kSig_i_i)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 0, // --
|
|
|
|
kExprI32LoadMem, 0, 0, // --
|
|
|
|
]) // --
|
|
|
|
.exportFunc();
|
|
|
|
|
|
|
|
{
|
|
|
|
// Create two instances.
|
|
|
|
let module = builder.toModule();
|
|
|
|
var a = new WebAssembly.Instance(module);
|
|
|
|
var b = new WebAssembly.Instance(module);
|
|
|
|
// Check that the memories are initially independent.
|
|
|
|
assertMemoryIndependence(a.exports.load, a.exports.store,
|
|
|
|
b.exports.load, b.exports.store);
|
|
|
|
}
|
|
|
|
|
|
|
|
let table = new WebAssembly.Table({element: "anyfunc",
|
|
|
|
initial: kTableSize,
|
|
|
|
maximum: kTableSize});
|
|
|
|
|
|
|
|
table.set(0, a.exports.store);
|
|
|
|
table.set(1, b.exports.store);
|
|
|
|
// Check that calling (from JS) through the table maintains independence.
|
|
|
|
assertMemoryIndependence(a.exports.load, table.get(0),
|
|
|
|
b.exports.load, table.get(1));
|
|
|
|
|
|
|
|
table.set(1, a.exports.store);
|
|
|
|
table.set(0, b.exports.store);
|
|
|
|
// Check that calling (from JS) through the table maintains independence,
|
|
|
|
// even after reorganizing the table.
|
|
|
|
assertMemoryIndependence(a.exports.load, table.get(1),
|
|
|
|
b.exports.load, table.get(0));
|
|
|
|
|
|
|
|
// Check that calling (from WASM) through the table maintains independence.
|
|
|
|
builder = new WasmModuleBuilder();
|
|
|
|
builder.addImportedTable("m", "table", kTableSize, kTableSize);
|
|
|
|
var sig_index = builder.addType(kSig_v_ii);
|
|
|
|
builder.addFunction("store", kSig_v_iii)
|
|
|
|
.addBody([
|
|
|
|
kExprGetLocal, 1,
|
|
|
|
kExprGetLocal, 2,
|
|
|
|
kExprGetLocal, 0,
|
|
|
|
kExprCallIndirect, sig_index, kTableZero,
|
|
|
|
]).exportFunc();
|
|
|
|
|
|
|
|
let c = builder.instantiate({m: {table: table}});
|
|
|
|
|
|
|
|
let a_index = 1;
|
|
|
|
let b_index = 0;
|
|
|
|
let store_a = (index, val) => c.exports.store(a_index, index, val)
|
|
|
|
let store_b = (index, val) => c.exports.store(b_index, index, val);
|
|
|
|
|
|
|
|
assertMemoryIndependence(a.exports.load, store_a,
|
|
|
|
b.exports.load, store_b);
|
|
|
|
|
|
|
|
// Flip the order in the table and do it again.
|
|
|
|
table.set(0, a.exports.store);
|
|
|
|
table.set(1, b.exports.store);
|
|
|
|
|
|
|
|
a_index = 0;
|
|
|
|
b_index = 1;
|
|
|
|
|
|
|
|
assertMemoryIndependence(a.exports.load, store_a,
|
|
|
|
b.exports.load, store_b);
|
|
|
|
|
|
|
|
})();
|