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 <climits>
     29 #include <csignal>
     30 #include <map>
     31 #include <string>
     32 
     33 #include "test/cctest/test-api.h"
     34 
     35 #if V8_OS_POSIX
     36 #include <unistd.h>  // NOLINT
     37 #endif
     38 
     39 #include "include/v8-util.h"
     40 #include "src/api.h"
     41 #include "src/arguments.h"
     42 #include "src/base/platform/platform.h"
     43 #include "src/base/smart-pointers.h"
     44 #include "src/compilation-cache.h"
     45 #include "src/debug/debug.h"
     46 #include "src/execution.h"
     47 #include "src/futex-emulation.h"
     48 #include "src/objects.h"
     49 #include "src/parsing/parser.h"
     50 #include "src/profiler/cpu-profiler.h"
     51 #include "src/unicode-inl.h"
     52 #include "src/utils.h"
     53 #include "src/vm-state.h"
     54 #include "test/cctest/heap/heap-tester.h"
     55 #include "test/cctest/heap/heap-utils.h"
     56 
     57 static const bool kLogThreading = false;
     58 
     59 using ::v8::Boolean;
     60 using ::v8::BooleanObject;
     61 using ::v8::Context;
     62 using ::v8::Extension;
     63 using ::v8::Function;
     64 using ::v8::FunctionTemplate;
     65 using ::v8::HandleScope;
     66 using ::v8::Local;
     67 using ::v8::Maybe;
     68 using ::v8::Message;
     69 using ::v8::MessageCallback;
     70 using ::v8::Name;
     71 using ::v8::None;
     72 using ::v8::Object;
     73 using ::v8::ObjectTemplate;
     74 using ::v8::Persistent;
     75 using ::v8::PropertyAttribute;
     76 using ::v8::Script;
     77 using ::v8::StackTrace;
     78 using ::v8::String;
     79 using ::v8::Symbol;
     80 using ::v8::TryCatch;
     81 using ::v8::Undefined;
     82 using ::v8::UniqueId;
     83 using ::v8::V8;
     84 using ::v8::Value;
     85 
     86 
     87 #define THREADED_PROFILED_TEST(Name)                                 \
     88   static void Test##Name();                                          \
     89   TEST(Name##WithProfiler) {                                         \
     90     RunWithProfiler(&Test##Name);                                    \
     91   }                                                                  \
     92   THREADED_TEST(Name)
     93 
     94 
     95 void RunWithProfiler(void (*test)()) {
     96   LocalContext env;
     97   v8::HandleScope scope(env->GetIsolate());
     98   v8::Local<v8::String> profile_name = v8_str("my_profile1");
     99   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
    100 
    101   cpu_profiler->StartProfiling(profile_name);
    102   (*test)();
    103   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
    104 }
    105 
    106 
    107 static int signature_callback_count;
    108 static Local<Value> signature_expected_receiver;
    109 static void IncrementingSignatureCallback(
    110     const v8::FunctionCallbackInfo<v8::Value>& args) {
    111   ApiTestFuzzer::Fuzz();
    112   signature_callback_count++;
    113   CHECK(signature_expected_receiver->Equals(
    114                                        args.GetIsolate()->GetCurrentContext(),
    115                                        args.Holder())
    116             .FromJust());
    117   CHECK(signature_expected_receiver->Equals(
    118                                        args.GetIsolate()->GetCurrentContext(),
    119                                        args.This())
    120             .FromJust());
    121   v8::Local<v8::Array> result =
    122       v8::Array::New(args.GetIsolate(), args.Length());
    123   for (int i = 0; i < args.Length(); i++) {
    124     CHECK(result->Set(args.GetIsolate()->GetCurrentContext(),
    125                       v8::Integer::New(args.GetIsolate(), i), args[i])
    126               .FromJust());
    127   }
    128   args.GetReturnValue().Set(result);
    129 }
    130 
    131 
    132 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
    133   info.GetReturnValue().Set(42);
    134 }
    135 
    136 
    137 // Tests that call v8::V8::Dispose() cannot be threaded.
    138 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
    139   CHECK(v8::V8::Initialize());
    140   CHECK(v8::V8::Dispose());
    141 }
    142 
    143 
    144 // Tests that call v8::V8::Dispose() cannot be threaded.
    145 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
    146   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    147   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
    148   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    149   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
    150   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    151 }
    152 
    153 
    154 THREADED_TEST(Handles) {
    155   v8::HandleScope scope(CcTest::isolate());
    156   Local<Context> local_env;
    157   {
    158     LocalContext env;
    159     local_env = env.local();
    160   }
    161 
    162   // Local context should still be live.
    163   CHECK(!local_env.IsEmpty());
    164   local_env->Enter();
    165 
    166   v8::Local<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
    167   CHECK(!undef.IsEmpty());
    168   CHECK(undef->IsUndefined());
    169 
    170   const char* source = "1 + 2 + 3";
    171   Local<Script> script = v8_compile(source);
    172   CHECK_EQ(6, v8_run_int32value(script));
    173 
    174   local_env->Exit();
    175 }
    176 
    177 
    178 THREADED_TEST(IsolateOfContext) {
    179   v8::HandleScope scope(CcTest::isolate());
    180   v8::Local<Context> env = Context::New(CcTest::isolate());
    181 
    182   CHECK(!env->GetIsolate()->InContext());
    183   CHECK(env->GetIsolate() == CcTest::isolate());
    184   env->Enter();
    185   CHECK(env->GetIsolate()->InContext());
    186   CHECK(env->GetIsolate() == CcTest::isolate());
    187   env->Exit();
    188   CHECK(!env->GetIsolate()->InContext());
    189   CHECK(env->GetIsolate() == CcTest::isolate());
    190 }
    191 
    192 
    193 static void TestSignature(const char* loop_js, Local<Value> receiver,
    194                           v8::Isolate* isolate) {
    195   i::ScopedVector<char> source(200);
    196   i::SNPrintF(source,
    197               "for (var i = 0; i < 10; i++) {"
    198               "  %s"
    199               "}",
    200               loop_js);
    201   signature_callback_count = 0;
    202   signature_expected_receiver = receiver;
    203   bool expected_to_throw = receiver.IsEmpty();
    204   v8::TryCatch try_catch(isolate);
    205   CompileRun(source.start());
    206   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
    207   if (!expected_to_throw) {
    208     CHECK_EQ(10, signature_callback_count);
    209   } else {
    210     CHECK(v8_str("TypeError: Illegal invocation")
    211               ->Equals(isolate->GetCurrentContext(),
    212                        try_catch.Exception()
    213                            ->ToString(isolate->GetCurrentContext())
    214                            .ToLocalChecked())
    215               .FromJust());
    216   }
    217 }
    218 
    219 
    220 THREADED_TEST(ReceiverSignature) {
    221   LocalContext env;
    222   v8::Isolate* isolate = env->GetIsolate();
    223   v8::HandleScope scope(isolate);
    224   // Setup templates.
    225   v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
    226   v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun);
    227   v8::Local<v8::FunctionTemplate> callback_sig = v8::FunctionTemplate::New(
    228       isolate, IncrementingSignatureCallback, Local<Value>(), sig);
    229   v8::Local<v8::FunctionTemplate> callback =
    230       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
    231   v8::Local<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
    232   sub_fun->Inherit(fun);
    233   v8::Local<v8::FunctionTemplate> unrel_fun =
    234       v8::FunctionTemplate::New(isolate);
    235   // Install properties.
    236   v8::Local<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
    237   fun_proto->Set(v8_str("prop_sig"), callback_sig);
    238   fun_proto->Set(v8_str("prop"), callback);
    239   fun_proto->SetAccessorProperty(
    240       v8_str("accessor_sig"), callback_sig, callback_sig);
    241   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
    242   // Instantiate templates.
    243   Local<Value> fun_instance =
    244       fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
    245   Local<Value> sub_fun_instance =
    246       sub_fun->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
    247   // Setup global variables.
    248   CHECK(env->Global()
    249             ->Set(env.local(), v8_str("Fun"),
    250                   fun->GetFunction(env.local()).ToLocalChecked())
    251             .FromJust());
    252   CHECK(env->Global()
    253             ->Set(env.local(), v8_str("UnrelFun"),
    254                   unrel_fun->GetFunction(env.local()).ToLocalChecked())
    255             .FromJust());
    256   CHECK(env->Global()
    257             ->Set(env.local(), v8_str("fun_instance"), fun_instance)
    258             .FromJust());
    259   CHECK(env->Global()
    260             ->Set(env.local(), v8_str("sub_fun_instance"), sub_fun_instance)
    261             .FromJust());
    262   CompileRun(
    263       "var accessor_sig_key = 'accessor_sig';"
    264       "var accessor_key = 'accessor';"
    265       "var prop_sig_key = 'prop_sig';"
    266       "var prop_key = 'prop';"
    267       ""
    268       "function copy_props(obj) {"
    269       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
    270       "  var source = Fun.prototype;"
    271       "  for (var i in keys) {"
    272       "    var key = keys[i];"
    273       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
    274       "    Object.defineProperty(obj, key, desc);"
    275       "  }"
    276       "}"
    277       ""
    278       "var obj = {};"
    279       "copy_props(obj);"
    280       "var unrel = new UnrelFun();"
    281       "copy_props(unrel);");
    282   // Test with and without ICs
    283   const char* test_objects[] = {
    284       "fun_instance", "sub_fun_instance", "obj", "unrel" };
    285   unsigned bad_signature_start_offset = 2;
    286   for (unsigned i = 0; i < arraysize(test_objects); i++) {
    287     i::ScopedVector<char> source(200);
    288     i::SNPrintF(
    289         source, "var test_object = %s; test_object", test_objects[i]);
    290     Local<Value> test_object = CompileRun(source.start());
    291     TestSignature("test_object.prop();", test_object, isolate);
    292     TestSignature("test_object.accessor;", test_object, isolate);
    293     TestSignature("test_object[accessor_key];", test_object, isolate);
    294     TestSignature("test_object.accessor = 1;", test_object, isolate);
    295     TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
    296     if (i >= bad_signature_start_offset) test_object = Local<Value>();
    297     TestSignature("test_object.prop_sig();", test_object, isolate);
    298     TestSignature("test_object.accessor_sig;", test_object, isolate);
    299     TestSignature("test_object[accessor_sig_key];", test_object, isolate);
    300     TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
    301     TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
    302   }
    303 }
    304 
    305 
    306 THREADED_TEST(HulIgennem) {
    307   LocalContext env;
    308   v8::Isolate* isolate = env->GetIsolate();
    309   v8::HandleScope scope(isolate);
    310   v8::Local<v8::Primitive> undef = v8::Undefined(isolate);
    311   Local<String> undef_str = undef->ToString(env.local()).ToLocalChecked();
    312   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
    313   undef_str->WriteUtf8(value);
    314   CHECK_EQ(0, strcmp(value, "undefined"));
    315   i::DeleteArray(value);
    316 }
    317 
    318 
    319 THREADED_TEST(Access) {
    320   LocalContext env;
    321   v8::Isolate* isolate = env->GetIsolate();
    322   v8::HandleScope scope(isolate);
    323   Local<v8::Object> obj = v8::Object::New(isolate);
    324   Local<Value> foo_before =
    325       obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
    326   CHECK(foo_before->IsUndefined());
    327   Local<String> bar_str = v8_str("bar");
    328   CHECK(obj->Set(env.local(), v8_str("foo"), bar_str).FromJust());
    329   Local<Value> foo_after =
    330       obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
    331   CHECK(!foo_after->IsUndefined());
    332   CHECK(foo_after->IsString());
    333   CHECK(bar_str->Equals(env.local(), foo_after).FromJust());
    334 }
    335 
    336 
    337 THREADED_TEST(AccessElement) {
    338   LocalContext env;
    339   v8::HandleScope scope(env->GetIsolate());
    340   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
    341   Local<Value> before = obj->Get(env.local(), 1).ToLocalChecked();
    342   CHECK(before->IsUndefined());
    343   Local<String> bar_str = v8_str("bar");
    344   CHECK(obj->Set(env.local(), 1, bar_str).FromJust());
    345   Local<Value> after = obj->Get(env.local(), 1).ToLocalChecked();
    346   CHECK(!after->IsUndefined());
    347   CHECK(after->IsString());
    348   CHECK(bar_str->Equals(env.local(), after).FromJust());
    349 
    350   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
    351   CHECK(v8_str("a")
    352             ->Equals(env.local(), value->Get(env.local(), 0).ToLocalChecked())
    353             .FromJust());
    354   CHECK(v8_str("b")
    355             ->Equals(env.local(), value->Get(env.local(), 1).ToLocalChecked())
    356             .FromJust());
    357 }
    358 
    359 
    360 THREADED_TEST(Script) {
    361   LocalContext env;
    362   v8::HandleScope scope(env->GetIsolate());
    363   const char* source = "1 + 2 + 3";
    364   Local<Script> script = v8_compile(source);
    365   CHECK_EQ(6, v8_run_int32value(script));
    366 }
    367 
    368 
    369 class TestResource: public String::ExternalStringResource {
    370  public:
    371   explicit TestResource(uint16_t* data, int* counter = NULL,
    372                         bool owning_data = true)
    373       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
    374     while (data[length_]) ++length_;
    375   }
    376 
    377   ~TestResource() {
    378     if (owning_data_) i::DeleteArray(data_);
    379     if (counter_ != NULL) ++*counter_;
    380   }
    381 
    382   const uint16_t* data() const {
    383     return data_;
    384   }
    385 
    386   size_t length() const {
    387     return length_;
    388   }
    389 
    390  private:
    391   uint16_t* data_;
    392   size_t length_;
    393   int* counter_;
    394   bool owning_data_;
    395 };
    396 
    397 
    398 class TestOneByteResource : public String::ExternalOneByteStringResource {
    399  public:
    400   explicit TestOneByteResource(const char* data, int* counter = NULL,
    401                                size_t offset = 0)
    402       : orig_data_(data),
    403         data_(data + offset),
    404         length_(strlen(data) - offset),
    405         counter_(counter) {}
    406 
    407   ~TestOneByteResource() {
    408     i::DeleteArray(orig_data_);
    409     if (counter_ != NULL) ++*counter_;
    410   }
    411 
    412   const char* data() const {
    413     return data_;
    414   }
    415 
    416   size_t length() const {
    417     return length_;
    418   }
    419 
    420  private:
    421   const char* orig_data_;
    422   const char* data_;
    423   size_t length_;
    424   int* counter_;
    425 };
    426 
    427 
    428 THREADED_TEST(ScriptUsingStringResource) {
    429   int dispose_count = 0;
    430   const char* c_source = "1 + 2 * 3";
    431   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
    432   {
    433     LocalContext env;
    434     v8::HandleScope scope(env->GetIsolate());
    435     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
    436     Local<String> source =
    437         String::NewExternalTwoByte(env->GetIsolate(), resource)
    438             .ToLocalChecked();
    439     Local<Script> script = v8_compile(source);
    440     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    441     CHECK(value->IsNumber());
    442     CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
    443     CHECK(source->IsExternal());
    444     CHECK_EQ(resource,
    445              static_cast<TestResource*>(source->GetExternalStringResource()));
    446     String::Encoding encoding = String::UNKNOWN_ENCODING;
    447     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    448              source->GetExternalStringResourceBase(&encoding));
    449     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
    450     CcTest::heap()->CollectAllGarbage();
    451     CHECK_EQ(0, dispose_count);
    452   }
    453   CcTest::i_isolate()->compilation_cache()->Clear();
    454   CcTest::heap()->CollectAllAvailableGarbage();
    455   CHECK_EQ(1, dispose_count);
    456 }
    457 
    458 
    459 THREADED_TEST(ScriptUsingOneByteStringResource) {
    460   int dispose_count = 0;
    461   const char* c_source = "1 + 2 * 3";
    462   {
    463     LocalContext env;
    464     v8::HandleScope scope(env->GetIsolate());
    465     TestOneByteResource* resource =
    466         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
    467     Local<String> source =
    468         String::NewExternalOneByte(env->GetIsolate(), resource)
    469             .ToLocalChecked();
    470     CHECK(source->IsExternalOneByte());
    471     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    472              source->GetExternalOneByteStringResource());
    473     String::Encoding encoding = String::UNKNOWN_ENCODING;
    474     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    475              source->GetExternalStringResourceBase(&encoding));
    476     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
    477     Local<Script> script = v8_compile(source);
    478     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    479     CHECK(value->IsNumber());
    480     CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
    481     CcTest::heap()->CollectAllGarbage();
    482     CHECK_EQ(0, dispose_count);
    483   }
    484   CcTest::i_isolate()->compilation_cache()->Clear();
    485   CcTest::heap()->CollectAllAvailableGarbage();
    486   CHECK_EQ(1, dispose_count);
    487 }
    488 
    489 
    490 THREADED_TEST(ScriptMakingExternalString) {
    491   int dispose_count = 0;
    492   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
    493   {
    494     LocalContext env;
    495     v8::HandleScope scope(env->GetIsolate());
    496     Local<String> source =
    497         String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
    498                                v8::NewStringType::kNormal)
    499             .ToLocalChecked();
    500     // Trigger GCs so that the newly allocated string moves to old gen.
    501     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    502     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    503     CHECK_EQ(source->IsExternal(), false);
    504     CHECK_EQ(source->IsExternalOneByte(), false);
    505     String::Encoding encoding = String::UNKNOWN_ENCODING;
    506     CHECK(!source->GetExternalStringResourceBase(&encoding));
    507     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
    508     bool success = source->MakeExternal(new TestResource(two_byte_source,
    509                                                          &dispose_count));
    510     CHECK(success);
    511     Local<Script> script = v8_compile(source);
    512     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    513     CHECK(value->IsNumber());
    514     CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
    515     CcTest::heap()->CollectAllGarbage();
    516     CHECK_EQ(0, dispose_count);
    517   }
    518   CcTest::i_isolate()->compilation_cache()->Clear();
    519   CcTest::heap()->CollectAllGarbage();
    520   CHECK_EQ(1, dispose_count);
    521 }
    522 
    523 
    524 THREADED_TEST(ScriptMakingExternalOneByteString) {
    525   int dispose_count = 0;
    526   const char* c_source = "1 + 2 * 3";
    527   {
    528     LocalContext env;
    529     v8::HandleScope scope(env->GetIsolate());
    530     Local<String> source = v8_str(c_source);
    531     // Trigger GCs so that the newly allocated string moves to old gen.
    532     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    533     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    534     bool success = source->MakeExternal(
    535         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
    536     CHECK(success);
    537     Local<Script> script = v8_compile(source);
    538     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    539     CHECK(value->IsNumber());
    540     CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
    541     CcTest::heap()->CollectAllGarbage();
    542     CHECK_EQ(0, dispose_count);
    543   }
    544   CcTest::i_isolate()->compilation_cache()->Clear();
    545   CcTest::heap()->CollectAllGarbage();
    546   CHECK_EQ(1, dispose_count);
    547 }
    548 
    549 
    550 TEST(MakingExternalStringConditions) {
    551   LocalContext env;
    552   v8::HandleScope scope(env->GetIsolate());
    553 
    554   // Free some space in the new space so that we can check freshness.
    555   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    556   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    557 
    558   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
    559   Local<String> local_string =
    560       String::NewFromTwoByte(env->GetIsolate(), two_byte_string,
    561                              v8::NewStringType::kNormal)
    562           .ToLocalChecked();
    563   i::DeleteArray(two_byte_string);
    564 
    565   // We should refuse to externalize new space strings.
    566   CHECK(!local_string->CanMakeExternal());
    567   // Trigger GCs so that the newly allocated string moves to old gen.
    568   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    569   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    570   // Old space strings should be accepted.
    571   CHECK(local_string->CanMakeExternal());
    572 }
    573 
    574 
    575 TEST(MakingExternalOneByteStringConditions) {
    576   LocalContext env;
    577   v8::HandleScope scope(env->GetIsolate());
    578 
    579   // Free some space in the new space so that we can check freshness.
    580   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    581   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    582 
    583   Local<String> local_string = v8_str("s1");
    584   // We should refuse to externalize new space strings.
    585   CHECK(!local_string->CanMakeExternal());
    586   // Trigger GCs so that the newly allocated string moves to old gen.
    587   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    588   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    589   // Old space strings should be accepted.
    590   CHECK(local_string->CanMakeExternal());
    591 }
    592 
    593 
    594 TEST(MakingExternalUnalignedOneByteString) {
    595   LocalContext env;
    596   v8::HandleScope scope(env->GetIsolate());
    597 
    598   CompileRun("function cons(a, b) { return a + b; }"
    599              "function slice(a) { return a.substring(1); }");
    600   // Create a cons string that will land in old pointer space.
    601   Local<String> cons = Local<String>::Cast(CompileRun(
    602       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
    603   // Create a sliced string that will land in old pointer space.
    604   Local<String> slice = Local<String>::Cast(CompileRun(
    605       "slice('abcdefghijklmnopqrstuvwxyz');"));
    606 
    607   // Trigger GCs so that the newly allocated string moves to old gen.
    608   i::heap::SimulateFullSpace(CcTest::heap()->old_space());
    609   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    610   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    611 
    612   // Turn into external string with unaligned resource data.
    613   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
    614   bool success =
    615       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
    616   CHECK(success);
    617   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
    618   success =
    619       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
    620   CHECK(success);
    621 
    622   // Trigger GCs and force evacuation.
    623   CcTest::heap()->CollectAllGarbage();
    624   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
    625 }
    626 
    627 
    628 THREADED_TEST(UsingExternalString) {
    629   i::Factory* factory = CcTest::i_isolate()->factory();
    630   {
    631     v8::HandleScope scope(CcTest::isolate());
    632     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    633     Local<String> string =
    634         String::NewExternalTwoByte(CcTest::isolate(),
    635                                    new TestResource(two_byte_string))
    636             .ToLocalChecked();
    637     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    638     // Trigger GCs so that the newly allocated string moves to old gen.
    639     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    640     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    641     i::Handle<i::String> isymbol =
    642         factory->InternalizeString(istring);
    643     CHECK(isymbol->IsInternalizedString());
    644   }
    645   CcTest::heap()->CollectAllGarbage();
    646   CcTest::heap()->CollectAllGarbage();
    647 }
    648 
    649 
    650 THREADED_TEST(UsingExternalOneByteString) {
    651   i::Factory* factory = CcTest::i_isolate()->factory();
    652   {
    653     v8::HandleScope scope(CcTest::isolate());
    654     const char* one_byte_string = "test string";
    655     Local<String> string =
    656         String::NewExternalOneByte(
    657             CcTest::isolate(),
    658             new TestOneByteResource(i::StrDup(one_byte_string)))
    659             .ToLocalChecked();
    660     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    661     // Trigger GCs so that the newly allocated string moves to old gen.
    662     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    663     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    664     i::Handle<i::String> isymbol =
    665         factory->InternalizeString(istring);
    666     CHECK(isymbol->IsInternalizedString());
    667   }
    668   CcTest::heap()->CollectAllGarbage();
    669   CcTest::heap()->CollectAllGarbage();
    670 }
    671 
    672 
    673 class RandomLengthResource : public v8::String::ExternalStringResource {
    674  public:
    675   explicit RandomLengthResource(int length) : length_(length) {}
    676   virtual const uint16_t* data() const { return string_; }
    677   virtual size_t length() const { return length_; }
    678 
    679  private:
    680   uint16_t string_[10];
    681   int length_;
    682 };
    683 
    684 
    685 class RandomLengthOneByteResource
    686     : public v8::String::ExternalOneByteStringResource {
    687  public:
    688   explicit RandomLengthOneByteResource(int length) : length_(length) {}
    689   virtual const char* data() const { return string_; }
    690   virtual size_t length() const { return length_; }
    691 
    692  private:
    693   char string_[10];
    694   int length_;
    695 };
    696 
    697 
    698 THREADED_TEST(NewExternalForVeryLongString) {
    699   auto isolate = CcTest::isolate();
    700   {
    701     v8::HandleScope scope(isolate);
    702     v8::TryCatch try_catch(isolate);
    703     RandomLengthOneByteResource r(1 << 30);
    704     v8::MaybeLocal<v8::String> maybe_str =
    705         v8::String::NewExternalOneByte(isolate, &r);
    706     CHECK(maybe_str.IsEmpty());
    707     CHECK(!try_catch.HasCaught());
    708   }
    709 
    710   {
    711     v8::HandleScope scope(isolate);
    712     v8::TryCatch try_catch(isolate);
    713     RandomLengthResource r(1 << 30);
    714     v8::MaybeLocal<v8::String> maybe_str =
    715         v8::String::NewExternalTwoByte(isolate, &r);
    716     CHECK(maybe_str.IsEmpty());
    717     CHECK(!try_catch.HasCaught());
    718   }
    719 }
    720 
    721 
    722 THREADED_TEST(ScavengeExternalString) {
    723   i::FLAG_stress_compaction = false;
    724   i::FLAG_gc_global = false;
    725   int dispose_count = 0;
    726   bool in_new_space = false;
    727   {
    728     v8::HandleScope scope(CcTest::isolate());
    729     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    730     Local<String> string =
    731         String::NewExternalTwoByte(
    732             CcTest::isolate(),
    733             new TestResource(two_byte_string, &dispose_count))
    734             .ToLocalChecked();
    735     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    736     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    737     in_new_space = CcTest::heap()->InNewSpace(*istring);
    738     CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
    739     CHECK_EQ(0, dispose_count);
    740   }
    741   CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
    742   CHECK_EQ(1, dispose_count);
    743 }
    744 
    745 
    746 THREADED_TEST(ScavengeExternalOneByteString) {
    747   i::FLAG_stress_compaction = false;
    748   i::FLAG_gc_global = false;
    749   int dispose_count = 0;
    750   bool in_new_space = false;
    751   {
    752     v8::HandleScope scope(CcTest::isolate());
    753     const char* one_byte_string = "test string";
    754     Local<String> string =
    755         String::NewExternalOneByte(
    756             CcTest::isolate(),
    757             new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count))
    758             .ToLocalChecked();
    759     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    760     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    761     in_new_space = CcTest::heap()->InNewSpace(*istring);
    762     CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
    763     CHECK_EQ(0, dispose_count);
    764   }
    765   CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
    766   CHECK_EQ(1, dispose_count);
    767 }
    768 
    769 
    770 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
    771  public:
    772   // Only used by non-threaded tests, so it can use static fields.
    773   static int dispose_calls;
    774   static int dispose_count;
    775 
    776   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
    777       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
    778 
    779   void Dispose() {
    780     ++dispose_calls;
    781     if (dispose_) delete this;
    782   }
    783  private:
    784   bool dispose_;
    785 };
    786 
    787 
    788 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
    789 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
    790 
    791 
    792 TEST(ExternalStringWithDisposeHandling) {
    793   const char* c_source = "1 + 2 * 3";
    794 
    795   // Use a stack allocated external string resource allocated object.
    796   TestOneByteResourceWithDisposeControl::dispose_count = 0;
    797   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
    798   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
    799   {
    800     LocalContext env;
    801     v8::HandleScope scope(env->GetIsolate());
    802     Local<String> source =
    803         String::NewExternalOneByte(env->GetIsolate(), &res_stack)
    804             .ToLocalChecked();
    805     Local<Script> script = v8_compile(source);
    806     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    807     CHECK(value->IsNumber());
    808     CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
    809     CcTest::heap()->CollectAllAvailableGarbage();
    810     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
    811   }
    812   CcTest::i_isolate()->compilation_cache()->Clear();
    813   CcTest::heap()->CollectAllAvailableGarbage();
    814   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
    815   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
    816 
    817   // Use a heap allocated external string resource allocated object.
    818   TestOneByteResourceWithDisposeControl::dispose_count = 0;
    819   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
    820   TestOneByteResource* res_heap =
    821       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
    822   {
    823     LocalContext env;
    824     v8::HandleScope scope(env->GetIsolate());
    825     Local<String> source =
    826         String::NewExternalOneByte(env->GetIsolate(), res_heap)
    827             .ToLocalChecked();
    828     Local<Script> script = v8_compile(source);
    829     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    830     CHECK(value->IsNumber());
    831     CHECK_EQ(7, value->Int32Value(env.local()).FromJust());
    832     CcTest::heap()->CollectAllAvailableGarbage();
    833     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
    834   }
    835   CcTest::i_isolate()->compilation_cache()->Clear();
    836   CcTest::heap()->CollectAllAvailableGarbage();
    837   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
    838   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
    839 }
    840 
    841 
    842 THREADED_TEST(StringConcat) {
    843   {
    844     LocalContext env;
    845     v8::HandleScope scope(env->GetIsolate());
    846     const char* one_byte_string_1 = "function a_times_t";
    847     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
    848     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
    849     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
    850     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    851     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    852     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
    853     Local<String> left = v8_str(one_byte_string_1);
    854 
    855     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
    856     Local<String> right =
    857         String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
    858                                v8::NewStringType::kNormal)
    859             .ToLocalChecked();
    860     i::DeleteArray(two_byte_source);
    861 
    862     Local<String> source = String::Concat(left, right);
    863     right = String::NewExternalOneByte(
    864                 env->GetIsolate(),
    865                 new TestOneByteResource(i::StrDup(one_byte_extern_1)))
    866                 .ToLocalChecked();
    867     source = String::Concat(source, right);
    868     right = String::NewExternalTwoByte(
    869                 env->GetIsolate(),
    870                 new TestResource(AsciiToTwoByteString(two_byte_extern_1)))
    871                 .ToLocalChecked();
    872     source = String::Concat(source, right);
    873     right = v8_str(one_byte_string_2);
    874     source = String::Concat(source, right);
    875 
    876     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
    877     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source,
    878                                    v8::NewStringType::kNormal)
    879                 .ToLocalChecked();
    880     i::DeleteArray(two_byte_source);
    881 
    882     source = String::Concat(source, right);
    883     right = String::NewExternalTwoByte(
    884                 env->GetIsolate(),
    885                 new TestResource(AsciiToTwoByteString(two_byte_extern_2)))
    886                 .ToLocalChecked();
    887     source = String::Concat(source, right);
    888     Local<Script> script = v8_compile(source);
    889     Local<Value> value = script->Run(env.local()).ToLocalChecked();
    890     CHECK(value->IsNumber());
    891     CHECK_EQ(68, value->Int32Value(env.local()).FromJust());
    892   }
    893   CcTest::i_isolate()->compilation_cache()->Clear();
    894   CcTest::heap()->CollectAllGarbage();
    895   CcTest::heap()->CollectAllGarbage();
    896 }
    897 
    898 
    899 THREADED_TEST(GlobalProperties) {
    900   LocalContext env;
    901   v8::HandleScope scope(env->GetIsolate());
    902   v8::Local<v8::Object> global = env->Global();
    903   CHECK(global->Set(env.local(), v8_str("pi"), v8_num(3.1415926)).FromJust());
    904   Local<Value> pi = global->Get(env.local(), v8_str("pi")).ToLocalChecked();
    905   CHECK_EQ(3.1415926, pi->NumberValue(env.local()).FromJust());
    906 }
    907 
    908 
    909 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
    910                                  i::Address callback) {
    911   ApiTestFuzzer::Fuzz();
    912   CheckReturnValue(info, callback);
    913   info.GetReturnValue().Set(v8_str("bad value"));
    914   info.GetReturnValue().Set(v8_num(102));
    915 }
    916 
    917 
    918 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
    919   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
    920 }
    921 
    922 
    923 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
    924   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
    925 }
    926 
    927 static void construct_callback(
    928     const v8::FunctionCallbackInfo<Value>& info) {
    929   ApiTestFuzzer::Fuzz();
    930   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
    931   CHECK(
    932       info.This()
    933           ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("x"), v8_num(1))
    934           .FromJust());
    935   CHECK(
    936       info.This()
    937           ->Set(info.GetIsolate()->GetCurrentContext(), v8_str("y"), v8_num(2))
    938           .FromJust());
    939   info.GetReturnValue().Set(v8_str("bad value"));
    940   info.GetReturnValue().Set(info.This());
    941 }
    942 
    943 
    944 static void Return239Callback(
    945     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
    946   ApiTestFuzzer::Fuzz();
    947   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
    948   info.GetReturnValue().Set(v8_str("bad value"));
    949   info.GetReturnValue().Set(v8_num(239));
    950 }
    951 
    952 
    953 template<typename Handler>
    954 static void TestFunctionTemplateInitializer(Handler handler,
    955                                             Handler handler_2) {
    956   // Test constructor calls.
    957   {
    958     LocalContext env;
    959     v8::Isolate* isolate = env->GetIsolate();
    960     v8::HandleScope scope(isolate);
    961 
    962     Local<v8::FunctionTemplate> fun_templ =
    963         v8::FunctionTemplate::New(isolate, handler);
    964     Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
    965     CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
    966     Local<Script> script = v8_compile("obj()");
    967     for (int i = 0; i < 30; i++) {
    968       CHECK_EQ(102, v8_run_int32value(script));
    969     }
    970   }
    971   // Use SetCallHandler to initialize a function template, should work like
    972   // the previous one.
    973   {
    974     LocalContext env;
    975     v8::Isolate* isolate = env->GetIsolate();
    976     v8::HandleScope scope(isolate);
    977 
    978     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
    979     fun_templ->SetCallHandler(handler_2);
    980     Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
    981     CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
    982     Local<Script> script = v8_compile("obj()");
    983     for (int i = 0; i < 30; i++) {
    984       CHECK_EQ(102, v8_run_int32value(script));
    985     }
    986   }
    987 }
    988 
    989 
    990 template<typename Constructor, typename Accessor>
    991 static void TestFunctionTemplateAccessor(Constructor constructor,
    992                                          Accessor accessor) {
    993   LocalContext env;
    994   v8::HandleScope scope(env->GetIsolate());
    995 
    996   Local<v8::FunctionTemplate> fun_templ =
    997       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
    998   fun_templ->SetClassName(v8_str("funky"));
    999   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
   1000   Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
   1001   CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
   1002   Local<Value> result =
   1003       v8_compile("(new obj()).toString()")->Run(env.local()).ToLocalChecked();
   1004   CHECK(v8_str("[object funky]")->Equals(env.local(), result).FromJust());
   1005   CompileRun("var obj_instance = new obj();");
   1006   Local<Script> script;
   1007   script = v8_compile("obj_instance.x");
   1008   for (int i = 0; i < 30; i++) {
   1009     CHECK_EQ(1, v8_run_int32value(script));
   1010   }
   1011   script = v8_compile("obj_instance.m");
   1012   for (int i = 0; i < 30; i++) {
   1013     CHECK_EQ(239, v8_run_int32value(script));
   1014   }
   1015 }
   1016 
   1017 
   1018 THREADED_PROFILED_TEST(FunctionTemplate) {
   1019   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
   1020   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
   1021 }
   1022 
   1023 
   1024 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1025   ApiTestFuzzer::Fuzz();
   1026   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
   1027   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
   1028 }
   1029 
   1030 
   1031 template<typename Callback>
   1032 static void TestSimpleCallback(Callback callback) {
   1033   LocalContext env;
   1034   v8::Isolate* isolate = env->GetIsolate();
   1035   v8::HandleScope scope(isolate);
   1036 
   1037   v8::Local<v8::ObjectTemplate> object_template =
   1038       v8::ObjectTemplate::New(isolate);
   1039   object_template->Set(isolate, "callback",
   1040                        v8::FunctionTemplate::New(isolate, callback));
   1041   v8::Local<v8::Object> object =
   1042       object_template->NewInstance(env.local()).ToLocalChecked();
   1043   CHECK((*env)
   1044             ->Global()
   1045             ->Set(env.local(), v8_str("callback_object"), object)
   1046             .FromJust());
   1047   v8::Local<v8::Script> script;
   1048   script = v8_compile("callback_object.callback(17)");
   1049   for (int i = 0; i < 30; i++) {
   1050     CHECK_EQ(51424, v8_run_int32value(script));
   1051   }
   1052   script = v8_compile("callback_object.callback(17, 24)");
   1053   for (int i = 0; i < 30; i++) {
   1054     CHECK_EQ(51425, v8_run_int32value(script));
   1055   }
   1056 }
   1057 
   1058 
   1059 THREADED_PROFILED_TEST(SimpleCallback) {
   1060   TestSimpleCallback(SimpleCallback);
   1061 }
   1062 
   1063 
   1064 template<typename T>
   1065 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
   1066 
   1067 // constant return values
   1068 static int32_t fast_return_value_int32 = 471;
   1069 static uint32_t fast_return_value_uint32 = 571;
   1070 static const double kFastReturnValueDouble = 2.7;
   1071 // variable return values
   1072 static bool fast_return_value_bool = false;
   1073 enum ReturnValueOddball {
   1074   kNullReturnValue,
   1075   kUndefinedReturnValue,
   1076   kEmptyStringReturnValue
   1077 };
   1078 static ReturnValueOddball fast_return_value_void;
   1079 static bool fast_return_value_object_is_empty = false;
   1080 
   1081 // Helper function to avoid compiler error: insufficient contextual information
   1082 // to determine type when applying FUNCTION_ADDR to a template function.
   1083 static i::Address address_of(v8::FunctionCallback callback) {
   1084   return FUNCTION_ADDR(callback);
   1085 }
   1086 
   1087 template<>
   1088 void FastReturnValueCallback<int32_t>(
   1089     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1090   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
   1091   info.GetReturnValue().Set(fast_return_value_int32);
   1092 }
   1093 
   1094 template<>
   1095 void FastReturnValueCallback<uint32_t>(
   1096     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1097   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
   1098   info.GetReturnValue().Set(fast_return_value_uint32);
   1099 }
   1100 
   1101 template<>
   1102 void FastReturnValueCallback<double>(
   1103     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1104   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
   1105   info.GetReturnValue().Set(kFastReturnValueDouble);
   1106 }
   1107 
   1108 template<>
   1109 void FastReturnValueCallback<bool>(
   1110     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1111   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
   1112   info.GetReturnValue().Set(fast_return_value_bool);
   1113 }
   1114 
   1115 template<>
   1116 void FastReturnValueCallback<void>(
   1117     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1118   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
   1119   switch (fast_return_value_void) {
   1120     case kNullReturnValue:
   1121       info.GetReturnValue().SetNull();
   1122       break;
   1123     case kUndefinedReturnValue:
   1124       info.GetReturnValue().SetUndefined();
   1125       break;
   1126     case kEmptyStringReturnValue:
   1127       info.GetReturnValue().SetEmptyString();
   1128       break;
   1129   }
   1130 }
   1131 
   1132 template<>
   1133 void FastReturnValueCallback<Object>(
   1134     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1135   v8::Local<v8::Object> object;
   1136   if (!fast_return_value_object_is_empty) {
   1137     object = Object::New(info.GetIsolate());
   1138   }
   1139   info.GetReturnValue().Set(object);
   1140 }
   1141 
   1142 template <typename T>
   1143 Local<Value> TestFastReturnValues() {
   1144   LocalContext env;
   1145   v8::Isolate* isolate = env->GetIsolate();
   1146   v8::EscapableHandleScope scope(isolate);
   1147   v8::Local<v8::ObjectTemplate> object_template =
   1148       v8::ObjectTemplate::New(isolate);
   1149   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
   1150   object_template->Set(isolate, "callback",
   1151                        v8::FunctionTemplate::New(isolate, callback));
   1152   v8::Local<v8::Object> object =
   1153       object_template->NewInstance(env.local()).ToLocalChecked();
   1154   CHECK((*env)
   1155             ->Global()
   1156             ->Set(env.local(), v8_str("callback_object"), object)
   1157             .FromJust());
   1158   return scope.Escape(CompileRun("callback_object.callback()"));
   1159 }
   1160 
   1161 
   1162 THREADED_PROFILED_TEST(FastReturnValues) {
   1163   LocalContext env;
   1164   v8::Isolate* isolate = env->GetIsolate();
   1165   v8::HandleScope scope(isolate);
   1166   v8::Local<v8::Value> value;
   1167   // check int32_t and uint32_t
   1168   int32_t int_values[] = {
   1169       0, 234, -723,
   1170       i::Smi::kMinValue, i::Smi::kMaxValue
   1171   };
   1172   for (size_t i = 0; i < arraysize(int_values); i++) {
   1173     for (int modifier = -1; modifier <= 1; modifier++) {
   1174       int int_value = int_values[i] + modifier;
   1175       // check int32_t
   1176       fast_return_value_int32 = int_value;
   1177       value = TestFastReturnValues<int32_t>();
   1178       CHECK(value->IsInt32());
   1179       CHECK_EQ(fast_return_value_int32,
   1180                value->Int32Value(env.local()).FromJust());
   1181       // check uint32_t
   1182       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
   1183       value = TestFastReturnValues<uint32_t>();
   1184       CHECK(value->IsUint32());
   1185       CHECK_EQ(fast_return_value_uint32,
   1186                value->Uint32Value(env.local()).FromJust());
   1187     }
   1188   }
   1189   // check double
   1190   value = TestFastReturnValues<double>();
   1191   CHECK(value->IsNumber());
   1192   CHECK_EQ(kFastReturnValueDouble,
   1193            value->ToNumber(env.local()).ToLocalChecked()->Value());
   1194   // check bool values
   1195   for (int i = 0; i < 2; i++) {
   1196     fast_return_value_bool = i == 0;
   1197     value = TestFastReturnValues<bool>();
   1198     CHECK(value->IsBoolean());
   1199     CHECK_EQ(fast_return_value_bool,
   1200              value->ToBoolean(env.local()).ToLocalChecked()->Value());
   1201   }
   1202   // check oddballs
   1203   ReturnValueOddball oddballs[] = {
   1204       kNullReturnValue,
   1205       kUndefinedReturnValue,
   1206       kEmptyStringReturnValue
   1207   };
   1208   for (size_t i = 0; i < arraysize(oddballs); i++) {
   1209     fast_return_value_void = oddballs[i];
   1210     value = TestFastReturnValues<void>();
   1211     switch (fast_return_value_void) {
   1212       case kNullReturnValue:
   1213         CHECK(value->IsNull());
   1214         break;
   1215       case kUndefinedReturnValue:
   1216         CHECK(value->IsUndefined());
   1217         break;
   1218       case kEmptyStringReturnValue:
   1219         CHECK(value->IsString());
   1220         CHECK_EQ(0, v8::String::Cast(*value)->Length());
   1221         break;
   1222     }
   1223   }
   1224   // check handles
   1225   fast_return_value_object_is_empty = false;
   1226   value = TestFastReturnValues<Object>();
   1227   CHECK(value->IsObject());
   1228   fast_return_value_object_is_empty = true;
   1229   value = TestFastReturnValues<Object>();
   1230   CHECK(value->IsUndefined());
   1231 }
   1232 
   1233 
   1234 THREADED_TEST(FunctionTemplateSetLength) {
   1235   LocalContext env;
   1236   v8::Isolate* isolate = env->GetIsolate();
   1237   v8::HandleScope scope(isolate);
   1238   {
   1239     Local<v8::FunctionTemplate> fun_templ =
   1240         v8::FunctionTemplate::New(isolate, handle_callback, Local<v8::Value>(),
   1241                                   Local<v8::Signature>(), 23);
   1242     Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
   1243     CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
   1244     Local<Script> script = v8_compile("obj.length");
   1245     CHECK_EQ(23, v8_run_int32value(script));
   1246   }
   1247   {
   1248     Local<v8::FunctionTemplate> fun_templ =
   1249         v8::FunctionTemplate::New(isolate, handle_callback);
   1250     fun_templ->SetLength(22);
   1251     Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
   1252     CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
   1253     Local<Script> script = v8_compile("obj.length");
   1254     CHECK_EQ(22, v8_run_int32value(script));
   1255   }
   1256   {
   1257     // Without setting length it defaults to 0.
   1258     Local<v8::FunctionTemplate> fun_templ =
   1259         v8::FunctionTemplate::New(isolate, handle_callback);
   1260     Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
   1261     CHECK(env->Global()->Set(env.local(), v8_str("obj"), fun).FromJust());
   1262     Local<Script> script = v8_compile("obj.length");
   1263     CHECK_EQ(0, v8_run_int32value(script));
   1264   }
   1265 }
   1266 
   1267 
   1268 static void* expected_ptr;
   1269 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1270   void* ptr = v8::External::Cast(*args.Data())->Value();
   1271   CHECK_EQ(expected_ptr, ptr);
   1272   args.GetReturnValue().Set(true);
   1273 }
   1274 
   1275 
   1276 static void TestExternalPointerWrapping() {
   1277   LocalContext env;
   1278   v8::Isolate* isolate = env->GetIsolate();
   1279   v8::HandleScope scope(isolate);
   1280 
   1281   v8::Local<v8::Value> data = v8::External::New(isolate, expected_ptr);
   1282 
   1283   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   1284   CHECK(obj->Set(env.local(), v8_str("func"),
   1285                  v8::FunctionTemplate::New(isolate, callback, data)
   1286                      ->GetFunction(env.local())
   1287                      .ToLocalChecked())
   1288             .FromJust());
   1289   CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
   1290 
   1291   CHECK(CompileRun("function foo() {\n"
   1292                    "  for (var i = 0; i < 13; i++) obj.func();\n"
   1293                    "}\n"
   1294                    "foo(), true")
   1295             ->BooleanValue(env.local())
   1296             .FromJust());
   1297 }
   1298 
   1299 
   1300 THREADED_TEST(ExternalWrap) {
   1301   // Check heap allocated object.
   1302   int* ptr = new int;
   1303   expected_ptr = ptr;
   1304   TestExternalPointerWrapping();
   1305   delete ptr;
   1306 
   1307   // Check stack allocated object.
   1308   int foo;
   1309   expected_ptr = &foo;
   1310   TestExternalPointerWrapping();
   1311 
   1312   // Check not aligned addresses.
   1313   const int n = 100;
   1314   char* s = new char[n];
   1315   for (int i = 0; i < n; i++) {
   1316     expected_ptr = s + i;
   1317     TestExternalPointerWrapping();
   1318   }
   1319 
   1320   delete[] s;
   1321 
   1322   // Check several invalid addresses.
   1323   expected_ptr = reinterpret_cast<void*>(1);
   1324   TestExternalPointerWrapping();
   1325 
   1326   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
   1327   TestExternalPointerWrapping();
   1328 
   1329   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
   1330   TestExternalPointerWrapping();
   1331 
   1332 #if defined(V8_HOST_ARCH_X64)
   1333   // Check a value with a leading 1 bit in x64 Smi encoding.
   1334   expected_ptr = reinterpret_cast<void*>(0x400000000);
   1335   TestExternalPointerWrapping();
   1336 
   1337   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
   1338   TestExternalPointerWrapping();
   1339 
   1340   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
   1341   TestExternalPointerWrapping();
   1342 #endif
   1343 }
   1344 
   1345 
   1346 THREADED_TEST(FindInstanceInPrototypeChain) {
   1347   LocalContext env;
   1348   v8::Isolate* isolate = env->GetIsolate();
   1349   v8::HandleScope scope(isolate);
   1350 
   1351   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
   1352   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
   1353   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
   1354   derived->Inherit(base);
   1355 
   1356   Local<v8::Function> base_function =
   1357       base->GetFunction(env.local()).ToLocalChecked();
   1358   Local<v8::Function> derived_function =
   1359       derived->GetFunction(env.local()).ToLocalChecked();
   1360   Local<v8::Function> other_function =
   1361       other->GetFunction(env.local()).ToLocalChecked();
   1362 
   1363   Local<v8::Object> base_instance =
   1364       base_function->NewInstance(env.local()).ToLocalChecked();
   1365   Local<v8::Object> derived_instance =
   1366       derived_function->NewInstance(env.local()).ToLocalChecked();
   1367   Local<v8::Object> derived_instance2 =
   1368       derived_function->NewInstance(env.local()).ToLocalChecked();
   1369   Local<v8::Object> other_instance =
   1370       other_function->NewInstance(env.local()).ToLocalChecked();
   1371   CHECK(
   1372       derived_instance2->Set(env.local(), v8_str("__proto__"), derived_instance)
   1373           .FromJust());
   1374   CHECK(other_instance->Set(env.local(), v8_str("__proto__"), derived_instance2)
   1375             .FromJust());
   1376 
   1377   // base_instance is only an instance of base.
   1378   CHECK(base_instance->Equals(env.local(),
   1379                               base_instance->FindInstanceInPrototypeChain(base))
   1380             .FromJust());
   1381   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
   1382   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
   1383 
   1384   // derived_instance is an instance of base and derived.
   1385   CHECK(derived_instance->Equals(env.local(),
   1386                                  derived_instance->FindInstanceInPrototypeChain(
   1387                                      base))
   1388             .FromJust());
   1389   CHECK(derived_instance->Equals(env.local(),
   1390                                  derived_instance->FindInstanceInPrototypeChain(
   1391                                      derived))
   1392             .FromJust());
   1393   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
   1394 
   1395   // other_instance is an instance of other and its immediate
   1396   // prototype derived_instance2 is an instance of base and derived.
   1397   // Note, derived_instance is an instance of base and derived too,
   1398   // but it comes after derived_instance2 in the prototype chain of
   1399   // other_instance.
   1400   CHECK(derived_instance2->Equals(
   1401                              env.local(),
   1402                              other_instance->FindInstanceInPrototypeChain(base))
   1403             .FromJust());
   1404   CHECK(derived_instance2->Equals(env.local(),
   1405                                   other_instance->FindInstanceInPrototypeChain(
   1406                                       derived))
   1407             .FromJust());
   1408   CHECK(other_instance->Equals(
   1409                           env.local(),
   1410                           other_instance->FindInstanceInPrototypeChain(other))
   1411             .FromJust());
   1412 }
   1413 
   1414 
   1415 THREADED_TEST(TinyInteger) {
   1416   LocalContext env;
   1417   v8::Isolate* isolate = env->GetIsolate();
   1418   v8::HandleScope scope(isolate);
   1419 
   1420   int32_t value = 239;
   1421   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1422   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1423 
   1424   value_obj = v8::Integer::New(isolate, value);
   1425   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1426 }
   1427 
   1428 
   1429 THREADED_TEST(BigSmiInteger) {
   1430   LocalContext env;
   1431   v8::HandleScope scope(env->GetIsolate());
   1432   v8::Isolate* isolate = CcTest::isolate();
   1433 
   1434   int32_t value = i::Smi::kMaxValue;
   1435   // We cannot add one to a Smi::kMaxValue without wrapping.
   1436   if (i::SmiValuesAre31Bits()) {
   1437     CHECK(i::Smi::IsValid(value));
   1438     CHECK(!i::Smi::IsValid(value + 1));
   1439 
   1440     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1441     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1442 
   1443     value_obj = v8::Integer::New(isolate, value);
   1444     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1445   }
   1446 }
   1447 
   1448 
   1449 THREADED_TEST(BigInteger) {
   1450   LocalContext env;
   1451   v8::HandleScope scope(env->GetIsolate());
   1452   v8::Isolate* isolate = CcTest::isolate();
   1453 
   1454   // We cannot add one to a Smi::kMaxValue without wrapping.
   1455   if (i::SmiValuesAre31Bits()) {
   1456     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
   1457     // The code will not be run in that case, due to the "if" guard.
   1458     int32_t value =
   1459         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
   1460     CHECK(value > i::Smi::kMaxValue);
   1461     CHECK(!i::Smi::IsValid(value));
   1462 
   1463     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1464     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1465 
   1466     value_obj = v8::Integer::New(isolate, value);
   1467     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1468   }
   1469 }
   1470 
   1471 
   1472 THREADED_TEST(TinyUnsignedInteger) {
   1473   LocalContext env;
   1474   v8::HandleScope scope(env->GetIsolate());
   1475   v8::Isolate* isolate = CcTest::isolate();
   1476 
   1477   uint32_t value = 239;
   1478 
   1479   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1480   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1481 
   1482   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1483   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1484 }
   1485 
   1486 
   1487 THREADED_TEST(BigUnsignedSmiInteger) {
   1488   LocalContext env;
   1489   v8::HandleScope scope(env->GetIsolate());
   1490   v8::Isolate* isolate = CcTest::isolate();
   1491 
   1492   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
   1493   CHECK(i::Smi::IsValid(value));
   1494   CHECK(!i::Smi::IsValid(value + 1));
   1495 
   1496   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1497   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1498 
   1499   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1500   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1501 }
   1502 
   1503 
   1504 THREADED_TEST(BigUnsignedInteger) {
   1505   LocalContext env;
   1506   v8::HandleScope scope(env->GetIsolate());
   1507   v8::Isolate* isolate = CcTest::isolate();
   1508 
   1509   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
   1510   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
   1511   CHECK(!i::Smi::IsValid(value));
   1512 
   1513   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1514   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1515 
   1516   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1517   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1518 }
   1519 
   1520 
   1521 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
   1522   LocalContext env;
   1523   v8::HandleScope scope(env->GetIsolate());
   1524   v8::Isolate* isolate = CcTest::isolate();
   1525 
   1526   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
   1527   uint32_t value = INT32_MAX_AS_UINT + 1;
   1528   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
   1529 
   1530   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1531   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1532 
   1533   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1534   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1535 }
   1536 
   1537 
   1538 THREADED_TEST(IsNativeError) {
   1539   LocalContext env;
   1540   v8::HandleScope scope(env->GetIsolate());
   1541   v8::Local<Value> syntax_error = CompileRun(
   1542       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
   1543   CHECK(syntax_error->IsNativeError());
   1544   v8::Local<Value> not_error = CompileRun("{a:42}");
   1545   CHECK(!not_error->IsNativeError());
   1546   v8::Local<Value> not_object = CompileRun("42");
   1547   CHECK(!not_object->IsNativeError());
   1548 }
   1549 
   1550 
   1551 THREADED_TEST(IsGeneratorFunctionOrObject) {
   1552   LocalContext env;
   1553   v8::HandleScope scope(env->GetIsolate());
   1554 
   1555   CompileRun("function *gen() { yield 1; }\nfunction func() {}");
   1556   v8::Local<Value> gen = CompileRun("gen");
   1557   v8::Local<Value> genObj = CompileRun("gen()");
   1558   v8::Local<Value> object = CompileRun("{a:42}");
   1559   v8::Local<Value> func = CompileRun("func");
   1560 
   1561   CHECK(gen->IsGeneratorFunction());
   1562   CHECK(gen->IsFunction());
   1563   CHECK(!gen->IsGeneratorObject());
   1564 
   1565   CHECK(!genObj->IsGeneratorFunction());
   1566   CHECK(!genObj->IsFunction());
   1567   CHECK(genObj->IsGeneratorObject());
   1568 
   1569   CHECK(!object->IsGeneratorFunction());
   1570   CHECK(!object->IsFunction());
   1571   CHECK(!object->IsGeneratorObject());
   1572 
   1573   CHECK(!func->IsGeneratorFunction());
   1574   CHECK(func->IsFunction());
   1575   CHECK(!func->IsGeneratorObject());
   1576 }
   1577 
   1578 
   1579 THREADED_TEST(ArgumentsObject) {
   1580   LocalContext env;
   1581   v8::HandleScope scope(env->GetIsolate());
   1582   v8::Local<Value> arguments_object =
   1583       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
   1584   CHECK(arguments_object->IsArgumentsObject());
   1585   v8::Local<Value> array = CompileRun("[1,2,3]");
   1586   CHECK(!array->IsArgumentsObject());
   1587   v8::Local<Value> object = CompileRun("{a:42}");
   1588   CHECK(!object->IsArgumentsObject());
   1589 }
   1590 
   1591 
   1592 THREADED_TEST(IsMapOrSet) {
   1593   LocalContext env;
   1594   v8::HandleScope scope(env->GetIsolate());
   1595   v8::Local<Value> map = CompileRun("new Map()");
   1596   v8::Local<Value> set = CompileRun("new Set()");
   1597   v8::Local<Value> weak_map = CompileRun("new WeakMap()");
   1598   v8::Local<Value> weak_set = CompileRun("new WeakSet()");
   1599   CHECK(map->IsMap());
   1600   CHECK(set->IsSet());
   1601   CHECK(weak_map->IsWeakMap());
   1602   CHECK(weak_set->IsWeakSet());
   1603 
   1604   CHECK(!map->IsSet());
   1605   CHECK(!map->IsWeakMap());
   1606   CHECK(!map->IsWeakSet());
   1607 
   1608   CHECK(!set->IsMap());
   1609   CHECK(!set->IsWeakMap());
   1610   CHECK(!set->IsWeakSet());
   1611 
   1612   CHECK(!weak_map->IsMap());
   1613   CHECK(!weak_map->IsSet());
   1614   CHECK(!weak_map->IsWeakSet());
   1615 
   1616   CHECK(!weak_set->IsMap());
   1617   CHECK(!weak_set->IsSet());
   1618   CHECK(!weak_set->IsWeakMap());
   1619 
   1620   v8::Local<Value> object = CompileRun("{a:42}");
   1621   CHECK(!object->IsMap());
   1622   CHECK(!object->IsSet());
   1623   CHECK(!object->IsWeakMap());
   1624   CHECK(!object->IsWeakSet());
   1625 }
   1626 
   1627 
   1628 THREADED_TEST(StringObject) {
   1629   LocalContext env;
   1630   v8::HandleScope scope(env->GetIsolate());
   1631   v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
   1632   CHECK(boxed_string->IsStringObject());
   1633   v8::Local<Value> unboxed_string = CompileRun("\"test\"");
   1634   CHECK(!unboxed_string->IsStringObject());
   1635   v8::Local<Value> boxed_not_string = CompileRun("new Number(42)");
   1636   CHECK(!boxed_not_string->IsStringObject());
   1637   v8::Local<Value> not_object = CompileRun("0");
   1638   CHECK(!not_object->IsStringObject());
   1639   v8::Local<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
   1640   CHECK(!as_boxed.IsEmpty());
   1641   Local<v8::String> the_string = as_boxed->ValueOf();
   1642   CHECK(!the_string.IsEmpty());
   1643   ExpectObject("\"test\"", the_string);
   1644   v8::Local<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
   1645   CHECK(new_boxed_string->IsStringObject());
   1646   as_boxed = new_boxed_string.As<v8::StringObject>();
   1647   the_string = as_boxed->ValueOf();
   1648   CHECK(!the_string.IsEmpty());
   1649   ExpectObject("\"test\"", the_string);
   1650 }
   1651 
   1652 
   1653 TEST(StringObjectDelete) {
   1654   LocalContext context;
   1655   v8::HandleScope scope(context->GetIsolate());
   1656   v8::Local<Value> boxed_string = CompileRun("new String(\"test\")");
   1657   CHECK(boxed_string->IsStringObject());
   1658   v8::Local<v8::Object> str_obj = boxed_string.As<v8::Object>();
   1659   CHECK(!str_obj->Delete(context.local(), 2).FromJust());
   1660   CHECK(!str_obj->Delete(context.local(), v8_num(2)).FromJust());
   1661 }
   1662 
   1663 
   1664 THREADED_TEST(NumberObject) {
   1665   LocalContext env;
   1666   v8::HandleScope scope(env->GetIsolate());
   1667   v8::Local<Value> boxed_number = CompileRun("new Number(42)");
   1668   CHECK(boxed_number->IsNumberObject());
   1669   v8::Local<Value> unboxed_number = CompileRun("42");
   1670   CHECK(!unboxed_number->IsNumberObject());
   1671   v8::Local<Value> boxed_not_number = CompileRun("new Boolean(false)");
   1672   CHECK(!boxed_not_number->IsNumberObject());
   1673   v8::Local<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
   1674   CHECK(!as_boxed.IsEmpty());
   1675   double the_number = as_boxed->ValueOf();
   1676   CHECK_EQ(42.0, the_number);
   1677   v8::Local<v8::Value> new_boxed_number =
   1678       v8::NumberObject::New(env->GetIsolate(), 43);
   1679   CHECK(new_boxed_number->IsNumberObject());
   1680   as_boxed = new_boxed_number.As<v8::NumberObject>();
   1681   the_number = as_boxed->ValueOf();
   1682   CHECK_EQ(43.0, the_number);
   1683 }
   1684 
   1685 
   1686 THREADED_TEST(BooleanObject) {
   1687   LocalContext env;
   1688   v8::HandleScope scope(env->GetIsolate());
   1689   v8::Local<Value> boxed_boolean = CompileRun("new Boolean(true)");
   1690   CHECK(boxed_boolean->IsBooleanObject());
   1691   v8::Local<Value> unboxed_boolean = CompileRun("true");
   1692   CHECK(!unboxed_boolean->IsBooleanObject());
   1693   v8::Local<Value> boxed_not_boolean = CompileRun("new Number(42)");
   1694   CHECK(!boxed_not_boolean->IsBooleanObject());
   1695   v8::Local<v8::BooleanObject> as_boxed = boxed_boolean.As<v8::BooleanObject>();
   1696   CHECK(!as_boxed.IsEmpty());
   1697   bool the_boolean = as_boxed->ValueOf();
   1698   CHECK_EQ(true, the_boolean);
   1699   v8::Local<v8::Value> boxed_true =
   1700       v8::BooleanObject::New(env->GetIsolate(), true);
   1701   v8::Local<v8::Value> boxed_false =
   1702       v8::BooleanObject::New(env->GetIsolate(), false);
   1703   CHECK(boxed_true->IsBooleanObject());
   1704   CHECK(boxed_false->IsBooleanObject());
   1705   as_boxed = boxed_true.As<v8::BooleanObject>();
   1706   CHECK_EQ(true, as_boxed->ValueOf());
   1707   as_boxed = boxed_false.As<v8::BooleanObject>();
   1708   CHECK_EQ(false, as_boxed->ValueOf());
   1709 }
   1710 
   1711 
   1712 THREADED_TEST(PrimitiveAndWrappedBooleans) {
   1713   LocalContext env;
   1714   v8::HandleScope scope(env->GetIsolate());
   1715 
   1716   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
   1717   CHECK(primitive_false->IsBoolean());
   1718   CHECK(!primitive_false->IsBooleanObject());
   1719   CHECK(!primitive_false->BooleanValue(env.local()).FromJust());
   1720   CHECK(!primitive_false->IsTrue());
   1721   CHECK(primitive_false->IsFalse());
   1722 
   1723   Local<Value> false_value = BooleanObject::New(env->GetIsolate(), false);
   1724   CHECK(!false_value->IsBoolean());
   1725   CHECK(false_value->IsBooleanObject());
   1726   CHECK(false_value->BooleanValue(env.local()).FromJust());
   1727   CHECK(!false_value->IsTrue());
   1728   CHECK(!false_value->IsFalse());
   1729 
   1730   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
   1731   CHECK(!false_boolean_object->IsBoolean());
   1732   CHECK(false_boolean_object->IsBooleanObject());
   1733   CHECK(false_boolean_object->BooleanValue(env.local()).FromJust());
   1734   CHECK(!false_boolean_object->ValueOf());
   1735   CHECK(!false_boolean_object->IsTrue());
   1736   CHECK(!false_boolean_object->IsFalse());
   1737 
   1738   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
   1739   CHECK(primitive_true->IsBoolean());
   1740   CHECK(!primitive_true->IsBooleanObject());
   1741   CHECK(primitive_true->BooleanValue(env.local()).FromJust());
   1742   CHECK(primitive_true->IsTrue());
   1743   CHECK(!primitive_true->IsFalse());
   1744 
   1745   Local<Value> true_value = BooleanObject::New(env->GetIsolate(), true);
   1746   CHECK(!true_value->IsBoolean());
   1747   CHECK(true_value->IsBooleanObject());
   1748   CHECK(true_value->BooleanValue(env.local()).FromJust());
   1749   CHECK(!true_value->IsTrue());
   1750   CHECK(!true_value->IsFalse());
   1751 
   1752   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
   1753   CHECK(!true_boolean_object->IsBoolean());
   1754   CHECK(true_boolean_object->IsBooleanObject());
   1755   CHECK(true_boolean_object->BooleanValue(env.local()).FromJust());
   1756   CHECK(true_boolean_object->ValueOf());
   1757   CHECK(!true_boolean_object->IsTrue());
   1758   CHECK(!true_boolean_object->IsFalse());
   1759 }
   1760 
   1761 
   1762 THREADED_TEST(Number) {
   1763   LocalContext env;
   1764   v8::HandleScope scope(env->GetIsolate());
   1765   double PI = 3.1415926;
   1766   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
   1767   CHECK_EQ(PI, pi_obj->NumberValue(env.local()).FromJust());
   1768 }
   1769 
   1770 
   1771 THREADED_TEST(ToNumber) {
   1772   LocalContext env;
   1773   v8::Isolate* isolate = CcTest::isolate();
   1774   v8::HandleScope scope(isolate);
   1775   Local<String> str = v8_str("3.1415926");
   1776   CHECK_EQ(3.1415926, str->NumberValue(env.local()).FromJust());
   1777   v8::Local<v8::Boolean> t = v8::True(isolate);
   1778   CHECK_EQ(1.0, t->NumberValue(env.local()).FromJust());
   1779   v8::Local<v8::Boolean> f = v8::False(isolate);
   1780   CHECK_EQ(0.0, f->NumberValue(env.local()).FromJust());
   1781 }
   1782 
   1783 
   1784 THREADED_TEST(Date) {
   1785   LocalContext env;
   1786   v8::HandleScope scope(env->GetIsolate());
   1787   double PI = 3.1415926;
   1788   Local<Value> date = v8::Date::New(env.local(), PI).ToLocalChecked();
   1789   CHECK_EQ(3.0, date->NumberValue(env.local()).FromJust());
   1790   CHECK(date.As<v8::Date>()
   1791             ->Set(env.local(), v8_str("property"),
   1792                   v8::Integer::New(env->GetIsolate(), 42))
   1793             .FromJust());
   1794   CHECK_EQ(42, date.As<v8::Date>()
   1795                    ->Get(env.local(), v8_str("property"))
   1796                    .ToLocalChecked()
   1797                    ->Int32Value(env.local())
   1798                    .FromJust());
   1799 }
   1800 
   1801 
   1802 THREADED_TEST(Boolean) {
   1803   LocalContext env;
   1804   v8::Isolate* isolate = env->GetIsolate();
   1805   v8::HandleScope scope(isolate);
   1806   v8::Local<v8::Boolean> t = v8::True(isolate);
   1807   CHECK(t->Value());
   1808   v8::Local<v8::Boolean> f = v8::False(isolate);
   1809   CHECK(!f->Value());
   1810   v8::Local<v8::Primitive> u = v8::Undefined(isolate);
   1811   CHECK(!u->BooleanValue(env.local()).FromJust());
   1812   v8::Local<v8::Primitive> n = v8::Null(isolate);
   1813   CHECK(!n->BooleanValue(env.local()).FromJust());
   1814   v8::Local<String> str1 = v8_str("");
   1815   CHECK(!str1->BooleanValue(env.local()).FromJust());
   1816   v8::Local<String> str2 = v8_str("x");
   1817   CHECK(str2->BooleanValue(env.local()).FromJust());
   1818   CHECK(!v8::Number::New(isolate, 0)->BooleanValue(env.local()).FromJust());
   1819   CHECK(v8::Number::New(isolate, -1)->BooleanValue(env.local()).FromJust());
   1820   CHECK(v8::Number::New(isolate, 1)->BooleanValue(env.local()).FromJust());
   1821   CHECK(v8::Number::New(isolate, 42)->BooleanValue(env.local()).FromJust());
   1822   CHECK(!v8_compile("NaN")
   1823              ->Run(env.local())
   1824              .ToLocalChecked()
   1825              ->BooleanValue(env.local())
   1826              .FromJust());
   1827 }
   1828 
   1829 
   1830 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1831   ApiTestFuzzer::Fuzz();
   1832   args.GetReturnValue().Set(v8_num(13.4));
   1833 }
   1834 
   1835 
   1836 static void GetM(Local<String> name,
   1837                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   1838   ApiTestFuzzer::Fuzz();
   1839   info.GetReturnValue().Set(v8_num(876));
   1840 }
   1841 
   1842 
   1843 THREADED_TEST(GlobalPrototype) {
   1844   v8::Isolate* isolate = CcTest::isolate();
   1845   v8::HandleScope scope(isolate);
   1846   v8::Local<v8::FunctionTemplate> func_templ =
   1847       v8::FunctionTemplate::New(isolate);
   1848   func_templ->PrototypeTemplate()->Set(
   1849       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
   1850   v8::Local<ObjectTemplate> templ = func_templ->InstanceTemplate();
   1851   templ->Set(isolate, "x", v8_num(200));
   1852   templ->SetAccessor(v8_str("m"), GetM);
   1853   LocalContext env(0, templ);
   1854   v8::Local<Script> script(v8_compile("dummy()"));
   1855   v8::Local<Value> result(script->Run(env.local()).ToLocalChecked());
   1856   CHECK_EQ(13.4, result->NumberValue(env.local()).FromJust());
   1857   CHECK_EQ(200, v8_run_int32value(v8_compile("x")));
   1858   CHECK_EQ(876, v8_run_int32value(v8_compile("m")));
   1859 }
   1860 
   1861 
   1862 THREADED_TEST(ObjectTemplate) {
   1863   LocalContext env;
   1864   v8::Isolate* isolate = CcTest::isolate();
   1865   v8::HandleScope scope(isolate);
   1866   Local<v8::FunctionTemplate> acc =
   1867       v8::FunctionTemplate::New(isolate, Returns42);
   1868   CHECK(env->Global()
   1869             ->Set(env.local(), v8_str("acc"),
   1870                   acc->GetFunction(env.local()).ToLocalChecked())
   1871             .FromJust());
   1872 
   1873   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
   1874   v8::Local<v8::String> class_name = v8_str("the_class_name");
   1875   fun->SetClassName(class_name);
   1876   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
   1877   templ1->Set(isolate, "x", v8_num(10));
   1878   templ1->Set(isolate, "y", v8_num(13));
   1879   templ1->Set(v8_str("foo"), acc);
   1880   Local<v8::Object> instance1 =
   1881       templ1->NewInstance(env.local()).ToLocalChecked();
   1882   CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
   1883   CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
   1884   CHECK(CompileRun("(p.x == 10)")->BooleanValue(env.local()).FromJust());
   1885   CHECK(CompileRun("(p.y == 13)")->BooleanValue(env.local()).FromJust());
   1886   CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(env.local()).FromJust());
   1887   CHECK(CompileRun("(p.foo == acc)")->BooleanValue(env.local()).FromJust());
   1888   // Ensure that foo become a data field.
   1889   CompileRun("p.foo = function() {}");
   1890   Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
   1891   fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
   1892   Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
   1893   templ2->Set(isolate, "a", v8_num(12));
   1894   templ2->Set(isolate, "b", templ1);
   1895   templ2->Set(v8_str("bar"), acc);
   1896   templ2->SetAccessorProperty(v8_str("acc"), acc);
   1897   Local<v8::Object> instance2 =
   1898       templ2->NewInstance(env.local()).ToLocalChecked();
   1899   CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust());
   1900   CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(env.local()).FromJust());
   1901   CHECK(CompileRun("(q.a == 12)")->BooleanValue(env.local()).FromJust());
   1902   CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(env.local()).FromJust());
   1903   CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(env.local()).FromJust());
   1904   CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(env.local()).FromJust());
   1905   CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(env.local()).FromJust());
   1906   CHECK(CompileRun("(q.b !== p)")->BooleanValue(env.local()).FromJust());
   1907   CHECK(CompileRun("(q.acc == 42)")->BooleanValue(env.local()).FromJust());
   1908   CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(env.local()).FromJust());
   1909   CHECK(CompileRun("(q.bar == acc)")->BooleanValue(env.local()).FromJust());
   1910 
   1911   instance2 = templ2->NewInstance(env.local()).ToLocalChecked();
   1912   CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust());
   1913   CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(env.local()).FromJust());
   1914   CHECK(CompileRun("(q2.a == 12)")->BooleanValue(env.local()).FromJust());
   1915   CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(env.local()).FromJust());
   1916   CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(env.local()).FromJust());
   1917   CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(env.local()).FromJust());
   1918   CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(env.local()).FromJust());
   1919   CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(env.local()).FromJust());
   1920   CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(env.local()).FromJust());
   1921   CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(env.local()).FromJust());
   1922 
   1923   CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(env.local()).FromJust());
   1924   CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)")
   1925             ->BooleanValue(env.local())
   1926             .FromJust());
   1927   CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');"
   1928                    "(desc1.get === acc)")
   1929             ->BooleanValue(env.local())
   1930             .FromJust());
   1931   CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');"
   1932                    "(desc2.get === acc)")
   1933             ->BooleanValue(env.local())
   1934             .FromJust());
   1935 }
   1936 
   1937 THREADED_TEST(IntegerValue) {
   1938   LocalContext env;
   1939   v8::Isolate* isolate = CcTest::isolate();
   1940   v8::HandleScope scope(isolate);
   1941 
   1942   CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust());
   1943 }
   1944 
   1945 static void GetNirk(Local<String> name,
   1946                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   1947   ApiTestFuzzer::Fuzz();
   1948   info.GetReturnValue().Set(v8_num(900));
   1949 }
   1950 
   1951 static void GetRino(Local<String> name,
   1952                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   1953   ApiTestFuzzer::Fuzz();
   1954   info.GetReturnValue().Set(v8_num(560));
   1955 }
   1956 
   1957 enum ObjectInstantiationMode {
   1958   // Create object using ObjectTemplate::NewInstance.
   1959   ObjectTemplate_NewInstance,
   1960   // Create object using FunctionTemplate::NewInstance on constructor.
   1961   Constructor_GetFunction_NewInstance,
   1962   // Create object using new operator on constructor.
   1963   Constructor_GetFunction_New
   1964 };
   1965 
   1966 // Test object instance creation using a function template with an instance
   1967 // template inherited from another function template with accessors and data
   1968 // properties in prototype template.
   1969 static void TestObjectTemplateInheritedWithPrototype(
   1970     ObjectInstantiationMode mode) {
   1971   LocalContext env;
   1972   v8::Isolate* isolate = CcTest::isolate();
   1973   v8::HandleScope scope(isolate);
   1974 
   1975   Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
   1976   fun_A->SetClassName(v8_str("A"));
   1977   v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate();
   1978   prototype_templ->Set(isolate, "a", v8_num(113));
   1979   prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk);
   1980   prototype_templ->Set(isolate, "b", v8_num(153));
   1981 
   1982   Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
   1983   v8::Local<v8::String> class_name = v8_str("B");
   1984   fun_B->SetClassName(class_name);
   1985   fun_B->Inherit(fun_A);
   1986   prototype_templ = fun_B->PrototypeTemplate();
   1987   prototype_templ->Set(isolate, "c", v8_num(713));
   1988   prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino);
   1989   prototype_templ->Set(isolate, "d", v8_num(753));
   1990 
   1991   Local<ObjectTemplate> templ = fun_B->InstanceTemplate();
   1992   templ->Set(isolate, "x", v8_num(10));
   1993   templ->Set(isolate, "y", v8_num(13));
   1994 
   1995   // Perform several iterations to trigger creation from cached boilerplate.
   1996   for (int i = 0; i < 3; i++) {
   1997     Local<v8::Object> instance;
   1998     switch (mode) {
   1999       case ObjectTemplate_NewInstance:
   2000         instance = templ->NewInstance(env.local()).ToLocalChecked();
   2001         break;
   2002 
   2003       case Constructor_GetFunction_NewInstance: {
   2004         Local<v8::Function> function_B =
   2005             fun_B->GetFunction(env.local()).ToLocalChecked();
   2006         instance = function_B->NewInstance(env.local()).ToLocalChecked();
   2007         break;
   2008       }
   2009       case Constructor_GetFunction_New: {
   2010         Local<v8::Function> function_B =
   2011             fun_B->GetFunction(env.local()).ToLocalChecked();
   2012         if (i == 0) {
   2013           CHECK(env->Global()
   2014                     ->Set(env.local(), class_name, function_B)
   2015                     .FromJust());
   2016         }
   2017         instance =
   2018             CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
   2019         break;
   2020       }
   2021       default:
   2022         UNREACHABLE();
   2023     }
   2024 
   2025     CHECK(class_name->StrictEquals(instance->GetConstructorName()));
   2026     CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
   2027 
   2028     CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust());
   2029     CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust());
   2030 
   2031     CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust());
   2032     CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
   2033     CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust());
   2034     CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust());
   2035     CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
   2036     CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust());
   2037   }
   2038 }
   2039 
   2040 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) {
   2041   TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance);
   2042 }
   2043 
   2044 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) {
   2045   TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance);
   2046 }
   2047 
   2048 THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) {
   2049   TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New);
   2050 }
   2051 
   2052 // Test object instance creation using a function template without an instance
   2053 // template inherited from another function template.
   2054 static void TestObjectTemplateInheritedWithoutInstanceTemplate(
   2055     ObjectInstantiationMode mode) {
   2056   LocalContext env;
   2057   v8::Isolate* isolate = CcTest::isolate();
   2058   v8::HandleScope scope(isolate);
   2059 
   2060   Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
   2061   fun_A->SetClassName(v8_str("A"));
   2062 
   2063   Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
   2064   templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
   2065   templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
   2066 
   2067   Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
   2068   v8::Local<v8::String> class_name = v8_str("B");
   2069   fun_B->SetClassName(class_name);
   2070   fun_B->Inherit(fun_A);
   2071 
   2072   // Perform several iterations to trigger creation from cached boilerplate.
   2073   for (int i = 0; i < 3; i++) {
   2074     Local<v8::Object> instance;
   2075     switch (mode) {
   2076       case Constructor_GetFunction_NewInstance: {
   2077         Local<v8::Function> function_B =
   2078             fun_B->GetFunction(env.local()).ToLocalChecked();
   2079         instance = function_B->NewInstance(env.local()).ToLocalChecked();
   2080         break;
   2081       }
   2082       case Constructor_GetFunction_New: {
   2083         Local<v8::Function> function_B =
   2084             fun_B->GetFunction(env.local()).ToLocalChecked();
   2085         if (i == 0) {
   2086           CHECK(env->Global()
   2087                     ->Set(env.local(), class_name, function_B)
   2088                     .FromJust());
   2089         }
   2090         instance =
   2091             CompileRun("new B()")->ToObject(env.local()).ToLocalChecked();
   2092         break;
   2093       }
   2094       default:
   2095         UNREACHABLE();
   2096     }
   2097 
   2098     CHECK(class_name->StrictEquals(instance->GetConstructorName()));
   2099     CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
   2100 
   2101     CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
   2102     CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
   2103   }
   2104 }
   2105 
   2106 THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) {
   2107   TestObjectTemplateInheritedWithoutInstanceTemplate(
   2108       Constructor_GetFunction_NewInstance);
   2109 }
   2110 
   2111 THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) {
   2112   TestObjectTemplateInheritedWithoutInstanceTemplate(
   2113       Constructor_GetFunction_New);
   2114 }
   2115 
   2116 THREADED_TEST(TestObjectTemplateClassInheritance) {
   2117   LocalContext env;
   2118   v8::Isolate* isolate = CcTest::isolate();
   2119   v8::HandleScope scope(isolate);
   2120 
   2121   Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
   2122   fun_A->SetClassName(v8_str("A"));
   2123 
   2124   Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate();
   2125   templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk);
   2126   templ_A->SetNativeDataProperty(v8_str("rino"), GetRino);
   2127 
   2128   Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
   2129   v8::Local<v8::String> class_name = v8_str("B");
   2130   fun_B->SetClassName(class_name);
   2131   fun_B->Inherit(fun_A);
   2132 
   2133   v8::Local<v8::String> subclass_name = v8_str("C");
   2134   v8::Local<v8::Object> b_proto;
   2135   v8::Local<v8::Object> c_proto;
   2136   // Perform several iterations to make sure the cache doesn't break
   2137   // subclassing.
   2138   for (int i = 0; i < 3; i++) {
   2139     Local<v8::Function> function_B =
   2140         fun_B->GetFunction(env.local()).ToLocalChecked();
   2141     if (i == 0) {
   2142       CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
   2143       CompileRun("class C extends B {}");
   2144       b_proto =
   2145           CompileRun("B.prototype")->ToObject(env.local()).ToLocalChecked();
   2146       c_proto =
   2147           CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
   2148       CHECK(b_proto->Equals(env.local(), c_proto->GetPrototype()).FromJust());
   2149     }
   2150     Local<v8::Object> instance =
   2151         CompileRun("new C()")->ToObject(env.local()).ToLocalChecked();
   2152     CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
   2153 
   2154     CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
   2155     CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
   2156 
   2157     CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
   2158     CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
   2159   }
   2160 }
   2161 
   2162 static void NamedPropertyGetterWhichReturns42(
   2163     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   2164   info.GetReturnValue().Set(v8_num(42));
   2165 }
   2166 
   2167 THREADED_TEST(TestObjectTemplateReflectConstruct) {
   2168   LocalContext env;
   2169   v8::Isolate* isolate = CcTest::isolate();
   2170   v8::HandleScope scope(isolate);
   2171 
   2172   Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
   2173   fun_B->InstanceTemplate()->SetHandler(
   2174       v8::NamedPropertyHandlerConfiguration(NamedPropertyGetterWhichReturns42));
   2175   v8::Local<v8::String> class_name = v8_str("B");
   2176   fun_B->SetClassName(class_name);
   2177 
   2178   v8::Local<v8::String> subclass_name = v8_str("C");
   2179   v8::Local<v8::Object> b_proto;
   2180   v8::Local<v8::Object> c_proto;
   2181   // Perform several iterations to make sure the cache doesn't break
   2182   // subclassing.
   2183   for (int i = 0; i < 3; i++) {
   2184     Local<v8::Function> function_B =
   2185         fun_B->GetFunction(env.local()).ToLocalChecked();
   2186     if (i == 0) {
   2187       CHECK(env->Global()->Set(env.local(), class_name, function_B).FromJust());
   2188       CompileRun("function C() {}");
   2189       c_proto =
   2190           CompileRun("C.prototype")->ToObject(env.local()).ToLocalChecked();
   2191     }
   2192     Local<v8::Object> instance = CompileRun("Reflect.construct(B, [], C)")
   2193                                      ->ToObject(env.local())
   2194                                      .ToLocalChecked();
   2195     CHECK(c_proto->Equals(env.local(), instance->GetPrototype()).FromJust());
   2196 
   2197     CHECK(subclass_name->StrictEquals(instance->GetConstructorName()));
   2198     CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust());
   2199 
   2200     CHECK_EQ(42, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust());
   2201     CHECK_EQ(42, CompileRun("o.rino")->IntegerValue(env.local()).FromJust());
   2202   }
   2203 }
   2204 
   2205 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
   2206   ApiTestFuzzer::Fuzz();
   2207   args.GetReturnValue().Set(v8_num(17.2));
   2208 }
   2209 
   2210 
   2211 static void GetKnurd(Local<String> property,
   2212                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   2213   ApiTestFuzzer::Fuzz();
   2214   info.GetReturnValue().Set(v8_num(15.2));
   2215 }
   2216 
   2217 
   2218 THREADED_TEST(DescriptorInheritance) {
   2219   v8::Isolate* isolate = CcTest::isolate();
   2220   v8::HandleScope scope(isolate);
   2221   v8::Local<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
   2222   super->PrototypeTemplate()->Set(isolate, "flabby",
   2223                                   v8::FunctionTemplate::New(isolate,
   2224                                                             GetFlabby));
   2225   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
   2226 
   2227   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
   2228 
   2229   v8::Local<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
   2230   base1->Inherit(super);
   2231   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
   2232 
   2233   v8::Local<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
   2234   base2->Inherit(super);
   2235   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
   2236 
   2237   LocalContext env;
   2238 
   2239   CHECK(env->Global()
   2240             ->Set(env.local(), v8_str("s"),
   2241                   super->GetFunction(env.local()).ToLocalChecked())
   2242             .FromJust());
   2243   CHECK(env->Global()
   2244             ->Set(env.local(), v8_str("base1"),
   2245                   base1->GetFunction(env.local()).ToLocalChecked())
   2246             .FromJust());
   2247   CHECK(env->Global()
   2248             ->Set(env.local(), v8_str("base2"),
   2249                   base2->GetFunction(env.local()).ToLocalChecked())
   2250             .FromJust());
   2251 
   2252   // Checks right __proto__ chain.
   2253   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")
   2254             ->BooleanValue(env.local())
   2255             .FromJust());
   2256   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")
   2257             ->BooleanValue(env.local())
   2258             .FromJust());
   2259 
   2260   CHECK(v8_compile("s.prototype.PI == 3.14")
   2261             ->Run(env.local())
   2262             .ToLocalChecked()
   2263             ->BooleanValue(env.local())
   2264             .FromJust());
   2265 
   2266   // Instance accessor should not be visible on function object or its prototype
   2267   CHECK(
   2268       CompileRun("s.knurd == undefined")->BooleanValue(env.local()).FromJust());
   2269   CHECK(CompileRun("s.prototype.knurd == undefined")
   2270             ->BooleanValue(env.local())
   2271             .FromJust());
   2272   CHECK(CompileRun("base1.prototype.knurd == undefined")
   2273             ->BooleanValue(env.local())
   2274             .FromJust());
   2275 
   2276   CHECK(env->Global()
   2277             ->Set(env.local(), v8_str("obj"), base1->GetFunction(env.local())
   2278                                                   .ToLocalChecked()
   2279                                                   ->NewInstance(env.local())
   2280                                                   .ToLocalChecked())
   2281             .FromJust());
   2282   CHECK_EQ(17.2,
   2283            CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust());
   2284   CHECK(CompileRun("'flabby' in obj")->BooleanValue(env.local()).FromJust());
   2285   CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust());
   2286   CHECK(CompileRun("'knurd' in obj")->BooleanValue(env.local()).FromJust());
   2287   CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust());
   2288 
   2289   CHECK(env->Global()
   2290             ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local())
   2291                                                    .ToLocalChecked()
   2292                                                    ->NewInstance(env.local())
   2293                                                    .ToLocalChecked())
   2294             .FromJust());
   2295   CHECK_EQ(17.2,
   2296            CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust());
   2297   CHECK(CompileRun("'flabby' in obj2")->BooleanValue(env.local()).FromJust());
   2298   CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust());
   2299   CHECK(CompileRun("'knurd' in obj2")->BooleanValue(env.local()).FromJust());
   2300   CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust());
   2301 
   2302   // base1 and base2 cannot cross reference to each's prototype
   2303   CHECK(CompileRun("obj.v2")->IsUndefined());
   2304   CHECK(CompileRun("obj2.v1")->IsUndefined());
   2305 }
   2306 
   2307 THREADED_TEST(DescriptorInheritance2) {
   2308   LocalContext env;
   2309   v8::Isolate* isolate = CcTest::isolate();
   2310   v8::HandleScope scope(isolate);
   2311   v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate);
   2312   fun_A->SetClassName(v8_str("A"));
   2313   fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd);
   2314   fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk);
   2315   fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino);
   2316 
   2317   v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate);
   2318   fun_B->SetClassName(v8_str("B"));
   2319   fun_B->Inherit(fun_A);
   2320 
   2321   v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate);
   2322   fun_C->SetClassName(v8_str("C"));
   2323   fun_C->Inherit(fun_B);
   2324   fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd);
   2325   fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk);
   2326   fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino);
   2327 
   2328   v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate);
   2329   fun_D->SetClassName(v8_str("D"));
   2330   fun_D->Inherit(fun_C);
   2331 
   2332   v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate);
   2333   fun_E->SetClassName(v8_str("E"));
   2334   fun_E->Inherit(fun_D);
   2335   fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd);
   2336   fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk);
   2337   fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino);
   2338 
   2339   v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate);
   2340   fun_F->SetClassName(v8_str("F"));
   2341   fun_F->Inherit(fun_E);
   2342   v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate();
   2343   const int kDataPropertiesNumber = 100;
   2344   for (int i = 0; i < kDataPropertiesNumber; i++) {
   2345     v8::Local<v8::Value> val = v8_num(i);
   2346     v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
   2347     v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str);
   2348 
   2349     templ->Set(name, val);
   2350     templ->Set(val_str, val);
   2351   }
   2352 
   2353   CHECK(env->Global()
   2354             ->Set(env.local(), v8_str("F"),
   2355                   fun_F->GetFunction(env.local()).ToLocalChecked())
   2356             .FromJust());
   2357 
   2358   v8::Local<v8::Script> script = v8_compile("o = new F()");
   2359 
   2360   for (int i = 0; i < 100; i++) {
   2361     v8::HandleScope scope(isolate);
   2362     script->Run(env.local()).ToLocalChecked();
   2363   }
   2364   v8::Local<v8::Object> object = script->Run(env.local())
   2365                                      .ToLocalChecked()
   2366                                      ->ToObject(env.local())
   2367                                      .ToLocalChecked();
   2368 
   2369   CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust());
   2370   CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust());
   2371   CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust());
   2372 
   2373   CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust());
   2374   CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust());
   2375   CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust());
   2376 
   2377   CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust());
   2378   CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust());
   2379   CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust());
   2380 
   2381   for (int i = 0; i < kDataPropertiesNumber; i++) {
   2382     v8::Local<v8::Value> val = v8_num(i);
   2383     v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked();
   2384     v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str);
   2385 
   2386     CHECK_EQ(i, object->Get(env.local(), name)
   2387                     .ToLocalChecked()
   2388                     ->IntegerValue(env.local())
   2389                     .FromJust());
   2390     CHECK_EQ(i, object->Get(env.local(), val)
   2391                     .ToLocalChecked()
   2392                     ->IntegerValue(env.local())
   2393                     .FromJust());
   2394   }
   2395 }
   2396 
   2397 
   2398 // Helper functions for Interceptor/Accessor interaction tests
   2399 
   2400 void SimpleAccessorGetter(Local<String> name,
   2401                           const v8::PropertyCallbackInfo<v8::Value>& info) {
   2402   Local<Object> self = Local<Object>::Cast(info.This());
   2403   info.GetReturnValue().Set(self->Get(info.GetIsolate()->GetCurrentContext(),
   2404                                       String::Concat(v8_str("accessor_"), name))
   2405                                 .ToLocalChecked());
   2406 }
   2407 
   2408 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
   2409                           const v8::PropertyCallbackInfo<void>& info) {
   2410   Local<Object> self = Local<Object>::Cast(info.This());
   2411   CHECK(self->Set(info.GetIsolate()->GetCurrentContext(),
   2412                   String::Concat(v8_str("accessor_"), name), value)
   2413             .FromJust());
   2414 }
   2415 
   2416 void SymbolAccessorGetter(Local<Name> name,
   2417                           const v8::PropertyCallbackInfo<v8::Value>& info) {
   2418   CHECK(name->IsSymbol());
   2419   Local<Symbol> sym = Local<Symbol>::Cast(name);
   2420   if (sym->Name()->IsUndefined())
   2421     return;
   2422   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
   2423 }
   2424 
   2425 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
   2426                           const v8::PropertyCallbackInfo<void>& info) {
   2427   CHECK(name->IsSymbol());
   2428   Local<Symbol> sym = Local<Symbol>::Cast(name);
   2429   if (sym->Name()->IsUndefined())
   2430     return;
   2431   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
   2432 }
   2433 
   2434 void SymbolAccessorGetterReturnsDefault(
   2435     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   2436   CHECK(name->IsSymbol());
   2437   Local<Symbol> sym = Local<Symbol>::Cast(name);
   2438   if (sym->Name()->IsUndefined()) return;
   2439   info.GetReturnValue().Set(info.Data());
   2440 }
   2441 
   2442 static void ThrowingSymbolAccessorGetter(
   2443     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   2444   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
   2445 }
   2446 
   2447 
   2448 THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
   2449   v8::Isolate* isolate = CcTest::isolate();
   2450   v8::HandleScope scope(isolate);
   2451   LocalContext env;
   2452   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
   2453   i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
   2454   CHECK(a->map()->instance_descriptors()->IsFixedArray());
   2455   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
   2456   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
   2457   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
   2458   // But we should still have an AccessorInfo.
   2459   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
   2460   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
   2461   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
   2462   CHECK(it.GetAccessors()->IsAccessorInfo());
   2463 }
   2464 
   2465 
   2466 THREADED_TEST(UndefinedIsNotEnumerable) {
   2467   LocalContext env;
   2468   v8::HandleScope scope(env->GetIsolate());
   2469   v8::Local<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
   2470   CHECK(result->IsFalse());
   2471 }
   2472 
   2473 
   2474 v8::Local<Script> call_recursively_script;
   2475 static const int kTargetRecursionDepth = 150;  // near maximum
   2476 
   2477 
   2478 static void CallScriptRecursivelyCall(
   2479     const v8::FunctionCallbackInfo<v8::Value>& args) {
   2480   ApiTestFuzzer::Fuzz();
   2481   v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
   2482   int depth = args.This()
   2483                   ->Get(context, v8_str("depth"))
   2484                   .ToLocalChecked()
   2485                   ->Int32Value(context)
   2486                   .FromJust();
   2487   if (depth == kTargetRecursionDepth) return;
   2488   CHECK(args.This()
   2489             ->Set(context, v8_str("depth"),
   2490                   v8::Integer::New(args.GetIsolate(), depth + 1))
   2491             .FromJust());
   2492   args.GetReturnValue().Set(
   2493       call_recursively_script->Run(context).ToLocalChecked());
   2494 }
   2495 
   2496 
   2497 static void CallFunctionRecursivelyCall(
   2498     const v8::FunctionCallbackInfo<v8::Value>& args) {
   2499   ApiTestFuzzer::Fuzz();
   2500   v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
   2501   int depth = args.This()
   2502                   ->Get(context, v8_str("depth"))
   2503                   .ToLocalChecked()
   2504                   ->Int32Value(context)
   2505                   .FromJust();
   2506   if (depth == kTargetRecursionDepth) {
   2507     printf("[depth = %d]\n", depth);
   2508     return;
   2509   }
   2510   CHECK(args.This()
   2511             ->Set(context, v8_str("depth"),
   2512                   v8::Integer::New(args.GetIsolate(), depth + 1))
   2513             .FromJust());
   2514   v8::Local<Value> function =
   2515       args.This()
   2516           ->Get(context, v8_str("callFunctionRecursively"))
   2517           .ToLocalChecked();
   2518   args.GetReturnValue().Set(function.As<Function>()
   2519                                 ->Call(context, args.This(), 0, NULL)
   2520                                 .ToLocalChecked());
   2521 }
   2522 
   2523 
   2524 THREADED_TEST(DeepCrossLanguageRecursion) {
   2525   v8::Isolate* isolate = CcTest::isolate();
   2526   v8::HandleScope scope(isolate);
   2527   v8::Local<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
   2528   global->Set(v8_str("callScriptRecursively"),
   2529               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
   2530   global->Set(v8_str("callFunctionRecursively"),
   2531               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
   2532   LocalContext env(NULL, global);
   2533 
   2534   CHECK(env->Global()
   2535             ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
   2536             .FromJust());
   2537   call_recursively_script = v8_compile("callScriptRecursively()");
   2538   call_recursively_script->Run(env.local()).ToLocalChecked();
   2539   call_recursively_script = v8::Local<Script>();
   2540 
   2541   CHECK(env->Global()
   2542             ->Set(env.local(), v8_str("depth"), v8::Integer::New(isolate, 0))
   2543             .FromJust());
   2544   CompileRun("callFunctionRecursively()");
   2545 }
   2546 
   2547 
   2548 static void ThrowingPropertyHandlerGet(
   2549     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   2550   // Since this interceptor is used on "with" objects, the runtime will look up
   2551   // @@unscopables.  Punt.
   2552   if (key->IsSymbol()) return;
   2553   ApiTestFuzzer::Fuzz();
   2554   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
   2555 }
   2556 
   2557 
   2558 static void ThrowingPropertyHandlerSet(
   2559     Local<Name> key, Local<Value>,
   2560     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2561   info.GetIsolate()->ThrowException(key);
   2562   info.GetReturnValue().SetUndefined();  // not the same as empty handle
   2563 }
   2564 
   2565 
   2566 THREADED_TEST(CallbackExceptionRegression) {
   2567   v8::Isolate* isolate = CcTest::isolate();
   2568   v8::HandleScope scope(isolate);
   2569   v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   2570   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
   2571       ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
   2572   LocalContext env;
   2573   CHECK(env->Global()
   2574             ->Set(env.local(), v8_str("obj"),
   2575                   obj->NewInstance(env.local()).ToLocalChecked())
   2576             .FromJust());
   2577   v8::Local<Value> otto =
   2578       CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
   2579   CHECK(v8_str("otto")->Equals(env.local(), otto).FromJust());
   2580   v8::Local<Value> netto =
   2581       CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
   2582   CHECK(v8_str("netto")->Equals(env.local(), netto).FromJust());
   2583 }
   2584 
   2585 
   2586 THREADED_TEST(FunctionPrototype) {
   2587   v8::Isolate* isolate = CcTest::isolate();
   2588   v8::HandleScope scope(isolate);
   2589   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
   2590   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
   2591   LocalContext env;
   2592   CHECK(env->Global()
   2593             ->Set(env.local(), v8_str("Foo"),
   2594                   Foo->GetFunction(env.local()).ToLocalChecked())
   2595             .FromJust());
   2596   Local<Script> script = v8_compile("Foo.prototype.plak");
   2597   CHECK_EQ(v8_run_int32value(script), 321);
   2598 }
   2599 
   2600 
   2601 THREADED_TEST(InternalFields) {
   2602   LocalContext env;
   2603   v8::Isolate* isolate = env->GetIsolate();
   2604   v8::HandleScope scope(isolate);
   2605 
   2606   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2607   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   2608   instance_templ->SetInternalFieldCount(1);
   2609   Local<v8::Object> obj = templ->GetFunction(env.local())
   2610                               .ToLocalChecked()
   2611                               ->NewInstance(env.local())
   2612                               .ToLocalChecked();
   2613   CHECK_EQ(1, obj->InternalFieldCount());
   2614   CHECK(obj->GetInternalField(0)->IsUndefined());
   2615   obj->SetInternalField(0, v8_num(17));
   2616   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
   2617 }
   2618 
   2619 
   2620 THREADED_TEST(GlobalObjectInternalFields) {
   2621   v8::Isolate* isolate = CcTest::isolate();
   2622   v8::HandleScope scope(isolate);
   2623   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
   2624   global_template->SetInternalFieldCount(1);
   2625   LocalContext env(NULL, global_template);
   2626   v8::Local<v8::Object> global_proxy = env->Global();
   2627   v8::Local<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
   2628   CHECK_EQ(1, global->InternalFieldCount());
   2629   CHECK(global->GetInternalField(0)->IsUndefined());
   2630   global->SetInternalField(0, v8_num(17));
   2631   CHECK_EQ(17, global->GetInternalField(0)->Int32Value(env.local()).FromJust());
   2632 }
   2633 
   2634 
   2635 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
   2636   LocalContext env;
   2637   v8::HandleScope scope(CcTest::isolate());
   2638 
   2639   v8::Local<v8::Object> global = env->Global();
   2640   CHECK(global->Set(env.local(), 0, v8_str("value")).FromJust());
   2641   CHECK(global->HasRealIndexedProperty(env.local(), 0).FromJust());
   2642 }
   2643 
   2644 
   2645 static void CheckAlignedPointerInInternalField(Local<v8::Object> obj,
   2646                                                void* value) {
   2647   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
   2648   obj->SetAlignedPointerInInternalField(0, value);
   2649   CcTest::heap()->CollectAllGarbage();
   2650   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
   2651 }
   2652 
   2653 
   2654 THREADED_TEST(InternalFieldsAlignedPointers) {
   2655   LocalContext env;
   2656   v8::Isolate* isolate = env->GetIsolate();
   2657   v8::HandleScope scope(isolate);
   2658 
   2659   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2660   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   2661   instance_templ->SetInternalFieldCount(1);
   2662   Local<v8::Object> obj = templ->GetFunction(env.local())
   2663                               .ToLocalChecked()
   2664                               ->NewInstance(env.local())
   2665                               .ToLocalChecked();
   2666   CHECK_EQ(1, obj->InternalFieldCount());
   2667 
   2668   CheckAlignedPointerInInternalField(obj, NULL);
   2669 
   2670   int* heap_allocated = new int[100];
   2671   CheckAlignedPointerInInternalField(obj, heap_allocated);
   2672   delete[] heap_allocated;
   2673 
   2674   int stack_allocated[100];
   2675   CheckAlignedPointerInInternalField(obj, stack_allocated);
   2676 
   2677   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   2678   CheckAlignedPointerInInternalField(obj, huge);
   2679 
   2680   v8::Global<v8::Object> persistent(isolate, obj);
   2681   CHECK_EQ(1, Object::InternalFieldCount(persistent));
   2682   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
   2683 }
   2684 
   2685 
   2686 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
   2687                                               void* value) {
   2688   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
   2689   (*env)->SetAlignedPointerInEmbedderData(index, value);
   2690   CcTest::heap()->CollectAllGarbage();
   2691   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
   2692 }
   2693 
   2694 
   2695 static void* AlignedTestPointer(int i) {
   2696   return reinterpret_cast<void*>(i * 1234);
   2697 }
   2698 
   2699 
   2700 THREADED_TEST(EmbedderDataAlignedPointers) {
   2701   LocalContext env;
   2702   v8::HandleScope scope(env->GetIsolate());
   2703 
   2704   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
   2705 
   2706   int* heap_allocated = new int[100];
   2707   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
   2708   delete[] heap_allocated;
   2709 
   2710   int stack_allocated[100];
   2711   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
   2712 
   2713   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   2714   CheckAlignedPointerInEmbedderData(&env, 3, huge);
   2715 
   2716   // Test growing of the embedder data's backing store.
   2717   for (int i = 0; i < 100; i++) {
   2718     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
   2719   }
   2720   CcTest::heap()->CollectAllGarbage();
   2721   for (int i = 0; i < 100; i++) {
   2722     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
   2723   }
   2724 }
   2725 
   2726 
   2727 static void CheckEmbedderData(LocalContext* env, int index,
   2728                               v8::Local<Value> data) {
   2729   (*env)->SetEmbedderData(index, data);
   2730   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
   2731 }
   2732 
   2733 
   2734 THREADED_TEST(EmbedderData) {
   2735   LocalContext env;
   2736   v8::Isolate* isolate = env->GetIsolate();
   2737   v8::HandleScope scope(isolate);
   2738 
   2739   CheckEmbedderData(&env, 3, v8_str("The quick brown fox jumps"));
   2740   CheckEmbedderData(&env, 2, v8_str("over the lazy dog."));
   2741   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
   2742   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
   2743 }
   2744 
   2745 
   2746 THREADED_TEST(IdentityHash) {
   2747   LocalContext env;
   2748   v8::Isolate* isolate = env->GetIsolate();
   2749   v8::HandleScope scope(isolate);
   2750 
   2751   // Ensure that the test starts with an fresh heap to test whether the hash
   2752   // code is based on the address.
   2753   CcTest::heap()->CollectAllGarbage();
   2754   Local<v8::Object> obj = v8::Object::New(isolate);
   2755   int hash = obj->GetIdentityHash();
   2756   int hash1 = obj->GetIdentityHash();
   2757   CHECK_EQ(hash, hash1);
   2758   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
   2759   // Since the identity hash is essentially a random number two consecutive
   2760   // objects should not be assigned the same hash code. If the test below fails
   2761   // the random number generator should be evaluated.
   2762   CHECK_NE(hash, hash2);
   2763   CcTest::heap()->CollectAllGarbage();
   2764   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
   2765   // Make sure that the identity hash is not based on the initial address of
   2766   // the object alone. If the test below fails the random number generator
   2767   // should be evaluated.
   2768   CHECK_NE(hash, hash3);
   2769   int hash4 = obj->GetIdentityHash();
   2770   CHECK_EQ(hash, hash4);
   2771 
   2772   // Check identity hashes behaviour in the presence of JS accessors.
   2773   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
   2774   {
   2775     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
   2776     Local<v8::Object> o1 = v8::Object::New(isolate);
   2777     Local<v8::Object> o2 = v8::Object::New(isolate);
   2778     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2779   }
   2780   {
   2781     CompileRun(
   2782         "function cnst() { return 42; };\n"
   2783         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
   2784     Local<v8::Object> o1 = v8::Object::New(isolate);
   2785     Local<v8::Object> o2 = v8::Object::New(isolate);
   2786     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2787   }
   2788 }
   2789 
   2790 
   2791 void GlobalProxyIdentityHash(bool set_in_js) {
   2792   LocalContext env;
   2793   v8::Isolate* isolate = env->GetIsolate();
   2794   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   2795   v8::HandleScope scope(isolate);
   2796   Local<Object> global_proxy = env->Global();
   2797   i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
   2798   CHECK(env->Global()
   2799             ->Set(env.local(), v8_str("global"), global_proxy)
   2800             .FromJust());
   2801   int32_t hash1;
   2802   if (set_in_js) {
   2803     CompileRun("var m = new Set(); m.add(global);");
   2804     i::Object* original_hash = i_global_proxy->GetHash();
   2805     CHECK(original_hash->IsSmi());
   2806     hash1 = i::Smi::cast(original_hash)->value();
   2807   } else {
   2808     hash1 = i::Object::GetOrCreateHash(i_isolate, i_global_proxy)->value();
   2809   }
   2810   // Hash should be retained after being detached.
   2811   env->DetachGlobal();
   2812   int hash2 = global_proxy->GetIdentityHash();
   2813   CHECK_EQ(hash1, hash2);
   2814   {
   2815     // Re-attach global proxy to a new context, hash should stay the same.
   2816     LocalContext env2(NULL, Local<ObjectTemplate>(), global_proxy);
   2817     int hash3 = global_proxy->GetIdentityHash();
   2818     CHECK_EQ(hash1, hash3);
   2819   }
   2820 }
   2821 
   2822 
   2823 THREADED_TEST(GlobalProxyIdentityHash) {
   2824   GlobalProxyIdentityHash(true);
   2825   GlobalProxyIdentityHash(false);
   2826 }
   2827 
   2828 
   2829 TEST(SymbolIdentityHash) {
   2830   LocalContext env;
   2831   v8::Isolate* isolate = env->GetIsolate();
   2832   v8::HandleScope scope(isolate);
   2833 
   2834   {
   2835     Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
   2836     int hash = symbol->GetIdentityHash();
   2837     int hash1 = symbol->GetIdentityHash();
   2838     CHECK_EQ(hash, hash1);
   2839     CcTest::heap()->CollectAllGarbage();
   2840     int hash3 = symbol->GetIdentityHash();
   2841     CHECK_EQ(hash, hash3);
   2842   }
   2843 
   2844   {
   2845     v8::Local<v8::Symbol> js_symbol =
   2846         CompileRun("Symbol('foo')").As<v8::Symbol>();
   2847     int hash = js_symbol->GetIdentityHash();
   2848     int hash1 = js_symbol->GetIdentityHash();
   2849     CHECK_EQ(hash, hash1);
   2850     CcTest::heap()->CollectAllGarbage();
   2851     int hash3 = js_symbol->GetIdentityHash();
   2852     CHECK_EQ(hash, hash3);
   2853   }
   2854 }
   2855 
   2856 
   2857 TEST(StringIdentityHash) {
   2858   LocalContext env;
   2859   v8::Isolate* isolate = env->GetIsolate();
   2860   v8::HandleScope scope(isolate);
   2861 
   2862   Local<v8::String> str = v8_str("str1");
   2863   int hash = str->GetIdentityHash();
   2864   int hash1 = str->GetIdentityHash();
   2865   CHECK_EQ(hash, hash1);
   2866   CcTest::heap()->CollectAllGarbage();
   2867   int hash3 = str->GetIdentityHash();
   2868   CHECK_EQ(hash, hash3);
   2869 
   2870   Local<v8::String> str2 = v8_str("str1");
   2871   int hash4 = str2->GetIdentityHash();
   2872   CHECK_EQ(hash, hash4);
   2873 }
   2874 
   2875 
   2876 THREADED_TEST(SymbolProperties) {
   2877   LocalContext env;
   2878   v8::Isolate* isolate = env->GetIsolate();
   2879   v8::HandleScope scope(isolate);
   2880 
   2881   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   2882   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
   2883   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
   2884   v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
   2885 
   2886   CcTest::heap()->CollectAllGarbage();
   2887 
   2888   // Check basic symbol functionality.
   2889   CHECK(sym1->IsSymbol());
   2890   CHECK(sym2->IsSymbol());
   2891   CHECK(!obj->IsSymbol());
   2892 
   2893   CHECK(sym1->Equals(env.local(), sym1).FromJust());
   2894   CHECK(sym2->Equals(env.local(), sym2).FromJust());
   2895   CHECK(!sym1->Equals(env.local(), sym2).FromJust());
   2896   CHECK(!sym2->Equals(env.local(), sym1).FromJust());
   2897   CHECK(sym1->StrictEquals(sym1));
   2898   CHECK(sym2->StrictEquals(sym2));
   2899   CHECK(!sym1->StrictEquals(sym2));
   2900   CHECK(!sym2->StrictEquals(sym1));
   2901 
   2902   CHECK(sym2->Name()->Equals(env.local(), v8_str("my-symbol")).FromJust());
   2903 
   2904   v8::Local<v8::Value> sym_val = sym2;
   2905   CHECK(sym_val->IsSymbol());
   2906   CHECK(sym_val->Equals(env.local(), sym2).FromJust());
   2907   CHECK(sym_val->StrictEquals(sym2));
   2908   CHECK(v8::Symbol::Cast(*sym_val)->Equals(env.local(), sym2).FromJust());
   2909 
   2910   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
   2911   CHECK(sym_obj->IsSymbolObject());
   2912   CHECK(!sym2->IsSymbolObject());
   2913   CHECK(!obj->IsSymbolObject());
   2914   CHECK(sym_obj->Equals(env.local(), sym2).FromJust());
   2915   CHECK(!sym_obj->StrictEquals(sym2));
   2916   CHECK(v8::SymbolObject::Cast(*sym_obj)
   2917             ->Equals(env.local(), sym_obj)
   2918             .FromJust());
   2919   CHECK(v8::SymbolObject::Cast(*sym_obj)
   2920             ->ValueOf()
   2921             ->Equals(env.local(), sym2)
   2922             .FromJust());
   2923 
   2924   // Make sure delete of a non-existent symbol property works.
   2925   CHECK(obj->Delete(env.local(), sym1).FromJust());
   2926   CHECK(!obj->Has(env.local(), sym1).FromJust());
   2927 
   2928   CHECK(
   2929       obj->Set(env.local(), sym1, v8::Integer::New(isolate, 1503)).FromJust());
   2930   CHECK(obj->Has(env.local(), sym1).FromJust());
   2931   CHECK_EQ(1503, obj->Get(env.local(), sym1)
   2932                      .ToLocalChecked()
   2933                      ->Int32Value(env.local())
   2934                      .FromJust());
   2935   CHECK(
   2936       obj->Set(env.local(), sym1, v8::Integer::New(isolate, 2002)).FromJust());
   2937   CHECK(obj->Has(env.local(), sym1).FromJust());
   2938   CHECK_EQ(2002, obj->Get(env.local(), sym1)
   2939                      .ToLocalChecked()
   2940                      ->Int32Value(env.local())
   2941                      .FromJust());
   2942   CHECK_EQ(v8::None, obj->GetPropertyAttributes(env.local(), sym1).FromJust());
   2943 
   2944   CHECK_EQ(0u,
   2945            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   2946   unsigned num_props =
   2947       obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
   2948   CHECK(obj->Set(env.local(), v8_str("bla"), v8::Integer::New(isolate, 20))
   2949             .FromJust());
   2950   CHECK_EQ(1u,
   2951            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   2952   CHECK_EQ(num_props + 1,
   2953            obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
   2954 
   2955   CcTest::heap()->CollectAllGarbage();
   2956 
   2957   CHECK(obj->SetAccessor(env.local(), sym3, SymbolAccessorGetter,
   2958                          SymbolAccessorSetter)
   2959             .FromJust());
   2960   CHECK(obj->Get(env.local(), sym3).ToLocalChecked()->IsUndefined());
   2961   CHECK(obj->Set(env.local(), sym3, v8::Integer::New(isolate, 42)).FromJust());
   2962   CHECK(obj->Get(env.local(), sym3)
   2963             .ToLocalChecked()
   2964             ->Equals(env.local(), v8::Integer::New(isolate, 42))
   2965             .FromJust());
   2966   CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
   2967             .ToLocalChecked()
   2968             ->Equals(env.local(), v8::Integer::New(isolate, 42))
   2969             .FromJust());
   2970 
   2971   // Add another property and delete it afterwards to force the object in
   2972   // slow case.
   2973   CHECK(
   2974       obj->Set(env.local(), sym2, v8::Integer::New(isolate, 2008)).FromJust());
   2975   CHECK_EQ(2002, obj->Get(env.local(), sym1)
   2976                      .ToLocalChecked()
   2977                      ->Int32Value(env.local())
   2978                      .FromJust());
   2979   CHECK_EQ(2008, obj->Get(env.local(), sym2)
   2980                      .ToLocalChecked()
   2981                      ->Int32Value(env.local())
   2982                      .FromJust());
   2983   CHECK_EQ(2002, obj->Get(env.local(), sym1)
   2984                      .ToLocalChecked()
   2985                      ->Int32Value(env.local())
   2986                      .FromJust());
   2987   CHECK_EQ(2u,
   2988            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   2989 
   2990   CHECK(obj->Has(env.local(), sym1).FromJust());
   2991   CHECK(obj->Has(env.local(), sym2).FromJust());
   2992   CHECK(obj->Has(env.local(), sym3).FromJust());
   2993   CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
   2994   CHECK(obj->Delete(env.local(), sym2).FromJust());
   2995   CHECK(obj->Has(env.local(), sym1).FromJust());
   2996   CHECK(!obj->Has(env.local(), sym2).FromJust());
   2997   CHECK(obj->Has(env.local(), sym3).FromJust());
   2998   CHECK(obj->Has(env.local(), v8_str("accessor_sym3")).FromJust());
   2999   CHECK_EQ(2002, obj->Get(env.local(), sym1)
   3000                      .ToLocalChecked()
   3001                      ->Int32Value(env.local())
   3002                      .FromJust());
   3003   CHECK(obj->Get(env.local(), sym3)
   3004             .ToLocalChecked()
   3005             ->Equals(env.local(), v8::Integer::New(isolate, 42))
   3006             .FromJust());
   3007   CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
   3008             .ToLocalChecked()
   3009             ->Equals(env.local(), v8::Integer::New(isolate, 42))
   3010             .FromJust());
   3011   CHECK_EQ(2u,
   3012            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3013 
   3014   // Symbol properties are inherited.
   3015   v8::Local<v8::Object> child = v8::Object::New(isolate);
   3016   CHECK(child->SetPrototype(env.local(), obj).FromJust());
   3017   CHECK(child->Has(env.local(), sym1).FromJust());
   3018   CHECK_EQ(2002, child->Get(env.local(), sym1)
   3019                      .ToLocalChecked()
   3020                      ->Int32Value(env.local())
   3021                      .FromJust());
   3022   CHECK(obj->Get(env.local(), sym3)
   3023             .ToLocalChecked()
   3024             ->Equals(env.local(), v8::Integer::New(isolate, 42))
   3025             .FromJust());
   3026   CHECK(obj->Get(env.local(), v8_str("accessor_sym3"))
   3027             .ToLocalChecked()
   3028             ->Equals(env.local(), v8::Integer::New(isolate, 42))
   3029             .FromJust());
   3030   CHECK_EQ(0u,
   3031            child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3032 }
   3033 
   3034 
   3035 THREADED_TEST(SymbolTemplateProperties) {
   3036   LocalContext env;
   3037   v8::Isolate* isolate = env->GetIsolate();
   3038   v8::HandleScope scope(isolate);
   3039   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
   3040   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
   3041   CHECK(!name.IsEmpty());
   3042   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
   3043   v8::Local<v8::Object> new_instance =
   3044       foo->InstanceTemplate()->NewInstance(env.local()).ToLocalChecked();
   3045   CHECK(!new_instance.IsEmpty());
   3046   CHECK(new_instance->Has(env.local(), name).FromJust());
   3047 }
   3048 
   3049 
   3050 THREADED_TEST(PrivatePropertiesOnProxies) {
   3051   LocalContext env;
   3052   v8::Isolate* isolate = env->GetIsolate();
   3053   v8::HandleScope scope(isolate);
   3054 
   3055   v8::Local<v8::Object> target = CompileRun("({})").As<v8::Object>();
   3056   v8::Local<v8::Object> handler = CompileRun("({})").As<v8::Object>();
   3057 
   3058   v8::Local<v8::Proxy> proxy =
   3059       v8::Proxy::New(env.local(), target, handler).ToLocalChecked();
   3060 
   3061   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
   3062   v8::Local<v8::Private> priv2 =
   3063       v8::Private::New(isolate, v8_str("my-private"));
   3064 
   3065   CcTest::heap()->CollectAllGarbage();
   3066 
   3067   CHECK(priv2->Name()
   3068             ->Equals(env.local(),
   3069                      v8::String::NewFromUtf8(isolate, "my-private",
   3070                                              v8::NewStringType::kNormal)
   3071                          .ToLocalChecked())
   3072             .FromJust());
   3073 
   3074   // Make sure delete of a non-existent private symbol property works.
   3075   proxy->DeletePrivate(env.local(), priv1).FromJust();
   3076   CHECK(!proxy->HasPrivate(env.local(), priv1).FromJust());
   3077 
   3078   CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
   3079             .FromJust());
   3080   CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
   3081   CHECK_EQ(1503, proxy->GetPrivate(env.local(), priv1)
   3082                      .ToLocalChecked()
   3083                      ->Int32Value(env.local())
   3084                      .FromJust());
   3085   CHECK(proxy->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
   3086             .FromJust());
   3087   CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
   3088   CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
   3089                      .ToLocalChecked()
   3090                      ->Int32Value(env.local())
   3091                      .FromJust());
   3092 
   3093   CHECK_EQ(0u,
   3094            proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3095   unsigned num_props =
   3096       proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length();
   3097   CHECK(proxy->Set(env.local(), v8::String::NewFromUtf8(
   3098                                     isolate, "bla", v8::NewStringType::kNormal)
   3099                                     .ToLocalChecked(),
   3100                    v8::Integer::New(isolate, 20))
   3101             .FromJust());
   3102   CHECK_EQ(1u,
   3103            proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3104   CHECK_EQ(num_props + 1,
   3105            proxy->GetPropertyNames(env.local()).ToLocalChecked()->Length());
   3106 
   3107   CcTest::heap()->CollectAllGarbage();
   3108 
   3109   // Add another property and delete it afterwards to force the object in
   3110   // slow case.
   3111   CHECK(proxy->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
   3112             .FromJust());
   3113   CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
   3114                      .ToLocalChecked()
   3115                      ->Int32Value(env.local())
   3116                      .FromJust());
   3117   CHECK_EQ(2008, proxy->GetPrivate(env.local(), priv2)
   3118                      .ToLocalChecked()
   3119                      ->Int32Value(env.local())
   3120                      .FromJust());
   3121   CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
   3122                      .ToLocalChecked()
   3123                      ->Int32Value(env.local())
   3124                      .FromJust());
   3125   CHECK_EQ(1u,
   3126            proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3127 
   3128   CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
   3129   CHECK(proxy->HasPrivate(env.local(), priv2).FromJust());
   3130   CHECK(proxy->DeletePrivate(env.local(), priv2).FromJust());
   3131   CHECK(proxy->HasPrivate(env.local(), priv1).FromJust());
   3132   CHECK(!proxy->HasPrivate(env.local(), priv2).FromJust());
   3133   CHECK_EQ(2002, proxy->GetPrivate(env.local(), priv1)
   3134                      .ToLocalChecked()
   3135                      ->Int32Value(env.local())
   3136                      .FromJust());
   3137   CHECK_EQ(1u,
   3138            proxy->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3139 
   3140   // Private properties are not inherited (for the time being).
   3141   v8::Local<v8::Object> child = v8::Object::New(isolate);
   3142   CHECK(child->SetPrototype(env.local(), proxy).FromJust());
   3143   CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
   3144   CHECK_EQ(0u,
   3145            child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3146 }
   3147 
   3148 
   3149 THREADED_TEST(PrivateProperties) {
   3150   LocalContext env;
   3151   v8::Isolate* isolate = env->GetIsolate();
   3152   v8::HandleScope scope(isolate);
   3153 
   3154   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   3155   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
   3156   v8::Local<v8::Private> priv2 =
   3157       v8::Private::New(isolate, v8_str("my-private"));
   3158 
   3159   CcTest::heap()->CollectAllGarbage();
   3160 
   3161   CHECK(priv2->Name()
   3162             ->Equals(env.local(),
   3163                      v8::String::NewFromUtf8(isolate, "my-private",
   3164                                              v8::NewStringType::kNormal)
   3165                          .ToLocalChecked())
   3166             .FromJust());
   3167 
   3168   // Make sure delete of a non-existent private symbol property works.
   3169   obj->DeletePrivate(env.local(), priv1).FromJust();
   3170   CHECK(!obj->HasPrivate(env.local(), priv1).FromJust());
   3171 
   3172   CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 1503))
   3173             .FromJust());
   3174   CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
   3175   CHECK_EQ(1503, obj->GetPrivate(env.local(), priv1)
   3176                      .ToLocalChecked()
   3177                      ->Int32Value(env.local())
   3178                      .FromJust());
   3179   CHECK(obj->SetPrivate(env.local(), priv1, v8::Integer::New(isolate, 2002))
   3180             .FromJust());
   3181   CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
   3182   CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
   3183                      .ToLocalChecked()
   3184                      ->Int32Value(env.local())
   3185                      .FromJust());
   3186 
   3187   CHECK_EQ(0u,
   3188            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3189   unsigned num_props =
   3190       obj->GetPropertyNames(env.local()).ToLocalChecked()->Length();
   3191   CHECK(obj->Set(env.local(), v8::String::NewFromUtf8(
   3192                                   isolate, "bla", v8::NewStringType::kNormal)
   3193                                   .ToLocalChecked(),
   3194                  v8::Integer::New(isolate, 20))
   3195             .FromJust());
   3196   CHECK_EQ(1u,
   3197            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3198   CHECK_EQ(num_props + 1,
   3199            obj->GetPropertyNames(env.local()).ToLocalChecked()->Length());
   3200 
   3201   CcTest::heap()->CollectAllGarbage();
   3202 
   3203   // Add another property and delete it afterwards to force the object in
   3204   // slow case.
   3205   CHECK(obj->SetPrivate(env.local(), priv2, v8::Integer::New(isolate, 2008))
   3206             .FromJust());
   3207   CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
   3208                      .ToLocalChecked()
   3209                      ->Int32Value(env.local())
   3210                      .FromJust());
   3211   CHECK_EQ(2008, obj->GetPrivate(env.local(), priv2)
   3212                      .ToLocalChecked()
   3213                      ->Int32Value(env.local())
   3214                      .FromJust());
   3215   CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
   3216                      .ToLocalChecked()
   3217                      ->Int32Value(env.local())
   3218                      .FromJust());
   3219   CHECK_EQ(1u,
   3220            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3221 
   3222   CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
   3223   CHECK(obj->HasPrivate(env.local(), priv2).FromJust());
   3224   CHECK(obj->DeletePrivate(env.local(), priv2).FromJust());
   3225   CHECK(obj->HasPrivate(env.local(), priv1).FromJust());
   3226   CHECK(!obj->HasPrivate(env.local(), priv2).FromJust());
   3227   CHECK_EQ(2002, obj->GetPrivate(env.local(), priv1)
   3228                      .ToLocalChecked()
   3229                      ->Int32Value(env.local())
   3230                      .FromJust());
   3231   CHECK_EQ(1u,
   3232            obj->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3233 
   3234   // Private properties are not inherited (for the time being).
   3235   v8::Local<v8::Object> child = v8::Object::New(isolate);
   3236   CHECK(child->SetPrototype(env.local(), obj).FromJust());
   3237   CHECK(!child->HasPrivate(env.local(), priv1).FromJust());
   3238   CHECK_EQ(0u,
   3239            child->GetOwnPropertyNames(env.local()).ToLocalChecked()->Length());
   3240 }
   3241 
   3242 
   3243 THREADED_TEST(GlobalSymbols) {
   3244   LocalContext env;
   3245   v8::Isolate* isolate = env->GetIsolate();
   3246   v8::HandleScope scope(isolate);
   3247 
   3248   v8::Local<String> name = v8_str("my-symbol");
   3249   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
   3250   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
   3251   CHECK(glob2->SameValue(glob));
   3252 
   3253   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
   3254   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
   3255   CHECK(glob_api2->SameValue(glob_api));
   3256   CHECK(!glob_api->SameValue(glob));
   3257 
   3258   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
   3259   CHECK(!sym->SameValue(glob));
   3260 
   3261   CompileRun("var sym2 = Symbol.for('my-symbol')");
   3262   v8::Local<Value> sym2 =
   3263       env->Global()->Get(env.local(), v8_str("sym2")).ToLocalChecked();
   3264   CHECK(sym2->SameValue(glob));
   3265   CHECK(!sym2->SameValue(glob_api));
   3266 }
   3267 
   3268 
   3269 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
   3270                                  const char* name) {
   3271   LocalContext env;
   3272   v8::Isolate* isolate = env->GetIsolate();
   3273   v8::HandleScope scope(isolate);
   3274 
   3275   v8::Local<v8::Symbol> symbol = getter(isolate);
   3276   std::string script = std::string("var sym = ") + name;
   3277   CompileRun(script.c_str());
   3278   v8::Local<Value> value =
   3279       env->Global()->Get(env.local(), v8_str("sym")).ToLocalChecked();
   3280 
   3281   CHECK(!value.IsEmpty());
   3282   CHECK(!symbol.IsEmpty());
   3283   CHECK(value->SameValue(symbol));
   3284 }
   3285 
   3286 
   3287 THREADED_TEST(WellKnownSymbols) {
   3288   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
   3289   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
   3290 }
   3291 
   3292 
   3293 THREADED_TEST(GlobalPrivates) {
   3294   i::FLAG_allow_natives_syntax = true;
   3295   LocalContext env;
   3296   v8::Isolate* isolate = env->GetIsolate();
   3297   v8::HandleScope scope(isolate);
   3298 
   3299   v8::Local<String> name = v8_str("my-private");
   3300   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
   3301   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   3302   CHECK(obj->SetPrivate(env.local(), glob, v8::Integer::New(isolate, 3))
   3303             .FromJust());
   3304 
   3305   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
   3306   CHECK(obj->HasPrivate(env.local(), glob2).FromJust());
   3307 
   3308   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
   3309   CHECK(!obj->HasPrivate(env.local(), priv).FromJust());
   3310 
   3311   CompileRun("var intern = %CreatePrivateSymbol('my-private')");
   3312   v8::Local<Value> intern =
   3313       env->Global()->Get(env.local(), v8_str("intern")).ToLocalChecked();
   3314   CHECK(!obj->Has(env.local(), intern).FromJust());
   3315 }
   3316 
   3317 
   3318 class ScopedArrayBufferContents {
   3319  public:
   3320   explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
   3321       : contents_(contents) {}
   3322   ~ScopedArrayBufferContents() { free(contents_.Data()); }
   3323   void* Data() const { return contents_.Data(); }
   3324   size_t ByteLength() const { return contents_.ByteLength(); }
   3325 
   3326  private:
   3327   const v8::ArrayBuffer::Contents contents_;
   3328 };
   3329 
   3330 template <typename T>
   3331 static void CheckInternalFieldsAreZero(v8::Local<T> value) {
   3332   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
   3333   for (int i = 0; i < value->InternalFieldCount(); i++) {
   3334     CHECK_EQ(0, value->GetInternalField(i)
   3335                     ->Int32Value(CcTest::isolate()->GetCurrentContext())
   3336                     .FromJust());
   3337   }
   3338 }
   3339 
   3340 
   3341 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
   3342   LocalContext env;
   3343   v8::Isolate* isolate = env->GetIsolate();
   3344   v8::HandleScope handle_scope(isolate);
   3345 
   3346   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
   3347   CheckInternalFieldsAreZero(ab);
   3348   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
   3349   CHECK(!ab->IsExternal());
   3350   CcTest::heap()->CollectAllGarbage();
   3351 
   3352   ScopedArrayBufferContents ab_contents(ab->Externalize());
   3353   CHECK(ab->IsExternal());
   3354 
   3355   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
   3356   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
   3357   CHECK(data != NULL);
   3358   CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
   3359 
   3360   v8::Local<v8::Value> result = CompileRun("ab.byteLength");
   3361   CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
   3362 
   3363   result = CompileRun(
   3364       "var u8 = new Uint8Array(ab);"
   3365       "u8[0] = 0xFF;"
   3366       "u8[1] = 0xAA;"
   3367       "u8.length");
   3368   CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
   3369   CHECK_EQ(0xFF, data[0]);
   3370   CHECK_EQ(0xAA, data[1]);
   3371   data[0] = 0xCC;
   3372   data[1] = 0x11;
   3373   result = CompileRun("u8[0] + u8[1]");
   3374   CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
   3375 }
   3376 
   3377 
   3378 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
   3379   LocalContext env;
   3380   v8::Isolate* isolate = env->GetIsolate();
   3381   v8::HandleScope handle_scope(isolate);
   3382 
   3383 
   3384   v8::Local<v8::Value> result = CompileRun(
   3385       "var ab1 = new ArrayBuffer(2);"
   3386       "var u8_a = new Uint8Array(ab1);"
   3387       "u8_a[0] = 0xAA;"
   3388       "u8_a[1] = 0xFF; u8_a.buffer");
   3389   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
   3390   CheckInternalFieldsAreZero(ab1);
   3391   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
   3392   CHECK(!ab1->IsExternal());
   3393   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
   3394   CHECK(ab1->IsExternal());
   3395 
   3396   result = CompileRun("ab1.byteLength");
   3397   CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
   3398   result = CompileRun("u8_a[0]");
   3399   CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
   3400   result = CompileRun("u8_a[1]");
   3401   CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
   3402   result = CompileRun(
   3403       "var u8_b = new Uint8Array(ab1);"
   3404       "u8_b[0] = 0xBB;"
   3405       "u8_a[0]");
   3406   CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
   3407   result = CompileRun("u8_b[1]");
   3408   CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
   3409 
   3410   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
   3411   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
   3412   CHECK_EQ(0xBB, ab1_data[0]);
   3413   CHECK_EQ(0xFF, ab1_data[1]);
   3414   ab1_data[0] = 0xCC;
   3415   ab1_data[1] = 0x11;
   3416   result = CompileRun("u8_a[0] + u8_a[1]");
   3417   CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
   3418 }
   3419 
   3420 
   3421 THREADED_TEST(ArrayBuffer_External) {
   3422   LocalContext env;
   3423   v8::Isolate* isolate = env->GetIsolate();
   3424   v8::HandleScope handle_scope(isolate);
   3425 
   3426   i::ScopedVector<uint8_t> my_data(100);
   3427   memset(my_data.start(), 0, 100);
   3428   Local<v8::ArrayBuffer> ab3 =
   3429       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
   3430   CheckInternalFieldsAreZero(ab3);
   3431   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
   3432   CHECK(ab3->IsExternal());
   3433 
   3434   CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
   3435 
   3436   v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
   3437   CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
   3438 
   3439   result = CompileRun(
   3440       "var u8_b = new Uint8Array(ab3);"
   3441       "u8_b[0] = 0xBB;"
   3442       "u8_b[1] = 0xCC;"
   3443       "u8_b.length");
   3444   CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
   3445   CHECK_EQ(0xBB, my_data[0]);
   3446   CHECK_EQ(0xCC, my_data[1]);
   3447   my_data[0] = 0xCC;
   3448   my_data[1] = 0x11;
   3449   result = CompileRun("u8_b[0] + u8_b[1]");
   3450   CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
   3451 }
   3452 
   3453 
   3454 THREADED_TEST(ArrayBuffer_DisableNeuter) {
   3455   LocalContext env;
   3456   v8::Isolate* isolate = env->GetIsolate();
   3457   v8::HandleScope handle_scope(isolate);
   3458 
   3459   i::ScopedVector<uint8_t> my_data(100);
   3460   memset(my_data.start(), 0, 100);
   3461   Local<v8::ArrayBuffer> ab =
   3462       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
   3463   CHECK(ab->IsNeuterable());
   3464 
   3465   i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
   3466   buf->set_is_neuterable(false);
   3467 
   3468   CHECK(!ab->IsNeuterable());
   3469 }
   3470 
   3471 
   3472 static void CheckDataViewIsNeutered(v8::Local<v8::DataView> dv) {
   3473   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
   3474   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
   3475 }
   3476 
   3477 
   3478 static void CheckIsNeutered(v8::Local<v8::TypedArray> ta) {
   3479   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
   3480   CHECK_EQ(0, static_cast<int>(ta->Length()));
   3481   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
   3482 }
   3483 
   3484 
   3485 static void CheckIsTypedArrayVarNeutered(const char* name) {
   3486   i::ScopedVector<char> source(1024);
   3487   i::SNPrintF(source,
   3488               "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
   3489               name, name, name);
   3490   CHECK(CompileRun(source.start())->IsTrue());
   3491   v8::Local<v8::TypedArray> ta =
   3492       v8::Local<v8::TypedArray>::Cast(CompileRun(name));
   3493   CheckIsNeutered(ta);
   3494 }
   3495 
   3496 
   3497 template <typename TypedArray, int kElementSize>
   3498 static Local<TypedArray> CreateAndCheck(Local<v8::ArrayBuffer> ab,
   3499                                         int byteOffset, int length) {
   3500   v8::Local<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
   3501   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
   3502   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
   3503   CHECK_EQ(length, static_cast<int>(ta->Length()));
   3504   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
   3505   return ta;
   3506 }
   3507 
   3508 
   3509 THREADED_TEST(ArrayBuffer_NeuteringApi) {
   3510   LocalContext env;
   3511   v8::Isolate* isolate = env->GetIsolate();
   3512   v8::HandleScope handle_scope(isolate);
   3513 
   3514   v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
   3515 
   3516   v8::Local<v8::Uint8Array> u8a =
   3517       CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
   3518   v8::Local<v8::Uint8ClampedArray> u8c =
   3519       CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
   3520   v8::Local<v8::Int8Array> i8a =
   3521       CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
   3522 
   3523   v8::Local<v8::Uint16Array> u16a =
   3524       CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
   3525   v8::Local<v8::Int16Array> i16a =
   3526       CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
   3527 
   3528   v8::Local<v8::Uint32Array> u32a =
   3529       CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
   3530   v8::Local<v8::Int32Array> i32a =
   3531       CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
   3532 
   3533   v8::Local<v8::Float32Array> f32a =
   3534       CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
   3535   v8::Local<v8::Float64Array> f64a =
   3536       CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
   3537 
   3538   v8::Local<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
   3539   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
   3540   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
   3541   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
   3542 
   3543   ScopedArrayBufferContents contents(buffer->Externalize());
   3544   buffer->Neuter();
   3545   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
   3546   CheckIsNeutered(u8a);
   3547   CheckIsNeutered(u8c);
   3548   CheckIsNeutered(i8a);
   3549   CheckIsNeutered(u16a);
   3550   CheckIsNeutered(i16a);
   3551   CheckIsNeutered(u32a);
   3552   CheckIsNeutered(i32a);
   3553   CheckIsNeutered(f32a);
   3554   CheckIsNeutered(f64a);
   3555   CheckDataViewIsNeutered(dv);
   3556 }
   3557 
   3558 
   3559 THREADED_TEST(ArrayBuffer_NeuteringScript) {
   3560   LocalContext env;
   3561   v8::Isolate* isolate = env->GetIsolate();
   3562   v8::HandleScope handle_scope(isolate);
   3563 
   3564   CompileRun(
   3565       "var ab = new ArrayBuffer(1024);"
   3566       "var u8a = new Uint8Array(ab, 1, 1023);"
   3567       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
   3568       "var i8a = new Int8Array(ab, 1, 1023);"
   3569       "var u16a = new Uint16Array(ab, 2, 511);"
   3570       "var i16a = new Int16Array(ab, 2, 511);"
   3571       "var u32a = new Uint32Array(ab, 4, 255);"
   3572       "var i32a = new Int32Array(ab, 4, 255);"
   3573       "var f32a = new Float32Array(ab, 4, 255);"
   3574       "var f64a = new Float64Array(ab, 8, 127);"
   3575       "var dv = new DataView(ab, 1, 1023);");
   3576 
   3577   v8::Local<v8::ArrayBuffer> ab =
   3578       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
   3579 
   3580   v8::Local<v8::DataView> dv = v8::Local<v8::DataView>::Cast(CompileRun("dv"));
   3581 
   3582   ScopedArrayBufferContents contents(ab->Externalize());
   3583   ab->Neuter();
   3584   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
   3585   CHECK_EQ(0, v8_run_int32value(v8_compile("ab.byteLength")));
   3586 
   3587   CheckIsTypedArrayVarNeutered("u8a");
   3588   CheckIsTypedArrayVarNeutered("u8c");
   3589   CheckIsTypedArrayVarNeutered("i8a");
   3590   CheckIsTypedArrayVarNeutered("u16a");
   3591   CheckIsTypedArrayVarNeutered("i16a");
   3592   CheckIsTypedArrayVarNeutered("u32a");
   3593   CheckIsTypedArrayVarNeutered("i32a");
   3594   CheckIsTypedArrayVarNeutered("f32a");
   3595   CheckIsTypedArrayVarNeutered("f64a");
   3596 
   3597   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
   3598   CheckDataViewIsNeutered(dv);
   3599 }
   3600 
   3601 
   3602 class ScopedSharedArrayBufferContents {
   3603  public:
   3604   explicit ScopedSharedArrayBufferContents(
   3605       const v8::SharedArrayBuffer::Contents& contents)
   3606       : contents_(contents) {}
   3607   ~ScopedSharedArrayBufferContents() { free(contents_.Data()); }
   3608   void* Data() const { return contents_.Data(); }
   3609   size_t ByteLength() const { return contents_.ByteLength(); }
   3610 
   3611  private:
   3612   const v8::SharedArrayBuffer::Contents contents_;
   3613 };
   3614 
   3615 
   3616 THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
   3617   i::FLAG_harmony_sharedarraybuffer = true;
   3618   LocalContext env;
   3619   v8::Isolate* isolate = env->GetIsolate();
   3620   v8::HandleScope handle_scope(isolate);
   3621 
   3622   Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
   3623   CheckInternalFieldsAreZero(ab);
   3624   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
   3625   CHECK(!ab->IsExternal());
   3626   CcTest::heap()->CollectAllGarbage();
   3627 
   3628   ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
   3629   CHECK(ab->IsExternal());
   3630 
   3631   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
   3632   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
   3633   CHECK(data != NULL);
   3634   CHECK(env->Global()->Set(env.local(), v8_str("ab"), ab).FromJust());
   3635 
   3636   v8::Local<v8::Value> result = CompileRun("ab.byteLength");
   3637   CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
   3638 
   3639   result = CompileRun(
   3640       "var u8 = new Uint8Array(ab);"
   3641       "u8[0] = 0xFF;"
   3642       "u8[1] = 0xAA;"
   3643       "u8.length");
   3644   CHECK_EQ(1024, result->Int32Value(env.local()).FromJust());
   3645   CHECK_EQ(0xFF, data[0]);
   3646   CHECK_EQ(0xAA, data[1]);
   3647   data[0] = 0xCC;
   3648   data[1] = 0x11;
   3649   result = CompileRun("u8[0] + u8[1]");
   3650   CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
   3651 }
   3652 
   3653 
   3654 THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
   3655   i::FLAG_harmony_sharedarraybuffer = true;
   3656   LocalContext env;
   3657   v8::Isolate* isolate = env->GetIsolate();
   3658   v8::HandleScope handle_scope(isolate);
   3659 
   3660 
   3661   v8::Local<v8::Value> result = CompileRun(
   3662       "var ab1 = new SharedArrayBuffer(2);"
   3663       "var u8_a = new Uint8Array(ab1);"
   3664       "u8_a[0] = 0xAA;"
   3665       "u8_a[1] = 0xFF; u8_a.buffer");
   3666   Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
   3667   CheckInternalFieldsAreZero(ab1);
   3668   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
   3669   CHECK(!ab1->IsExternal());
   3670   ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
   3671   CHECK(ab1->IsExternal());
   3672 
   3673   result = CompileRun("ab1.byteLength");
   3674   CHECK_EQ(2, result->Int32Value(env.local()).FromJust());
   3675   result = CompileRun("u8_a[0]");
   3676   CHECK_EQ(0xAA, result->Int32Value(env.local()).FromJust());
   3677   result = CompileRun("u8_a[1]");
   3678   CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
   3679   result = CompileRun(
   3680       "var u8_b = new Uint8Array(ab1);"
   3681       "u8_b[0] = 0xBB;"
   3682       "u8_a[0]");
   3683   CHECK_EQ(0xBB, result->Int32Value(env.local()).FromJust());
   3684   result = CompileRun("u8_b[1]");
   3685   CHECK_EQ(0xFF, result->Int32Value(env.local()).FromJust());
   3686 
   3687   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
   3688   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
   3689   CHECK_EQ(0xBB, ab1_data[0]);
   3690   CHECK_EQ(0xFF, ab1_data[1]);
   3691   ab1_data[0] = 0xCC;
   3692   ab1_data[1] = 0x11;
   3693   result = CompileRun("u8_a[0] + u8_a[1]");
   3694   CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
   3695 }
   3696 
   3697 
   3698 THREADED_TEST(SharedArrayBuffer_External) {
   3699   i::FLAG_harmony_sharedarraybuffer = true;
   3700   LocalContext env;
   3701   v8::Isolate* isolate = env->GetIsolate();
   3702   v8::HandleScope handle_scope(isolate);
   3703 
   3704   i::ScopedVector<uint8_t> my_data(100);
   3705   memset(my_data.start(), 0, 100);
   3706   Local<v8::SharedArrayBuffer> ab3 =
   3707       v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
   3708   CheckInternalFieldsAreZero(ab3);
   3709   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
   3710   CHECK(ab3->IsExternal());
   3711 
   3712   CHECK(env->Global()->Set(env.local(), v8_str("ab3"), ab3).FromJust());
   3713 
   3714   v8::Local<v8::Value> result = CompileRun("ab3.byteLength");
   3715   CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
   3716 
   3717   result = CompileRun(
   3718       "var u8_b = new Uint8Array(ab3);"
   3719       "u8_b[0] = 0xBB;"
   3720       "u8_b[1] = 0xCC;"
   3721       "u8_b.length");
   3722   CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
   3723   CHECK_EQ(0xBB, my_data[0]);
   3724   CHECK_EQ(0xCC, my_data[1]);
   3725   my_data[0] = 0xCC;
   3726   my_data[1] = 0x11;
   3727   result = CompileRun("u8_b[0] + u8_b[1]");
   3728   CHECK_EQ(0xDD, result->Int32Value(env.local()).FromJust());
   3729 }
   3730 
   3731 
   3732 THREADED_TEST(HiddenProperties) {
   3733   LocalContext env;
   3734   v8::Isolate* isolate = env->GetIsolate();
   3735   v8::HandleScope scope(isolate);
   3736 
   3737   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
   3738   v8::Local<v8::Private> key =
   3739       v8::Private::ForApi(isolate, v8_str("api-test::hidden-key"));
   3740   v8::Local<v8::String> empty = v8_str("");
   3741   v8::Local<v8::String> prop_name = v8_str("prop_name");
   3742 
   3743   CcTest::heap()->CollectAllGarbage();
   3744 
   3745   // Make sure delete of a non-existent hidden value works
   3746   obj->DeletePrivate(env.local(), key).FromJust();
   3747 
   3748   CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 1503))
   3749             .FromJust());
   3750   CHECK_EQ(1503, obj->GetPrivate(env.local(), key)
   3751                      .ToLocalChecked()
   3752                      ->Int32Value(env.local())
   3753                      .FromJust());
   3754   CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
   3755             .FromJust());
   3756   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3757                      .ToLocalChecked()
   3758                      ->Int32Value(env.local())
   3759                      .FromJust());
   3760 
   3761   CcTest::heap()->CollectAllGarbage();
   3762 
   3763   // Make sure we do not find the hidden property.
   3764   CHECK(!obj->Has(env.local(), empty).FromJust());
   3765   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3766                      .ToLocalChecked()
   3767                      ->Int32Value(env.local())
   3768                      .FromJust());
   3769   CHECK(obj->Get(env.local(), empty).ToLocalChecked()->IsUndefined());
   3770   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3771                      .ToLocalChecked()
   3772                      ->Int32Value(env.local())
   3773                      .FromJust());
   3774   CHECK(
   3775       obj->Set(env.local(), empty, v8::Integer::New(isolate, 2003)).FromJust());
   3776   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3777                      .ToLocalChecked()
   3778                      ->Int32Value(env.local())
   3779                      .FromJust());
   3780   CHECK_EQ(2003, obj->Get(env.local(), empty)
   3781                      .ToLocalChecked()
   3782                      ->Int32Value(env.local())
   3783                      .FromJust());
   3784 
   3785   CcTest::heap()->CollectAllGarbage();
   3786 
   3787   // Add another property and delete it afterwards to force the object in
   3788   // slow case.
   3789   CHECK(obj->Set(env.local(), prop_name, v8::Integer::New(isolate, 2008))
   3790             .FromJust());
   3791   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3792                      .ToLocalChecked()
   3793                      ->Int32Value(env.local())
   3794                      .FromJust());
   3795   CHECK_EQ(2008, obj->Get(env.local(), prop_name)
   3796                      .ToLocalChecked()
   3797                      ->Int32Value(env.local())
   3798                      .FromJust());
   3799   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3800                      .ToLocalChecked()
   3801                      ->Int32Value(env.local())
   3802                      .FromJust());
   3803   CHECK(obj->Delete(env.local(), prop_name).FromJust());
   3804   CHECK_EQ(2002, obj->GetPrivate(env.local(), key)
   3805                      .ToLocalChecked()
   3806                      ->Int32Value(env.local())
   3807                      .FromJust());
   3808 
   3809   CcTest::heap()->CollectAllGarbage();
   3810 
   3811   CHECK(obj->SetPrivate(env.local(), key, v8::Integer::New(isolate, 2002))
   3812             .FromJust());
   3813   CHECK(obj->DeletePrivate(env.local(), key).FromJust());
   3814   CHECK(!obj->HasPrivate(env.local(), key).FromJust());
   3815 }
   3816 
   3817 
   3818 THREADED_TEST(Regress97784) {
   3819   // Regression test for crbug.com/97784
   3820   // Messing with the Object.prototype should not have effect on
   3821   // hidden properties.
   3822   LocalContext env;
   3823   v8::HandleScope scope(env->GetIsolate());
   3824 
   3825   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
   3826   v8::Local<v8::Private> key =
   3827       v8::Private::New(env->GetIsolate(), v8_str("hidden"));
   3828 
   3829   CompileRun(
   3830       "set_called = false;"
   3831       "Object.defineProperty("
   3832       "    Object.prototype,"
   3833       "    'hidden',"
   3834       "    {get: function() { return 45; },"
   3835       "     set: function() { set_called = true; }})");
   3836 
   3837   CHECK(!obj->HasPrivate(env.local(), key).FromJust());
   3838   // Make sure that the getter and setter from Object.prototype is not invoked.
   3839   // If it did we would have full access to the hidden properties in
   3840   // the accessor.
   3841   CHECK(
   3842       obj->SetPrivate(env.local(), key, v8::Integer::New(env->GetIsolate(), 42))
   3843           .FromJust());
   3844   ExpectFalse("set_called");
   3845   CHECK_EQ(42, obj->GetPrivate(env.local(), key)
   3846                    .ToLocalChecked()
   3847                    ->Int32Value(env.local())
   3848                    .FromJust());
   3849 }
   3850 
   3851 
   3852 THREADED_TEST(External) {
   3853   v8::HandleScope scope(CcTest::isolate());
   3854   int x = 3;
   3855   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
   3856   LocalContext env;
   3857   CHECK(env->Global()->Set(env.local(), v8_str("ext"), ext).FromJust());
   3858   Local<Value> reext_obj = CompileRun("this.ext");
   3859   v8::Local<v8::External> reext = reext_obj.As<v8::External>();
   3860   int* ptr = static_cast<int*>(reext->Value());
   3861   CHECK_EQ(x, 3);
   3862   *ptr = 10;
   3863   CHECK_EQ(x, 10);
   3864 
   3865   // Make sure unaligned pointers are wrapped properly.
   3866   char* data = i::StrDup("0123456789");
   3867   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
   3868   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
   3869   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
   3870   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
   3871 
   3872   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
   3873   CHECK_EQ('0', *char_ptr);
   3874   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
   3875   CHECK_EQ('1', *char_ptr);
   3876   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
   3877   CHECK_EQ('2', *char_ptr);
   3878   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
   3879   CHECK_EQ('3', *char_ptr);
   3880   i::DeleteArray(data);
   3881 }
   3882 
   3883 
   3884 THREADED_TEST(GlobalHandle) {
   3885   v8::Isolate* isolate = CcTest::isolate();
   3886   v8::Persistent<String> global;
   3887   {
   3888     v8::HandleScope scope(isolate);
   3889     global.Reset(isolate, v8_str("str"));
   3890   }
   3891   {
   3892     v8::HandleScope scope(isolate);
   3893     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3894   }
   3895   global.Reset();
   3896   {
   3897     v8::HandleScope scope(isolate);
   3898     global.Reset(isolate, v8_str("str"));
   3899   }
   3900   {
   3901     v8::HandleScope scope(isolate);
   3902     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3903   }
   3904   global.Reset();
   3905 }
   3906 
   3907 
   3908 THREADED_TEST(ResettingGlobalHandle) {
   3909   v8::Isolate* isolate = CcTest::isolate();
   3910   v8::Persistent<String> global;
   3911   {
   3912     v8::HandleScope scope(isolate);
   3913     global.Reset(isolate, v8_str("str"));
   3914   }
   3915   v8::internal::GlobalHandles* global_handles =
   3916       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3917   int initial_handle_count = global_handles->global_handles_count();
   3918   {
   3919     v8::HandleScope scope(isolate);
   3920     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3921   }
   3922   {
   3923     v8::HandleScope scope(isolate);
   3924     global.Reset(isolate, v8_str("longer"));
   3925   }
   3926   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
   3927   {
   3928     v8::HandleScope scope(isolate);
   3929     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
   3930   }
   3931   global.Reset();
   3932   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
   3933 }
   3934 
   3935 
   3936 THREADED_TEST(ResettingGlobalHandleToEmpty) {
   3937   v8::Isolate* isolate = CcTest::isolate();
   3938   v8::Persistent<String> global;
   3939   {
   3940     v8::HandleScope scope(isolate);
   3941     global.Reset(isolate, v8_str("str"));
   3942   }
   3943   v8::internal::GlobalHandles* global_handles =
   3944       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3945   int initial_handle_count = global_handles->global_handles_count();
   3946   {
   3947     v8::HandleScope scope(isolate);
   3948     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3949   }
   3950   {
   3951     v8::HandleScope scope(isolate);
   3952     Local<String> empty;
   3953     global.Reset(isolate, empty);
   3954   }
   3955   CHECK(global.IsEmpty());
   3956   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
   3957 }
   3958 
   3959 
   3960 template <class T>
   3961 static v8::Global<T> PassUnique(v8::Global<T> unique) {
   3962   return unique.Pass();
   3963 }
   3964 
   3965 
   3966 template <class T>
   3967 static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
   3968                                   const v8::Persistent<T>& global) {
   3969   v8::Global<String> unique(isolate, global);
   3970   return unique.Pass();
   3971 }
   3972 
   3973 
   3974 THREADED_TEST(Global) {
   3975   v8::Isolate* isolate = CcTest::isolate();
   3976   v8::Persistent<String> global;
   3977   {
   3978     v8::HandleScope scope(isolate);
   3979     global.Reset(isolate, v8_str("str"));
   3980   }
   3981   v8::internal::GlobalHandles* global_handles =
   3982       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3983   int initial_handle_count = global_handles->global_handles_count();
   3984   {
   3985     v8::Global<String> unique(isolate, global);
   3986     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3987     // Test assignment via Pass
   3988     {
   3989       v8::Global<String> copy = unique.Pass();
   3990       CHECK(unique.IsEmpty());
   3991       CHECK(copy == global);
   3992       CHECK_EQ(initial_handle_count + 1,
   3993                global_handles->global_handles_count());
   3994       unique = copy.Pass();
   3995     }
   3996     // Test ctor via Pass
   3997     {
   3998       v8::Global<String> copy(unique.Pass());
   3999       CHECK(unique.IsEmpty());
   4000       CHECK(copy == global);
   4001       CHECK_EQ(initial_handle_count + 1,
   4002                global_handles->global_handles_count());
   4003       unique = copy.Pass();
   4004     }
   4005     // Test pass through function call
   4006     {
   4007       v8::Global<String> copy = PassUnique(unique.Pass());
   4008       CHECK(unique.IsEmpty());
   4009       CHECK(copy == global);
   4010       CHECK_EQ(initial_handle_count + 1,
   4011                global_handles->global_handles_count());
   4012       unique = copy.Pass();
   4013     }
   4014     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   4015   }
   4016   // Test pass from function call
   4017   {
   4018     v8::Global<String> unique = ReturnUnique(isolate, global);
   4019     CHECK(unique == global);
   4020     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   4021   }
   4022   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   4023   global.Reset();
   4024 }
   4025 
   4026 
   4027 namespace {
   4028 
   4029 class TwoPassCallbackData;
   4030 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
   4031 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
   4032 
   4033 
   4034 class TwoPassCallbackData {
   4035  public:
   4036   TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
   4037       : first_pass_called_(false),
   4038         second_pass_called_(false),
   4039         trigger_gc_(false),
   4040         instance_counter_(instance_counter) {
   4041     HandleScope scope(isolate);
   4042     i::ScopedVector<char> buffer(40);
   4043     i::SNPrintF(buffer, "%p", static_cast<void*>(this));
   4044     auto string =
   4045         v8::String::NewFromUtf8(isolate, buffer.start(),
   4046                                 v8::NewStringType::kNormal).ToLocalChecked();
   4047     cell_.Reset(isolate, string);
   4048     (*instance_counter_)++;
   4049   }
   4050 
   4051   ~TwoPassCallbackData() {
   4052     CHECK(first_pass_called_);
   4053     CHECK(second_pass_called_);
   4054     CHECK(cell_.IsEmpty());
   4055     (*instance_counter_)--;
   4056   }
   4057 
   4058   void FirstPass() {
   4059     CHECK(!first_pass_called_);
   4060     CHECK(!second_pass_called_);
   4061     CHECK(!cell_.IsEmpty());
   4062     cell_.Reset();
   4063     first_pass_called_ = true;
   4064   }
   4065 
   4066   void SecondPass() {
   4067     CHECK(first_pass_called_);
   4068     CHECK(!second_pass_called_);
   4069     CHECK(cell_.IsEmpty());
   4070     second_pass_called_ = true;
   4071     delete this;
   4072   }
   4073 
   4074   void SetWeak() {
   4075     cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
   4076   }
   4077 
   4078   void MarkTriggerGc() { trigger_gc_ = true; }
   4079   bool trigger_gc() { return trigger_gc_; }
   4080 
   4081   int* instance_counter() { return instance_counter_; }
   4082 
   4083  private:
   4084   bool first_pass_called_;
   4085   bool second_pass_called_;
   4086   bool trigger_gc_;
   4087   v8::Global<v8::String> cell_;
   4088   int* instance_counter_;
   4089 };
   4090 
   4091 
   4092 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
   4093   ApiTestFuzzer::Fuzz();
   4094   bool trigger_gc = data.GetParameter()->trigger_gc();
   4095   int* instance_counter = data.GetParameter()->instance_counter();
   4096   data.GetParameter()->SecondPass();
   4097   if (!trigger_gc) return;
   4098   auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
   4099   data_2->SetWeak();
   4100   CcTest::heap()->CollectAllGarbage();
   4101 }
   4102 
   4103 
   4104 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
   4105   data.GetParameter()->FirstPass();
   4106   data.SetSecondPassCallback(SecondPassCallback);
   4107 }
   4108 
   4109 }  // namespace
   4110 
   4111 
   4112 TEST(TwoPassPhantomCallbacks) {
   4113   auto isolate = CcTest::isolate();
   4114   const size_t kLength = 20;
   4115   int instance_counter = 0;
   4116   for (size_t i = 0; i < kLength; ++i) {
   4117     auto data = new TwoPassCallbackData(isolate, &instance_counter);
   4118     data->SetWeak();
   4119   }
   4120   CHECK_EQ(static_cast<int>(kLength), instance_counter);
   4121   CcTest::heap()->CollectAllGarbage();
   4122   EmptyMessageQueues(isolate);
   4123   CHECK_EQ(0, instance_counter);
   4124 }
   4125 
   4126 
   4127 TEST(TwoPassPhantomCallbacksNestedGc) {
   4128   auto isolate = CcTest::isolate();
   4129   const size_t kLength = 20;
   4130   TwoPassCallbackData* array[kLength];
   4131   int instance_counter = 0;
   4132   for (size_t i = 0; i < kLength; ++i) {
   4133     array[i] = new TwoPassCallbackData(isolate, &instance_counter);
   4134     array[i]->SetWeak();
   4135   }
   4136   array[5]->MarkTriggerGc();
   4137   array[10]->MarkTriggerGc();
   4138   array[15]->MarkTriggerGc();
   4139   CHECK_EQ(static_cast<int>(kLength), instance_counter);
   4140   CcTest::heap()->CollectAllGarbage();
   4141   EmptyMessageQueues(isolate);
   4142   CHECK_EQ(0, instance_counter);
   4143 }
   4144 
   4145 
   4146 namespace {
   4147 
   4148 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
   4149 
   4150 
   4151 Local<v8::Object> NewObjectForIntKey(
   4152     v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
   4153     int key) {
   4154   auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
   4155   auto obj = local->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
   4156   obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
   4157   return obj;
   4158 }
   4159 
   4160 
   4161 template <typename K, typename V>
   4162 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
   4163  public:
   4164   typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
   4165   static const v8::PersistentContainerCallbackType kCallbackType =
   4166       v8::kWeakWithInternalFields;
   4167   struct WeakCallbackDataType {
   4168     MapType* map;
   4169     K key;
   4170   };
   4171   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
   4172                                                      Local<V> value) {
   4173     WeakCallbackDataType* data = new WeakCallbackDataType;
   4174     data->map = map;
   4175     data->key = key;
   4176     return data;
   4177   }
   4178   static MapType* MapFromWeakCallbackInfo(
   4179       const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
   4180     return data.GetParameter()->map;
   4181   }
   4182   static K KeyFromWeakCallbackInfo(
   4183       const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
   4184     return data.GetParameter()->key;
   4185   }
   4186   static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
   4187   static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
   4188     CHECK_EQ(IntKeyToVoidPointer(key),
   4189              v8::Object::GetAlignedPointerFromInternalField(value, 0));
   4190   }
   4191   static void OnWeakCallback(
   4192       const v8::WeakCallbackInfo<WeakCallbackDataType>&) {}
   4193   static void DisposeWeak(
   4194       const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
   4195     K key = KeyFromWeakCallbackInfo(info);
   4196     CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
   4197     DisposeCallbackData(info.GetParameter());
   4198   }
   4199 };
   4200 
   4201 
   4202 template <typename Map>
   4203 void TestGlobalValueMap() {
   4204   LocalContext env;
   4205   v8::Isolate* isolate = env->GetIsolate();
   4206   v8::Global<ObjectTemplate> templ;
   4207   {
   4208     HandleScope scope(isolate);
   4209     auto t = ObjectTemplate::New(isolate);
   4210     t->SetInternalFieldCount(1);
   4211     templ.Reset(isolate, t);
   4212   }
   4213   Map map(isolate);
   4214   v8::internal::GlobalHandles* global_handles =
   4215       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   4216   int initial_handle_count = global_handles->global_handles_count();
   4217   CHECK_EQ(0, static_cast<int>(map.Size()));
   4218   {
   4219     HandleScope scope(isolate);
   4220     Local<v8::Object> obj = map.Get(7);
   4221     CHECK(obj.IsEmpty());
   4222     Local<v8::Object> expected = v8::Object::New(isolate);
   4223     map.Set(7, expected);
   4224     CHECK_EQ(1, static_cast<int>(map.Size()));
   4225     obj = map.Get(7);
   4226     CHECK(expected->Equals(env.local(), obj).FromJust());
   4227     {
   4228       typename Map::PersistentValueReference ref = map.GetReference(7);
   4229       CHECK(expected->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
   4230     }
   4231     v8::Global<v8::Object> removed = map.Remove(7);
   4232     CHECK_EQ(0, static_cast<int>(map.Size()));
   4233     CHECK(expected == removed);
   4234     removed = map.Remove(7);
   4235     CHECK(removed.IsEmpty());
   4236     map.Set(8, expected);
   4237     CHECK_EQ(1, static_cast<int>(map.Size()));
   4238     map.Set(8, expected);
   4239     CHECK_EQ(1, static_cast<int>(map.Size()));
   4240     {
   4241       typename Map::PersistentValueReference ref;
   4242       Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
   4243       removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
   4244       CHECK_EQ(1, static_cast<int>(map.Size()));
   4245       CHECK(expected == removed);
   4246       CHECK(expected2->Equals(env.local(), ref.NewLocal(isolate)).FromJust());
   4247     }
   4248   }
   4249   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   4250   if (map.IsWeak()) {
   4251     CcTest::i_isolate()->heap()->CollectAllGarbage(
   4252         i::Heap::kAbortIncrementalMarkingMask);
   4253   } else {
   4254     map.Clear();
   4255   }
   4256   CHECK_EQ(0, static_cast<int>(map.Size()));
   4257   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   4258   {
   4259     HandleScope scope(isolate);
   4260     Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
   4261     map.Set(9, value);
   4262     map.Clear();
   4263   }
   4264   CHECK_EQ(0, static_cast<int>(map.Size()));
   4265   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   4266 }
   4267 
   4268 }  // namespace
   4269 
   4270 
   4271 TEST(GlobalValueMap) {
   4272   // Default case, w/o weak callbacks:
   4273   TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
   4274 
   4275   // Custom traits with weak callbacks:
   4276   typedef v8::GlobalValueMap<int, v8::Object,
   4277                              PhantomStdMapTraits<int, v8::Object>> WeakMap;
   4278   TestGlobalValueMap<WeakMap>();
   4279 }
   4280 
   4281 
   4282 TEST(PersistentValueVector) {
   4283   LocalContext env;
   4284   v8::Isolate* isolate = env->GetIsolate();
   4285   v8::internal::GlobalHandles* global_handles =
   4286       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   4287   int handle_count = global_handles->global_handles_count();
   4288   HandleScope scope(isolate);
   4289 
   4290   v8::PersistentValueVector<v8::Object> vector(isolate);
   4291 
   4292   Local<v8::Object> obj1 = v8::Object::New(isolate);
   4293   Local<v8::Object> obj2 = v8::Object::New(isolate);
   4294   v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
   4295 
   4296   CHECK(vector.IsEmpty());
   4297   CHECK_EQ(0, static_cast<int>(vector.Size()));
   4298 
   4299   vector.ReserveCapacity(3);
   4300   CHECK(vector.IsEmpty());
   4301 
   4302   vector.Append(obj1);
   4303   vector.Append(obj2);
   4304   vector.Append(obj1);
   4305   vector.Append(obj3.Pass());
   4306   vector.Append(obj1);
   4307 
   4308   CHECK(!vector.IsEmpty());
   4309   CHECK_EQ(5, static_cast<int>(vector.Size()));
   4310   CHECK(obj3.IsEmpty());
   4311   CHECK(obj1->Equals(env.local(), vector.Get(0)).FromJust());
   4312   CHECK(obj1->Equals(env.local(), vector.Get(2)).FromJust());
   4313   CHECK(obj1->Equals(env.local(), vector.Get(4)).FromJust());
   4314   CHECK(obj2->Equals(env.local(), vector.Get(1)).FromJust());
   4315 
   4316   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
   4317 
   4318   vector.Clear();
   4319   CHECK(vector.IsEmpty());
   4320   CHECK_EQ(0, static_cast<int>(vector.Size()));
   4321   CHECK_EQ(handle_count, global_handles->global_handles_count());
   4322 }
   4323 
   4324 
   4325 THREADED_TEST(GlobalHandleUpcast) {
   4326   v8::Isolate* isolate = CcTest::isolate();
   4327   v8::HandleScope scope(isolate);
   4328   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
   4329   v8::Persistent<String> global_string(isolate, local);
   4330   v8::Persistent<Value>& global_value =
   4331       v8::Persistent<Value>::Cast(global_string);
   4332   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
   4333   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
   4334   global_string.Reset();
   4335 }
   4336 
   4337 
   4338 THREADED_TEST(HandleEquality) {
   4339   v8::Isolate* isolate = CcTest::isolate();
   4340   v8::Persistent<String> global1;
   4341   v8::Persistent<String> global2;
   4342   {
   4343     v8::HandleScope scope(isolate);
   4344     global1.Reset(isolate, v8_str("str"));
   4345     global2.Reset(isolate, v8_str("str2"));
   4346   }
   4347   CHECK_EQ(global1 == global1, true);
   4348   CHECK_EQ(global1 != global1, false);
   4349   {
   4350     v8::HandleScope scope(isolate);
   4351     Local<String> local1 = Local<String>::New(isolate, global1);
   4352     Local<String> local2 = Local<String>::New(isolate, global2);
   4353 
   4354     CHECK_EQ(global1 == local1, true);
   4355     CHECK_EQ(global1 != local1, false);
   4356     CHECK_EQ(local1 == global1, true);
   4357     CHECK_EQ(local1 != global1, false);
   4358 
   4359     CHECK_EQ(global1 == local2, false);
   4360     CHECK_EQ(global1 != local2, true);
   4361     CHECK_EQ(local2 == global1, false);
   4362     CHECK_EQ(local2 != global1, true);
   4363 
   4364     CHECK_EQ(local1 == local2, false);
   4365     CHECK_EQ(local1 != local2, true);
   4366 
   4367     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
   4368     CHECK_EQ(local1 == anotherLocal1, true);
   4369     CHECK_EQ(local1 != anotherLocal1, false);
   4370   }
   4371   global1.Reset();
   4372   global2.Reset();
   4373 }
   4374 
   4375 
   4376 THREADED_TEST(LocalHandle) {
   4377   v8::HandleScope scope(CcTest::isolate());
   4378   v8::Local<String> local =
   4379       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
   4380   CHECK_EQ(local->Length(), 3);
   4381 }
   4382 
   4383 
   4384 class WeakCallCounter {
   4385  public:
   4386   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
   4387   int id() { return id_; }
   4388   void increment() { number_of_weak_calls_++; }
   4389   int NumberOfWeakCalls() { return number_of_weak_calls_; }
   4390 
   4391  private:
   4392   int id_;
   4393   int number_of_weak_calls_;
   4394 };
   4395 
   4396 
   4397 template <typename T>
   4398 struct WeakCallCounterAndPersistent {
   4399   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
   4400       : counter(counter) {}
   4401   WeakCallCounter* counter;
   4402   v8::Persistent<T> handle;
   4403 };
   4404 
   4405 
   4406 template <typename T>
   4407 static void WeakPointerCallback(
   4408     const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
   4409   CHECK_EQ(1234, data.GetParameter()->counter->id());
   4410   data.GetParameter()->counter->increment();
   4411   data.GetParameter()->handle.Reset();
   4412 }
   4413 
   4414 
   4415 template <typename T>
   4416 static UniqueId MakeUniqueId(const Persistent<T>& p) {
   4417   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
   4418 }
   4419 
   4420 
   4421 THREADED_TEST(ApiObjectGroups) {
   4422   LocalContext env;
   4423   v8::Isolate* iso = env->GetIsolate();
   4424   HandleScope scope(iso);
   4425 
   4426   WeakCallCounter counter(1234);
   4427 
   4428   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   4429   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   4430   WeakCallCounterAndPersistent<Value> g1c1(&counter);
   4431   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   4432   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   4433   WeakCallCounterAndPersistent<Value> g2c1(&counter);
   4434 
   4435   {
   4436     HandleScope scope(iso);
   4437     g1s1.handle.Reset(iso, Object::New(iso));
   4438     g1s2.handle.Reset(iso, Object::New(iso));
   4439     g1c1.handle.Reset(iso, Object::New(iso));
   4440     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
   4441                         v8::WeakCallbackType::kParameter);
   4442     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
   4443                         v8::WeakCallbackType::kParameter);
   4444     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
   4445                         v8::WeakCallbackType::kParameter);
   4446 
   4447     g2s1.handle.Reset(iso, Object::New(iso));
   4448     g2s2.handle.Reset(iso, Object::New(iso));
   4449     g2c1.handle.Reset(iso, Object::New(iso));
   4450     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
   4451                         v8::WeakCallbackType::kParameter);
   4452     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
   4453                         v8::WeakCallbackType::kParameter);
   4454     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
   4455                         v8::WeakCallbackType::kParameter);
   4456   }
   4457 
   4458   WeakCallCounterAndPersistent<Value> root(&counter);
   4459   root.handle.Reset(iso, g1s1.handle);  // make a root.
   4460 
   4461   // Connect group 1 and 2, make a cycle.
   4462   {
   4463     HandleScope scope(iso);
   4464     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
   4465               ->Set(env.local(), 0, Local<Value>::New(iso, g2s2.handle))
   4466               .FromJust());
   4467     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
   4468               ->Set(env.local(), 0, Local<Value>::New(iso, g1s1.handle))
   4469               .FromJust());
   4470   }
   4471 
   4472   {
   4473     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4474     UniqueId id2 = MakeUniqueId(g2s2.handle);
   4475     iso->SetObjectGroupId(g1s1.handle, id1);
   4476     iso->SetObjectGroupId(g1s2.handle, id1);
   4477     iso->SetReferenceFromGroup(id1, g1c1.handle);
   4478     iso->SetObjectGroupId(g2s1.handle, id2);
   4479     iso->SetObjectGroupId(g2s2.handle, id2);
   4480     iso->SetReferenceFromGroup(id2, g2c1.handle);
   4481   }
   4482   // Do a single full GC, ensure incremental marking is stopped.
   4483   v8::internal::Heap* heap =
   4484       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
   4485   heap->CollectAllGarbage();
   4486 
   4487   // All object should be alive.
   4488   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4489 
   4490   // Weaken the root.
   4491   root.handle.SetWeak(&root, &WeakPointerCallback,
   4492                       v8::WeakCallbackType::kParameter);
   4493   // But make children strong roots---all the objects (except for children)
   4494   // should be collectable now.
   4495   g1c1.handle.ClearWeak();
   4496   g2c1.handle.ClearWeak();
   4497 
   4498   // Groups are deleted, rebuild groups.
   4499   {
   4500     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4501     UniqueId id2 = MakeUniqueId(g2s2.handle);
   4502     iso->SetObjectGroupId(g1s1.handle, id1);
   4503     iso->SetObjectGroupId(g1s2.handle, id1);
   4504     iso->SetReferenceFromGroup(id1, g1c1.handle);
   4505     iso->SetObjectGroupId(g2s1.handle, id2);
   4506     iso->SetObjectGroupId(g2s2.handle, id2);
   4507     iso->SetReferenceFromGroup(id2, g2c1.handle);
   4508   }
   4509 
   4510   heap->CollectAllGarbage();
   4511 
   4512   // All objects should be gone. 5 global handles in total.
   4513   CHECK_EQ(5, counter.NumberOfWeakCalls());
   4514 
   4515   // And now make children weak again and collect them.
   4516   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
   4517                       v8::WeakCallbackType::kParameter);
   4518   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
   4519                       v8::WeakCallbackType::kParameter);
   4520 
   4521   heap->CollectAllGarbage();
   4522   CHECK_EQ(7, counter.NumberOfWeakCalls());
   4523 }
   4524 
   4525 
   4526 THREADED_TEST(ApiObjectGroupsForSubtypes) {
   4527   LocalContext env;
   4528   v8::Isolate* iso = env->GetIsolate();
   4529   HandleScope scope(iso);
   4530 
   4531   WeakCallCounter counter(1234);
   4532 
   4533   WeakCallCounterAndPersistent<Object> g1s1(&counter);
   4534   WeakCallCounterAndPersistent<String> g1s2(&counter);
   4535   WeakCallCounterAndPersistent<String> g1c1(&counter);
   4536   WeakCallCounterAndPersistent<Object> g2s1(&counter);
   4537   WeakCallCounterAndPersistent<String> g2s2(&counter);
   4538   WeakCallCounterAndPersistent<String> g2c1(&counter);
   4539 
   4540   {
   4541     HandleScope scope(iso);
   4542     g1s1.handle.Reset(iso, Object::New(iso));
   4543     g1s2.handle.Reset(iso, v8_str("foo1"));
   4544     g1c1.handle.Reset(iso, v8_str("foo2"));
   4545     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
   4546                         v8::WeakCallbackType::kParameter);
   4547     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
   4548                         v8::WeakCallbackType::kParameter);
   4549     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
   4550                         v8::WeakCallbackType::kParameter);
   4551 
   4552     g2s1.handle.Reset(iso, Object::New(iso));
   4553     g2s2.handle.Reset(iso, v8_str("foo3"));
   4554     g2c1.handle.Reset(iso, v8_str("foo4"));
   4555     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
   4556                         v8::WeakCallbackType::kParameter);
   4557     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
   4558                         v8::WeakCallbackType::kParameter);
   4559     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
   4560                         v8::WeakCallbackType::kParameter);
   4561   }
   4562 
   4563   WeakCallCounterAndPersistent<Value> root(&counter);
   4564   root.handle.Reset(iso, g1s1.handle);  // make a root.
   4565 
   4566   // Connect group 1 and 2, make a cycle.
   4567   {
   4568     HandleScope scope(iso);
   4569     CHECK(Local<Object>::New(iso, g1s1.handle)
   4570               ->Set(env.local(), 0, Local<Object>::New(iso, g2s1.handle))
   4571               .FromJust());
   4572     CHECK(Local<Object>::New(iso, g2s1.handle)
   4573               ->Set(env.local(), 0, Local<Object>::New(iso, g1s1.handle))
   4574               .FromJust());
   4575   }
   4576 
   4577   {
   4578     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4579     UniqueId id2 = MakeUniqueId(g2s2.handle);
   4580     iso->SetObjectGroupId(g1s1.handle, id1);
   4581     iso->SetObjectGroupId(g1s2.handle, id1);
   4582     iso->SetReference(g1s1.handle, g1c1.handle);
   4583     iso->SetObjectGroupId(g2s1.handle, id2);
   4584     iso->SetObjectGroupId(g2s2.handle, id2);
   4585     iso->SetReferenceFromGroup(id2, g2c1.handle);
   4586   }
   4587   // Do a single full GC, ensure incremental marking is stopped.
   4588   v8::internal::Heap* heap =
   4589       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
   4590   heap->CollectAllGarbage();
   4591 
   4592   // All object should be alive.
   4593   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4594 
   4595   // Weaken the root.
   4596   root.handle.SetWeak(&root, &WeakPointerCallback,
   4597                       v8::WeakCallbackType::kParameter);
   4598   // But make children strong roots---all the objects (except for children)
   4599   // should be collectable now.
   4600   g1c1.handle.ClearWeak();
   4601   g2c1.handle.ClearWeak();
   4602 
   4603   // Groups are deleted, rebuild groups.
   4604   {
   4605     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4606     UniqueId id2 = MakeUniqueId(g2s2.handle);
   4607     iso->SetObjectGroupId(g1s1.handle, id1);
   4608     iso->SetObjectGroupId(g1s2.handle, id1);
   4609     iso->SetReference(g1s1.handle, g1c1.handle);
   4610     iso->SetObjectGroupId(g2s1.handle, id2);
   4611     iso->SetObjectGroupId(g2s2.handle, id2);
   4612     iso->SetReferenceFromGroup(id2, g2c1.handle);
   4613   }
   4614 
   4615   heap->CollectAllGarbage();
   4616 
   4617   // All objects should be gone. 5 global handles in total.
   4618   CHECK_EQ(5, counter.NumberOfWeakCalls());
   4619 
   4620   // And now make children weak again and collect them.
   4621   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
   4622                       v8::WeakCallbackType::kParameter);
   4623   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
   4624                       v8::WeakCallbackType::kParameter);
   4625 
   4626   heap->CollectAllGarbage();
   4627   CHECK_EQ(7, counter.NumberOfWeakCalls());
   4628 }
   4629 
   4630 
   4631 THREADED_TEST(ApiObjectGroupsCycle) {
   4632   LocalContext env;
   4633   v8::Isolate* iso = env->GetIsolate();
   4634   HandleScope scope(iso);
   4635 
   4636   WeakCallCounter counter(1234);
   4637 
   4638   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   4639   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   4640   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   4641   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   4642   WeakCallCounterAndPersistent<Value> g3s1(&counter);
   4643   WeakCallCounterAndPersistent<Value> g3s2(&counter);
   4644   WeakCallCounterAndPersistent<Value> g4s1(&counter);
   4645   WeakCallCounterAndPersistent<Value> g4s2(&counter);
   4646 
   4647   {
   4648     HandleScope scope(iso);
   4649     g1s1.handle.Reset(iso, Object::New(iso));
   4650     g1s2.handle.Reset(iso, Object::New(iso));
   4651     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
   4652                         v8::WeakCallbackType::kParameter);
   4653     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
   4654                         v8::WeakCallbackType::kParameter);
   4655     CHECK(g1s1.handle.IsWeak());
   4656     CHECK(g1s2.handle.IsWeak());
   4657 
   4658     g2s1.handle.Reset(iso, Object::New(iso));
   4659     g2s2.handle.Reset(iso, Object::New(iso));
   4660     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
   4661                         v8::WeakCallbackType::kParameter);
   4662     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
   4663                         v8::WeakCallbackType::kParameter);
   4664     CHECK(g2s1.handle.IsWeak());
   4665     CHECK(g2s2.handle.IsWeak());
   4666 
   4667     g3s1.handle.Reset(iso, Object::New(iso));
   4668     g3s2.handle.Reset(iso, Object::New(iso));
   4669     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
   4670                         v8::WeakCallbackType::kParameter);
   4671     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
   4672                         v8::WeakCallbackType::kParameter);
   4673     CHECK(g3s1.handle.IsWeak());
   4674     CHECK(g3s2.handle.IsWeak());
   4675 
   4676     g4s1.handle.Reset(iso, Object::New(iso));
   4677     g4s2.handle.Reset(iso, Object::New(iso));
   4678     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback,
   4679                         v8::WeakCallbackType::kParameter);
   4680     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback,
   4681                         v8::WeakCallbackType::kParameter);
   4682     CHECK(g4s1.handle.IsWeak());
   4683     CHECK(g4s2.handle.IsWeak());
   4684   }
   4685 
   4686   WeakCallCounterAndPersistent<Value> root(&counter);
   4687   root.handle.Reset(iso, g1s1.handle);  // make a root.
   4688 
   4689   // Connect groups.  We're building the following cycle:
   4690   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
   4691   // groups.
   4692   {
   4693     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4694     UniqueId id2 = MakeUniqueId(g2s1.handle);
   4695     UniqueId id3 = MakeUniqueId(g3s1.handle);
   4696     UniqueId id4 = MakeUniqueId(g4s1.handle);
   4697     iso->SetObjectGroupId(g1s1.handle, id1);
   4698     iso->SetObjectGroupId(g1s2.handle, id1);
   4699     iso->SetReferenceFromGroup(id1, g2s1.handle);
   4700     iso->SetObjectGroupId(g2s1.handle, id2);
   4701     iso->SetObjectGroupId(g2s2.handle, id2);
   4702     iso->SetReferenceFromGroup(id2, g3s1.handle);
   4703     iso->SetObjectGroupId(g3s1.handle, id3);
   4704     iso->SetObjectGroupId(g3s2.handle, id3);
   4705     iso->SetReferenceFromGroup(id3, g4s1.handle);
   4706     iso->SetObjectGroupId(g4s1.handle, id4);
   4707     iso->SetObjectGroupId(g4s2.handle, id4);
   4708     iso->SetReferenceFromGroup(id4, g1s1.handle);
   4709   }
   4710   // Do a single full GC
   4711   v8::internal::Heap* heap =
   4712       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
   4713   heap->CollectAllGarbage();
   4714 
   4715   // All object should be alive.
   4716   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4717 
   4718   // Weaken the root.
   4719   root.handle.SetWeak(&root, &WeakPointerCallback,
   4720                       v8::WeakCallbackType::kParameter);
   4721 
   4722   // Groups are deleted, rebuild groups.
   4723   {
   4724     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4725     UniqueId id2 = MakeUniqueId(g2s1.handle);
   4726     UniqueId id3 = MakeUniqueId(g3s1.handle);
   4727     UniqueId id4 = MakeUniqueId(g4s1.handle);
   4728     iso->SetObjectGroupId(g1s1.handle, id1);
   4729     iso->SetObjectGroupId(g1s2.handle, id1);
   4730     iso->SetReferenceFromGroup(id1, g2s1.handle);
   4731     iso->SetObjectGroupId(g2s1.handle, id2);
   4732     iso->SetObjectGroupId(g2s2.handle, id2);
   4733     iso->SetReferenceFromGroup(id2, g3s1.handle);
   4734     iso->SetObjectGroupId(g3s1.handle, id3);
   4735     iso->SetObjectGroupId(g3s2.handle, id3);
   4736     iso->SetReferenceFromGroup(id3, g4s1.handle);
   4737     iso->SetObjectGroupId(g4s1.handle, id4);
   4738     iso->SetObjectGroupId(g4s2.handle, id4);
   4739     iso->SetReferenceFromGroup(id4, g1s1.handle);
   4740   }
   4741 
   4742   heap->CollectAllGarbage();
   4743 
   4744   // All objects should be gone. 9 global handles in total.
   4745   CHECK_EQ(9, counter.NumberOfWeakCalls());
   4746 }
   4747 
   4748 
   4749 THREADED_TEST(ScriptException) {
   4750   LocalContext env;
   4751   v8::HandleScope scope(env->GetIsolate());
   4752   Local<Script> script = v8_compile("throw 'panama!';");
   4753   v8::TryCatch try_catch(env->GetIsolate());
   4754   v8::MaybeLocal<Value> result = script->Run(env.local());
   4755   CHECK(result.IsEmpty());
   4756   CHECK(try_catch.HasCaught());
   4757   String::Utf8Value exception_value(try_catch.Exception());
   4758   CHECK_EQ(0, strcmp(*exception_value, "panama!"));
   4759 }
   4760 
   4761 
   4762 TEST(TryCatchCustomException) {
   4763   LocalContext env;
   4764   v8::Isolate* isolate = env->GetIsolate();
   4765   v8::HandleScope scope(isolate);
   4766   v8::TryCatch try_catch(isolate);
   4767   CompileRun(
   4768       "function CustomError() { this.a = 'b'; }"
   4769       "(function f() { throw new CustomError(); })();");
   4770   CHECK(try_catch.HasCaught());
   4771   CHECK(try_catch.Exception()
   4772             ->ToObject(env.local())
   4773             .ToLocalChecked()
   4774             ->Get(env.local(), v8_str("a"))
   4775             .ToLocalChecked()
   4776             ->Equals(env.local(), v8_str("b"))
   4777             .FromJust());
   4778 }
   4779 
   4780 
   4781 bool message_received;
   4782 
   4783 
   4784 static void check_message_0(v8::Local<v8::Message> message,
   4785                             v8::Local<Value> data) {
   4786   CHECK_EQ(5.76, data->NumberValue(CcTest::isolate()->GetCurrentContext())
   4787                      .FromJust());
   4788   CHECK_EQ(6.75, message->GetScriptOrigin()
   4789                      .ResourceName()
   4790                      ->NumberValue(CcTest::isolate()->GetCurrentContext())
   4791                      .FromJust());
   4792   CHECK(!message->IsSharedCrossOrigin());
   4793   message_received = true;
   4794 }
   4795 
   4796 
   4797 THREADED_TEST(MessageHandler0) {
   4798   message_received = false;
   4799   v8::HandleScope scope(CcTest::isolate());
   4800   CHECK(!message_received);
   4801   LocalContext context;
   4802   CcTest::isolate()->AddMessageListener(check_message_0, v8_num(5.76));
   4803   v8::Local<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
   4804   CHECK(script->Run(context.local()).IsEmpty());
   4805   CHECK(message_received);
   4806   // clear out the message listener
   4807   CcTest::isolate()->RemoveMessageListeners(check_message_0);
   4808 }
   4809 
   4810 
   4811 static void check_message_1(v8::Local<v8::Message> message,
   4812                             v8::Local<Value> data) {
   4813   CHECK(data->IsNumber());
   4814   CHECK_EQ(1337,
   4815            data->Int32Value(CcTest::isolate()->GetCurrentContext()).FromJust());
   4816   CHECK(!message->IsSharedCrossOrigin());
   4817   message_received = true;
   4818 }
   4819 
   4820 
   4821 TEST(MessageHandler1) {
   4822   message_received = false;
   4823   v8::HandleScope scope(CcTest::isolate());
   4824   CHECK(!message_received);
   4825   CcTest::isolate()->AddMessageListener(check_message_1);
   4826   LocalContext context;
   4827   CompileRun("throw 1337;");
   4828   CHECK(message_received);
   4829   // clear out the message listener
   4830   CcTest::isolate()->RemoveMessageListeners(check_message_1);
   4831 }
   4832 
   4833 
   4834 static void check_message_2(v8::Local<v8::Message> message,
   4835                             v8::Local<Value> data) {
   4836   LocalContext context;
   4837   CHECK(data->IsObject());
   4838   v8::Local<v8::Value> hidden_property =
   4839       v8::Object::Cast(*data)
   4840           ->GetPrivate(
   4841               context.local(),
   4842               v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")))
   4843           .ToLocalChecked();
   4844   CHECK(v8_str("hidden value")
   4845             ->Equals(context.local(), hidden_property)
   4846             .FromJust());
   4847   CHECK(!message->IsSharedCrossOrigin());
   4848   message_received = true;
   4849 }
   4850 
   4851 
   4852 TEST(MessageHandler2) {
   4853   message_received = false;
   4854   v8::HandleScope scope(CcTest::isolate());
   4855   CHECK(!message_received);
   4856   CcTest::isolate()->AddMessageListener(check_message_2);
   4857   LocalContext context;
   4858   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
   4859   v8::Object::Cast(*error)
   4860       ->SetPrivate(context.local(),
   4861                    v8::Private::ForApi(CcTest::isolate(), v8_str("hidden key")),
   4862                    v8_str("hidden value"))
   4863       .FromJust();
   4864   CHECK(context->Global()
   4865             ->Set(context.local(), v8_str("error"), error)
   4866             .FromJust());
   4867   CompileRun("throw error;");
   4868   CHECK(message_received);
   4869   // clear out the message listener
   4870   CcTest::isolate()->RemoveMessageListeners(check_message_2);
   4871 }
   4872 
   4873 
   4874 static void check_message_3(v8::Local<v8::Message> message,
   4875                             v8::Local<Value> data) {
   4876   CHECK(message->IsSharedCrossOrigin());
   4877   CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
   4878   CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript());
   4879   CHECK(message->GetScriptOrigin().Options().IsOpaque());
   4880   CHECK_EQ(6.75, message->GetScriptOrigin()
   4881                      .ResourceName()
   4882                      ->NumberValue(CcTest::isolate()->GetCurrentContext())
   4883                      .FromJust());
   4884   CHECK_EQ(7.40, message->GetScriptOrigin()
   4885                      .SourceMapUrl()
   4886                      ->NumberValue(CcTest::isolate()->GetCurrentContext())
   4887                      .FromJust());
   4888   message_received = true;
   4889 }
   4890 
   4891 
   4892 TEST(MessageHandler3) {
   4893   message_received = false;
   4894   v8::Isolate* isolate = CcTest::isolate();
   4895   v8::HandleScope scope(isolate);
   4896   CHECK(!message_received);
   4897   isolate->AddMessageListener(check_message_3);
   4898   LocalContext context;
   4899   v8::ScriptOrigin origin = v8::ScriptOrigin(
   4900       v8_str("6.75"), v8::Integer::New(isolate, 1),
   4901       v8::Integer::New(isolate, 2), v8::True(isolate), Local<v8::Integer>(),
   4902       v8::True(isolate), v8_str("7.40"), v8::True(isolate));
   4903   v8::Local<v8::Script> script =
   4904       Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
   4905           .ToLocalChecked();
   4906   CHECK(script->Run(context.local()).IsEmpty());
   4907   CHECK(message_received);
   4908   // clear out the message listener
   4909   isolate->RemoveMessageListeners(check_message_3);
   4910 }
   4911 
   4912 
   4913 static void check_message_4(v8::Local<v8::Message> message,
   4914                             v8::Local<Value> data) {
   4915   CHECK(!message->IsSharedCrossOrigin());
   4916   CHECK_EQ(6.75, message->GetScriptOrigin()
   4917                      .ResourceName()
   4918                      ->NumberValue(CcTest::isolate()->GetCurrentContext())
   4919                      .FromJust());
   4920   message_received = true;
   4921 }
   4922 
   4923 
   4924 TEST(MessageHandler4) {
   4925   message_received = false;
   4926   v8::Isolate* isolate = CcTest::isolate();
   4927   v8::HandleScope scope(isolate);
   4928   CHECK(!message_received);
   4929   isolate->AddMessageListener(check_message_4);
   4930   LocalContext context;
   4931   v8::ScriptOrigin origin =
   4932       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
   4933                        v8::Integer::New(isolate, 2), v8::False(isolate));
   4934   v8::Local<v8::Script> script =
   4935       Script::Compile(context.local(), v8_str("throw 'error'"), &origin)
   4936           .ToLocalChecked();
   4937   CHECK(script->Run(context.local()).IsEmpty());
   4938   CHECK(message_received);
   4939   // clear out the message listener
   4940   isolate->RemoveMessageListeners(check_message_4);
   4941 }
   4942 
   4943 
   4944 static void check_message_5a(v8::Local<v8::Message> message,
   4945                              v8::Local<Value> data) {
   4946   CHECK(message->IsSharedCrossOrigin());
   4947   CHECK_EQ(6.75, message->GetScriptOrigin()
   4948                      .ResourceName()
   4949                      ->NumberValue(CcTest::isolate()->GetCurrentContext())
   4950                      .FromJust());
   4951   message_received = true;
   4952 }
   4953 
   4954 
   4955 static void check_message_5b(v8::Local<v8::Message> message,
   4956                              v8::Local<Value> data) {
   4957   CHECK(!message->IsSharedCrossOrigin());
   4958   CHECK_EQ(6.75, message->GetScriptOrigin()
   4959                      .ResourceName()
   4960                      ->NumberValue(CcTest::isolate()->GetCurrentContext())
   4961                      .FromJust());
   4962   message_received = true;
   4963 }
   4964 
   4965 
   4966 TEST(MessageHandler5) {
   4967   message_received = false;
   4968   v8::Isolate* isolate = CcTest::isolate();
   4969   v8::HandleScope scope(isolate);
   4970   CHECK(!message_received);
   4971   isolate->AddMessageListener(check_message_5a);
   4972   LocalContext context;
   4973   v8::ScriptOrigin origin1 =
   4974       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
   4975                        v8::Integer::New(isolate, 2), v8::True(isolate));
   4976   v8::Local<v8::Script> script =
   4977       Script::Compile(context.local(), v8_str("throw 'error'"), &origin1)
   4978           .ToLocalChecked();
   4979   CHECK(script->Run(context.local()).IsEmpty());
   4980   CHECK(message_received);
   4981   // clear out the message listener
   4982   isolate->RemoveMessageListeners(check_message_5a);
   4983 
   4984   message_received = false;
   4985   isolate->AddMessageListener(check_message_5b);
   4986   v8::ScriptOrigin origin2 =
   4987       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
   4988                        v8::Integer::New(isolate, 2), v8::False(isolate));
   4989   script = Script::Compile(context.local(), v8_str("throw 'error'"), &origin2)
   4990                .ToLocalChecked();
   4991   CHECK(script->Run(context.local()).IsEmpty());
   4992   CHECK(message_received);
   4993   // clear out the message listener
   4994   isolate->RemoveMessageListeners(check_message_5b);
   4995 }
   4996 
   4997 
   4998 TEST(NativeWeakMap) {
   4999   v8::Isolate* isolate = CcTest::isolate();
   5000   HandleScope scope(isolate);
   5001   Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
   5002   CHECK(!weak_map.IsEmpty());
   5003 
   5004   LocalContext env;
   5005   Local<Object> value = v8::Object::New(isolate);
   5006 
   5007   Local<Object> local1 = v8::Object::New(isolate);
   5008   CHECK(!weak_map->Has(local1));
   5009   CHECK(weak_map->Get(local1)->IsUndefined());
   5010   weak_map->Set(local1, value);
   5011   CHECK(weak_map->Has(local1));
   5012   CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
   5013 
   5014   WeakCallCounter counter(1234);
   5015   WeakCallCounterAndPersistent<Value> o1(&counter);
   5016   WeakCallCounterAndPersistent<Value> o2(&counter);
   5017   WeakCallCounterAndPersistent<Value> s1(&counter);
   5018   {
   5019     HandleScope scope(isolate);
   5020     Local<v8::Object> obj1 = v8::Object::New(isolate);
   5021     Local<v8::Object> obj2 = v8::Object::New(isolate);
   5022     Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
   5023 
   5024     weak_map->Set(obj1, value);
   5025     weak_map->Set(obj2, value);
   5026     weak_map->Set(sym1, value);
   5027 
   5028     o1.handle.Reset(isolate, obj1);
   5029     o2.handle.Reset(isolate, obj2);
   5030     s1.handle.Reset(isolate, sym1);
   5031 
   5032     CHECK(weak_map->Has(local1));
   5033     CHECK(weak_map->Has(obj1));
   5034     CHECK(weak_map->Has(obj2));
   5035     CHECK(weak_map->Has(sym1));
   5036 
   5037     CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
   5038     CHECK(value->Equals(env.local(), weak_map->Get(obj1)).FromJust());
   5039     CHECK(value->Equals(env.local(), weak_map->Get(obj2)).FromJust());
   5040     CHECK(value->Equals(env.local(), weak_map->Get(sym1)).FromJust());
   5041   }
   5042   CcTest::heap()->CollectAllGarbage();
   5043   {
   5044     HandleScope scope(isolate);
   5045     CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
   5046     CHECK(value->Equals(env.local(),
   5047                         weak_map->Get(Local<Value>::New(isolate, o1.handle)))
   5048               .FromJust());
   5049     CHECK(value->Equals(env.local(),
   5050                         weak_map->Get(Local<Value>::New(isolate, o2.handle)))
   5051               .FromJust());
   5052     CHECK(value->Equals(env.local(),
   5053                         weak_map->Get(Local<Value>::New(isolate, s1.handle)))
   5054               .FromJust());
   5055   }
   5056 
   5057   o1.handle.SetWeak(&o1, &WeakPointerCallback,
   5058                     v8::WeakCallbackType::kParameter);
   5059   o2.handle.SetWeak(&o2, &WeakPointerCallback,
   5060                     v8::WeakCallbackType::kParameter);
   5061   s1.handle.SetWeak(&s1, &WeakPointerCallback,
   5062                     v8::WeakCallbackType::kParameter);
   5063 
   5064   CcTest::heap()->CollectAllGarbage();
   5065   CHECK_EQ(3, counter.NumberOfWeakCalls());
   5066 
   5067   CHECK(o1.handle.IsEmpty());
   5068   CHECK(o2.handle.IsEmpty());
   5069   CHECK(s1.handle.IsEmpty());
   5070 
   5071   CHECK(value->Equals(env.local(), weak_map->Get(local1)).FromJust());
   5072   CHECK(weak_map->Delete(local1));
   5073   CHECK(!weak_map->Has(local1));
   5074   CHECK(weak_map->Get(local1)->IsUndefined());
   5075 }
   5076 
   5077 
   5078 THREADED_TEST(GetSetProperty) {
   5079   LocalContext context;
   5080   v8::Isolate* isolate = context->GetIsolate();
   5081   v8::HandleScope scope(isolate);
   5082   CHECK(context->Global()
   5083             ->Set(context.local(), v8_str("foo"), v8_num(14))
   5084             .FromJust());
   5085   CHECK(context->Global()
   5086             ->Set(context.local(), v8_str("12"), v8_num(92))
   5087             .FromJust());
   5088   CHECK(context->Global()
   5089             ->Set(context.local(), v8::Integer::New(isolate, 16), v8_num(32))
   5090             .FromJust());
   5091   CHECK(context->Global()
   5092             ->Set(context.local(), v8_num(13), v8_num(56))
   5093             .FromJust());
   5094   Local<Value> foo = CompileRun("this.foo");
   5095   CHECK_EQ(14, foo->Int32Value(context.local()).FromJust());
   5096   Local<Value> twelve = CompileRun("this[12]");
   5097   CHECK_EQ(92, twelve->Int32Value(context.local()).FromJust());
   5098   Local<Value> sixteen = CompileRun("this[16]");
   5099   CHECK_EQ(32, sixteen->Int32Value(context.local()).FromJust());
   5100   Local<Value> thirteen = CompileRun("this[13]");
   5101   CHECK_EQ(56, thirteen->Int32Value(context.local()).FromJust());
   5102   CHECK_EQ(92, context->Global()
   5103                    ->Get(context.local(), v8::Integer::New(isolate, 12))
   5104                    .ToLocalChecked()
   5105                    ->Int32Value(context.local())
   5106                    .FromJust());
   5107   CHECK_EQ(92, context->Global()
   5108                    ->Get(context.local(), v8_str("12"))
   5109                    .ToLocalChecked()
   5110                    ->Int32Value(context.local())
   5111                    .FromJust());
   5112   CHECK_EQ(92, context->Global()
   5113                    ->Get(context.local(), v8_num(12))
   5114                    .ToLocalChecked()
   5115                    ->Int32Value(context.local())
   5116                    .FromJust());
   5117   CHECK_EQ(32, context->Global()
   5118                    ->Get(context.local(), v8::Integer::New(isolate, 16))
   5119                    .ToLocalChecked()
   5120                    ->Int32Value(context.local())
   5121                    .FromJust());
   5122   CHECK_EQ(32, context->Global()
   5123                    ->Get(context.local(), v8_str("16"))
   5124                    .ToLocalChecked()
   5125                    ->Int32Value(context.local())
   5126                    .FromJust());
   5127   CHECK_EQ(32, context->Global()
   5128                    ->Get(context.local(), v8_num(16))
   5129                    .ToLocalChecked()
   5130                    ->Int32Value(context.local())
   5131                    .FromJust());
   5132   CHECK_EQ(56, context->Global()
   5133                    ->Get(context.local(), v8::Integer::New(isolate, 13))
   5134                    .ToLocalChecked()
   5135                    ->Int32Value(context.local())
   5136                    .FromJust());
   5137   CHECK_EQ(56, context->Global()
   5138                    ->Get(context.local(), v8_str("13"))
   5139                    .ToLocalChecked()
   5140                    ->Int32Value(context.local())
   5141                    .FromJust());
   5142   CHECK_EQ(56, context->Global()
   5143                    ->Get(context.local(), v8_num(13))
   5144                    .ToLocalChecked()
   5145                    ->Int32Value(context.local())
   5146                    .FromJust());
   5147 }
   5148 
   5149 
   5150 THREADED_TEST(PropertyAttributes) {
   5151   LocalContext context;
   5152   v8::HandleScope scope(context->GetIsolate());
   5153   // none
   5154   Local<String> prop = v8_str("none");
   5155   CHECK(context->Global()->Set(context.local(), prop, v8_num(7)).FromJust());
   5156   CHECK_EQ(v8::None, context->Global()
   5157                          ->GetPropertyAttributes(context.local(), prop)
   5158                          .FromJust());
   5159   // read-only
   5160   prop = v8_str("read_only");
   5161   context->Global()
   5162       ->DefineOwnProperty(context.local(), prop, v8_num(7), v8::ReadOnly)
   5163       .FromJust();
   5164   CHECK_EQ(7, context->Global()
   5165                   ->Get(context.local(), prop)
   5166                   .ToLocalChecked()
   5167                   ->Int32Value(context.local())
   5168                   .FromJust());
   5169   CHECK_EQ(v8::ReadOnly, context->Global()
   5170                              ->GetPropertyAttributes(context.local(), prop)
   5171                              .FromJust());
   5172   CompileRun("read_only = 9");
   5173   CHECK_EQ(7, context->Global()
   5174                   ->Get(context.local(), prop)
   5175                   .ToLocalChecked()
   5176                   ->Int32Value(context.local())
   5177                   .FromJust());
   5178   CHECK(context->Global()->Set(context.local(), prop, v8_num(10)).FromJust());
   5179   CHECK_EQ(7, context->Global()
   5180                   ->Get(context.local(), prop)
   5181                   .ToLocalChecked()
   5182                   ->Int32Value(context.local())
   5183                   .FromJust());
   5184   // dont-delete
   5185   prop = v8_str("dont_delete");
   5186   context->Global()
   5187       ->DefineOwnProperty(context.local(), prop, v8_num(13), v8::DontDelete)
   5188       .FromJust();
   5189   CHECK_EQ(13, context->Global()
   5190                    ->Get(context.local(), prop)
   5191                    .ToLocalChecked()
   5192                    ->Int32Value(context.local())
   5193                    .FromJust());
   5194   CompileRun("delete dont_delete");
   5195   CHECK_EQ(13, context->Global()
   5196                    ->Get(context.local(), prop)
   5197                    .ToLocalChecked()
   5198                    ->Int32Value(context.local())
   5199                    .FromJust());
   5200   CHECK_EQ(v8::DontDelete, context->Global()
   5201                                ->GetPropertyAttributes(context.local(), prop)
   5202                                .FromJust());
   5203   // dont-enum
   5204   prop = v8_str("dont_enum");
   5205   context->Global()
   5206       ->DefineOwnProperty(context.local(), prop, v8_num(28), v8::DontEnum)
   5207       .FromJust();
   5208   CHECK_EQ(v8::DontEnum, context->Global()
   5209                              ->GetPropertyAttributes(context.local(), prop)
   5210                              .FromJust());
   5211   // absent
   5212   prop = v8_str("absent");
   5213   CHECK_EQ(v8::None, context->Global()
   5214                          ->GetPropertyAttributes(context.local(), prop)
   5215                          .FromJust());
   5216   Local<Value> fake_prop = v8_num(1);
   5217   CHECK_EQ(v8::None, context->Global()
   5218                          ->GetPropertyAttributes(context.local(), fake_prop)
   5219                          .FromJust());
   5220   // exception
   5221   TryCatch try_catch(context->GetIsolate());
   5222   Local<Value> exception =
   5223       CompileRun("({ toString: function() { throw 'exception';} })");
   5224   CHECK(context->Global()
   5225             ->GetPropertyAttributes(context.local(), exception)
   5226             .IsNothing());
   5227   CHECK(try_catch.HasCaught());
   5228   String::Utf8Value exception_value(try_catch.Exception());
   5229   CHECK_EQ(0, strcmp("exception", *exception_value));
   5230   try_catch.Reset();
   5231 }
   5232 
   5233 
   5234 THREADED_TEST(Array) {
   5235   LocalContext context;
   5236   v8::HandleScope scope(context->GetIsolate());
   5237   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
   5238   CHECK_EQ(0u, array->Length());
   5239   CHECK(array->Get(context.local(), 0).ToLocalChecked()->IsUndefined());
   5240   CHECK(!array->Has(context.local(), 0).FromJust());
   5241   CHECK(array->Get(context.local(), 100).ToLocalChecked()->IsUndefined());
   5242   CHECK(!array->Has(context.local(), 100).FromJust());
   5243   CHECK(array->Set(context.local(), 2, v8_num(7)).FromJust());
   5244   CHECK_EQ(3u, array->Length());
   5245   CHECK(!array->Has(context.local(), 0).FromJust());
   5246   CHECK(!array->Has(context.local(), 1).FromJust());
   5247   CHECK(array->Has(context.local(), 2).FromJust());
   5248   CHECK_EQ(7, array->Get(context.local(), 2)
   5249                   .ToLocalChecked()
   5250                   ->Int32Value(context.local())
   5251                   .FromJust());
   5252   Local<Value> obj = CompileRun("[1, 2, 3]");
   5253   Local<v8::Array> arr = obj.As<v8::Array>();
   5254   CHECK_EQ(3u, arr->Length());
   5255   CHECK_EQ(1, arr->Get(context.local(), 0)
   5256                   .ToLocalChecked()
   5257                   ->Int32Value(context.local())
   5258                   .FromJust());
   5259   CHECK_EQ(2, arr->Get(context.local(), 1)
   5260                   .ToLocalChecked()
   5261                   ->Int32Value(context.local())
   5262                   .FromJust());
   5263   CHECK_EQ(3, arr->Get(context.local(), 2)
   5264                   .ToLocalChecked()
   5265                   ->Int32Value(context.local())
   5266                   .FromJust());
   5267   array = v8::Array::New(context->GetIsolate(), 27);
   5268   CHECK_EQ(27u, array->Length());
   5269   array = v8::Array::New(context->GetIsolate(), -27);
   5270   CHECK_EQ(0u, array->Length());
   5271 }
   5272 
   5273 
   5274 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5275   v8::EscapableHandleScope scope(args.GetIsolate());
   5276   ApiTestFuzzer::Fuzz();
   5277   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
   5278   for (int i = 0; i < args.Length(); i++) {
   5279     CHECK(result->Set(CcTest::isolate()->GetCurrentContext(), i, args[i])
   5280               .FromJust());
   5281   }
   5282   args.GetReturnValue().Set(scope.Escape(result));
   5283 }
   5284 
   5285 
   5286 THREADED_TEST(Vector) {
   5287   v8::Isolate* isolate = CcTest::isolate();
   5288   v8::HandleScope scope(isolate);
   5289   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
   5290   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
   5291   LocalContext context(0, global);
   5292 
   5293   const char* fun = "f()";
   5294   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
   5295   CHECK_EQ(0u, a0->Length());
   5296 
   5297   const char* fun2 = "f(11)";
   5298   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
   5299   CHECK_EQ(1u, a1->Length());
   5300   CHECK_EQ(11, a1->Get(context.local(), 0)
   5301                    .ToLocalChecked()
   5302                    ->Int32Value(context.local())
   5303                    .FromJust());
   5304 
   5305   const char* fun3 = "f(12, 13)";
   5306   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
   5307   CHECK_EQ(2u, a2->Length());
   5308   CHECK_EQ(12, a2->Get(context.local(), 0)
   5309                    .ToLocalChecked()
   5310                    ->Int32Value(context.local())
   5311                    .FromJust());
   5312   CHECK_EQ(13, a2->Get(context.local(), 1)
   5313                    .ToLocalChecked()
   5314                    ->Int32Value(context.local())
   5315                    .FromJust());
   5316 
   5317   const char* fun4 = "f(14, 15, 16)";
   5318   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
   5319   CHECK_EQ(3u, a3->Length());
   5320   CHECK_EQ(14, a3->Get(context.local(), 0)
   5321                    .ToLocalChecked()
   5322                    ->Int32Value(context.local())
   5323                    .FromJust());
   5324   CHECK_EQ(15, a3->Get(context.local(), 1)
   5325                    .ToLocalChecked()
   5326                    ->Int32Value(context.local())
   5327                    .FromJust());
   5328   CHECK_EQ(16, a3->Get(context.local(), 2)
   5329                    .ToLocalChecked()
   5330                    ->Int32Value(context.local())
   5331                    .FromJust());
   5332 
   5333   const char* fun5 = "f(17, 18, 19, 20)";
   5334   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
   5335   CHECK_EQ(4u, a4->Length());
   5336   CHECK_EQ(17, a4->Get(context.local(), 0)
   5337                    .ToLocalChecked()
   5338                    ->Int32Value(context.local())
   5339                    .FromJust());
   5340   CHECK_EQ(18, a4->Get(context.local(), 1)
   5341                    .ToLocalChecked()
   5342                    ->Int32Value(context.local())
   5343                    .FromJust());
   5344   CHECK_EQ(19, a4->Get(context.local(), 2)
   5345                    .ToLocalChecked()
   5346                    ->Int32Value(context.local())
   5347                    .FromJust());
   5348   CHECK_EQ(20, a4->Get(context.local(), 3)
   5349                    .ToLocalChecked()
   5350                    ->Int32Value(context.local())
   5351                    .FromJust());
   5352 }
   5353 
   5354 
   5355 THREADED_TEST(FunctionCall) {
   5356   LocalContext context;
   5357   v8::Isolate* isolate = context->GetIsolate();
   5358   v8::HandleScope scope(isolate);
   5359   CompileRun(
   5360       "function Foo() {"
   5361       "  var result = [];"
   5362       "  for (var i = 0; i < arguments.length; i++) {"
   5363       "    result.push(arguments[i]);"
   5364       "  }"
   5365       "  return result;"
   5366       "}"
   5367       "function ReturnThisSloppy() {"
   5368       "  return this;"
   5369       "}"
   5370       "function ReturnThisStrict() {"
   5371       "  'use strict';"
   5372       "  return this;"
   5373       "}");
   5374   Local<Function> Foo = Local<Function>::Cast(
   5375       context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
   5376   Local<Function> ReturnThisSloppy = Local<Function>::Cast(
   5377       context->Global()
   5378           ->Get(context.local(), v8_str("ReturnThisSloppy"))
   5379           .ToLocalChecked());
   5380   Local<Function> ReturnThisStrict = Local<Function>::Cast(
   5381       context->Global()
   5382           ->Get(context.local(), v8_str("ReturnThisStrict"))
   5383           .ToLocalChecked());
   5384 
   5385   v8::Local<Value>* args0 = NULL;
   5386   Local<v8::Array> a0 = Local<v8::Array>::Cast(
   5387       Foo->Call(context.local(), Foo, 0, args0).ToLocalChecked());
   5388   CHECK_EQ(0u, a0->Length());
   5389 
   5390   v8::Local<Value> args1[] = {v8_num(1.1)};
   5391   Local<v8::Array> a1 = Local<v8::Array>::Cast(
   5392       Foo->Call(context.local(), Foo, 1, args1).ToLocalChecked());
   5393   CHECK_EQ(1u, a1->Length());
   5394   CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
   5395                     .ToLocalChecked()
   5396                     ->NumberValue(context.local())
   5397                     .FromJust());
   5398 
   5399   v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
   5400   Local<v8::Array> a2 = Local<v8::Array>::Cast(
   5401       Foo->Call(context.local(), Foo, 2, args2).ToLocalChecked());
   5402   CHECK_EQ(2u, a2->Length());
   5403   CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
   5404                     .ToLocalChecked()
   5405                     ->NumberValue(context.local())
   5406                     .FromJust());
   5407   CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
   5408                     .ToLocalChecked()
   5409                     ->NumberValue(context.local())
   5410                     .FromJust());
   5411 
   5412   v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
   5413   Local<v8::Array> a3 = Local<v8::Array>::Cast(
   5414       Foo->Call(context.local(), Foo, 3, args3).ToLocalChecked());
   5415   CHECK_EQ(3u, a3->Length());
   5416   CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
   5417                     .ToLocalChecked()
   5418                     ->NumberValue(context.local())
   5419                     .FromJust());
   5420   CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
   5421                     .ToLocalChecked()
   5422                     ->NumberValue(context.local())
   5423                     .FromJust());
   5424   CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
   5425                     .ToLocalChecked()
   5426                     ->NumberValue(context.local())
   5427                     .FromJust());
   5428 
   5429   v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
   5430                               v8_num(10.11)};
   5431   Local<v8::Array> a4 = Local<v8::Array>::Cast(
   5432       Foo->Call(context.local(), Foo, 4, args4).ToLocalChecked());
   5433   CHECK_EQ(4u, a4->Length());
   5434   CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
   5435                     .ToLocalChecked()
   5436                     ->NumberValue(context.local())
   5437                     .FromJust());
   5438   CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
   5439                     .ToLocalChecked()
   5440                     ->NumberValue(context.local())
   5441                     .FromJust());
   5442   CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
   5443                     .ToLocalChecked()
   5444                     ->NumberValue(context.local())
   5445                     .FromJust());
   5446   CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
   5447                       .ToLocalChecked()
   5448                       ->NumberValue(context.local())
   5449                       .FromJust());
   5450 
   5451   Local<v8::Value> r1 =
   5452       ReturnThisSloppy->Call(context.local(), v8::Undefined(isolate), 0, NULL)
   5453           .ToLocalChecked();
   5454   CHECK(r1->StrictEquals(context->Global()));
   5455   Local<v8::Value> r2 =
   5456       ReturnThisSloppy->Call(context.local(), v8::Null(isolate), 0, NULL)
   5457           .ToLocalChecked();
   5458   CHECK(r2->StrictEquals(context->Global()));
   5459   Local<v8::Value> r3 =
   5460       ReturnThisSloppy->Call(context.local(), v8_num(42), 0, NULL)
   5461           .ToLocalChecked();
   5462   CHECK(r3->IsNumberObject());
   5463   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
   5464   Local<v8::Value> r4 =
   5465       ReturnThisSloppy->Call(context.local(), v8_str("hello"), 0, NULL)
   5466           .ToLocalChecked();
   5467   CHECK(r4->IsStringObject());
   5468   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
   5469   Local<v8::Value> r5 =
   5470       ReturnThisSloppy->Call(context.local(), v8::True(isolate), 0, NULL)
   5471           .ToLocalChecked();
   5472   CHECK(r5->IsBooleanObject());
   5473   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
   5474 
   5475   Local<v8::Value> r6 =
   5476       ReturnThisStrict->Call(context.local(), v8::Undefined(isolate), 0, NULL)
   5477           .ToLocalChecked();
   5478   CHECK(r6->IsUndefined());
   5479   Local<v8::Value> r7 =
   5480       ReturnThisStrict->Call(context.local(), v8::Null(isolate), 0, NULL)
   5481           .ToLocalChecked();
   5482   CHECK(r7->IsNull());
   5483   Local<v8::Value> r8 =
   5484       ReturnThisStrict->Call(context.local(), v8_num(42), 0, NULL)
   5485           .ToLocalChecked();
   5486   CHECK(r8->StrictEquals(v8_num(42)));
   5487   Local<v8::Value> r9 =
   5488       ReturnThisStrict->Call(context.local(), v8_str("hello"), 0, NULL)
   5489           .ToLocalChecked();
   5490   CHECK(r9->StrictEquals(v8_str("hello")));
   5491   Local<v8::Value> r10 =
   5492       ReturnThisStrict->Call(context.local(), v8::True(isolate), 0, NULL)
   5493           .ToLocalChecked();
   5494   CHECK(r10->StrictEquals(v8::True(isolate)));
   5495 }
   5496 
   5497 
   5498 THREADED_TEST(ConstructCall) {
   5499   LocalContext context;
   5500   v8::Isolate* isolate = context->GetIsolate();
   5501   v8::HandleScope scope(isolate);
   5502   CompileRun(
   5503       "function Foo() {"
   5504       "  var result = [];"
   5505       "  for (var i = 0; i < arguments.length; i++) {"
   5506       "    result.push(arguments[i]);"
   5507       "  }"
   5508       "  return result;"
   5509       "}");
   5510   Local<Function> Foo = Local<Function>::Cast(
   5511       context->Global()->Get(context.local(), v8_str("Foo")).ToLocalChecked());
   5512 
   5513   v8::Local<Value>* args0 = NULL;
   5514   Local<v8::Array> a0 = Local<v8::Array>::Cast(
   5515       Foo->NewInstance(context.local(), 0, args0).ToLocalChecked());
   5516   CHECK_EQ(0u, a0->Length());
   5517 
   5518   v8::Local<Value> args1[] = {v8_num(1.1)};
   5519   Local<v8::Array> a1 = Local<v8::Array>::Cast(
   5520       Foo->NewInstance(context.local(), 1, args1).ToLocalChecked());
   5521   CHECK_EQ(1u, a1->Length());
   5522   CHECK_EQ(1.1, a1->Get(context.local(), v8::Integer::New(isolate, 0))
   5523                     .ToLocalChecked()
   5524                     ->NumberValue(context.local())
   5525                     .FromJust());
   5526 
   5527   v8::Local<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
   5528   Local<v8::Array> a2 = Local<v8::Array>::Cast(
   5529       Foo->NewInstance(context.local(), 2, args2).ToLocalChecked());
   5530   CHECK_EQ(2u, a2->Length());
   5531   CHECK_EQ(2.2, a2->Get(context.local(), v8::Integer::New(isolate, 0))
   5532                     .ToLocalChecked()
   5533                     ->NumberValue(context.local())
   5534                     .FromJust());
   5535   CHECK_EQ(3.3, a2->Get(context.local(), v8::Integer::New(isolate, 1))
   5536                     .ToLocalChecked()
   5537                     ->NumberValue(context.local())
   5538                     .FromJust());
   5539 
   5540   v8::Local<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
   5541   Local<v8::Array> a3 = Local<v8::Array>::Cast(
   5542       Foo->NewInstance(context.local(), 3, args3).ToLocalChecked());
   5543   CHECK_EQ(3u, a3->Length());
   5544   CHECK_EQ(4.4, a3->Get(context.local(), v8::Integer::New(isolate, 0))
   5545                     .ToLocalChecked()
   5546                     ->NumberValue(context.local())
   5547                     .FromJust());
   5548   CHECK_EQ(5.5, a3->Get(context.local(), v8::Integer::New(isolate, 1))
   5549                     .ToLocalChecked()
   5550                     ->NumberValue(context.local())
   5551                     .FromJust());
   5552   CHECK_EQ(6.6, a3->Get(context.local(), v8::Integer::New(isolate, 2))
   5553                     .ToLocalChecked()
   5554                     ->NumberValue(context.local())
   5555                     .FromJust());
   5556 
   5557   v8::Local<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
   5558                               v8_num(10.11)};
   5559   Local<v8::Array> a4 = Local<v8::Array>::Cast(
   5560       Foo->NewInstance(context.local(), 4, args4).ToLocalChecked());
   5561   CHECK_EQ(4u, a4->Length());
   5562   CHECK_EQ(7.7, a4->Get(context.local(), v8::Integer::New(isolate, 0))
   5563                     .ToLocalChecked()
   5564                     ->NumberValue(context.local())
   5565                     .FromJust());
   5566   CHECK_EQ(8.8, a4->Get(context.local(), v8::Integer::New(isolate, 1))
   5567                     .ToLocalChecked()
   5568                     ->NumberValue(context.local())
   5569                     .FromJust());
   5570   CHECK_EQ(9.9, a4->Get(context.local(), v8::Integer::New(isolate, 2))
   5571                     .ToLocalChecked()
   5572                     ->NumberValue(context.local())
   5573                     .FromJust());
   5574   CHECK_EQ(10.11, a4->Get(context.local(), v8::Integer::New(isolate, 3))
   5575                       .ToLocalChecked()
   5576                       ->NumberValue(context.local())
   5577                       .FromJust());
   5578 }
   5579 
   5580 
   5581 THREADED_TEST(ConversionNumber) {
   5582   LocalContext env;
   5583   v8::Isolate* isolate = env->GetIsolate();
   5584   v8::HandleScope scope(isolate);
   5585   // Very large number.
   5586   CompileRun("var obj = Math.pow(2,32) * 1237;");
   5587   Local<Value> obj =
   5588       env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5589   CHECK_EQ(5312874545152.0,
   5590            obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5591   CHECK_EQ(0, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5592   CHECK(0u ==
   5593         obj->ToUint32(env.local())
   5594             .ToLocalChecked()
   5595             ->Value());  // NOLINT - no CHECK_EQ for unsigned.
   5596   // Large number.
   5597   CompileRun("var obj = -1234567890123;");
   5598   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5599   CHECK_EQ(-1234567890123.0,
   5600            obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5601   CHECK_EQ(-1912276171, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5602   CHECK(2382691125u ==
   5603         obj->ToUint32(env.local()).ToLocalChecked()->Value());  // NOLINT
   5604   // Small positive integer.
   5605   CompileRun("var obj = 42;");
   5606   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5607   CHECK_EQ(42.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5608   CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5609   CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value());  // NOLINT
   5610   // Negative integer.
   5611   CompileRun("var obj = -37;");
   5612   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5613   CHECK_EQ(-37.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5614   CHECK_EQ(-37, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5615   CHECK(4294967259u ==
   5616         obj->ToUint32(env.local()).ToLocalChecked()->Value());  // NOLINT
   5617   // Positive non-int32 integer.
   5618   CompileRun("var obj = 0x81234567;");
   5619   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5620   CHECK_EQ(2166572391.0, obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5621   CHECK_EQ(-2128394905, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5622   CHECK(2166572391u ==
   5623         obj->ToUint32(env.local()).ToLocalChecked()->Value());  // NOLINT
   5624   // Fraction.
   5625   CompileRun("var obj = 42.3;");
   5626   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5627   CHECK_EQ(42.3, obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5628   CHECK_EQ(42, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5629   CHECK(42u == obj->ToUint32(env.local()).ToLocalChecked()->Value());  // NOLINT
   5630   // Large negative fraction.
   5631   CompileRun("var obj = -5726623061.75;");
   5632   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5633   CHECK_EQ(-5726623061.75,
   5634            obj->ToNumber(env.local()).ToLocalChecked()->Value());
   5635   CHECK_EQ(-1431655765, obj->ToInt32(env.local()).ToLocalChecked()->Value());
   5636   CHECK(2863311531u ==
   5637         obj->ToUint32(env.local()).ToLocalChecked()->Value());  // NOLINT
   5638 }
   5639 
   5640 
   5641 THREADED_TEST(isNumberType) {
   5642   LocalContext env;
   5643   v8::HandleScope scope(env->GetIsolate());
   5644   // Very large number.
   5645   CompileRun("var obj = Math.pow(2,32) * 1237;");
   5646   Local<Value> obj =
   5647       env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5648   CHECK(!obj->IsInt32());
   5649   CHECK(!obj->IsUint32());
   5650   // Large negative number.
   5651   CompileRun("var obj = -1234567890123;");
   5652   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5653   CHECK(!obj->IsInt32());
   5654   CHECK(!obj->IsUint32());
   5655   // Small positive integer.
   5656   CompileRun("var obj = 42;");
   5657   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5658   CHECK(obj->IsInt32());
   5659   CHECK(obj->IsUint32());
   5660   // Negative integer.
   5661   CompileRun("var obj = -37;");
   5662   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5663   CHECK(obj->IsInt32());
   5664   CHECK(!obj->IsUint32());
   5665   // Positive non-int32 integer.
   5666   CompileRun("var obj = 0x81234567;");
   5667   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5668   CHECK(!obj->IsInt32());
   5669   CHECK(obj->IsUint32());
   5670   // Fraction.
   5671   CompileRun("var obj = 42.3;");
   5672   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5673   CHECK(!obj->IsInt32());
   5674   CHECK(!obj->IsUint32());
   5675   // Large negative fraction.
   5676   CompileRun("var obj = -5726623061.75;");
   5677   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5678   CHECK(!obj->IsInt32());
   5679   CHECK(!obj->IsUint32());
   5680   // Positive zero
   5681   CompileRun("var obj = 0.0;");
   5682   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5683   CHECK(obj->IsInt32());
   5684   CHECK(obj->IsUint32());
   5685   // Positive zero
   5686   CompileRun("var obj = -0.0;");
   5687   obj = env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5688   CHECK(!obj->IsInt32());
   5689   CHECK(!obj->IsUint32());
   5690 }
   5691 
   5692 
   5693 static void CheckUncle(v8::TryCatch* try_catch) {
   5694   CHECK(try_catch->HasCaught());
   5695   String::Utf8Value str_value(try_catch->Exception());
   5696   CHECK_EQ(0, strcmp(*str_value, "uncle?"));
   5697   try_catch->Reset();
   5698 }
   5699 
   5700 
   5701 THREADED_TEST(ConversionException) {
   5702   LocalContext env;
   5703   v8::Isolate* isolate = env->GetIsolate();
   5704   v8::HandleScope scope(isolate);
   5705   CompileRun(
   5706       "function TestClass() { };"
   5707       "TestClass.prototype.toString = function () { throw 'uncle?'; };"
   5708       "var obj = new TestClass();");
   5709   Local<Value> obj =
   5710       env->Global()->Get(env.local(), v8_str("obj")).ToLocalChecked();
   5711 
   5712   v8::TryCatch try_catch(isolate);
   5713 
   5714   CHECK(obj->ToString(env.local()).IsEmpty());
   5715   CheckUncle(&try_catch);
   5716 
   5717   CHECK(obj->ToNumber(env.local()).IsEmpty());
   5718   CheckUncle(&try_catch);
   5719 
   5720   CHECK(obj->ToInteger(env.local()).IsEmpty());
   5721   CheckUncle(&try_catch);
   5722 
   5723   CHECK(obj->ToUint32(env.local()).IsEmpty());
   5724   CheckUncle(&try_catch);
   5725 
   5726   CHECK(obj->ToInt32(env.local()).IsEmpty());
   5727   CheckUncle(&try_catch);
   5728 
   5729   CHECK(v8::Undefined(isolate)->ToObject(env.local()).IsEmpty());
   5730   CHECK(try_catch.HasCaught());
   5731   try_catch.Reset();
   5732 
   5733   CHECK(obj->Int32Value(env.local()).IsNothing());
   5734   CheckUncle(&try_catch);
   5735 
   5736   CHECK(obj->Uint32Value(env.local()).IsNothing());
   5737   CheckUncle(&try_catch);
   5738 
   5739   CHECK(obj->NumberValue(env.local()).IsNothing());
   5740   CheckUncle(&try_catch);
   5741 
   5742   CHECK(obj->IntegerValue(env.local()).IsNothing());
   5743   CheckUncle(&try_catch);
   5744 }
   5745 
   5746 
   5747 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5748   ApiTestFuzzer::Fuzz();
   5749   args.GetIsolate()->ThrowException(v8_str("konto"));
   5750 }
   5751 
   5752 
   5753 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5754   if (args.Length() < 1) {
   5755     args.GetReturnValue().Set(false);
   5756     return;
   5757   }
   5758   v8::HandleScope scope(args.GetIsolate());
   5759   v8::TryCatch try_catch(args.GetIsolate());
   5760   Local<Value> result =
   5761       CompileRun(args[0]
   5762                      ->ToString(args.GetIsolate()->GetCurrentContext())
   5763                      .ToLocalChecked());
   5764   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   5765   args.GetReturnValue().Set(try_catch.HasCaught());
   5766 }
   5767 
   5768 
   5769 THREADED_TEST(APICatch) {
   5770   v8::Isolate* isolate = CcTest::isolate();
   5771   v8::HandleScope scope(isolate);
   5772   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5773   templ->Set(v8_str("ThrowFromC"),
   5774              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5775   LocalContext context(0, templ);
   5776   CompileRun(
   5777       "var thrown = false;"
   5778       "try {"
   5779       "  ThrowFromC();"
   5780       "} catch (e) {"
   5781       "  thrown = true;"
   5782       "}");
   5783   Local<Value> thrown = context->Global()
   5784                             ->Get(context.local(), v8_str("thrown"))
   5785                             .ToLocalChecked();
   5786   CHECK(thrown->BooleanValue(context.local()).FromJust());
   5787 }
   5788 
   5789 
   5790 THREADED_TEST(APIThrowTryCatch) {
   5791   v8::Isolate* isolate = CcTest::isolate();
   5792   v8::HandleScope scope(isolate);
   5793   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5794   templ->Set(v8_str("ThrowFromC"),
   5795              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5796   LocalContext context(0, templ);
   5797   v8::TryCatch try_catch(isolate);
   5798   CompileRun("ThrowFromC();");
   5799   CHECK(try_catch.HasCaught());
   5800 }
   5801 
   5802 
   5803 // Test that a try-finally block doesn't shadow a try-catch block
   5804 // when setting up an external handler.
   5805 //
   5806 // BUG(271): Some of the exception propagation does not work on the
   5807 // ARM simulator because the simulator separates the C++ stack and the
   5808 // JS stack.  This test therefore fails on the simulator.  The test is
   5809 // not threaded to allow the threading tests to run on the simulator.
   5810 TEST(TryCatchInTryFinally) {
   5811   v8::Isolate* isolate = CcTest::isolate();
   5812   v8::HandleScope scope(isolate);
   5813   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5814   templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
   5815   LocalContext context(0, templ);
   5816   Local<Value> result = CompileRun(
   5817       "try {"
   5818       "  try {"
   5819       "    CCatcher('throw 7;');"
   5820       "  } finally {"
   5821       "  }"
   5822       "} catch (e) {"
   5823       "}");
   5824   CHECK(result->IsTrue());
   5825 }
   5826 
   5827 
   5828 static void check_custom_error_tostring(v8::Local<v8::Message> message,
   5829                                         v8::Local<v8::Value> data) {
   5830   const char* uncaught_error = "Uncaught MyError toString";
   5831   CHECK(message->Get()
   5832             ->Equals(CcTest::isolate()->GetCurrentContext(),
   5833                      v8_str(uncaught_error))
   5834             .FromJust());
   5835 }
   5836 
   5837 
   5838 TEST(CustomErrorToString) {
   5839   LocalContext context;
   5840   v8::HandleScope scope(context->GetIsolate());
   5841   context->GetIsolate()->AddMessageListener(check_custom_error_tostring);
   5842   CompileRun(
   5843       "function MyError(name, message) {                   "
   5844       "  this.name = name;                                 "
   5845       "  this.message = message;                           "
   5846       "}                                                   "
   5847       "MyError.prototype = Object.create(Error.prototype); "
   5848       "MyError.prototype.toString = function() {           "
   5849       "  return 'MyError toString';                        "
   5850       "};                                                  "
   5851       "throw new MyError('my name', 'my message');         ");
   5852   context->GetIsolate()->RemoveMessageListeners(check_custom_error_tostring);
   5853 }
   5854 
   5855 
   5856 static void check_custom_error_message(v8::Local<v8::Message> message,
   5857                                        v8::Local<v8::Value> data) {
   5858   const char* uncaught_error = "Uncaught MyError: my message";
   5859   printf("%s\n", *v8::String::Utf8Value(message->Get()));
   5860   CHECK(message->Get()
   5861             ->Equals(CcTest::isolate()->GetCurrentContext(),
   5862                      v8_str(uncaught_error))
   5863             .FromJust());
   5864 }
   5865 
   5866 
   5867 TEST(CustomErrorMessage) {
   5868   LocalContext context;
   5869   v8::HandleScope scope(context->GetIsolate());
   5870   context->GetIsolate()->AddMessageListener(check_custom_error_message);
   5871 
   5872   // Handlebars.
   5873   CompileRun(
   5874       "function MyError(msg) {                             "
   5875       "  this.name = 'MyError';                            "
   5876       "  this.message = msg;                               "
   5877       "}                                                   "
   5878       "MyError.prototype = new Error();                    "
   5879       "throw new MyError('my message');                    ");
   5880 
   5881   // Closure.
   5882   CompileRun(
   5883       "function MyError(msg) {                             "
   5884       "  this.name = 'MyError';                            "
   5885       "  this.message = msg;                               "
   5886       "}                                                   "
   5887       "inherits = function(childCtor, parentCtor) {        "
   5888       "    function tempCtor() {};                         "
   5889       "    tempCtor.prototype = parentCtor.prototype;      "
   5890       "    childCtor.superClass_ = parentCtor.prototype;   "
   5891       "    childCtor.prototype = new tempCtor();           "
   5892       "    childCtor.prototype.constructor = childCtor;    "
   5893       "};                                                  "
   5894       "inherits(MyError, Error);                           "
   5895       "throw new MyError('my message');                    ");
   5896 
   5897   // Object.create.
   5898   CompileRun(
   5899       "function MyError(msg) {                             "
   5900       "  this.name = 'MyError';                            "
   5901       "  this.message = msg;                               "
   5902       "}                                                   "
   5903       "MyError.prototype = Object.create(Error.prototype); "
   5904       "throw new MyError('my message');                    ");
   5905 
   5906   context->GetIsolate()->RemoveMessageListeners(check_custom_error_message);
   5907 }
   5908 
   5909 
   5910 static void check_custom_rethrowing_message(v8::Local<v8::Message> message,
   5911                                             v8::Local<v8::Value> data) {
   5912   const char* uncaught_error = "Uncaught exception";
   5913   CHECK(message->Get()
   5914             ->Equals(CcTest::isolate()->GetCurrentContext(),
   5915                      v8_str(uncaught_error))
   5916             .FromJust());
   5917 }
   5918 
   5919 
   5920 TEST(CustomErrorRethrowsOnToString) {
   5921   LocalContext context;
   5922   v8::HandleScope scope(context->GetIsolate());
   5923   context->GetIsolate()->AddMessageListener(check_custom_rethrowing_message);
   5924 
   5925   CompileRun(
   5926       "var e = { toString: function() { throw e; } };"
   5927       "try { throw e; } finally {}");
   5928 
   5929   context->GetIsolate()->RemoveMessageListeners(
   5930       check_custom_rethrowing_message);
   5931 }
   5932 
   5933 
   5934 static void receive_message(v8::Local<v8::Message> message,
   5935                             v8::Local<v8::Value> data) {
   5936   message->Get();
   5937   message_received = true;
   5938 }
   5939 
   5940 
   5941 TEST(APIThrowMessage) {
   5942   message_received = false;
   5943   v8::Isolate* isolate = CcTest::isolate();
   5944   v8::HandleScope scope(isolate);
   5945   isolate->AddMessageListener(receive_message);
   5946   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5947   templ->Set(v8_str("ThrowFromC"),
   5948              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5949   LocalContext context(0, templ);
   5950   CompileRun("ThrowFromC();");
   5951   CHECK(message_received);
   5952   isolate->RemoveMessageListeners(receive_message);
   5953 }
   5954 
   5955 
   5956 TEST(APIThrowMessageAndVerboseTryCatch) {
   5957   message_received = false;
   5958   v8::Isolate* isolate = CcTest::isolate();
   5959   v8::HandleScope scope(isolate);
   5960   isolate->AddMessageListener(receive_message);
   5961   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5962   templ->Set(v8_str("ThrowFromC"),
   5963              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5964   LocalContext context(0, templ);
   5965   v8::TryCatch try_catch(isolate);
   5966   try_catch.SetVerbose(true);
   5967   Local<Value> result = CompileRun("ThrowFromC();");
   5968   CHECK(try_catch.HasCaught());
   5969   CHECK(result.IsEmpty());
   5970   CHECK(message_received);
   5971   isolate->RemoveMessageListeners(receive_message);
   5972 }
   5973 
   5974 
   5975 TEST(APIStackOverflowAndVerboseTryCatch) {
   5976   message_received = false;
   5977   LocalContext context;
   5978   v8::HandleScope scope(context->GetIsolate());
   5979   context->GetIsolate()->AddMessageListener(receive_message);
   5980   v8::TryCatch try_catch(context->GetIsolate());
   5981   try_catch.SetVerbose(true);
   5982   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
   5983   CHECK(try_catch.HasCaught());
   5984   CHECK(result.IsEmpty());
   5985   CHECK(message_received);
   5986   context->GetIsolate()->RemoveMessageListeners(receive_message);
   5987 }
   5988 
   5989 
   5990 THREADED_TEST(ExternalScriptException) {
   5991   v8::Isolate* isolate = CcTest::isolate();
   5992   v8::HandleScope scope(isolate);
   5993   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5994   templ->Set(v8_str("ThrowFromC"),
   5995              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5996   LocalContext context(0, templ);
   5997 
   5998   v8::TryCatch try_catch(isolate);
   5999   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
   6000   CHECK(result.IsEmpty());
   6001   CHECK(try_catch.HasCaught());
   6002   String::Utf8Value exception_value(try_catch.Exception());
   6003   CHECK_EQ(0, strcmp("konto", *exception_value));
   6004 }
   6005 
   6006 
   6007 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
   6008   ApiTestFuzzer::Fuzz();
   6009   CHECK_EQ(4, args.Length());
   6010   v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
   6011   int count = args[0]->Int32Value(context).FromJust();
   6012   int cInterval = args[2]->Int32Value(context).FromJust();
   6013   if (count == 0) {
   6014     args.GetIsolate()->ThrowException(v8_str("FromC"));
   6015     return;
   6016   } else {
   6017     Local<v8::Object> global = context->Global();
   6018     Local<Value> fun =
   6019         global->Get(context, v8_str("JSThrowCountDown")).ToLocalChecked();
   6020     v8::Local<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
   6021     if (count % cInterval == 0) {
   6022       v8::TryCatch try_catch(args.GetIsolate());
   6023       Local<Value> result = fun.As<Function>()
   6024                                 ->Call(context, global, 4, argv)
   6025                                 .FromMaybe(Local<Value>());
   6026       int expected = args[3]->Int32Value(context).FromJust();
   6027       if (try_catch.HasCaught()) {
   6028         CHECK_EQ(expected, count);
   6029         CHECK(result.IsEmpty());
   6030         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
   6031       } else {
   6032         CHECK_NE(expected, count);
   6033       }
   6034       args.GetReturnValue().Set(result);
   6035       return;
   6036     } else {
   6037       args.GetReturnValue().Set(fun.As<Function>()
   6038                                     ->Call(context, global, 4, argv)
   6039                                     .FromMaybe(v8::Local<v8::Value>()));
   6040       return;
   6041     }
   6042   }
   6043 }
   6044 
   6045 
   6046 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
   6047   ApiTestFuzzer::Fuzz();
   6048   CHECK_EQ(3, args.Length());
   6049   v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
   6050   bool equality = args[0]->BooleanValue(context).FromJust();
   6051   int count = args[1]->Int32Value(context).FromJust();
   6052   int expected = args[2]->Int32Value(context).FromJust();
   6053   if (equality) {
   6054     CHECK_EQ(count, expected);
   6055   } else {
   6056     CHECK_NE(count, expected);
   6057   }
   6058 }
   6059 
   6060 
   6061 THREADED_TEST(EvalInTryFinally) {
   6062   LocalContext context;
   6063   v8::HandleScope scope(context->GetIsolate());
   6064   v8::TryCatch try_catch(context->GetIsolate());
   6065   CompileRun(
   6066       "(function() {"
   6067       "  try {"
   6068       "    eval('asldkf (*&^&*^');"
   6069       "  } finally {"
   6070       "    return;"
   6071       "  }"
   6072       "})()");
   6073   CHECK(!try_catch.HasCaught());
   6074 }
   6075 
   6076 
   6077 // This test works by making a stack of alternating JavaScript and C
   6078 // activations.  These activations set up exception handlers with regular
   6079 // intervals, one interval for C activations and another for JavaScript
   6080 // activations.  When enough activations have been created an exception is
   6081 // thrown and we check that the right activation catches the exception and that
   6082 // no other activations do.  The right activation is always the topmost one with
   6083 // a handler, regardless of whether it is in JavaScript or C.
   6084 //
   6085 // The notation used to describe a test case looks like this:
   6086 //
   6087 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
   6088 //
   6089 // Each entry is an activation, either JS or C.  The index is the count at that
   6090 // level.  Stars identify activations with exception handlers, the @ identifies
   6091 // the exception handler that should catch the exception.
   6092 //
   6093 // BUG(271): Some of the exception propagation does not work on the
   6094 // ARM simulator because the simulator separates the C++ stack and the
   6095 // JS stack.  This test therefore fails on the simulator.  The test is
   6096 // not threaded to allow the threading tests to run on the simulator.
   6097 TEST(ExceptionOrder) {
   6098   v8::Isolate* isolate = CcTest::isolate();
   6099   v8::HandleScope scope(isolate);
   6100   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6101   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
   6102   templ->Set(v8_str("CThrowCountDown"),
   6103              v8::FunctionTemplate::New(isolate, CThrowCountDown));
   6104   LocalContext context(0, templ);
   6105   CompileRun(
   6106       "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
   6107       "  if (count == 0) throw 'FromJS';"
   6108       "  if (count % jsInterval == 0) {"
   6109       "    try {"
   6110       "      var value = CThrowCountDown(count - 1,"
   6111       "                                  jsInterval,"
   6112       "                                  cInterval,"
   6113       "                                  expected);"
   6114       "      check(false, count, expected);"
   6115       "      return value;"
   6116       "    } catch (e) {"
   6117       "      check(true, count, expected);"
   6118       "    }"
   6119       "  } else {"
   6120       "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
   6121       "  }"
   6122       "}");
   6123   Local<Function> fun = Local<Function>::Cast(
   6124       context->Global()
   6125           ->Get(context.local(), v8_str("JSThrowCountDown"))
   6126           .ToLocalChecked());
   6127 
   6128   const int argc = 4;
   6129   //                             count      jsInterval cInterval  expected
   6130 
   6131   // *JS[4] *C[3] @JS[2] C[1] JS[0]
   6132   v8::Local<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
   6133   fun->Call(context.local(), fun, argc, a0).ToLocalChecked();
   6134 
   6135   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
   6136   v8::Local<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
   6137   fun->Call(context.local(), fun, argc, a1).ToLocalChecked();
   6138 
   6139   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
   6140   v8::Local<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
   6141   fun->Call(context.local(), fun, argc, a2).ToLocalChecked();
   6142 
   6143   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
   6144   v8::Local<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
   6145   fun->Call(context.local(), fun, argc, a3).ToLocalChecked();
   6146 
   6147   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
   6148   v8::Local<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
   6149   fun->Call(context.local(), fun, argc, a4).ToLocalChecked();
   6150 
   6151   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
   6152   v8::Local<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
   6153   fun->Call(context.local(), fun, argc, a5).ToLocalChecked();
   6154 }
   6155 
   6156 
   6157 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
   6158   ApiTestFuzzer::