Revision: 23020
Author:   [email protected]
Date:     Mon Aug 11 06:55:16 2014 UTC
Log:      Initial shot at deoptimizing JSCallFunction in Turbofan.

BUG=
[email protected]

Review URL: https://codereview.chromium.org/444883006
http://code.google.com/p/v8/source/detail?r=23020

Modified:
 /branches/bleeding_edge/src/compiler/arm/linkage-arm.cc
 /branches/bleeding_edge/src/compiler/arm64/linkage-arm64.cc
 /branches/bleeding_edge/src/compiler/ast-graph-builder.cc
 /branches/bleeding_edge/src/compiler/code-generator.cc
 /branches/bleeding_edge/src/compiler/ia32/linkage-ia32.cc
 /branches/bleeding_edge/src/compiler/js-generic-lowering.cc
 /branches/bleeding_edge/src/compiler/js-operator.h
 /branches/bleeding_edge/src/compiler/linkage-impl.h
 /branches/bleeding_edge/src/compiler/linkage.cc
 /branches/bleeding_edge/src/compiler/linkage.h
 /branches/bleeding_edge/src/compiler/operator-properties-inl.h
 /branches/bleeding_edge/src/compiler/register-allocator.cc
 /branches/bleeding_edge/src/compiler/register-allocator.h
 /branches/bleeding_edge/src/compiler/x64/linkage-x64.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/test/cctest/cctest.status
 /branches/bleeding_edge/test/cctest/compiler/test-scheduler.cc
 /branches/bleeding_edge/test/cctest/test-deoptimization.cc

=======================================
--- /branches/bleeding_edge/src/compiler/arm/linkage-arm.cc Wed Jul 30 13:54:45 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm/linkage-arm.cc Mon Aug 11 06:55:16 2014 UTC
@@ -49,9 +49,10 @@


 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count) {
+    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+    CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone) {
   return LinkageHelper::GetStubCallDescriptor<LinkageHelperTraits>(
-      this->info_->zone(), descriptor, stack_parameter_count);
+      zone, descriptor, stack_parameter_count, can_deoptimize);
 }


=======================================
--- /branches/bleeding_edge/src/compiler/arm64/linkage-arm64.cc Tue Aug 5 14:06:33 2014 UTC +++ /branches/bleeding_edge/src/compiler/arm64/linkage-arm64.cc Mon Aug 11 06:55:16 2014 UTC
@@ -49,9 +49,10 @@


 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count) {
+    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+    CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone) {
   return LinkageHelper::GetStubCallDescriptor<LinkageHelperTraits>(
-      this->info_->zone(), descriptor, stack_parameter_count);
+      zone, descriptor, stack_parameter_count, can_deoptimize);
 }


=======================================
--- /branches/bleeding_edge/src/compiler/ast-graph-builder.cc Fri Aug 8 13:51:30 2014 UTC +++ /branches/bleeding_edge/src/compiler/ast-graph-builder.cc Mon Aug 11 06:55:16 2014 UTC
@@ -722,8 +722,13 @@
           environment()->Push(value);
// result is either the string key or Smi(0) indicating the property
           // is gone.
+          // TODO(jarin) Insert lazy deoptimization support here - the call
+          // actually
+          // can deoptimize.
           Node* res = ProcessArguments(
-              javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3);
+              javascript()->Call(3, NO_CALL_FUNCTION_FLAGS,
+                                 CallDescriptor::kCannotDeoptimize),
+              3);
Node* property_missing = NewNode(javascript()->StrictEqual(), res,
                                            jsgraph()->ZeroConstant());
           {
@@ -1246,9 +1251,12 @@
   }

   // Create node to perform the function call.
-  Operator* call = javascript()->Call(args->length() + 2, flags);
+  Operator* call = javascript()->Call(args->length() + 2, flags,
+                                      CallDescriptor::kCanDeoptimize);
   Node* value = ProcessArguments(call, args->length() + 2);
   ast_context()->ProduceValue(value);
+
+  BuildLazyBailout(value, expr->id());
 }


@@ -1283,9 +1291,12 @@
   VisitForValues(args);

   // Create node to perform the JS runtime call.
-  Operator* call = javascript()->Call(args->length() + 2, flags);
+  Operator* call = javascript()->Call(args->length() + 2, flags,
+                                      CallDescriptor::kCanDeoptimize);
   Node* value = ProcessArguments(call, args->length() + 2);
   ast_context()->ProduceValue(value);
+
+  BuildLazyBailout(value, expr->id());
 }


=======================================
--- /branches/bleeding_edge/src/compiler/code-generator.cc Wed Aug 6 11:49:02 2014 UTC +++ /branches/bleeding_edge/src/compiler/code-generator.cc Mon Aug 11 06:55:16 2014 UTC
@@ -215,7 +215,9 @@
   for (int i = 0; i < deopt_count; i++) {
     FrameStateDescriptor* descriptor = code()->GetDeoptimizationEntry(i);
     data->SetAstId(i, descriptor->bailout_id());
-    data->SetTranslationIndex(i, Smi::FromInt(0));
+    CHECK_NE(NULL, deoptimization_states_[i]);
+    data->SetTranslationIndex(
+        i, Smi::FromInt(deoptimization_states_[i]->translation_id_));
     data->SetArgumentsStackHeight(i, Smi::FromInt(0));
     data->SetPc(i, Smi::FromInt(-1));
   }
=======================================
--- /branches/bleeding_edge/src/compiler/ia32/linkage-ia32.cc Wed Jul 30 13:54:45 2014 UTC +++ /branches/bleeding_edge/src/compiler/ia32/linkage-ia32.cc Mon Aug 11 06:55:16 2014 UTC
@@ -45,9 +45,10 @@


 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count) {
+    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+    CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone) {
   return LinkageHelper::GetStubCallDescriptor<LinkageHelperTraits>(
-      this->info_->zone(), descriptor, stack_parameter_count);
+      zone, descriptor, stack_parameter_count, can_deoptimize);
 }


=======================================
--- /branches/bleeding_edge/src/compiler/js-generic-lowering.cc Fri Aug 8 12:41:57 2014 UTC +++ /branches/bleeding_edge/src/compiler/js-generic-lowering.cc Mon Aug 11 06:55:16 2014 UTC
@@ -347,6 +347,14 @@
   PatchInsertInput(node, 1, function_node);
   PatchOperator(node, common()->Call(desc));
 }
+
+
+static CallDescriptor::DeoptimizationSupport DeoptimizationSupportForNode(
+    Node* node) {
+  return OperatorProperties::CanLazilyDeoptimize(node->op())
+             ? CallDescriptor::kCanDeoptimize
+             : CallDescriptor::kCannotDeoptimize;
+}


 void JSGenericLowering::ReplaceWithRuntimeCall(Node* node,
@@ -355,12 +363,8 @@
   Operator::Property props = node->op()->properties();
   const Runtime::Function* fun = Runtime::FunctionForId(f);
   int nargs = (nargs_override < 0) ? fun->nargs : nargs_override;
-  CallDescriptor::DeoptimizationSupport deopt =
-      OperatorProperties::CanLazilyDeoptimize(node->op())
-          ? CallDescriptor::kCanDeoptimize
-          : CallDescriptor::kCannotDeoptimize;
-  CallDescriptor* desc =
-      linkage()->GetRuntimeCallDescriptor(f, nargs, props, deopt);
+  CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
+      f, nargs, props, DeoptimizationSupportForNode(node));
   Node* ref = ExternalConstant(ExternalReference(f, isolate()));
   Node* arity = Int32Constant(nargs);
   if (!centrystub_constant_.is_set()) {
@@ -524,7 +528,8 @@
   CallParameters p = OpParameter<CallParameters>(node);
   CallFunctionStub stub(isolate(), p.arity - 2, p.flags);
CodeStubInterfaceDescriptor* d = GetInterfaceDescriptor(isolate(), &stub);
-  CallDescriptor* desc = linkage()->GetStubCallDescriptor(d, p.arity - 1);
+  CallDescriptor* desc = linkage()->GetStubCallDescriptor(
+      d, p.arity - 1, DeoptimizationSupportForNode(node));
   Node* stub_code = CodeConstant(stub.GetCode());
   PatchInsertInput(node, 0, stub_code);
   PatchOperator(node, common()->Call(desc));
=======================================
--- /branches/bleeding_edge/src/compiler/js-operator.h Wed Aug 6 08:50:57 2014 UTC +++ /branches/bleeding_edge/src/compiler/js-operator.h Mon Aug 11 06:55:16 2014 UTC
@@ -5,6 +5,7 @@
 #ifndef V8_COMPILER_JS_OPERATOR_H_
 #define V8_COMPILER_JS_OPERATOR_H_

+#include "src/compiler/linkage.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/unique.h"
@@ -48,6 +49,9 @@
 struct CallParameters {
   int arity;
   CallFunctionFlags flags;
+ // TODO(jarin) Remove the deopt flag once we can deoptimize all JavaScript
+  // calls (specifically the FILTER_KEY call in ForInStatement).
+  CallDescriptor::DeoptimizationSupport can_deoptimize;
 };

// Interface for building JavaScript-level operators, e.g. directly from the
@@ -103,8 +107,9 @@

   Operator* Create() { SIMPLE(JSCreate, Operator::kEliminatable, 0, 1); }

-  Operator* Call(int arguments, CallFunctionFlags flags) {
-    CallParameters parameters = {arguments, flags};
+  Operator* Call(int arguments, CallFunctionFlags flags,
+                 CallDescriptor::DeoptimizationSupport can_deoptimize) {
+    CallParameters parameters = {arguments, flags, can_deoptimize};
OP1(JSCallFunction, CallParameters, parameters, Operator::kNoProperties,
         arguments, 1);
   }
=======================================
--- /branches/bleeding_edge/src/compiler/linkage-impl.h Mon Aug 4 11:34:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/linkage-impl.h Mon Aug 11 06:55:16 2014 UTC
@@ -128,7 +128,8 @@
   template <typename LinkageTraits>
   static CallDescriptor* GetStubCallDescriptor(
       Zone* zone, CodeStubInterfaceDescriptor* descriptor,
-      int stack_parameter_count) {
+      int stack_parameter_count,
+      CallDescriptor::DeoptimizationSupport can_deoptimize) {
int register_parameter_count = descriptor->GetEnvironmentParameterCount();
     int parameter_count = register_parameter_count + stack_parameter_count;
     const int code_count = 1;
@@ -165,9 +166,8 @@
                        locations,                        // locations
                        Operator::kNoProperties,          // properties
                        kNoCalleeSaved,  // callee-saved registers
- CallDescriptor::kCannotDeoptimize, // deoptimization
+                       can_deoptimize,  // deoptimization
                        CodeStub::MajorName(descriptor->MajorKey(), false));
-    // TODO(jarin) should deoptimize!
   }


=======================================
--- /branches/bleeding_edge/src/compiler/linkage.cc Tue Aug 5 14:06:33 2014 UTC +++ /branches/bleeding_edge/src/compiler/linkage.cc Mon Aug 11 06:55:16 2014 UTC
@@ -100,6 +100,14 @@
   return GetRuntimeCallDescriptor(function, parameter_count, properties,
                                   can_deoptimize, this->info_->zone());
 }
+
+
+CallDescriptor* Linkage::GetStubCallDescriptor(
+    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+    CallDescriptor::DeoptimizationSupport can_deoptimize) {
+  return GetStubCallDescriptor(descriptor, stack_parameter_count,
+                               can_deoptimize, this->info_->zone());
+}


//==============================================================================
@@ -122,7 +130,8 @@


 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count) {
+    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+    CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone) {
   UNIMPLEMENTED();
   return NULL;
 }
=======================================
--- /branches/bleeding_edge/src/compiler/linkage.h Mon Aug 4 11:34:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/linkage.h Mon Aug 11 06:55:16 2014 UTC
@@ -147,8 +147,13 @@
       Operator::Property properties,
       CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone);

- CallDescriptor* GetStubCallDescriptor(CodeStubInterfaceDescriptor* descriptor,
-                                        int stack_parameter_count = 0);
+  CallDescriptor* GetStubCallDescriptor(
+ CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count = 0,
+      CallDescriptor::DeoptimizationSupport can_deoptimize =
+          CallDescriptor::kCannotDeoptimize);
+  static CallDescriptor* GetStubCallDescriptor(
+      CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+      CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone);

   // Creates a call descriptor for simplified C calls that is appropriate
// for the host platform. This simplified calling convention only supports
=======================================
--- /branches/bleeding_edge/src/compiler/operator-properties-inl.h Thu Aug 7 09:14:37 2014 UTC +++ /branches/bleeding_edge/src/compiler/operator-properties-inl.h Mon Aug 11 06:55:16 2014 UTC
@@ -7,6 +7,7 @@

 #include "src/v8.h"

+#include "src/compiler/js-operator.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator-properties.h"

@@ -130,6 +131,14 @@
 }

 inline bool OperatorProperties::CanLazilyDeoptimize(Operator* op) {
+  // TODO(jarin) This function allows turning on lazy deoptimization
+  // incrementally. It will change as we turn on lazy deopt for
+  // more nodes.
+
+  if (!FLAG_turbo_deoptimization) {
+    return false;
+  }
+
   if (op->opcode() == IrOpcode::kCall) {
     CallOperator* call_op = reinterpret_cast<CallOperator*>(op);
     CallDescriptor* descriptor = call_op->parameter();
@@ -142,6 +151,11 @@
         reinterpret_cast<Operator1<Runtime::FunctionId>*>(op)->parameter();
     return function == Runtime::kDeoptimizeFunction;
   }
+  if (op->opcode() == IrOpcode::kJSCallFunction) {
+    CallParameters p =
+        reinterpret_cast<Operator1<CallParameters>*>(op)->parameter();
+    return p.can_deoptimize == CallDescriptor::kCanDeoptimize;
+  }
   return false;
 }
 }
=======================================
--- /branches/bleeding_edge/src/compiler/register-allocator.cc Mon Aug 4 11:34:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/register-allocator.cc Mon Aug 11 06:55:16 2014 UTC
@@ -744,6 +744,70 @@
       if (!AllocationOk()) return;
     }
   }
+
+  // Meet register constraints for the instruction in the end.
+  if (!code()->IsGapAt(end)) {
+    MeetRegisterConstraintsForLastInstructionInBlock(block);
+  }
+}
+
+
+void RegisterAllocator::MeetRegisterConstraintsForLastInstructionInBlock(
+    BasicBlock* block) {
+  int end = block->last_instruction_index();
+  Instruction* last_instruction = InstructionAt(end);
+  for (size_t i = 0; i < last_instruction->OutputCount(); i++) {
+    InstructionOperand* output_operand = last_instruction->OutputAt(i);
+    DCHECK(!output_operand->IsConstant());
+    UnallocatedOperand* output = UnallocatedOperand::cast(output_operand);
+    int output_vreg = output->virtual_register();
+    LiveRange* range = LiveRangeFor(output_vreg);
+    bool assigned = false;
+    if (output->HasFixedPolicy()) {
+      AllocateFixed(output, -1, false);
+      // This value is produced on the stack, we never need to spill it.
+      if (output->IsStackSlot()) {
+        range->SetSpillOperand(output);
+        range->SetSpillStartIndex(end);
+        assigned = true;
+      }
+
+      BasicBlock::Successors successors = block->successors();
+      for (BasicBlock::Successors::iterator succ = successors.begin();
+           succ != successors.end(); ++succ) {
+        DCHECK((*succ)->PredecessorCount() == 1);
+        int gap_index = (*succ)->first_instruction_index() + 1;
+        DCHECK(code()->IsGapAt(gap_index));
+
+        // Create an unconstrained operand for the same virtual register
+        // and insert a gap move from the fixed output to the operand.
+        UnallocatedOperand* output_copy =
+            new (code_zone()) UnallocatedOperand(UnallocatedOperand::ANY);
+        output_copy->set_virtual_register(output_vreg);
+
+        code()->AddGapMove(gap_index, output, output_copy);
+      }
+    }
+
+    if (!assigned) {
+      BasicBlock::Successors successors = block->successors();
+      for (BasicBlock::Successors::iterator succ = successors.begin();
+           succ != successors.end(); ++succ) {
+        DCHECK((*succ)->PredecessorCount() == 1);
+        int gap_index = (*succ)->first_instruction_index() + 1;
+        range->SetSpillStartIndex(gap_index);
+
+        // This move to spill operand is not a real use. Liveness analysis
+        // and splitting of live ranges do not account for it.
+ // Thus it should be inserted to a lifetime position corresponding to
+        // the instruction end.
+        GapInstruction* gap = code()->GapAt(gap_index);
+        ParallelMove* move =
+ gap->GetOrCreateParallelMove(GapInstruction::BEFORE, code_zone());
+        move->AddMove(output, range->GetSpillOperand(), code_zone());
+      }
+    }
+  }
 }


@@ -786,6 +850,8 @@
           code()->AddGapMove(gap_index, first_output, output_copy);
         }

+        // Make sure we add a gap move for spilling (if we have not done
+        // so already).
         if (!assigned) {
           range->SetSpillStartIndex(gap_index);

=======================================
--- /branches/bleeding_edge/src/compiler/register-allocator.h Mon Aug 4 11:34:54 2014 UTC +++ /branches/bleeding_edge/src/compiler/register-allocator.h Mon Aug 11 06:55:16 2014 UTC
@@ -391,6 +391,7 @@
   void MeetRegisterConstraints(BasicBlock* block);
   void MeetConstraintsBetween(Instruction* first, Instruction* second,
                               int gap_index);
+  void MeetRegisterConstraintsForLastInstructionInBlock(BasicBlock* block);
   void ResolvePhis(BasicBlock* block);

   // Helper methods for building intervals.
=======================================
--- /branches/bleeding_edge/src/compiler/x64/linkage-x64.cc Tue Aug 5 14:06:33 2014 UTC +++ /branches/bleeding_edge/src/compiler/x64/linkage-x64.cc Mon Aug 11 06:55:16 2014 UTC
@@ -64,9 +64,10 @@


 CallDescriptor* Linkage::GetStubCallDescriptor(
-    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count) {
+    CodeStubInterfaceDescriptor* descriptor, int stack_parameter_count,
+    CallDescriptor::DeoptimizationSupport can_deoptimize, Zone* zone) {
   return LinkageHelper::GetStubCallDescriptor<LinkageHelperTraits>(
-      this->info_->zone(), descriptor, stack_parameter_count);
+      zone, descriptor, stack_parameter_count, can_deoptimize);
 }


=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Aug  7 16:14:22 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc      Mon Aug 11 06:55:16 2014 UTC
@@ -11128,7 +11128,7 @@
os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
   if (0 != deopt_count) {
     os << " index  ast id    argc     pc";
-    if (FLAG_print_code_verbose) os << "commands";
+    if (FLAG_print_code_verbose) os << "  commands";
     os << "\n";
   }
   for (int i = 0; i < deopt_count; i++) {
@@ -11158,7 +11158,7 @@
            Translation::BEGIN !=
            (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
       Vector<char> buf2 = Vector<char>::New(128);
-      SNPrintF(buf2, "%24s    %s ", "", Translation::StringFor(opcode));
+      SNPrintF(buf2, "%27s    %s ", "", Translation::StringFor(opcode));
       os << buf2.start();

       switch (opcode) {
@@ -11284,11 +11284,11 @@
   if (return_address_patch_count != 0) {
os << "Return address patch data (count = " << return_address_patch_count
        << ")\n";
-    os << "index pc    patched_pc\n";
+    os << " index    pc  patched_pc\n";
   }
   for (int i = 0; i < return_address_patch_count; i++) {
     Vector<char> buf = Vector<char>::New(128);
-    SNPrintF(buf, "%6d  %6d  %10d", i, ReturnAddressPc(i)->value(),
+    SNPrintF(buf, "%6d  %6d  %12d\n", i, ReturnAddressPc(i)->value(),
              PatchedAddressPc(i)->value());
     os << buf.start();
   }
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.status Fri Aug 8 14:05:24 2014 UTC +++ /branches/bleeding_edge/test/cctest/cctest.status Mon Aug 11 06:55:16 2014 UTC
@@ -107,9 +107,6 @@
   'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS],

   # Support for lazy deoptimization is missing.
-  'test-deoptimization/DeoptimizeSimple': [PASS, NO_VARIANTS],
-  'test-deoptimization/DeoptimizeSimpleNested': [PASS, NO_VARIANTS],
-  'test-deoptimization/DeoptimizeSimpleWithArguments': [PASS, NO_VARIANTS],
   'test-deoptimization/DeoptimizeBinaryOperation*': [PASS, NO_VARIANTS],
   'test-deoptimization/DeoptimizeCompare': [PASS, NO_VARIANTS],
   'test-deoptimization/DeoptimizeLoadICStoreIC': [PASS, NO_VARIANTS],
=======================================
--- /branches/bleeding_edge/test/cctest/compiler/test-scheduler.cc Wed Aug 6 11:49:02 2014 UTC +++ /branches/bleeding_edge/test/cctest/compiler/test-scheduler.cc Mon Aug 11 06:55:16 2014 UTC
@@ -1713,6 +1713,8 @@


 TEST(BuildScheduleTrivialLazyDeoptCall) {
+  FLAG_turbo_deoptimization = true;
+
   HandleAndZoneScope scope;
   Isolate* isolate = scope.main_isolate();
   Graph graph(scope.main_zone());
=======================================
--- /branches/bleeding_edge/test/cctest/test-deoptimization.cc Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-deoptimization.cc Mon Aug 11 06:55:16 2014 UTC
@@ -113,6 +113,8 @@


 TEST(DeoptimizeSimple) {
+  i::FLAG_turbo_deoptimization = true;
+
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());

@@ -151,6 +153,8 @@


 TEST(DeoptimizeSimpleWithArguments) {
+  i::FLAG_turbo_deoptimization = true;
+
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());

@@ -190,6 +194,8 @@


 TEST(DeoptimizeSimpleNested) {
+  i::FLAG_turbo_deoptimization = true;
+
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());

--
--
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.

Reply via email to