mirror of https://github.com/tc39/test262.git
RAB: Integrate staging tests for .fill method (#4075)
RAB: Integrate staging tests for the .fill method of Array.prototype and TypedArray.prototype This is part of PR #3888 to make reviewing easier. Includes changes to use the helper ./harness/resizableArrayBufferUtils.js
This commit is contained in:
parent
cbdff1ca5f
commit
c2815ec090
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright 2023 the V8 project authors. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-array.prototype.fill
|
||||||
|
description: >
|
||||||
|
Array.p.fill behaves correctly when the receiver is backed by
|
||||||
|
resizable buffer
|
||||||
|
includes: [compareArray.js, resizableArrayBufferUtils.js]
|
||||||
|
features: [resizable-arraybuffer]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
function ReadDataFromBuffer(ab, ctor) {
|
||||||
|
let result = [];
|
||||||
|
const ta = new ctor(ab, 0, ab.byteLength / ctor.BYTES_PER_ELEMENT);
|
||||||
|
for (let item of ta) {
|
||||||
|
result.push(Number(item));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ArrayFillHelper(ta, n, start, end) {
|
||||||
|
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
|
||||||
|
Array.prototype.fill.call(ta, BigInt(n), start, end);
|
||||||
|
} else {
|
||||||
|
Array.prototype.fill.call(ta, n, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
|
||||||
|
const lengthTracking = new ctor(rab, 0);
|
||||||
|
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(fixedLength, 1);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(fixedLengthWithOffset, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTracking, 3);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTrackingWithOffset, 4);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
4
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Shrink so that fixed length TAs go out of bounds.
|
||||||
|
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
ArrayFillHelper(fixedLength, 5);
|
||||||
|
ArrayFillHelper(fixedLengthWithOffset, 6);
|
||||||
|
// We'll check below that these were no-op.
|
||||||
|
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTracking, 7);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTrackingWithOffset, 8);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
8
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Shrink so that the TAs with offset go out of bounds.
|
||||||
|
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
// We'll check below that these were no-op.
|
||||||
|
ArrayFillHelper(fixedLength, 9);
|
||||||
|
ArrayFillHelper(fixedLengthWithOffset, 10);
|
||||||
|
ArrayFillHelper(lengthTrackingWithOffset, 11);
|
||||||
|
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [7]);
|
||||||
|
ArrayFillHelper(lengthTracking, 12);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [12]);
|
||||||
|
|
||||||
|
// Grow so that all TAs are back in-bounds.
|
||||||
|
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
ArrayFillHelper(fixedLength, 13);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(fixedLengthWithOffset, 14);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
14,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTracking, 15);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTrackingWithOffset, 16);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Filling with non-undefined start & end.
|
||||||
|
ArrayFillHelper(fixedLength, 17, 1, 3);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
17,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(fixedLengthWithOffset, 18, 1, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
17,
|
||||||
|
18,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTracking, 19, 1, 3);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
19,
|
||||||
|
19,
|
||||||
|
18,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
ArrayFillHelper(lengthTrackingWithOffset, 20, 1, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
19,
|
||||||
|
19,
|
||||||
|
20,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright 2023 the V8 project authors. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-array.prototype.fill
|
||||||
|
description: >
|
||||||
|
Array.p.fill called on a TypedArray backed by a resizable buffer
|
||||||
|
that goes out of bounds during evaluation of the arguments
|
||||||
|
includes: [compareArray.js, resizableArrayBufferUtils.js]
|
||||||
|
features: [resizable-arraybuffer]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
function ReadDataFromBuffer(ab, ctor) {
|
||||||
|
let result = [];
|
||||||
|
const ta = new ctor(ab, 0, ab.byteLength / ctor.BYTES_PER_ELEMENT);
|
||||||
|
for (let item of ta) {
|
||||||
|
result.push(Number(item));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ArrayFillHelper(ta, n, start, end) {
|
||||||
|
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
|
||||||
|
Array.prototype.fill.call(ta, BigInt(n), start, end);
|
||||||
|
} else {
|
||||||
|
Array.prototype.fill.call(ta, n, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const evil = {
|
||||||
|
valueOf: () => {
|
||||||
|
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ArrayFillHelper(fixedLength, evil, 1, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const evil = {
|
||||||
|
valueOf: () => {
|
||||||
|
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ArrayFillHelper(fixedLength, 3, evil, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const evil = {
|
||||||
|
valueOf: () => {
|
||||||
|
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ArrayFillHelper(fixedLength, 3, 1, evil);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright 2023 the V8 project authors. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-%typedarray%.prototype.fill
|
||||||
|
description: >
|
||||||
|
TypedArray.p.fill behaves correctly on receivers backed by a resizable
|
||||||
|
buffer that's resized during argument coercion
|
||||||
|
includes: [resizableArrayBufferUtils.js]
|
||||||
|
features: [resizable-arraybuffer]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
function TypedArrayFillHelper(ta, n, start, end) {
|
||||||
|
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
|
||||||
|
ta.fill(BigInt(n), start, end);
|
||||||
|
} else {
|
||||||
|
ta.fill(n, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const evil = {
|
||||||
|
valueOf: () => {
|
||||||
|
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert.throws(TypeError, () => {
|
||||||
|
TypedArrayFillHelper(fixedLength, evil, 1, 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const evil = {
|
||||||
|
valueOf: () => {
|
||||||
|
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert.throws(TypeError, () => {
|
||||||
|
TypedArrayFillHelper(fixedLength, 3, evil, 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const evil = {
|
||||||
|
valueOf: () => {
|
||||||
|
rab.resize(2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert.throws(TypeError, () => {
|
||||||
|
TypedArrayFillHelper(fixedLength, 3, 1, evil);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
// Copyright 2023 the V8 project authors. All rights reserved.
|
||||||
|
// This code is governed by the BSD license found in the LICENSE file.
|
||||||
|
|
||||||
|
/*---
|
||||||
|
esid: sec-%typedarray%.prototype.fill
|
||||||
|
description: >
|
||||||
|
TypedArray.p.fill behaves correctly when the receiver is backed by
|
||||||
|
resizable buffer
|
||||||
|
includes: [compareArray.js, resizableArrayBufferUtils.js]
|
||||||
|
features: [resizable-arraybuffer]
|
||||||
|
---*/
|
||||||
|
|
||||||
|
function ReadDataFromBuffer(ab, ctor) {
|
||||||
|
let result = [];
|
||||||
|
const ta = new ctor(ab, 0, ab.byteLength / ctor.BYTES_PER_ELEMENT);
|
||||||
|
for (let item of ta) {
|
||||||
|
result.push(Number(item));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TypedArrayFillHelper(ta, n, start, end) {
|
||||||
|
if (ta instanceof BigInt64Array || ta instanceof BigUint64Array) {
|
||||||
|
ta.fill(BigInt(n), start, end);
|
||||||
|
} else {
|
||||||
|
ta.fill(n, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let ctor of ctors) {
|
||||||
|
const rab = CreateResizableArrayBuffer(4 * ctor.BYTES_PER_ELEMENT, 8 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
const fixedLength = new ctor(rab, 0, 4);
|
||||||
|
const fixedLengthWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT, 2);
|
||||||
|
const lengthTracking = new ctor(rab, 0);
|
||||||
|
const lengthTrackingWithOffset = new ctor(rab, 2 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(fixedLength, 1);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(fixedLengthWithOffset, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
2
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTracking, 3);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
3
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTrackingWithOffset, 4);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
4
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Shrink so that fixed length TAs go out of bounds.
|
||||||
|
rab.resize(3 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
assert.throws(TypeError, () => TypedArrayFillHelper(fixedLength, 5));
|
||||||
|
assert.throws(TypeError, () => TypedArrayFillHelper(fixedLengthWithOffset, 6));
|
||||||
|
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTracking, 7);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
7
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTrackingWithOffset, 8);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
7,
|
||||||
|
7,
|
||||||
|
8
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Shrink so that the TAs with offset go out of bounds.
|
||||||
|
rab.resize(1 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
assert.throws(TypeError, () => TypedArrayFillHelper(fixedLength, 9));
|
||||||
|
assert.throws(TypeError, () => TypedArrayFillHelper(fixedLengthWithOffset, 10));
|
||||||
|
assert.throws(TypeError, () => TypedArrayFillHelper(lengthTrackingWithOffset, 11));
|
||||||
|
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [7]);
|
||||||
|
TypedArrayFillHelper(lengthTracking, 12);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [12]);
|
||||||
|
|
||||||
|
// Grow so that all TAs are back in-bounds.
|
||||||
|
rab.resize(6 * ctor.BYTES_PER_ELEMENT);
|
||||||
|
TypedArrayFillHelper(fixedLength, 13);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(fixedLengthWithOffset, 14);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
13,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
14,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTracking, 15);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
15
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTrackingWithOffset, 16);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
15,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Filling with non-undefined start & end.
|
||||||
|
TypedArrayFillHelper(fixedLength, 17, 1, 3);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
17,
|
||||||
|
16,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(fixedLengthWithOffset, 18, 1, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
17,
|
||||||
|
18,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTracking, 19, 1, 3);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
19,
|
||||||
|
19,
|
||||||
|
18,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
TypedArrayFillHelper(lengthTrackingWithOffset, 20, 1, 2);
|
||||||
|
assert.compareArray(ReadDataFromBuffer(rab, ctor), [
|
||||||
|
15,
|
||||||
|
19,
|
||||||
|
19,
|
||||||
|
20,
|
||||||
|
16,
|
||||||
|
16
|
||||||
|
]);
|
||||||
|
}
|
Loading…
Reference in New Issue