Revision: 8452
Author:   [email protected]
Date:     Tue Jun 28 08:22:08 2011
Log:      Remove the fcontext field from all contexts.

Before: every context cached the nearest enclosing function context.  This
assumed that for nested contexts (i.e., with and catch contexts) the
enclosing function had a materialized link in the context chain.

Now: when necessary, we loop up the context chain to find such a context.
This enables catch contexts without forcing the enclosing function to
allocate its own context.

[email protected]
BUG=
TEST=

Review URL: http://codereview.chromium.org/7230047
http://code.google.com/p/v8/source/detail?r=8452

Modified:
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/contexts.cc
 /branches/bleeding_edge/src/contexts.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Thu Jun 23 05:03:16 2011 +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Tue Jun 28 08:22:08 2011
@@ -165,7 +165,6 @@
   // Setup the fixed slots.
   __ mov(r1, Operand(Smi::FromInt(0)));
   __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
-  __ str(r0, MemOperand(r0, Context::SlotOffset(Context::FCONTEXT_INDEX)));
   __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
__ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Jun 24 07:30:10 2011 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue Jun 28 08:22:08 2011
@@ -713,10 +713,12 @@
         // context.
         ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
         if (FLAG_debug_code) {
-          // Check that we're not inside a 'with'.
-          __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
-          __ cmp(r1, cp);
-          __ Check(eq, "Unexpected declaration in current context.");
+          // Check that we're not inside a with or catch context.
+          __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
+          __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
+          __ Check(ne, "Declaration in with context.");
+          __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
+          __ Check(ne, "Declaration in catch context.");
         }
         if (mode == Variable::CONST) {
           __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
@@ -1867,18 +1869,7 @@
         __ b(ne, &skip);
         __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
         break;
-      case Slot::CONTEXT: {
-        __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
-        __ ldr(r2, ContextOperand(r1, slot->index()));
-        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-        __ cmp(r2, ip);
-        __ b(ne, &skip);
-        __ str(r0, ContextOperand(r1, slot->index()));
-        int offset = Context::SlotOffset(slot->index());
-        __ mov(r3, r0);  // Preserve the stored value in r0.
-        __ RecordWrite(r1, Operand(offset), r3, r2);
-        break;
-      }
+      case Slot::CONTEXT:
       case Slot::LOOKUP:
         __ push(r0);
         __ mov(r0, Operand(slot->var()->name()));
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Thu Jun 23 05:03:16 2011 +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jun 28 08:22:08 2011
@@ -2562,17 +2562,6 @@
     // cannot be allowed to destroy the context in esi).
     mov(dst, cp);
   }
-
-  // We should not have found a 'with' context by walking the context chain
-  // (i.e., the static scope chain and runtime context chain do not agree).
-  // A variable occurring in such a scope should have slot type LOOKUP and
-  // not CONTEXT.
-  if (emit_debug_code()) {
-    ldr(ip, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
-    cmp(dst, ip);
-    Check(eq, "Yo dawg, I heard you liked function contexts "
-              "so I put function contexts in all your contexts");
-  }
 }


=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Jun 16 07:12:58 2011
+++ /branches/bleeding_edge/src/bootstrapper.cc Tue Jun 28 08:22:08 2011
@@ -814,7 +814,6 @@
   // --- G l o b a l   C o n t e x t ---
   // Use the empty function as closure (no scope info).
   global_context()->set_closure(*empty_function);
-  global_context()->set_fcontext(*global_context());
   global_context()->set_previous(NULL);
   // Set extension and global object.
   global_context()->set_extension(*inner_global);
=======================================
--- /branches/bleeding_edge/src/contexts.cc     Thu Jun 16 07:12:58 2011
+++ /branches/bleeding_edge/src/contexts.cc     Tue Jun 28 08:22:08 2011
@@ -34,6 +34,16 @@
 namespace v8 {
 namespace internal {

+Context* Context::declaration_context() {
+  Context* current = this;
+  while (!current->IsFunctionContext() && !current->IsGlobalContext()) {
+    current = current->previous();
+    ASSERT(current->closure() == closure());
+  }
+  return current;
+}
+
+
 JSBuiltinsObject* Context::builtins() {
   GlobalObject* object = global();
   if (object->IsJSGlobalObject()) {
@@ -246,20 +256,22 @@
bool* outer_scope_calls_non_strict_eval) {
   // Skip up the context chain checking all the function contexts to see
   // whether they call eval.
-  Context* context = fcontext();
+  Context* context = this;
   while (!context->IsGlobalContext()) {
-    Handle<SerializedScopeInfo> scope_info(
-        context->closure()->shared()->scope_info());
-    if (scope_info->CallsEval()) {
-      *outer_scope_calls_eval = true;
-      if (!scope_info->IsStrictMode()) {
-        // No need to go further since the answers will not change
-        // from here.
-        *outer_scope_calls_non_strict_eval = true;
-        return;
+    if (context->IsFunctionContext()) {
+      Handle<SerializedScopeInfo> scope_info(
+          context->closure()->shared()->scope_info());
+      if (scope_info->CallsEval()) {
+        *outer_scope_calls_eval = true;
+        if (!scope_info->IsStrictMode()) {
+          // No need to go further since the answers will not change from
+          // here.
+          *outer_scope_calls_non_strict_eval = true;
+          return;
+        }
       }
     }
-    context = context->previous()->fcontext();
+    context = context->previous();
   }
 }

=======================================
--- /branches/bleeding_edge/src/contexts.h      Thu Jun 16 07:12:58 2011
+++ /branches/bleeding_edge/src/contexts.h      Tue Jun 28 08:22:08 2011
@@ -130,13 +130,6 @@
 //                statically allocated context slots. The names are needed
 //                for dynamic lookups in the presence of 'with' or 'eval'.
 //
-// [ fcontext  ]  A pointer to the innermost enclosing function context.
-//                It is the same for all contexts *allocated* inside a
-//                function, and the function context's fcontext points
-//                to itself. It is only needed for fast access of the
-//                function context (used for declarations, and static
-//                context slot access).
-//
 // [ previous  ]  A pointer to the previous context. It is NULL for
 //                function contexts, and non-NULL for 'with' contexts.
 //                Used to implement the 'with' statement.
@@ -158,16 +151,6 @@
// (via static context addresses) or through 'eval' (dynamic context lookups).
 // Finally, the global context contains additional slots for fast access to
 // global properties.
-//
-// We may be able to simplify the implementation:
-//
-// - We may be able to get rid of 'fcontext': We can always use the fact that -// previous == NULL for function contexts and so we can search for them. They -// are only needed when doing dynamic declarations, and the context chains
-//   tend to be very very short (depth of nesting of 'with' statements). At
-// the moment we also use it in generated code for context slot accesses -
-//   and there we don't want a loop because of code bloat - but we may not
-//   need it there after all (see comment in codegen_*.cc).

 class Context: public FixedArray {
  public:
@@ -181,7 +164,6 @@
   enum {
     // These slots are in all contexts.
     CLOSURE_INDEX,
-    FCONTEXT_INDEX,
     PREVIOUS_INDEX,
     // The extension slot is used for either the global object (in global
// contexts), eval extension object (function contexts), subject of with
@@ -263,9 +245,6 @@
   // Direct slot access.
   JSFunction* closure() { return JSFunction::cast(get(CLOSURE_INDEX)); }
   void set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); }
-
-  Context* fcontext() { return Context::cast(get(FCONTEXT_INDEX)); }
-  void set_fcontext(Context* context) { set(FCONTEXT_INDEX, context); }

   Context* previous() {
     Object* result = unchecked_previous();
@@ -277,6 +256,10 @@
   bool has_extension() { return extension() != NULL; }
   Object* extension() { return get(EXTENSION_INDEX); }
   void set_extension(Object* object) { set(EXTENSION_INDEX, object); }
+
+  // Get the context where var declarations will be hoisted to, which
+  // may be the context itself.
+  Context* declaration_context();

   GlobalObject* global() {
     Object* result = get(GLOBAL_INDEX);
=======================================
--- /branches/bleeding_edge/src/heap.cc Fri Jun 24 06:44:27 2011
+++ /branches/bleeding_edge/src/heap.cc Tue Jun 28 08:22:08 2011
@@ -3932,7 +3932,6 @@
   Context* context = reinterpret_cast<Context*>(result);
   context->set_map(function_context_map());
   context->set_closure(function);
-  context->set_fcontext(context);
   context->set_previous(function->context());
   context->set_extension(NULL);
   context->set_global(function->context()->global());
@@ -3952,7 +3951,6 @@
   Context* context = reinterpret_cast<Context*>(result);
   context->set_map(catch_context_map());
   context->set_closure(previous->closure());
-  context->set_fcontext(previous->fcontext());
   context->set_previous(previous);
   context->set_extension(name);
   context->set_global(previous->global());
@@ -3970,7 +3968,6 @@
   Context* context = reinterpret_cast<Context*>(result);
   context->set_map(with_context_map());
   context->set_closure(previous->closure());
-  context->set_fcontext(previous->fcontext());
   context->set_previous(previous);
   context->set_extension(extension);
   context->set_global(previous->global());
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Wed Jun 22 01:28:35 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Jun 28 08:22:08 2011
@@ -136,7 +136,6 @@
   // Setup the fixed slots.
   __ Set(ebx, Immediate(0));  // Set to NULL.
   __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx);
-  __ mov(Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)), eax);
   __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi);
   __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx);

=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Jun 24 07:30:10 2011 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Jun 28 08:22:08 2011
@@ -687,10 +687,12 @@
         // context.
         ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
         if (FLAG_debug_code) {
-          // Check that we're not inside a 'with'.
-          __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX));
-          __ cmp(ebx, Operand(esi));
-          __ Check(equal, "Unexpected declaration in current context.");
+          // Check that we're not inside a with or catch context.
+          __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
+          __ cmp(ebx, isolate()->factory()->with_context_map());
+          __ Check(not_equal, "Declaration in with context.");
+          __ cmp(ebx, isolate()->factory()->catch_context_map());
+          __ Check(not_equal, "Declaration in catch context.");
         }
         if (mode == Variable::CONST) {
           __ mov(ContextOperand(esi, slot->index()),
@@ -1818,17 +1820,7 @@
         __ j(not_equal, &skip);
         __ mov(Operand(ebp, SlotOffset(slot)), eax);
         break;
-      case Slot::CONTEXT: {
-        __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX));
-        __ mov(edx, ContextOperand(ecx, slot->index()));
-        __ cmp(edx, isolate()->factory()->the_hole_value());
-        __ j(not_equal, &skip);
-        __ mov(ContextOperand(ecx, slot->index()), eax);
-        int offset = Context::SlotOffset(slot->index());
-        __ mov(edx, eax);  // Preserve the stored value in eax.
-        __ RecordWrite(ecx, offset, edx, ebx);
-        break;
-      }
+      case Slot::CONTEXT:
       case Slot::LOOKUP:
         __ push(eax);
         __ push(esi);
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Jun 17 11:32:36 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Jun 28 08:22:08 2011
@@ -1766,14 +1766,17 @@
     mov(dst, esi);
   }

-  // We should not have found a 'with' context by walking the context chain
-  // (i.e., the static scope chain and runtime context chain do not agree).
-  // A variable occurring in such a scope should have slot type LOOKUP and
-  // not CONTEXT.
+ // We should not have found a with or catch context by walking the context
+  // chain (i.e., the static scope chain and runtime context chain do not
+  // agree).  A variable occurring in such a scope should have slot type
+  // LOOKUP and not CONTEXT.
   if (emit_debug_code()) {
-    cmp(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
-    Check(equal, "Yo dawg, I heard you liked function contexts "
-                 "so I put function contexts in all your contexts");
+    cmp(FieldOperand(dst, HeapObject::kMapOffset),
+        isolate()->factory()->with_context_map());
+    Check(not_equal, "Variable resolved to with context.");
+    cmp(FieldOperand(dst, HeapObject::kMapOffset),
+        isolate()->factory()->with_context_map());
+    Check(not_equal, "Variable resolved to catch context.");
   }
 }

=======================================
--- /branches/bleeding_edge/src/runtime.cc      Mon Jun 27 02:02:34 2011
+++ /branches/bleeding_edge/src/runtime.cc      Tue Jun 28 08:22:08 2011
@@ -1236,9 +1236,8 @@
   RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
   Handle<Object> initial_value(args[3], isolate);

-  // Declarations are always done in the function context.
-  context = Handle<Context>(context->fcontext());
-  ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
+  // Declarations are always done in a function or global context.
+  context = Handle<Context>(context->declaration_context());

   int index;
   PropertyAttributes attributes;
@@ -1525,8 +1524,8 @@
   CONVERT_ARG_CHECKED(Context, context, 1);
   Handle<String> name(String::cast(args[2]));

-  // Initializations are always done in the function context.
-  context = Handle<Context>(context->fcontext());
+  // Initializations are always done in a function or global context.
+  context = Handle<Context>(context->declaration_context());

   int index;
   PropertyAttributes attributes;
@@ -1547,14 +1546,12 @@
   // In that case, the initialization behaves like a normal assignment
   // to property 'x'.
   if (index >= 0) {
-    // Property was found in a context.
     if (holder->IsContext()) {
-      // The holder cannot be the function context.  If it is, there
-      // should have been a const redeclaration error when declaring
-      // the const property.
-      ASSERT(!holder.is_identical_to(context));
-      if ((attributes & READ_ONLY) == 0) {
-        Handle<Context>::cast(holder)->set(index, *value);
+      // Property was found in a context.  Perform the assignment if we
+      // found some non-constant or an uninitialized constant.
+      Handle<Context> context = Handle<Context>::cast(holder);
+ if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
+        context->set(index, *value);
       }
     } else {
       // The holder is an arguments object.
@@ -9986,9 +9983,6 @@
   Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
   ScopeInfo<> info(*scope_info);

-  // Get the nearest enclosing function context.
- Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
-
   // Get the locals names and values into a temporary array.
   //
   // TODO(1240907): Hide compiler-introduced stack variables
@@ -9996,11 +9990,6 @@
   // confusing.
   Handle<FixedArray> locals =
       isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
-
-  // Fill in the names of the locals.
-  for (int i = 0; i < info.NumberOfLocals(); i++) {
-    locals->set(i * 2, *info.LocalName(i));
-  }

   // Fill in the values of the locals.
   if (is_optimized_frame) {
@@ -10010,15 +9999,22 @@
     // TODO(1140): We should be able to get the correct values
     // for locals in optimized frames.
     for (int i = 0; i < info.NumberOfLocals(); i++) {
+      locals->set(i * 2, *info.LocalName(i));
       locals->set(i * 2 + 1, isolate->heap()->undefined_value());
     }
   } else {
-    for (int i = 0; i < info.number_of_stack_slots(); i++) {
-      // Get the value from the stack.
+    int i = 0;
+    for (; i < info.number_of_stack_slots(); ++i) {
+      // Use the value from the stack.
+      locals->set(i * 2, *info.LocalName(i));
       locals->set(i * 2 + 1, it.frame()->GetExpression(i));
     }
- for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
+    // Get the context containing declarations.
+    Handle<Context> context(
+        Context::cast(it.frame()->context())->declaration_context());
+    for (; i < info.NumberOfLocals(); ++i) {
       Handle<String> name = info.LocalName(i);
+      locals->set(i * 2, *name);
       locals->set(i * 2 + 1,
                   context->get(scope_info->ContextSlotIndex(*name, NULL)));
     }
@@ -10239,7 +10235,7 @@

   // Third fill all context locals.
   Handle<Context> frame_context(Context::cast(frame->context()));
-  Handle<Context> function_context(frame_context->fcontext());
+  Handle<Context> function_context(frame_context->declaration_context());
   if (!CopyContextLocalsToScopeObject(isolate,
                                       serialized_scope_info, scope_info,
                                       function_context, local_scope)) {
@@ -11121,7 +11117,7 @@
   context->set_extension(*local_scope);
// Copy any with contexts present and chain them in front of this context.
   Handle<Context> frame_context(Context::cast(frame->context()));
-  Handle<Context> function_context(frame_context->fcontext());
+  Handle<Context> function_context(frame_context->declaration_context());
   context = CopyWithContextChain(isolate, frame_context, context);

   if (additional_context->IsJSObject()) {
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Wed Jun 22 01:28:35 2011 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Tue Jun 28 08:22:08 2011
@@ -132,7 +132,6 @@
   // Setup the fixed slots.
   __ Set(rbx, 0);  // Set to NULL.
   __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx);
-  __ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax);
   __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi);
__ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx);

=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Jun 24 07:30:10 2011 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue Jun 28 08:22:08 2011
@@ -680,13 +680,16 @@
         // We bypass the general EmitSlotSearch because we know more about
         // this specific context.

-        // The variable in the decl always resides in the current context.
+        // The variable in the decl always resides in the current function
+        // context.
         ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
         if (FLAG_debug_code) {
-          // Check if we have the correct context pointer.
-          __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
-          __ cmpq(rbx, rsi);
-          __ Check(equal, "Unexpected declaration in current context.");
+          // Check that we're not inside a with or catch context.
+          __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
+          __ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
+          __ Check(not_equal, "Declaration in with context.");
+          __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
+          __ Check(not_equal, "Declaration in catch context.");
         }
         if (mode == Variable::CONST) {
           __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
@@ -1778,17 +1781,7 @@
         __ j(not_equal, &skip);
         __ movq(Operand(rbp, SlotOffset(slot)), rax);
         break;
-      case Slot::CONTEXT: {
-        __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
-        __ movq(rdx, ContextOperand(rcx, slot->index()));
-        __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
-        __ j(not_equal, &skip);
-        __ movq(ContextOperand(rcx, slot->index()), rax);
-        int offset = Context::SlotOffset(slot->index());
-        __ movq(rdx, rax);  // Preserve the stored value in eax.
-        __ RecordWrite(rcx, offset, rdx, rbx);
-        break;
-      }
+      case Slot::CONTEXT:
       case Slot::LOOKUP:
         __ push(rax);
         __ push(rsi);
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Thu Jun 9 05:45:26 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jun 28 08:22:08 2011
@@ -3628,14 +3628,17 @@
     movq(dst, rsi);
   }

-  // We should not have found a 'with' context by walking the context chain
-  // (i.e., the static scope chain and runtime context chain do not agree).
-  // A variable occurring in such a scope should have slot type LOOKUP and
-  // not CONTEXT.
+ // We should not have found a with or catch context by walking the context
+  // chain (i.e., the static scope chain and runtime context chain do not
+  // agree).  A variable occurring in such a scope should have slot type
+  // LOOKUP and not CONTEXT.
   if (emit_debug_code()) {
-    cmpq(dst, Operand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX)));
-    Check(equal, "Yo dawg, I heard you liked function contexts "
-                 "so I put function contexts in all your contexts");
+    CompareRoot(FieldOperand(dst, HeapObject::kMapOffset),
+                Heap::kWithContextMapRootIndex);
+    Check(not_equal, "Variable resolved to with context.");
+    CompareRoot(FieldOperand(dst, HeapObject::kMapOffset),
+                Heap::kCatchContextMapRootIndex);
+    Check(not_equal, "Variable resolved to catch context.");
   }
 }

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

Reply via email to