From 646eff01948e8a100bd9f86f7df2a80183c4ac23 Mon Sep 17 00:00:00 2001
From: Igor Sheludko <ishell@chromium.org>
Date: Wed, 5 Jul 2017 20:29:13 +0200
Subject: [PATCH] deps: cherry-pick 6cb999b97b from V8 upstream
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Original commit message:

    Properly handle loads from global interceptor via prototype chain.

    ... when receiver is in dictionary mode.

    Bug: v8:6490
    Change-Id: Ic5a8d214adcc4efd4cb163cbc6b351c4e6b596af
    Reviewed-on: https://chromium-review.googlesource.com/559548
    Reviewed-by: Camillo Bruni <cbruni@chromium.org>
    Commit-Queue: Igor Sheludko <ishell@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#46428}

Ref: https://chromium.googlesource.com/v8/v8.git/+/6cb999b97b7953ebfd4aabf2e1f62bf405f21c69
Fixes: https://github.com/nodejs/node/issues/13804
PR-URL: https://github.com/nodejs/node/pull/14188
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
---
 deps/v8/include/v8-version.h                 |  2 +-
 deps/v8/src/ic/handler-configuration-inl.h   |  5 +++
 deps/v8/src/ic/handler-configuration.h       |  3 ++
 deps/v8/src/ic/ic.cc                         | 21 +++++++++---
 deps/v8/test/cctest/test-api-interceptors.cc | 35 ++++++++++++++++++++
 5 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h
index 0d920efac46d52..f1b394a8c4a1ab 100644
--- a/deps/v8/include/v8-version.h
+++ b/deps/v8/include/v8-version.h
@@ -11,7 +11,7 @@
 #define V8_MAJOR_VERSION 5
 #define V8_MINOR_VERSION 9
 #define V8_BUILD_NUMBER 211
-#define V8_PATCH_LEVEL 37
+#define V8_PATCH_LEVEL 38
 
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h
index 2b9dc04b5a9395..5f31d15d46fcc3 100644
--- a/deps/v8/src/ic/handler-configuration-inl.h
+++ b/deps/v8/src/ic/handler-configuration-inl.h
@@ -13,6 +13,11 @@
 namespace v8 {
 namespace internal {
 
+// Decodes kind from Smi-handler.
+LoadHandler::Kind LoadHandler::GetHandlerKind(Smi* smi_handler) {
+  return KindBits::decode(smi_handler->value());
+}
+
 Handle<Smi> LoadHandler::LoadNormal(Isolate* isolate) {
   int config = KindBits::encode(kNormal);
   return handle(Smi::FromInt(config), isolate);
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
index ab117d5c9bd5cb..eed548b4d5edeb 100644
--- a/deps/v8/src/ic/handler-configuration.h
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -90,6 +90,9 @@ class LoadHandler {
   static const int kHolderCellIndex = 2;
   static const int kFirstPrototypeIndex = 3;
 
+  // Decodes kind from Smi-handler.
+  static inline Kind GetHandlerKind(Smi* smi_handler);
+
   // Creates a Smi-handler for loading a property from a slow object.
   static inline Handle<Smi> LoadNormal(Isolate* isolate);
 
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index b3b0eb4c849e52..ca3f70df2ab41d 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -868,10 +868,15 @@ int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
                                     Handle<FixedArray>(), 0);
 }
 
+enum class HolderCellRequest {
+  kGlobalPropertyCell,
+  kHolder,
+};
+
 Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder,
-                            Handle<Name> name, Handle<Smi> smi_handler) {
-  if (holder->IsJSGlobalObject() &&
-      *smi_handler != *LoadHandler::LoadInterceptor(isolate)) {
+                            Handle<Name> name, HolderCellRequest request) {
+  if (request == HolderCellRequest::kGlobalPropertyCell) {
+    DCHECK(holder->IsJSGlobalObject());
     Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
     GlobalDictionary* dict = global->global_dictionary();
     int number = dict->FindEntry(name);
@@ -908,8 +913,14 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
   DCHECK(!validity_cell.is_null());
 
-  Handle<WeakCell> holder_cell =
-      HolderCell(isolate(), holder, name, smi_handler);
+  // LoadIC dispatcher expects PropertyCell as a "holder" in case of kGlobal
+  // handler kind.
+  HolderCellRequest request =
+      LoadHandler::GetHandlerKind(*smi_handler) == LoadHandler::kGlobal
+          ? HolderCellRequest::kGlobalPropertyCell
+          : HolderCellRequest::kHolder;
+
+  Handle<WeakCell> holder_cell = HolderCell(isolate(), holder, name, request);
 
   if (checks_count == 0) {
     return isolate()->factory()->NewTuple3(holder_cell, smi_handler,
diff --git a/deps/v8/test/cctest/test-api-interceptors.cc b/deps/v8/test/cctest/test-api-interceptors.cc
index 9680b4241b8521..9e739687b4c3c5 100644
--- a/deps/v8/test/cctest/test-api-interceptors.cc
+++ b/deps/v8/test/cctest/test-api-interceptors.cc
@@ -1383,6 +1383,41 @@ THREADED_TEST(InterceptorLoadGlobalICGlobalWithInterceptor) {
   CHECK(value->BooleanValue(context.local()).FromJust());
 }
 
+// Test load of a non-existing global through prototype chain when a global
+// object has an interceptor.
+THREADED_TEST(InterceptorLoadICGlobalWithInterceptor) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New(isolate);
+  templ_global->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      GenericInterceptorGetter, GenericInterceptorSetter));
+
+  LocalContext context(nullptr, templ_global);
+  i::Handle<i::JSReceiver> global_proxy =
+      v8::Utils::OpenHandle<Object, i::JSReceiver>(context->Global());
+  CHECK(global_proxy->IsJSGlobalProxy());
+  i::Handle<i::JSGlobalObject> global(
+      i::JSGlobalObject::cast(global_proxy->map()->prototype()));
+  CHECK(global->map()->has_named_interceptor());
+
+  ExpectInt32(
+      "(function() {"
+      "  var f = function(obj) { "
+      "    return obj.foo;"
+      "  };"
+      "  var obj = { __proto__: this, _str_foo: 42 };"
+      "  for (var i = 0; i < 1500; i++) obj['p' + i] = 0;"
+      "  /* Ensure that |obj| is in dictionary mode. */"
+      "  if (%HasFastProperties(obj)) return -1;"
+      "  for (var i = 0; i < 3; i++) {"
+      "    f(obj);"
+      "  };"
+      "  return f(obj);"
+      "})();",
+      42);
+}
+
 static void InterceptorLoadICGetter0(
     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();