Add support for abortion in v8::OutputStream.

It's a good idea to allow receiver to interrupt data transmission.

Review URL: http://codereview.chromium.org/3409002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5452 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent fc83faa8
......@@ -3204,6 +3204,10 @@ public:
enum OutputEncoding {
kAscii = 0 // 7-bit ASCII.
};
enum WriteResult {
kContinue = 0,
kAbort = 1
};
virtual ~OutputStream() {}
/** Notify about the end of stream. */
virtual void EndOfStream() = 0;
......@@ -3211,8 +3215,12 @@ public:
virtual int GetChunkSize() { return 1024; }
/** Get preferred output encoding. Called only once. */
virtual OutputEncoding GetOutputEncoding() { return kAscii; }
/** Writes the next chunk of snapshot data into the stream. */
virtual void WriteAsciiChunk(char* data, int size) = 0;
/**
* Writes the next chunk of snapshot data into the stream. Writing
* can be stopped by returning kAbort as function result. EndOfStream
* will not be called in case writing was aborted.
*/
virtual WriteResult WriteAsciiChunk(char* data, int size) = 0;
};
......
......@@ -2140,9 +2140,11 @@ class OutputStreamWriter {
: stream_(stream),
chunk_size_(stream->GetChunkSize()),
chunk_(chunk_size_),
chunk_pos_(0) {
chunk_pos_(0),
aborted_(false) {
ASSERT(chunk_size_ > 0);
}
bool aborted() { return aborted_; }
void AddCharacter(char c) {
ASSERT(c != '\0');
ASSERT(chunk_pos_ < chunk_size_);
......@@ -2170,6 +2172,7 @@ class OutputStreamWriter {
void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
void AddNumber(uint64_t n) { AddNumberImpl<uint64_t>(n, "%llu"); }
void Finalize() {
if (aborted_) return;
ASSERT(chunk_pos_ < chunk_size_);
if (chunk_pos_ != 0) {
WriteChunk();
......@@ -2194,13 +2197,16 @@ class OutputStreamWriter {
}
}
void WriteChunk() {
stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_);
if (aborted_) return;
if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) ==
v8::OutputStream::kAbort) aborted_ = true;
}
v8::OutputStream* stream_;
int chunk_size_;
ScopedVector<char> chunk_;
int chunk_pos_;
bool aborted_;
};
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
......@@ -2210,22 +2216,29 @@ void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
// Since nodes graph is cyclic, we need the first pass to enumerate
// them. Strings can be serialized in one pass.
EnumerateNodes();
SerializeImpl();
delete writer_;
writer_ = NULL;
}
void HeapSnapshotJSONSerializer::SerializeImpl() {
writer_->AddCharacter('{');
writer_->AddString("\"snapshot\":{");
SerializeSnapshot();
if (writer_->aborted()) return;
writer_->AddString("},\n");
writer_->AddString("\"nodes\":[");
SerializeNodes();
if (writer_->aborted()) return;
writer_->AddString("],\n");
writer_->AddString("\"strings\":[");
SerializeStrings();
if (writer_->aborted()) return;
writer_->AddCharacter(']');
writer_->AddCharacter('}');
writer_->Finalize();
delete writer_;
writer_ = NULL;
}
......@@ -2296,6 +2309,7 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
writer_->AddNumber(children.length());
for (int i = 0; i < children.length(); ++i) {
SerializeEdge(&children[i]);
if (writer_->aborted()) return;
}
}
......@@ -2363,6 +2377,7 @@ void HeapSnapshotJSONSerializer::SerializeNodes() {
}
for (int i = 0; i < sorted_nodes.length(); ++i) {
SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key));
if (writer_->aborted()) return;
}
}
......@@ -2443,6 +2458,7 @@ void HeapSnapshotJSONSerializer::SerializeStrings() {
writer_->AddCharacter(',');
SerializeString(
reinterpret_cast<const unsigned char*>(sorted_strings[i]->key));
if (writer_->aborted()) return;
}
}
......
......@@ -1003,6 +1003,7 @@ class HeapSnapshotJSONSerializer {
int GetNodeId(HeapEntry* entry);
int GetStringId(const char* s);
void SerializeEdge(HeapGraphEdge* edge);
void SerializeImpl();
void SerializeNode(HeapEntry* entry);
void SerializeNodes();
void SerializeSnapshot();
......
......@@ -993,13 +993,18 @@ namespace {
class TestJSONStream : public v8::OutputStream {
public:
TestJSONStream() : eos_signaled_(0) {}
TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
explicit TestJSONStream(int abort_countdown)
: eos_signaled_(0), abort_countdown_(abort_countdown) {}
virtual ~TestJSONStream() {}
virtual void EndOfStream() { ++eos_signaled_; }
virtual void WriteAsciiChunk(char* buffer, int chars_written) {
virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
if (abort_countdown_ > 0) --abort_countdown_;
if (abort_countdown_ == 0) return kAbort;
CHECK_GT(chars_written, 0);
i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
memcpy(chunk.start(), buffer, chars_written);
return kContinue;
}
void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
int eos_signaled() { return eos_signaled_; }
......@@ -1007,6 +1012,7 @@ class TestJSONStream : public v8::OutputStream {
private:
i::Collector<char> buffer_;
int eos_signaled_;
int abort_countdown_;
};
class AsciiResource: public v8::String::ExternalAsciiStringResource {
......@@ -1123,4 +1129,16 @@ TEST(HeapSnapshotJSONSerialization) {
*v8::String::Utf8Value(string));
}
TEST(HeapSnapshotJSONSerializationAborting) {
v8::HandleScope scope;
LocalContext env;
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"));
TestJSONStream stream(5);
snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
CHECK_GT(stream.size(), 0);
CHECK_EQ(0, stream.eos_signaled());
}
#endif // ENABLE_LOGGING_AND_PROFILING
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment