Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Unified Diff: sdk/lib/io/websocket_impl.dart

Issue 148343002: Speed up web-socket impl by ensuring the optimized compiler is triggered. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/io/websocket_impl.dart
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 48eeca131d3f6ce888b612521836f4200e59a72b..69a7f0eb69f36793cff1db27e937694c2ec5d299 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -6,10 +6,11 @@ part of dart.io;
const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+// Matches _WebSocketOpcode.
class _WebSocketMessageType {
static const int NONE = 0;
- static const int BINARY = 1;
- static const int TEXT = 2;
+ static const int TEXT = 1;
+ static const int BINARY = 2;
}
@@ -51,31 +52,26 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
static const int CLOSED = 5;
static const int FAILURE = 6;
- int _state;
- bool _fin;
- int _opcode;
- int _len;
- bool _masked;
- int _maskingKey;
- int _remainingLenBytes;
- int _remainingMaskingKeyBytes;
- int _remainingPayloadBytes;
- int _unmaskingIndex;
-
- int _currentMessageType;
- List<int> _controlPayload;
- StreamController _controller;
-
+ int _state = START;
+ bool _fin = false;
+ int _opcode = -1;
+ int _len = -1;
+ bool _masked = false;
+ int _remainingLenBytes = -1;
+ int _remainingMaskingKeyBytes = 4;
+ int _remainingPayloadBytes = -1;
+ int _unmaskingIndex = 0;
+ int _currentMessageType = _WebSocketMessageType.NONE;
int closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
String closeReason = "";
- bool _serverSide;
EventSink _eventSink;
- _WebSocketProtocolTransformer([this._serverSide = false]) {
- _prepareForNextFrame();
- _currentMessageType = _WebSocketMessageType.NONE;
- }
+ final bool _serverSide;
+ final List _maskingBytes = new List(4);
+ final BytesBuilder _payload = new BytesBuilder();
+
+ _WebSocketProtocolTransformer([this._serverSide = false]);
Stream bind(Stream stream) {
return new Stream.eventTransformed(
@@ -101,163 +97,106 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
int count = buffer.length;
int index = 0;
int lastIndex = count;
- try {
- if (_state == CLOSED) {
- throw new WebSocketException("Data on closed connection");
- }
- if (_state == FAILURE) {
- throw new WebSocketException("Data on failed connection");
- }
- while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
- int byte = buffer[index];
- switch (_state) {
- case START:
- _fin = (byte & 0x80) != 0;
- if ((byte & 0x70) != 0) {
- // The RSV1, RSV2 bits RSV3 most be all zero.
- throw new WebSocketException("Protocol error");
- }
- _opcode = (byte & 0xF);
- switch (_opcode) {
- case _WebSocketOpcode.CONTINUATION:
+ if (_state == CLOSED) {
+ throw new WebSocketException("Data on closed connection");
+ }
+ if (_state == FAILURE) {
+ throw new WebSocketException("Data on failed connection");
+ }
+ while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
+ int byte = buffer[index];
+ if (_state <= LEN_REST) {
+ if (_state == START) {
+ _fin = (byte & 0x80) != 0;
+ if ((byte & 0x70) != 0) {
+ // The RSV1, RSV2 bits RSV3 must be all zero.
+ throw new WebSocketException("Protocol error");
+ }
+ _opcode = (byte & 0xF);
+ if (_opcode <= _WebSocketOpcode.BINARY) {
+ if (_opcode == _WebSocketOpcode.CONTINUATION) {
if (_currentMessageType == _WebSocketMessageType.NONE) {
throw new WebSocketException("Protocol error");
}
- break;
-
- case _WebSocketOpcode.TEXT:
- if (_currentMessageType != _WebSocketMessageType.NONE) {
- throw new WebSocketException("Protocol error");
- }
- _currentMessageType = _WebSocketMessageType.TEXT;
- _controller = new StreamController(sync: true);
- _controller.stream
- .transform(UTF8.decoder)
- .fold(new StringBuffer(), (buffer, str) => buffer..write(str))
- .then((buffer) {
- _eventSink.add(buffer.toString());
- }, onError: _eventSink.addError);
- break;
-
- case _WebSocketOpcode.BINARY:
+ } else {
+ assert(_opcode == _WebSocketOpcode.TEXT ||
+ _opcode == _WebSocketOpcode.BINARY);
if (_currentMessageType != _WebSocketMessageType.NONE) {
throw new WebSocketException("Protocol error");
}
- _currentMessageType = _WebSocketMessageType.BINARY;
- _controller = new StreamController(sync: true);
- _controller.stream
- .fold(new BytesBuilder(), (buffer, data) => buffer..add(data))
- .then((buffer) {
- _eventSink.add(buffer.takeBytes());
- }, onError: _eventSink.addError);
- break;
-
- case _WebSocketOpcode.CLOSE:
- case _WebSocketOpcode.PING:
- case _WebSocketOpcode.PONG:
- // Control frames cannot be fragmented.
- if (!_fin) throw new WebSocketException("Protocol error");
- break;
-
- default:
- throw new WebSocketException("Protocol error");
- }
- _state = LEN_FIRST;
- break;
-
- case LEN_FIRST:
- _masked = (byte & 0x80) != 0;
- _len = byte & 0x7F;
- if (_isControlFrame() && _len > 125) {
- throw new WebSocketException("Protocol error");
- }
- if (_len < 126) {
- _lengthDone();
- } else if (_len == 126) {
- _len = 0;
- _remainingLenBytes = 2;
- _state = LEN_REST;
- } else if (_len == 127) {
- _len = 0;
- _remainingLenBytes = 8;
- _state = LEN_REST;
- }
- break;
-
- case LEN_REST:
- _len = _len << 8 | byte;
- _remainingLenBytes--;
- if (_remainingLenBytes == 0) {
- _lengthDone();
- }
- break;
-
- case MASK:
- _maskingKey = _maskingKey << 8 | byte;
- _remainingMaskingKeyBytes--;
- if (_remainingMaskingKeyBytes == 0) {
- _maskDone();
- }
- break;
-
- case PAYLOAD:
- // The payload is not handled one byte at a time but in blocks.
- int payload;
- if (lastIndex - index <= _remainingPayloadBytes) {
- payload = lastIndex - index;
- } else {
- payload = _remainingPayloadBytes;
+ _currentMessageType = _opcode;
}
- _remainingPayloadBytes -= payload;
-
- // Unmask payload if masked.
- if (_masked) {
- for (int i = 0; i < payload; i++) {
- int maskingByte =
- ((_maskingKey >> ((3 - _unmaskingIndex) * 8)) & 0xFF);
- buffer[index + i] = buffer[index + i] ^ maskingByte;
- _unmaskingIndex = (_unmaskingIndex + 1) % 4;
- }
+ } else if (_opcode >= _WebSocketOpcode.CLOSE &&
+ _opcode <= _WebSocketOpcode.PONG) {
+ // Control frames cannot be fragmented.
+ if (!_fin) throw new WebSocketException("Protocol error");
+ } else {
+ throw new WebSocketException("Protocol error");
+ }
+ _state = LEN_FIRST;
+ } else if (_state == LEN_FIRST) {
+ _masked = (byte & 0x80) != 0;
+ _len = byte & 0x7F;
+ if (_isControlFrame() && _len > 125) {
+ throw new WebSocketException("Protocol error");
+ }
+ if (_len == 126) {
+ _len = 0;
+ _remainingLenBytes = 2;
+ _state = LEN_REST;
+ } else if (_len == 127) {
+ _len = 0;
+ _remainingLenBytes = 8;
+ _state = LEN_REST;
+ } else {
+ assert(_len < 126);
+ _lengthDone();
+ }
+ } else {
+ assert(_state == LEN_REST);
+ _len = _len << 8 | byte;
+ _remainingLenBytes--;
+ if (_remainingLenBytes == 0) {
+ _lengthDone();
+ }
+ }
+ } else {
+ if (_state == MASK) {
+ _maskingBytes[4 - _remainingMaskingKeyBytes--] = byte;
+ if (_remainingMaskingKeyBytes == 0) {
+ _maskDone();
+ }
+ } else {
+ assert(_state == PAYLOAD);
+ // The payload is not handled one byte at a time but in blocks.
+ int payload = min(lastIndex - index, _remainingPayloadBytes);
+ _remainingPayloadBytes -= payload;
+ // Unmask payload if masked.
+ if (_masked) {
+ for (int i = index; i < index + payload; i++) {
+ buffer[i] ^= _maskingBytes[_unmaskingIndex++ & 3];
}
-
- if (_isControlFrame()) {
- if (payload > 0) {
- // Allocate a buffer for collecting the control frame
- // payload if any.
- if (_controlPayload == null) {
- _controlPayload = new List<int>();
- }
- _controlPayload.addAll(buffer.sublist(index, index + payload));
- index += payload;
- }
-
- if (_remainingPayloadBytes == 0) {
- _controlFrameEnd();
- }
- } else {
- if (_currentMessageType != _WebSocketMessageType.TEXT &&
- _currentMessageType != _WebSocketMessageType.BINARY) {
- throw new WebSocketException("Protocol error");
- }
- _controller.add(
- new Uint8List.view(buffer.buffer, index, payload));
- index += payload;
- if (_remainingPayloadBytes == 0) {
- _messageFrameEnd();
- }
+ }
+ // Control frame and data frame share _payload builder.
+ _payload.add(new Uint8List.view(buffer.buffer, index, payload));
+ index += payload;
+ if (_isControlFrame()) {
+ if (_remainingPayloadBytes == 0) _controlFrameEnd();
+ } else {
+ if (_currentMessageType != _WebSocketMessageType.TEXT &&
+ _currentMessageType != _WebSocketMessageType.BINARY) {
+ throw new WebSocketException("Protocol error");
}
+ if (_remainingPayloadBytes == 0) _messageFrameEnd();
+ }
- // Hack - as we always do index++ below.
- index--;
- break;
+ // Hack - as we always do index++ below.
+ index--;
}
-
- // Move to the next byte.
- index++;
}
- } catch (e, stackTrace) {
- _state = FAILURE;
- _eventSink.addError(e, stackTrace);
+
+ // Move to the next byte.
+ index++;
}
}
@@ -267,7 +206,6 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
throw new WebSocketException("Received masked frame from server");
}
_state = MASK;
- _remainingMaskingKeyBytes = 4;
} else {
if (_serverSide) {
throw new WebSocketException("Received unmasked frame from client");
@@ -312,13 +250,12 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
if (_fin) {
switch (_currentMessageType) {
case _WebSocketMessageType.TEXT:
- _controller.close();
+ _eventSink.add(UTF8.decode(_payload.takeBytes()));
break;
case _WebSocketMessageType.BINARY:
- _controller.close();
+ _eventSink.add(_payload.takeBytes());
break;
}
- _controller = null;
_currentMessageType = _WebSocketMessageType.NONE;
}
_prepareForNextFrame();
@@ -328,16 +265,17 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
switch (_opcode) {
case _WebSocketOpcode.CLOSE:
closeCode = WebSocketStatus.NO_STATUS_RECEIVED;
- if (_controlPayload.length > 0) {
- if (_controlPayload.length == 1) {
+ if (_payload.length > 0) {
+ var bytes = _payload.takeBytes();
+ if (bytes.length == 1) {
throw new WebSocketException("Protocol error");
}
- closeCode = _controlPayload[0] << 8 | _controlPayload[1];
+ closeCode = bytes[0] << 8 | bytes[1];
if (closeCode == WebSocketStatus.NO_STATUS_RECEIVED) {
throw new WebSocketException("Protocol error");
}
- if (_controlPayload.length > 2) {
- closeReason = UTF8.decode(_controlPayload.sublist(2));
+ if (bytes.length > 2) {
+ closeReason = UTF8.decode(bytes.sublist(2));
}
}
_state = CLOSED;
@@ -345,11 +283,11 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
break;
case _WebSocketOpcode.PING:
- _eventSink.add(new _WebSocketPing(_controlPayload));
+ _eventSink.add(new _WebSocketPing(_payload.takeBytes()));
break;
case _WebSocketOpcode.PONG:
- _eventSink.add(new _WebSocketPong(_controlPayload));
+ _eventSink.add(new _WebSocketPong(_payload.takeBytes()));
break;
}
_prepareForNextFrame();
@@ -363,16 +301,13 @@ class _WebSocketProtocolTransformer implements StreamTransformer, EventSink {
void _prepareForNextFrame() {
if (_state != CLOSED && _state != FAILURE) _state = START;
- _fin = null;
- _opcode = null;
- _len = null;
- _masked = null;
- _maskingKey = 0;
- _remainingLenBytes = null;
- _remainingMaskingKeyBytes = null;
- _remainingPayloadBytes = null;
+ _fin = false;
+ _opcode = -1;
+ _len = -1;
+ _remainingLenBytes = -1;
+ _remainingMaskingKeyBytes = 4;
+ _remainingPayloadBytes = -1;
_unmaskingIndex = 0;
- _controlPayload = null;
}
}
@@ -571,7 +506,7 @@ class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink {
} else if (dataLength > 125) {
headerSize += 2;
}
- List<int> header = new List<int>(headerSize);
+ Uint8List header = new Uint8List(headerSize);
int index = 0;
// Set FIN and opcode.
header[index++] = 0x80 | opcode;
@@ -605,7 +540,7 @@ class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink {
}
if (data is Uint8List) {
for (int i = 0; i < data.length; i++) {
- list[i] = data[i] ^ maskBytes[i % 4];
+ list[i] = data[i] ^ maskBytes[i & 3];
}
} else {
for (int i = 0; i < data.length; i++) {
@@ -614,7 +549,7 @@ class _WebSocketOutgoingTransformer implements StreamTransformer, EventSink {
"List element is not a byte value "
"(value ${data[i]} at index $i)");
}
- list[i] = data[i] ^ maskBytes[i % 4];
+ list[i] = data[i] ^ maskBytes[i & 3];
}
}
data = list;
@@ -786,7 +721,7 @@ class _WebSocketImpl extends Stream implements WebSocket {
Random random = new Random();
// Generate 16 random bytes.
- List<int> nonceData = new List<int>(16);
+ Uint8List nonceData = new Uint8List(16);
for (int i = 0; i < 16; i++) {
nonceData[i] = random.nextInt(256);
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698