Push bleeding_edge revisions 2004 and 2006 to trunk.

r2004 fixes compilation on newer gcc versions.

r2006 exposes the calling JavaScript context through the API.

Review URL: http://codereview.chromium.org/112047

git-svn-id: http://v8.googlecode.com/svn/trunk@2012 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/include/v8.h b/include/v8.h
index 9f59e4e..1f72572 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -2246,6 +2246,13 @@
   static Local<Context> GetCurrent();
 
   /**
+   * Returns the context of the calling JavaScript code.  That is the
+   * context of the top-most JavaScript frame.  If there are no
+   * JavaScript frames an empty handle is returned.
+   */
+  static Local<Context> GetCalling();
+
+  /**
    * Sets the security token for the context.  To access an object in
    * another context, the security tokens must match.
    */
diff --git a/src/api.cc b/src/api.cc
index 943b5e1..c16920b 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2612,6 +2612,13 @@
 }
 
 
+v8::Local<v8::Context> Context::GetCalling() {
+  if (IsDeadCheck("v8::Context::GetCalling()")) return Local<Context>();
+  i::Handle<i::Context> context(i::Top::GetCallingGlobalContext());
+  return Utils::ToLocal(context);
+}
+
+
 v8::Local<v8::Object> Context::Global() {
   if (IsDeadCheck("v8::Context::Global()")) return Local<v8::Object>();
   i::Object** ctx = reinterpret_cast<i::Object**>(this);
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index 1105945..f9658e8 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -54,14 +54,15 @@
 }
 
 
-static Handle<CompilationCacheTable> GetTable(CompilationCache::Entry entry) {
+static Handle<CompilationCacheTable> GetTable(int index) {
+  ASSERT(index >= 0 && index < NUMBER_OF_TABLE_ENTRIES);
   Handle<CompilationCacheTable> result;
-  if (tables[entry]->IsUndefined()) {
+  if (tables[index]->IsUndefined()) {
     static const int kInitialCacheSize = 64;
     result = AllocateTable(kInitialCacheSize);
-    tables[entry] = *result;
+    tables[index] = *result;
   } else {
-    CompilationCacheTable* table = CompilationCacheTable::cast(tables[entry]);
+    CompilationCacheTable* table = CompilationCacheTable::cast(tables[index]);
     result = Handle<CompilationCacheTable>(table);
   }
   return result;
@@ -137,8 +138,11 @@
                                                   Handle<Object> name,
                                                   int line_offset,
                                                   int column_offset) {
+  // Use an int for the generation index, so value range propagation
+  // in gcc 4.3+ won't assume it can only go up to LAST_ENTRY when in
+  // fact it can go up to SCRIPT + NUMBER_OF_SCRIPT_GENERATIONS.
+  int generation = SCRIPT;
   Object* result = NULL;
-  Entry generation = SCRIPT;  // First generation.
 
   // Probe the script generation tables. Make sure not to leak handles
   // into the caller's handle scope.
@@ -156,7 +160,7 @@
         }
       }
       // Go to the next generation.
-      generation = static_cast<Entry>(generation + 1);
+      generation++;
     }
   }
 
diff --git a/src/top.cc b/src/top.cc
index 96f98a5..b5a0b94 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -881,6 +881,15 @@
 }
 
 
+Handle<Context> Top::GetCallingGlobalContext() {
+  JavaScriptFrameIterator it;
+  if (it.done()) return Handle<Context>::null();
+  JavaScriptFrame* frame = it.frame();
+  Context* context = Context::cast(frame->context());
+  return Handle<Context>(context->global_context());
+}
+
+
 Object* Top::LookupSpecialFunction(JSObject* receiver,
                                    JSObject* prototype,
                                    JSFunction* function) {
diff --git a/src/top.h b/src/top.h
index 1e5ec5a..e0cfdc3 100644
--- a/src/top.h
+++ b/src/top.h
@@ -255,8 +255,13 @@
     return context()->global_proxy();
   }
 
+  // Returns the current global context.
   static Handle<Context> global_context();
 
+  // Returns the global context of the calling JavaScript code.  That
+  // is, the global context of the top-most JavaScript frame.
+  static Handle<Context> GetCallingGlobalContext();
+
   static Handle<JSBuiltinsObject> builtins() {
     return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
   }
diff --git a/src/version.cc b/src/version.cc
index bce5d6b..4d8871b 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     1
 #define MINOR_VERSION     2
 #define BUILD_NUMBER      4
-#define PATCH_LEVEL       1
+#define PATCH_LEVEL       2
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 59e3e50..926823b 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -6608,3 +6608,67 @@
   CHECK_EQ(1, force_set_set_count);
   CHECK_EQ(6, force_set_get_count);
 }
+
+
+v8::Persistent<Context> calling_context0;
+v8::Persistent<Context> calling_context1;
+v8::Persistent<Context> calling_context2;
+
+
+// Check that the call to the callback is initiated in
+// calling_context2, the directly calling context is calling_context1
+// and the callback itself is in calling_context0.
+static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
+  ApiTestFuzzer::Fuzz();
+  CHECK(Context::GetCurrent() == calling_context0);
+  CHECK(Context::GetCalling() == calling_context1);
+  CHECK(Context::GetEntered() == calling_context2);
+  return v8::Integer::New(42);
+}
+
+
+THREADED_TEST(GetCallingContext) {
+  v8::HandleScope scope;
+
+  calling_context0 = Context::New();
+  calling_context1 = Context::New();
+  calling_context2 = Context::New();
+
+  // Allow cross-domain access.
+  Local<String> token = v8_str("<security token>");
+  calling_context0->SetSecurityToken(token);
+  calling_context1->SetSecurityToken(token);
+  calling_context2->SetSecurityToken(token);
+
+  // Create an object with a C++ callback in context0.
+  calling_context0->Enter();
+  Local<v8::FunctionTemplate> callback_templ =
+      v8::FunctionTemplate::New(GetCallingContextCallback);
+  calling_context0->Global()->Set(v8_str("callback"),
+                                  callback_templ->GetFunction());
+  calling_context0->Exit();
+
+  // Expose context0 in context1 and setup a function that calls the
+  // callback function.
+  calling_context1->Enter();
+  calling_context1->Global()->Set(v8_str("context0"),
+                                  calling_context0->Global());
+  CompileRun("function f() { context0.callback() }");
+  calling_context1->Exit();
+
+  // Expose context1 in context2 and call the callback function in
+  // context0 indirectly through f in context1.
+  calling_context2->Enter();
+  calling_context2->Global()->Set(v8_str("context1"),
+                                  calling_context1->Global());
+  CompileRun("context1.f()");
+  calling_context2->Exit();
+
+  // Dispose the contexts to allow them to be garbage collected.
+  calling_context0.Dispose();
+  calling_context1.Dispose();
+  calling_context2.Dispose();
+  calling_context0.Clear();
+  calling_context1.Clear();
+  calling_context2.Clear();
+}