bulk-memory.js 7.06 KB
Newer Older
1 2 3 4
// Copyright 2018 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.

5
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
6 7 8 9 10 11 12 13

(function TestPassiveDataSegment() {
  const builder = new WasmModuleBuilder();
  builder.addMemory(1, 1, false);
  builder.addPassiveDataSegment([0, 1, 2]);
  builder.addPassiveDataSegment([3, 4]);

  // Should not throw.
14
  builder.instantiate();
15 16 17 18 19
})();

(function TestPassiveElementSegment() {
  const builder = new WasmModuleBuilder();
  builder.addFunction('f', kSig_v_v).addBody([]);
20
  builder.setTableBounds(1, 1);
21 22 23 24
  builder.addPassiveElementSegment([0, 0, 0]);
  builder.addPassiveElementSegment([0, 0]);

  // Should not throw.
25 26 27
  builder.instantiate();
})();

28 29
function getMemoryInit(mem, segment_data) {
  const builder = new WasmModuleBuilder();
30
  builder.addImportedMemory('', 'mem', 0);
31 32 33
  builder.addPassiveDataSegment(segment_data);
  builder.addFunction('init', kSig_v_iii)
      .addBody([
34 35 36
        kExprLocalGet, 0,  // Dest.
        kExprLocalGet, 1,  // Source.
        kExprLocalGet, 2,  // Size in bytes.
37 38
        kNumericPrefix, kExprMemoryInit,
        0,  // Data segment index.
39
        0,  // Memory index.
40 41 42 43 44
      ])
      .exportAs('init');
  return builder.instantiate({'': {mem}}).exports.init;
}

45
(function TestMemoryInitOutOfBoundsGrow() {
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
  const mem = new WebAssembly.Memory({initial: 1});
  // Create a data segment that has a length of kPageSize.
  const memoryInit = getMemoryInit(mem, new Array(kPageSize));

  mem.grow(1);

  // Works properly after grow.
  memoryInit(kPageSize, 0, 1000);

  // Traps at new boundary.
  assertTraps(
      kTrapMemOutOfBounds, () => memoryInit(kPageSize + 1, 0, kPageSize));
})();

(function TestMemoryInitOnActiveSegment() {
  const builder = new WasmModuleBuilder();
  builder.addMemory(1);
  builder.addPassiveDataSegment([1, 2, 3]);
  builder.addDataSegment(0, [4, 5, 6]);
65
  builder.addFunction('init', kSig_v_i)
66 67 68
      .addBody([
        kExprI32Const, 0,  // Dest.
        kExprI32Const, 0,  // Source.
69
        kExprLocalGet, 0,  // Size in bytes.
70 71
        kNumericPrefix, kExprMemoryInit,
        1,  // Data segment index.
72
        0,  // Memory index.
73 74 75 76 77 78 79
      ])
      .exportAs('init');

  // Instantiation succeeds, because using memory.init with an active segment
  // is a trap, not a validation error.
  const instance = builder.instantiate();

80 81
  // Initialization succeeds, because source address and size are 0
  // which is valid on a dropped segment.
82 83
  instance.exports.init(0);

84 85
  // Initialization fails, because the segment is implicitly dropped.
  assertTraps(kTrapMemOutOfBounds, () => instance.exports.init(1));
86 87
})();

88
(function TestDataDropOnActiveSegment() {
89 90 91 92 93 94
  const builder = new WasmModuleBuilder();
  builder.addMemory(1);
  builder.addPassiveDataSegment([1, 2, 3]);
  builder.addDataSegment(0, [4, 5, 6]);
  builder.addFunction('drop', kSig_v_v)
      .addBody([
95
        kNumericPrefix, kExprDataDrop,
96 97 98 99 100
        1,  // Data segment index.
      ])
      .exportAs('drop');

  const instance = builder.instantiate();
101 102
  // Drop on passive segment is equivalent to double drop which is allowed.
  instance.exports.drop();
103 104
})();

105 106 107 108
function getMemoryCopy(mem) {
  const builder = new WasmModuleBuilder();
  builder.addImportedMemory("", "mem", 0);
  builder.addFunction("copy", kSig_v_iii).addBody([
109 110 111
    kExprLocalGet, 0,  // Dest.
    kExprLocalGet, 1,  // Source.
    kExprLocalGet, 2,  // Size in bytes.
112
    kNumericPrefix, kExprMemoryCopy, 0, 0,
113 114 115 116
  ]).exportAs("copy");
  return builder.instantiate({'': {mem}}).exports.copy;
}

117
(function TestMemoryCopyOutOfBoundsGrow() {
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
  const mem = new WebAssembly.Memory({initial: 1});
  const memoryCopy = getMemoryCopy(mem);

  mem.grow(1);

  // Works properly after grow.
  memoryCopy(0, kPageSize, 1000);

  // Traps at new boundary.
  assertTraps(
      kTrapMemOutOfBounds, () => memoryCopy(0, kPageSize + 1, kPageSize));
})();

function getMemoryFill(mem) {
  const builder = new WasmModuleBuilder();
  builder.addImportedMemory("", "mem", 0);
  builder.addFunction("fill", kSig_v_iii).addBody([
135 136 137
    kExprLocalGet, 0,  // Dest.
    kExprLocalGet, 1,  // Byte value.
    kExprLocalGet, 2,  // Size.
138 139 140 141 142
    kNumericPrefix, kExprMemoryFill, 0,
  ]).exportAs("fill");
  return builder.instantiate({'': {mem}}).exports.fill;
}

143
(function TestMemoryFillOutOfBoundsGrow() {
144 145 146 147
  const mem = new WebAssembly.Memory({initial: 1});
  const memoryFill = getMemoryFill(mem);
  const v = 123;

148 149 150 151 152 153 154 155
  mem.grow(1);

  // Works properly after grow.
  memoryFill(kPageSize, v, 1000);

  // Traps at new boundary.
  assertTraps(
      kTrapMemOutOfBounds, () => memoryFill(kPageSize + 1, v, kPageSize));
156
})();
157

158
(function TestElemDropActive() {
159 160
  const builder = new WasmModuleBuilder();
  builder.setTableBounds(5, 5);
161
  builder.addActiveElementSegment(0, WasmInitExpr.I32Const(0), [0, 0, 0]);
162 163
  builder.addFunction('drop', kSig_v_v)
      .addBody([
164
        kNumericPrefix, kExprElemDrop,
165 166 167 168 169
        0,  // Element segment index.
      ])
      .exportAs('drop');

  const instance = builder.instantiate();
170 171 172
  // Segment already got dropped after initialization and is therefore
  // not active anymore.
  instance.exports.drop();
173
})();
174 175 176 177 178 179 180 181 182 183 184

(function TestLazyDataSegmentBoundsCheck() {
  const memory = new WebAssembly.Memory({initial: 1});
  const view = new Uint8Array(memory.buffer);
  const builder = new WasmModuleBuilder();
  builder.addImportedMemory('m', 'memory', 1);
  builder.addDataSegment(kPageSize - 1, [42, 42]);
  builder.addDataSegment(0, [111, 111]);

  assertEquals(0, view[kPageSize - 1]);

185
  // Instantiation fails, memory remains unmodified.
186 187
  assertThrows(
      () => builder.instantiate({m: {memory}}), WebAssembly.RuntimeError);
188

189
  assertEquals(0, view[kPageSize - 1]);
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
  // The second segment is not initialized.
  assertEquals(0, view[0]);
})();

(function TestLazyDataAndElementSegments() {
  const table = new WebAssembly.Table({initial: 1, element: 'anyfunc'});
  const memory = new WebAssembly.Memory({initial: 1});
  const view = new Uint8Array(memory.buffer);
  const builder = new WasmModuleBuilder();

  builder.addImportedMemory('m', 'memory', 1);
  builder.addImportedTable('m', 'table', 1);
  const f = builder.addFunction('f', kSig_i_v).addBody([kExprI32Const, 42]);

  const tableIndex = 0;
205 206 207 208
  builder.addActiveElementSegment(
      tableIndex,
      WasmInitExpr.I32Const(0),
      [f.index, f.index]);
209 210 211 212 213
  builder.addDataSegment(0, [42]);

  // Instantiation fails, but still modifies the table. The memory is not
  // modified, since data segments are initialized after element segments.
  assertThrows(
214 215
      () => builder.instantiate({m: {memory, table}}),
      WebAssembly.RuntimeError);
216 217 218

  assertEquals(0, view[0]);
})();
219 220 221 222 223 224 225 226

(function TestPassiveDataSegmentNoMemory() {
  const builder = new WasmModuleBuilder();
  builder.addPassiveDataSegment([0, 1, 2]);

  // Should not throw.
  builder.instantiate();
})();
227 228 229 230 231 232 233 234 235

(function TestPassiveElementSegmentNoMemory() {
  const builder = new WasmModuleBuilder();
  builder.addFunction('f', kSig_v_v).addBody([]);
  builder.addPassiveElementSegment([0, 0, 0]);

  // Should not throw.
  builder.instantiate();
})();