anchor.diff:        header.setRange(index, index + 4, maskBytes);
         index += 4;
         if (data != null) {
  -        var list;
  +        Uint8List list;
           // If this is a text message just do the masking inside the
           // encoded data.
  -        if (opcode == _WebSocketOpcode.TEXT) {
  +        if (opcode == _WebSocketOpcode.TEXT && data is Uint8List) {
             list = data;
           } else {
  -          list = new Uint8List(data.length);
  -        }
  -        if (data is Uint8List) {
  -          for (int i = 0; i < data.length; i++) {
  -            list[i] = data[i] ^ maskBytes[i & 3];
  -          }
  -        } else {
  -          for (int i = 0; i < data.length; i++) {
  -            if (data[i] < 0 || 255 < data[i]) {
  -              throw new ArgumentError(
  -                  "List element is not a byte value "
  -                  "(value ${data[i]} at index $i)");
  +          if (data is Uint8List) {
  +            list = new Uint8List.fromList(data);
  +          } else {
  +            list = new Uint8List(data.length);
  +            for (int i = 0; i < data.length; i++) {
  +              if (data[i] < 0 || 255 < data[i]) {
  +                throw new ArgumentError(
  +                    "List element is not a byte value "
  +                    "(value ${data[i]} at index $i)");
  +              }
  +              list[i] = data[i];
               }
  -            list[i] = data[i] ^ maskBytes[i & 3];
  -          }
  +          }
  +        }
  +        const int BLOCK_SIZE = 16;
  +        int blockCount = list.length ~/ BLOCK_SIZE;
  +        if (blockCount > 0) {
  +          // Create mask block.
  +          int mask = 0;
  +          for (int i = 3; i >= 0; i--) {
  +            mask = (mask << 8) | maskBytes[i];
  +          }
  +          Int32x4 blockMask = new Int32x4(mask, mask, mask, mask);
  +          Int32x4List blockBuffer = new Int32x4List.view(
  +              list.buffer, 0, blockCount);
  +          for (int i = 0; i < blockBuffer.length; i++) {
  +            blockBuffer[i] ^= blockMask;
  +          }
  +        }
  +        // Handle end.
  +        for (int i = blockCount * BLOCK_SIZE; i < list.length; i++) {
  +          list[i] ^= maskBytes[i & 3];
           }
           data = list;
         }
  
positive.code: 
        // Move to the next byte.
        index++;
      }
    }
  
  
negative.code:         } else {
            assert(_state == PAYLOAD);
            // The payload is not handled one byte at a time but in blocks.
            int payloadLength = min(lastIndex - index, _remainingPayloadBytes);
            _remainingPayloadBytes -= payloadLength;
            // Unmask payload if masked.
            if (_masked) {
              _unmask(index, payloadLength, buffer);
            }
            // Control frame and data frame share _payload builder.
            _payload.add(new Uint8List.view(buffer.buffer, index, payloadLength));
            index += payloadLength;
            if (_isControlFrame()) {
              if (_remainingPayloadBytes == 0) _controlFrameEnd();
            } else {
  