Revision: 24458
Author: [email protected]
Date: Wed Oct 8 09:15:09 2014 UTC
Log: Updates to maintain flag --vector-ics
Experimental feature vector-ics needs some maintenance.
[email protected]
Review URL: https://codereview.chromium.org/638523003
https://code.google.com/p/v8/source/detail?r=24458
Modified:
/branches/bleeding_edge/src/arm/debug-arm.cc
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/arm64/debug-arm64.cc
/branches/bleeding_edge/src/arm64/full-codegen-arm64.cc
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/code-stubs.cc
/branches/bleeding_edge/src/code-stubs.h
/branches/bleeding_edge/src/ia32/builtins-ia32.cc
/branches/bleeding_edge/src/ia32/debug-ia32.cc
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/ic/ic.cc
/branches/bleeding_edge/src/ic/ic.h
/branches/bleeding_edge/src/mips/debug-mips.cc
/branches/bleeding_edge/src/mips/full-codegen-mips.cc
/branches/bleeding_edge/src/x64/builtins-x64.cc
/branches/bleeding_edge/src/x64/debug-x64.cc
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/debug-arm.cc Wed Sep 3 10:51:51 2014
UTC
+++ /branches/bleeding_edge/src/arm/debug-arm.cc Wed Oct 8 09:15:09 2014
UTC
@@ -178,7 +178,11 @@
// Calling convention for IC load (from ic-arm.cc).
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0);
+ RegList regs = receiver.bit() | name.bit();
+ if (FLAG_vector_ics) {
+ regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+ }
+ Generate_DebugBreakCallHelper(masm, regs, 0);
}
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Oct 6 08:25:27
2014 UTC
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Oct 8 09:15:09
2014 UTC
@@ -1364,7 +1364,13 @@
Handle<Symbol>
home_object_symbol(isolate()->heap()->home_object_symbol());
__ Move(LoadDescriptor::NameRegister(), home_object_symbol);
- CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ if (FLAG_vector_ics) {
+ __ mov(VectorLoadICDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(expr->HomeObjectFeedbackSlot())));
+ CallLoadIC(NOT_CONTEXTUAL);
+ } else {
+ CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ }
__ cmp(r0, Operand(isolate()->factory()->undefined_value()));
Label done;
=======================================
--- /branches/bleeding_edge/src/arm64/debug-arm64.cc Wed Sep 3 10:51:51
2014 UTC
+++ /branches/bleeding_edge/src/arm64/debug-arm64.cc Wed Oct 8 09:15:09
2014 UTC
@@ -238,7 +238,11 @@
// Calling convention for IC load (from ic-arm.cc).
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- Generate_DebugBreakCallHelper(masm, receiver.Bit() | name.Bit(), 0, x10);
+ RegList regs = receiver.Bit() | name.Bit();
+ if (FLAG_vector_ics) {
+ regs |= VectorLoadICTrampolineDescriptor::SlotRegister().Bit();
+ }
+ Generate_DebugBreakCallHelper(masm, regs, 0, x10);
}
=======================================
--- /branches/bleeding_edge/src/arm64/full-codegen-arm64.cc Mon Oct 6
08:25:27 2014 UTC
+++ /branches/bleeding_edge/src/arm64/full-codegen-arm64.cc Wed Oct 8
09:15:09 2014 UTC
@@ -1350,7 +1350,13 @@
Handle<Symbol>
home_object_symbol(isolate()->heap()->home_object_symbol());
__ Mov(LoadDescriptor::NameRegister(), Operand(home_object_symbol));
- CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ if (FLAG_vector_ics) {
+ __ Mov(VectorLoadICDescriptor::SlotRegister(),
+ Smi::FromInt(expr->HomeObjectFeedbackSlot()));
+ CallLoadIC(NOT_CONTEXTUAL);
+ } else {
+ CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ }
__ Mov(x10, Operand(isolate()->factory()->undefined_value()));
__ cmp(x0, x10);
=======================================
--- /branches/bleeding_edge/src/ast.cc Tue Oct 7 12:35:06 2014 UTC
+++ /branches/bleeding_edge/src/ast.cc Wed Oct 8 09:15:09 2014 UTC
@@ -1026,6 +1026,14 @@
set_dont_turbofan_reason(k##NodeType); \
add_flag(kDontSelfOptimize); \
}
+#define DONT_TURBOFAN_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
+ void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
+ increase_node_count(); \
+ add_slot_node(node); \
+ set_dont_crankshaft_reason(k##NodeType); \
+ set_dont_turbofan_reason(k##NodeType); \
+ add_flag(kDontSelfOptimize); \
+ }
#define DONT_SELFOPTIMIZE_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
increase_node_count(); \
@@ -1100,7 +1108,8 @@
DONT_TURBOFAN_NODE(TryCatchStatement)
DONT_TURBOFAN_NODE(TryFinallyStatement)
DONT_TURBOFAN_NODE(ClassLiteral)
-DONT_TURBOFAN_NODE(SuperReference)
+
+DONT_TURBOFAN_NODE_WITH_FEEDBACK_SLOTS(SuperReference)
DONT_SELFOPTIMIZE_NODE(DoWhileStatement)
DONT_SELFOPTIMIZE_NODE(WhileStatement)
=======================================
--- /branches/bleeding_edge/src/ast.h Mon Oct 6 12:56:11 2014 UTC
+++ /branches/bleeding_edge/src/ast.h Wed Oct 8 09:15:09 2014 UTC
@@ -2590,14 +2590,29 @@
VariableProxy* this_var() const { return this_var_; }
TypeFeedbackId HomeObjectFeedbackId() { return reuse(id()); }
+
+ // Type feedback information.
+ virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0;
}
+ virtual void SetFirstFeedbackSlot(int slot) {
+ homeobject_feedback_slot_ = slot;
+ }
+
+ int HomeObjectFeedbackSlot() {
+ DCHECK(!FLAG_vector_ics ||
+ homeobject_feedback_slot_ != kInvalidFeedbackSlot);
+ return homeobject_feedback_slot_;
+ }
protected:
SuperReference(Zone* zone, VariableProxy* this_var, int pos, IdGen*
id_gen)
- : Expression(zone, pos, id_gen), this_var_(this_var) {
+ : Expression(zone, pos, id_gen),
+ this_var_(this_var),
+ homeobject_feedback_slot_(kInvalidFeedbackSlot) {
DCHECK(this_var->is_this());
}
VariableProxy* this_var_;
+ int homeobject_feedback_slot_;
};
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc Thu Oct 2 07:04:28 2014 UTC
+++ /branches/bleeding_edge/src/code-stubs.cc Wed Oct 8 09:15:09 2014 UTC
@@ -592,6 +592,9 @@
CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() {
if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
+ if (FLAG_vector_ics) {
+ return VectorLoadICDescriptor(isolate());
+ }
return LoadDescriptor(isolate());
} else {
DCHECK_EQ(Code::STORE_IC, kind());
@@ -627,14 +630,13 @@
void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
InitializeVectorLoadStub(isolate(), descriptor,
-
FUNCTION_ADDR(VectorLoadIC_MissFromStubFailure));
+ FUNCTION_ADDR(LoadIC_MissFromStubFailure));
}
void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor*
descriptor) {
- InitializeVectorLoadStub(
- isolate(), descriptor,
- FUNCTION_ADDR(VectorKeyedLoadIC_MissFromStubFailure));
+ InitializeVectorLoadStub(isolate(), descriptor,
+ FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
}
=======================================
--- /branches/bleeding_edge/src/code-stubs.h Tue Sep 30 14:54:14 2014 UTC
+++ /branches/bleeding_edge/src/code-stubs.h Wed Oct 8 09:15:09 2014 UTC
@@ -857,7 +857,13 @@
// TODO(mvstanton): only the receiver register is accessed. When this is
// translated to a hydrogen code stub, a new CallInterfaceDescriptor
// should be created that just uses that register for more efficient
code.
- DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+ virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+ if (FLAG_vector_ics) {
+ return VectorLoadICDescriptor(isolate());
+ }
+ return LoadDescriptor(isolate());
+ }
+
DEFINE_PLATFORM_CODE_STUB(FunctionPrototype, PlatformCodeStub);
};
@@ -1819,7 +1825,13 @@
explicit LoadDictionaryElementStub(Isolate* isolate)
: HydrogenCodeStub(isolate) {}
- DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+ virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+ if (FLAG_vector_ics) {
+ return VectorLoadICDescriptor(isolate());
+ }
+ return LoadDescriptor(isolate());
+ }
+
DEFINE_HYDROGEN_CODE_STUB(LoadDictionaryElement, HydrogenCodeStub);
};
@@ -1831,7 +1843,11 @@
virtual Code::Kind GetCodeKind() const { return Code::KEYED_LOAD_IC; }
virtual InlineCacheState GetICState() const { return GENERIC; }
+ // Since KeyedLoadGeneric stub doesn't miss (simply calls runtime), it
+ // doesn't need to use the VectorLoadICDescriptor for the case when
+ // flag --vector-ics is true.
DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+
DEFINE_HYDROGEN_CODE_STUB(KeyedLoadGeneric, HydrogenCodeStub);
};
@@ -1845,9 +1861,7 @@
virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
- virtual InlineCacheState GetICState() const FINAL OVERRIDE {
- return GENERIC;
- }
+ virtual InlineCacheState GetICState() const FINAL OVERRIDE { return
DEFAULT; }
virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
return static_cast<ExtraICState>(minor_key_);
@@ -1893,7 +1907,13 @@
return static_cast<ExtraICState>(sub_minor_key());
}
- DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+ virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+ if (FLAG_vector_ics) {
+ return VectorLoadICDescriptor(isolate());
+ }
+ return LoadDescriptor(isolate());
+ }
+
DEFINE_HYDROGEN_CODE_STUB(MegamorphicLoad, HydrogenCodeStub);
};
@@ -1907,9 +1927,7 @@
virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
- virtual InlineCacheState GetICState() const FINAL OVERRIDE {
- return GENERIC;
- }
+ virtual InlineCacheState GetICState() const FINAL OVERRIDE { return
DEFAULT; }
virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
return static_cast<ExtraICState>(sub_minor_key());
@@ -2003,7 +2021,13 @@
class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
class IsJSArrayBits: public BitField<bool, 8, 1> {};
- DEFINE_CALL_INTERFACE_DESCRIPTOR(Load);
+ virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE {
+ if (FLAG_vector_ics) {
+ return VectorLoadICDescriptor(isolate());
+ }
+ return LoadDescriptor(isolate());
+ }
+
DEFINE_HYDROGEN_CODE_STUB(LoadFastElement, HydrogenCodeStub);
};
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Wed Sep 17 15:29:42
2014 UTC
+++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Wed Oct 8 09:15:09
2014 UTC
@@ -1002,17 +1002,21 @@
__ bind(&loop);
__ mov(receiver, Operand(ebp, kArgumentsOffset)); // load arguments
- // Use inline caching to speed up access to arguments.
if (FLAG_vector_ics) {
- __ mov(VectorLoadICDescriptor::SlotRegister(),
- Immediate(Smi::FromInt(0)));
+ // TODO(mvstanton): Vector-based ics need additional infrastructure
to
+ // be embedded here. For now, just call the runtime.
+ __ push(receiver);
+ __ push(key);
+ __ CallRuntime(Runtime::kGetProperty, 2);
+ } else {
+ // Use inline caching to speed up access to arguments.
+ Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
+ __ call(ic, RelocInfo::CODE_TARGET);
+ // It is important that we do not have a test instruction after the
+ // call. A test instruction after the call is used to indicate that
+ // we have generated an inline version of the keyed load. In this
+ // case, we know that we are not generating a test instruction next.
}
- Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
- __ call(ic, RelocInfo::CODE_TARGET);
- // It is important that we do not have a test instruction after the
- // call. A test instruction after the call is used to indicate that
- // we have generated an inline version of the keyed load. In this
- // case, we know that we are not generating a test instruction next.
// Push the nth argument.
__ push(eax);
=======================================
--- /branches/bleeding_edge/src/ia32/debug-ia32.cc Wed Sep 3 10:51:51 2014
UTC
+++ /branches/bleeding_edge/src/ia32/debug-ia32.cc Wed Oct 8 09:15:09 2014
UTC
@@ -182,7 +182,11 @@
// Register state for IC load call (from ic-ia32.cc).
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0,
false);
+ RegList regs = receiver.bit() | name.bit();
+ if (FLAG_vector_ics) {
+ regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+ }
+ Generate_DebugBreakCallHelper(masm, regs, 0, false);
}
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Mon Oct 6
08:25:27 2014 UTC
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Oct 8
09:15:09 2014 UTC
@@ -1287,7 +1287,13 @@
Handle<Symbol>
home_object_symbol(isolate()->heap()->home_object_symbol());
__ mov(LoadDescriptor::NameRegister(), home_object_symbol);
- CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ if (FLAG_vector_ics) {
+ __ mov(VectorLoadICDescriptor::SlotRegister(),
+ Immediate(Smi::FromInt(expr->HomeObjectFeedbackSlot())));
+ CallLoadIC(NOT_CONTEXTUAL);
+ } else {
+ CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ }
__ cmp(eax, isolate()->factory()->undefined_value());
Label done;
=======================================
--- /branches/bleeding_edge/src/ic/ic.cc Wed Oct 1 11:09:06 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic.cc Wed Oct 8 09:15:09 2014 UTC
@@ -2647,15 +2647,17 @@
}
-RUNTIME_FUNCTION(VectorLoadIC_MissFromStubFailure) {
- // TODO(mvstanton): To be enabled when ICs can accept a vector and slot
- return NULL;
-}
-
-
-RUNTIME_FUNCTION(VectorKeyedLoadIC_MissFromStubFailure) {
- // TODO(mvstanton): To be enabled when ICs can accept a vector and slot
- return NULL;
+RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
+ TimerEventScope<TimerEventIcMiss> timer(isolate);
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 2);
+ LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
+ Handle<Object> receiver = args.at<Object>(0);
+ Handle<Name> key = args.at<Name>(1);
+ ic.UpdateState(receiver, key);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver,
key));
+ return *result;
}
=======================================
--- /branches/bleeding_edge/src/ic/ic.h Mon Sep 29 13:11:27 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic.h Wed Oct 8 09:15:09 2014 UTC
@@ -680,8 +680,7 @@
DECLARE_RUNTIME_FUNCTION(BinaryOpIC_MissWithAllocationSite);
DECLARE_RUNTIME_FUNCTION(CompareNilIC_Miss);
DECLARE_RUNTIME_FUNCTION(ToBooleanIC_Miss);
-DECLARE_RUNTIME_FUNCTION(VectorLoadIC_MissFromStubFailure);
-DECLARE_RUNTIME_FUNCTION(VectorKeyedLoadIC_MissFromStubFailure);
+DECLARE_RUNTIME_FUNCTION(LoadIC_MissFromStubFailure);
// Support functions for callbacks handlers.
DECLARE_RUNTIME_FUNCTION(StoreCallbackProperty);
=======================================
--- /branches/bleeding_edge/src/mips/debug-mips.cc Wed Sep 3 18:19:54 2014
UTC
+++ /branches/bleeding_edge/src/mips/debug-mips.cc Wed Oct 8 09:15:09 2014
UTC
@@ -187,7 +187,11 @@
void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0);
+ RegList regs = receiver.bit() | name.bit();
+ if (FLAG_vector_ics) {
+ regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+ }
+ Generate_DebugBreakCallHelper(masm, regs, 0);
}
=======================================
--- /branches/bleeding_edge/src/mips/full-codegen-mips.cc Mon Oct 6
15:48:56 2014 UTC
+++ /branches/bleeding_edge/src/mips/full-codegen-mips.cc Wed Oct 8
09:15:09 2014 UTC
@@ -1351,7 +1351,13 @@
Handle<Symbol>
home_object_symbol(isolate()->heap()->home_object_symbol());
__ li(LoadDescriptor::NameRegister(), home_object_symbol);
- CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ if (FLAG_vector_ics) {
+ __ li(VectorLoadICDescriptor::SlotRegister(),
+ Operand(Smi::FromInt(expr->HomeObjectFeedbackSlot())));
+ CallLoadIC(NOT_CONTEXTUAL);
+ } else {
+ CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ }
Label done;
__ Branch(&done, ne, v0,
Operand(isolate()->factory()->undefined_value()));
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc Wed Sep 17 15:29:42
2014 UTC
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc Wed Oct 8 09:15:09
2014 UTC
@@ -1075,14 +1075,19 @@
// Use inline caching to speed up access to arguments.
if (FLAG_vector_ics) {
- __ Move(VectorLoadICDescriptor::SlotRegister(), Smi::FromInt(0));
+ // TODO(mvstanton): Vector-based ics need additional infrastructure
to
+ // be embedded here. For now, just call the runtime.
+ __ Push(receiver);
+ __ Push(key);
+ __ CallRuntime(Runtime::kGetProperty, 2);
+ } else {
+ Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ // It is important that we do not have a test instruction after the
+ // call. A test instruction after the call is used to indicate that
+ // we have generated an inline version of the keyed load. In this
+ // case, we know that we are not generating a test instruction next.
}
- Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code();
- __ Call(ic, RelocInfo::CODE_TARGET);
- // It is important that we do not have a test instruction after the
- // call. A test instruction after the call is used to indicate that
- // we have generated an inline version of the keyed load. In this
- // case, we know that we are not generating a test instruction next.
// Push the nth argument.
__ Push(rax);
=======================================
--- /branches/bleeding_edge/src/x64/debug-x64.cc Wed Sep 3 10:51:51 2014
UTC
+++ /branches/bleeding_edge/src/x64/debug-x64.cc Wed Oct 8 09:15:09 2014
UTC
@@ -164,7 +164,11 @@
// Register state for IC load call (from ic-x64.cc).
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
- Generate_DebugBreakCallHelper(masm, receiver.bit() | name.bit(), 0,
false);
+ RegList regs = receiver.bit() | name.bit();
+ if (FLAG_vector_ics) {
+ regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
+ }
+ Generate_DebugBreakCallHelper(masm, regs, 0, false);
}
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Mon Oct 6 08:25:27
2014 UTC
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Oct 8 09:15:09
2014 UTC
@@ -1321,7 +1321,14 @@
Handle<Symbol>
home_object_symbol(isolate()->heap()->home_object_symbol());
__ Move(LoadDescriptor::NameRegister(), home_object_symbol);
- CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ if (FLAG_vector_ics) {
+ __ Move(VectorLoadICDescriptor::SlotRegister(),
+ Smi::FromInt(expr->HomeObjectFeedbackSlot()));
+ CallLoadIC(NOT_CONTEXTUAL);
+ } else {
+ CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+ }
+
__ Cmp(rax, isolate()->factory()->undefined_value());
Label done;
--
--
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.