Make sure to use the correct context for eval checks

We can't assume that there's no entered context during microtask
execution. We also can't assume that we'll never enter an context during
microtask execution either.

We can however assume that we don't execute microtasks recursively, so
remembering the length of the entered context stack is enough to decide
which context to use.

BUG=chromium:635769
R=verwaest@chromium.org

Review-Url: https://codereview.chromium.org/2350933007
Cr-Commit-Position: refs/heads/master@{#39627}
diff --git a/src/api.h b/src/api.h
index c5007a7..22c10dd 100644
--- a/src/api.h
+++ b/src/api.h
@@ -395,6 +395,7 @@
         call_depth_(0),
         microtasks_depth_(0),
         microtasks_suppressions_(0),
+        entered_context_count_during_microtasks_(0),
 #ifdef DEBUG
         debug_microtasks_depth_(0),
 #endif
@@ -460,6 +461,11 @@
   inline void EnterMicrotaskContext(Handle<Context> context);
   inline void LeaveMicrotaskContext();
   inline Handle<Context> MicrotaskContext();
+  inline bool MicrotaskContextIsLastEnteredContext() const {
+    return microtask_context_ &&
+           entered_context_count_during_microtasks_ ==
+               entered_contexts_.length();
+  }
 
   inline void SaveContext(Context* context);
   inline Context* RestoreContext();
@@ -480,6 +486,7 @@
     entered_contexts_.Initialize(0);
     saved_contexts_.Initialize(0);
     microtask_context_ = nullptr;
+    entered_context_count_during_microtasks_ = 0;
     spare_ = NULL;
     last_handle_before_deferred_block_ = NULL;
     call_depth_ = 0;
@@ -514,6 +521,7 @@
   int call_depth_;
   int microtasks_depth_;
   int microtasks_suppressions_;
+  int entered_context_count_during_microtasks_;
 #ifdef DEBUG
   int debug_microtasks_depth_;
 #endif
@@ -585,11 +593,13 @@
 void HandleScopeImplementer::EnterMicrotaskContext(Handle<Context> context) {
   DCHECK(!microtask_context_);
   microtask_context_ = *context;
+  entered_context_count_during_microtasks_ = entered_contexts_.length();
 }
 
 void HandleScopeImplementer::LeaveMicrotaskContext() {
   DCHECK(microtask_context_);
   microtask_context_ = nullptr;
+  entered_context_count_during_microtasks_ = 0;
 }
 
 Handle<Context> HandleScopeImplementer::MicrotaskContext() {
diff --git a/src/builtins/builtins.cc b/src/builtins/builtins.cc
index dd5b433..d5a0e17 100644
--- a/src/builtins/builtins.cc
+++ b/src/builtins/builtins.cc
@@ -280,13 +280,12 @@
                                     Handle<JSObject> target_global_proxy) {
   if (FLAG_allow_unsafe_function_constructor) return true;
   HandleScopeImplementer* impl = isolate->handle_scope_implementer();
-  Handle<Context> responsible_context = impl->LastEnteredContext();
+  Handle<Context> responsible_context =
+      impl->MicrotaskContextIsLastEnteredContext() ? impl->MicrotaskContext()
+                                                   : impl->LastEnteredContext();
+  // TODO(jochen): Remove this.
   if (responsible_context.is_null()) {
-    responsible_context = impl->MicrotaskContext();
-    // TODO(jochen): Remove this.
-    if (responsible_context.is_null()) {
-      return true;
-    }
+    return true;
   }
   if (*responsible_context == target->context()) return true;
   return isolate->MayAccess(responsible_context, target_global_proxy);