Revision: 18680
Author: [email protected]
Date: Mon Jan 20 09:25:23 2014 UTC
Log: Experimental lexer: fix internalization and allocation of
literals.
BUG=
[email protected], [email protected]
Review URL: https://codereview.chromium.org/140913009
http://code.google.com/p/v8/source/detail?r=18680
Modified:
/branches/experimental/parser/src/factory.cc
/branches/experimental/parser/src/factory.h
/branches/experimental/parser/src/lexer/experimental-scanner.cc
/branches/experimental/parser/src/lexer/experimental-scanner.h
/branches/experimental/parser/src/objects-inl.h
/branches/experimental/parser/src/objects.cc
/branches/experimental/parser/src/parser.cc
/branches/experimental/parser/src/parser.h
=======================================
--- /branches/experimental/parser/src/factory.cc Fri Jan 17 11:13:31 2014
UTC
+++ /branches/experimental/parser/src/factory.cc Mon Jan 20 09:25:23 2014
UTC
@@ -227,7 +227,7 @@
Handle<String> Factory::InternalizeOneByteString(
Handle<SeqOneByteString> string, int from, int length) {
- SubStringOneByteStringKey key(string, from, length);
+ SubStringKey<uint8_t> key(string, from, length);
return InternalizeStringWithKey(&key);
}
@@ -244,6 +244,12 @@
isolate()->heap()->InternalizeStringWithKey(key),
String);
}
+
+
+template Handle<String> Factory::InternalizeStringWithKey<
+ SubStringKey<uint8_t> > (SubStringKey<uint8_t>* key);
+template Handle<String> Factory::InternalizeStringWithKey<
+ SubStringKey<uint16_t> > (SubStringKey<uint16_t>* key);
Handle<String> Factory::NewStringFromOneByte(Vector<const uint8_t> string,
=======================================
--- /branches/experimental/parser/src/factory.h Fri Jan 17 11:13:31 2014 UTC
+++ /branches/experimental/parser/src/factory.h Mon Jan 20 09:25:23 2014 UTC
@@ -99,9 +99,9 @@
}
Handle<String> InternalizeString(Handle<String> str);
Handle<String> InternalizeOneByteString(Vector<const uint8_t> str);
- Handle<String> InternalizeOneByteString(Handle<SeqOneByteString>,
- int from,
- int length);
+ Handle<String> InternalizeOneByteString(
+ Handle<SeqOneByteString>, int from, int length);
+
Handle<String> InternalizeTwoByteString(Vector<const uc16> str);
template<class StringTableKey>
=======================================
--- /branches/experimental/parser/src/lexer/experimental-scanner.cc Mon
Dec 2 15:07:21 2013 UTC
+++ /branches/experimental/parser/src/lexer/experimental-scanner.cc Mon Jan
20 09:25:23 2014 UTC
@@ -50,6 +50,33 @@
String::FlatContent content = source_handle_->GetFlatContent();
return reinterpret_cast<const
int8_t*>(content.ToOneByteVector().start());
}
+
+
+template<>
+bool ExperimentalScanner<uint8_t>::IsSubstringOfSource(const TokenDesc&
token) {
+ return !token.has_escapes;
+}
+
+
+template<>
+bool ExperimentalScanner<uint16_t>::IsSubstringOfSource(
+ const TokenDesc& token) {
+ if (token.has_escapes) return false;
+ const uint16_t* start = buffer_ + token.beg_pos;
+ const uint16_t* end = buffer_ + token.end_pos;
+ for (const uint16_t* cursor = start; cursor != end; ++cursor) {
+ if (*cursor >= unibrow::Latin1::kMaxChar) return true;
+ }
+ return false;
+}
+
+
+template<>
+bool ExperimentalScanner<int8_t>::IsSubstringOfSource(const TokenDesc&
token) {
+ // FIXME: implement.
+ UNREACHABLE();
+ return false;
+}
template<>
@@ -62,37 +89,16 @@
++start;
--end;
}
- if (!token.has_escapes) {
+ if (IsSubstringOfSource(token)) {
literal->is_ascii = true;
+ literal->is_in_buffer = false;
+ literal->offset = start - buffer_;
literal->length = end - start;
literal->ascii_string = Vector<const char>(
reinterpret_cast<const char*>(start), literal->length);
return true;
}
- literal->buffer.Reset();
- for (const uint8_t* cursor = start; cursor != end;) {
- if (*cursor != '\\') {
- literal->buffer.AddChar(*cursor++);
- } else if (token.token == Token::IDENTIFIER) {
- uc32 c;
- cursor = ScanIdentifierUnicodeEscape(cursor, end, &c);
- ASSERT(cursor != NULL);
- if (cursor == NULL) return false;
- literal->buffer.AddChar(c);
- } else {
- cursor = ScanEscape(cursor, end, &literal->buffer);
- ASSERT(cursor != NULL);
- if (cursor == NULL) return false;
- }
- }
- literal->is_ascii = literal->buffer.is_ascii();
- literal->length = literal->buffer.length();
- if (literal->is_ascii) {
- literal->ascii_string = literal->buffer.ascii_literal();
- } else {
- literal->utf16_string = literal->buffer.utf16_literal();
- }
- return true;
+ return CopyToLiteralBuffer(start, end, token, literal);
}
@@ -106,44 +112,56 @@
++start;
--end;
}
- if (!token.has_escapes) {
- // UTF-16 can also contain only one byte chars. Note that is_ascii here
- // means is_onebyte.
- literal->is_ascii = true;
- literal->buffer.Reset();
- for (const uint16_t* cursor = start; cursor != end; ++cursor) {
- if (*cursor >= unibrow::Latin1::kMaxChar) {
- literal->is_ascii = false;
- break;
- }
- literal->buffer.AddChar(*cursor);
- }
+ if (IsSubstringOfSource(token)) {
+ literal->is_ascii = false;
+ literal->is_in_buffer = false;
+ literal->offset = start - buffer_;
literal->length = end - start;
- if (literal->is_ascii) {
- literal->ascii_string = literal->buffer.ascii_literal();
- } else {
- literal->buffer.Reset();
- literal->utf16_string = Vector<const uint16_t>(start,
literal->length);
- }
+ literal->utf16_string = Vector<const uint16_t>(start, literal->length);
return true;
}
+ return CopyToLiteralBuffer(start, end, token, literal);
+}
+
+
+template<>
+bool ExperimentalScanner<int8_t>::FillLiteral(
+ const TokenDesc& token, LiteralDesc* literal) {
+ // FIXME: implement.
+ UNREACHABLE();
+ return false;
+}
+
+
+template<class Char>
+bool ExperimentalScanner<Char>::CopyToLiteralBuffer(const Char* start,
+ const Char* end,
+ const TokenDesc& token,
+ LiteralDesc* literal) {
literal->buffer.Reset();
- for (const uint16_t* cursor = start; cursor != end;) {
- if (*cursor != '\\') {
- literal->buffer.AddChar(*cursor++);
- } else if (token.token == Token::IDENTIFIER) {
- uc32 c;
- cursor = ScanIdentifierUnicodeEscape(cursor, end, &c);
- ASSERT(cursor != NULL);
- if (cursor == NULL) return false;
- literal->buffer.AddChar(c);
- } else {
- cursor = ScanEscape(cursor, end, &literal->buffer);
- ASSERT(cursor != NULL);
- if (cursor == NULL) return false;
+ if (token.has_escapes) {
+ for (const Char* cursor = start; cursor != end;) {
+ if (*cursor != '\\') {
+ literal->buffer.AddChar(*cursor++);
+ } else if (token.token == Token::IDENTIFIER) {
+ uc32 c;
+ cursor = ScanIdentifierUnicodeEscape(cursor, end, &c);
+ ASSERT(cursor != NULL);
+ if (cursor == NULL) return false;
+ literal->buffer.AddChar(c);
+ } else {
+ cursor = ScanEscape(cursor, end, &literal->buffer);
+ ASSERT(cursor != NULL);
+ if (cursor == NULL) return false;
+ }
+ }
+ } else {
+ for (const Char* cursor = start; cursor != end;) {
+ literal->buffer.AddChar(*cursor++);
}
}
literal->is_ascii = literal->buffer.is_ascii();
+ literal->is_in_buffer = true;
literal->length = literal->buffer.length();
if (literal->is_ascii) {
literal->ascii_string = literal->buffer.ascii_literal();
@@ -152,14 +170,80 @@
}
return true;
}
+
+
+template<class Char>
+Handle<String> ExperimentalScanner<Char>::InternalizeLiteral(
+ LiteralDesc* literal) {
+ Factory* factory = isolate_->factory();
+ if (literal->is_in_buffer) {
+ return literal->is_ascii
+ ? factory->InternalizeOneByteString(
+ Vector<const uint8_t>::cast(literal->ascii_string))
+ : factory->InternalizeTwoByteString(literal->utf16_string);
+ }
+ if (sizeof(Char) == 1) {
+ SubStringKey<uint8_t> key(
+ source_handle_, literal->offset, literal->length);
+ return factory->InternalizeStringWithKey(&key);
+ } else {
+ SubStringKey<uint16_t> key(
+ source_handle_, literal->offset, literal->length);
+ return factory->InternalizeStringWithKey(&key);
+ }
+}
+
template<>
-bool ExperimentalScanner<int8_t>::FillLiteral(
- const TokenDesc& token, LiteralDesc* literal) {
- // FIXME: implement.
- return false;
+Handle<String> ExperimentalScanner<uint8_t>::AllocateLiteral(
+ LiteralDesc* literal, PretenureFlag pretenured) {
+ Factory* factory = isolate_->factory();
+ if (literal->is_in_buffer) {
+ return literal->is_ascii
+ ? factory->NewStringFromAscii(literal->ascii_string, pretenured)
+ : factory->NewStringFromTwoByte(literal->utf16_string, pretenured);
+ }
+ int from = literal->offset;
+ int length = literal->length;
+ // Save the offset and the length before allocating the string as it may
+ // cause a GC, invalidate the literal, and move the source.
+ Handle<String> result = factory->NewRawOneByteString(length, pretenured);
+ uint8_t* chars = SeqOneByteString::cast(*result)->GetChars();
+ String::WriteToFlat(*source_handle_, chars, from, from + length);
+ return result;
}
+template<>
+Handle<String> ExperimentalScanner<uint16_t>::AllocateLiteral(
+ LiteralDesc* literal, PretenureFlag pretenured) {
+ Factory* factory = isolate_->factory();
+ if (literal->is_in_buffer) {
+ return literal->is_ascii
+ ? factory->NewStringFromAscii(literal->ascii_string, pretenured)
+ : factory->NewStringFromTwoByte(literal->utf16_string, pretenured);
+ }
+ // Save the offset and the length before allocating the string as it may
+ // cause a GC, invalidate the literal, and move the source.
+ int from = literal->offset;
+ int length = literal->length;
+ Handle<String> result = factory->NewRawTwoByteString(length, pretenured);
+ uint16_t* chars = SeqTwoByteString::cast(*result)->GetChars();
+ String::WriteToFlat(*source_handle_, chars, from, from + length);
+ return result;
}
+
+
+template<>
+Handle<String> ExperimentalScanner<int8_t>::AllocateLiteral(
+ LiteralDesc* literal, PretenureFlag pretenured) {
+ // FIXME: implement
+ UNREACHABLE();
+ return Handle<String>();
}
+
+template class ExperimentalScanner<uint8_t>;
+template class ExperimentalScanner<uint16_t>;
+template class ExperimentalScanner<int8_t>;
+
+} } // v8::internal
=======================================
--- /branches/experimental/parser/src/lexer/experimental-scanner.h Fri Jan
17 16:36:05 2014 UTC
+++ /branches/experimental/parser/src/lexer/experimental-scanner.h Mon Jan
20 09:25:23 2014 UTC
@@ -156,33 +156,40 @@
return has_line_terminator_before_next_ ||
has_multiline_comment_before_next_;
}
+
+ Handle<String> GetLiteralSymbol() {
+ EnsureCurrentLiteralIsValid();
+ return InternalizeLiteral(current_literal_);
+ }
+
+ Handle<String> GetLiteralString(PretenureFlag tenured) {
+ EnsureCurrentLiteralIsValid();
+ return AllocateLiteral(current_literal_, tenured);
+ }
+
+ Handle<String> GetNextLiteralString(PretenureFlag tenured) {
+ EnsureNextLiteralIsValid();
+ return AllocateLiteral(next_literal_, tenured);
+ }
Vector<const char> literal_ascii_string() {
- if (!current_literal_->Valid(current_.beg_pos)) {
- FillLiteral(current_, current_literal_);
- }
+ EnsureCurrentLiteralIsValid();
return current_literal_->ascii_string;
}
Vector<const uc16> literal_utf16_string() {
- if (!current_literal_->Valid(current_.beg_pos)) {
- FillLiteral(current_, current_literal_);
- }
+ EnsureCurrentLiteralIsValid();
return current_literal_->utf16_string;
}
int literal_length() {
- if (!current_literal_->Valid(current_.beg_pos)) {
- FillLiteral(current_, current_literal_);
- }
+ EnsureCurrentLiteralIsValid();
return current_literal_->length;
}
// This should be is_onebyte or is_latin1; it doesn't mean ASCII for
real.
bool is_literal_ascii() {
- if (!current_literal_->Valid(current_.beg_pos)) {
- FillLiteral(current_, current_literal_);
- }
+ EnsureCurrentLiteralIsValid();
return current_literal_->is_ascii;
}
@@ -198,30 +205,22 @@
}
Vector<const char> next_literal_ascii_string() {
- if (!next_literal_->Valid(next_.beg_pos)) {
- FillLiteral(next_, next_literal_);
- }
+ EnsureNextLiteralIsValid();
return next_literal_->ascii_string;
}
Vector<const uc16> next_literal_utf16_string() {
- if (!next_literal_->Valid(next_.beg_pos)) {
- FillLiteral(next_, next_literal_);
- }
+ EnsureNextLiteralIsValid();
return next_literal_->utf16_string;
}
int next_literal_length() {
- if (!next_literal_->Valid(next_.beg_pos)) {
- FillLiteral(next_, next_literal_);
- }
+ EnsureNextLiteralIsValid();
return next_literal_->length;
}
bool is_next_literal_ascii() {
- if (!next_literal_->Valid(next_.beg_pos)) {
- FillLiteral(next_, next_literal_);
- }
+ EnsureNextLiteralIsValid();
return next_literal_->is_ascii;
}
@@ -244,11 +243,14 @@
struct LiteralDesc {
int beg_pos;
bool is_ascii;
+ bool is_in_buffer;
+ int offset;
int length;
Vector<const char> ascii_string;
Vector<const uc16> utf16_string;
LiteralBuffer buffer;
- LiteralDesc() : beg_pos(-1), is_ascii(false), length(0) { }
+ LiteralDesc() : beg_pos(-1), is_ascii(false), is_in_buffer(false),
+ offset(0), length(0) { }
bool Valid(int pos) { return beg_pos == pos; }
};
@@ -256,9 +258,25 @@
virtual bool FillLiteral(const TokenDesc& token, LiteralDesc* literal) =
0;
void ResetLiterals() {
- current_literal_->beg_pos = -1;
- next_literal_->beg_pos = -1;
+ if (!current_literal_->is_in_buffer) current_literal_->beg_pos = -1;
+ if (!next_literal_->is_in_buffer) next_literal_->beg_pos = -1;
+ }
+
+ void EnsureCurrentLiteralIsValid() {
+ if (!current_literal_->Valid(current_.beg_pos)) {
+ FillLiteral(current_, current_literal_);
+ }
+ }
+
+ void EnsureNextLiteralIsValid() {
+ if (!next_literal_->Valid(next_.beg_pos)) {
+ FillLiteral(next_, next_literal_);
+ }
}
+
+ virtual Handle<String> InternalizeLiteral(LiteralDesc* literal) = 0;
+ virtual Handle<String> AllocateLiteral(LiteralDesc* literal,
+ PretenureFlag tenured) = 0;
Isolate* isolate_;
UnicodeCache* unicode_cache_;
@@ -340,6 +358,10 @@
const Char* GetNewBufferBasedOnHandle() const;
virtual bool FillLiteral(const TokenDesc& token, LiteralDesc* literal);
+ virtual Handle<String> InternalizeLiteral(LiteralDesc* literal);
+ virtual Handle<String> AllocateLiteral(LiteralDesc* literal,
+ PretenureFlag tenured);
+
private:
bool ValidIdentifierPart() {
@@ -366,6 +388,15 @@
const Char* end,
LiteralBuffer* literal);
+ // Returns true if the literal of the token can be represented as a
+ // substring of the source.
+ bool IsSubstringOfSource(const TokenDesc& token);
+
+ bool CopyToLiteralBuffer(const Char* start,
+ const Char* end,
+ const TokenDesc& token,
+ LiteralDesc* literal);
+
Handle<String> source_handle_;
const Char* buffer_;
const Char* buffer_end_;
=======================================
--- /branches/experimental/parser/src/objects-inl.h Fri Jan 17 11:13:31
2014 UTC
+++ /branches/experimental/parser/src/objects-inl.h Mon Jan 20 09:25:23
2014 UTC
@@ -499,38 +499,34 @@
};
-class SubStringOneByteStringKey : public HashTableKey {
+template<class Char>
+class SubStringKey : public HashTableKey {
public:
- explicit SubStringOneByteStringKey(Handle<SeqOneByteString> string,
- int from,
- int length)
+ SubStringKey(Handle<String> string, int from, int length)
: string_(string), from_(from), length_(length) { }
virtual uint32_t Hash() {
ASSERT(length_ >= 0);
ASSERT(from_ + length_ <= string_->length());
- uint8_t* chars = string_->GetChars() + from_;
+ const Char* chars = GetChars() + from_;
hash_field_ = StringHasher::HashSequentialString(
chars, length_, string_->GetHeap()->HashSeed());
uint32_t result = hash_field_ >> String::kHashShift;
ASSERT(result != 0); // Ensure that the hash value of 0 is never
computed.
return result;
}
-
virtual uint32_t HashForObject(Object* other) {
return String::cast(other)->Hash();
}
- virtual bool IsMatch(Object* string) {
- Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
- return String::cast(string)->IsOneByteEqualTo(chars);
- }
-
+ virtual bool IsMatch(Object* string);
virtual MaybeObject* AsObject(Heap* heap);
private:
- Handle<SeqOneByteString> string_;
+ const Char* GetChars();
+
+ Handle<String> string_;
int from_;
int length_;
uint32_t hash_field_;
=======================================
--- /branches/experimental/parser/src/objects.cc Fri Jan 17 11:13:31 2014
UTC
+++ /branches/experimental/parser/src/objects.cc Mon Jan 20 09:25:23 2014
UTC
@@ -14006,17 +14006,61 @@
}
-MaybeObject* SubStringOneByteStringKey::AsObject(Heap* heap) {
+MaybeObject* TwoByteStringKey::AsObject(Heap* heap) {
if (hash_field_ == 0) Hash();
- Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
+ return heap->AllocateTwoByteInternalizedString(string_, hash_field_);
+}
+
+
+template<>
+const uint8_t* SubStringKey<uint8_t>::GetChars() {
+ return string_->IsSeqOneByteString()
+ ? SeqOneByteString::cast(*string_)->GetChars()
+ : ExternalAsciiString::cast(*string_)->GetChars();
+}
+
+
+template<>
+const uint16_t* SubStringKey<uint16_t>::GetChars() {
+ return string_->IsSeqTwoByteString()
+ ? SeqTwoByteString::cast(*string_)->GetChars()
+ : ExternalTwoByteString::cast(*string_)->GetChars();
+}
+
+
+template<>
+MaybeObject* SubStringKey<uint8_t>::AsObject(Heap* heap) {
+ if (hash_field_ == 0) Hash();
+ Vector<const uint8_t> chars(GetChars() + from_, length_);
return heap->AllocateOneByteInternalizedString(chars, hash_field_);
}
-MaybeObject* TwoByteStringKey::AsObject(Heap* heap) {
+template<>
+MaybeObject* SubStringKey<uint16_t>::AsObject(
+ Heap* heap) {
if (hash_field_ == 0) Hash();
- return heap->AllocateTwoByteInternalizedString(string_, hash_field_);
+ Vector<const uint16_t> chars(GetChars() + from_, length_);
+ return heap->AllocateTwoByteInternalizedString(chars, hash_field_);
}
+
+
+template<>
+bool SubStringKey<uint8_t>::IsMatch(Object* string) {
+ Vector<const uint8_t> chars(GetChars() + from_, length_);
+ return String::cast(string)->IsOneByteEqualTo(chars);
+}
+
+
+template<>
+bool SubStringKey<uint16_t>::IsMatch(Object* string) {
+ Vector<const uint16_t> chars(GetChars() + from_, length_);
+ return String::cast(string)->IsTwoByteEqualTo(chars);
+}
+
+
+template class SubStringKey<uint8_t>;
+template class SubStringKey<uint16_t>;
// InternalizedStringKey carries a string/internalized-string object as
key.
=======================================
--- /branches/experimental/parser/src/parser.cc Wed Dec 11 14:40:08 2013 UTC
+++ /branches/experimental/parser/src/parser.cc Mon Jan 20 09:25:23 2014 UTC
@@ -256,13 +256,7 @@
// if there is some preparser data.
if (static_cast<unsigned>(symbol_id)
>= static_cast<unsigned>(symbol_cache_.length())) {
- if (scanner().is_literal_ascii()) {
- return isolate()->factory()->InternalizeOneByteString(
- Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
- } else {
- return isolate()->factory()->InternalizeTwoByteString(
- scanner().literal_utf16_string());
- }
+ return scanner().GetLiteralSymbol();
}
return LookupCachedSymbol(symbol_id);
}
@@ -277,13 +271,7 @@
}
Handle<String> result = symbol_cache_.at(symbol_id);
if (result.is_null()) {
- if (scanner().is_literal_ascii()) {
- result = isolate()->factory()->InternalizeOneByteString(
- Vector<const uint8_t>::cast(scanner().literal_ascii_string()));
- } else {
- result = isolate()->factory()->InternalizeTwoByteString(
- scanner().literal_utf16_string());
- }
+ result = scanner().GetLiteralSymbol();
symbol_cache_.at(symbol_id) = result;
return result;
}
@@ -576,7 +564,7 @@
fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
// Initialize parser state.
- FlattenString(source);
+ source = FlattenGetString(source);
FunctionLiteral* result;
if (source->IsTwoByteRepresentation()) {
delete reusable_preparser_;
@@ -707,7 +695,6 @@
timer.Start();
}
// Initialize parser state.
- FlattenString(source);
Handle<SharedFunctionInfo> shared_info = info()->shared_info();
FunctionLiteral* result = ParseLazy(
source, shared_info->start_position(), shared_info->end_position());
@@ -721,6 +708,7 @@
FunctionLiteral* Parser::ParseLazy(Handle<String> source, int start, int
end) {
+ source = FlattenGetString(source);
delete reusable_preparser_;
delete scanner_;
if (source->IsTwoByteRepresentation()) {
@@ -5614,6 +5602,7 @@
Handle<String> source) {
CompleteParserRecorder recorder;
HistogramTimerScope timer(isolate->counters()->pre_parse());
+ source = FlattenGetString(source);
ScannerBase* scanner = NULL;
if (source->IsTwoByteRepresentation()) {
scanner = new ExperimentalScanner<uint16_t>(source, isolate);
=======================================
--- /branches/experimental/parser/src/parser.h Thu Jan 9 09:32:53 2014 UTC
+++ /branches/experimental/parser/src/parser.h Mon Jan 20 09:25:23 2014 UTC
@@ -666,23 +666,11 @@
bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode*
visit_mode);
Handle<String> LiteralString(PretenureFlag tenured) {
- if (scanner().is_literal_ascii()) {
- return isolate_->factory()->NewStringFromAscii(
- scanner().literal_ascii_string(), tenured);
- } else {
- return isolate_->factory()->NewStringFromTwoByte(
- scanner().literal_utf16_string(), tenured);
- }
+ return scanner().GetLiteralString(tenured);
}
Handle<String> NextLiteralString(PretenureFlag tenured) {
- if (scanner().is_next_literal_ascii()) {
- return isolate_->factory()->NewStringFromAscii(
- scanner().next_literal_ascii_string(), tenured);
- } else {
- return isolate_->factory()->NewStringFromTwoByte(
- scanner().next_literal_utf16_string(), tenured);
- }
+ return scanner().GetNextLiteralString(tenured);
}
Handle<String> GetSymbol();
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.