v8_mock.js 6.13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2016 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.

// This is intended for permanent JS behavior changes for mocking out
// non-deterministic behavior. For temporary suppressions, please refer to
// v8_suppressions.js.
// This file is loaded before each correctness test cases and won't get
// minimized.


// This will be overridden in the test cases. The override can be minimized.
13
var prettyPrinted = function prettyPrinted(msg) { return msg; };
14 15

// Mock Math.random.
16
(function() {
17
  let index = 1;
18
  Math.random = function() {
19 20
      const x = Math.sin(index++) * 10000;
      return x - Math.floor(x);
21 22
  }
})();
23

24 25 26 27 28 29 30 31 32 33 34 35 36
// Mock Math.pow. Work around an optimization for -0.5.
(function() {
  const origMathPow = Math.pow;
  Math.pow = function(a, b) {
    if (b === -0.5) {
      return 0;
    } else {
      return origMathPow(a, b);
    }
  }
})();


37
// Mock Date.
38 39 40 41 42 43 44
(function() {
  let index = 0;
  let mockDate = 1477662728696;
  const mockDateNow = function() {
    index = (index + 1) % 10;
    mockDate = mockDate + index + 1;
    return mockDate;
45
  }
46

47
  const origDate = Date;
48
  const construct = Reflect.construct;
49 50 51
  const constructDate = function(args) {
    let result;
    if (args.length) {
52
      result = construct(origDate, args);
53
    } else {
54
      result = new origDate(mockDateNow());
55 56 57 58
    }
    result.constructor = function(...args) { return constructDate(args); }
    Object.defineProperty(
        result, "constructor", { configurable: false, writable: false });
59
    return result;
60 61
  }

62 63 64 65
  origDate.prototype.constructor = function(...args) {
    return constructDate(args);
  };

66
  var handler = {
67 68
    apply: function(target, thisArg, args) {
      return constructDate(args);
69
    },
70 71
    construct: function(target, args, newTarget) {
      return constructDate(args);
72 73 74 75 76
    },
    get: function(target, property, receiver) {
      if (property == "now") {
        return mockDateNow;
      }
77
      if (property == "prototype") {
78
        return origDate.prototype;
79
      }
80 81
    },
  }
82

83 84
  Date = new Proxy(Date, handler);
})();
85

86
// Mock performance methods.
87 88
performance.now = function() { return 1.2; };
performance.measureMemory = function() { return []; };
89 90

// Mock readline so that test cases don't hang.
91
readline = function() { return "foo"; };
92

93
// Mock stack traces.
94
Error.prepareStackTrace = function(error, structuredStackTrace) {
95
  return "";
96
};
97 98
Object.defineProperty(
    Error, 'prepareStackTrace', { configurable: false, writable: false });
99

100
// Mock buffer access in float typed arrays because of varying NaN patterns.
101
(function() {
102 103 104
  const origArrayFrom = Array.from;
  const origArrayIsArray = Array.isArray;
  const origFunctionPrototype = Function.prototype;
105
  const origIsNaN = isNaN;
106
  const origIterator = Symbol.iterator;
107 108 109 110 111 112 113 114 115 116 117 118
  const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; };
  const mock = function(type) {

    // Remove NaN values from parameters to "set" function.
    const set = type.prototype.set;
    type.prototype.set = function(array, offset) {
      if (Array.isArray(array)) {
        array = array.map(deNaNify);
      }
      set.apply(this, [array, offset]);
    };

119
    const handler = {
120
      // Remove NaN values from parameters to constructor.
121
      construct: function(target, args) {
122
        for (let i = 0; i < args.length; i++) {
123
          if (args[i] != null &&
124
              typeof args[i][origIterator] === 'function') {
125
            // Consume iterators.
126
            args[i] = origArrayFrom(args[i]);
127
          }
128
          if (origArrayIsArray(args[i])) {
129
            args[i] = args[i].map(deNaNify);
130 131
          }
        }
132

133
        const obj = new (
134
            origFunctionPrototype.bind.call(type, null, ...args));
135 136 137
        return new Proxy(obj, {
          get: function(x, prop) {
            if (typeof x[prop] == "function")
138
              return x[prop].bind(obj);
139 140
            return x[prop];
          },
141 142 143 144 145
          // Remove NaN values that get assigned.
          set: function(target, prop, value, receiver) {
            target[prop] = deNaNify(value);
            return value;
          }
146
        });
147 148
      },
    };
149
    return new Proxy(type, handler);
150
  }
151

152 153 154
  Float32Array = mock(Float32Array);
  Float64Array = mock(Float64Array);
})();
155

156 157 158 159 160 161 162 163 164 165 166 167 168 169
// Mock buffer access via DataViews because of varying NaN patterns.
(function() {
  const origIsNaN = isNaN;
  const deNaNify = function(value) { return origIsNaN(value) ? 1 : value; };
  const origSetFloat32 = DataView.prototype.setFloat32;
  DataView.prototype.setFloat32 = function(offset, value, ...rest) {
    origSetFloat32.call(this, offset, deNaNify(value), ...rest);
  };
  const origSetFloat64 = DataView.prototype.setFloat64;
  DataView.prototype.setFloat64 = function(offset, value, ...rest) {
    origSetFloat64.call(this, offset, deNaNify(value), ...rest);
  };
})();

170
// Mock Worker.
171 172
(function() {
  let index = 0;
173 174
  // TODO(machenbach): Randomize this for each test case, but keep stable
  // during comparison. Also data and random above.
175
  const workerMessages = [
176 177 178 179
    undefined, 0, -1, "", "foo", 42, [], {}, [0], {"x": 0}
  ];
  Worker = function(code){
    try {
180
      print(prettyPrinted(eval(code)));
181
    } catch(e) {
182
      print(prettyPrinted(e));
183 184 185 186 187 188
    }
    this.getMessage = function(){
      index = (index + 1) % 10;
      return workerMessages[index];
    }
    this.postMessage = function(msg){
189
      print(prettyPrinted(msg));
190 191 192
    }
  };
})();
193 194 195

// Mock Realm.
Realm.eval = function(realm, code) { return eval(code) };
196 197 198 199 200 201 202 203

// Mock the nondeterministic parts of WeakRef and FinalizationRegistry.
WeakRef.prototype.deref = function() { };
FinalizationRegistry = function(callback) { };
FinalizationRegistry.prototype.register = function(target, holdings) { };
FinalizationRegistry.prototype.unregister = function(unregisterToken) { };
FinalizationRegistry.prototype.cleanupSome = function() { };
FinalizationRegistry.prototype[Symbol.toStringTag] = "FinalizationRegistry";
204 205 206 207 208 209 210

// Mock the nondeterministic Atomics.waitAsync.
Atomics.waitAsync = function() {
  // Return a mock "Promise" whose "then" function will call the callback
  // immediately.
  return {'value': {'then': function (f) { f(); }}};
}