Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "test/cctest/cctest.h"
6 :
7 : #include "include/v8.h"
8 : #include "src/api.h"
9 : #include "src/objects-inl.h"
10 :
11 : namespace i = v8::internal;
12 :
13 : // The goal is to avoid the callback.
14 0 : static void UnreachableCallback(
15 : const v8::FunctionCallbackInfo<v8::Value>& info) {
16 0 : UNREACHABLE();
17 : }
18 :
19 26644 : TEST(CachedAccessor) {
20 : // TurboFan support for fast accessors is not implemented; turbofanned
21 : // code uses the slow accessor which breaks this test's expectations.
22 5 : v8::internal::FLAG_always_opt = false;
23 5 : LocalContext env;
24 5 : v8::Isolate* isolate = env->GetIsolate();
25 10 : v8::HandleScope scope(isolate);
26 :
27 : // Create 'foo' class, with a hidden property.
28 5 : v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate);
29 :
30 : v8::Local<v8::Private> priv =
31 5 : v8::Private::ForApi(isolate, v8_str("Foo#draft"));
32 :
33 10 : foo->SetAccessorProperty(v8_str("draft"), v8::FunctionTemplate::NewWithCache(
34 : isolate, UnreachableCallback,
35 5 : priv, v8::Local<v8::Value>()));
36 :
37 : // Create 'obj', instance of 'foo'.
38 5 : v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked();
39 :
40 : // Install the private property on the instance.
41 10 : CHECK(obj->SetPrivate(isolate->GetCurrentContext(), priv,
42 : v8::Undefined(isolate))
43 : .FromJust());
44 :
45 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
46 :
47 : // Access cached accessor.
48 5 : ExpectUndefined("obj.draft");
49 :
50 : // Set hidden property.
51 15 : CHECK(obj->SetPrivate(isolate->GetCurrentContext(), priv,
52 : v8_str("Shhh, I'm private!"))
53 : .FromJust());
54 :
55 5 : ExpectString("obj.draft", "Shhh, I'm private!");
56 :
57 : // Stress the accessor to use the IC.
58 : ExpectString(
59 : "var result = '';"
60 : "for (var i = 0; i < 10; ++i) { "
61 : " result = obj.draft; "
62 : "} "
63 : "result; ",
64 5 : "Shhh, I'm private!");
65 5 : }
66 :
67 26644 : TEST(CachedAccessorTurboFan) {
68 5 : i::FLAG_allow_natives_syntax = true;
69 : // v8::internal::FLAG_always_opt = false;
70 5 : LocalContext env;
71 5 : v8::Isolate* isolate = env->GetIsolate();
72 10 : v8::HandleScope scope(isolate);
73 :
74 : // Create 'foo' class, with a hidden property.
75 5 : v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate);
76 : v8::Local<v8::Private> priv =
77 5 : v8::Private::ForApi(isolate, v8_str("Foo#draft"));
78 :
79 : // Install the private property on the template.
80 : // foo->SetPrivate(priv, v8::Undefined(isolate));
81 :
82 10 : foo->SetAccessorProperty(v8_str("draft"), v8::FunctionTemplate::NewWithCache(
83 : isolate, UnreachableCallback,
84 5 : priv, v8::Local<v8::Value>()));
85 :
86 : // Create 'obj', instance of 'foo'.
87 5 : v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked();
88 :
89 : // Install the private property on the instance.
90 10 : CHECK(obj->SetPrivate(isolate->GetCurrentContext(), priv,
91 : v8::Undefined(isolate))
92 : .FromJust());
93 :
94 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
95 :
96 : // Access surrogate accessor.
97 5 : ExpectUndefined("obj.draft");
98 :
99 : // Set hidden property.
100 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 123))
101 : .FromJust());
102 :
103 : // Test ICs.
104 : CompileRun(
105 : "function f() {"
106 : " var x;"
107 : " for (var i = 0; i < 100; i++) {"
108 : " x = obj.draft;"
109 : " }"
110 : " return x;"
111 : "}");
112 :
113 5 : ExpectInt32("f()", 123);
114 :
115 : // Reset hidden property.
116 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 456))
117 : .FromJust());
118 :
119 : // Test TurboFan.
120 : CompileRun("%OptimizeFunctionOnNextCall(f);");
121 :
122 5 : ExpectInt32("f()", 456);
123 :
124 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 456))
125 : .FromJust());
126 : // Test non-global ICs.
127 : CompileRun(
128 : "function g() {"
129 : " var x = obj;"
130 : " var r = 0;"
131 : " for (var i = 0; i < 100; i++) {"
132 : " r = x.draft;"
133 : " }"
134 : " return r;"
135 : "}");
136 :
137 5 : ExpectInt32("g()", 456);
138 :
139 : // Reset hidden property.
140 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 789))
141 : .FromJust());
142 :
143 : // Test non-global access in TurboFan.
144 : CompileRun("%OptimizeFunctionOnNextCall(g);");
145 :
146 5 : ExpectInt32("g()", 789);
147 5 : }
148 :
149 26644 : TEST(CachedAccessorOnGlobalObject) {
150 5 : i::FLAG_allow_natives_syntax = true;
151 5 : LocalContext env;
152 5 : v8::Isolate* isolate = env->GetIsolate();
153 10 : v8::HandleScope scope(isolate);
154 :
155 : v8::Local<v8::FunctionTemplate> templ =
156 5 : v8::FunctionTemplate::New(CcTest::isolate());
157 5 : v8::Local<v8::ObjectTemplate> object_template = templ->InstanceTemplate();
158 : v8::Local<v8::Private> priv =
159 5 : v8::Private::ForApi(isolate, v8_str("Foo#draft"));
160 :
161 10 : object_template->SetAccessorProperty(
162 : v8_str("draft"),
163 : v8::FunctionTemplate::NewWithCache(isolate, UnreachableCallback, priv,
164 5 : v8::Local<v8::Value>()));
165 :
166 : v8::Local<v8::Context> ctx =
167 5 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
168 5 : v8::Local<v8::Object> obj = ctx->Global();
169 :
170 : // Install the private property on the instance.
171 10 : CHECK(obj->SetPrivate(isolate->GetCurrentContext(), priv,
172 : v8::Undefined(isolate))
173 : .FromJust());
174 :
175 : {
176 : v8::Context::Scope context_scope(ctx);
177 :
178 : // Access surrogate accessor.
179 5 : ExpectUndefined("draft");
180 :
181 : // Set hidden property.
182 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 123))
183 : .FromJust());
184 :
185 : // Test ICs.
186 : CompileRun(
187 : "function f() {"
188 : " var x;"
189 : " for (var i = 0; i < 100; i++) {"
190 : " x = draft;"
191 : " }"
192 : " return x;"
193 : "}");
194 :
195 5 : ExpectInt32("f()", 123);
196 :
197 : // Reset hidden property.
198 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 456))
199 : .FromJust());
200 :
201 : // Test TurboFan.
202 : CompileRun("%OptimizeFunctionOnNextCall(f);");
203 :
204 5 : ExpectInt32("f()", 456);
205 :
206 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 456))
207 : .FromJust());
208 : // Test non-global ICs.
209 : CompileRun(
210 : "var x = this;"
211 : "function g() {"
212 : " var r = 0;"
213 : " for (var i = 0; i < 100; i++) {"
214 : " r = x.draft;"
215 : " }"
216 : " return r;"
217 : "}");
218 :
219 5 : ExpectInt32("g()", 456);
220 :
221 : // Reset hidden property.
222 15 : CHECK(obj->SetPrivate(env.local(), priv, v8::Integer::New(isolate, 789))
223 : .FromJust());
224 :
225 : // Test non-global access in TurboFan.
226 : CompileRun("%OptimizeFunctionOnNextCall(g);");
227 :
228 5 : ExpectInt32("g()", 789);
229 : }
230 5 : }
231 :
232 : namespace {
233 :
234 : // Getter return value should be non-null to trigger lazy property paths.
235 50 : static void Getter(v8::Local<v8::Name> name,
236 : const v8::PropertyCallbackInfo<v8::Value>& info) {
237 50 : info.GetReturnValue().Set(v8_str("return value"));
238 50 : }
239 :
240 10 : static void StringGetter(v8::Local<v8::String> name,
241 10 : const v8::PropertyCallbackInfo<v8::Value>& info) {}
242 :
243 : static int set_accessor_call_count = 0;
244 :
245 5 : static void Setter(v8::Local<v8::Name> name, v8::Local<v8::Value> value,
246 : const v8::PropertyCallbackInfo<void>& info) {
247 5 : set_accessor_call_count++;
248 5 : }
249 : } // namespace
250 :
251 : // Re-declaration of non-configurable accessors should throw.
252 26644 : TEST(RedeclareAccessor) {
253 10 : v8::HandleScope scope(CcTest::isolate());
254 5 : LocalContext env;
255 :
256 : v8::Local<v8::FunctionTemplate> templ =
257 5 : v8::FunctionTemplate::New(CcTest::isolate());
258 :
259 5 : v8::Local<v8::ObjectTemplate> object_template = templ->InstanceTemplate();
260 10 : object_template->SetAccessor(
261 : v8_str("foo"), nullptr, Setter, v8::Local<v8::Value>(),
262 5 : v8::AccessControl::DEFAULT, v8::PropertyAttribute::DontDelete);
263 :
264 : v8::Local<v8::Context> ctx =
265 5 : v8::Context::New(CcTest::isolate(), nullptr, object_template);
266 :
267 : // Declare function.
268 5 : v8::Local<v8::String> code = v8_str("function foo() {};");
269 :
270 10 : v8::TryCatch try_catch(CcTest::isolate());
271 10 : v8::Script::Compile(ctx, code).ToLocalChecked()->Run(ctx).IsEmpty();
272 5 : CHECK(try_catch.HasCaught());
273 5 : }
274 :
275 : // Accessors can be whitelisted as side-effect-free via SetAccessor.
276 26644 : TEST(AccessorSetHasNoSideEffect) {
277 5 : LocalContext env;
278 5 : v8::Isolate* isolate = env->GetIsolate();
279 10 : v8::HandleScope scope(isolate);
280 5 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
281 :
282 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
283 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
284 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
285 15 : obj->SetAccessor(context, v8_str("foo"), Getter).ToChecked();
286 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).IsEmpty());
287 :
288 10 : obj->SetAccessor(context, v8_str("foo"), Getter, nullptr,
289 : v8::MaybeLocal<v8::Value>(), v8::AccessControl::DEFAULT,
290 : v8::PropertyAttribute::None,
291 10 : v8::SideEffectType::kHasNoSideEffect)
292 : .ToChecked();
293 5 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).ToLocalChecked();
294 :
295 : // Check that setter is not whitelisted.
296 10 : v8::TryCatch try_catch(isolate);
297 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo = 1"), true)
298 : .IsEmpty());
299 5 : CHECK(try_catch.HasCaught());
300 15 : CHECK_NE(1, v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), false)
301 : .ToLocalChecked()
302 : ->Int32Value(env.local())
303 : .FromJust());
304 5 : CHECK_EQ(0, set_accessor_call_count);
305 5 : }
306 :
307 : // Set accessors can be whitelisted as side-effect-free via SetAccessor.
308 26644 : TEST(SetAccessorSetSideEffectReceiverCheck1) {
309 5 : LocalContext env;
310 5 : v8::Isolate* isolate = env->GetIsolate();
311 10 : v8::HandleScope scope(isolate);
312 :
313 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
314 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
315 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
316 10 : obj->SetAccessor(env.local(), v8_str("foo"), Getter, Setter,
317 : v8::MaybeLocal<v8::Value>(), v8::AccessControl::DEFAULT,
318 : v8::PropertyAttribute::None,
319 : v8::SideEffectType::kHasNoSideEffect,
320 10 : v8::SideEffectType::kHasSideEffectToReceiver)
321 : .ToChecked();
322 20 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true)
323 : .ToLocalChecked()
324 : ->Equals(env.local(), v8_str("return value"))
325 : .FromJust());
326 10 : v8::TryCatch try_catch(isolate);
327 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo = 1"), true)
328 : .IsEmpty());
329 5 : CHECK(try_catch.HasCaught());
330 5 : CHECK_EQ(0, set_accessor_call_count);
331 5 : }
332 :
333 10 : static void ConstructCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
334 10 : }
335 :
336 26644 : TEST(SetAccessorSetSideEffectReceiverCheck2) {
337 5 : LocalContext env;
338 5 : v8::Isolate* isolate = env->GetIsolate();
339 10 : v8::HandleScope scope(isolate);
340 5 : i::FLAG_enable_one_shot_optimization = false;
341 :
342 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(
343 : isolate, ConstructCallback, v8::Local<v8::Value>(),
344 : v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kAllow,
345 5 : v8::SideEffectType::kHasNoSideEffect);
346 15 : templ->InstanceTemplate()->SetAccessor(
347 : v8_str("bar"), Getter, Setter, v8::Local<v8::Value>(),
348 : v8::AccessControl::DEFAULT, v8::PropertyAttribute::None,
349 : v8::Local<v8::AccessorSignature>(),
350 : v8::SideEffectType::kHasSideEffectToReceiver,
351 5 : v8::SideEffectType::kHasSideEffectToReceiver);
352 25 : CHECK(env->Global()
353 : ->Set(env.local(), v8_str("f"),
354 : templ->GetFunction(env.local()).ToLocalChecked())
355 : .FromJust());
356 20 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("new f().bar"), true)
357 : .ToLocalChecked()
358 : ->Equals(env.local(), v8_str("return value"))
359 : .FromJust());
360 5 : v8::debug::EvaluateGlobal(isolate, v8_str("new f().bar = 1"), true)
361 : .ToLocalChecked();
362 5 : CHECK_EQ(1, set_accessor_call_count);
363 5 : }
364 :
365 : // Accessors can be whitelisted as side-effect-free via SetNativeDataProperty.
366 26644 : TEST(AccessorSetNativeDataPropertyHasNoSideEffect) {
367 5 : LocalContext env;
368 5 : v8::Isolate* isolate = env->GetIsolate();
369 10 : v8::HandleScope scope(isolate);
370 5 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
371 :
372 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
373 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
374 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
375 15 : obj->SetNativeDataProperty(context, v8_str("foo"), Getter).ToChecked();
376 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).IsEmpty());
377 :
378 10 : obj->SetNativeDataProperty(
379 : context, v8_str("foo"), Getter, nullptr, v8::Local<v8::Value>(),
380 10 : v8::PropertyAttribute::None, v8::SideEffectType::kHasNoSideEffect)
381 : .ToChecked();
382 5 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).ToLocalChecked();
383 :
384 : // Check that setter is not whitelisted.
385 10 : v8::TryCatch try_catch(isolate);
386 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo = 1"), true)
387 : .IsEmpty());
388 5 : CHECK(try_catch.HasCaught());
389 15 : CHECK_NE(1, v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), false)
390 : .ToLocalChecked()
391 : ->Int32Value(env.local())
392 : .FromJust());
393 5 : }
394 :
395 : // Accessors can be whitelisted as side-effect-free via SetLazyDataProperty.
396 26644 : TEST(AccessorSetLazyDataPropertyHasNoSideEffect) {
397 5 : LocalContext env;
398 5 : v8::Isolate* isolate = env->GetIsolate();
399 10 : v8::HandleScope scope(isolate);
400 5 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
401 :
402 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
403 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
404 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
405 15 : obj->SetLazyDataProperty(context, v8_str("foo"), Getter).ToChecked();
406 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).IsEmpty());
407 :
408 10 : obj->SetLazyDataProperty(context, v8_str("foo"), Getter,
409 : v8::Local<v8::Value>(), v8::PropertyAttribute::None,
410 10 : v8::SideEffectType::kHasNoSideEffect)
411 : .ToChecked();
412 5 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).ToLocalChecked();
413 :
414 : // Check that setter is not whitelisted.
415 10 : v8::TryCatch try_catch(isolate);
416 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo = 1"), true)
417 : .IsEmpty());
418 5 : CHECK(try_catch.HasCaught());
419 15 : CHECK_NE(1, v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), false)
420 : .ToLocalChecked()
421 : ->Int32Value(env.local())
422 : .FromJust());
423 5 : }
424 :
425 26644 : TEST(ObjectTemplateSetAccessorHasNoSideEffect) {
426 5 : LocalContext env;
427 5 : v8::Isolate* isolate = env->GetIsolate();
428 10 : v8::HandleScope scope(isolate);
429 :
430 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
431 5 : templ->SetAccessor(v8_str("foo"), StringGetter);
432 10 : templ->SetAccessor(
433 : v8_str("foo2"), StringGetter, nullptr, v8::Local<v8::Value>(),
434 : v8::AccessControl::DEFAULT, v8::PropertyAttribute::None,
435 5 : v8::Local<v8::AccessorSignature>(), v8::SideEffectType::kHasNoSideEffect);
436 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
437 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
438 :
439 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).IsEmpty());
440 5 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2"), true).ToLocalChecked();
441 :
442 : // Check that setter is not whitelisted.
443 10 : v8::TryCatch try_catch(isolate);
444 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2 = 1"), true)
445 : .IsEmpty());
446 5 : CHECK(try_catch.HasCaught());
447 15 : CHECK_NE(1, v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2"), false)
448 : .ToLocalChecked()
449 : ->Int32Value(env.local())
450 : .FromJust());
451 5 : }
452 :
453 26644 : TEST(ObjectTemplateSetNativePropertyHasNoSideEffect) {
454 5 : LocalContext env;
455 5 : v8::Isolate* isolate = env->GetIsolate();
456 10 : v8::HandleScope scope(isolate);
457 :
458 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
459 10 : templ->SetNativeDataProperty(v8_str("foo"), Getter);
460 10 : templ->SetNativeDataProperty(
461 : v8_str("foo2"), Getter, nullptr, v8::Local<v8::Value>(),
462 : v8::PropertyAttribute::None, v8::Local<v8::AccessorSignature>(),
463 5 : v8::AccessControl::DEFAULT, v8::SideEffectType::kHasNoSideEffect);
464 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
465 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
466 :
467 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).IsEmpty());
468 5 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2"), true).ToLocalChecked();
469 :
470 : // Check that setter is not whitelisted.
471 10 : v8::TryCatch try_catch(isolate);
472 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2 = 1"), true)
473 : .IsEmpty());
474 5 : CHECK(try_catch.HasCaught());
475 15 : CHECK_NE(1, v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2"), false)
476 : .ToLocalChecked()
477 : ->Int32Value(env.local())
478 : .FromJust());
479 5 : }
480 :
481 26644 : TEST(ObjectTemplateSetLazyPropertyHasNoSideEffect) {
482 5 : LocalContext env;
483 5 : v8::Isolate* isolate = env->GetIsolate();
484 10 : v8::HandleScope scope(isolate);
485 :
486 5 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
487 10 : templ->SetLazyDataProperty(v8_str("foo"), Getter);
488 10 : templ->SetLazyDataProperty(v8_str("foo2"), Getter, v8::Local<v8::Value>(),
489 : v8::PropertyAttribute::None,
490 5 : v8::SideEffectType::kHasNoSideEffect);
491 5 : v8::Local<v8::Object> obj = templ->NewInstance(env.local()).ToLocalChecked();
492 20 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
493 :
494 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo"), true).IsEmpty());
495 5 : v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2"), true).ToLocalChecked();
496 :
497 : // Check that setter is not whitelisted.
498 10 : v8::TryCatch try_catch(isolate);
499 10 : CHECK(v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2 = 1"), true)
500 : .IsEmpty());
501 5 : CHECK(try_catch.HasCaught());
502 15 : CHECK_NE(1, v8::debug::EvaluateGlobal(isolate, v8_str("obj.foo2"), false)
503 : .ToLocalChecked()
504 : ->Int32Value(env.local())
505 : .FromJust());
506 79922 : }
|