test-accessors.cc 26.8 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <stdlib.h>

30
#include "src/v8.h"
31

32 33 34 35
#include "src/api.h"
#include "src/frames-inl.h"
#include "src/string-stream.h"
#include "test/cctest/cctest.h"
36 37 38 39 40

using ::v8::ObjectTemplate;
using ::v8::Value;
using ::v8::Context;
using ::v8::Local;
41
using ::v8::Name;
42 43 44 45 46
using ::v8::String;
using ::v8::Script;
using ::v8::Function;
using ::v8::Extension;

47 48
static void handle_property(Local<String> name,
                            const v8::PropertyCallbackInfo<v8::Value>& info) {
49
  ApiTestFuzzer::Fuzz();
50
  info.GetReturnValue().Set(v8_num(900));
51 52
}

53 54 55 56 57 58
static void handle_property_2(Local<String> name,
                              const v8::PropertyCallbackInfo<v8::Value>& info) {
  ApiTestFuzzer::Fuzz();
  info.GetReturnValue().Set(v8_num(902));
}

59

60 61 62 63 64 65 66
static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
  ApiTestFuzzer::Fuzz();
  CHECK_EQ(0, info.Length());
  info.GetReturnValue().Set(v8_num(907));
}


67
THREADED_TEST(PropertyHandler) {
68
  LocalContext env;
69 70 71
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  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 76 77
  getter_templ->SetLength(0);
  fun_templ->
      InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
78 79 80
  fun_templ->InstanceTemplate()->
      SetNativeDataProperty(v8_str("instance_foo"), handle_property);
  fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2);
81 82
  Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
  CHECK(env->Global()->Set(env.local(), v8_str("Fun"), fun).FromJust());
83 84 85 86
  Local<Script> getter;
  Local<Script> setter;
  // check function instance accessors
  getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
87 88 89 90
  CHECK_EQ(900, getter->Run(env.local())
                    .ToLocalChecked()
                    ->Int32Value(env.local())
                    .FromJust());
91
  setter = v8_compile("obj.instance_foo = 901;");
92 93 94 95
  CHECK_EQ(901, setter->Run(env.local())
                    .ToLocalChecked()
                    ->Int32Value(env.local())
                    .FromJust());
96
  getter = v8_compile("obj.bar;");
97 98 99 100
  CHECK_EQ(907, getter->Run(env.local())
                    .ToLocalChecked()
                    ->Int32Value(env.local())
                    .FromJust());
101
  setter = v8_compile("obj.bar = 908;");
102 103 104 105
  CHECK_EQ(908, setter->Run(env.local())
                    .ToLocalChecked()
                    ->Int32Value(env.local())
                    .FromJust());
106 107
  // check function static accessors
  getter = v8_compile("Fun.object_foo;");
108 109 110 111
  CHECK_EQ(902, getter->Run(env.local())
                    .ToLocalChecked()
                    ->Int32Value(env.local())
                    .FromJust());
112
  setter = v8_compile("Fun.object_foo = 903;");
113 114 115 116
  CHECK_EQ(903, setter->Run(env.local())
                    .ToLocalChecked()
                    ->Int32Value(env.local())
                    .FromJust());
117 118 119
}


120 121
static void GetIntValue(Local<String> property,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
122 123
  ApiTestFuzzer::Fuzz();
  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 130
}


static void SetIntValue(Local<String> property,
                        Local<Value> value,
131
                        const v8::PropertyCallbackInfo<void>& info) {
132
  int* field =
133 134
      static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value());
  *field = value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
135 136 137 138 139 140 141 142
}

int foo, bar, baz;

THREADED_TEST(GlobalVariableAccess) {
  foo = 0;
  bar = -4;
  baz = 10;
143 144
  v8::Isolate* isolate = CcTest::isolate();
  v8::HandleScope scope(isolate);
145
  v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
146 147
  templ->InstanceTemplate()->SetAccessor(
      v8_str("foo"), GetIntValue, SetIntValue,
148
      v8::External::New(isolate, &foo));
149 150
  templ->InstanceTemplate()->SetAccessor(
      v8_str("bar"), GetIntValue, SetIntValue,
151
      v8::External::New(isolate, &bar));
152 153
  templ->InstanceTemplate()->SetAccessor(
      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 158 159 160 161
  CHECK_EQ(bar, -3);
  CHECK_EQ(foo, 7);
}


162
static int x_register[2] = {0, 0};
163 164
static v8::Local<v8::Object> x_receiver;
static v8::Local<v8::Object> x_holder;
165

166 167
template<class Info>
static void XGetter(const Info& info, int offset) {
168
  ApiTestFuzzer::Fuzz();
169
  v8::Isolate* isolate = CcTest::isolate();
170
  CHECK_EQ(isolate, info.GetIsolate());
171 172
  CHECK(
      x_receiver->Equals(isolate->GetCurrentContext(), info.This()).FromJust());
173 174 175 176 177 178
  info.GetReturnValue().Set(v8_num(x_register[offset]));
}


static void XGetter(Local<String> name,
                    const v8::PropertyCallbackInfo<v8::Value>& info) {
179 180
  CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
            .FromJust());
181
  XGetter(info, 0);
182 183 184
}


185
static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
186 187 188
  CHECK(
      x_receiver->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
          .FromJust());
189 190 191 192 193 194
  XGetter(info, 1);
}


template<class Info>
static void XSetter(Local<Value> value, const Info& info, int offset) {
195
  v8::Isolate* isolate = CcTest::isolate();
196
  CHECK_EQ(isolate, info.GetIsolate());
197 198 199 200 201 202
  CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.This())
            .FromJust());
  CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
            .FromJust());
  x_register[offset] =
      value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
203
  info.GetReturnValue().Set(v8_num(-1));
204 205 206 207 208 209 210 211 212 213 214 215 216
}


static void XSetter(Local<String> name,
                    Local<Value> value,
                    const v8::PropertyCallbackInfo<void>& info) {
  XSetter(value, info, 0);
}


static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
  CHECK_EQ(1, info.Length());
  XSetter(info[0], info, 1);
217 218 219 220
}


THREADED_TEST(AccessorIC) {
221
  LocalContext context;
222 223
  v8::Isolate* isolate = context->GetIsolate();
  v8::HandleScope scope(isolate);
224
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
225 226
  obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
  obj->SetAccessorProperty(v8_str("x1"),
227 228
                           v8::FunctionTemplate::New(isolate, XGetter),
                           v8::FunctionTemplate::New(isolate, XSetter));
229 230 231 232
  x_holder = obj->NewInstance(context.local()).ToLocalChecked();
  CHECK(context->Global()
            ->Set(context.local(), v8_str("holder"), x_holder)
            .FromJust());
233
  x_receiver = v8::Object::New(isolate);
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
  CHECK(context->Global()
            ->Set(context.local(), v8_str("obj"), x_receiver)
            .FromJust());
  v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(
      CompileRun("obj.__proto__ = holder;"
                 "var result = [];"
                 "var key_0 = 'x0';"
                 "var key_1 = 'x1';"
                 "for (var j = 0; j < 10; j++) {"
                 "  var i = 4*j;"
                 "  result.push(holder.x0 = i);"
                 "  result.push(obj.x0);"
                 "  result.push(holder.x1 = i + 1);"
                 "  result.push(obj.x1);"
                 "  result.push(holder[key_0] = i + 2);"
                 "  result.push(obj[key_0]);"
                 "  result.push(holder[key_1] = i + 3);"
                 "  result.push(obj[key_1]);"
                 "}"
                 "result"));
254
  CHECK_EQ(80u, array->Length());
255
  for (int i = 0; i < 80; i++) {
256 257 258 259 260 261
    v8::Local<Value> entry =
        array->Get(context.local(), v8::Integer::New(isolate, i))
            .ToLocalChecked();
    CHECK(v8::Integer::New(isolate, i / 2)
              ->Equals(context.local(), entry)
              .FromJust());
262 263 264 265 266
  }
}


template <int C>
267 268 269
static void HandleAllocatingGetter(
    Local<String> name,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
270
  ApiTestFuzzer::Fuzz();
271 272 273 274 275 276 277 278
  for (int i = 0; i < C; i++) {
    v8::String::NewFromUtf8(info.GetIsolate(), "foo",
                            v8::NewStringType::kNormal)
        .ToLocalChecked();
  }
  info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo",
                                                    v8::NewStringType::kNormal)
                                .ToLocalChecked());
279 280 281 282
}


THREADED_TEST(HandleScopePop) {
283
  LocalContext context;
284 285
  v8::Isolate* isolate = context->GetIsolate();
  v8::HandleScope scope(isolate);
286
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
287 288
  obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
  obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
289 290 291 292
  v8::Local<v8::Object> inst =
      obj->NewInstance(context.local()).ToLocalChecked();
  CHECK(
      context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
293 294
  int count_before =
      i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
295
  {
296
    v8::HandleScope scope(isolate);
297 298 299 300 301 302
    CompileRun(
        "for (var i = 0; i < 1000; i++) {"
        "  obj.one;"
        "  obj.many;"
        "}");
  }
303 304
  int count_after =
      i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
305 306 307
  CHECK_EQ(count_before, count_after);
}

308 309 310
static void CheckAccessorArgsCorrect(
    Local<String> name,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
311
  CHECK(info.GetIsolate() == CcTest::isolate());
312
  CHECK(info.This() == info.Holder());
313 314 315
  CHECK(info.Data()
            ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
            .FromJust());
316
  ApiTestFuzzer::Fuzz();
317
  CHECK(info.GetIsolate() == CcTest::isolate());
318
  CHECK(info.This() == info.Holder());
319 320 321
  CHECK(info.Data()
            ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
            .FromJust());
322
  CcTest::heap()->CollectAllGarbage();
323
  CHECK(info.GetIsolate() == CcTest::isolate());
324
  CHECK(info.This() == info.Holder());
325 326 327
  CHECK(info.Data()
            ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
            .FromJust());
328
  info.GetReturnValue().Set(17);
329 330
}

331

332
THREADED_TEST(DirectCall) {
333
  LocalContext context;
334 335
  v8::Isolate* isolate = context->GetIsolate();
  v8::HandleScope scope(isolate);
336 337 338 339 340 341 342 343 344
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
  obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, NULL,
                   v8_str("data"));
  v8::Local<v8::Object> inst =
      obj->NewInstance(context.local()).ToLocalChecked();
  CHECK(
      context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
  Local<Script> scr =
      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 353
static void EmptyGetter(Local<String> name,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
354 355 356
  CheckAccessorArgsCorrect(name, info);
  ApiTestFuzzer::Fuzz();
  CheckAccessorArgsCorrect(name, info);
357
  info.GetReturnValue().Set(v8::Local<v8::Value>());
358 359
}

360

361
THREADED_TEST(EmptyResult) {
362
  LocalContext context;
363 364
  v8::Isolate* isolate = context->GetIsolate();
  v8::HandleScope scope(isolate);
365 366 367 368 369 370
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
  obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8_str("data"));
  v8::Local<v8::Object> inst =
      obj->NewInstance(context.local()).ToLocalChecked();
  CHECK(
      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 381 382
  }
}


THREADED_TEST(NoReuseRegress) {
  // Check that the IC generated for the one test doesn't get reused
  // for the other.
383 384
  v8::Isolate* isolate = CcTest::isolate();
  v8::HandleScope scope(isolate);
385
  {
386 387
    v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8_str("data"));
388
    LocalContext context;
389 390 391 392 393 394 395
    v8::Local<v8::Object> inst =
        obj->NewInstance(context.local()).ToLocalChecked();
    CHECK(context->Global()
              ->Set(context.local(), v8_str("obj"), inst)
              .FromJust());
    Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
                            .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 403 404
    v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
    obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, NULL,
                     v8_str("data"));
405
    LocalContext context;
406 407 408 409 410 411 412
    v8::Local<v8::Object> inst =
        obj->NewInstance(context.local()).ToLocalChecked();
    CHECK(context->Global()
              ->Set(context.local(), v8_str("obj"), inst)
              .FromJust());
    Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
                            .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 422 423
static void ThrowingGetAccessor(
    Local<String> name,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
424
  ApiTestFuzzer::Fuzz();
425
  info.GetIsolate()->ThrowException(v8_str("g"));
426 427 428 429 430
}


static void ThrowingSetAccessor(Local<String> name,
                                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 439
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
440
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
441 442 443 444 445
  obj->SetAccessor(v8_str("x"),
                   ThrowingGetAccessor,
                   ThrowingSetAccessor,
                   Local<Value>());

446 447 448 449
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
450 451 452

  // Use the throwing property setter/getter in a loop to force
  // the accessor ICs to be initialized.
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
  v8::Local<Value> result;
  result = Script::Compile(env.local(),
                           v8_str("var result = '';"
                                  "for (var i = 0; i < 5; i++) {"
                                  "  try { obj.x; } catch (e) { result += e; }"
                                  "}; result"))
               .ToLocalChecked()
               ->Run(env.local())
               .ToLocalChecked();
  CHECK(v8_str("ggggg")->Equals(env.local(), result).FromJust());

  result =
      Script::Compile(env.local(),
                      v8_str("var result = '';"
                             "for (var i = 0; i < 5; i++) {"
                             "  try { obj.x = i; } catch (e) { result += e; }"
                             "}; result"))
          .ToLocalChecked()
          ->Run(env.local())
          .ToLocalChecked();
  CHECK(v8_str("01234")->Equals(env.local(), result).FromJust());
474 475 476
}


477 478
static void AllocGetter(Local<String> name,
                        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 487
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
488
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
489
  obj->SetAccessor(v8_str("xxx"), AllocGetter);
490 491 492 493 494 495 496 497 498 499 500 501 502
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
  Script::Compile(env.local(), v8_str("var last = [];"
                                      "for (var i = 0; i < 2048; i++) {"
                                      "  var result = obj.xxx;"
                                      "  result[0] = last;"
                                      "  last = result;"
                                      "}"))
      .ToLocalChecked()
      ->Run(env.local())
      .ToLocalChecked();
503 504 505
}


506 507
static void StackCheck(Local<String> name,
                       const v8::PropertyCallbackInfo<v8::Value>& info) {
508
  i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
509 510 511
  for (int i = 0; !iter.done(); i++) {
    i::StackFrame* frame = iter.frame();
    CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
512
    i::Code* code = frame->LookupCode();
513
    CHECK(code->IsCode());
514 515 516 517 518 519 520 521
    i::Address pc = frame->pc();
    CHECK(code->contains(pc));
    iter.Advance();
  }
}


THREADED_TEST(StackIteration) {
522
  LocalContext env;
523 524
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
525
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
526 527
  i::StringStream::ClearMentionedObjectCache(
      reinterpret_cast<i::Isolate*>(isolate));
528
  obj->SetAccessor(v8_str("xxx"), StackCheck);
529 530 531 532 533 534 535 536 537 538 539 540 541
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
  Script::Compile(env.local(), v8_str("function foo() {"
                                      "  return obj.xxx;"
                                      "}"
                                      "for (var i = 0; i < 100; i++) {"
                                      "  foo();"
                                      "}"))
      .ToLocalChecked()
      ->Run(env.local())
      .ToLocalChecked();
542
}
543 544


545 546
static void AllocateHandles(Local<String> name,
                            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 555 556
}


THREADED_TEST(HandleScopeSegment) {
  // Check that we can return values past popping of handle scope
  // segments.
557
  LocalContext env;
558 559
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
560
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
561
  obj->SetAccessor(v8_str("xxx"), AllocateHandles);
562 563 564 565 566 567 568 569 570 571 572 573 574
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
  v8::Local<v8::Value> result =
      Script::Compile(env.local(), v8_str("var result;"
                                          "for (var i = 0; i < 4; i++)"
                                          "  result = obj.xxx;"
                                          "result;"))
          .ToLocalChecked()
          ->Run(env.local())
          .ToLocalChecked();
  CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
575
}
576 577


578
void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
579 580 581
  v8::Local<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
  CHECK(array->Set(info.GetIsolate()->GetCurrentContext(), 0, v8_str("regress"))
            .FromJust());
582
  info.GetReturnValue().Set(array);
583 584 585
}


586
void JSONStringifyGetter(Local<Name> name,
587 588
                         const v8::PropertyCallbackInfo<v8::Value>& info) {
  info.GetReturnValue().Set(v8_str("crbug-161028"));
589 590 591 592 593
}


THREADED_TEST(JSONStringifyNamedInterceptorObject) {
  LocalContext env;
594 595
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
596

597
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
598 599
  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator));
600 601 602 603 604 605 606 607
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
  v8::Local<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
  CHECK(CompileRun("JSON.stringify(obj)")
            ->Equals(env.local(), expected)
            .FromJust());
608
}
609 610


611 612 613 614 615 616 617 618 619
static v8::Local<v8::Context> expected_current_context;


static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
  ApiTestFuzzer::Fuzz();
  CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
}


620
THREADED_TEST(AccessorPropertyCrossContext) {
621 622 623
  LocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
624 625
  v8::Local<v8::Function> fun =
      v8::Function::New(env.local(), check_contexts).ToLocalChecked();
626
  LocalContext switch_context;
627 628 629
  CHECK(switch_context->Global()
            ->Set(switch_context.local(), v8_str("fun"), fun)
            .FromJust());
630
  v8::TryCatch try_catch(isolate);
631
  expected_current_context = env.local();
632 633 634 635 636
  CompileRun(
      "var o = Object.create(null, { n: { get:fun } });"
      "for (var i = 0; i < 10; i++) o.n;");
  CHECK(!try_catch.HasCaught());
}
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654


THREADED_TEST(GlobalObjectAccessor) {
  LocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  CompileRun(
      "var set_value = 1;"
      "Object.defineProperty(this.__proto__, 'x', {"
      "    get : function() { return this; },"
      "    set : function() { set_value = this; }"
      "});"
      "function getter() { return x; }"
      "function setter() { x = 1; }"
      "for (var i = 0; i < 4; i++) { getter(); setter(); }");
  CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
  CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
}
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673


static void EmptyGetter(Local<Name> name,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
  ApiTestFuzzer::Fuzz();
}


static void OneProperty(Local<String> name,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
  ApiTestFuzzer::Fuzz();
  info.GetReturnValue().Set(v8_num(1));
}


THREADED_TEST(Regress433458) {
  LocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
674
  v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
675 676
  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
  obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
677 678 679 680
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
681 682 683 684
  CompileRun(
      "Object.defineProperty(obj, 'prop', { writable: false });"
      "Object.defineProperty(obj, 'prop', { writable: true });");
}
685 686 687 688


static bool security_check_value = false;

689
static bool SecurityTestCallback(Local<v8::Context> accessing_context,
690 691
                                 Local<v8::Object> accessed_object,
                                 Local<v8::Value> data) {
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  return security_check_value;
}


TEST(PrototypeGetterAccessCheck) {
  i::FLAG_allow_natives_syntax = true;
  LocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  auto fun_templ = v8::FunctionTemplate::New(isolate);
  auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property);
  getter_templ->SetAcceptAnyReceiver(false);
  fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"),
                                                     getter_templ);
  auto obj_templ = v8::ObjectTemplate::New(isolate);
707
  obj_templ->SetAccessCheckCallback(SecurityTestCallback);
708 709 710 711 712 713 714 715 716 717 718 719
  CHECK(env->Global()
            ->Set(env.local(), v8_str("Fun"),
                  fun_templ->GetFunction(env.local()).ToLocalChecked())
            .FromJust());
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj"),
                  obj_templ->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
  CHECK(env->Global()
            ->Set(env.local(), v8_str("obj2"),
                  obj_templ->NewInstance(env.local()).ToLocalChecked())
            .FromJust());
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776

  security_check_value = true;
  CompileRun("var proto = new Fun();");
  CompileRun("obj.__proto__ = proto;");
  ExpectInt32("proto.foo", 907);

  // Test direct.
  security_check_value = true;
  ExpectInt32("obj.foo", 907);
  security_check_value = false;
  {
    v8::TryCatch try_catch(isolate);
    CompileRun("obj.foo");
    CHECK(try_catch.HasCaught());
  }

  // Test through call.
  security_check_value = true;
  ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907);
  security_check_value = false;
  {
    v8::TryCatch try_catch(isolate);
    CompileRun("proto.__lookupGetter__('foo').call(obj)");
    CHECK(try_catch.HasCaught());
  }

  // Test ics.
  CompileRun(
      "function f() {"
      "   var x;"
      "  for (var i = 0; i < 4; i++) {"
      "    x = obj.foo;"
      "  }"
      "  return x;"
      "}");

  security_check_value = true;
  ExpectInt32("f()", 907);
  security_check_value = false;
  {
    v8::TryCatch try_catch(isolate);
    CompileRun("f();");
    CHECK(try_catch.HasCaught());
  }

  // Test crankshaft.
  CompileRun("%OptimizeFunctionOnNextCall(f);");

  security_check_value = true;
  ExpectInt32("f()", 907);
  security_check_value = false;
  {
    v8::TryCatch try_catch(isolate);
    CompileRun("f();");
    CHECK(try_catch.HasCaught());
  }
}