--- /dev/null
+"use strict";
+
+function createRNG(seed)
+{
+ return function() {
+ // Robert Jenkins' 32 bit integer hash function.
+ seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
+ seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
+ seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
+ seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
+ seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
+ seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
+ return (seed & 0xfffffff) / 0x10000000;
+ };
+}
+
+let random = createRNG(0x7a11bec8);
+
+function mergeSorted(array, cont)
+{
+ if (array.length <= 1)
+ return cont(array);
+
+ let midIndex = Math.floor(array.length / 2);
+ return mergeSorted(array.slice(0, midIndex), (left) => {
+ return mergeSorted(array.slice(midIndex), (right) => {
+
+ let result = [];
+
+ function finish(source, index)
+ {
+ if (index >= source.length)
+ return;
+ result.push(source[index]);
+ return finish(source, index + 1);
+ }
+
+ function merge(leftIndex, rightIndex)
+ {
+ if (leftIndex >= left.length)
+ return finish(right, rightIndex);
+ if (rightIndex >= right.length)
+ return finish(left, leftIndex);
+
+ let leftValue = left[leftIndex];
+ let rightValue = right[rightIndex];
+ if (leftValue < rightValue) {
+ result.push(leftValue);
+ return merge(leftIndex + 1, rightIndex);
+ }
+ result.push(rightValue);
+ return merge(leftIndex, rightIndex + 1);
+ }
+
+ merge(0, 0);
+
+ return cont(result);
+}); }); }
+
+function checkSorted(array)
+{
+ function check(index)
+ {
+ if (index >= array.length - 1)
+ return;
+
+ if (array[index] > array[index + 1])
+ throw new Error("array not sorted at index " + index + ": " + array);
+
+ return check(index + 1);
+ }
+
+ check(0);
+}
+
+function checkSpectrum(a, b)
+{
+ var aMap = new Map();
+ var bMap = new Map();
+
+ function add(map, value)
+ {
+ let existing = map.get(value);
+ if (existing == null)
+ existing = 0;
+ map.set(value, existing + 1);
+ }
+
+ function build(map, array, index)
+ {
+ if (index >= array.length)
+ return;
+
+ add(map, array[index]);
+ return build(map, array, index + 1);
+ }
+
+ build(aMap, a, 0);
+ build(bMap, b, 0);
+
+ function compare(keys)
+ {
+ let entry = keys.next();
+ if (entry.done)
+ return;
+ if (aMap.get(entry.value) != bMap.get(entry.value))
+ throw new Error("arrays don't have the same number of: " + entry.value + " (a = " + a + ", b = " + b + ")");
+ return compare(keys);
+ }
+
+ compare(aMap.keys());
+}
+
+function buildArray(length, value)
+{
+ let array = [];
+
+ function build()
+ {
+ if (array.length >= length)
+ return;
+ array.push(value(array.length));
+ return build();
+ }
+
+ build();
+
+ return array;
+}
+
+let arrays = [
+ buildArray(10, x => x),
+ buildArray(10, x => -x),
+ buildArray(1000, x => random())
+];
+
+function test(index)
+{
+ if (index >= arrays.length)
+ return;
+
+ let array = arrays[index];
+ mergeSorted(array, (sorted) => {
+ checkSorted(sorted);
+ checkSpectrum(array, sorted);
+ test(index + 1);
+}); }
+
+for (var i = 0; i < 100; ++i)
+ test(0);
if (UNLIKELY(!Options::optimizeRecursiveTailCalls()))
return false;
+ // Currently we cannot do this optimisation for closures. The problem is that "emitFunctionChecks" which we use later is too coarse, only checking the executable
+ // and not the value of captured variables.
+ if (callVariant.isClosureCall())
+ return false;
+
auto targetExecutable = callVariant.executable();
InlineStackEntry* stackEntry = m_inlineStackTop;
do {
return false;
}
- // We must add some check that the profiling information was correct and the target of this call is what we thought
+ // We must add some check that the profiling information was correct and the target of this call is what we thought.
emitFunctionCheckIfNeeded();
+ // We flush everything, as if we were in the backedge of a loop (see treatment of op_jmp in parseBlock).
+ flushForTerminal();
// We must set the arguments to the right values
int argIndex = 0;
m_inlineStackTop = oldStackTop;
m_exitOK = false;
- // We flush everything, as if we were in the backedge of a loop (see treatment of op_jmp in parseBlock).
- flushForTerminal();
-
BasicBlock** entryBlockPtr = tryBinarySearch<BasicBlock*, unsigned>(stackEntry->m_blockLinkingTargets, stackEntry->m_blockLinkingTargets.size(), OPCODE_LENGTH(op_enter), getBytecodeBeginForBlock);
RELEASE_ASSERT(entryBlockPtr);
addJumpTo(*entryBlockPtr);