@@ -201,7 +201,7 @@ v8::Intercepted GenericInterceptorGetter(
201201 Local<String> name = generic_name.As <String>();
202202 String::Utf8Value utf8 (isolate, name);
203203 char * name_str = *utf8;
204- if (*name_str == ' _ ' ) return v8::Intercepted::kNo ;
204+ if (*name_str != ' $ ' ) return v8::Intercepted::kNo ;
205205 str = String::Concat (isolate, v8_str (" _str_" ), name);
206206 }
207207
@@ -211,6 +211,35 @@ v8::Intercepted GenericInterceptorGetter(
211211 return v8::Intercepted::kYes ;
212212}
213213
214+ v8::Intercepted GenericInterceptorQuery (
215+ Local<Name> generic_name,
216+ const v8::PropertyCallbackInfo<v8::Integer>& info) {
217+ v8::Isolate* isolate = info.GetIsolate ();
218+ Local<String> str;
219+ if (generic_name->IsSymbol ()) {
220+ Local<Value> name = generic_name.As <Symbol>()->Description (isolate);
221+ if (name->IsUndefined ()) return v8::Intercepted::kNo ;
222+ str = String::Concat (isolate, v8_str (" _sym_" ), name.As <String>());
223+ } else {
224+ Local<String> name = generic_name.As <String>();
225+ String::Utf8Value utf8 (isolate, name);
226+ char * name_str = *utf8;
227+ if (*name_str != ' $' ) return v8::Intercepted::kNo ;
228+ str = String::Concat (isolate, v8_str (" _str_" ), name);
229+ }
230+
231+ Local<Object> self = info.HolderV2 ();
232+ v8::PropertyAttribute attributes;
233+ bool exists;
234+ if (self->GetPropertyAttributes (isolate->GetCurrentContext (), str,
235+ &attributes)
236+ .To (&exists)) {
237+ if (!exists) return v8::Intercepted::kNo ;
238+ info.GetReturnValue ().Set (attributes);
239+ }
240+ return v8::Intercepted::kYes ;
241+ }
242+
214243v8::Intercepted GenericInterceptorSetter (
215244 Local<Name> generic_name, Local<Value> value,
216245 const v8::PropertyCallbackInfo<Boolean>& info) {
@@ -224,7 +253,7 @@ v8::Intercepted GenericInterceptorSetter(
224253 Local<String> name = generic_name.As <String>();
225254 String::Utf8Value utf8 (info.GetIsolate (), name);
226255 char * name_str = *utf8;
227- if (*name_str == ' _ ' ) return v8::Intercepted::kNo ;
256+ if (*name_str != ' $ ' ) return v8::Intercepted::kNo ;
228257 str = String::Concat (info.GetIsolate (), v8_str (" _str_" ), name);
229258 }
230259
@@ -1639,9 +1668,9 @@ void InterceptorLoadICGlobalWithInterceptor(bool masking) {
16391668 ExpectInt32 (
16401669 " (function() {"
16411670 " var f = function(obj) { "
1642- " return obj.foo;"
1671+ " return obj.$ foo;"
16431672 " };"
1644- " this._str_foo = 42;"
1673+ " this._str_$foo = 42;"
16451674 " var obj = { __proto__: this };"
16461675 " for (var i = 0; i < 1500; i++) obj['p' + i] = 0;"
16471676 " /* Ensure that |obj| is in dictionary mode. */"
@@ -2068,6 +2097,138 @@ THREADED_TEST(EmptyInterceptorVsStoreGlobalICs) {
20682097 120 );
20692098}
20702099
2100+ namespace {
2101+
2102+ void CheckGlobalInterceptorIC (v8::NamedPropertyGetterCallback getter,
2103+ v8::NamedPropertySetterCallback setter,
2104+ v8::NamedPropertyQueryCallback query,
2105+ v8::PropertyHandlerFlags flags,
2106+ const char * source, std::optional<int > expected) {
2107+ v8::Isolate* isolate = CcTest::isolate ();
2108+ v8::HandleScope scope (isolate);
2109+ v8::Local<v8::ObjectTemplate> templ_global = v8::ObjectTemplate::New (isolate);
2110+ v8::NamedPropertyHandlerConfiguration config (
2111+ getter, setter, query, nullptr /* deleter */ , nullptr /* enumerator */ ,
2112+ nullptr /* definer */ , nullptr /* descriptor */ , {}, flags);
2113+ templ_global->SetHandler (config);
2114+
2115+ LocalContext context (nullptr , templ_global);
2116+ i::DirectHandle<i::JSReceiver> global_proxy =
2117+ v8::Utils::OpenDirectHandle<Object, i::JSReceiver>(context->Global ());
2118+ CHECK (IsJSGlobalProxy (*global_proxy));
2119+ i::DirectHandle<i::JSGlobalObject> global (
2120+ i::Cast<i::JSGlobalObject>(global_proxy->map ()->prototype ()),
2121+ CcTest::i_isolate ());
2122+ CHECK (global->map ()->has_named_interceptor ());
2123+
2124+ v8::Local<Value> value = CompileRun (source);
2125+ if (expected) {
2126+ CHECK_EQ (*expected, value->Int32Value (context.local ()).FromJust ());
2127+ } else {
2128+ CHECK (value.IsEmpty ());
2129+ }
2130+ }
2131+
2132+ void StoreGlobalICWithGlobalInterceptor (bool masking) {
2133+ v8::PropertyHandlerFlags flags = v8::PropertyHandlerFlags::kNone ;
2134+ if (!masking) {
2135+ flags = v8::PropertyHandlerFlags::kNonMasking ;
2136+ }
2137+
2138+ // In sloppy mode storing to global must succeed.
2139+ CheckGlobalInterceptorIC ( //
2140+ GenericInterceptorGetter, //
2141+ GenericInterceptorSetter, //
2142+ GenericInterceptorQuery, //
2143+ flags, //
2144+ R"(
2145+ // Make interceptor behave like it has a read-only property "$y".
2146+ Object.defineProperty(globalThis, '_str_$y',
2147+ {value: 153, writable: false});
2148+
2149+ let result = 0;
2150+
2151+ result += (typeof($x) === 'undefined' ? 0 : 10000);
2152+ result += ($y === 153 ? 0 : 10000);
2153+
2154+ for (var i = 0; i < 20; i++) {
2155+ try {
2156+ $x = i; // not intercepted, absent variable
2157+ result++;
2158+ } catch (e) {
2159+ }
2160+ }
2161+ for (var i = 0; i < 20; i++) {
2162+ try {
2163+ $y = i; // intercepted, read only property
2164+ result++;
2165+ } catch (e) {
2166+ }
2167+ }
2168+
2169+ // Check contextual stores succeeded.
2170+ result += ($x === 19 ? 0 : 100);
2171+ result += ($y === 153 ? 0 : 1000);
2172+
2173+ result
2174+ )" ,
2175+ 40 );
2176+
2177+ // In strict mode storing to global must throw.
2178+ CheckGlobalInterceptorIC ( //
2179+ GenericInterceptorGetter, //
2180+ GenericInterceptorSetter, //
2181+ GenericInterceptorQuery, //
2182+ flags,
2183+ R"(
2184+ 'use strict';
2185+
2186+ // Make interceptor behave like it has a read-only property "$y".
2187+ Object.defineProperty(globalThis, '_str_$y',
2188+ {value: 153, writable: false});
2189+
2190+ let result = 0;
2191+
2192+ result += (typeof($x) === 'undefined' ? 0 : 10000);
2193+ result += ($y === 153 ? 0 : 10000);
2194+
2195+ for (var i = 0; i < 20; i++) {
2196+ try {
2197+ $x = i; // not intercepted, absent variable
2198+ } catch (e) {
2199+ result++;
2200+ }
2201+ }
2202+ for (var i = 0; i < 20; i++) {
2203+ try {
2204+ $y = i; // intercepted, read only property
2205+ } catch (e) {
2206+ result++;
2207+ }
2208+ }
2209+
2210+ // Check contextual stores did not happen.
2211+ result += (typeof($x) === 'undefined' ? 0 : 100);
2212+ result += ($y === 153 ? 0 : 1000);
2213+
2214+ result
2215+ )" ,
2216+ 40 );
2217+ }
2218+
2219+ } // namespace
2220+
2221+ // Checks correctness of global objects with interceptor vs contextual stores.
2222+ THREADED_TEST (StoreGlobalICWithGlobalNonMaskingInterceptor) {
2223+ const bool masking = false ;
2224+ StoreGlobalICWithGlobalInterceptor (masking);
2225+ }
2226+
2227+ THREADED_TEST (StoreGlobalICWithGlobalMaskingInterceptor) {
2228+ const bool masking = true ;
2229+ StoreGlobalICWithGlobalInterceptor (masking);
2230+ }
2231+
20712232THREADED_TEST (LegacyInterceptorDoesNotSeeSymbols) {
20722233 LocalContext env;
20732234 v8::Isolate* isolate = CcTest::isolate ();
@@ -2120,9 +2281,9 @@ THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
21202281 ExpectInt32 (" child._sym_age" , 10 );
21212282
21222283 // Check that it also sees strings.
2123- CompileRun (" child.foo = 47" );
2124- ExpectInt32 (" child.foo" , 47 );
2125- ExpectInt32 (" child._str_foo " , 47 );
2284+ CompileRun (" child.$ foo = 47" );
2285+ ExpectInt32 (" child.$ foo" , 47 );
2286+ ExpectInt32 (" child._str_$foo " , 47 );
21262287
21272288 // Check that the interceptor can punt (in this case, on anonymous symbols).
21282289 CompileRun (" child[anon] = 31337" );
0 commit comments