Home | History | Annotate | Download | only in cctest
      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 "src/v8.h"
     31 
     32 #include "src/api.h"
     33 #include "src/frames-inl.h"
     34 #include "src/string-stream.h"
     35 #include "test/cctest/cctest.h"
     36 
     37 using ::v8::ObjectTemplate;
     38 using ::v8::Value;
     39 using ::v8::Context;
     40 using ::v8::Local;
     41 using ::v8::Name;
     42 using ::v8::String;
     43 using ::v8::Script;
     44 using ::v8::Function;
     45 using ::v8::Extension;
     46 
     47 static void handle_property(Local<String> name,
     48                             const v8::PropertyCallbackInfo<v8::Value>& info) {
     49   ApiTestFuzzer::Fuzz();
     50   info.GetReturnValue().Set(v8_num(900));
     51 }
     52 
     53 static void handle_property_2(Local<String> name,
     54                               const v8::PropertyCallbackInfo<v8::Value>& info) {
     55   ApiTestFuzzer::Fuzz();
     56   info.GetReturnValue().Set(v8_num(902));
     57 }
     58 
     59 
     60 static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
     61   ApiTestFuzzer::Fuzz();
     62   CHECK_EQ(0, info.Length());
     63   info.GetReturnValue().Set(v8_num(907));
     64 }
     65 
     66 
     67 THREADED_TEST(PropertyHandler) {
     68   LocalContext env;
     69   v8::Isolate* isolate = env->GetIsolate();
     70   v8::HandleScope scope(isolate);
     71   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
     72   fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
     73   Local<v8::FunctionTemplate> getter_templ =
     74       v8::FunctionTemplate::New(isolate, handle_property);
     75   getter_templ->SetLength(0);
     76   fun_templ->
     77       InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
     78   fun_templ->InstanceTemplate()->
     79       SetNativeDataProperty(v8_str("instance_foo"), handle_property);
     80   fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2);
     81   Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
     82   CHECK(env->Global()->Set(env.local(), v8_str("Fun"), fun).FromJust());
     83   Local<Script> getter;
     84   Local<Script> setter;
     85   // check function instance accessors
     86   getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
     87   CHECK_EQ(900, getter->Run(env.local())
     88                     .ToLocalChecked()
     89                     ->Int32Value(env.local())
     90                     .FromJust());
     91   setter = v8_compile("obj.instance_foo = 901;");
     92   CHECK_EQ(901, setter->Run(env.local())
     93                     .ToLocalChecked()
     94                     ->Int32Value(env.local())
     95                     .FromJust());
     96   getter = v8_compile("obj.bar;");
     97   CHECK_EQ(907, getter->Run(env.local())
     98                     .ToLocalChecked()
     99                     ->Int32Value(env.local())
    100                     .FromJust());
    101   setter = v8_compile("obj.bar = 908;");
    102   CHECK_EQ(908, setter->Run(env.local())
    103                     .ToLocalChecked()
    104                     ->Int32Value(env.local())
    105                     .FromJust());
    106   // check function static accessors
    107   getter = v8_compile("Fun.object_foo;");
    108   CHECK_EQ(902, getter->Run(env.local())
    109                     .ToLocalChecked()
    110                     ->Int32Value(env.local())
    111                     .FromJust());
    112   setter = v8_compile("Fun.object_foo = 903;");
    113   CHECK_EQ(903, setter->Run(env.local())
    114                     .ToLocalChecked()
    115                     ->Int32Value(env.local())
    116                     .FromJust());
    117 }
    118 
    119 
    120 static void GetIntValue(Local<String> property,
    121                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    122   ApiTestFuzzer::Fuzz();
    123   int* value =
    124       static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value());
    125   info.GetReturnValue().Set(v8_num(*value));
    126 }
    127 
    128 
    129 static void SetIntValue(Local<String> property,
    130                         Local<Value> value,
    131                         const v8::PropertyCallbackInfo<void>& info) {
    132   int* field =
    133       static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value());
    134   *field = value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
    135 }
    136 
    137 int foo, bar, baz;
    138 
    139 THREADED_TEST(GlobalVariableAccess) {
    140   foo = 0;
    141   bar = -4;
    142   baz = 10;
    143   v8::Isolate* isolate = CcTest::isolate();
    144   v8::HandleScope scope(isolate);
    145   v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
    146   templ->InstanceTemplate()->SetAccessor(
    147       v8_str("foo"), GetIntValue, SetIntValue,
    148       v8::External::New(isolate, &foo));
    149   templ->InstanceTemplate()->SetAccessor(
    150       v8_str("bar"), GetIntValue, SetIntValue,
    151       v8::External::New(isolate, &bar));
    152   templ->InstanceTemplate()->SetAccessor(
    153       v8_str("baz"), GetIntValue, SetIntValue,
    154       v8::External::New(isolate, &baz));
    155   LocalContext env(0, templ->InstanceTemplate());
    156   v8_compile("foo = (++bar) + baz")->Run(env.local()).ToLocalChecked();
    157   CHECK_EQ(bar, -3);
    158   CHECK_EQ(foo, 7);
    159 }
    160 
    161 
    162 static int x_register[2] = {0, 0};
    163 static v8::Local<v8::Object> x_receiver;
    164 static v8::Local<v8::Object> x_holder;
    165 
    166 template<class Info>
    167 static void XGetter(const Info& info, int offset) {
    168   ApiTestFuzzer::Fuzz();
    169   v8::Isolate* isolate = CcTest::isolate();
    170   CHECK_EQ(isolate, info.GetIsolate());
    171   CHECK(
    172       x_receiver->Equals(isolate->GetCurrentContext(), info.This()).FromJust());
    173   info.GetReturnValue().Set(v8_num(x_register[offset]));
    174 }
    175 
    176 
    177 static void XGetter(Local<String> name,
    178                     const v8::PropertyCallbackInfo<v8::Value>& info) {
    179   CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
    180             .FromJust());
    181   XGetter(info, 0);
    182 }
    183 
    184 
    185 static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
    186   CHECK(
    187       x_receiver->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
    188           .FromJust());
    189   XGetter(info, 1);
    190 }
    191 
    192 
    193 template<class Info>
    194 static void XSetter(Local<Value> value, const Info& info, int offset) {
    195   v8::Isolate* isolate = CcTest::isolate();
    196   CHECK_EQ(isolate, info.GetIsolate());
    197   CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.This())
    198             .FromJust());
    199   CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
    200             .FromJust());
    201   x_register[offset] =
    202       value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
    203   info.GetReturnValue().Set(v8_num(-1));
    204 }
    205 
    206 
    207 static void XSetter(Local<String> name,
    208                     Local<Value> value,
    209                     const v8::PropertyCallbackInfo<void>& info) {
    210   XSetter(value, info, 0);
    211 }
    212 
    213 
    214 static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
    215   CHECK_EQ(1, info.Length());
    216   XSetter(info[0], info, 1);
    217 }
    218 
    219 
    220 THREADED_TEST(AccessorIC) {
    221   LocalContext context;
    222   v8::Isolate* isolate = context->GetIsolate();
    223   v8::HandleScope scope(isolate);
    224   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    225   obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
    226   obj->SetAccessorProperty(v8_str("x1"),
    227                            v8::FunctionTemplate::New(isolate, XGetter),
    228                            v8::FunctionTemplate::New(isolate, XSetter));
    229   x_holder = obj->NewInstance(context.local()).ToLocalChecked();
    230   CHECK(context->Global()
    231             ->Set(context.local(), v8_str("holder"), x_holder)
    232             .FromJust());
    233   x_receiver = v8::Object::New(isolate);
    234   CHECK(context->Global()
    235             ->Set(context.local(), v8_str("obj"), x_receiver)
    236             .FromJust());
    237   v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(
    238       CompileRun("obj.__proto__ = holder;"
    239                  "var result = [];"
    240                  "var key_0 = 'x0';"
    241                  "var key_1 = 'x1';"
    242                  "for (var j = 0; j < 10; j++) {"
    243                  "  var i = 4*j;"
    244                  "  result.push(holder.x0 = i);"
    245                  "  result.push(obj.x0);"
    246                  "  result.push(holder.x1 = i + 1);"
    247                  "  result.push(obj.x1);"
    248                  "  result.push(holder[key_0] = i + 2);"
    249                  "  result.push(obj[key_0]);"
    250                  "  result.push(holder[key_1] = i + 3);"
    251                  "  result.push(obj[key_1]);"
    252                  "}"
    253                  "result"));
    254   CHECK_EQ(80u, array->Length());
    255   for (int i = 0; i < 80; i++) {
    256     v8::Local<Value> entry =
    257         array->Get(context.local(), v8::Integer::New(isolate, i))
    258             .ToLocalChecked();
    259     CHECK(v8::Integer::New(isolate, i / 2)
    260               ->Equals(context.local(), entry)
    261               .FromJust());
    262   }
    263 }
    264 
    265 
    266 template <int C>
    267 static void HandleAllocatingGetter(
    268     Local<String> name,
    269     const v8::PropertyCallbackInfo<v8::Value>& info) {
    270   ApiTestFuzzer::Fuzz();
    271   for (int i = 0; i < C; i++) {
    272     v8::String::NewFromUtf8(info.GetIsolate(), "foo",
    273                             v8::NewStringType::kNormal)
    274         .ToLocalChecked();
    275   }
    276   info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo",
    277                                                     v8::NewStringType::kNormal)
    278                                 .ToLocalChecked());
    279 }
    280 
    281 
    282 THREADED_TEST(HandleScopePop) {
    283   LocalContext context;
    284   v8::Isolate* isolate = context->GetIsolate();
    285   v8::HandleScope scope(isolate);
    286   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    287   obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
    288   obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
    289   v8::Local<v8::Object> inst =
    290       obj->NewInstance(context.local()).ToLocalChecked();
    291   CHECK(
    292       context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
    293   int count_before =
    294       i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
    295   {
    296     v8::HandleScope scope(isolate);
    297     CompileRun(
    298         "for (var i = 0; i < 1000; i++) {"
    299         "  obj.one;"
    300         "  obj.many;"
    301         "}");
    302   }
    303   int count_after =
    304       i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
    305   CHECK_EQ(count_before, count_after);
    306 }
    307 
    308 static void CheckAccessorArgsCorrect(
    309     Local<String> name,
    310     const v8::PropertyCallbackInfo<v8::Value>& info) {
    311   CHECK(info.GetIsolate() == CcTest::isolate());
    312   CHECK(info.This() == info.Holder());
    313   CHECK(info.Data()
    314             ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
    315             .FromJust());
    316   ApiTestFuzzer::Fuzz();
    317   CHECK(info.GetIsolate() == CcTest::isolate());
    318   CHECK(info.This() == info.Holder());
    319   CHECK(info.Data()
    320             ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
    321             .FromJust());
    322   CcTest::heap()->CollectAllGarbage();
    323   CHECK(info.GetIsolate() == CcTest::isolate());
    324   CHECK(info.This() == info.Holder());
    325   CHECK(info.Data()
    326             ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
    327             .FromJust());
    328   info.GetReturnValue().Set(17);
    329 }
    330 
    331 
    332 THREADED_TEST(DirectCall) {
    333   LocalContext context;
    334   v8::Isolate* isolate = context->GetIsolate();
    335   v8::HandleScope scope(isolate);
    336   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    337   obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, NULL,
    338                    v8_str("data"));
    339   v8::Local<v8::Object> inst =
    340       obj->NewInstance(context.local()).ToLocalChecked();
    341   CHECK(
    342       context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
    343   Local<Script> scr =
    344       v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked();
    345   for (int i = 0; i < 10; i++) {
    346     Local<Value> result = scr->Run(context.local()).ToLocalChecked();
    347     CHECK(!result.IsEmpty());
    348     CHECK_EQ(17, result->Int32Value(context.local()).FromJust());
    349   }
    350 }
    351 
    352 static void EmptyGetter(Local<String> name,
    353                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    354   CheckAccessorArgsCorrect(name, info);
    355   ApiTestFuzzer::Fuzz();
    356   CheckAccessorArgsCorrect(name, info);
    357   info.GetReturnValue().Set(v8::Local<v8::Value>());
    358 }
    359 
    360 
    361 THREADED_TEST(EmptyResult) {
    362   LocalContext context;
    363   v8::Isolate* isolate = context->GetIsolate();
    364   v8::HandleScope scope(isolate);
    365   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    366   obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8_str("data"));
    367   v8::Local<v8::Object> inst =
    368       obj->NewInstance(context.local()).ToLocalChecked();
    369   CHECK(
    370       context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
    371   Local<Script> scr =
    372       v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked();
    373   for (int i = 0; i < 10; i++) {
    374     Local<Value> result = scr->Run(context.local()).ToLocalChecked();
    375     CHECK(result == v8::Undefined(isolate));
    376   }
    377 }
    378 
    379 
    380 THREADED_TEST(NoReuseRegress) {
    381   // Check that the IC generated for the one test doesn't get reused
    382   // for the other.
    383   v8::Isolate* isolate = CcTest::isolate();
    384   v8::HandleScope scope(isolate);
    385   {
    386     v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    387     obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8_str("data"));
    388     LocalContext context;
    389     v8::Local<v8::Object> inst =
    390         obj->NewInstance(context.local()).ToLocalChecked();
    391     CHECK(context->Global()
    392               ->Set(context.local(), v8_str("obj"), inst)
    393               .FromJust());
    394     Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
    395                             .ToLocalChecked();
    396     for (int i = 0; i < 2; i++) {
    397       Local<Value> result = scr->Run(context.local()).ToLocalChecked();
    398       CHECK(result == v8::Undefined(isolate));
    399     }
    400   }
    401   {
    402     v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    403     obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, NULL,
    404                      v8_str("data"));
    405     LocalContext context;
    406     v8::Local<v8::Object> inst =
    407         obj->NewInstance(context.local()).ToLocalChecked();
    408     CHECK(context->Global()
    409               ->Set(context.local(), v8_str("obj"), inst)
    410               .FromJust());
    411     Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
    412                             .ToLocalChecked();
    413     for (int i = 0; i < 10; i++) {
    414       Local<Value> result = scr->Run(context.local()).ToLocalChecked();
    415       CHECK(!result.IsEmpty());
    416       CHECK_EQ(17, result->Int32Value(context.local()).FromJust());
    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::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    441   obj->SetAccessor(v8_str("x"),
    442                    ThrowingGetAccessor,
    443                    ThrowingSetAccessor,
    444                    Local<Value>());
    445 
    446   CHECK(env->Global()
    447             ->Set(env.local(), v8_str("obj"),
    448                   obj->NewInstance(env.local()).ToLocalChecked())
    449             .FromJust());
    450 
    451   // Use the throwing property setter/getter in a loop to force
    452   // the accessor ICs to be initialized.
    453   v8::Local<Value> result;
    454   result = Script::Compile(env.local(),
    455                            v8_str("var result = '';"
    456                                   "for (var i = 0; i < 5; i++) {"
    457                                   "  try { obj.x; } catch (e) { result += e; }"
    458                                   "}; result"))
    459                .ToLocalChecked()
    460                ->Run(env.local())
    461                .ToLocalChecked();
    462   CHECK(v8_str("ggggg")->Equals(env.local(), result).FromJust());
    463 
    464   result =
    465       Script::Compile(env.local(),
    466                       v8_str("var result = '';"
    467                              "for (var i = 0; i < 5; i++) {"
    468                              "  try { obj.x = i; } catch (e) { result += e; }"
    469                              "}; result"))
    470           .ToLocalChecked()
    471           ->Run(env.local())
    472           .ToLocalChecked();
    473   CHECK(v8_str("01234")->Equals(env.local(), result).FromJust());
    474 }
    475 
    476 
    477 static void AllocGetter(Local<String> name,
    478                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    479   ApiTestFuzzer::Fuzz();
    480   info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000));
    481 }
    482 
    483 
    484 THREADED_TEST(Gc) {
    485   LocalContext env;
    486   v8::Isolate* isolate = env->GetIsolate();
    487   v8::HandleScope scope(isolate);
    488   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    489   obj->SetAccessor(v8_str("xxx"), AllocGetter);
    490   CHECK(env->Global()
    491             ->Set(env.local(), v8_str("obj"),
    492                   obj->NewInstance(env.local()).ToLocalChecked())
    493             .FromJust());
    494   Script::Compile(env.local(), v8_str("var last = [];"
    495                                       "for (var i = 0; i < 2048; i++) {"
    496                                       "  var result = obj.xxx;"
    497                                       "  result[0] = last;"
    498                                       "  last = result;"
    499                                       "}"))
    500       .ToLocalChecked()
    501       ->Run(env.local())
    502       .ToLocalChecked();
    503 }
    504 
    505 
    506 static void StackCheck(Local<String> name,
    507                        const v8::PropertyCallbackInfo<v8::Value>& info) {
    508   i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
    509   for (int i = 0; !iter.done(); i++) {
    510     i::StackFrame* frame = iter.frame();
    511     CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
    512     i::Code* code = frame->LookupCode();
    513     CHECK(code->IsCode());
    514     i::Address pc = frame->pc();
    515     CHECK(code->contains(pc));
    516     iter.Advance();
    517   }
    518 }
    519 
    520 
    521 THREADED_TEST(StackIteration) {
    522   LocalContext env;
    523   v8::Isolate* isolate = env->GetIsolate();
    524   v8::HandleScope scope(isolate);
    525   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    526   i::StringStream::ClearMentionedObjectCache(
    527       reinterpret_cast<i::Isolate*>(isolate));
    528   obj->SetAccessor(v8_str("xxx"), StackCheck);
    529   CHECK(env->Global()
    530             ->Set(env.local(), v8_str("obj"),
    531                   obj->NewInstance(env.local()).ToLocalChecked())
    532             .FromJust());
    533   Script::Compile(env.local(), v8_str("function foo() {"
    534                                       "  return obj.xxx;"
    535                                       "}"
    536                                       "for (var i = 0; i < 100; i++) {"
    537                                       "  foo();"
    538                                       "}"))
    539       .ToLocalChecked()
    540       ->Run(env.local())
    541       .ToLocalChecked();
    542 }
    543 
    544 
    545 static void AllocateHandles(Local<String> name,
    546                             const v8::PropertyCallbackInfo<v8::Value>& info) {
    547   for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
    548     v8::Local<v8::Value>::New(info.GetIsolate(), name);
    549   }
    550   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100));
    551 }
    552 
    553 
    554 THREADED_TEST(HandleScopeSegment) {
    555   // Check that we can return values past popping of handle scope
    556   // segments.
    557   LocalContext env;
    558   v8::Isolate* isolate = env->GetIsolate();
    559   v8::HandleScope scope(isolate);
    560   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    561   obj->SetAccessor(v8_str("xxx"), AllocateHandles);
    562   CHECK(env->Global()
    563             ->Set(env.local(), v8_str("obj"),
    564                   obj->NewInstance(env.local()).ToLocalChecked())
    565             .FromJust());
    566   v8::Local<v8::Value> result =
    567       Script::Compile(env.local(), v8_str("var result;"
    568                                           "for (var i = 0; i < 4; i++)"
    569                                           "  result = obj.xxx;"
    570                                           "result;"))
    571           .ToLocalChecked()
    572           ->Run(env.local())
    573           .ToLocalChecked();
    574   CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
    575 }
    576 
    577 
    578 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
    579   v8::Local<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
    580   CHECK(array->Set(info.GetIsolate()->GetCurrentContext(), 0, v8_str("regress"))
    581             .FromJust());
    582   info.GetReturnValue().Set(array);
    583 }
    584 
    585 
    586 void JSONStringifyGetter(Local<Name> name,
    587                          const v8::PropertyCallbackInfo<v8::Value>& info) {
    588   info.GetReturnValue().Set(v8_str("crbug-161028"));
    589 }
    590 
    591 
    592 THREADED_TEST(JSONStringifyNamedInterceptorObject) {
    593   LocalContext env;
    594   v8::Isolate* isolate = env->GetIsolate();
    595   v8::HandleScope scope(isolate);
    596 
    597   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    598   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
    599       JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator));
    600   CHECK(env->Global()
    601             ->Set(env.local(), v8_str("obj"),
    602                   obj->NewInstance(env.local()).ToLocalChecked())
    603             .FromJust());
    604   v8::Local<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
    605   CHECK(CompileRun("JSON.stringify(obj)")
    606             ->Equals(env.local(), expected)
    607             .FromJust());
    608 }
    609 
    610 
    611 static v8::Local<v8::Context> expected_current_context;
    612 
    613 
    614 static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
    615   ApiTestFuzzer::Fuzz();
    616   CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
    617 }
    618 
    619 
    620 THREADED_TEST(AccessorPropertyCrossContext) {
    621   LocalContext env;
    622   v8::Isolate* isolate = env->GetIsolate();
    623   v8::HandleScope scope(isolate);
    624   v8::Local<v8::Function> fun =
    625       v8::Function::New(env.local(), check_contexts).ToLocalChecked();
    626   LocalContext switch_context;
    627   CHECK(switch_context->Global()
    628             ->Set(switch_context.local(), v8_str("fun"), fun)
    629             .FromJust());
    630   v8::TryCatch try_catch(isolate);
    631   expected_current_context = env.local();
    632   CompileRun(
    633       "var o = Object.create(null, { n: { get:fun } });"
    634       "for (var i = 0; i < 10; i++) o.n;");
    635   CHECK(!try_catch.HasCaught());
    636 }
    637 
    638 
    639 THREADED_TEST(GlobalObjectAccessor) {
    640   LocalContext env;
    641   v8::Isolate* isolate = env->GetIsolate();
    642   v8::HandleScope scope(isolate);
    643   CompileRun(
    644       "var set_value = 1;"
    645       "Object.defineProperty(this.__proto__, 'x', {"
    646       "    get : function() { return this; },"
    647       "    set : function() { set_value = this; }"
    648       "});"
    649       "function getter() { return x; }"
    650       "function setter() { x = 1; }"
    651       "for (var i = 0; i < 4; i++) { getter(); setter(); }");
    652   CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
    653   CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
    654 }
    655 
    656 
    657 static void EmptyGetter(Local<Name> name,
    658                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    659   ApiTestFuzzer::Fuzz();
    660 }
    661 
    662 
    663 static void OneProperty(Local<String> name,
    664                         const v8::PropertyCallbackInfo<v8::Value>& info) {
    665   ApiTestFuzzer::Fuzz();
    666   info.GetReturnValue().Set(v8_num(1));
    667 }
    668 
    669 
    670 THREADED_TEST(Regress433458) {
    671   LocalContext env;
    672   v8::Isolate* isolate = env->GetIsolate();
    673   v8::HandleScope scope(isolate);
    674   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    675   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
    676   obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
    677   CHECK(env->Global()
    678             ->Set(env.local(), v8_str("obj"),
    679                   obj->NewInstance(env.local()).ToLocalChecked())
    680             .FromJust());
    681   CompileRun(
    682       "Object.defineProperty(obj, 'prop', { writable: false });"
    683       "Object.defineProperty(obj, 'prop', { writable: true });");
    684 }
    685 
    686 
    687 static bool security_check_value = false;
    688 
    689 
    690 static bool SecurityTestCallback(Local<v8::Context> accessing_context,
    691                                  Local<v8::Object> accessed_object) {
    692   return security_check_value;
    693 }
    694 
    695 
    696 TEST(PrototypeGetterAccessCheck) {
    697   i::FLAG_allow_natives_syntax = true;
    698   LocalContext env;
    699   v8::Isolate* isolate = env->GetIsolate();
    700   v8::HandleScope scope(isolate);
    701   auto fun_templ = v8::FunctionTemplate::New(isolate);
    702   auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property);
    703   getter_templ->SetAcceptAnyReceiver(false);
    704   fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"),
    705                                                      getter_templ);
    706   auto obj_templ = v8::ObjectTemplate::New(isolate);
    707   obj_templ->SetAccessCheckCallback(SecurityTestCallback);
    708   CHECK(env->Global()
    709             ->Set(env.local(), v8_str("Fun"),
    710                   fun_templ->GetFunction(env.local()).ToLocalChecked())
    711             .FromJust());
    712   CHECK(env->Global()
    713             ->Set(env.local(), v8_str("obj"),
    714                   obj_templ->NewInstance(env.local()).ToLocalChecked())
    715             .FromJust());
    716   CHECK(env->Global()
    717             ->Set(env.local(), v8_str("obj2"),
    718                   obj_templ->NewInstance(env.local()).ToLocalChecked())
    719             .FromJust());
    720 
    721   security_check_value = true;
    722   CompileRun("var proto = new Fun();");
    723   CompileRun("obj.__proto__ = proto;");
    724   ExpectInt32("proto.foo", 907);
    725 
    726   // Test direct.
    727   security_check_value = true;
    728   ExpectInt32("obj.foo", 907);
    729   security_check_value = false;
    730   {
    731     v8::TryCatch try_catch(isolate);
    732     CompileRun("obj.foo");
    733     CHECK(try_catch.HasCaught());
    734   }
    735 
    736   // Test through call.
    737   security_check_value = true;
    738   ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907);
    739   security_check_value = false;
    740   {
    741     v8::TryCatch try_catch(isolate);
    742     CompileRun("proto.__lookupGetter__('foo').call(obj)");
    743     CHECK(try_catch.HasCaught());
    744   }
    745 
    746   // Test ics.
    747   CompileRun(
    748       "function f() {"
    749       "   var x;"
    750       "  for (var i = 0; i < 4; i++) {"
    751       "    x = obj.foo;"
    752       "  }"
    753       "  return x;"
    754       "}");
    755 
    756   security_check_value = true;
    757   ExpectInt32("f()", 907);
    758   security_check_value = false;
    759   {
    760     v8::TryCatch try_catch(isolate);
    761     CompileRun("f();");
    762     CHECK(try_catch.HasCaught());
    763   }
    764 
    765   // Test crankshaft.
    766   CompileRun("%OptimizeFunctionOnNextCall(f);");
    767 
    768   security_check_value = true;
    769   ExpectInt32("f()", 907);
    770   security_check_value = false;
    771   {
    772     v8::TryCatch try_catch(isolate);
    773     CompileRun("f();");
    774     CHECK(try_catch.HasCaught());
    775   }
    776 }
    777