blob: 752bb5ced2ae0dded36553d71c52f35356cf7bb0 [file] [log] [blame]
// Copyright 2015 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test the Worker API of d8. This test only makes sense with d8. A Worker
// spawns a new OS thread and isolate, and runs it concurrently with the
// current running thread.
var workerScript =
`postMessage('Starting worker');
// Set a global variable; should not be visible outside of the worker's
// context.
foo = 100;
var c = 0;
onmessage = function(m) {
switch (c++) {
case 0:
if (m !== undefined) throw new Error('undefined');
break;
case 1:
if (m !== null) throw new Error('null');
break;
case 2:
if (m !== true) throw new Error('true');
break;
case 3:
if (m !== false) throw new Error('false');
break;
case 4:
if (m !== 100) throw new Error('Number');
break;
case 5:
if (m !== 'hi') throw new Error('String');
break;
case 6:
if (JSON.stringify(m) !== '[4,true,\"bye\"]') {
throw new Error('Array');
}
break;
case 7:
if (JSON.stringify(m) !== '{"a":1,"b":2.5,"c":"three"}')
throw new Error('Object' + JSON.stringify(m));
break;
case 8:
var ab = m;
var t = new Uint32Array(ab);
if (ab.byteLength !== 16)
throw new Error('ArrayBuffer clone byteLength');
for (var i = 0; i < 4; ++i)
if (t[i] !== i)
throw new Error('ArrayBuffer clone value ' + i);
break;
case 9:
var ab = m;
var t = new Uint32Array(ab);
if (ab.byteLength !== 32)
throw new Error('ArrayBuffer transfer byteLength');
for (var i = 0; i < 8; ++i)
if (t[i] !== i)
throw new Error('ArrayBuffer transfer value ' + i);
break;
}
if (c == 10) {
postMessage('DONE');
}
};`;
if (this.Worker) {
function createArrayBuffer(byteLength) {
var ab = new ArrayBuffer(byteLength);
var t = new Uint32Array(ab);
for (var i = 0; i < byteLength / 4; ++i)
t[i] = i;
return ab;
}
assertThrows(function() {
// Second arg must be 'options' object
new Worker(workerScript, 123);
});
assertThrows(function() {
new Worker('test/mjsunit/d8/d8-worker.js', {type: 'invalid'});
});
assertThrows(function() {
// worker type defaults to 'classic' which tries to load from file
new Worker(workerScript);
});
var w = new Worker(workerScript, {type: 'string'});
assertEquals("Starting worker", w.getMessage());
w.postMessage(undefined);
w.postMessage(null);
w.postMessage(true);
w.postMessage(false);
w.postMessage(100);
w.postMessage("hi");
w.postMessage([4, true, "bye"]);
w.postMessage({a: 1, b: 2.5, c: "three"});
// Test bad get in transfer list.
var transferList = [undefined];
Object.defineProperty(transferList, '0', {
get: function() {
throw 'unexpected!';
}
});
assertThrows(function() {
w.postMessage([], transferList);
});
// Test console.log in transfer list.
(function() {
var val = [undefined];
Object.defineProperty(val, '0', {get: () => console.log()});
assertThrows(function() {
w.postMessage(val, [val]);
});
})();
// Clone ArrayBuffer
var ab1 = createArrayBuffer(16);
w.postMessage(ab1);
assertEquals(16, ab1.byteLength); // ArrayBuffer should not be detached.
// Transfer ArrayBuffer
var ab2 = createArrayBuffer(32);
w.postMessage(ab2, [ab2]);
assertEquals(0, ab2.byteLength); // ArrayBuffer should be detached.
// Attempting to transfer the same ArrayBuffer twice should throw.
assertThrows(function() {
var ab3 = createArrayBuffer(4);
w.postMessage(ab3, [ab3, ab3]);
});
assertEquals("undefined", typeof foo);
// Read a message from the worker.
assertEquals("DONE", w.getMessage());
w.terminate();
// Make sure that the main thread doesn't block forever in getMessage() if
// the worker dies without posting a message.
var w2 = new Worker('', {type: 'string'});
var msg = w2.getMessage();
assertEquals(undefined, msg);
}