Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-accessors.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <stdlib.h>
29
30 #include "v8.h"
31
32 #include "api.h"
33 #include "cctest.h"
34 #include "frames-inl.h"
35 #include "string-stream.h"
36
37 using ::v8::ObjectTemplate;
38 using ::v8::Value;
39 using ::v8::Context;
40 using ::v8::Local;
41 using ::v8::String;
42 using ::v8::Script;
43 using ::v8::Function;
44 using ::v8::Extension;
45
46 static void handle_property(Local<String> name,
47                             const v8::PropertyCallbackInfo<v8::Value>& info) {
48   ApiTestFuzzer::Fuzz();
49   info.GetReturnValue().Set(v8_num(900));
50 }
51
52 static void handle_property_2(Local<String> name,
53                               const v8::PropertyCallbackInfo<v8::Value>& info) {
54   ApiTestFuzzer::Fuzz();
55   info.GetReturnValue().Set(v8_num(902));
56 }
57
58
59 static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
60   ApiTestFuzzer::Fuzz();
61   CHECK_EQ(0, info.Length());
62   info.GetReturnValue().Set(v8_num(907));
63 }
64
65
66 THREADED_TEST(PropertyHandler) {
67   LocalContext env;
68   v8::Isolate* isolate = env->GetIsolate();
69   v8::HandleScope scope(isolate);
70   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
71   fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
72   Local<v8::FunctionTemplate> getter_templ =
73       v8::FunctionTemplate::New(isolate, handle_property);
74   getter_templ->SetLength(0);
75   fun_templ->
76       InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
77   fun_templ->InstanceTemplate()->
78       SetNativeDataProperty(v8_str("instance_foo"), handle_property);
79   fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2);
80   Local<Function> fun = fun_templ->GetFunction();
81   env->Global()->Set(v8_str("Fun"), fun);
82   Local<Script> getter;
83   Local<Script> setter;
84   // check function instance accessors
85   getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
86   CHECK_EQ(900, getter->Run()->Int32Value());
87   setter = v8_compile("obj.instance_foo = 901;");
88   CHECK_EQ(901, setter->Run()->Int32Value());
89   getter = v8_compile("obj.bar;");
90   CHECK_EQ(907, getter->Run()->Int32Value());
91   setter = v8_compile("obj.bar = 908;");
92   CHECK_EQ(908, setter->Run()->Int32Value());
93   // check function static accessors
94   getter = v8_compile("Fun.object_foo;");
95   CHECK_EQ(902, getter->Run()->Int32Value());
96   setter = v8_compile("Fun.object_foo = 903;");
97   CHECK_EQ(903, setter->Run()->Int32Value());
98 }
99
100
101 static void GetIntValue(Local<String> property,
102                         const v8::PropertyCallbackInfo<v8::Value>& info) {
103   ApiTestFuzzer::Fuzz();
104   int* value =
105       static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
106   info.GetReturnValue().Set(v8_num(*value));
107 }
108
109
110 static void SetIntValue(Local<String> property,
111                         Local<Value> value,
112                         const v8::PropertyCallbackInfo<void>& info) {
113   int* field =
114       static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
115   *field = value->Int32Value();
116 }
117
118 int foo, bar, baz;
119
120 THREADED_TEST(GlobalVariableAccess) {
121   foo = 0;
122   bar = -4;
123   baz = 10;
124   v8::Isolate* isolate = CcTest::isolate();
125   v8::HandleScope scope(isolate);
126   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
127   templ->InstanceTemplate()->SetAccessor(
128       v8_str("foo"), GetIntValue, SetIntValue,
129       v8::External::New(isolate, &foo));
130   templ->InstanceTemplate()->SetAccessor(
131       v8_str("bar"), GetIntValue, SetIntValue,
132       v8::External::New(isolate, &bar));
133   templ->InstanceTemplate()->SetAccessor(
134       v8_str("baz"), GetIntValue, SetIntValue,
135       v8::External::New(isolate, &baz));
136   LocalContext env(0, templ->InstanceTemplate());
137   v8_compile("foo = (++bar) + baz")->Run();
138   CHECK_EQ(bar, -3);
139   CHECK_EQ(foo, 7);
140 }
141
142
143 static int x_register[2] = {0, 0};
144 static v8::Handle<v8::Object> x_receiver;
145 static v8::Handle<v8::Object> x_holder;
146
147 template<class Info>
148 static void XGetter(const Info& info, int offset) {
149   ApiTestFuzzer::Fuzz();
150   v8::Isolate* isolate = CcTest::isolate();
151   CHECK_EQ(isolate, info.GetIsolate());
152   CHECK_EQ(x_receiver, info.This());
153   info.GetReturnValue().Set(v8_num(x_register[offset]));
154 }
155
156
157 static void XGetter(Local<String> name,
158                     const v8::PropertyCallbackInfo<v8::Value>& info) {
159   CHECK_EQ(x_holder, info.Holder());
160   XGetter(info, 0);
161 }
162
163
164 static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
165   CHECK_EQ(x_receiver, info.Holder());
166   XGetter(info, 1);
167 }
168
169
170 template<class Info>
171 static void XSetter(Local<Value> value, const Info& info, int offset) {
172   v8::Isolate* isolate = CcTest::isolate();
173   CHECK_EQ(isolate, info.GetIsolate());
174   CHECK_EQ(x_holder, info.This());
175   CHECK_EQ(x_holder, info.Holder());
176   x_register[offset] = value->Int32Value();
177 }
178
179
180 static void XSetter(Local<String> name,
181                     Local<Value> value,
182                     const v8::PropertyCallbackInfo<void>& info) {
183   XSetter(value, info, 0);
184 }
185
186
187 static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
188   CHECK_EQ(1, info.Length());
189   XSetter(info[0], info, 1);
190 }
191
192
193 THREADED_TEST(AccessorIC) {
194   LocalContext context;
195   v8::Isolate* isolate = context->GetIsolate();
196   v8::HandleScope scope(isolate);
197   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
198   obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
199   obj->SetAccessorProperty(v8_str("x1"),
200                            v8::FunctionTemplate::New(isolate, XGetter),
201                            v8::FunctionTemplate::New(isolate, XSetter));
202   x_holder = obj->NewInstance();
203   context->Global()->Set(v8_str("holder"), x_holder);
204   x_receiver = v8::Object::New(isolate);
205   context->Global()->Set(v8_str("obj"), x_receiver);
206   v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
207     "obj.__proto__ = holder;"
208     "var result = [];"
209     "var key_0 = 'x0';"
210     "var key_1 = 'x1';"
211     "for (var j = 0; j < 10; j++) {"
212     "  var i = 4*j;"
213     "  holder.x0 = i;"
214     "  result.push(obj.x0);"
215     "  holder.x1 = i + 1;"
216     "  result.push(obj.x1);"
217     "  holder[key_0] = i + 2;"
218     "  result.push(obj[key_0]);"
219     "  holder[key_1] = i + 3;"
220     "  result.push(obj[key_1]);"
221     "}"
222     "result"));
223   CHECK_EQ(40, array->Length());
224   for (int i = 0; i < 40; i++) {
225     v8::Handle<Value> entry = array->Get(v8::Integer::New(isolate, i));
226     CHECK_EQ(v8::Integer::New(isolate, i), entry);
227   }
228 }
229
230
231 static void AccessorProhibitsOverwritingGetter(
232     Local<String> name,
233     const v8::PropertyCallbackInfo<v8::Value>& info) {
234   ApiTestFuzzer::Fuzz();
235   info.GetReturnValue().Set(true);
236 }
237
238
239 THREADED_TEST(AccessorProhibitsOverwriting) {
240   LocalContext context;
241   v8::Isolate* isolate = context->GetIsolate();
242   v8::HandleScope scope(isolate);
243   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
244   templ->SetAccessor(v8_str("x"),
245                      AccessorProhibitsOverwritingGetter,
246                      0,
247                      v8::Handle<Value>(),
248                      v8::PROHIBITS_OVERWRITING,
249                      v8::ReadOnly);
250   Local<v8::Object> instance = templ->NewInstance();
251   context->Global()->Set(v8_str("obj"), instance);
252   Local<Value> value = CompileRun(
253       "obj.__defineGetter__('x', function() { return false; });"
254       "obj.x");
255   CHECK(value->BooleanValue());
256   value = CompileRun(
257       "var setter_called = false;"
258       "obj.__defineSetter__('x', function() { setter_called = true; });"
259       "obj.x = 42;"
260       "setter_called");
261   CHECK(!value->BooleanValue());
262   value = CompileRun(
263       "obj2 = {};"
264       "obj2.__proto__ = obj;"
265       "obj2.__defineGetter__('x', function() { return false; });"
266       "obj2.x");
267   CHECK(value->BooleanValue());
268   value = CompileRun(
269       "var setter_called = false;"
270       "obj2 = {};"
271       "obj2.__proto__ = obj;"
272       "obj2.__defineSetter__('x', function() { setter_called = true; });"
273       "obj2.x = 42;"
274       "setter_called");
275   CHECK(!value->BooleanValue());
276 }
277
278
279 template <int C>
280 static void HandleAllocatingGetter(
281     Local<String> name,
282     const v8::PropertyCallbackInfo<v8::Value>& info) {
283   ApiTestFuzzer::Fuzz();
284   for (int i = 0; i < C; i++)
285     v8::String::NewFromUtf8(info.GetIsolate(), "foo");
286   info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo"));
287 }
288
289
290 THREADED_TEST(HandleScopePop) {
291   LocalContext context;
292   v8::Isolate* isolate = context->GetIsolate();
293   v8::HandleScope scope(isolate);
294   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
295   obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
296   obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
297   v8::Handle<v8::Object> inst = obj->NewInstance();
298   context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
299   int count_before =
300       i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
301   {
302     v8::HandleScope scope(isolate);
303     CompileRun(
304         "for (var i = 0; i < 1000; i++) {"
305         "  obj.one;"
306         "  obj.many;"
307         "}");
308   }
309   int count_after =
310       i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
311   CHECK_EQ(count_before, count_after);
312 }
313
314 static void CheckAccessorArgsCorrect(
315     Local<String> name,
316     const v8::PropertyCallbackInfo<v8::Value>& info) {
317   CHECK(info.GetIsolate() == CcTest::isolate());
318   CHECK(info.This() == info.Holder());
319   CHECK(
320       info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
321   ApiTestFuzzer::Fuzz();
322   CHECK(info.GetIsolate() == CcTest::isolate());
323   CHECK(info.This() == info.Holder());
324   CHECK(
325       info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
326   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
327   CHECK(info.GetIsolate() == CcTest::isolate());
328   CHECK(info.This() == info.Holder());
329   CHECK(
330       info.Data()->Equals(v8::String::NewFromUtf8(CcTest::isolate(), "data")));
331   info.GetReturnValue().Set(17);
332 }
333
334
335 THREADED_TEST(DirectCall) {
336   LocalContext context;
337   v8::Isolate* isolate = context->GetIsolate();
338   v8::HandleScope scope(isolate);
339   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
340   obj->SetAccessor(v8_str("xxx"),
341                    CheckAccessorArgsCorrect,
342                    NULL,
343                    v8::String::NewFromUtf8(isolate, "data"));
344   v8::Handle<v8::Object> inst = obj->NewInstance();
345   context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"),
346                          inst);
347   Local<Script> scr = v8::Script::Compile(
348       v8::String::NewFromUtf8(isolate, "obj.xxx"));
349   for (int i = 0; i < 10; i++) {
350     Local<Value> result = scr->Run();
351     CHECK(!result.IsEmpty());
352     CHECK_EQ(17, result->Int32Value());
353   }
354 }
355
356 static void EmptyGetter(Local<String> name,
357                         const v8::PropertyCallbackInfo<v8::Value>& info) {
358   CheckAccessorArgsCorrect(name, info);
359   ApiTestFuzzer::Fuzz();
360   CheckAccessorArgsCorrect(name, info);
361   info.GetReturnValue().Set(v8::Handle<v8::Value>());
362 }
363
364
365 THREADED_TEST(EmptyResult) {
366   LocalContext context;
367   v8::Isolate* isolate = context->GetIsolate();
368   v8::HandleScope scope(isolate);
369   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
370   obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL,
371                    v8::String::NewFromUtf8(isolate, "data"));
372   v8::Handle<v8::Object> inst = obj->NewInstance();
373   context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
374   Local<Script> scr =
375       v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
376   for (int i = 0; i < 10; i++) {
377     Local<Value> result = scr->Run();
378     CHECK(result == v8::Undefined(isolate));
379   }
380 }
381
382
383 THREADED_TEST(NoReuseRegress) {
384   // Check that the IC generated for the one test doesn't get reused
385   // for the other.
386   v8::Isolate* isolate = CcTest::isolate();
387   v8::HandleScope scope(isolate);
388   {
389     v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
390     obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL,
391                      v8::String::NewFromUtf8(isolate, "data"));
392     LocalContext context;
393     v8::Handle<v8::Object> inst = obj->NewInstance();
394     context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
395     Local<Script> scr =
396         v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
397     for (int i = 0; i < 2; i++) {
398       Local<Value> result = scr->Run();
399       CHECK(result == v8::Undefined(isolate));
400     }
401   }
402   {
403     v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
404     obj->SetAccessor(v8_str("xxx"),
405                      CheckAccessorArgsCorrect,
406                      NULL,
407                      v8::String::NewFromUtf8(isolate, "data"));
408     LocalContext context;
409     v8::Handle<v8::Object> inst = obj->NewInstance();
410     context->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"), inst);
411     Local<Script> scr =
412         v8::Script::Compile(v8::String::NewFromUtf8(isolate, "obj.xxx"));
413     for (int i = 0; i < 10; i++) {
414       Local<Value> result = scr->Run();
415       CHECK(!result.IsEmpty());
416       CHECK_EQ(17, result->Int32Value());
417     }
418   }
419 }
420
421 static void ThrowingGetAccessor(
422     Local<String> name,
423     const v8::PropertyCallbackInfo<v8::Value>& info) {
424   ApiTestFuzzer::Fuzz();
425   info.GetIsolate()->ThrowException(v8_str("g"));
426 }
427
428
429 static void ThrowingSetAccessor(Local<String> name,
430                                 Local<Value> value,
431                                 const v8::PropertyCallbackInfo<void>& info) {
432   info.GetIsolate()->ThrowException(value);
433 }
434
435
436 THREADED_TEST(Regress1054726) {
437   LocalContext env;
438   v8::Isolate* isolate = env->GetIsolate();
439   v8::HandleScope scope(isolate);
440   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
441   obj->SetAccessor(v8_str("x"),
442                    ThrowingGetAccessor,
443                    ThrowingSetAccessor,
444                    Local<Value>());
445
446   env->Global()->Set(v8_str("obj"), obj->NewInstance());
447
448   // Use the throwing property setter/getter in a loop to force
449   // the accessor ICs to be initialized.
450   v8::Handle<Value> result;
451   result = Script::Compile(v8_str(
452       "var result = '';"
453       "for (var i = 0; i < 5; i++) {"
454       "  try { obj.x; } catch (e) { result += e; }"
455       "}; result"))->Run();
456   CHECK_EQ(v8_str("ggggg"), result);
457
458   result = Script::Compile(String::NewFromUtf8(
459       isolate,
460       "var result = '';"
461       "for (var i = 0; i < 5; i++) {"
462       "  try { obj.x = i; } catch (e) { result += e; }"
463       "}; result"))->Run();
464   CHECK_EQ(v8_str("01234"), result);
465 }
466
467
468 static void AllocGetter(Local<String> name,
469                         const v8::PropertyCallbackInfo<v8::Value>& info) {
470   ApiTestFuzzer::Fuzz();
471   info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000));
472 }
473
474
475 THREADED_TEST(Gc) {
476   LocalContext env;
477   v8::Isolate* isolate = env->GetIsolate();
478   v8::HandleScope scope(isolate);
479   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
480   obj->SetAccessor(v8_str("xxx"), AllocGetter);
481   env->Global()->Set(v8_str("obj"), obj->NewInstance());
482   Script::Compile(String::NewFromUtf8(
483       isolate,
484       "var last = [];"
485       "for (var i = 0; i < 2048; i++) {"
486       "  var result = obj.xxx;"
487       "  result[0] = last;"
488       "  last = result;"
489       "}"))->Run();
490 }
491
492
493 static void StackCheck(Local<String> name,
494                        const v8::PropertyCallbackInfo<v8::Value>& info) {
495   i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
496   for (int i = 0; !iter.done(); i++) {
497     i::StackFrame* frame = iter.frame();
498     CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
499     i::Code* code = frame->LookupCode();
500     CHECK(code->IsCode());
501     i::Address pc = frame->pc();
502     CHECK(code->contains(pc));
503     iter.Advance();
504   }
505 }
506
507
508 THREADED_TEST(StackIteration) {
509   LocalContext env;
510   v8::Isolate* isolate = env->GetIsolate();
511   v8::HandleScope scope(isolate);
512   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
513   i::StringStream::ClearMentionedObjectCache(
514       reinterpret_cast<i::Isolate*>(isolate));
515   obj->SetAccessor(v8_str("xxx"), StackCheck);
516   env->Global()->Set(v8_str("obj"), obj->NewInstance());
517   Script::Compile(String::NewFromUtf8(
518       isolate,
519       "function foo() {"
520       "  return obj.xxx;"
521       "}"
522       "for (var i = 0; i < 100; i++) {"
523       "  foo();"
524       "}"))->Run();
525 }
526
527
528 static void AllocateHandles(Local<String> name,
529                             const v8::PropertyCallbackInfo<v8::Value>& info) {
530   for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
531     v8::Local<v8::Value>::New(info.GetIsolate(), name);
532   }
533   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100));
534 }
535
536
537 THREADED_TEST(HandleScopeSegment) {
538   // Check that we can return values past popping of handle scope
539   // segments.
540   LocalContext env;
541   v8::Isolate* isolate = env->GetIsolate();
542   v8::HandleScope scope(isolate);
543   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
544   obj->SetAccessor(v8_str("xxx"), AllocateHandles);
545   env->Global()->Set(v8_str("obj"), obj->NewInstance());
546   v8::Handle<v8::Value> result = Script::Compile(String::NewFromUtf8(
547       isolate,
548       "var result;"
549       "for (var i = 0; i < 4; i++)"
550       "  result = obj.xxx;"
551       "result;"))->Run();
552   CHECK_EQ(100, result->Int32Value());
553 }
554
555
556 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
557   v8::Handle<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
558   array->Set(0, v8_str("regress"));
559   info.GetReturnValue().Set(array);
560 }
561
562
563 void JSONStringifyGetter(Local<String> name,
564                          const v8::PropertyCallbackInfo<v8::Value>& info) {
565   info.GetReturnValue().Set(v8_str("crbug-161028"));
566 }
567
568
569 THREADED_TEST(JSONStringifyNamedInterceptorObject) {
570   LocalContext env;
571   v8::Isolate* isolate = env->GetIsolate();
572   v8::HandleScope scope(isolate);
573
574   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
575   obj->SetNamedPropertyHandler(
576       JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator);
577   env->Global()->Set(v8_str("obj"), obj->NewInstance());
578   v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
579   CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
580 }
581
582
583 static v8::Local<v8::Context> expected_current_context;
584 static v8::Local<v8::Context> expected_calling_context;
585
586
587 static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
588   ApiTestFuzzer::Fuzz();
589   CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
590   CHECK(expected_calling_context == info.GetIsolate()->GetCallingContext());
591 }
592
593
594 THREADED_TEST(AccessorPropertyCrossContext) {
595   LocalContext env;
596   v8::Isolate* isolate = env->GetIsolate();
597   v8::HandleScope scope(isolate);
598   v8::Handle<v8::Function> fun = v8::Function::New(isolate, check_contexts);
599   LocalContext switch_context;
600   switch_context->Global()->Set(v8_str("fun"), fun);
601   v8::TryCatch try_catch;
602   expected_current_context = env.local();
603   expected_calling_context = switch_context.local();
604   CompileRun(
605       "var o = Object.create(null, { n: { get:fun } });"
606       "for (var i = 0; i < 10; i++) o.n;");
607   CHECK(!try_catch.HasCaught());
608 }
609
610
611 THREADED_TEST(GlobalObjectAccessor) {
612   LocalContext env;
613   v8::Isolate* isolate = env->GetIsolate();
614   v8::HandleScope scope(isolate);
615   CompileRun(
616       "var set_value = 1;"
617       "Object.defineProperty(this.__proto__, 'x', {"
618       "    get : function() { return this; },"
619       "    set : function() { set_value = this; }"
620       "});"
621       "function getter() { return x; }"
622       "function setter() { x = 1; }"
623       "for (var i = 0; i < 4; i++) { getter(); setter(); }");
624   CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
625   CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
626 }