Revision: 21468
Author: [email protected]
Date: Fri May 23 14:06:42 2014 UTC
Log: Allow HPushArgument to handle more than one argument.
[email protected]
Review URL: https://codereview.chromium.org/296113008
http://code.google.com/p/v8/source/detail?r=21468
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm64/lithium-arm64.cc
/branches/bleeding_edge/src/arm64/lithium-arm64.h
/branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc
/branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc
/branches/bleeding_edge/src/arm64/macro-assembler-arm64.h
/branches/bleeding_edge/src/code-stubs-hydrogen.cc
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/lithium.cc
/branches/bleeding_edge/src/mips/lithium-mips.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Fri May 23 13:15:07 2014
UTC
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Fri May 23 14:06:42 2014
UTC
@@ -1005,9 +1005,13 @@
}
-LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
- LOperand* argument = Use(instr->argument());
- return new(zone()) LPushArgument(argument);
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+ int argc = instr->OperandCount();
+ for (int i = 0; i < argc; ++i) {
+ LOperand* argument = Use(instr->argument(i));
+ AddInstruction(new(zone()) LPushArgument(argument), instr);
+ }
+ return NULL;
}
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-arm64.cc Fri May 23 13:15:07
2014 UTC
+++ /branches/bleeding_edge/src/arm64/lithium-arm64.cc Fri May 23 14:06:42
2014 UTC
@@ -1995,9 +1995,21 @@
}
-LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
- LOperand* argument = UseRegister(instr->argument());
- return new(zone()) LPushArgument(argument);
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+ int argc = instr->OperandCount();
+ AddInstruction(new(zone()) LPreparePushArguments(argc), instr);
+
+ LPushArguments* push_args = new(zone()) LPushArguments(zone());
+
+ for (int i = 0; i < argc; ++i) {
+ if (push_args->ShouldSplitPush()) {
+ AddInstruction(push_args, instr);
+ push_args = new(zone()) LPushArguments(zone());
+ }
+ push_args->AddArgument(UseRegister(instr->argument(i)));
+ }
+
+ return push_args;
}
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-arm64.h Fri May 23 13:15:07
2014 UTC
+++ /branches/bleeding_edge/src/arm64/lithium-arm64.h Fri May 23 14:06:42
2014 UTC
@@ -136,7 +136,8 @@
V(OsrEntry) \
V(Parameter) \
V(Power) \
- V(PushArgument) \
+ V(PreparePushArguments) \
+ V(PushArguments) \
V(RegExpLiteral) \
V(Return) \
V(SeqStringGetChar) \
@@ -2249,15 +2250,50 @@
};
-class LPushArgument V8_FINAL : public LTemplateInstruction<0, 1, 0> {
+class LPreparePushArguments V8_FINAL : public LTemplateInstruction<0, 0,
0> {
public:
- explicit LPushArgument(LOperand* value) {
- inputs_[0] = value;
+ explicit LPreparePushArguments(int argc) : argc_(argc) {}
+
+ inline int argc() const { return argc_; }
+
+
DECLARE_CONCRETE_INSTRUCTION(PreparePushArguments, "prepare-push-arguments")
+
+ protected:
+ int argc_;
+};
+
+
+class LPushArguments V8_FINAL : public LTemplateResultInstruction<0> {
+ public:
+ explicit LPushArguments(Zone* zone,
+ int capacity = kRecommendedMaxPushedArgs)
+ : zone_(zone), inputs_(capacity, zone) {}
+
+ LOperand* argument(int i) { return inputs_[i]; }
+ int ArgumentCount() const { return inputs_.length(); }
+
+ void AddArgument(LOperand* arg) { inputs_.Add(arg, zone_); }
+
+ DECLARE_CONCRETE_INSTRUCTION(PushArguments, "push-arguments")
+
+ // It is better to limit the number of arguments pushed simultaneously to
+ // avoid pressure on the register allocator.
+ static const int kRecommendedMaxPushedArgs = 4;
+ bool ShouldSplitPush() const {
+ return inputs_.length() >= kRecommendedMaxPushedArgs;
}
- LOperand* value() { return inputs_[0]; }
+ protected:
+ Zone* zone_;
+ ZoneList<LOperand*> inputs_;
- DECLARE_CONCRETE_INSTRUCTION(PushArgument, "push-argument")
+ private:
+ // Iterator support.
+ virtual int InputCount() V8_FINAL V8_OVERRIDE { return inputs_.length();
}
+ virtual LOperand* InputAt(int i) V8_FINAL V8_OVERRIDE { return
inputs_[i]; }
+
+ virtual int TempCount() V8_FINAL V8_OVERRIDE { return 0; }
+ virtual LOperand* TempAt(int i) V8_FINAL V8_OVERRIDE { return NULL; }
};
=======================================
--- /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Thu May 22
08:37:50 2014 UTC
+++ /branches/bleeding_edge/src/arm64/lithium-codegen-arm64.cc Fri May 23
14:06:42 2014 UTC
@@ -4677,14 +4677,27 @@
}
-void LCodeGen::DoPushArgument(LPushArgument* instr) {
- LOperand* argument = instr->value();
- if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
- Abort(kDoPushArgumentNotImplementedForDoubleType);
- } else {
- __ Push(ToRegister(argument));
- after_push_argument_ = true;
+void LCodeGen::DoPreparePushArguments(LPreparePushArguments* instr) {
+ __ PushPreamble(instr->argc(), kPointerSize);
+}
+
+
+void LCodeGen::DoPushArguments(LPushArguments* instr) {
+ MacroAssembler::PushPopQueue args(masm());
+
+ for (int i = 0; i < instr->ArgumentCount(); ++i) {
+ LOperand* arg = instr->argument(i);
+ if (arg->IsDoubleRegister() || arg->IsDoubleStackSlot()) {
+ Abort(kDoPushArgumentNotImplementedForDoubleType);
+ return;
+ }
+ args.Queue(ToRegister(arg));
}
+
+ // The preamble was done by LPreparePushArguments.
+ args.PushQueued(MacroAssembler::PushPopQueue::SKIP_PREAMBLE);
+
+ after_push_argument_ = true;
}
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc Fri May 16
15:18:24 2014 UTC
+++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc Fri May 23
14:06:42 2014 UTC
@@ -805,10 +805,13 @@
}
-void MacroAssembler::PushPopQueue::PushQueued() {
+void MacroAssembler::PushPopQueue::PushQueued(
+ PreambleDirective preamble_directive) {
if (queued_.empty()) return;
- masm_->PushPreamble(size_);
+ if (preamble_directive == WITH_PREAMBLE) {
+ masm_->PushPreamble(size_);
+ }
int count = queued_.size();
int index = 0;
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h Fri May 23
08:52:05 2014 UTC
+++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h Fri May 23
14:06:42 2014 UTC
@@ -614,7 +614,11 @@
queued_.push_back(rt);
}
- void PushQueued();
+ enum PreambleDirective {
+ WITH_PREAMBLE,
+ SKIP_PREAMBLE
+ };
+ void PushQueued(PreambleDirective preamble_directive = WITH_PREAMBLE);
void PopQueued();
private:
@@ -2012,6 +2016,15 @@
void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
Register scratch1, Label* found);
+ // Perform necessary maintenance operations before a push or after a pop.
+ //
+ // Note that size is specified in bytes.
+ void PushPreamble(Operand total_size);
+ void PopPostamble(Operand total_size);
+
+ void PushPreamble(int count, int size) { PushPreamble(count * size); }
+ void PopPostamble(int count, int size) { PopPostamble(count * size); }
+
private:
// Helpers for CopyFields.
// These each implement CopyFields in a different way.
@@ -2038,15 +2051,6 @@
void PopHelper(int count, int size,
const CPURegister& dst0, const CPURegister& dst1,
const CPURegister& dst2, const CPURegister& dst3);
-
- // Perform necessary maintenance operations before a push or after a pop.
- //
- // Note that size is specified in bytes.
- void PushPreamble(Operand total_size);
- void PopPostamble(Operand total_size);
-
- void PushPreamble(int count, int size) { PushPreamble(count * size); }
- void PopPostamble(int count, int size) { PopPostamble(count * size); }
// Call Printf. On a native build, a simple call will be generated, but
if the
// simulator is being used then a suitable pseudo-instruction is used.
The
=======================================
--- /branches/bleeding_edge/src/code-stubs-hydrogen.cc Tue May 20 11:25:47
2014 UTC
+++ /branches/bleeding_edge/src/code-stubs-hydrogen.cc Fri May 23 14:06:42
2014 UTC
@@ -298,7 +298,7 @@
// Convert the parameter to number using the builtin.
HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER);
- Add<HPushArgument>(value);
+ Add<HPushArguments>(zone(), value);
Push(Add<HInvokeFunction>(function, 1));
if_number.End();
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Thu May 22
08:37:50 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Fri May 23
14:06:42 2014 UTC
@@ -868,7 +868,7 @@
case HValue::kMathMinMax:
case HValue::kParameter:
case HValue::kPhi:
- case HValue::kPushArgument:
+ case HValue::kPushArguments:
case HValue::kRegExpLiteral:
case HValue::kReturn:
case HValue::kRor:
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri May 23 14:02:08
2014 UTC
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Fri May 23 14:06:42
2014 UTC
@@ -127,7 +127,7 @@
V(OsrEntry) \
V(Parameter) \
V(Power) \
- V(PushArgument) \
+ V(PushArguments) \
V(RegExpLiteral) \
V(Return) \
V(Ror) \
@@ -2176,23 +2176,66 @@
};
-class HPushArgument V8_FINAL : public HUnaryOperation {
+class HPushArguments V8_FINAL : public HInstruction {
public:
- DECLARE_INSTRUCTION_FACTORY_P1(HPushArgument, HValue*);
+ DECLARE_INSTRUCTION_FACTORY_P1(HPushArguments, Zone*);
+ DECLARE_INSTRUCTION_FACTORY_P2(HPushArguments, Zone*, HValue*);
+ DECLARE_INSTRUCTION_FACTORY_P3(HPushArguments, Zone*, HValue*, HValue*);
+ DECLARE_INSTRUCTION_FACTORY_P4(HPushArguments, Zone*,
+ HValue*, HValue*, HValue*);
+ DECLARE_INSTRUCTION_FACTORY_P5(HPushArguments, Zone*,
+ HValue*, HValue*, HValue*, HValue*);
virtual Representation RequiredInputRepresentation(int index)
V8_OVERRIDE {
return Representation::Tagged();
}
- virtual int argument_delta() const V8_OVERRIDE { return 1; }
- HValue* argument() { return OperandAt(0); }
+ virtual int argument_delta() const V8_OVERRIDE { return
inputs_.length(); }
+ HValue* argument(int i) { return OperandAt(i); }
+
+ virtual int OperandCount() V8_FINAL V8_OVERRIDE { return
inputs_.length(); }
+ virtual HValue* OperandAt(int i) const V8_FINAL V8_OVERRIDE {
+ return inputs_[i];
+ }
- DECLARE_CONCRETE_INSTRUCTION(PushArgument)
+ void AddArgument(HValue* arg) {
+ inputs_.Add(NULL, zone_);
+ SetOperandAt(inputs_.length() - 1, arg);
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(PushArguments)
+
+ protected:
+ virtual void InternalSetOperandAt(int i, HValue* value) V8_FINAL
V8_OVERRIDE {
+ inputs_[i] = value;
+ }
private:
- explicit HPushArgument(HValue* value) : HUnaryOperation(value) {
+ HPushArguments(Zone* zone,
+ HValue* arg1 = NULL, HValue* arg2 = NULL,
+ HValue* arg3 = NULL, HValue* arg4 = NULL)
+ : HInstruction(HType::Tagged()), zone_(zone), inputs_(4, zone) {
set_representation(Representation::Tagged());
+ if (arg1) {
+ inputs_.Add(NULL, zone);
+ SetOperandAt(0, arg1);
+ }
+ if (arg2) {
+ inputs_.Add(NULL, zone);
+ SetOperandAt(1, arg2);
+ }
+ if (arg3) {
+ inputs_.Add(NULL, zone);
+ SetOperandAt(2, arg3);
+ }
+ if (arg4) {
+ inputs_.Add(NULL, zone);
+ SetOperandAt(3, arg4);
+ }
}
+
+ Zone* zone_;
+ ZoneList<HValue*> inputs_;
};
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri May 23 09:30:47 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc Fri May 23 14:06:42 2014 UTC
@@ -1726,7 +1726,7 @@
if_found.Else();
{
// Cache miss, fallback to runtime.
- Add<HPushArgument>(object);
+ Add<HPushArguments>(zone(), object);
Push(Add<HCallRuntime>(
isolate()->factory()->empty_string(),
Runtime::FunctionForId(Runtime::kHiddenNumberToStringSkipCache),
@@ -2050,8 +2050,7 @@
if_sameencodingandsequential.Else();
{
// Fallback to the runtime to add the two strings.
- Add<HPushArgument>(left);
- Add<HPushArgument>(right);
+ Add<HPushArguments>(zone(), left, right);
Push(Add<HCallRuntime>(
isolate()->factory()->empty_string(),
Runtime::FunctionForId(Runtime::kHiddenStringAdd),
@@ -4188,9 +4187,11 @@
arguments.Add(Pop(), zone());
}
+ HPushArguments* push_args = New<HPushArguments>(zone());
while (!arguments.is_empty()) {
- Add<HPushArgument>(arguments.RemoveLast());
+ push_args->AddArgument(arguments.RemoveLast());
}
+ AddInstruction(push_args);
}
@@ -5184,10 +5185,11 @@
flags |= expr->has_function()
? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags;
- Add<HPushArgument>(Add<HConstant>(closure_literals));
- Add<HPushArgument>(Add<HConstant>(literal_index));
- Add<HPushArgument>(Add<HConstant>(constant_properties));
- Add<HPushArgument>(Add<HConstant>(flags));
+ Add<HPushArguments>(zone(),
+ Add<HConstant>(closure_literals),
+ Add<HConstant>(literal_index),
+ Add<HConstant>(constant_properties),
+ Add<HConstant>(flags));
// TODO(mvstanton): Add a flag to turn off creation of any
// AllocationMementos for this call: we are in crankshaft and should
have
@@ -5342,10 +5344,11 @@
: ArrayLiteral::kNoFlags;
flags |= ArrayLiteral::kDisableMementos;
- Add<HPushArgument>(Add<HConstant>(literals));
- Add<HPushArgument>(Add<HConstant>(literal_index));
- Add<HPushArgument>(Add<HConstant>(constants));
- Add<HPushArgument>(Add<HConstant>(flags));
+ Add<HPushArguments>(zone(),
+ Add<HConstant>(literals),
+ Add<HConstant>(literal_index),
+ Add<HConstant>(constants),
+ Add<HConstant>(flags));
// TODO(mvstanton): Consider a flag to turn off creation of any
// AllocationMementos for this call: we are in crankshaft and should
have
@@ -6379,7 +6382,7 @@
HValue* value = environment()->Pop();
if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
- Add<HPushArgument>(value);
+ Add<HPushArguments>(zone(), value);
Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(Runtime::kHiddenThrow), 1);
Add<HSimulate>(expr->id());
@@ -6781,7 +6784,7 @@
HInstruction* insert_after = entry;
for (int i = 0; i < arguments_values->length(); i++) {
HValue* argument = arguments_values->at(i);
- HInstruction* push_argument = New<HPushArgument>(argument);
+ HInstruction* push_argument = New<HPushArguments>(zone(), argument);
push_argument->InsertAfter(insert_after);
insert_after = push_argument;
}
@@ -8076,7 +8079,7 @@
ASSERT_EQ(NULL, receiver);
// Receiver is on expression stack.
receiver = Pop();
- Add<HPushArgument>(receiver);
+ Add<HPushArguments>(zone(), receiver);
break;
case kCallApiSetter:
{
@@ -8087,8 +8090,7 @@
// Receiver and value are on expression stack.
HValue* value = Pop();
receiver = Pop();
- Add<HPushArgument>(receiver);
- Add<HPushArgument>(value);
+ Add<HPushArguments>(zone(), receiver, value);
break;
}
}
@@ -8656,7 +8658,7 @@
}
// TODO(mstarzinger): For now we remove the previous HAllocate and all
- // corresponding instructions and instead add HPushArgument for the
+ // corresponding instructions and instead add HPushArguments for the
// arguments in case inlining failed. What we actually should do is
for
// inlining to try to build a subgraph without mutating the parent
graph.
HInstruction* instr = current_block()->last();
@@ -9135,9 +9137,8 @@
HValue* key = Pop();
HValue* obj = Pop();
HValue* function = AddLoadJSBuiltin(Builtins::DELETE);
- Add<HPushArgument>(obj);
- Add<HPushArgument>(key);
- Add<HPushArgument>(Add<HConstant>(function_strict_mode()));
+ Add<HPushArguments>(zone(),
+ obj, key, Add<HConstant>(function_strict_mode()));
// TODO(olivf) InvokeFunction produces a check for the parameter count,
// even though we are certain to pass the correct number of arguments
here.
HInstruction* instr = New<HInvokeFunction>(function, 3);
@@ -9622,8 +9623,7 @@
} else if (!left_type->Is(Type::String())) {
ASSERT(right_type->Is(Type::String()));
HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
- Add<HPushArgument>(left);
- Add<HPushArgument>(right);
+ Add<HPushArguments>(zone(), left, right);
return AddUncasted<HInvokeFunction>(function, 2);
}
@@ -9634,8 +9634,7 @@
} else if (!right_type->Is(Type::String())) {
ASSERT(left_type->Is(Type::String()));
HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
- Add<HPushArgument>(left);
- Add<HPushArgument>(right);
+ Add<HPushArguments>(zone(), left, right);
return AddUncasted<HInvokeFunction>(function, 2);
}
@@ -9697,8 +9696,7 @@
// operation in optimized code, which is more expensive, than a stub
call.
if (graph()->info()->IsStub() && is_non_primitive) {
HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
- Add<HPushArgument>(left);
- Add<HPushArgument>(right);
+ Add<HPushArguments>(zone(), left, right);
instr = AddUncasted<HInvokeFunction>(function, 2);
} else {
switch (op) {
@@ -10062,8 +10060,7 @@
UNREACHABLE();
} else if (op == Token::IN) {
HValue* function = AddLoadJSBuiltin(Builtins::IN);
- Add<HPushArgument>(left);
- Add<HPushArgument>(right);
+ Add<HPushArguments>(zone(), left, right);
// TODO(olivf) InvokeFunction produces a check for the parameter count,
// even though we are certain to pass the correct number of arguments
here.
HInstruction* result = New<HInvokeFunction>(function, 2);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri May 23 13:15:07
2014 UTC
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri May 23 14:06:42
2014 UTC
@@ -1060,9 +1060,13 @@
}
-LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
- LOperand* argument = UseAny(instr->argument());
- return new(zone()) LPushArgument(argument);
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+ int argc = instr->OperandCount();
+ for (int i = 0; i < argc; ++i) {
+ LOperand* argument = UseAny(instr->argument(i));
+ AddInstruction(new(zone()) LPushArgument(argument), instr);
+ }
+ return NULL;
}
=======================================
--- /branches/bleeding_edge/src/lithium.cc Thu May 22 09:36:20 2014 UTC
+++ /branches/bleeding_edge/src/lithium.cc Fri May 23 14:06:42 2014 UTC
@@ -509,7 +509,7 @@
LOperand* op;
HValue* value = hydrogen_env->values()->at(i);
- CHECK(!value->IsPushArgument()); // Do not deopt outgoing arguments
+ CHECK(!value->IsPushArguments()); // Do not deopt outgoing arguments
if (value->IsArgumentsObject() || value->IsCapturedObject()) {
op = LEnvironment::materialization_marker();
} else {
@@ -590,7 +590,7 @@
// Insert a hole for nested objects
op = LEnvironment::materialization_marker();
} else {
- ASSERT(!arg_value->IsPushArgument());
+ ASSERT(!arg_value->IsPushArguments());
// For ordinary values, tell the register allocator we need the value
// to be alive here
op = UseAny(arg_value);
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.cc Fri May 23 13:15:07
2014 UTC
+++ /branches/bleeding_edge/src/mips/lithium-mips.cc Fri May 23 14:06:42
2014 UTC
@@ -1008,9 +1008,13 @@
}
-LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
- LOperand* argument = Use(instr->argument());
- return new(zone()) LPushArgument(argument);
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+ int argc = instr->OperandCount();
+ for (int i = 0; i < argc; ++i) {
+ LOperand* argument = Use(instr->argument(i));
+ AddInstruction(new(zone()) LPushArgument(argument), instr);
+ }
+ return NULL;
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Fri May 23 13:15:07 2014
UTC
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Fri May 23 14:06:42 2014
UTC
@@ -1023,9 +1023,13 @@
}
-LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
- LOperand* argument = UseOrConstant(instr->argument());
- return new(zone()) LPushArgument(argument);
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+ int argc = instr->OperandCount();
+ for (int i = 0; i < argc; ++i) {
+ LOperand* argument = UseOrConstant(instr->argument(i));
+ AddInstruction(new(zone()) LPushArgument(argument), instr);
+ }
+ return NULL;
}
--
--
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/d/optout.