Commit 73d401b9 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[test] Make worker related tests more fuzzable

Details: https://docs.google.com/document/d/1-Gi37Ks7rXMVVRkC_HkwGxenP7T1huQUOMrYOtkUCFk/edit?usp=sharing

Bug: v8:11340
Change-Id: Ia1d75270373a7ef2307e7ee0fd24da9ecfa27d18
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2643381Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72315}
parent ca5da5b9
...@@ -1928,51 +1928,141 @@ void Shell::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1928,51 +1928,141 @@ void Shell::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) {
PerIsolateData::Get(isolate)->SetTimeout(callback, context); PerIsolateData::Get(isolate)->SetTimeout(callback, context);
} }
void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { enum WorkerType { kClassic, kString, kFunction, kInvalid, kNone };
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
if (args.Length() < 1 || !args[0]->IsString()) {
Throw(args.GetIsolate(), "1st argument must be string");
return;
}
// d8 honors `options={type: string}`, which means the first argument is void ReadWorkerTypeAndArguments(const v8::FunctionCallbackInfo<v8::Value>& args,
// not a filename but string of script to be run. WorkerType* worker_type,
bool load_from_file = true; Local<Value>* arguments = nullptr) {
Isolate* isolate = args.GetIsolate();
if (args.Length() > 1 && args[1]->IsObject()) { if (args.Length() > 1 && args[1]->IsObject()) {
Local<Object> object = args[1].As<Object>(); Local<Object> object = args[1].As<Object>();
Local<Context> context = isolate->GetCurrentContext(); Local<Context> context = isolate->GetCurrentContext();
Local<Value> value; Local<Value> value;
if (TryGetValue(args.GetIsolate(), context, object, "type") if (!TryGetValue(isolate, context, object, "type").ToLocal(&value)) {
.ToLocal(&value) && *worker_type = WorkerType::kNone;
value->IsString()) { return;
Local<String> worker_type = value->ToString(context).ToLocalChecked(); }
String::Utf8Value str(isolate, worker_type); if (!value->IsString()) {
if (strcmp("string", *str) == 0) { *worker_type = WorkerType::kInvalid;
load_from_file = false; return;
} else if (strcmp("classic", *str) == 0) { }
load_from_file = true; Local<String> worker_type_string =
} else { value->ToString(context).ToLocalChecked();
Throw(args.GetIsolate(), "Unsupported worker type"); String::Utf8Value str(isolate, worker_type_string);
return; if (strcmp("string", *str) == 0) {
*worker_type = WorkerType::kString;
} else if (strcmp("classic", *str) == 0) {
*worker_type = WorkerType::kClassic;
} else if (strcmp("function", *str) == 0) {
*worker_type = WorkerType::kFunction;
} else {
*worker_type = WorkerType::kInvalid;
}
if (arguments != nullptr) {
bool got_arguments =
TryGetValue(isolate, context, object, "arguments").ToLocal(arguments);
USE(got_arguments);
}
} else {
*worker_type = WorkerType::kNone;
}
}
bool FunctionAndArgumentsToString(Local<Function> function,
Local<Value> arguments, Local<String>* source,
Isolate* isolate) {
Local<Context> context = isolate->GetCurrentContext();
MaybeLocal<String> maybe_function_string =
function->FunctionProtoToString(context);
Local<String> function_string;
if (!maybe_function_string.ToLocal(&function_string)) {
Throw(isolate, "Failed to convert function to string");
return false;
}
*source = String::NewFromUtf8Literal(isolate, "(");
*source = String::Concat(isolate, *source, function_string);
Local<String> middle = String::NewFromUtf8Literal(isolate, ")(");
*source = String::Concat(isolate, *source, middle);
if (!arguments.IsEmpty() && !arguments->IsUndefined()) {
if (!arguments->IsArray()) {
Throw(isolate, "'arguments' must be an array");
return false;
}
Local<String> comma = String::NewFromUtf8Literal(isolate, ",");
Local<Array> array = arguments.As<Array>();
for (uint32_t i = 0; i < array->Length(); ++i) {
if (i > 0) {
*source = String::Concat(isolate, *source, comma);
}
Local<Value> argument = array->Get(context, i).ToLocalChecked();
Local<String> argument_string;
if (!JSON::Stringify(context, argument).ToLocal(&argument_string)) {
Throw(isolate, "Failed to convert argument to string");
return false;
} }
*source = String::Concat(isolate, *source, argument_string);
} }
} }
Local<String> suffix = String::NewFromUtf8Literal(isolate, ")");
*source = String::Concat(isolate, *source, suffix);
return true;
}
Local<Value> source; void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (load_from_file) { Isolate* isolate = args.GetIsolate();
String::Utf8Value filename(args.GetIsolate(), args[0]); HandleScope handle_scope(isolate);
source = ReadFile(args.GetIsolate(), *filename); if (args.Length() < 1 || (!args[0]->IsString() && !args[0]->IsFunction())) {
if (source.IsEmpty()) { Throw(isolate, "1st argument must be a string or a function");
Throw(args.GetIsolate(), "Error loading worker script"); return;
}
Local<String> source;
if (args[0]->IsFunction()) {
// d8 supports `options={type: 'function', arguments:[...]}`, which means
// the first argument is a function with the code to be ran. Restrictions
// apply; in particular the function will be converted to a string and the
// Worker constructed based on it.
WorkerType worker_type;
Local<Value> arguments;
ReadWorkerTypeAndArguments(args, &worker_type, &arguments);
if (worker_type != WorkerType::kFunction) {
Throw(isolate, "Invalid or missing worker type");
return;
}
// Source: ( function_to_string )( params )
if (!FunctionAndArgumentsToString(args[0].As<Function>(), arguments,
&source, isolate)) {
return; return;
} }
} else { } else {
source = args[0]; // d8 honors `options={type: 'string'}`, which means the first argument is
// not a filename but string of script to be run.
bool load_from_file = true;
WorkerType worker_type;
ReadWorkerTypeAndArguments(args, &worker_type);
if (worker_type == WorkerType::kString) {
load_from_file = false;
} else if (worker_type != WorkerType::kNone &&
worker_type != WorkerType::kClassic) {
Throw(isolate, "Invalid worker type");
return;
}
if (load_from_file) {
String::Utf8Value filename(isolate, args[0]);
source = ReadFile(isolate, *filename);
if (source.IsEmpty()) {
Throw(args.GetIsolate(), "Error loading worker script");
return;
}
} else {
source = args[0].As<String>();
}
} }
if (!args.IsConstructCall()) { if (!args.IsConstructCall()) {
Throw(args.GetIsolate(), "Worker must be constructed with new"); Throw(isolate, "Worker must be constructed with new");
return; return;
} }
...@@ -1987,9 +2077,9 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -1987,9 +2077,9 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
base::MutexGuard lock_guard(workers_mutex_.Pointer()); base::MutexGuard lock_guard(workers_mutex_.Pointer());
if (!allow_new_workers_) return; if (!allow_new_workers_) return;
String::Utf8Value script(args.GetIsolate(), source); String::Utf8Value script(isolate, source);
if (!*script) { if (!*script) {
Throw(args.GetIsolate(), "Can't get worker script"); Throw(isolate, "Can't get worker script");
return; return;
} }
...@@ -2003,7 +2093,7 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -2003,7 +2093,7 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
i_isolate, kWorkerSizeEstimate, worker); i_isolate, kWorkerSizeEstimate, worker);
args.Holder()->SetInternalField(0, Utils::ToLocal(managed)); args.Holder()->SetInternalField(0, Utils::ToLocal(managed));
if (!Worker::StartWorkerThread(std::move(worker))) { if (!Worker::StartWorkerThread(std::move(worker))) {
Throw(args.GetIsolate(), "Can't start thread"); Throw(isolate, "Can't start thread");
return; return;
} }
} }
......
// Copyright 2021 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.
// Tests for a more fuzzable way for creating workers based on functions.
(function TestWorker() {
function workerCode1() {
onmessage = function() {
postMessage('hi');
}
}
let w = new Worker(workerCode1, {type: 'function'});
w.postMessage('');
assertEquals('hi', w.getMessage());
})();
(function TestPassingNumberParam() {
function workerCode2(n) {
onmessage = function() {
postMessage('worker ' + (n + 1));
}
}
w = new Worker(workerCode2, {type: 'function', arguments: [2021]});
w.postMessage('');
assertEquals('worker 2022', w.getMessage());
})();
(function TestPassingStringParam() {
function workerCode3(s) {
onmessage = function() {
postMessage('worker ' + s);
}
}
w = new Worker(workerCode3, {type: 'function', arguments: ['hello']});
w.postMessage('');
assertEquals('worker hello', w.getMessage());
})();
(function TestPassingObjectParam() {
function workerCode4(o) {
onmessage = function() {
postMessage('worker ' + (o.x + 1));
}
}
w = new Worker(workerCode4, {type: 'function', arguments: [{x: 1}]});
w.postMessage('');
assertEquals('worker 2', w.getMessage());
})();
(function TestPassingFunctionParam() {
function workerCode5(f) {
eval(f);
onmessage = function() {
postMessage('worker ' + func());
}
}
let config = {'func': function func() { return 'hi';} };
w = new Worker(workerCode5, {type: 'function',
arguments: [config.func.toString()]});
w.postMessage('');
assertEquals('worker hi', w.getMessage());
})();
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
var sab = new SharedArrayBuffer(4); var sab = new SharedArrayBuffer(4);
var sta = new Int8Array(sab); var sta = new Int8Array(sab);
sta[0] = 5; sta[0] = 5;
var workerScript = function workerCode() {
`onmessage=function(msg) { onmessage = function(msg) {
postMessage(0); postMessage(0);
};`; };
var worker = new Worker(workerScript, {type: 'string'}); }
var worker = new Worker(workerCode, {type: 'function'});
var value_obj = { var value_obj = {
valueOf: function() {worker.postMessage({sab:sab}, [sta.buffer]); valueOf: function() {worker.postMessage({sab:sab}, [sta.buffer]);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
load("test/mjsunit/harmony/atomics-waitasync-helpers.js"); load("test/mjsunit/harmony/atomics-waitasync-helpers.js");
const script = ` function workerCode() {
const sab = new SharedArrayBuffer(16); const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab); const i32a = new Int32Array(sab);
...@@ -28,7 +28,8 @@ const script = ` ...@@ -28,7 +28,8 @@ const script = `
postMessage("notify return value " + notify_return_value); postMessage("notify return value " + notify_return_value);
}, },
() => { postMessage("unexpected"); }); () => { postMessage("unexpected"); });
}`; };
}
const expected_messages = [ const expected_messages = [
"fast timed-out", "fast timed-out",
...@@ -36,4 +37,4 @@ const expected_messages = [ ...@@ -36,4 +37,4 @@ const expected_messages = [
"slow ok" "slow ok"
]; ];
runTestWithWorker(script, expected_messages); runTestWithWorker(workerCode, expected_messages);
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
load("test/mjsunit/harmony/atomics-waitasync-helpers.js"); load("test/mjsunit/harmony/atomics-waitasync-helpers.js");
const script = ` function workerCode() {
onmessage = function() { onmessage = function() {
(function() { (function() {
const sab = new SharedArrayBuffer(16); const sab = new SharedArrayBuffer(16);
...@@ -31,7 +31,8 @@ const script = ` ...@@ -31,7 +31,8 @@ const script = `
const notify_return_value = Atomics.notify(i32a2, 0); const notify_return_value = Atomics.notify(i32a2, 0);
postMessage("notify return value " + notify_return_value); postMessage("notify return value " + notify_return_value);
}`; };
}
const expected_messages = [ const expected_messages = [
"notify return value 1", "notify return value 1",
...@@ -39,4 +40,4 @@ const expected_messages = [ ...@@ -39,4 +40,4 @@ const expected_messages = [
"result timed-out" "result timed-out"
]; ];
runTestWithWorker(script, expected_messages); runTestWithWorker(workerCode, expected_messages);
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
load("test/mjsunit/harmony/atomics-waitasync-helpers.js"); load("test/mjsunit/harmony/atomics-waitasync-helpers.js");
const script = ` function workerCode() {
onmessage = function() { onmessage = function() {
const sab = new SharedArrayBuffer(16); const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab); const i32a = new Int32Array(sab);
...@@ -17,10 +17,11 @@ const script = ` ...@@ -17,10 +17,11 @@ const script = `
result.value.then( result.value.then(
(value) => { postMessage("result " + value); }, (value) => { postMessage("result " + value); },
() => { postMessage("unexpected"); }); () => { postMessage("unexpected"); });
}`; };
}
const expected_messages = [ const expected_messages = [
"result timed-out" "result timed-out"
]; ];
runTestWithWorker(script, expected_messages); runTestWithWorker(workerCode, expected_messages);
...@@ -6,14 +6,12 @@ ...@@ -6,14 +6,12 @@
const N = 10; const N = 10;
const script = ` function workerCode(N) {
const sab = new SharedArrayBuffer(16); const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab); const i32a = new Int32Array(sab);
const location = 0; const location = 0;
const expected_value = 0; const expected_value = 0;
const N = ${N};
function start() { function start() {
// Create N async waiters; the even ones without timeout and the odd ones // Create N async waiters; the even ones without timeout and the odd ones
// with timeout. // with timeout.
...@@ -36,15 +34,16 @@ const script = ` ...@@ -36,15 +34,16 @@ const script = `
postMessage("notify return value " + notify_return_value); postMessage("notify return value " + notify_return_value);
} }
function onmessage(param) { onmessage = function(param) {
if (param == "start") { if (param == "start") {
start(); start();
} else if (param == "wakeUpRemainingWaiters") { } else if (param == "wakeUpRemainingWaiters") {
wakeUpRemainingWaiters(); wakeUpRemainingWaiters();
} }
}` };
}
const w = new Worker(script, {type : 'string'}); const w = new Worker(workerCode, {type: 'function', arguments: [N]});
w.postMessage("start"); w.postMessage("start");
// Verify that all timed out waiters timed out in timeout order. // Verify that all timed out waiters timed out in timeout order.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
function runTestWithWorker(script, expected_messages) { function runTestWithWorker(worker_code, expected_messages) {
const w = new Worker(script, {type : 'string'}); const w = new Worker(worker_code, {type: 'function'});
w.postMessage('start'); w.postMessage('start');
let i = 0; let i = 0;
while (i < expected_messages.length) { while (i < expected_messages.length) {
......
...@@ -10,16 +10,18 @@ ...@@ -10,16 +10,18 @@
const location = 0; const location = 0;
(function createWorker() { (function createWorker() {
const script = `onmessage = function(msg) { function workerCode(location) {
if (msg.sab) { onmessage = function(msg) {
const i32a = new Int32Array(msg.sab); if (msg.sab) {
// Start 2 async waits in the same location. const i32a = new Int32Array(msg.sab);
const result1 = Atomics.waitAsync(i32a, ${location}, 0); // Start 2 async waits in the same location.
const result2 = Atomics.waitAsync(i32a, ${location}, 0); const result1 = Atomics.waitAsync(i32a, location, 0);
postMessage('worker waiting'); const result2 = Atomics.waitAsync(i32a, location, 0);
postMessage('worker waiting');
}
} }
}`; }
const w = new Worker(script, {type : 'string'}); const w = new Worker(workerCode, {type: 'function', arguments: [location]});
w.postMessage({sab: sab}); w.postMessage({sab: sab});
const m = w.getMessage(); const m = w.getMessage();
assertEquals('worker waiting', m); assertEquals('worker waiting', m);
......
...@@ -10,18 +10,21 @@ ...@@ -10,18 +10,21 @@
const location = 0; const location = 0;
(function createWorker() { (function createWorker() {
const script = `onmessage = function(msg) { function workerCode(location) {
if (msg.sab) { onmessage = function(msg) {
const i32a = new Int32Array(msg.sab); if (msg.sab) {
Atomics.waitAsync(i32a, ${location}, 0); const i32a = new Int32Array(msg.sab);
postMessage('worker waiting'); Atomics.waitAsync(i32a, location, 0);
postMessage('worker waiting');
}
} }
}`; }
// Create 2 workers which wait on the same location. // Create 2 workers which wait on the same location.
let workers = []; let workers = [];
const worker_count = 2; const worker_count = 2;
for (let i = 0; i < worker_count; ++i) { for (let i = 0; i < worker_count; ++i) {
workers[i] = new Worker(script, {type : 'string'}); workers[i] = new Worker(workerCode,
{type: 'function', arguments: [location]});
workers[i].postMessage({sab: sab}); workers[i].postMessage({sab: sab});
const m = workers[i].getMessage(); const m = workers[i].getMessage();
assertEquals('worker waiting', m); assertEquals('worker waiting', m);
......
...@@ -9,14 +9,16 @@ ...@@ -9,14 +9,16 @@
const i32a = new Int32Array(sab); const i32a = new Int32Array(sab);
(function createWorker() { (function createWorker() {
const script = `onmessage = function(msg) { function workerCode() {
if (msg.sab) { onmessage = function(msg) {
const i32a = new Int32Array(msg.sab); if (msg.sab) {
const result = Atomics.waitAsync(i32a, 0, 0); const i32a = new Int32Array(msg.sab);
postMessage('worker waiting'); const result = Atomics.waitAsync(i32a, 0, 0);
postMessage('worker waiting');
}
} }
}`; };
const w = new Worker(script, {type : 'string'}); const w = new Worker(workerCode, {type: 'function'});
w.postMessage({sab: sab}); w.postMessage({sab: sab});
const m = w.getMessage(); const m = w.getMessage();
assertEquals('worker waiting', m); assertEquals('worker waiting', m);
......
...@@ -9,14 +9,16 @@ ...@@ -9,14 +9,16 @@
const i32a = new Int32Array(sab); const i32a = new Int32Array(sab);
(function createWorker() { (function createWorker() {
const script = `onmessage = function(msg) { function workerCode() {
if (msg.sab) { onmessage = function(msg) {
const i32a = new Int32Array(msg.sab); if (msg.sab) {
const result = Atomics.waitAsync(i32a, 0, 0, 100000); const i32a = new Int32Array(msg.sab);
postMessage('worker waiting'); const result = Atomics.waitAsync(i32a, 0, 0, 100000);
postMessage('worker waiting');
}
} }
}`; }
const w = new Worker(script, {type : 'string'}); const w = new Worker(workerCode, {type: 'function'});
w.postMessage({sab: sab}); w.postMessage({sab: sab});
const m = w.getMessage(); const m = w.getMessage();
assertEquals('worker waiting', m); assertEquals('worker waiting', m);
......
...@@ -189,23 +189,24 @@ if (this.Worker) { ...@@ -189,23 +189,24 @@ if (this.Worker) {
// i32a[4]: // i32a[4]:
// always 0. Each worker is waiting on this index. // always 0. Each worker is waiting on this index.
var workerScript = function workerCode() {
`onmessage = function(msg) { onmessage = function(msg) {
var id = msg.id; var id = msg.id;
var i32a = new Int32Array(msg.sab); var i32a = new Int32Array(msg.sab);
// Wait on i32a[4] (should be zero). // Wait on i32a[4] (should be zero).
var result = Atomics.wait(i32a, 4, 0); var result = Atomics.wait(i32a, 4, 0);
// Set i32a[id] to 1 to notify the main thread which workers were // Set i32a[id] to 1 to notify the main thread which workers were
// woken up. // woken up.
Atomics.store(i32a, id, 1); Atomics.store(i32a, id, 1);
postMessage(result); postMessage(result);
};`; };
}
var id; var id;
var workers = []; var workers = [];
for (id = 0; id < 4; id++) { for (id = 0; id < 4; id++) {
workers[id] = new Worker(workerScript, {type: 'string'}); workers[id] = new Worker(workerCode, {type: 'function'});
workers[id].postMessage({sab: sab, id: id}); workers[id].postMessage({sab: sab, id: id});
} }
......
...@@ -299,25 +299,27 @@ function getSequence(start, end) { ...@@ -299,25 +299,27 @@ function getSequence(start, end) {
} }
function spawnWorkers() { function spawnWorkers() {
function workerCode() {
onmessage = function(msg) {
if (msg.module) {
let module = msg.module;
let mem = msg.mem;
this.instance = new WebAssembly.Instance(module, {m: {imported_mem: mem}});
postMessage({instantiated: true});
} else {
let address = msg.address;
let sequence = msg.sequence;
let index = msg.index;
let spin = msg.spin;
let result = instance.exports["worker" + index](address, sequence, spin);
postMessage({index: index, sequence: sequence, result: result});
}
}
}
let workers = []; let workers = [];
for (let i = 0; i < kNumberOfWorker; i++) { for (let i = 0; i < kNumberOfWorker; i++) {
let worker = new Worker( let worker = new Worker(workerCode, {type: 'function'});
`onmessage = function(msg) {
if (msg.module) {
let module = msg.module;
let mem = msg.mem;
this.instance = new WebAssembly.Instance(module, {m: {imported_mem: mem}});
postMessage({instantiated: true});
} else {
let address = msg.address;
let sequence = msg.sequence;
let index = msg.index;
let spin = msg.spin;
let result = instance.exports["worker" + index](address, sequence, spin);
postMessage({index: index, sequence: sequence, result: result});
}
}`,
{type: 'string'});
workers.push(worker); workers.push(worker);
} }
return workers; return workers;
......
This diff is collapsed.
...@@ -7,13 +7,14 @@ ...@@ -7,13 +7,14 @@
const kNumIterations = 10; const kNumIterations = 10;
function NewWorker() { function NewWorker() {
let script = function workerCode() {
`onmessage = (msg) => { onmessage = (msg) => {
if (msg.memory) postMessage("ack"); if (msg.memory) postMessage("ack");
if (msg.quit) postMessage("bye"); if (msg.quit) postMessage("bye");
gc(); gc();
}`; }
return new Worker(script, {type: 'string'}); }
return new Worker(workerCode, {type: 'function'});
} }
function PingWorker(worker, memory) { function PingWorker(worker, memory) {
......
...@@ -11,12 +11,15 @@ function AllocMemory(pages = 1, max = pages) { ...@@ -11,12 +11,15 @@ function AllocMemory(pages = 1, max = pages) {
} }
(function RunTest() { (function RunTest() {
let worker = new Worker( function workerCode() {
`onmessage = onmessage =
function(msg) { function(msg) {
if (msg.memory) postMessage({memory : msg.memory}); if (msg.memory) postMessage({memory : msg.memory});
gc(); gc();
}`, {type : 'string'}); }
}
let worker = new Worker(workerCode);
let time = performance.now(); let time = performance.now();
......
...@@ -12,34 +12,39 @@ ...@@ -12,34 +12,39 @@
})(); })();
// Can't use assert in a worker. // Can't use assert in a worker.
let workerHelpers = function workerHelpersHelper() {
`function assertTrue(value, msg) { assertTrue = function(value, msg) {
if (!value) { if (!value) {
postMessage("Error: " + msg); postMessage("Error: " + msg);
throw new Error("Exit"); // To stop testing. throw new Error("Exit"); // To stop testing.
} }
} }
function assertIsWasmMemory(memory, expectedSize) { assertIsWasmMemory = function(memory, expectedSize) {
assertTrue(memory instanceof WebAssembly.Memory, assertTrue(memory instanceof WebAssembly.Memory,
"object is not a WebAssembly.Memory"); "object is not a WebAssembly.Memory");
assertTrue(memory.buffer instanceof SharedArrayBuffer, assertTrue(memory.buffer instanceof SharedArrayBuffer,
"object.buffer is not a SharedArrayBuffer"); "object.buffer is not a SharedArrayBuffer");
assertTrue(memory.buffer.byteLength == expectedSize, assertTrue(memory.buffer.byteLength == expectedSize,
"object.buffer.byteLength is not " + expectedSize + " bytes"); "object.buffer.byteLength is not " + expectedSize + " bytes");
} }
`; }
let workerHelpers = "(" + workerHelpersHelper.toString() + ")()";
(function TestPostMessageSharedMemory() { (function TestPostMessageSharedMemory() {
let workerScript = workerHelpers + function workerCode(workerHelpers) {
`onmessage = function(memory) { eval(workerHelpers);
assertIsWasmMemory(memory, 65536); onmessage = function(memory) {
postMessage("OK"); assertIsWasmMemory(memory, 65536);
};`; postMessage("OK");
};
}
let worker = new Worker(workerScript, {type: 'string'}); let worker = new Worker(workerCode,
{type: 'function', arguments: [workerHelpers]});
let memory = new WebAssembly.Memory({initial: 1, maximum: 2, shared: true}); let memory = new WebAssembly.Memory({initial: 1, maximum: 2, shared: true});
worker.postMessage(memory); worker.postMessage(memory);
assertEquals("OK", worker.getMessage()); assertEquals("OK", worker.getMessage());
...@@ -47,8 +52,9 @@ let workerHelpers = ...@@ -47,8 +52,9 @@ let workerHelpers =
})(); })();
(function TestPostMessageComplexObjectWithSharedMemory() { (function TestPostMessageComplexObjectWithSharedMemory() {
let workerScript = workerHelpers + function workerCode(workerHelpers) {
`onmessage = function(obj) { eval(workerHelpers);
onmessage = function(obj) {
assertIsWasmMemory(obj.memories[0], 65536); assertIsWasmMemory(obj.memories[0], 65536);
assertIsWasmMemory(obj.memories[1], 65536); assertIsWasmMemory(obj.memories[1], 65536);
assertTrue(obj.buffer instanceof SharedArrayBuffer, assertTrue(obj.buffer instanceof SharedArrayBuffer,
...@@ -58,9 +64,11 @@ let workerHelpers = ...@@ -58,9 +64,11 @@ let workerHelpers =
"buffers aren't equal"); "buffers aren't equal");
assertTrue(obj.foo === 1, "foo is not 1"); assertTrue(obj.foo === 1, "foo is not 1");
postMessage("OK"); postMessage("OK");
};`; };
}
let worker = new Worker(workerScript, {type: 'string'}); let worker = new Worker(workerCode,
{type: 'function', arguments: [workerHelpers]});
let memory = new WebAssembly.Memory({initial: 1, maximum: 2, shared: true}); let memory = new WebAssembly.Memory({initial: 1, maximum: 2, shared: true});
let obj = {memories: [memory, memory], buffer: memory.buffer, foo: 1}; let obj = {memories: [memory, memory], buffer: memory.buffer, foo: 1};
worker.postMessage(obj); worker.postMessage(obj);
...@@ -69,14 +77,18 @@ let workerHelpers = ...@@ -69,14 +77,18 @@ let workerHelpers =
})(); })();
(function TestTwoWorkers() { (function TestTwoWorkers() {
let workerScript = workerHelpers + function workerCode(workerHelpers) {
`onmessage = function(memory) { eval(workerHelpers);
onmessage = function(memory) {
assertIsWasmMemory(memory, 65536); assertIsWasmMemory(memory, 65536);
postMessage("OK"); postMessage("OK");
};`; };
}
let workers = [new Worker(workerScript, {type: 'string'}), let workers = [new Worker(workerCode,
new Worker(workerScript, {type: 'string'})]; {type: 'function', arguments: [workerHelpers]}),
new Worker(workerCode,
{type: 'function', arguments: [workerHelpers]})];
let memory = new WebAssembly.Memory({initial: 1, maximum: 2, shared: true}); let memory = new WebAssembly.Memory({initial: 1, maximum: 2, shared: true});
for (let worker of workers) { for (let worker of workers) {
worker.postMessage(memory); worker.postMessage(memory);
......
...@@ -12,7 +12,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -12,7 +12,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let module = builder.toModule(); let module = builder.toModule();
let workerScript = ` function workerCode() {
onmessage = function(module) { onmessage = function(module) {
try { try {
let instance = new WebAssembly.Instance(module); let instance = new WebAssembly.Instance(module);
...@@ -22,9 +22,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -22,9 +22,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
postMessage('ERROR: ' + e); postMessage('ERROR: ' + e);
} }
} }
`; }
let worker = new Worker(workerScript, {type: 'string'}); let worker = new Worker(workerCode, {type: 'function'});
worker.postMessage(module); worker.postMessage(module);
assertEquals(42, worker.getMessage()); assertEquals(42, worker.getMessage());
worker.terminate(); worker.terminate();
......
...@@ -44,53 +44,63 @@ function RunWorkerPingTest(config) { ...@@ -44,53 +44,63 @@ function RunWorkerPingTest(config) {
// Every {config.allocInterval}, a worker creates a new thing by // Every {config.allocInterval}, a worker creates a new thing by
// {config.AllocThing}. // {config.AllocThing}.
let script = function workerCode(config, AllocThing, BeforeReceive) {
`const kNumThings = ${config.numThings}; eval(AllocThing);
const kAllocInterval = ${config.allocInterval}; eval(BeforeReceive);
let index = 0; const kNumThings = config.numThings;
let total = 0; const kAllocInterval = config.allocInterval;
let id = 0; let index = 0;
let things = new Array(kNumThings); let total = 0;
for (let i = 0; i < kNumThings; i++) { let id = 0;
things[i] = TryAllocThing(); let things = new Array(kNumThings);
} for (let i = 0; i < kNumThings; i++) {
things[i] = TryAllocThing();
}
function TryAllocThing() { function TryAllocThing() {
try { try {
let thing = AllocThing(id++); let thing = AllocThing(id++);
${config.traceAlloc ? "print(\"alloc success\");" : ""} if (config.traceAlloc) {
print("alloc success");
}
return thing; return thing;
} catch(e) { } catch(e) {
${config.abortOnFail ? "postMessage({error: e.toString()}); throw e;" : "" } if (config.abortOnFail) {
${config.traceAlloc ? "print(\"alloc fail: \" + e);" : ""} postMessage({error: e.toString()}); throw e;
}
if (config.traceAlloc) {
print("alloc fail: " + e);
}
} }
} }
onmessage = function(msg) { onmessage = function(msg) {
BeforeReceive(msg); BeforeReceive(msg);
if (msg.thing !== undefined) { if (msg.thing !== undefined) {
let reply = things[index]; let reply = things[index];
if ((total % kAllocInterval) == 0) { if ((total % kAllocInterval) == 0) {
reply = TryAllocThing(); reply = TryAllocThing();
}
things[index] = msg.thing;
postMessage({thing : reply});
index = (index + 1) % kNumThings;
total++;
} }
things[index] = msg.thing;
postMessage({thing : reply});
index = (index + 1) % kNumThings;
total++;
} }
} }
${config.AllocThing.toString()}
${beforeReceive.toString()}
`;
if (config.traceScript) { if (config.traceScript) {
print("========== Worker script =========="); print("========== Worker script ==========");
print(script); print(workerCode.toString());
print("==================================="); print("===================================");
} }
let arguments = [config,
config.AllocThing.toString(),
beforeReceive.toString()];
for (let i = 0; i < config.numWorkers; i++) { for (let i = 0; i < config.numWorkers; i++) {
let worker = new Worker(script, {type : 'string'}); let worker = new Worker(workerCode, {type: 'function',
arguments: arguments});
workers.push(worker); workers.push(worker);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment