Revision: 3856
Author: [email protected]
Date: Mon Feb 15 04:26:07 2010
Log: Change CallIC interface on ARM. Remove name from the stack, and pass it in register r2.
Review URL: http://codereview.chromium.org/598065
http://code.google.com/p/v8/source/detail?r=3856

Modified:
 /branches/bleeding_edge/src/arm/builtins-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/ic-arm.cc
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc

=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc     Fri Jan 15 04:25:24 2010
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc     Mon Feb 15 04:26:07 2010
@@ -915,7 +915,7 @@
   }

   // 2. Get the function to call from the stack.
-  // r0: actual number of argument
+  // r0: actual number of arguments
   { Label done, non_function, function;
     __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
     __ tst(r1, Operand(kSmiTagMask));
@@ -997,13 +997,27 @@
     __ bind(&done);
   }

-  // 4. Shift stuff one slot down the stack
+  // 4. Handle non-functions.
   // r0: actual number of arguments (including call() receiver)
   // r1: function
+  { Label done;
+    __ tst(r1, r1);
+    __ b(ne, &done);
+ __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
+    // Transfer the receiver from the first argument to the top of the
+    // caller's expression stack simply by decrementing argc.
+    __ sub(r0, r0, Operand(1));
+    __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
+    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+                         RelocInfo::CODE_TARGET);
+    __ bind(&done);
+  }
+
+  // 5. Shift arguments one slot toward the bottom of the
+  //    stack, overwriting the receiver.
   { Label loop;
// Calculate the copy start address (destination). Copy end address is sp.
     __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
-    __ add(r2, r2, Operand(kPointerSize));  // copy receiver too

     __ bind(&loop);
     __ ldr(ip, MemOperand(r2, -kPointerSize));
@@ -1011,43 +1025,28 @@
     __ sub(r2, r2, Operand(kPointerSize));
     __ cmp(r2, sp);
     __ b(ne, &loop);
-  }
-
-  // 5. Adjust the actual number of arguments and remove the top element.
-  // r0: actual number of arguments (including call() receiver)
-  // r1: function
-  __ sub(r0, r0, Operand(1));
-  __ add(sp, sp, Operand(kPointerSize));
+    // Adjust the actual number of arguments and remove the top element.
+    __ sub(r0, r0, Operand(1));
+    __ pop();
+  }

   // 6. Get the code for the function or the non-function builtin.
// If number of expected arguments matches, then call. Otherwise restart
   //    the arguments adaptor stub.
   // r0: actual number of arguments
   // r1: function
-  { Label invoke;
-    __ tst(r1, r1);
-    __ b(ne, &invoke);
- __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
-    __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
-    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
-                         RelocInfo::CODE_TARGET);
-
-    __ bind(&invoke);
-    __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
-    __ ldr(r2,
-           FieldMemOperand(r3,
- SharedFunctionInfo::kFormalParameterCountOffset));
-    __ ldr(r3,
- MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
-    __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
-    __ cmp(r2, r0);  // Check formal and actual parameter counts.
-    __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
-                         RelocInfo::CODE_TARGET, ne);
-
-    // 7. Jump to the code in r3 without checking arguments.
-    ParameterCount expected(0);
-    __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
-  }
+  __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+  __ ldr(r2,
+ FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
+  __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset));
+  __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ cmp(r2, r0);  // Check formal and actual parameter counts.
+  __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+          RelocInfo::CODE_TARGET, ne);
+
+  // 7. Jump (tail-call) to the code in r3 without checking arguments.
+  ParameterCount expected(0);
+  __ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
 }


=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Thu Feb 11 04:28:49 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Mon Feb 15 04:26:07 2010
@@ -3023,11 +3023,6 @@
     // ----------------------------------
     // JavaScript example: 'foo(1, 2, 3)'  // foo is global
     // ----------------------------------
-
-    // Push the name of the function and the receiver onto the stack.
-    __ mov(r0, Operand(var->name()));
-    frame_->EmitPush(r0);
-
     // Pass the global object as the receiver and let the IC stub
     // patch the stack to use the global proxy as 'this' in the
     // invoked function.
@@ -3039,15 +3034,14 @@
       LoadAndSpill(args->at(i));
     }

-    // Setup the receiver register and call the IC initialization code.
+    // Setup the name register and call the IC initialization code.
+    __ mov(r2, Operand(var->name()));
     InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
     Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
     CodeForSourcePosition(node->position());
     frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
                            arg_count + 1);
     __ ldr(cp, frame_->Context());
-    // Remove the function from the stack.
-    frame_->Drop();
     frame_->EmitPush(r0);

   } else if (var != NULL && var->slot() != NULL &&
@@ -3080,28 +3074,21 @@
       // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
       // ------------------------------------------------------------------

-      // Push the name of the function and the receiver onto the stack.
-      __ mov(r0, Operand(literal->handle()));
-      frame_->EmitPush(r0);
-      LoadAndSpill(property->obj());
-
+      LoadAndSpill(property->obj());  // Receiver.
       // Load the arguments.
       int arg_count = args->length();
       for (int i = 0; i < arg_count; i++) {
         LoadAndSpill(args->at(i));
       }

-      // Set the receiver register and call the IC initialization code.
+      // Set the name register and call the IC initialization code.
+      __ mov(r2, Operand(literal->handle()));
       InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
       Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
       CodeForSourcePosition(node->position());
       frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
       __ ldr(cp, frame_->Context());
-
-      // Remove the function from the stack.
-      frame_->Drop();
-
- frame_->EmitPush(r0); // push after get rid of function from the stack
+      frame_->EmitPush(r0);

     } else {
       // -------------------------------------------
@@ -3636,8 +3623,6 @@

   if (function == NULL) {
     // Prepare stack for calling JS runtime function.
-    __ mov(r0, Operand(node->name()));
-    frame_->EmitPush(r0);
     // Push the builtins object found in the current global object.
     __ ldr(r1, GlobalObject());
     __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
@@ -3652,11 +3637,11 @@

   if (function == NULL) {
     // Call the JS runtime function.
+    __ mov(r2, Operand(node->name()));
     InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
     Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
     frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
     __ ldr(cp, frame_->Context());
-    frame_->Drop();
     frame_->EmitPush(r0);
   } else {
     // Call the C runtime function.
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Feb 10 07:06:08 2010 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Mon Feb 15 04:26:07 2010
@@ -1090,7 +1090,7 @@
 }

 void FullCodeGenerator::EmitCallWithIC(Call* expr,
-                                       Handle<Object> ignored,
+                                       Handle<Object> name,
                                        RelocInfo::Mode mode) {
   // Code common for calls using the IC.
   ZoneList<Expression*>* args = expr->arguments();
@@ -1098,16 +1098,16 @@
   for (int i = 0; i < arg_count; i++) {
     VisitForValue(args->at(i), kStack);
   }
+  __ mov(r2, Operand(name));
   // Record source position for debugger.
   SetSourcePosition(expr->position());
   // Call the IC initialization code.
-  Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
-                                                         NOT_IN_LOOP);
+  InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
+ Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
   __ Call(ic, mode);
   // Restore context register.
   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  // Discard the function left on TOS.
-  DropAndApply(1, context_, r0);
+  Apply(context_, r0);
 }


@@ -1124,7 +1124,6 @@
   __ CallStub(&stub);
   // Restore context register.
   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  // Discard the function left on TOS.
   DropAndApply(1, context_, r0);
 }

@@ -1138,11 +1137,9 @@
     // Call to the identifier 'eval'.
     UNREACHABLE();
   } else if (var != NULL && !var->is_this() && var->is_global()) {
-    // Call to a global variable.
-    __ mov(r1, Operand(var->name()));
-    // Push global object as receiver for the call IC lookup.
+    // Push global object as receiver for the call IC.
     __ ldr(r0, CodeGenerator::GlobalObject());
-    __ stm(db_w, sp, r1.bit() | r0.bit());
+    __ push(r0);
     EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
   } else if (var != NULL && var->slot() != NULL &&
              var->slot()->type() == Slot::LOOKUP) {
@@ -1154,8 +1151,6 @@
     Literal* key = prop->key()->AsLiteral();
     if (key != NULL && key->handle()->IsSymbol()) {
       // Call to a named property, use call IC.
-      __ mov(r0, Operand(key->handle()));
-      __ push(r0);
       VisitForValue(prop->obj(), kStack);
       EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
     } else {
@@ -1241,10 +1236,9 @@

   if (expr->is_jsruntime()) {
     // Prepare for calling JS runtime function.
-    __ mov(r1, Operand(expr->name()));
     __ ldr(r0, CodeGenerator::GlobalObject());
     __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
-    __ stm(db_w, sp, r1.bit() | r0.bit());
+    __ push(r0);
   }

   // Push the arguments ("left-to-right").
@@ -1255,18 +1249,17 @@

   if (expr->is_jsruntime()) {
     // Call the JS runtime function.
+    __ mov(r2, Operand(expr->name()));
     Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
                                                            NOT_IN_LOOP);
     __ Call(ic, RelocInfo::CODE_TARGET);
     // Restore context register.
     __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-    // Discard the function left on TOS.
-    DropAndApply(1, context_, r0);
   } else {
     // Call the C runtime function.
     __ CallRuntime(expr->function(), arg_count);
-    Apply(context_, r0);
-  }
+  }
+  Apply(context_, r0);
 }


=======================================
--- /branches/bleeding_edge/src/arm/ic-arm.cc   Fri Feb 12 06:21:18 2010
+++ /branches/bleeding_edge/src/arm/ic-arm.cc   Mon Feb 15 04:26:07 2010
@@ -59,7 +59,7 @@
   // r3 - used as temporary and to hold the capacity of the property
   //      dictionary.
   //
-  // r2 - holds the name of the property and is unchanges.
+  // r2 - holds the name of the property and is unchanged.

   Label done;

@@ -219,14 +219,13 @@

 void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------
   Label number, non_number, non_string, boolean, probe, miss;

   // Get the receiver of the function from the stack into r1.
   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
-  // Get the name of the function from the stack; 1 ~ receiver.
-  __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));

   // Probe the stub cache.
   Code::Flags flags =
@@ -301,9 +300,9 @@

   // Patch the receiver with the global proxy if necessary.
   if (is_global_object) {
-    __ ldr(r2, MemOperand(sp, argc * kPointerSize));
-    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
-    __ str(r2, MemOperand(sp, argc * kPointerSize));
+    __ ldr(r0, MemOperand(sp, argc * kPointerSize));
+    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
+    __ str(r0, MemOperand(sp, argc * kPointerSize));
   }

   // Invoke the function.
@@ -314,14 +313,13 @@

 void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------
   Label miss, global_object, non_global_object;

   // Get the receiver of the function from the stack into r1.
   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
-  // Get the name of the function from the stack; 1 ~ receiver.
-  __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));

   // Check that the receiver isn't a smi.
   __ tst(r1, Operand(kSmiTagMask));
@@ -374,18 +372,17 @@

 void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------

   // Get the receiver of the function from the stack.
-  __ ldr(r2, MemOperand(sp, argc * kPointerSize));
-  // Get the name of the function to call from the stack.
-  __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
+  __ ldr(r3, MemOperand(sp, argc * kPointerSize));

   __ EnterInternalFrame();

   // Push the receiver and the name of the function.
-  __ stm(db_w, sp, r1.bit() | r2.bit());
+  __ stm(db_w, sp, r2.bit() | r3.bit());

   // Call the entry.
   __ mov(r0, Operand(2));
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Feb 15 03:52:18 2010 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Feb 15 04:26:07 2010
@@ -376,7 +376,7 @@

   // Check that the function really is a function.
   __ BranchOnSmi(r1, miss);
-  __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
+  __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
   __ b(ne, miss);

   // Patch the receiver on the stack with the global proxy if
@@ -803,7 +803,8 @@
                                            int index,
                                            String* name) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------
   Label miss;

@@ -817,7 +818,7 @@

   // Do the right check and compute the holder register.
   Register reg =
- CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss); + CheckPrototypes(JSObject::cast(object), r0, holder, r1, r3, name, &miss);
   GenerateFastPropertyLoad(masm(), r1, reg, holder, index);

   GenerateCallFunction(masm(), object, arguments(), &miss);
@@ -838,7 +839,8 @@
                                               String* name,
                                               CheckType check) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------
   Label miss;

@@ -859,7 +861,7 @@
   switch (check) {
     case RECEIVER_MAP_CHECK:
       // Check that the maps haven't changed.
- CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss); + CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);

       // Patch the receiver on the stack with the global proxy if
       // necessary.
@@ -875,13 +877,13 @@
         __ jmp(&miss);
       } else {
         // Check that the object is a two-byte string or a symbol.
-        __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
+        __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
         __ b(hs, &miss);
         // Check that the maps starting from the prototype haven't changed.
         GenerateLoadGlobalFunctionPrototype(masm(),
                                             Context::STRING_FUNCTION_INDEX,
-                                            r2);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
+                                            r0);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
                         r1, name, &miss);
       }
       break;
@@ -895,14 +897,14 @@
         // Check that the object is a smi or a heap number.
         __ tst(r1, Operand(kSmiTagMask));
         __ b(eq, &fast);
-        __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
+        __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
         __ b(ne, &miss);
         __ bind(&fast);
         // Check that the maps starting from the prototype haven't changed.
         GenerateLoadGlobalFunctionPrototype(masm(),
                                             Context::NUMBER_FUNCTION_INDEX,
-                                            r2);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
+                                            r0);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
                         r1, name, &miss);
       }
       break;
@@ -925,22 +927,22 @@
         // Check that the maps starting from the prototype haven't changed.
         GenerateLoadGlobalFunctionPrototype(masm(),
Context::BOOLEAN_FUNCTION_INDEX,
-                                            r2);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
+                                            r0);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
                         r1, name, &miss);
       }
       break;
     }

     case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
- CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss); + CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
       // Make sure object->HasFastElements().
       // Get the elements array of the object.
       __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
       // Check that the object is in fast mode (not dictionary).
-      __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
+      __ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset));
       __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
-      __ cmp(r2, ip);
+      __ cmp(r0, ip);
       __ b(ne, &miss);
       break;

@@ -968,15 +970,16 @@
                                                  JSObject* holder,
                                                  String* name) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------
   ASSERT(holder->HasNamedInterceptor());
   ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
   Label miss;

   const Register receiver = r0;
-  const Register name_reg = r1;
-  const Register holder_reg = r2;
+  const Register holder_reg = r1;
+  const Register name_reg = r2;
   const Register scratch = r3;

   // Get the number of arguments.
@@ -985,10 +988,8 @@
   LookupResult lookup;
   LookupPostInterceptor(holder, name, &lookup);

-  // Load the receiver from the stack.
-  __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
-  // Load the name from the stack.
-  __ ldr(name_reg, MemOperand(sp, (argc + 1) * kPointerSize));
+  // Get the receiver from the stack into r0.
+  __ ldr(r0, MemOperand(sp, argc * kPointerSize));

   // Check that the receiver isn't a smi.
   __ BranchOnSmi(receiver, &miss);
@@ -1060,10 +1061,8 @@
     __ pop(name_reg);
     __ LeaveInternalFrame();
   }
-

   // Move returned value, the function to call, to r1.
-  // Neither receiver nor name contain their original value at this point.
   __ mov(r1, r0);
   // Restore receiver.
   __ ldr(receiver, MemOperand(sp, argc * kPointerSize));
@@ -1086,7 +1085,8 @@
                                             JSFunction* function,
                                             String* name) {
   // ----------- S t a t e -------------
-  //  -- lr: return address
+  //  -- r2    : name
+  //  -- lr    : return address
   // -----------------------------------
   Label miss;

@@ -1105,7 +1105,7 @@
   }

   // Check that the maps haven't changed.
-  CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
+  CheckPrototypes(object, r0, holder, r3, r1, name, &miss);

   // Get the value from the cell.
   __ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
@@ -1125,8 +1125,8 @@

     // Check the shared function info. Make sure it hasn't changed.
     __ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
-    __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
-    __ cmp(r2, r3);
+    __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+    __ cmp(r4, r3);
     __ b(ne, &miss);
   } else {
     __ cmp(r1, Operand(Handle<JSFunction>(function)));
@@ -1144,7 +1144,7 @@
   __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));

   // Jump to the cached code (tail call).
-  __ IncrementCounter(&Counters::call_global_inline, 1, r2, r3);
+  __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
   ASSERT(function->is_compiled());
   Handle<Code> code(function->code());
   ParameterCount expected(function->shared()->formal_parameter_count());

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to