@@ -673,15 +673,17 @@ Readable.prototype.read = function(n) { |
673 | 673 |
|
674 | 674 | // If we're doing read(0) to trigger a readable event, but we |
675 | 675 | // already have a bunch of data in the buffer, then just trigger |
676 | | - // the 'readable' event and move on. |
| 676 | + // the 'readable' event and move on. `state.length` cannot change |
| 677 | + // within this block, so it is loaded once instead of three times. |
| 678 | + const stateLength = state.length; |
677 | 679 | if (n === 0 && |
678 | 680 | (state[kState] & kNeedReadable) !== 0 && |
679 | 681 | ((state.highWaterMark !== 0 ? |
680 | | - state.length >= state.highWaterMark : |
681 | | - state.length > 0) || |
| 682 | + stateLength >= state.highWaterMark : |
| 683 | + stateLength > 0) || |
682 | 684 | (state[kState] & kEnded) !== 0)) { |
683 | 685 | debug('read: emitReadable'); |
684 | | - if (state.length === 0 && (state[kState] & kEnded) !== 0) |
| 686 | + if (stateLength === 0 && (state[kState] & kEnded) !== 0) |
685 | 687 | endReadable(this); |
686 | 688 | else |
687 | 689 | emitReadable(this); |
@@ -1624,8 +1626,14 @@ Readable._fromList = fromList; |
1624 | 1626 | // This function is designed to be inlinable, so please take care when making |
1625 | 1627 | // changes to the function body. |
1626 | 1628 | function fromList(n, state) { |
| 1629 | + // `state.length` cannot change while this function runs (only the |
| 1630 | + // caller updates it, after this returns) and the chunk lengths feeding |
| 1631 | + // the copy loops cannot change across the copy calls, so every |
| 1632 | + // repeated property load below is hoisted into a local. |
| 1633 | + const stateLength = state.length; |
| 1634 | + |
1627 | 1635 | // nothing buffered. |
1628 | | - if (state.length === 0) |
| 1636 | + if (stateLength === 0) |
1629 | 1637 | return null; |
1630 | 1638 |
|
1631 | 1639 | let idx = state.bufferIndex; |
@@ -1637,7 +1645,7 @@ function fromList(n, state) { |
1637 | 1645 | if ((state[kState] & kObjectMode) !== 0) { |
1638 | 1646 | ret = buf[idx]; |
1639 | 1647 | buf[idx++] = null; |
1640 | | - } else if (!n || n >= state.length) { |
| 1648 | + } else if (!n || n >= stateLength) { |
1641 | 1649 | // Read it all, truncate the list. |
1642 | 1650 | if ((state[kState] & kDecoder) !== 0) { |
1643 | 1651 | ret = ''; |
@@ -1651,61 +1659,68 @@ function fromList(n, state) { |
1651 | 1659 | ret = buf[idx]; |
1652 | 1660 | buf[idx++] = null; |
1653 | 1661 | } else { |
1654 | | - ret = Buffer.allocUnsafe(state.length); |
| 1662 | + ret = Buffer.allocUnsafe(stateLength); |
1655 | 1663 |
|
1656 | 1664 | let i = 0; |
1657 | 1665 | while (idx < len) { |
1658 | | - TypedArrayPrototypeSet(ret, buf[idx], i); |
1659 | | - i += buf[idx].length; |
| 1666 | + const data = buf[idx]; |
| 1667 | + TypedArrayPrototypeSet(ret, data, i); |
| 1668 | + i += data.length; |
1660 | 1669 | buf[idx++] = null; |
1661 | 1670 | } |
1662 | 1671 | } |
1663 | | - } else if (n < buf[idx].length) { |
1664 | | - // `slice` is the same for buffers and strings. |
1665 | | - ret = buf[idx].slice(0, n); |
1666 | | - buf[idx] = buf[idx].slice(n); |
1667 | | - } else if (n === buf[idx].length) { |
1668 | | - // First chunk is a perfect match. |
1669 | | - ret = buf[idx]; |
1670 | | - buf[idx++] = null; |
1671 | | - } else if ((state[kState] & kDecoder) !== 0) { |
1672 | | - ret = ''; |
1673 | | - while (idx < len) { |
1674 | | - const str = buf[idx]; |
1675 | | - if (n > str.length) { |
1676 | | - ret += str; |
1677 | | - n -= str.length; |
1678 | | - buf[idx++] = null; |
1679 | | - } else { |
1680 | | - if (n === str.length) { |
| 1672 | + } else { |
| 1673 | + const first = buf[idx]; |
| 1674 | + const firstLength = first.length; |
| 1675 | + if (n < firstLength) { |
| 1676 | + // `slice` is the same for buffers and strings. |
| 1677 | + ret = first.slice(0, n); |
| 1678 | + buf[idx] = first.slice(n); |
| 1679 | + } else if (n === firstLength) { |
| 1680 | + // First chunk is a perfect match. |
| 1681 | + ret = first; |
| 1682 | + buf[idx++] = null; |
| 1683 | + } else if ((state[kState] & kDecoder) !== 0) { |
| 1684 | + ret = ''; |
| 1685 | + while (idx < len) { |
| 1686 | + const str = buf[idx]; |
| 1687 | + const strLength = str.length; |
| 1688 | + if (n > strLength) { |
1681 | 1689 | ret += str; |
| 1690 | + n -= strLength; |
1682 | 1691 | buf[idx++] = null; |
1683 | 1692 | } else { |
1684 | | - ret += str.slice(0, n); |
1685 | | - buf[idx] = str.slice(n); |
| 1693 | + if (n === strLength) { |
| 1694 | + ret += str; |
| 1695 | + buf[idx++] = null; |
| 1696 | + } else { |
| 1697 | + ret += str.slice(0, n); |
| 1698 | + buf[idx] = str.slice(n); |
| 1699 | + } |
| 1700 | + break; |
1686 | 1701 | } |
1687 | | - break; |
1688 | 1702 | } |
1689 | | - } |
1690 | | - } else { |
1691 | | - ret = Buffer.allocUnsafe(n); |
1692 | | - |
1693 | | - const retLen = n; |
1694 | | - while (idx < len) { |
1695 | | - const data = buf[idx]; |
1696 | | - if (n > data.length) { |
1697 | | - TypedArrayPrototypeSet(ret, data, retLen - n); |
1698 | | - n -= data.length; |
1699 | | - buf[idx++] = null; |
1700 | | - } else { |
1701 | | - if (n === data.length) { |
| 1703 | + } else { |
| 1704 | + ret = Buffer.allocUnsafe(n); |
| 1705 | + |
| 1706 | + const retLen = n; |
| 1707 | + while (idx < len) { |
| 1708 | + const data = buf[idx]; |
| 1709 | + const dataLength = data.length; |
| 1710 | + if (n > dataLength) { |
1702 | 1711 | TypedArrayPrototypeSet(ret, data, retLen - n); |
| 1712 | + n -= dataLength; |
1703 | 1713 | buf[idx++] = null; |
1704 | 1714 | } else { |
1705 | | - TypedArrayPrototypeSet(ret, new FastBuffer(data.buffer, data.byteOffset, n), retLen - n); |
1706 | | - buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, data.length - n); |
| 1715 | + if (n === dataLength) { |
| 1716 | + TypedArrayPrototypeSet(ret, data, retLen - n); |
| 1717 | + buf[idx++] = null; |
| 1718 | + } else { |
| 1719 | + TypedArrayPrototypeSet(ret, new FastBuffer(data.buffer, data.byteOffset, n), retLen - n); |
| 1720 | + buf[idx] = new FastBuffer(data.buffer, data.byteOffset + n, dataLength - n); |
| 1721 | + } |
| 1722 | + break; |
1707 | 1723 | } |
1708 | | - break; |
1709 | 1724 | } |
1710 | 1725 | } |
1711 | 1726 | } |
|