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 "src/v8.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/compilation-cache.h"
     44 #include "src/cpu-profiler.h"
     45 #include "src/execution.h"
     46 #include "src/isolate.h"
     47 #include "src/objects.h"
     48 #include "src/parser.h"
     49 #include "src/snapshot.h"
     50 #include "src/unicode-inl.h"
     51 #include "src/utils.h"
     52 #include "src/vm-state.h"
     53 #include "test/cctest/cctest.h"
     54 
     55 static const bool kLogThreading = false;
     56 
     57 using ::v8::Boolean;
     58 using ::v8::BooleanObject;
     59 using ::v8::Context;
     60 using ::v8::Extension;
     61 using ::v8::Function;
     62 using ::v8::FunctionTemplate;
     63 using ::v8::Handle;
     64 using ::v8::HandleScope;
     65 using ::v8::Local;
     66 using ::v8::Name;
     67 using ::v8::Message;
     68 using ::v8::MessageCallback;
     69 using ::v8::Object;
     70 using ::v8::ObjectTemplate;
     71 using ::v8::Persistent;
     72 using ::v8::Script;
     73 using ::v8::StackTrace;
     74 using ::v8::String;
     75 using ::v8::Symbol;
     76 using ::v8::TryCatch;
     77 using ::v8::Undefined;
     78 using ::v8::UniqueId;
     79 using ::v8::V8;
     80 using ::v8::Value;
     81 
     82 
     83 #define THREADED_PROFILED_TEST(Name)                                 \
     84   static void Test##Name();                                          \
     85   TEST(Name##WithProfiler) {                                         \
     86     RunWithProfiler(&Test##Name);                                    \
     87   }                                                                  \
     88   THREADED_TEST(Name)
     89 
     90 
     91 void RunWithProfiler(void (*test)()) {
     92   LocalContext env;
     93   v8::HandleScope scope(env->GetIsolate());
     94   v8::Local<v8::String> profile_name =
     95       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
     96   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
     97 
     98   cpu_profiler->StartProfiling(profile_name);
     99   (*test)();
    100   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
    101 }
    102 
    103 
    104 static int signature_callback_count;
    105 static Local<Value> signature_expected_receiver;
    106 static void IncrementingSignatureCallback(
    107     const v8::FunctionCallbackInfo<v8::Value>& args) {
    108   ApiTestFuzzer::Fuzz();
    109   signature_callback_count++;
    110   CHECK_EQ(signature_expected_receiver, args.Holder());
    111   CHECK_EQ(signature_expected_receiver, args.This());
    112   v8::Handle<v8::Array> result =
    113       v8::Array::New(args.GetIsolate(), args.Length());
    114   for (int i = 0; i < args.Length(); i++)
    115     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
    116   args.GetReturnValue().Set(result);
    117 }
    118 
    119 
    120 static void SignatureCallback(
    121     const v8::FunctionCallbackInfo<v8::Value>& args) {
    122   ApiTestFuzzer::Fuzz();
    123   v8::Handle<v8::Array> result =
    124       v8::Array::New(args.GetIsolate(), args.Length());
    125   for (int i = 0; i < args.Length(); i++) {
    126     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
    127   }
    128   args.GetReturnValue().Set(result);
    129 }
    130 
    131 
    132 // Tests that call v8::V8::Dispose() cannot be threaded.
    133 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
    134   CHECK(v8::V8::Initialize());
    135   CHECK(v8::V8::Dispose());
    136 }
    137 
    138 
    139 // Tests that call v8::V8::Dispose() cannot be threaded.
    140 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
    141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    142   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
    143   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
    145   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    146 }
    147 
    148 
    149 THREADED_TEST(Handles) {
    150   v8::HandleScope scope(CcTest::isolate());
    151   Local<Context> local_env;
    152   {
    153     LocalContext env;
    154     local_env = env.local();
    155   }
    156 
    157   // Local context should still be live.
    158   CHECK(!local_env.IsEmpty());
    159   local_env->Enter();
    160 
    161   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
    162   CHECK(!undef.IsEmpty());
    163   CHECK(undef->IsUndefined());
    164 
    165   const char* source = "1 + 2 + 3";
    166   Local<Script> script = v8_compile(source);
    167   CHECK_EQ(6, script->Run()->Int32Value());
    168 
    169   local_env->Exit();
    170 }
    171 
    172 
    173 THREADED_TEST(IsolateOfContext) {
    174   v8::HandleScope scope(CcTest::isolate());
    175   v8::Handle<Context> env = Context::New(CcTest::isolate());
    176 
    177   CHECK(!env->GetIsolate()->InContext());
    178   CHECK(env->GetIsolate() == CcTest::isolate());
    179   env->Enter();
    180   CHECK(env->GetIsolate()->InContext());
    181   CHECK(env->GetIsolate() == CcTest::isolate());
    182   env->Exit();
    183   CHECK(!env->GetIsolate()->InContext());
    184   CHECK(env->GetIsolate() == CcTest::isolate());
    185 }
    186 
    187 
    188 static void TestSignature(const char* loop_js, Local<Value> receiver) {
    189   i::ScopedVector<char> source(200);
    190   i::SNPrintF(source,
    191               "for (var i = 0; i < 10; i++) {"
    192               "  %s"
    193               "}",
    194               loop_js);
    195   signature_callback_count = 0;
    196   signature_expected_receiver = receiver;
    197   bool expected_to_throw = receiver.IsEmpty();
    198   v8::TryCatch try_catch;
    199   CompileRun(source.start());
    200   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
    201   if (!expected_to_throw) {
    202     CHECK_EQ(10, signature_callback_count);
    203   } else {
    204     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
    205              try_catch.Exception()->ToString());
    206   }
    207 }
    208 
    209 
    210 THREADED_TEST(ReceiverSignature) {
    211   LocalContext env;
    212   v8::Isolate* isolate = env->GetIsolate();
    213   v8::HandleScope scope(isolate);
    214   // Setup templates.
    215   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
    216   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
    217   v8::Handle<v8::FunctionTemplate> callback_sig =
    218       v8::FunctionTemplate::New(
    219           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
    220   v8::Handle<v8::FunctionTemplate> callback =
    221       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
    222   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
    223   sub_fun->Inherit(fun);
    224   v8::Handle<v8::FunctionTemplate> unrel_fun =
    225       v8::FunctionTemplate::New(isolate);
    226   // Install properties.
    227   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
    228   fun_proto->Set(v8_str("prop_sig"), callback_sig);
    229   fun_proto->Set(v8_str("prop"), callback);
    230   fun_proto->SetAccessorProperty(
    231       v8_str("accessor_sig"), callback_sig, callback_sig);
    232   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
    233   // Instantiate templates.
    234   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
    235   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
    236   // Setup global variables.
    237   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
    238   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
    239   env->Global()->Set(v8_str("fun_instance"), fun_instance);
    240   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
    241   CompileRun(
    242       "var accessor_sig_key = 'accessor_sig';"
    243       "var accessor_key = 'accessor';"
    244       "var prop_sig_key = 'prop_sig';"
    245       "var prop_key = 'prop';"
    246       ""
    247       "function copy_props(obj) {"
    248       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
    249       "  var source = Fun.prototype;"
    250       "  for (var i in keys) {"
    251       "    var key = keys[i];"
    252       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
    253       "    Object.defineProperty(obj, key, desc);"
    254       "  }"
    255       "}"
    256       ""
    257       "var obj = {};"
    258       "copy_props(obj);"
    259       "var unrel = new UnrelFun();"
    260       "copy_props(unrel);");
    261   // Test with and without ICs
    262   const char* test_objects[] = {
    263       "fun_instance", "sub_fun_instance", "obj", "unrel" };
    264   unsigned bad_signature_start_offset = 2;
    265   for (unsigned i = 0; i < arraysize(test_objects); i++) {
    266     i::ScopedVector<char> source(200);
    267     i::SNPrintF(
    268         source, "var test_object = %s; test_object", test_objects[i]);
    269     Local<Value> test_object = CompileRun(source.start());
    270     TestSignature("test_object.prop();", test_object);
    271     TestSignature("test_object.accessor;", test_object);
    272     TestSignature("test_object[accessor_key];", test_object);
    273     TestSignature("test_object.accessor = 1;", test_object);
    274     TestSignature("test_object[accessor_key] = 1;", test_object);
    275     if (i >= bad_signature_start_offset) test_object = Local<Value>();
    276     TestSignature("test_object.prop_sig();", test_object);
    277     TestSignature("test_object.accessor_sig;", test_object);
    278     TestSignature("test_object[accessor_sig_key];", test_object);
    279     TestSignature("test_object.accessor_sig = 1;", test_object);
    280     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
    281   }
    282 }
    283 
    284 
    285 THREADED_TEST(ArgumentSignature) {
    286   LocalContext env;
    287   v8::Isolate* isolate = env->GetIsolate();
    288   v8::HandleScope scope(isolate);
    289   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
    290   cons->SetClassName(v8_str("Cons"));
    291   v8::Handle<v8::Signature> sig = v8::Signature::New(
    292       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
    293   v8::Handle<v8::FunctionTemplate> fun =
    294       v8::FunctionTemplate::New(isolate,
    295                                 SignatureCallback,
    296                                 v8::Handle<Value>(),
    297                                 sig);
    298   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
    299   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
    300 
    301   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
    302   CHECK(value1->IsTrue());
    303 
    304   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
    305   CHECK(value2->IsTrue());
    306 
    307   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
    308   CHECK(value3->IsTrue());
    309 
    310   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
    311   cons1->SetClassName(v8_str("Cons1"));
    312   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
    313   cons2->SetClassName(v8_str("Cons2"));
    314   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
    315   cons3->SetClassName(v8_str("Cons3"));
    316 
    317   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
    318   v8::Handle<v8::Signature> wsig = v8::Signature::New(
    319       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
    320   v8::Handle<v8::FunctionTemplate> fun2 =
    321       v8::FunctionTemplate::New(isolate,
    322                                 SignatureCallback,
    323                                 v8::Handle<Value>(),
    324                                 wsig);
    325 
    326   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
    327   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
    328   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
    329   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
    330   v8::Handle<Value> value4 = CompileRun(
    331       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
    332       "'[object Cons1],[object Cons2],[object Cons3]'");
    333   CHECK(value4->IsTrue());
    334 
    335   v8::Handle<Value> value5 = CompileRun(
    336       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
    337   CHECK(value5->IsTrue());
    338 
    339   v8::Handle<Value> value6 = CompileRun(
    340       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
    341   CHECK(value6->IsTrue());
    342 
    343   v8::Handle<Value> value7 = CompileRun(
    344       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
    345       "'[object Cons1],[object Cons2],[object Cons3],d';");
    346   CHECK(value7->IsTrue());
    347 
    348   v8::Handle<Value> value8 = CompileRun(
    349       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
    350   CHECK(value8->IsTrue());
    351 }
    352 
    353 
    354 THREADED_TEST(HulIgennem) {
    355   LocalContext env;
    356   v8::Isolate* isolate = env->GetIsolate();
    357   v8::HandleScope scope(isolate);
    358   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
    359   Local<String> undef_str = undef->ToString();
    360   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
    361   undef_str->WriteUtf8(value);
    362   CHECK_EQ(0, strcmp(value, "undefined"));
    363   i::DeleteArray(value);
    364 }
    365 
    366 
    367 THREADED_TEST(Access) {
    368   LocalContext env;
    369   v8::Isolate* isolate = env->GetIsolate();
    370   v8::HandleScope scope(isolate);
    371   Local<v8::Object> obj = v8::Object::New(isolate);
    372   Local<Value> foo_before = obj->Get(v8_str("foo"));
    373   CHECK(foo_before->IsUndefined());
    374   Local<String> bar_str = v8_str("bar");
    375   obj->Set(v8_str("foo"), bar_str);
    376   Local<Value> foo_after = obj->Get(v8_str("foo"));
    377   CHECK(!foo_after->IsUndefined());
    378   CHECK(foo_after->IsString());
    379   CHECK_EQ(bar_str, foo_after);
    380 }
    381 
    382 
    383 THREADED_TEST(AccessElement) {
    384   LocalContext env;
    385   v8::HandleScope scope(env->GetIsolate());
    386   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
    387   Local<Value> before = obj->Get(1);
    388   CHECK(before->IsUndefined());
    389   Local<String> bar_str = v8_str("bar");
    390   obj->Set(1, bar_str);
    391   Local<Value> after = obj->Get(1);
    392   CHECK(!after->IsUndefined());
    393   CHECK(after->IsString());
    394   CHECK_EQ(bar_str, after);
    395 
    396   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
    397   CHECK_EQ(v8_str("a"), value->Get(0));
    398   CHECK_EQ(v8_str("b"), value->Get(1));
    399 }
    400 
    401 
    402 THREADED_TEST(Script) {
    403   LocalContext env;
    404   v8::HandleScope scope(env->GetIsolate());
    405   const char* source = "1 + 2 + 3";
    406   Local<Script> script = v8_compile(source);
    407   CHECK_EQ(6, script->Run()->Int32Value());
    408 }
    409 
    410 
    411 class TestResource: public String::ExternalStringResource {
    412  public:
    413   explicit TestResource(uint16_t* data, int* counter = NULL,
    414                         bool owning_data = true)
    415       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
    416     while (data[length_]) ++length_;
    417   }
    418 
    419   ~TestResource() {
    420     if (owning_data_) i::DeleteArray(data_);
    421     if (counter_ != NULL) ++*counter_;
    422   }
    423 
    424   const uint16_t* data() const {
    425     return data_;
    426   }
    427 
    428   size_t length() const {
    429     return length_;
    430   }
    431 
    432  private:
    433   uint16_t* data_;
    434   size_t length_;
    435   int* counter_;
    436   bool owning_data_;
    437 };
    438 
    439 
    440 class TestOneByteResource : public String::ExternalOneByteStringResource {
    441  public:
    442   explicit TestOneByteResource(const char* data, int* counter = NULL,
    443                                size_t offset = 0)
    444       : orig_data_(data),
    445         data_(data + offset),
    446         length_(strlen(data) - offset),
    447         counter_(counter) {}
    448 
    449   ~TestOneByteResource() {
    450     i::DeleteArray(orig_data_);
    451     if (counter_ != NULL) ++*counter_;
    452   }
    453 
    454   const char* data() const {
    455     return data_;
    456   }
    457 
    458   size_t length() const {
    459     return length_;
    460   }
    461 
    462  private:
    463   const char* orig_data_;
    464   const char* data_;
    465   size_t length_;
    466   int* counter_;
    467 };
    468 
    469 
    470 THREADED_TEST(ScriptUsingStringResource) {
    471   int dispose_count = 0;
    472   const char* c_source = "1 + 2 * 3";
    473   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
    474   {
    475     LocalContext env;
    476     v8::HandleScope scope(env->GetIsolate());
    477     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
    478     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
    479     Local<Script> script = v8_compile(source);
    480     Local<Value> value = script->Run();
    481     CHECK(value->IsNumber());
    482     CHECK_EQ(7, value->Int32Value());
    483     CHECK(source->IsExternal());
    484     CHECK_EQ(resource,
    485              static_cast<TestResource*>(source->GetExternalStringResource()));
    486     String::Encoding encoding = String::UNKNOWN_ENCODING;
    487     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    488              source->GetExternalStringResourceBase(&encoding));
    489     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
    490     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    491     CHECK_EQ(0, dispose_count);
    492   }
    493   CcTest::i_isolate()->compilation_cache()->Clear();
    494   CcTest::heap()->CollectAllAvailableGarbage();
    495   CHECK_EQ(1, dispose_count);
    496 }
    497 
    498 
    499 THREADED_TEST(ScriptUsingOneByteStringResource) {
    500   int dispose_count = 0;
    501   const char* c_source = "1 + 2 * 3";
    502   {
    503     LocalContext env;
    504     v8::HandleScope scope(env->GetIsolate());
    505     TestOneByteResource* resource =
    506         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
    507     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
    508     CHECK(source->IsExternalOneByte());
    509     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    510              source->GetExternalOneByteStringResource());
    511     String::Encoding encoding = String::UNKNOWN_ENCODING;
    512     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    513              source->GetExternalStringResourceBase(&encoding));
    514     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
    515     Local<Script> script = v8_compile(source);
    516     Local<Value> value = script->Run();
    517     CHECK(value->IsNumber());
    518     CHECK_EQ(7, value->Int32Value());
    519     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    520     CHECK_EQ(0, dispose_count);
    521   }
    522   CcTest::i_isolate()->compilation_cache()->Clear();
    523   CcTest::heap()->CollectAllAvailableGarbage();
    524   CHECK_EQ(1, dispose_count);
    525 }
    526 
    527 
    528 THREADED_TEST(ScriptMakingExternalString) {
    529   int dispose_count = 0;
    530   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
    531   {
    532     LocalContext env;
    533     v8::HandleScope scope(env->GetIsolate());
    534     Local<String> source =
    535         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
    536     // Trigger GCs so that the newly allocated string moves to old gen.
    537     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    538     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    539     CHECK_EQ(source->IsExternal(), false);
    540     CHECK_EQ(source->IsExternalOneByte(), false);
    541     String::Encoding encoding = String::UNKNOWN_ENCODING;
    542     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
    543     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
    544     bool success = source->MakeExternal(new TestResource(two_byte_source,
    545                                                          &dispose_count));
    546     CHECK(success);
    547     Local<Script> script = v8_compile(source);
    548     Local<Value> value = script->Run();
    549     CHECK(value->IsNumber());
    550     CHECK_EQ(7, value->Int32Value());
    551     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    552     CHECK_EQ(0, dispose_count);
    553   }
    554   CcTest::i_isolate()->compilation_cache()->Clear();
    555   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
    556   CHECK_EQ(1, dispose_count);
    557 }
    558 
    559 
    560 THREADED_TEST(ScriptMakingExternalOneByteString) {
    561   int dispose_count = 0;
    562   const char* c_source = "1 + 2 * 3";
    563   {
    564     LocalContext env;
    565     v8::HandleScope scope(env->GetIsolate());
    566     Local<String> source = v8_str(c_source);
    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     bool success = source->MakeExternal(
    571         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
    572     CHECK(success);
    573     Local<Script> script = v8_compile(source);
    574     Local<Value> value = script->Run();
    575     CHECK(value->IsNumber());
    576     CHECK_EQ(7, value->Int32Value());
    577     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    578     CHECK_EQ(0, dispose_count);
    579   }
    580   CcTest::i_isolate()->compilation_cache()->Clear();
    581   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
    582   CHECK_EQ(1, dispose_count);
    583 }
    584 
    585 
    586 TEST(MakingExternalStringConditions) {
    587   LocalContext env;
    588   v8::HandleScope scope(env->GetIsolate());
    589 
    590   // Free some space in the new space so that we can check freshness.
    591   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    592   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    593 
    594   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
    595   Local<String> small_string =
    596       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
    597   i::DeleteArray(two_byte_string);
    598 
    599   // We should refuse to externalize newly created small string.
    600   CHECK(!small_string->CanMakeExternal());
    601   // Trigger GCs so that the newly allocated string moves to old gen.
    602   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    603   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    604   // Old space strings should be accepted.
    605   CHECK(small_string->CanMakeExternal());
    606 
    607   two_byte_string = AsciiToTwoByteString("small string 2");
    608   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
    609   i::DeleteArray(two_byte_string);
    610 
    611   // We should refuse externalizing newly created small string.
    612   CHECK(!small_string->CanMakeExternal());
    613   for (int i = 0; i < 100; i++) {
    614     String::Value value(small_string);
    615   }
    616   // Frequently used strings should be accepted.
    617   CHECK(small_string->CanMakeExternal());
    618 
    619   const int buf_size = 10 * 1024;
    620   char* buf = i::NewArray<char>(buf_size);
    621   memset(buf, 'a', buf_size);
    622   buf[buf_size - 1] = '\0';
    623 
    624   two_byte_string = AsciiToTwoByteString(buf);
    625   Local<String> large_string =
    626       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
    627   i::DeleteArray(buf);
    628   i::DeleteArray(two_byte_string);
    629   // Large strings should be immediately accepted.
    630   CHECK(large_string->CanMakeExternal());
    631 }
    632 
    633 
    634 TEST(MakingExternalOneByteStringConditions) {
    635   LocalContext env;
    636   v8::HandleScope scope(env->GetIsolate());
    637 
    638   // Free some space in the new space so that we can check freshness.
    639   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    641 
    642   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
    643   // We should refuse to externalize newly created small string.
    644   CHECK(!small_string->CanMakeExternal());
    645   // Trigger GCs so that the newly allocated string moves to old gen.
    646   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    647   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    648   // Old space strings should be accepted.
    649   CHECK(small_string->CanMakeExternal());
    650 
    651   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
    652   // We should refuse externalizing newly created small string.
    653   CHECK(!small_string->CanMakeExternal());
    654   for (int i = 0; i < 100; i++) {
    655     String::Value value(small_string);
    656   }
    657   // Frequently used strings should be accepted.
    658   CHECK(small_string->CanMakeExternal());
    659 
    660   const int buf_size = 10 * 1024;
    661   char* buf = i::NewArray<char>(buf_size);
    662   memset(buf, 'a', buf_size);
    663   buf[buf_size - 1] = '\0';
    664   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
    665   i::DeleteArray(buf);
    666   // Large strings should be immediately accepted.
    667   CHECK(large_string->CanMakeExternal());
    668 }
    669 
    670 
    671 TEST(MakingExternalUnalignedOneByteString) {
    672   LocalContext env;
    673   v8::HandleScope scope(env->GetIsolate());
    674 
    675   CompileRun("function cons(a, b) { return a + b; }"
    676              "function slice(a) { return a.substring(1); }");
    677   // Create a cons string that will land in old pointer space.
    678   Local<String> cons = Local<String>::Cast(CompileRun(
    679       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
    680   // Create a sliced string that will land in old pointer space.
    681   Local<String> slice = Local<String>::Cast(CompileRun(
    682       "slice('abcdefghijklmnopqrstuvwxyz');"));
    683 
    684   // Trigger GCs so that the newly allocated string moves to old gen.
    685   SimulateFullSpace(CcTest::heap()->old_pointer_space());
    686   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    687   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    688 
    689   // Turn into external string with unaligned resource data.
    690   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
    691   bool success =
    692       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
    693   CHECK(success);
    694   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
    695   success =
    696       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
    697   CHECK(success);
    698 
    699   // Trigger GCs and force evacuation.
    700   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    701   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
    702 }
    703 
    704 
    705 THREADED_TEST(UsingExternalString) {
    706   i::Factory* factory = CcTest::i_isolate()->factory();
    707   {
    708     v8::HandleScope scope(CcTest::isolate());
    709     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    710     Local<String> string = String::NewExternal(
    711         CcTest::isolate(), new TestResource(two_byte_string));
    712     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    713     // Trigger GCs so that the newly allocated string moves to old gen.
    714     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    715     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    716     i::Handle<i::String> isymbol =
    717         factory->InternalizeString(istring);
    718     CHECK(isymbol->IsInternalizedString());
    719   }
    720   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    721   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    722 }
    723 
    724 
    725 THREADED_TEST(UsingExternalOneByteString) {
    726   i::Factory* factory = CcTest::i_isolate()->factory();
    727   {
    728     v8::HandleScope scope(CcTest::isolate());
    729     const char* one_byte_string = "test string";
    730     Local<String> string = String::NewExternal(
    731         CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
    732     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    733     // Trigger GCs so that the newly allocated string moves to old gen.
    734     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    735     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    736     i::Handle<i::String> isymbol =
    737         factory->InternalizeString(istring);
    738     CHECK(isymbol->IsInternalizedString());
    739   }
    740   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    741   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    742 }
    743 
    744 
    745 THREADED_TEST(ScavengeExternalString) {
    746   i::FLAG_stress_compaction = false;
    747   i::FLAG_gc_global = false;
    748   int dispose_count = 0;
    749   bool in_new_space = false;
    750   {
    751     v8::HandleScope scope(CcTest::isolate());
    752     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    753     Local<String> string = String::NewExternal(
    754         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
    755     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    756     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    757     in_new_space = CcTest::heap()->InNewSpace(*istring);
    758     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
    759     CHECK_EQ(0, dispose_count);
    760   }
    761   CcTest::heap()->CollectGarbage(
    762       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
    763   CHECK_EQ(1, dispose_count);
    764 }
    765 
    766 
    767 THREADED_TEST(ScavengeExternalOneByteString) {
    768   i::FLAG_stress_compaction = false;
    769   i::FLAG_gc_global = false;
    770   int dispose_count = 0;
    771   bool in_new_space = false;
    772   {
    773     v8::HandleScope scope(CcTest::isolate());
    774     const char* one_byte_string = "test string";
    775     Local<String> string = String::NewExternal(
    776         CcTest::isolate(),
    777         new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
    778     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    779     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    780     in_new_space = CcTest::heap()->InNewSpace(*istring);
    781     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
    782     CHECK_EQ(0, dispose_count);
    783   }
    784   CcTest::heap()->CollectGarbage(
    785       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
    786   CHECK_EQ(1, dispose_count);
    787 }
    788 
    789 
    790 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
    791  public:
    792   // Only used by non-threaded tests, so it can use static fields.
    793   static int dispose_calls;
    794   static int dispose_count;
    795 
    796   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
    797       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
    798 
    799   void Dispose() {
    800     ++dispose_calls;
    801     if (dispose_) delete this;
    802   }
    803  private:
    804   bool dispose_;
    805 };
    806 
    807 
    808 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
    809 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
    810 
    811 
    812 TEST(ExternalStringWithDisposeHandling) {
    813   const char* c_source = "1 + 2 * 3";
    814 
    815   // Use a stack allocated external string resource allocated object.
    816   TestOneByteResourceWithDisposeControl::dispose_count = 0;
    817   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
    818   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
    819   {
    820     LocalContext env;
    821     v8::HandleScope scope(env->GetIsolate());
    822     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
    823     Local<Script> script = v8_compile(source);
    824     Local<Value> value = script->Run();
    825     CHECK(value->IsNumber());
    826     CHECK_EQ(7, value->Int32Value());
    827     CcTest::heap()->CollectAllAvailableGarbage();
    828     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
    829   }
    830   CcTest::i_isolate()->compilation_cache()->Clear();
    831   CcTest::heap()->CollectAllAvailableGarbage();
    832   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
    833   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
    834 
    835   // Use a heap allocated external string resource allocated object.
    836   TestOneByteResourceWithDisposeControl::dispose_count = 0;
    837   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
    838   TestOneByteResource* res_heap =
    839       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
    840   {
    841     LocalContext env;
    842     v8::HandleScope scope(env->GetIsolate());
    843     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
    844     Local<Script> script = v8_compile(source);
    845     Local<Value> value = script->Run();
    846     CHECK(value->IsNumber());
    847     CHECK_EQ(7, value->Int32Value());
    848     CcTest::heap()->CollectAllAvailableGarbage();
    849     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
    850   }
    851   CcTest::i_isolate()->compilation_cache()->Clear();
    852   CcTest::heap()->CollectAllAvailableGarbage();
    853   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
    854   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
    855 }
    856 
    857 
    858 THREADED_TEST(StringConcat) {
    859   {
    860     LocalContext env;
    861     v8::HandleScope scope(env->GetIsolate());
    862     const char* one_byte_string_1 = "function a_times_t";
    863     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
    864     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
    865     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
    866     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    867     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    868     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
    869     Local<String> left = v8_str(one_byte_string_1);
    870 
    871     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
    872     Local<String> right =
    873         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
    874     i::DeleteArray(two_byte_source);
    875 
    876     Local<String> source = String::Concat(left, right);
    877     right = String::NewExternal(
    878         env->GetIsolate(),
    879         new TestOneByteResource(i::StrDup(one_byte_extern_1)));
    880     source = String::Concat(source, right);
    881     right = String::NewExternal(
    882         env->GetIsolate(),
    883         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
    884     source = String::Concat(source, right);
    885     right = v8_str(one_byte_string_2);
    886     source = String::Concat(source, right);
    887 
    888     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
    889     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
    890     i::DeleteArray(two_byte_source);
    891 
    892     source = String::Concat(source, right);
    893     right = String::NewExternal(
    894         env->GetIsolate(),
    895         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
    896     source = String::Concat(source, right);
    897     Local<Script> script = v8_compile(source);
    898     Local<Value> value = script->Run();
    899     CHECK(value->IsNumber());
    900     CHECK_EQ(68, value->Int32Value());
    901   }
    902   CcTest::i_isolate()->compilation_cache()->Clear();
    903   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    904   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    905 }
    906 
    907 
    908 THREADED_TEST(GlobalProperties) {
    909   LocalContext env;
    910   v8::HandleScope scope(env->GetIsolate());
    911   v8::Handle<v8::Object> global = env->Global();
    912   global->Set(v8_str("pi"), v8_num(3.1415926));
    913   Local<Value> pi = global->Get(v8_str("pi"));
    914   CHECK_EQ(3.1415926, pi->NumberValue());
    915 }
    916 
    917 
    918 template<typename T>
    919 static void CheckReturnValue(const T& t, i::Address callback) {
    920   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
    921   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
    922   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
    923   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
    924   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
    925   // Verify reset
    926   bool is_runtime = (*o)->IsTheHole();
    927   rv.Set(true);
    928   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
    929   rv.Set(v8::Handle<v8::Object>());
    930   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
    931   CHECK_EQ(is_runtime, (*o)->IsTheHole());
    932 
    933   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
    934   // If CPU profiler is active check that when API callback is invoked
    935   // VMState is set to EXTERNAL.
    936   if (isolate->cpu_profiler()->is_profiling()) {
    937     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
    938     CHECK(isolate->external_callback_scope());
    939     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
    940   }
    941 }
    942 
    943 
    944 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
    945                                  i::Address callback) {
    946   ApiTestFuzzer::Fuzz();
    947   CheckReturnValue(info, callback);
    948   info.GetReturnValue().Set(v8_str("bad value"));
    949   info.GetReturnValue().Set(v8_num(102));
    950 }
    951 
    952 
    953 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
    954   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
    955 }
    956 
    957 
    958 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
    959   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
    960 }
    961 
    962 static void construct_callback(
    963     const v8::FunctionCallbackInfo<Value>& info) {
    964   ApiTestFuzzer::Fuzz();
    965   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
    966   info.This()->Set(v8_str("x"), v8_num(1));
    967   info.This()->Set(v8_str("y"), v8_num(2));
    968   info.GetReturnValue().Set(v8_str("bad value"));
    969   info.GetReturnValue().Set(info.This());
    970 }
    971 
    972 
    973 static void Return239Callback(
    974     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
    975   ApiTestFuzzer::Fuzz();
    976   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
    977   info.GetReturnValue().Set(v8_str("bad value"));
    978   info.GetReturnValue().Set(v8_num(239));
    979 }
    980 
    981 
    982 template<typename Handler>
    983 static void TestFunctionTemplateInitializer(Handler handler,
    984                                             Handler handler_2) {
    985   // Test constructor calls.
    986   {
    987     LocalContext env;
    988     v8::Isolate* isolate = env->GetIsolate();
    989     v8::HandleScope scope(isolate);
    990 
    991     Local<v8::FunctionTemplate> fun_templ =
    992         v8::FunctionTemplate::New(isolate, handler);
    993     Local<Function> fun = fun_templ->GetFunction();
    994     env->Global()->Set(v8_str("obj"), fun);
    995     Local<Script> script = v8_compile("obj()");
    996     for (int i = 0; i < 30; i++) {
    997       CHECK_EQ(102, script->Run()->Int32Value());
    998     }
    999   }
   1000   // Use SetCallHandler to initialize a function template, should work like
   1001   // the previous one.
   1002   {
   1003     LocalContext env;
   1004     v8::Isolate* isolate = env->GetIsolate();
   1005     v8::HandleScope scope(isolate);
   1006 
   1007     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   1008     fun_templ->SetCallHandler(handler_2);
   1009     Local<Function> fun = fun_templ->GetFunction();
   1010     env->Global()->Set(v8_str("obj"), fun);
   1011     Local<Script> script = v8_compile("obj()");
   1012     for (int i = 0; i < 30; i++) {
   1013       CHECK_EQ(102, script->Run()->Int32Value());
   1014     }
   1015   }
   1016 }
   1017 
   1018 
   1019 template<typename Constructor, typename Accessor>
   1020 static void TestFunctionTemplateAccessor(Constructor constructor,
   1021                                          Accessor accessor) {
   1022   LocalContext env;
   1023   v8::HandleScope scope(env->GetIsolate());
   1024 
   1025   Local<v8::FunctionTemplate> fun_templ =
   1026       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
   1027   fun_templ->SetClassName(v8_str("funky"));
   1028   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
   1029   Local<Function> fun = fun_templ->GetFunction();
   1030   env->Global()->Set(v8_str("obj"), fun);
   1031   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
   1032   CHECK_EQ(v8_str("[object funky]"), result);
   1033   CompileRun("var obj_instance = new obj();");
   1034   Local<Script> script;
   1035   script = v8_compile("obj_instance.x");
   1036   for (int i = 0; i < 30; i++) {
   1037     CHECK_EQ(1, script->Run()->Int32Value());
   1038   }
   1039   script = v8_compile("obj_instance.m");
   1040   for (int i = 0; i < 30; i++) {
   1041     CHECK_EQ(239, script->Run()->Int32Value());
   1042   }
   1043 }
   1044 
   1045 
   1046 THREADED_PROFILED_TEST(FunctionTemplate) {
   1047   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
   1048   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
   1049 }
   1050 
   1051 
   1052 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1053   ApiTestFuzzer::Fuzz();
   1054   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
   1055   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
   1056 }
   1057 
   1058 
   1059 template<typename Callback>
   1060 static void TestSimpleCallback(Callback callback) {
   1061   LocalContext env;
   1062   v8::Isolate* isolate = env->GetIsolate();
   1063   v8::HandleScope scope(isolate);
   1064 
   1065   v8::Handle<v8::ObjectTemplate> object_template =
   1066       v8::ObjectTemplate::New(isolate);
   1067   object_template->Set(isolate, "callback",
   1068                        v8::FunctionTemplate::New(isolate, callback));
   1069   v8::Local<v8::Object> object = object_template->NewInstance();
   1070   (*env)->Global()->Set(v8_str("callback_object"), object);
   1071   v8::Handle<v8::Script> script;
   1072   script = v8_compile("callback_object.callback(17)");
   1073   for (int i = 0; i < 30; i++) {
   1074     CHECK_EQ(51424, script->Run()->Int32Value());
   1075   }
   1076   script = v8_compile("callback_object.callback(17, 24)");
   1077   for (int i = 0; i < 30; i++) {
   1078     CHECK_EQ(51425, script->Run()->Int32Value());
   1079   }
   1080 }
   1081 
   1082 
   1083 THREADED_PROFILED_TEST(SimpleCallback) {
   1084   TestSimpleCallback(SimpleCallback);
   1085 }
   1086 
   1087 
   1088 template<typename T>
   1089 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
   1090 
   1091 // constant return values
   1092 static int32_t fast_return_value_int32 = 471;
   1093 static uint32_t fast_return_value_uint32 = 571;
   1094 static const double kFastReturnValueDouble = 2.7;
   1095 // variable return values
   1096 static bool fast_return_value_bool = false;
   1097 enum ReturnValueOddball {
   1098   kNullReturnValue,
   1099   kUndefinedReturnValue,
   1100   kEmptyStringReturnValue
   1101 };
   1102 static ReturnValueOddball fast_return_value_void;
   1103 static bool fast_return_value_object_is_empty = false;
   1104 
   1105 // Helper function to avoid compiler error: insufficient contextual information
   1106 // to determine type when applying FUNCTION_ADDR to a template function.
   1107 static i::Address address_of(v8::FunctionCallback callback) {
   1108   return FUNCTION_ADDR(callback);
   1109 }
   1110 
   1111 template<>
   1112 void FastReturnValueCallback<int32_t>(
   1113     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1114   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
   1115   info.GetReturnValue().Set(fast_return_value_int32);
   1116 }
   1117 
   1118 template<>
   1119 void FastReturnValueCallback<uint32_t>(
   1120     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1121   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
   1122   info.GetReturnValue().Set(fast_return_value_uint32);
   1123 }
   1124 
   1125 template<>
   1126 void FastReturnValueCallback<double>(
   1127     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1128   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
   1129   info.GetReturnValue().Set(kFastReturnValueDouble);
   1130 }
   1131 
   1132 template<>
   1133 void FastReturnValueCallback<bool>(
   1134     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1135   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
   1136   info.GetReturnValue().Set(fast_return_value_bool);
   1137 }
   1138 
   1139 template<>
   1140 void FastReturnValueCallback<void>(
   1141     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1142   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
   1143   switch (fast_return_value_void) {
   1144     case kNullReturnValue:
   1145       info.GetReturnValue().SetNull();
   1146       break;
   1147     case kUndefinedReturnValue:
   1148       info.GetReturnValue().SetUndefined();
   1149       break;
   1150     case kEmptyStringReturnValue:
   1151       info.GetReturnValue().SetEmptyString();
   1152       break;
   1153   }
   1154 }
   1155 
   1156 template<>
   1157 void FastReturnValueCallback<Object>(
   1158     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1159   v8::Handle<v8::Object> object;
   1160   if (!fast_return_value_object_is_empty) {
   1161     object = Object::New(info.GetIsolate());
   1162   }
   1163   info.GetReturnValue().Set(object);
   1164 }
   1165 
   1166 template<typename T>
   1167 Handle<Value> TestFastReturnValues() {
   1168   LocalContext env;
   1169   v8::Isolate* isolate = env->GetIsolate();
   1170   v8::EscapableHandleScope scope(isolate);
   1171   v8::Handle<v8::ObjectTemplate> object_template =
   1172       v8::ObjectTemplate::New(isolate);
   1173   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
   1174   object_template->Set(isolate, "callback",
   1175                        v8::FunctionTemplate::New(isolate, callback));
   1176   v8::Local<v8::Object> object = object_template->NewInstance();
   1177   (*env)->Global()->Set(v8_str("callback_object"), object);
   1178   return scope.Escape(CompileRun("callback_object.callback()"));
   1179 }
   1180 
   1181 
   1182 THREADED_PROFILED_TEST(FastReturnValues) {
   1183   LocalContext env;
   1184   v8::HandleScope scope(CcTest::isolate());
   1185   v8::Handle<v8::Value> value;
   1186   // check int32_t and uint32_t
   1187   int32_t int_values[] = {
   1188       0, 234, -723,
   1189       i::Smi::kMinValue, i::Smi::kMaxValue
   1190   };
   1191   for (size_t i = 0; i < arraysize(int_values); i++) {
   1192     for (int modifier = -1; modifier <= 1; modifier++) {
   1193       int int_value = int_values[i] + modifier;
   1194       // check int32_t
   1195       fast_return_value_int32 = int_value;
   1196       value = TestFastReturnValues<int32_t>();
   1197       CHECK(value->IsInt32());
   1198       CHECK(fast_return_value_int32 == value->Int32Value());
   1199       // check uint32_t
   1200       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
   1201       value = TestFastReturnValues<uint32_t>();
   1202       CHECK(value->IsUint32());
   1203       CHECK(fast_return_value_uint32 == value->Uint32Value());
   1204     }
   1205   }
   1206   // check double
   1207   value = TestFastReturnValues<double>();
   1208   CHECK(value->IsNumber());
   1209   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
   1210   // check bool values
   1211   for (int i = 0; i < 2; i++) {
   1212     fast_return_value_bool = i == 0;
   1213     value = TestFastReturnValues<bool>();
   1214     CHECK(value->IsBoolean());
   1215     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
   1216   }
   1217   // check oddballs
   1218   ReturnValueOddball oddballs[] = {
   1219       kNullReturnValue,
   1220       kUndefinedReturnValue,
   1221       kEmptyStringReturnValue
   1222   };
   1223   for (size_t i = 0; i < arraysize(oddballs); i++) {
   1224     fast_return_value_void = oddballs[i];
   1225     value = TestFastReturnValues<void>();
   1226     switch (fast_return_value_void) {
   1227       case kNullReturnValue:
   1228         CHECK(value->IsNull());
   1229         break;
   1230       case kUndefinedReturnValue:
   1231         CHECK(value->IsUndefined());
   1232         break;
   1233       case kEmptyStringReturnValue:
   1234         CHECK(value->IsString());
   1235         CHECK_EQ(0, v8::String::Cast(*value)->Length());
   1236         break;
   1237     }
   1238   }
   1239   // check handles
   1240   fast_return_value_object_is_empty = false;
   1241   value = TestFastReturnValues<Object>();
   1242   CHECK(value->IsObject());
   1243   fast_return_value_object_is_empty = true;
   1244   value = TestFastReturnValues<Object>();
   1245   CHECK(value->IsUndefined());
   1246 }
   1247 
   1248 
   1249 THREADED_TEST(FunctionTemplateSetLength) {
   1250   LocalContext env;
   1251   v8::Isolate* isolate = env->GetIsolate();
   1252   v8::HandleScope scope(isolate);
   1253   {
   1254     Local<v8::FunctionTemplate> fun_templ =
   1255         v8::FunctionTemplate::New(isolate,
   1256                                   handle_callback,
   1257                                   Handle<v8::Value>(),
   1258                                   Handle<v8::Signature>(),
   1259                                   23);
   1260     Local<Function> fun = fun_templ->GetFunction();
   1261     env->Global()->Set(v8_str("obj"), fun);
   1262     Local<Script> script = v8_compile("obj.length");
   1263     CHECK_EQ(23, script->Run()->Int32Value());
   1264   }
   1265   {
   1266     Local<v8::FunctionTemplate> fun_templ =
   1267         v8::FunctionTemplate::New(isolate, handle_callback);
   1268     fun_templ->SetLength(22);
   1269     Local<Function> fun = fun_templ->GetFunction();
   1270     env->Global()->Set(v8_str("obj"), fun);
   1271     Local<Script> script = v8_compile("obj.length");
   1272     CHECK_EQ(22, script->Run()->Int32Value());
   1273   }
   1274   {
   1275     // Without setting length it defaults to 0.
   1276     Local<v8::FunctionTemplate> fun_templ =
   1277         v8::FunctionTemplate::New(isolate, handle_callback);
   1278     Local<Function> fun = fun_templ->GetFunction();
   1279     env->Global()->Set(v8_str("obj"), fun);
   1280     Local<Script> script = v8_compile("obj.length");
   1281     CHECK_EQ(0, script->Run()->Int32Value());
   1282   }
   1283 }
   1284 
   1285 
   1286 static void* expected_ptr;
   1287 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1288   void* ptr = v8::External::Cast(*args.Data())->Value();
   1289   CHECK_EQ(expected_ptr, ptr);
   1290   args.GetReturnValue().Set(true);
   1291 }
   1292 
   1293 
   1294 static void TestExternalPointerWrapping() {
   1295   LocalContext env;
   1296   v8::Isolate* isolate = env->GetIsolate();
   1297   v8::HandleScope scope(isolate);
   1298 
   1299   v8::Handle<v8::Value> data =
   1300       v8::External::New(isolate, expected_ptr);
   1301 
   1302   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   1303   obj->Set(v8_str("func"),
   1304            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
   1305   env->Global()->Set(v8_str("obj"), obj);
   1306 
   1307   CHECK(CompileRun(
   1308         "function foo() {\n"
   1309         "  for (var i = 0; i < 13; i++) obj.func();\n"
   1310         "}\n"
   1311         "foo(), true")->BooleanValue());
   1312 }
   1313 
   1314 
   1315 THREADED_TEST(ExternalWrap) {
   1316   // Check heap allocated object.
   1317   int* ptr = new int;
   1318   expected_ptr = ptr;
   1319   TestExternalPointerWrapping();
   1320   delete ptr;
   1321 
   1322   // Check stack allocated object.
   1323   int foo;
   1324   expected_ptr = &foo;
   1325   TestExternalPointerWrapping();
   1326 
   1327   // Check not aligned addresses.
   1328   const int n = 100;
   1329   char* s = new char[n];
   1330   for (int i = 0; i < n; i++) {
   1331     expected_ptr = s + i;
   1332     TestExternalPointerWrapping();
   1333   }
   1334 
   1335   delete[] s;
   1336 
   1337   // Check several invalid addresses.
   1338   expected_ptr = reinterpret_cast<void*>(1);
   1339   TestExternalPointerWrapping();
   1340 
   1341   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
   1342   TestExternalPointerWrapping();
   1343 
   1344   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
   1345   TestExternalPointerWrapping();
   1346 
   1347 #if defined(V8_HOST_ARCH_X64)
   1348   // Check a value with a leading 1 bit in x64 Smi encoding.
   1349   expected_ptr = reinterpret_cast<void*>(0x400000000);
   1350   TestExternalPointerWrapping();
   1351 
   1352   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
   1353   TestExternalPointerWrapping();
   1354 
   1355   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
   1356   TestExternalPointerWrapping();
   1357 #endif
   1358 }
   1359 
   1360 
   1361 THREADED_TEST(FindInstanceInPrototypeChain) {
   1362   LocalContext env;
   1363   v8::Isolate* isolate = env->GetIsolate();
   1364   v8::HandleScope scope(isolate);
   1365 
   1366   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
   1367   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
   1368   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
   1369   derived->Inherit(base);
   1370 
   1371   Local<v8::Function> base_function = base->GetFunction();
   1372   Local<v8::Function> derived_function = derived->GetFunction();
   1373   Local<v8::Function> other_function = other->GetFunction();
   1374 
   1375   Local<v8::Object> base_instance = base_function->NewInstance();
   1376   Local<v8::Object> derived_instance = derived_function->NewInstance();
   1377   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
   1378   Local<v8::Object> other_instance = other_function->NewInstance();
   1379   derived_instance2->Set(v8_str("__proto__"), derived_instance);
   1380   other_instance->Set(v8_str("__proto__"), derived_instance2);
   1381 
   1382   // base_instance is only an instance of base.
   1383   CHECK_EQ(base_instance,
   1384            base_instance->FindInstanceInPrototypeChain(base));
   1385   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
   1386   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
   1387 
   1388   // derived_instance is an instance of base and derived.
   1389   CHECK_EQ(derived_instance,
   1390            derived_instance->FindInstanceInPrototypeChain(base));
   1391   CHECK_EQ(derived_instance,
   1392            derived_instance->FindInstanceInPrototypeChain(derived));
   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_EQ(derived_instance2,
   1401            other_instance->FindInstanceInPrototypeChain(base));
   1402   CHECK_EQ(derived_instance2,
   1403            other_instance->FindInstanceInPrototypeChain(derived));
   1404   CHECK_EQ(other_instance,
   1405            other_instance->FindInstanceInPrototypeChain(other));
   1406 }
   1407 
   1408 
   1409 THREADED_TEST(TinyInteger) {
   1410   LocalContext env;
   1411   v8::Isolate* isolate = env->GetIsolate();
   1412   v8::HandleScope scope(isolate);
   1413 
   1414   int32_t value = 239;
   1415   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1416   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1417 
   1418   value_obj = v8::Integer::New(isolate, value);
   1419   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1420 }
   1421 
   1422 
   1423 THREADED_TEST(BigSmiInteger) {
   1424   LocalContext env;
   1425   v8::HandleScope scope(env->GetIsolate());
   1426   v8::Isolate* isolate = CcTest::isolate();
   1427 
   1428   int32_t value = i::Smi::kMaxValue;
   1429   // We cannot add one to a Smi::kMaxValue without wrapping.
   1430   if (i::SmiValuesAre31Bits()) {
   1431     CHECK(i::Smi::IsValid(value));
   1432     CHECK(!i::Smi::IsValid(value + 1));
   1433 
   1434     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1435     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1436 
   1437     value_obj = v8::Integer::New(isolate, value);
   1438     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1439   }
   1440 }
   1441 
   1442 
   1443 THREADED_TEST(BigInteger) {
   1444   LocalContext env;
   1445   v8::HandleScope scope(env->GetIsolate());
   1446   v8::Isolate* isolate = CcTest::isolate();
   1447 
   1448   // We cannot add one to a Smi::kMaxValue without wrapping.
   1449   if (i::SmiValuesAre31Bits()) {
   1450     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
   1451     // The code will not be run in that case, due to the "if" guard.
   1452     int32_t value =
   1453         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
   1454     CHECK(value > i::Smi::kMaxValue);
   1455     CHECK(!i::Smi::IsValid(value));
   1456 
   1457     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1458     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1459 
   1460     value_obj = v8::Integer::New(isolate, value);
   1461     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1462   }
   1463 }
   1464 
   1465 
   1466 THREADED_TEST(TinyUnsignedInteger) {
   1467   LocalContext env;
   1468   v8::HandleScope scope(env->GetIsolate());
   1469   v8::Isolate* isolate = CcTest::isolate();
   1470 
   1471   uint32_t value = 239;
   1472 
   1473   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1474   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1475 
   1476   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1477   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1478 }
   1479 
   1480 
   1481 THREADED_TEST(BigUnsignedSmiInteger) {
   1482   LocalContext env;
   1483   v8::HandleScope scope(env->GetIsolate());
   1484   v8::Isolate* isolate = CcTest::isolate();
   1485 
   1486   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
   1487   CHECK(i::Smi::IsValid(value));
   1488   CHECK(!i::Smi::IsValid(value + 1));
   1489 
   1490   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1491   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1492 
   1493   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1494   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1495 }
   1496 
   1497 
   1498 THREADED_TEST(BigUnsignedInteger) {
   1499   LocalContext env;
   1500   v8::HandleScope scope(env->GetIsolate());
   1501   v8::Isolate* isolate = CcTest::isolate();
   1502 
   1503   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
   1504   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
   1505   CHECK(!i::Smi::IsValid(value));
   1506 
   1507   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1508   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1509 
   1510   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1511   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1512 }
   1513 
   1514 
   1515 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
   1516   LocalContext env;
   1517   v8::HandleScope scope(env->GetIsolate());
   1518   v8::Isolate* isolate = CcTest::isolate();
   1519 
   1520   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
   1521   uint32_t value = INT32_MAX_AS_UINT + 1;
   1522   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
   1523 
   1524   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1525   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1526 
   1527   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1528   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1529 }
   1530 
   1531 
   1532 THREADED_TEST(IsNativeError) {
   1533   LocalContext env;
   1534   v8::HandleScope scope(env->GetIsolate());
   1535   v8::Handle<Value> syntax_error = CompileRun(
   1536       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
   1537   CHECK(syntax_error->IsNativeError());
   1538   v8::Handle<Value> not_error = CompileRun("{a:42}");
   1539   CHECK(!not_error->IsNativeError());
   1540   v8::Handle<Value> not_object = CompileRun("42");
   1541   CHECK(!not_object->IsNativeError());
   1542 }
   1543 
   1544 
   1545 THREADED_TEST(ArgumentsObject) {
   1546   LocalContext env;
   1547   v8::HandleScope scope(env->GetIsolate());
   1548   v8::Handle<Value> arguments_object =
   1549       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
   1550   CHECK(arguments_object->IsArgumentsObject());
   1551   v8::Handle<Value> array = CompileRun("[1,2,3]");
   1552   CHECK(!array->IsArgumentsObject());
   1553   v8::Handle<Value> object = CompileRun("{a:42}");
   1554   CHECK(!object->IsArgumentsObject());
   1555 }
   1556 
   1557 
   1558 THREADED_TEST(IsMapOrSet) {
   1559   LocalContext env;
   1560   v8::HandleScope scope(env->GetIsolate());
   1561   v8::Handle<Value> map = CompileRun("new Map()");
   1562   v8::Handle<Value> set = CompileRun("new Set()");
   1563   v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
   1564   v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
   1565   CHECK(map->IsMap());
   1566   CHECK(set->IsSet());
   1567   CHECK(weak_map->IsWeakMap());
   1568   CHECK(weak_set->IsWeakSet());
   1569 
   1570   CHECK(!map->IsSet());
   1571   CHECK(!map->IsWeakMap());
   1572   CHECK(!map->IsWeakSet());
   1573 
   1574   CHECK(!set->IsMap());
   1575   CHECK(!set->IsWeakMap());
   1576   CHECK(!set->IsWeakSet());
   1577 
   1578   CHECK(!weak_map->IsMap());
   1579   CHECK(!weak_map->IsSet());
   1580   CHECK(!weak_map->IsWeakSet());
   1581 
   1582   CHECK(!weak_set->IsMap());
   1583   CHECK(!weak_set->IsSet());
   1584   CHECK(!weak_set->IsWeakMap());
   1585 
   1586   v8::Handle<Value> object = CompileRun("{a:42}");
   1587   CHECK(!object->IsMap());
   1588   CHECK(!object->IsSet());
   1589   CHECK(!object->IsWeakMap());
   1590   CHECK(!object->IsWeakSet());
   1591 }
   1592 
   1593 
   1594 THREADED_TEST(StringObject) {
   1595   LocalContext env;
   1596   v8::HandleScope scope(env->GetIsolate());
   1597   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
   1598   CHECK(boxed_string->IsStringObject());
   1599   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
   1600   CHECK(!unboxed_string->IsStringObject());
   1601   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
   1602   CHECK(!boxed_not_string->IsStringObject());
   1603   v8::Handle<Value> not_object = CompileRun("0");
   1604   CHECK(!not_object->IsStringObject());
   1605   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
   1606   CHECK(!as_boxed.IsEmpty());
   1607   Local<v8::String> the_string = as_boxed->ValueOf();
   1608   CHECK(!the_string.IsEmpty());
   1609   ExpectObject("\"test\"", the_string);
   1610   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
   1611   CHECK(new_boxed_string->IsStringObject());
   1612   as_boxed = new_boxed_string.As<v8::StringObject>();
   1613   the_string = as_boxed->ValueOf();
   1614   CHECK(!the_string.IsEmpty());
   1615   ExpectObject("\"test\"", the_string);
   1616 }
   1617 
   1618 
   1619 THREADED_TEST(NumberObject) {
   1620   LocalContext env;
   1621   v8::HandleScope scope(env->GetIsolate());
   1622   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
   1623   CHECK(boxed_number->IsNumberObject());
   1624   v8::Handle<Value> unboxed_number = CompileRun("42");
   1625   CHECK(!unboxed_number->IsNumberObject());
   1626   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
   1627   CHECK(!boxed_not_number->IsNumberObject());
   1628   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
   1629   CHECK(!as_boxed.IsEmpty());
   1630   double the_number = as_boxed->ValueOf();
   1631   CHECK_EQ(42.0, the_number);
   1632   v8::Handle<v8::Value> new_boxed_number =
   1633       v8::NumberObject::New(env->GetIsolate(), 43);
   1634   CHECK(new_boxed_number->IsNumberObject());
   1635   as_boxed = new_boxed_number.As<v8::NumberObject>();
   1636   the_number = as_boxed->ValueOf();
   1637   CHECK_EQ(43.0, the_number);
   1638 }
   1639 
   1640 
   1641 THREADED_TEST(BooleanObject) {
   1642   LocalContext env;
   1643   v8::HandleScope scope(env->GetIsolate());
   1644   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
   1645   CHECK(boxed_boolean->IsBooleanObject());
   1646   v8::Handle<Value> unboxed_boolean = CompileRun("true");
   1647   CHECK(!unboxed_boolean->IsBooleanObject());
   1648   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
   1649   CHECK(!boxed_not_boolean->IsBooleanObject());
   1650   v8::Handle<v8::BooleanObject> as_boxed =
   1651       boxed_boolean.As<v8::BooleanObject>();
   1652   CHECK(!as_boxed.IsEmpty());
   1653   bool the_boolean = as_boxed->ValueOf();
   1654   CHECK_EQ(true, the_boolean);
   1655   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
   1656   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
   1657   CHECK(boxed_true->IsBooleanObject());
   1658   CHECK(boxed_false->IsBooleanObject());
   1659   as_boxed = boxed_true.As<v8::BooleanObject>();
   1660   CHECK_EQ(true, as_boxed->ValueOf());
   1661   as_boxed = boxed_false.As<v8::BooleanObject>();
   1662   CHECK_EQ(false, as_boxed->ValueOf());
   1663 }
   1664 
   1665 
   1666 THREADED_TEST(PrimitiveAndWrappedBooleans) {
   1667   LocalContext env;
   1668   v8::HandleScope scope(env->GetIsolate());
   1669 
   1670   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
   1671   CHECK(primitive_false->IsBoolean());
   1672   CHECK(!primitive_false->IsBooleanObject());
   1673   CHECK(!primitive_false->BooleanValue());
   1674   CHECK(!primitive_false->IsTrue());
   1675   CHECK(primitive_false->IsFalse());
   1676 
   1677   Local<Value> false_value = BooleanObject::New(false);
   1678   CHECK(!false_value->IsBoolean());
   1679   CHECK(false_value->IsBooleanObject());
   1680   CHECK(false_value->BooleanValue());
   1681   CHECK(!false_value->IsTrue());
   1682   CHECK(!false_value->IsFalse());
   1683 
   1684   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
   1685   CHECK(!false_boolean_object->IsBoolean());
   1686   CHECK(false_boolean_object->IsBooleanObject());
   1687   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
   1688   // CHECK(false_boolean_object->BooleanValue());
   1689   CHECK(!false_boolean_object->ValueOf());
   1690   CHECK(!false_boolean_object->IsTrue());
   1691   CHECK(!false_boolean_object->IsFalse());
   1692 
   1693   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
   1694   CHECK(primitive_true->IsBoolean());
   1695   CHECK(!primitive_true->IsBooleanObject());
   1696   CHECK(primitive_true->BooleanValue());
   1697   CHECK(primitive_true->IsTrue());
   1698   CHECK(!primitive_true->IsFalse());
   1699 
   1700   Local<Value> true_value = BooleanObject::New(true);
   1701   CHECK(!true_value->IsBoolean());
   1702   CHECK(true_value->IsBooleanObject());
   1703   CHECK(true_value->BooleanValue());
   1704   CHECK(!true_value->IsTrue());
   1705   CHECK(!true_value->IsFalse());
   1706 
   1707   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
   1708   CHECK(!true_boolean_object->IsBoolean());
   1709   CHECK(true_boolean_object->IsBooleanObject());
   1710   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
   1711   // CHECK(true_boolean_object->BooleanValue());
   1712   CHECK(true_boolean_object->ValueOf());
   1713   CHECK(!true_boolean_object->IsTrue());
   1714   CHECK(!true_boolean_object->IsFalse());
   1715 }
   1716 
   1717 
   1718 THREADED_TEST(Number) {
   1719   LocalContext env;
   1720   v8::HandleScope scope(env->GetIsolate());
   1721   double PI = 3.1415926;
   1722   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
   1723   CHECK_EQ(PI, pi_obj->NumberValue());
   1724 }
   1725 
   1726 
   1727 THREADED_TEST(ToNumber) {
   1728   LocalContext env;
   1729   v8::Isolate* isolate = CcTest::isolate();
   1730   v8::HandleScope scope(isolate);
   1731   Local<String> str = v8_str("3.1415926");
   1732   CHECK_EQ(3.1415926, str->NumberValue());
   1733   v8::Handle<v8::Boolean> t = v8::True(isolate);
   1734   CHECK_EQ(1.0, t->NumberValue());
   1735   v8::Handle<v8::Boolean> f = v8::False(isolate);
   1736   CHECK_EQ(0.0, f->NumberValue());
   1737 }
   1738 
   1739 
   1740 THREADED_TEST(Date) {
   1741   LocalContext env;
   1742   v8::HandleScope scope(env->GetIsolate());
   1743   double PI = 3.1415926;
   1744   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
   1745   CHECK_EQ(3.0, date->NumberValue());
   1746   date.As<v8::Date>()->Set(v8_str("property"),
   1747                            v8::Integer::New(env->GetIsolate(), 42));
   1748   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
   1749 }
   1750 
   1751 
   1752 THREADED_TEST(Boolean) {
   1753   LocalContext env;
   1754   v8::Isolate* isolate = env->GetIsolate();
   1755   v8::HandleScope scope(isolate);
   1756   v8::Handle<v8::Boolean> t = v8::True(isolate);
   1757   CHECK(t->Value());
   1758   v8::Handle<v8::Boolean> f = v8::False(isolate);
   1759   CHECK(!f->Value());
   1760   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
   1761   CHECK(!u->BooleanValue());
   1762   v8::Handle<v8::Primitive> n = v8::Null(isolate);
   1763   CHECK(!n->BooleanValue());
   1764   v8::Handle<String> str1 = v8_str("");
   1765   CHECK(!str1->BooleanValue());
   1766   v8::Handle<String> str2 = v8_str("x");
   1767   CHECK(str2->BooleanValue());
   1768   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
   1769   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
   1770   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
   1771   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
   1772   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
   1773 }
   1774 
   1775 
   1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1777   ApiTestFuzzer::Fuzz();
   1778   args.GetReturnValue().Set(v8_num(13.4));
   1779 }
   1780 
   1781 
   1782 static void GetM(Local<String> name,
   1783                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   1784   ApiTestFuzzer::Fuzz();
   1785   info.GetReturnValue().Set(v8_num(876));
   1786 }
   1787 
   1788 
   1789 THREADED_TEST(GlobalPrototype) {
   1790   v8::Isolate* isolate = CcTest::isolate();
   1791   v8::HandleScope scope(isolate);
   1792   v8::Handle<v8::FunctionTemplate> func_templ =
   1793       v8::FunctionTemplate::New(isolate);
   1794   func_templ->PrototypeTemplate()->Set(
   1795       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
   1796   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
   1797   templ->Set(isolate, "x", v8_num(200));
   1798   templ->SetAccessor(v8_str("m"), GetM);
   1799   LocalContext env(0, templ);
   1800   v8::Handle<Script> script(v8_compile("dummy()"));
   1801   v8::Handle<Value> result(script->Run());
   1802   CHECK_EQ(13.4, result->NumberValue());
   1803   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
   1804   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
   1805 }
   1806 
   1807 
   1808 THREADED_TEST(ObjectTemplate) {
   1809   v8::Isolate* isolate = CcTest::isolate();
   1810   v8::HandleScope scope(isolate);
   1811   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
   1812   templ1->Set(isolate, "x", v8_num(10));
   1813   templ1->Set(isolate, "y", v8_num(13));
   1814   LocalContext env;
   1815   Local<v8::Object> instance1 = templ1->NewInstance();
   1816   env->Global()->Set(v8_str("p"), instance1);
   1817   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
   1818   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
   1819   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
   1820   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
   1821   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
   1822   templ2->Set(isolate, "a", v8_num(12));
   1823   templ2->Set(isolate, "b", templ1);
   1824   Local<v8::Object> instance2 = templ2->NewInstance();
   1825   env->Global()->Set(v8_str("q"), instance2);
   1826   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
   1827   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
   1828   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
   1829   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
   1830 }
   1831 
   1832 
   1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1834   ApiTestFuzzer::Fuzz();
   1835   args.GetReturnValue().Set(v8_num(17.2));
   1836 }
   1837 
   1838 
   1839 static void GetKnurd(Local<String> property,
   1840                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   1841   ApiTestFuzzer::Fuzz();
   1842   info.GetReturnValue().Set(v8_num(15.2));
   1843 }
   1844 
   1845 
   1846 THREADED_TEST(DescriptorInheritance) {
   1847   v8::Isolate* isolate = CcTest::isolate();
   1848   v8::HandleScope scope(isolate);
   1849   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
   1850   super->PrototypeTemplate()->Set(isolate, "flabby",
   1851                                   v8::FunctionTemplate::New(isolate,
   1852                                                             GetFlabby));
   1853   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
   1854 
   1855   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
   1856 
   1857   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
   1858   base1->Inherit(super);
   1859   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
   1860 
   1861   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
   1862   base2->Inherit(super);
   1863   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
   1864 
   1865   LocalContext env;
   1866 
   1867   env->Global()->Set(v8_str("s"), super->GetFunction());
   1868   env->Global()->Set(v8_str("base1"), base1->GetFunction());
   1869   env->Global()->Set(v8_str("base2"), base2->GetFunction());
   1870 
   1871   // Checks right __proto__ chain.
   1872   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
   1873   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
   1874 
   1875   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
   1876 
   1877   // Instance accessor should not be visible on function object or its prototype
   1878   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
   1879   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
   1880   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
   1881 
   1882   env->Global()->Set(v8_str("obj"),
   1883                      base1->GetFunction()->NewInstance());
   1884   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
   1885   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
   1886   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
   1887   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
   1888   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
   1889 
   1890   env->Global()->Set(v8_str("obj2"),
   1891                      base2->GetFunction()->NewInstance());
   1892   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
   1893   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
   1894   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
   1895   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
   1896   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
   1897 
   1898   // base1 and base2 cannot cross reference to each's prototype
   1899   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
   1900   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
   1901 }
   1902 
   1903 
   1904 int echo_named_call_count;
   1905 
   1906 
   1907 static void EchoNamedProperty(Local<String> name,
   1908                               const v8::PropertyCallbackInfo<v8::Value>& info) {
   1909   ApiTestFuzzer::Fuzz();
   1910   CHECK_EQ(v8_str("data"), info.Data());
   1911   echo_named_call_count++;
   1912   info.GetReturnValue().Set(name);
   1913 }
   1914 
   1915 
   1916 // Helper functions for Interceptor/Accessor interaction tests
   1917 
   1918 void SimpleAccessorGetter(Local<String> name,
   1919                           const v8::PropertyCallbackInfo<v8::Value>& info) {
   1920   Handle<Object> self = Handle<Object>::Cast(info.This());
   1921   info.GetReturnValue().Set(
   1922       self->Get(String::Concat(v8_str("accessor_"), name)));
   1923 }
   1924 
   1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
   1926                           const v8::PropertyCallbackInfo<void>& info) {
   1927   Handle<Object> self = Handle<Object>::Cast(info.This());
   1928   self->Set(String::Concat(v8_str("accessor_"), name), value);
   1929 }
   1930 
   1931 void SymbolAccessorGetter(Local<Name> name,
   1932                           const v8::PropertyCallbackInfo<v8::Value>& info) {
   1933   CHECK(name->IsSymbol());
   1934   Local<Symbol> sym = Local<Symbol>::Cast(name);
   1935   if (sym->Name()->IsUndefined())
   1936     return;
   1937   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
   1938 }
   1939 
   1940 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
   1941                           const v8::PropertyCallbackInfo<void>& info) {
   1942   CHECK(name->IsSymbol());
   1943   Local<Symbol> sym = Local<Symbol>::Cast(name);
   1944   if (sym->Name()->IsUndefined())
   1945     return;
   1946   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
   1947 }
   1948 
   1949 void EmptyInterceptorGetter(Local<String> name,
   1950                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   1951 }
   1952 
   1953 void EmptyInterceptorSetter(Local<String> name,
   1954                             Local<Value> value,
   1955                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   1956 }
   1957 
   1958 void InterceptorGetter(Local<String> name,
   1959                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   1960   // Intercept names that start with 'interceptor_'.
   1961   String::Utf8Value utf8(name);
   1962   char* name_str = *utf8;
   1963   char prefix[] = "interceptor_";
   1964   int i;
   1965   for (i = 0; name_str[i] && prefix[i]; ++i) {
   1966     if (name_str[i] != prefix[i]) return;
   1967   }
   1968   Handle<Object> self = Handle<Object>::Cast(info.This());
   1969   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
   1970 }
   1971 
   1972 void InterceptorSetter(Local<String> name,
   1973                        Local<Value> value,
   1974                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   1975   // Intercept accesses that set certain integer values, for which the name does
   1976   // not start with 'accessor_'.
   1977   String::Utf8Value utf8(name);
   1978   char* name_str = *utf8;
   1979   char prefix[] = "accessor_";
   1980   int i;
   1981   for (i = 0; name_str[i] && prefix[i]; ++i) {
   1982     if (name_str[i] != prefix[i]) break;
   1983   }
   1984   if (!prefix[i]) return;
   1985 
   1986   if (value->IsInt32() && value->Int32Value() < 10000) {
   1987     Handle<Object> self = Handle<Object>::Cast(info.This());
   1988     self->SetHiddenValue(name, value);
   1989     info.GetReturnValue().Set(value);
   1990   }
   1991 }
   1992 
   1993 void AddAccessor(Handle<FunctionTemplate> templ,
   1994                  Handle<String> name,
   1995                  v8::AccessorGetterCallback getter,
   1996                  v8::AccessorSetterCallback setter) {
   1997   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
   1998 }
   1999 
   2000 void AddInterceptor(Handle<FunctionTemplate> templ,
   2001                     v8::NamedPropertyGetterCallback getter,
   2002                     v8::NamedPropertySetterCallback setter) {
   2003   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
   2004 }
   2005 
   2006 
   2007 void AddAccessor(Handle<FunctionTemplate> templ,
   2008                  Handle<Name> name,
   2009                  v8::AccessorNameGetterCallback getter,
   2010                  v8::AccessorNameSetterCallback setter) {
   2011   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
   2012 }
   2013 
   2014 
   2015 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   2016   v8::HandleScope scope(CcTest::isolate());
   2017   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2018   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2019   child->Inherit(parent);
   2020   AddAccessor(parent, v8_str("age"),
   2021               SimpleAccessorGetter, SimpleAccessorSetter);
   2022   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   2023   LocalContext env;
   2024   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2025   CompileRun("var child = new Child;"
   2026              "child.age = 10;");
   2027   ExpectBoolean("child.hasOwnProperty('age')", false);
   2028   ExpectInt32("child.age", 10);
   2029   ExpectInt32("child.accessor_age", 10);
   2030 }
   2031 
   2032 
   2033 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
   2034   v8::Isolate* isolate = CcTest::isolate();
   2035   v8::HandleScope scope(isolate);
   2036   LocalContext env;
   2037   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
   2038   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
   2039   CHECK(a->map()->instance_descriptors()->IsFixedArray());
   2040   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
   2041   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
   2042   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
   2043   // But we should still have an ExecutableAccessorInfo.
   2044   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   2045   i::LookupResult lookup(i_isolate);
   2046   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
   2047   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
   2048   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
   2049   CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
   2050 }
   2051 
   2052 
   2053 THREADED_TEST(EmptyInterceptorBreakTransitions) {
   2054   v8::HandleScope scope(CcTest::isolate());
   2055   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2056   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
   2057   LocalContext env;
   2058   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
   2059   CompileRun("var o1 = new Constructor;"
   2060              "o1.a = 1;"  // Ensure a and x share the descriptor array.
   2061              "Object.defineProperty(o1, 'x', {value: 10});");
   2062   CompileRun("var o2 = new Constructor;"
   2063              "o2.a = 1;"
   2064              "Object.defineProperty(o2, 'x', {value: 10});");
   2065 }
   2066 
   2067 
   2068 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
   2069   v8::Isolate* isolate = CcTest::isolate();
   2070   v8::HandleScope scope(isolate);
   2071   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
   2072   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
   2073   child->Inherit(parent);
   2074   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   2075   LocalContext env;
   2076   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2077   CompileRun("var child = new Child;"
   2078              "var parent = child.__proto__;"
   2079              "Object.defineProperty(parent, 'age', "
   2080              "  {get: function(){ return this.accessor_age; }, "
   2081              "   set: function(v){ this.accessor_age = v; }, "
   2082              "   enumerable: true, configurable: true});"
   2083              "child.age = 10;");
   2084   ExpectBoolean("child.hasOwnProperty('age')", false);
   2085   ExpectInt32("child.age", 10);
   2086   ExpectInt32("child.accessor_age", 10);
   2087 }
   2088 
   2089 
   2090 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
   2091   v8::Isolate* isolate = CcTest::isolate();
   2092   v8::HandleScope scope(isolate);
   2093   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
   2094   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
   2095   child->Inherit(parent);
   2096   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   2097   LocalContext env;
   2098   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2099   CompileRun("var child = new Child;"
   2100              "var parent = child.__proto__;"
   2101              "parent.name = 'Alice';");
   2102   ExpectBoolean("child.hasOwnProperty('name')", false);
   2103   ExpectString("child.name", "Alice");
   2104   CompileRun("child.name = 'Bob';");
   2105   ExpectString("child.name", "Bob");
   2106   ExpectBoolean("child.hasOwnProperty('name')", true);
   2107   ExpectString("parent.name", "Alice");
   2108 }
   2109 
   2110 
   2111 THREADED_TEST(SwitchFromInterceptorToAccessor) {
   2112   v8::HandleScope scope(CcTest::isolate());
   2113   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2114   AddAccessor(templ, v8_str("age"),
   2115               SimpleAccessorGetter, SimpleAccessorSetter);
   2116   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2117   LocalContext env;
   2118   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2119   CompileRun("var obj = new Obj;"
   2120              "function setAge(i){ obj.age = i; };"
   2121              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2122   // All i < 10000 go to the interceptor.
   2123   ExpectInt32("obj.interceptor_age", 9999);
   2124   // The last i goes to the accessor.
   2125   ExpectInt32("obj.accessor_age", 10000);
   2126 }
   2127 
   2128 
   2129 THREADED_TEST(SwitchFromAccessorToInterceptor) {
   2130   v8::HandleScope scope(CcTest::isolate());
   2131   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2132   AddAccessor(templ, v8_str("age"),
   2133               SimpleAccessorGetter, SimpleAccessorSetter);
   2134   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2135   LocalContext env;
   2136   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2137   CompileRun("var obj = new Obj;"
   2138              "function setAge(i){ obj.age = i; };"
   2139              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2140   // All i >= 10000 go to the accessor.
   2141   ExpectInt32("obj.accessor_age", 10000);
   2142   // The last i goes to the interceptor.
   2143   ExpectInt32("obj.interceptor_age", 9999);
   2144 }
   2145 
   2146 
   2147 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
   2148   v8::HandleScope scope(CcTest::isolate());
   2149   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2150   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2151   child->Inherit(parent);
   2152   AddAccessor(parent, v8_str("age"),
   2153               SimpleAccessorGetter, SimpleAccessorSetter);
   2154   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2155   LocalContext env;
   2156   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2157   CompileRun("var child = new Child;"
   2158              "function setAge(i){ child.age = i; };"
   2159              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2160   // All i < 10000 go to the interceptor.
   2161   ExpectInt32("child.interceptor_age", 9999);
   2162   // The last i goes to the accessor.
   2163   ExpectInt32("child.accessor_age", 10000);
   2164 }
   2165 
   2166 
   2167 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
   2168   v8::HandleScope scope(CcTest::isolate());
   2169   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2170   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2171   child->Inherit(parent);
   2172   AddAccessor(parent, v8_str("age"),
   2173               SimpleAccessorGetter, SimpleAccessorSetter);
   2174   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2175   LocalContext env;
   2176   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2177   CompileRun("var child = new Child;"
   2178              "function setAge(i){ child.age = i; };"
   2179              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2180   // All i >= 10000 go to the accessor.
   2181   ExpectInt32("child.accessor_age", 10000);
   2182   // The last i goes to the interceptor.
   2183   ExpectInt32("child.interceptor_age", 9999);
   2184 }
   2185 
   2186 
   2187 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
   2188   v8::HandleScope scope(CcTest::isolate());
   2189   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2190   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2191   LocalContext env;
   2192   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2193   CompileRun("var obj = new Obj;"
   2194              "function setter(i) { this.accessor_age = i; };"
   2195              "function getter() { return this.accessor_age; };"
   2196              "function setAge(i) { obj.age = i; };"
   2197              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   2198              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2199   // All i < 10000 go to the interceptor.
   2200   ExpectInt32("obj.interceptor_age", 9999);
   2201   // The last i goes to the JavaScript accessor.
   2202   ExpectInt32("obj.accessor_age", 10000);
   2203   // The installed JavaScript getter is still intact.
   2204   // This last part is a regression test for issue 1651 and relies on the fact
   2205   // that both interceptor and accessor are being installed on the same object.
   2206   ExpectInt32("obj.age", 10000);
   2207   ExpectBoolean("obj.hasOwnProperty('age')", true);
   2208   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
   2209 }
   2210 
   2211 
   2212 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
   2213   v8::HandleScope scope(CcTest::isolate());
   2214   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2215   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2216   LocalContext env;
   2217   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2218   CompileRun("var obj = new Obj;"
   2219              "function setter(i) { this.accessor_age = i; };"
   2220              "function getter() { return this.accessor_age; };"
   2221              "function setAge(i) { obj.age = i; };"
   2222              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   2223              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2224   // All i >= 10000 go to the accessor.
   2225   ExpectInt32("obj.accessor_age", 10000);
   2226   // The last i goes to the interceptor.
   2227   ExpectInt32("obj.interceptor_age", 9999);
   2228   // The installed JavaScript getter is still intact.
   2229   // This last part is a regression test for issue 1651 and relies on the fact
   2230   // that both interceptor and accessor are being installed on the same object.
   2231   ExpectInt32("obj.age", 10000);
   2232   ExpectBoolean("obj.hasOwnProperty('age')", true);
   2233   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
   2234 }
   2235 
   2236 
   2237 THREADED_TEST(SwitchFromInterceptorToProperty) {
   2238   v8::HandleScope scope(CcTest::isolate());
   2239   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2240   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2241   child->Inherit(parent);
   2242   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2243   LocalContext env;
   2244   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2245   CompileRun("var child = new Child;"
   2246              "function setAge(i){ child.age = i; };"
   2247              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2248   // All i < 10000 go to the interceptor.
   2249   ExpectInt32("child.interceptor_age", 9999);
   2250   // The last i goes to child's own property.
   2251   ExpectInt32("child.age", 10000);
   2252 }
   2253 
   2254 
   2255 THREADED_TEST(SwitchFromPropertyToInterceptor) {
   2256   v8::HandleScope scope(CcTest::isolate());
   2257   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2258   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2259   child->Inherit(parent);
   2260   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2261   LocalContext env;
   2262   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2263   CompileRun("var child = new Child;"
   2264              "function setAge(i){ child.age = i; };"
   2265              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2266   // All i >= 10000 go to child's own property.
   2267   ExpectInt32("child.age", 10000);
   2268   // The last i goes to the interceptor.
   2269   ExpectInt32("child.interceptor_age", 9999);
   2270 }
   2271 
   2272 
   2273 THREADED_TEST(NamedPropertyHandlerGetter) {
   2274   echo_named_call_count = 0;
   2275   v8::HandleScope scope(CcTest::isolate());
   2276   v8::Handle<v8::FunctionTemplate> templ =
   2277       v8::FunctionTemplate::New(CcTest::isolate());
   2278   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
   2279                                                      0, 0, 0, 0,
   2280                                                      v8_str("data"));
   2281   LocalContext env;
   2282   env->Global()->Set(v8_str("obj"),
   2283                      templ->GetFunction()->NewInstance());
   2284   CHECK_EQ(echo_named_call_count, 0);
   2285   v8_compile("obj.x")->Run();
   2286   CHECK_EQ(echo_named_call_count, 1);
   2287   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
   2288   v8::Handle<Value> str = CompileRun(code);
   2289   String::Utf8Value value(str);
   2290   CHECK_EQ(*value, "oddlepoddle");
   2291   // Check default behavior
   2292   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
   2293   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
   2294   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
   2295 }
   2296 
   2297 
   2298 int echo_indexed_call_count = 0;
   2299 
   2300 
   2301 static void EchoIndexedProperty(
   2302     uint32_t index,
   2303     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2304   ApiTestFuzzer::Fuzz();
   2305   CHECK_EQ(v8_num(637), info.Data());
   2306   echo_indexed_call_count++;
   2307   info.GetReturnValue().Set(v8_num(index));
   2308 }
   2309 
   2310 
   2311 THREADED_TEST(IndexedPropertyHandlerGetter) {
   2312   v8::Isolate* isolate = CcTest::isolate();
   2313   v8::HandleScope scope(isolate);
   2314   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2315   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
   2316                                                        0, 0, 0, 0,
   2317                                                        v8_num(637));
   2318   LocalContext env;
   2319   env->Global()->Set(v8_str("obj"),
   2320                      templ->GetFunction()->NewInstance());
   2321   Local<Script> script = v8_compile("obj[900]");
   2322   CHECK_EQ(script->Run()->Int32Value(), 900);
   2323 }
   2324 
   2325 
   2326 v8::Handle<v8::Object> bottom;
   2327 
   2328 static void CheckThisIndexedPropertyHandler(
   2329     uint32_t index,
   2330     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2331   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
   2332   ApiTestFuzzer::Fuzz();
   2333   CHECK(info.This()->Equals(bottom));
   2334 }
   2335 
   2336 static void CheckThisNamedPropertyHandler(
   2337     Local<String> name,
   2338     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2339   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
   2340   ApiTestFuzzer::Fuzz();
   2341   CHECK(info.This()->Equals(bottom));
   2342 }
   2343 
   2344 void CheckThisIndexedPropertySetter(
   2345     uint32_t index,
   2346     Local<Value> value,
   2347     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2348   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
   2349   ApiTestFuzzer::Fuzz();
   2350   CHECK(info.This()->Equals(bottom));
   2351 }
   2352 
   2353 
   2354 void CheckThisNamedPropertySetter(
   2355     Local<String> property,
   2356     Local<Value> value,
   2357     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2358   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
   2359   ApiTestFuzzer::Fuzz();
   2360   CHECK(info.This()->Equals(bottom));
   2361 }
   2362 
   2363 void CheckThisIndexedPropertyQuery(
   2364     uint32_t index,
   2365     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   2366   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
   2367   ApiTestFuzzer::Fuzz();
   2368   CHECK(info.This()->Equals(bottom));
   2369 }
   2370 
   2371 
   2372 void CheckThisNamedPropertyQuery(
   2373     Local<String> property,
   2374     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   2375   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
   2376   ApiTestFuzzer::Fuzz();
   2377   CHECK(info.This()->Equals(bottom));
   2378 }
   2379 
   2380 
   2381 void CheckThisIndexedPropertyDeleter(
   2382     uint32_t index,
   2383     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   2384   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
   2385   ApiTestFuzzer::Fuzz();
   2386   CHECK(info.This()->Equals(bottom));
   2387 }
   2388 
   2389 
   2390 void CheckThisNamedPropertyDeleter(
   2391     Local<String> property,
   2392     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   2393   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
   2394   ApiTestFuzzer::Fuzz();
   2395   CHECK(info.This()->Equals(bottom));
   2396 }
   2397 
   2398 
   2399 void CheckThisIndexedPropertyEnumerator(
   2400     const v8::PropertyCallbackInfo<v8::Array>& info) {
   2401   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
   2402   ApiTestFuzzer::Fuzz();
   2403   CHECK(info.This()->Equals(bottom));
   2404 }
   2405 
   2406 
   2407 void CheckThisNamedPropertyEnumerator(
   2408     const v8::PropertyCallbackInfo<v8::Array>& info) {
   2409   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
   2410   ApiTestFuzzer::Fuzz();
   2411   CHECK(info.This()->Equals(bottom));
   2412 }
   2413 
   2414 
   2415 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
   2416   LocalContext env;
   2417   v8::Isolate* isolate = env->GetIsolate();
   2418   v8::HandleScope scope(isolate);
   2419 
   2420   // Set up a prototype chain with three interceptors.
   2421   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2422   templ->InstanceTemplate()->SetIndexedPropertyHandler(
   2423       CheckThisIndexedPropertyHandler,
   2424       CheckThisIndexedPropertySetter,
   2425       CheckThisIndexedPropertyQuery,
   2426       CheckThisIndexedPropertyDeleter,
   2427       CheckThisIndexedPropertyEnumerator);
   2428 
   2429   templ->InstanceTemplate()->SetNamedPropertyHandler(
   2430       CheckThisNamedPropertyHandler,
   2431       CheckThisNamedPropertySetter,
   2432       CheckThisNamedPropertyQuery,
   2433       CheckThisNamedPropertyDeleter,
   2434       CheckThisNamedPropertyEnumerator);
   2435 
   2436   bottom = templ->GetFunction()->NewInstance();
   2437   Local<v8::Object> top = templ->GetFunction()->NewInstance();
   2438   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
   2439 
   2440   bottom->SetPrototype(middle);
   2441   middle->SetPrototype(top);
   2442   env->Global()->Set(v8_str("obj"), bottom);
   2443 
   2444   // Indexed and named get.
   2445   CompileRun("obj[0]");
   2446   CompileRun("obj.x");
   2447 
   2448   // Indexed and named set.
   2449   CompileRun("obj[1] = 42");
   2450   CompileRun("obj.y = 42");
   2451 
   2452   // Indexed and named query.
   2453   CompileRun("0 in obj");
   2454   CompileRun("'x' in obj");
   2455 
   2456   // Indexed and named deleter.
   2457   CompileRun("delete obj[0]");
   2458   CompileRun("delete obj.x");
   2459 
   2460   // Enumerators.
   2461   CompileRun("for (var p in obj) ;");
   2462 }
   2463 
   2464 
   2465 static void PrePropertyHandlerGet(
   2466     Local<String> key,
   2467     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2468   ApiTestFuzzer::Fuzz();
   2469   if (v8_str("pre")->Equals(key)) {
   2470     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
   2471   }
   2472 }
   2473 
   2474 
   2475 static void PrePropertyHandlerQuery(
   2476     Local<String> key,
   2477     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   2478   if (v8_str("pre")->Equals(key)) {
   2479     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
   2480   }
   2481 }
   2482 
   2483 
   2484 THREADED_TEST(PrePropertyHandler) {
   2485   v8::Isolate* isolate = CcTest::isolate();
   2486   v8::HandleScope scope(isolate);
   2487   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
   2488   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
   2489                                                     0,
   2490                                                     PrePropertyHandlerQuery);
   2491   LocalContext env(NULL, desc->InstanceTemplate());
   2492   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
   2493   v8::Handle<Value> result_pre = CompileRun("pre");
   2494   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
   2495   v8::Handle<Value> result_on = CompileRun("on");
   2496   CHECK_EQ(v8_str("Object: on"), result_on);
   2497   v8::Handle<Value> result_post = CompileRun("post");
   2498   CHECK(result_post.IsEmpty());
   2499 }
   2500 
   2501 
   2502 THREADED_TEST(UndefinedIsNotEnumerable) {
   2503   LocalContext env;
   2504   v8::HandleScope scope(env->GetIsolate());
   2505   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
   2506   CHECK(result->IsFalse());
   2507 }
   2508 
   2509 
   2510 v8::Handle<Script> call_recursively_script;
   2511 static const int kTargetRecursionDepth = 200;  // near maximum
   2512 
   2513 
   2514 static void CallScriptRecursivelyCall(
   2515     const v8::FunctionCallbackInfo<v8::Value>& args) {
   2516   ApiTestFuzzer::Fuzz();
   2517   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   2518   if (depth == kTargetRecursionDepth) return;
   2519   args.This()->Set(v8_str("depth"),
   2520                    v8::Integer::New(args.GetIsolate(), depth + 1));
   2521   args.GetReturnValue().Set(call_recursively_script->Run());
   2522 }
   2523 
   2524 
   2525 static void CallFunctionRecursivelyCall(
   2526     const v8::FunctionCallbackInfo<v8::Value>& args) {
   2527   ApiTestFuzzer::Fuzz();
   2528   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   2529   if (depth == kTargetRecursionDepth) {
   2530     printf("[depth = %d]\n", depth);
   2531     return;
   2532   }
   2533   args.This()->Set(v8_str("depth"),
   2534                    v8::Integer::New(args.GetIsolate(), depth + 1));
   2535   v8::Handle<Value> function =
   2536       args.This()->Get(v8_str("callFunctionRecursively"));
   2537   args.GetReturnValue().Set(
   2538       function.As<Function>()->Call(args.This(), 0, NULL));
   2539 }
   2540 
   2541 
   2542 THREADED_TEST(DeepCrossLanguageRecursion) {
   2543   v8::Isolate* isolate = CcTest::isolate();
   2544   v8::HandleScope scope(isolate);
   2545   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
   2546   global->Set(v8_str("callScriptRecursively"),
   2547               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
   2548   global->Set(v8_str("callFunctionRecursively"),
   2549               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
   2550   LocalContext env(NULL, global);
   2551 
   2552   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
   2553   call_recursively_script = v8_compile("callScriptRecursively()");
   2554   call_recursively_script->Run();
   2555   call_recursively_script = v8::Handle<Script>();
   2556 
   2557   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
   2558   CompileRun("callFunctionRecursively()");
   2559 }
   2560 
   2561 
   2562 static void ThrowingPropertyHandlerGet(
   2563     Local<String> key,
   2564     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2565   ApiTestFuzzer::Fuzz();
   2566   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
   2567 }
   2568 
   2569 
   2570 static void ThrowingPropertyHandlerSet(
   2571     Local<String> key,
   2572     Local<Value>,
   2573     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2574   info.GetIsolate()->ThrowException(key);
   2575   info.GetReturnValue().SetUndefined();  // not the same as empty handle
   2576 }
   2577 
   2578 
   2579 THREADED_TEST(CallbackExceptionRegression) {
   2580   v8::Isolate* isolate = CcTest::isolate();
   2581   v8::HandleScope scope(isolate);
   2582   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   2583   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
   2584                                ThrowingPropertyHandlerSet);
   2585   LocalContext env;
   2586   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   2587   v8::Handle<Value> otto = CompileRun(
   2588       "try { with (obj) { otto; } } catch (e) { e; }");
   2589   CHECK_EQ(v8_str("otto"), otto);
   2590   v8::Handle<Value> netto = CompileRun(
   2591       "try { with (obj) { netto = 4; } } catch (e) { e; }");
   2592   CHECK_EQ(v8_str("netto"), netto);
   2593 }
   2594 
   2595 
   2596 THREADED_TEST(FunctionPrototype) {
   2597   v8::Isolate* isolate = CcTest::isolate();
   2598   v8::HandleScope scope(isolate);
   2599   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
   2600   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
   2601   LocalContext env;
   2602   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
   2603   Local<Script> script = v8_compile("Foo.prototype.plak");
   2604   CHECK_EQ(script->Run()->Int32Value(), 321);
   2605 }
   2606 
   2607 
   2608 THREADED_TEST(InternalFields) {
   2609   LocalContext env;
   2610   v8::Isolate* isolate = env->GetIsolate();
   2611   v8::HandleScope scope(isolate);
   2612 
   2613   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2614   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   2615   instance_templ->SetInternalFieldCount(1);
   2616   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   2617   CHECK_EQ(1, obj->InternalFieldCount());
   2618   CHECK(obj->GetInternalField(0)->IsUndefined());
   2619   obj->SetInternalField(0, v8_num(17));
   2620   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
   2621 }
   2622 
   2623 
   2624 THREADED_TEST(GlobalObjectInternalFields) {
   2625   v8::Isolate* isolate = CcTest::isolate();
   2626   v8::HandleScope scope(isolate);
   2627   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
   2628   global_template->SetInternalFieldCount(1);
   2629   LocalContext env(NULL, global_template);
   2630   v8::Handle<v8::Object> global_proxy = env->Global();
   2631   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
   2632   CHECK_EQ(1, global->InternalFieldCount());
   2633   CHECK(global->GetInternalField(0)->IsUndefined());
   2634   global->SetInternalField(0, v8_num(17));
   2635   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
   2636 }
   2637 
   2638 
   2639 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
   2640   LocalContext env;
   2641   v8::HandleScope scope(CcTest::isolate());
   2642 
   2643   v8::Local<v8::Object> global = env->Global();
   2644   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
   2645   CHECK(global->HasRealIndexedProperty(0));
   2646 }
   2647 
   2648 
   2649 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
   2650                                                void* value) {
   2651   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
   2652   obj->SetAlignedPointerInInternalField(0, value);
   2653   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2654   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
   2655 }
   2656 
   2657 
   2658 THREADED_TEST(InternalFieldsAlignedPointers) {
   2659   LocalContext env;
   2660   v8::Isolate* isolate = env->GetIsolate();
   2661   v8::HandleScope scope(isolate);
   2662 
   2663   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2664   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   2665   instance_templ->SetInternalFieldCount(1);
   2666   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   2667   CHECK_EQ(1, obj->InternalFieldCount());
   2668 
   2669   CheckAlignedPointerInInternalField(obj, NULL);
   2670 
   2671   int* heap_allocated = new int[100];
   2672   CheckAlignedPointerInInternalField(obj, heap_allocated);
   2673   delete[] heap_allocated;
   2674 
   2675   int stack_allocated[100];
   2676   CheckAlignedPointerInInternalField(obj, stack_allocated);
   2677 
   2678   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   2679   CheckAlignedPointerInInternalField(obj, huge);
   2680 
   2681   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
   2682   CHECK_EQ(1, Object::InternalFieldCount(persistent));
   2683   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
   2684 }
   2685 
   2686 
   2687 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
   2688                                               int index,
   2689                                               void* value) {
   2690   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
   2691   (*env)->SetAlignedPointerInEmbedderData(index, value);
   2692   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2693   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
   2694 }
   2695 
   2696 
   2697 static void* AlignedTestPointer(int i) {
   2698   return reinterpret_cast<void*>(i * 1234);
   2699 }
   2700 
   2701 
   2702 THREADED_TEST(EmbedderDataAlignedPointers) {
   2703   LocalContext env;
   2704   v8::HandleScope scope(env->GetIsolate());
   2705 
   2706   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
   2707 
   2708   int* heap_allocated = new int[100];
   2709   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
   2710   delete[] heap_allocated;
   2711 
   2712   int stack_allocated[100];
   2713   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
   2714 
   2715   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   2716   CheckAlignedPointerInEmbedderData(&env, 3, huge);
   2717 
   2718   // Test growing of the embedder data's backing store.
   2719   for (int i = 0; i < 100; i++) {
   2720     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
   2721   }
   2722   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2723   for (int i = 0; i < 100; i++) {
   2724     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
   2725   }
   2726 }
   2727 
   2728 
   2729 static void CheckEmbedderData(LocalContext* env,
   2730                               int index,
   2731                               v8::Handle<Value> data) {
   2732   (*env)->SetEmbedderData(index, data);
   2733   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
   2734 }
   2735 
   2736 
   2737 THREADED_TEST(EmbedderData) {
   2738   LocalContext env;
   2739   v8::Isolate* isolate = env->GetIsolate();
   2740   v8::HandleScope scope(isolate);
   2741 
   2742   CheckEmbedderData(
   2743       &env, 3,
   2744       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
   2745   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
   2746                                                      "over the lazy dog."));
   2747   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
   2748   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
   2749 }
   2750 
   2751 
   2752 THREADED_TEST(IdentityHash) {
   2753   LocalContext env;
   2754   v8::Isolate* isolate = env->GetIsolate();
   2755   v8::HandleScope scope(isolate);
   2756 
   2757   // Ensure that the test starts with an fresh heap to test whether the hash
   2758   // code is based on the address.
   2759   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2760   Local<v8::Object> obj = v8::Object::New(isolate);
   2761   int hash = obj->GetIdentityHash();
   2762   int hash1 = obj->GetIdentityHash();
   2763   CHECK_EQ(hash, hash1);
   2764   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
   2765   // Since the identity hash is essentially a random number two consecutive
   2766   // objects should not be assigned the same hash code. If the test below fails
   2767   // the random number generator should be evaluated.
   2768   CHECK_NE(hash, hash2);
   2769   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2770   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
   2771   // Make sure that the identity hash is not based on the initial address of
   2772   // the object alone. If the test below fails the random number generator
   2773   // should be evaluated.
   2774   CHECK_NE(hash, hash3);
   2775   int hash4 = obj->GetIdentityHash();
   2776   CHECK_EQ(hash, hash4);
   2777 
   2778   // Check identity hashes behaviour in the presence of JS accessors.
   2779   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
   2780   {
   2781     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
   2782     Local<v8::Object> o1 = v8::Object::New(isolate);
   2783     Local<v8::Object> o2 = v8::Object::New(isolate);
   2784     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2785   }
   2786   {
   2787     CompileRun(
   2788         "function cnst() { return 42; };\n"
   2789         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
   2790     Local<v8::Object> o1 = v8::Object::New(isolate);
   2791     Local<v8::Object> o2 = v8::Object::New(isolate);
   2792     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2793   }
   2794 }
   2795 
   2796 
   2797 THREADED_TEST(GlobalProxyIdentityHash) {
   2798   LocalContext env;
   2799   v8::Isolate* isolate = env->GetIsolate();
   2800   v8::HandleScope scope(isolate);
   2801   Handle<Object> global_proxy = env->Global();
   2802   int hash1 = global_proxy->GetIdentityHash();
   2803   // Hash should be retained after being detached.
   2804   env->DetachGlobal();
   2805   int hash2 = global_proxy->GetIdentityHash();
   2806   CHECK_EQ(hash1, hash2);
   2807   {
   2808     // Re-attach global proxy to a new context, hash should stay the same.
   2809     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
   2810     int hash3 = global_proxy->GetIdentityHash();
   2811     CHECK_EQ(hash1, hash3);
   2812   }
   2813 }
   2814 
   2815 
   2816 THREADED_TEST(SymbolProperties) {
   2817   LocalContext env;
   2818   v8::Isolate* isolate = env->GetIsolate();
   2819   v8::HandleScope scope(isolate);
   2820 
   2821   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   2822   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
   2823   v8::Local<v8::Symbol> sym2 =
   2824       v8::Symbol::New(isolate, v8_str("my-symbol"));
   2825   v8::Local<v8::Symbol> sym3 =
   2826       v8::Symbol::New(isolate, v8_str("sym3"));
   2827 
   2828   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2829 
   2830   // Check basic symbol functionality.
   2831   CHECK(sym1->IsSymbol());
   2832   CHECK(sym2->IsSymbol());
   2833   CHECK(!obj->IsSymbol());
   2834 
   2835   CHECK(sym1->Equals(sym1));
   2836   CHECK(sym2->Equals(sym2));
   2837   CHECK(!sym1->Equals(sym2));
   2838   CHECK(!sym2->Equals(sym1));
   2839   CHECK(sym1->StrictEquals(sym1));
   2840   CHECK(sym2->StrictEquals(sym2));
   2841   CHECK(!sym1->StrictEquals(sym2));
   2842   CHECK(!sym2->StrictEquals(sym1));
   2843 
   2844   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
   2845 
   2846   v8::Local<v8::Value> sym_val = sym2;
   2847   CHECK(sym_val->IsSymbol());
   2848   CHECK(sym_val->Equals(sym2));
   2849   CHECK(sym_val->StrictEquals(sym2));
   2850   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
   2851 
   2852   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
   2853   CHECK(sym_obj->IsSymbolObject());
   2854   CHECK(!sym2->IsSymbolObject());
   2855   CHECK(!obj->IsSymbolObject());
   2856   CHECK(!sym_obj->Equals(sym2));
   2857   CHECK(!sym_obj->StrictEquals(sym2));
   2858   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
   2859   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
   2860 
   2861   // Make sure delete of a non-existent symbol property works.
   2862   CHECK(obj->Delete(sym1));
   2863   CHECK(!obj->Has(sym1));
   2864 
   2865   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
   2866   CHECK(obj->Has(sym1));
   2867   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
   2868   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
   2869   CHECK(obj->Has(sym1));
   2870   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2871   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
   2872 
   2873   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
   2874   int num_props = obj->GetPropertyNames()->Length();
   2875   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
   2876                  v8::Integer::New(isolate, 20)));
   2877   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2878   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
   2879 
   2880   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2881 
   2882   CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
   2883   CHECK(obj->Get(sym3)->IsUndefined());
   2884   CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
   2885   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
   2886   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
   2887       v8::Integer::New(isolate, 42)));
   2888 
   2889   // Add another property and delete it afterwards to force the object in
   2890   // slow case.
   2891   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
   2892   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2893   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
   2894   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2895   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
   2896 
   2897   CHECK(obj->Has(sym1));
   2898   CHECK(obj->Has(sym2));
   2899   CHECK(obj->Has(sym3));
   2900   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
   2901   CHECK(obj->Delete(sym2));
   2902   CHECK(obj->Has(sym1));
   2903   CHECK(!obj->Has(sym2));
   2904   CHECK(obj->Has(sym3));
   2905   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
   2906   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2907   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
   2908   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
   2909       v8::Integer::New(isolate, 42)));
   2910   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
   2911 
   2912   // Symbol properties are inherited.
   2913   v8::Local<v8::Object> child = v8::Object::New(isolate);
   2914   child->SetPrototype(obj);
   2915   CHECK(child->Has(sym1));
   2916   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
   2917   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
   2918   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
   2919       v8::Integer::New(isolate, 42)));
   2920   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
   2921 }
   2922 
   2923 
   2924 THREADED_TEST(SymbolTemplateProperties) {
   2925   LocalContext env;
   2926   v8::Isolate* isolate = env->GetIsolate();
   2927   v8::HandleScope scope(isolate);
   2928   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
   2929   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
   2930   CHECK(!name.IsEmpty());
   2931   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
   2932   v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
   2933   CHECK(!new_instance.IsEmpty());
   2934   CHECK(new_instance->Has(name));
   2935 }
   2936 
   2937 
   2938 THREADED_TEST(PrivateProperties) {
   2939   LocalContext env;
   2940   v8::Isolate* isolate = env->GetIsolate();
   2941   v8::HandleScope scope(isolate);
   2942 
   2943   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   2944   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
   2945   v8::Local<v8::Private> priv2 =
   2946       v8::Private::New(isolate, v8_str("my-private"));
   2947 
   2948   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2949 
   2950   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
   2951 
   2952   // Make sure delete of a non-existent private symbol property works.
   2953   CHECK(obj->DeletePrivate(priv1));
   2954   CHECK(!obj->HasPrivate(priv1));
   2955 
   2956   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
   2957   CHECK(obj->HasPrivate(priv1));
   2958   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
   2959   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
   2960   CHECK(obj->HasPrivate(priv1));
   2961   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2962 
   2963   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
   2964   int num_props = obj->GetPropertyNames()->Length();
   2965   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
   2966                  v8::Integer::New(isolate, 20)));
   2967   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2968   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
   2969 
   2970   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2971 
   2972   // Add another property and delete it afterwards to force the object in
   2973   // slow case.
   2974   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
   2975   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2976   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
   2977   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2978   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2979 
   2980   CHECK(obj->HasPrivate(priv1));
   2981   CHECK(obj->HasPrivate(priv2));
   2982   CHECK(obj->DeletePrivate(priv2));
   2983   CHECK(obj->HasPrivate(priv1));
   2984   CHECK(!obj->HasPrivate(priv2));
   2985   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2986   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2987 
   2988   // Private properties are inherited (for the time being).
   2989   v8::Local<v8::Object> child = v8::Object::New(isolate);
   2990   child->SetPrototype(obj);
   2991   CHECK(child->HasPrivate(priv1));
   2992   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
   2993   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
   2994 }
   2995 
   2996 
   2997 THREADED_TEST(GlobalSymbols) {
   2998   LocalContext env;
   2999   v8::Isolate* isolate = env->GetIsolate();
   3000   v8::HandleScope scope(isolate);
   3001 
   3002   v8::Local<String> name = v8_str("my-symbol");
   3003   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
   3004   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
   3005   CHECK(glob2->SameValue(glob));
   3006 
   3007   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
   3008   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
   3009   CHECK(glob_api2->SameValue(glob_api));
   3010   CHECK(!glob_api->SameValue(glob));
   3011 
   3012   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
   3013   CHECK(!sym->SameValue(glob));
   3014 
   3015   CompileRun("var sym2 = Symbol.for('my-symbol')");
   3016   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
   3017   CHECK(sym2->SameValue(glob));
   3018   CHECK(!sym2->SameValue(glob_api));
   3019 }
   3020 
   3021 
   3022 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
   3023                                  const char* name) {
   3024   LocalContext env;
   3025   v8::Isolate* isolate = env->GetIsolate();
   3026   v8::HandleScope scope(isolate);
   3027 
   3028   v8::Local<v8::Symbol> symbol = getter(isolate);
   3029   std::string script = std::string("var sym = ") + name;
   3030   CompileRun(script.c_str());
   3031   v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
   3032 
   3033   CHECK(!value.IsEmpty());
   3034   CHECK(!symbol.IsEmpty());
   3035   CHECK(value->SameValue(symbol));
   3036 }
   3037 
   3038 
   3039 THREADED_TEST(WellKnownSymbols) {
   3040   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
   3041   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
   3042 }
   3043 
   3044 
   3045 THREADED_TEST(GlobalPrivates) {
   3046   LocalContext env;
   3047   v8::Isolate* isolate = env->GetIsolate();
   3048   v8::HandleScope scope(isolate);
   3049 
   3050   v8::Local<String> name = v8_str("my-private");
   3051   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
   3052   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   3053   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
   3054 
   3055   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
   3056   CHECK(obj->HasPrivate(glob2));
   3057 
   3058   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
   3059   CHECK(!obj->HasPrivate(priv));
   3060 
   3061   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
   3062   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
   3063   CHECK(!obj->Has(intern));
   3064 }
   3065 
   3066 
   3067 class ScopedArrayBufferContents {
   3068  public:
   3069   explicit ScopedArrayBufferContents(
   3070       const v8::ArrayBuffer::Contents& contents)
   3071     : contents_(contents) {}
   3072   ~ScopedArrayBufferContents() { free(contents_.Data()); }
   3073   void* Data() const { return contents_.Data(); }
   3074   size_t ByteLength() const { return contents_.ByteLength(); }
   3075  private:
   3076   const v8::ArrayBuffer::Contents contents_;
   3077 };
   3078 
   3079 template <typename T>
   3080 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
   3081   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
   3082   for (int i = 0; i < value->InternalFieldCount(); i++) {
   3083     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
   3084   }
   3085 }
   3086 
   3087 
   3088 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
   3089   LocalContext env;
   3090   v8::Isolate* isolate = env->GetIsolate();
   3091   v8::HandleScope handle_scope(isolate);
   3092 
   3093   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
   3094   CheckInternalFieldsAreZero(ab);
   3095   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
   3096   CHECK(!ab->IsExternal());
   3097   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3098 
   3099   ScopedArrayBufferContents ab_contents(ab->Externalize());
   3100   CHECK(ab->IsExternal());
   3101 
   3102   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
   3103   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
   3104   DCHECK(data != NULL);
   3105   env->Global()->Set(v8_str("ab"), ab);
   3106 
   3107   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
   3108   CHECK_EQ(1024, result->Int32Value());
   3109 
   3110   result = CompileRun("var u8 = new Uint8Array(ab);"
   3111                       "u8[0] = 0xFF;"
   3112                       "u8[1] = 0xAA;"
   3113                       "u8.length");
   3114   CHECK_EQ(1024, result->Int32Value());
   3115   CHECK_EQ(0xFF, data[0]);
   3116   CHECK_EQ(0xAA, data[1]);
   3117   data[0] = 0xCC;
   3118   data[1] = 0x11;
   3119   result = CompileRun("u8[0] + u8[1]");
   3120   CHECK_EQ(0xDD, result->Int32Value());
   3121 }
   3122 
   3123 
   3124 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
   3125   LocalContext env;
   3126   v8::Isolate* isolate = env->GetIsolate();
   3127   v8::HandleScope handle_scope(isolate);
   3128 
   3129 
   3130   v8::Local<v8::Value> result =
   3131       CompileRun("var ab1 = new ArrayBuffer(2);"
   3132                  "var u8_a = new Uint8Array(ab1);"
   3133                  "u8_a[0] = 0xAA;"
   3134                  "u8_a[1] = 0xFF; u8_a.buffer");
   3135   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
   3136   CheckInternalFieldsAreZero(ab1);
   3137   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
   3138   CHECK(!ab1->IsExternal());
   3139   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
   3140   CHECK(ab1->IsExternal());
   3141 
   3142   result = CompileRun("ab1.byteLength");
   3143   CHECK_EQ(2, result->Int32Value());
   3144   result = CompileRun("u8_a[0]");
   3145   CHECK_EQ(0xAA, result->Int32Value());
   3146   result = CompileRun("u8_a[1]");
   3147   CHECK_EQ(0xFF, result->Int32Value());
   3148   result = CompileRun("var u8_b = new Uint8Array(ab1);"
   3149                       "u8_b[0] = 0xBB;"
   3150                       "u8_a[0]");
   3151   CHECK_EQ(0xBB, result->Int32Value());
   3152   result = CompileRun("u8_b[1]");
   3153   CHECK_EQ(0xFF, result->Int32Value());
   3154 
   3155   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
   3156   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
   3157   CHECK_EQ(0xBB, ab1_data[0]);
   3158   CHECK_EQ(0xFF, ab1_data[1]);
   3159   ab1_data[0] = 0xCC;
   3160   ab1_data[1] = 0x11;
   3161   result = CompileRun("u8_a[0] + u8_a[1]");
   3162   CHECK_EQ(0xDD, result->Int32Value());
   3163 }
   3164 
   3165 
   3166 THREADED_TEST(ArrayBuffer_External) {
   3167   LocalContext env;
   3168   v8::Isolate* isolate = env->GetIsolate();
   3169   v8::HandleScope handle_scope(isolate);
   3170 
   3171   i::ScopedVector<uint8_t> my_data(100);
   3172   memset(my_data.start(), 0, 100);
   3173   Local<v8::ArrayBuffer> ab3 =
   3174       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
   3175   CheckInternalFieldsAreZero(ab3);
   3176   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
   3177   CHECK(ab3->IsExternal());
   3178 
   3179   env->Global()->Set(v8_str("ab3"), ab3);
   3180 
   3181   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
   3182   CHECK_EQ(100, result->Int32Value());
   3183 
   3184   result = CompileRun("var u8_b = new Uint8Array(ab3);"
   3185                       "u8_b[0] = 0xBB;"
   3186                       "u8_b[1] = 0xCC;"
   3187                       "u8_b.length");
   3188   CHECK_EQ(100, result->Int32Value());
   3189   CHECK_EQ(0xBB, my_data[0]);
   3190   CHECK_EQ(0xCC, my_data[1]);
   3191   my_data[0] = 0xCC;
   3192   my_data[1] = 0x11;
   3193   result = CompileRun("u8_b[0] + u8_b[1]");
   3194   CHECK_EQ(0xDD, result->Int32Value());
   3195 }
   3196 
   3197 
   3198 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
   3199   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
   3200   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
   3201 }
   3202 
   3203 
   3204 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
   3205   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
   3206   CHECK_EQ(0, static_cast<int>(ta->Length()));
   3207   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
   3208 }
   3209 
   3210 
   3211 static void CheckIsTypedArrayVarNeutered(const char* name) {
   3212   i::ScopedVector<char> source(1024);
   3213   i::SNPrintF(source,
   3214       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
   3215       name, name, name);
   3216   CHECK(CompileRun(source.start())->IsTrue());
   3217   v8::Handle<v8::TypedArray> ta =
   3218     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
   3219   CheckIsNeutered(ta);
   3220 }
   3221 
   3222 
   3223 template <typename TypedArray, int kElementSize>
   3224 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
   3225                                          int byteOffset,
   3226                                          int length) {
   3227   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
   3228   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
   3229   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
   3230   CHECK_EQ(length, static_cast<int>(ta->Length()));
   3231   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
   3232   return ta;
   3233 }
   3234 
   3235 
   3236 THREADED_TEST(ArrayBuffer_NeuteringApi) {
   3237   LocalContext env;
   3238   v8::Isolate* isolate = env->GetIsolate();
   3239   v8::HandleScope handle_scope(isolate);
   3240 
   3241   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
   3242 
   3243   v8::Handle<v8::Uint8Array> u8a =
   3244     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
   3245   v8::Handle<v8::Uint8ClampedArray> u8c =
   3246     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
   3247   v8::Handle<v8::Int8Array> i8a =
   3248     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
   3249 
   3250   v8::Handle<v8::Uint16Array> u16a =
   3251     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
   3252   v8::Handle<v8::Int16Array> i16a =
   3253     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
   3254 
   3255   v8::Handle<v8::Uint32Array> u32a =
   3256     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
   3257   v8::Handle<v8::Int32Array> i32a =
   3258     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
   3259 
   3260   v8::Handle<v8::Float32Array> f32a =
   3261     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
   3262   v8::Handle<v8::Float64Array> f64a =
   3263     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
   3264 
   3265   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
   3266   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
   3267   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
   3268   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
   3269 
   3270   ScopedArrayBufferContents contents(buffer->Externalize());
   3271   buffer->Neuter();
   3272   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
   3273   CheckIsNeutered(u8a);
   3274   CheckIsNeutered(u8c);
   3275   CheckIsNeutered(i8a);
   3276   CheckIsNeutered(u16a);
   3277   CheckIsNeutered(i16a);
   3278   CheckIsNeutered(u32a);
   3279   CheckIsNeutered(i32a);
   3280   CheckIsNeutered(f32a);
   3281   CheckIsNeutered(f64a);
   3282   CheckDataViewIsNeutered(dv);
   3283 }
   3284 
   3285 
   3286 THREADED_TEST(ArrayBuffer_NeuteringScript) {
   3287   LocalContext env;
   3288   v8::Isolate* isolate = env->GetIsolate();
   3289   v8::HandleScope handle_scope(isolate);
   3290 
   3291   CompileRun(
   3292       "var ab = new ArrayBuffer(1024);"
   3293       "var u8a = new Uint8Array(ab, 1, 1023);"
   3294       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
   3295       "var i8a = new Int8Array(ab, 1, 1023);"
   3296       "var u16a = new Uint16Array(ab, 2, 511);"
   3297       "var i16a = new Int16Array(ab, 2, 511);"
   3298       "var u32a = new Uint32Array(ab, 4, 255);"
   3299       "var i32a = new Int32Array(ab, 4, 255);"
   3300       "var f32a = new Float32Array(ab, 4, 255);"
   3301       "var f64a = new Float64Array(ab, 8, 127);"
   3302       "var dv = new DataView(ab, 1, 1023);");
   3303 
   3304   v8::Handle<v8::ArrayBuffer> ab =
   3305       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
   3306 
   3307   v8::Handle<v8::DataView> dv =
   3308     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
   3309 
   3310   ScopedArrayBufferContents contents(ab->Externalize());
   3311   ab->Neuter();
   3312   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
   3313   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
   3314 
   3315   CheckIsTypedArrayVarNeutered("u8a");
   3316   CheckIsTypedArrayVarNeutered("u8c");
   3317   CheckIsTypedArrayVarNeutered("i8a");
   3318   CheckIsTypedArrayVarNeutered("u16a");
   3319   CheckIsTypedArrayVarNeutered("i16a");
   3320   CheckIsTypedArrayVarNeutered("u32a");
   3321   CheckIsTypedArrayVarNeutered("i32a");
   3322   CheckIsTypedArrayVarNeutered("f32a");
   3323   CheckIsTypedArrayVarNeutered("f64a");
   3324 
   3325   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
   3326   CheckDataViewIsNeutered(dv);
   3327 }
   3328 
   3329 
   3330 
   3331 THREADED_TEST(HiddenProperties) {
   3332   LocalContext env;
   3333   v8::Isolate* isolate = env->GetIsolate();
   3334   v8::HandleScope scope(isolate);
   3335 
   3336   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
   3337   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   3338   v8::Local<v8::String> empty = v8_str("");
   3339   v8::Local<v8::String> prop_name = v8_str("prop_name");
   3340 
   3341   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3342 
   3343   // Make sure delete of a non-existent hidden value works
   3344   CHECK(obj->DeleteHiddenValue(key));
   3345 
   3346   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
   3347   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
   3348   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
   3349   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3350 
   3351   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3352 
   3353   // Make sure we do not find the hidden property.
   3354   CHECK(!obj->Has(empty));
   3355   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3356   CHECK(obj->Get(empty)->IsUndefined());
   3357   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3358   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
   3359   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3360   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
   3361 
   3362   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3363 
   3364   // Add another property and delete it afterwards to force the object in
   3365   // slow case.
   3366   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
   3367   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3368   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
   3369   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3370   CHECK(obj->Delete(prop_name));
   3371   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3372 
   3373   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3374 
   3375   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
   3376   CHECK(obj->GetHiddenValue(key).IsEmpty());
   3377 
   3378   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
   3379   CHECK(obj->DeleteHiddenValue(key));
   3380   CHECK(obj->GetHiddenValue(key).IsEmpty());
   3381 }
   3382 
   3383 
   3384 THREADED_TEST(Regress97784) {
   3385   // Regression test for crbug.com/97784
   3386   // Messing with the Object.prototype should not have effect on
   3387   // hidden properties.
   3388   LocalContext env;
   3389   v8::HandleScope scope(env->GetIsolate());
   3390 
   3391   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
   3392   v8::Local<v8::String> key = v8_str("hidden");
   3393 
   3394   CompileRun(
   3395       "set_called = false;"
   3396       "Object.defineProperty("
   3397       "    Object.prototype,"
   3398       "    'hidden',"
   3399       "    {get: function() { return 45; },"
   3400       "     set: function() { set_called = true; }})");
   3401 
   3402   CHECK(obj->GetHiddenValue(key).IsEmpty());
   3403   // Make sure that the getter and setter from Object.prototype is not invoked.
   3404   // If it did we would have full access to the hidden properties in
   3405   // the accessor.
   3406   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
   3407   ExpectFalse("set_called");
   3408   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
   3409 }
   3410 
   3411 
   3412 static bool interceptor_for_hidden_properties_called;
   3413 static void InterceptorForHiddenProperties(
   3414     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   3415   interceptor_for_hidden_properties_called = true;
   3416 }
   3417 
   3418 
   3419 THREADED_TEST(HiddenPropertiesWithInterceptors) {
   3420   LocalContext context;
   3421   v8::Isolate* isolate = context->GetIsolate();
   3422   v8::HandleScope scope(isolate);
   3423 
   3424   interceptor_for_hidden_properties_called = false;
   3425 
   3426   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   3427 
   3428   // Associate an interceptor with an object and start setting hidden values.
   3429   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   3430   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   3431   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
   3432   Local<v8::Function> function = fun_templ->GetFunction();
   3433   Local<v8::Object> obj = function->NewInstance();
   3434   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
   3435   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
   3436   CHECK(!interceptor_for_hidden_properties_called);
   3437 }
   3438 
   3439 
   3440 THREADED_TEST(External) {
   3441   v8::HandleScope scope(CcTest::isolate());
   3442   int x = 3;
   3443   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
   3444   LocalContext env;
   3445   env->Global()->Set(v8_str("ext"), ext);
   3446   Local<Value> reext_obj = CompileRun("this.ext");
   3447   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
   3448   int* ptr = static_cast<int*>(reext->Value());
   3449   CHECK_EQ(x, 3);
   3450   *ptr = 10;
   3451   CHECK_EQ(x, 10);
   3452 
   3453   // Make sure unaligned pointers are wrapped properly.
   3454   char* data = i::StrDup("0123456789");
   3455   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
   3456   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
   3457   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
   3458   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
   3459 
   3460   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
   3461   CHECK_EQ('0', *char_ptr);
   3462   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
   3463   CHECK_EQ('1', *char_ptr);
   3464   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
   3465   CHECK_EQ('2', *char_ptr);
   3466   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
   3467   CHECK_EQ('3', *char_ptr);
   3468   i::DeleteArray(data);
   3469 }
   3470 
   3471 
   3472 THREADED_TEST(GlobalHandle) {
   3473   v8::Isolate* isolate = CcTest::isolate();
   3474   v8::Persistent<String> global;
   3475   {
   3476     v8::HandleScope scope(isolate);
   3477     global.Reset(isolate, v8_str("str"));
   3478   }
   3479   {
   3480     v8::HandleScope scope(isolate);
   3481     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3482   }
   3483   global.Reset();
   3484   {
   3485     v8::HandleScope scope(isolate);
   3486     global.Reset(isolate, v8_str("str"));
   3487   }
   3488   {
   3489     v8::HandleScope scope(isolate);
   3490     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3491   }
   3492   global.Reset();
   3493 }
   3494 
   3495 
   3496 THREADED_TEST(ResettingGlobalHandle) {
   3497   v8::Isolate* isolate = CcTest::isolate();
   3498   v8::Persistent<String> global;
   3499   {
   3500     v8::HandleScope scope(isolate);
   3501     global.Reset(isolate, v8_str("str"));
   3502   }
   3503   v8::internal::GlobalHandles* global_handles =
   3504       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3505   int initial_handle_count = global_handles->global_handles_count();
   3506   {
   3507     v8::HandleScope scope(isolate);
   3508     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3509   }
   3510   {
   3511     v8::HandleScope scope(isolate);
   3512     global.Reset(isolate, v8_str("longer"));
   3513   }
   3514   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
   3515   {
   3516     v8::HandleScope scope(isolate);
   3517     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
   3518   }
   3519   global.Reset();
   3520   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
   3521 }
   3522 
   3523 
   3524 THREADED_TEST(ResettingGlobalHandleToEmpty) {
   3525   v8::Isolate* isolate = CcTest::isolate();
   3526   v8::Persistent<String> global;
   3527   {
   3528     v8::HandleScope scope(isolate);
   3529     global.Reset(isolate, v8_str("str"));
   3530   }
   3531   v8::internal::GlobalHandles* global_handles =
   3532       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3533   int initial_handle_count = global_handles->global_handles_count();
   3534   {
   3535     v8::HandleScope scope(isolate);
   3536     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3537   }
   3538   {
   3539     v8::HandleScope scope(isolate);
   3540     Local<String> empty;
   3541     global.Reset(isolate, empty);
   3542   }
   3543   CHECK(global.IsEmpty());
   3544   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
   3545 }
   3546 
   3547 
   3548 template<class T>
   3549 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
   3550   return unique.Pass();
   3551 }
   3552 
   3553 
   3554 template<class T>
   3555 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
   3556                                             const v8::Persistent<T> & global) {
   3557   v8::UniquePersistent<String> unique(isolate, global);
   3558   return unique.Pass();
   3559 }
   3560 
   3561 
   3562 THREADED_TEST(UniquePersistent) {
   3563   v8::Isolate* isolate = CcTest::isolate();
   3564   v8::Persistent<String> global;
   3565   {
   3566     v8::HandleScope scope(isolate);
   3567     global.Reset(isolate, v8_str("str"));
   3568   }
   3569   v8::internal::GlobalHandles* global_handles =
   3570       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3571   int initial_handle_count = global_handles->global_handles_count();
   3572   {
   3573     v8::UniquePersistent<String> unique(isolate, global);
   3574     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3575     // Test assignment via Pass
   3576     {
   3577       v8::UniquePersistent<String> copy = unique.Pass();
   3578       CHECK(unique.IsEmpty());
   3579       CHECK(copy == global);
   3580       CHECK_EQ(initial_handle_count + 1,
   3581                global_handles->global_handles_count());
   3582       unique = copy.Pass();
   3583     }
   3584     // Test ctor via Pass
   3585     {
   3586       v8::UniquePersistent<String> copy(unique.Pass());
   3587       CHECK(unique.IsEmpty());
   3588       CHECK(copy == global);
   3589       CHECK_EQ(initial_handle_count + 1,
   3590                global_handles->global_handles_count());
   3591       unique = copy.Pass();
   3592     }
   3593     // Test pass through function call
   3594     {
   3595       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
   3596       CHECK(unique.IsEmpty());
   3597       CHECK(copy == global);
   3598       CHECK_EQ(initial_handle_count + 1,
   3599                global_handles->global_handles_count());
   3600       unique = copy.Pass();
   3601     }
   3602     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3603   }
   3604   // Test pass from function call
   3605   {
   3606     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
   3607     CHECK(unique == global);
   3608     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3609   }
   3610   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   3611   global.Reset();
   3612 }
   3613 
   3614 
   3615 template<typename K, typename V>
   3616 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
   3617  public:
   3618   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
   3619       MapType;
   3620   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
   3621   struct WeakCallbackDataType {
   3622     MapType* map;
   3623     K key;
   3624   };
   3625   static WeakCallbackDataType* WeakCallbackParameter(
   3626       MapType* map, const K& key, Local<V> value) {
   3627     WeakCallbackDataType* data = new WeakCallbackDataType;
   3628     data->map = map;
   3629     data->key = key;
   3630     return data;
   3631   }
   3632   static MapType* MapFromWeakCallbackData(
   3633       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
   3634     return data.GetParameter()->map;
   3635   }
   3636   static K KeyFromWeakCallbackData(
   3637       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
   3638     return data.GetParameter()->key;
   3639   }
   3640   static void DisposeCallbackData(WeakCallbackDataType* data) {
   3641     delete data;
   3642   }
   3643   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
   3644       K key) { }
   3645 };
   3646 
   3647 
   3648 template<typename Map>
   3649 static void TestPersistentValueMap() {
   3650   LocalContext env;
   3651   v8::Isolate* isolate = env->GetIsolate();
   3652   Map map(isolate);
   3653   v8::internal::GlobalHandles* global_handles =
   3654       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3655   int initial_handle_count = global_handles->global_handles_count();
   3656   CHECK_EQ(0, static_cast<int>(map.Size()));
   3657   {
   3658     HandleScope scope(isolate);
   3659     Local<v8::Object> obj = map.Get(7);
   3660     CHECK(obj.IsEmpty());
   3661     Local<v8::Object> expected = v8::Object::New(isolate);
   3662     map.Set(7, expected);
   3663     CHECK_EQ(1, static_cast<int>(map.Size()));
   3664     obj = map.Get(7);
   3665     CHECK_EQ(expected, obj);
   3666     {
   3667       typename Map::PersistentValueReference ref = map.GetReference(7);
   3668       CHECK_EQ(expected, ref.NewLocal(isolate));
   3669     }
   3670     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
   3671     CHECK_EQ(0, static_cast<int>(map.Size()));
   3672     CHECK(expected == removed);
   3673     removed = map.Remove(7);
   3674     CHECK(removed.IsEmpty());
   3675     map.Set(8, expected);
   3676     CHECK_EQ(1, static_cast<int>(map.Size()));
   3677     map.Set(8, expected);
   3678     CHECK_EQ(1, static_cast<int>(map.Size()));
   3679     {
   3680       typename Map::PersistentValueReference ref;
   3681       Local<v8::Object> expected2 = v8::Object::New(isolate);
   3682       removed = map.Set(8,
   3683           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
   3684       CHECK_EQ(1, static_cast<int>(map.Size()));
   3685       CHECK(expected == removed);
   3686       CHECK_EQ(expected2, ref.NewLocal(isolate));
   3687     }
   3688   }
   3689   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3690   if (map.IsWeak()) {
   3691     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
   3692         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3693   } else {
   3694     map.Clear();
   3695   }
   3696   CHECK_EQ(0, static_cast<int>(map.Size()));
   3697   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   3698 }
   3699 
   3700 
   3701 TEST(PersistentValueMap) {
   3702   // Default case, w/o weak callbacks:
   3703   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
   3704 
   3705   // Custom traits with weak callbacks:
   3706   typedef v8::PersistentValueMap<int, v8::Object,
   3707       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
   3708   TestPersistentValueMap<WeakPersistentValueMap>();
   3709 }
   3710 
   3711 
   3712 TEST(PersistentValueVector) {
   3713   LocalContext env;
   3714   v8::Isolate* isolate = env->GetIsolate();
   3715   v8::internal::GlobalHandles* global_handles =
   3716       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3717   int handle_count = global_handles->global_handles_count();
   3718   HandleScope scope(isolate);
   3719 
   3720   v8::PersistentValueVector<v8::Object> vector(isolate);
   3721 
   3722   Local<v8::Object> obj1 = v8::Object::New(isolate);
   3723   Local<v8::Object> obj2 = v8::Object::New(isolate);
   3724   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
   3725 
   3726   CHECK(vector.IsEmpty());
   3727   CHECK_EQ(0, static_cast<int>(vector.Size()));
   3728 
   3729   vector.ReserveCapacity(3);
   3730   CHECK(vector.IsEmpty());
   3731 
   3732   vector.Append(obj1);
   3733   vector.Append(obj2);
   3734   vector.Append(obj1);
   3735   vector.Append(obj3.Pass());
   3736   vector.Append(obj1);
   3737 
   3738   CHECK(!vector.IsEmpty());
   3739   CHECK_EQ(5, static_cast<int>(vector.Size()));
   3740   CHECK(obj3.IsEmpty());
   3741   CHECK_EQ(obj1, vector.Get(0));
   3742   CHECK_EQ(obj1, vector.Get(2));
   3743   CHECK_EQ(obj1, vector.Get(4));
   3744   CHECK_EQ(obj2, vector.Get(1));
   3745 
   3746   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
   3747 
   3748   vector.Clear();
   3749   CHECK(vector.IsEmpty());
   3750   CHECK_EQ(0, static_cast<int>(vector.Size()));
   3751   CHECK_EQ(handle_count, global_handles->global_handles_count());
   3752 }
   3753 
   3754 
   3755 THREADED_TEST(GlobalHandleUpcast) {
   3756   v8::Isolate* isolate = CcTest::isolate();
   3757   v8::HandleScope scope(isolate);
   3758   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
   3759   v8::Persistent<String> global_string(isolate, local);
   3760   v8::Persistent<Value>& global_value =
   3761       v8::Persistent<Value>::Cast(global_string);
   3762   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
   3763   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
   3764   global_string.Reset();
   3765 }
   3766 
   3767 
   3768 THREADED_TEST(HandleEquality) {
   3769   v8::Isolate* isolate = CcTest::isolate();
   3770   v8::Persistent<String> global1;
   3771   v8::Persistent<String> global2;
   3772   {
   3773     v8::HandleScope scope(isolate);
   3774     global1.Reset(isolate, v8_str("str"));
   3775     global2.Reset(isolate, v8_str("str2"));
   3776   }
   3777   CHECK_EQ(global1 == global1, true);
   3778   CHECK_EQ(global1 != global1, false);
   3779   {
   3780     v8::HandleScope scope(isolate);
   3781     Local<String> local1 = Local<String>::New(isolate, global1);
   3782     Local<String> local2 = Local<String>::New(isolate, global2);
   3783 
   3784     CHECK_EQ(global1 == local1, true);
   3785     CHECK_EQ(global1 != local1, false);
   3786     CHECK_EQ(local1 == global1, true);
   3787     CHECK_EQ(local1 != global1, false);
   3788 
   3789     CHECK_EQ(global1 == local2, false);
   3790     CHECK_EQ(global1 != local2, true);
   3791     CHECK_EQ(local2 == global1, false);
   3792     CHECK_EQ(local2 != global1, true);
   3793 
   3794     CHECK_EQ(local1 == local2, false);
   3795     CHECK_EQ(local1 != local2, true);
   3796 
   3797     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
   3798     CHECK_EQ(local1 == anotherLocal1, true);
   3799     CHECK_EQ(local1 != anotherLocal1, false);
   3800   }
   3801   global1.Reset();
   3802   global2.Reset();
   3803 }
   3804 
   3805 
   3806 THREADED_TEST(LocalHandle) {
   3807   v8::HandleScope scope(CcTest::isolate());
   3808   v8::Local<String> local =
   3809       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
   3810   CHECK_EQ(local->Length(), 3);
   3811 }
   3812 
   3813 
   3814 class WeakCallCounter {
   3815  public:
   3816   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
   3817   int id() { return id_; }
   3818   void increment() { number_of_weak_calls_++; }
   3819   int NumberOfWeakCalls() { return number_of_weak_calls_; }
   3820  private:
   3821   int id_;
   3822   int number_of_weak_calls_;
   3823 };
   3824 
   3825 
   3826 template<typename T>
   3827 struct WeakCallCounterAndPersistent {
   3828   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
   3829       : counter(counter) {}
   3830   WeakCallCounter* counter;
   3831   v8::Persistent<T> handle;
   3832 };
   3833 
   3834 
   3835 template <typename T>
   3836 static void WeakPointerCallback(
   3837     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
   3838   CHECK_EQ(1234, data.GetParameter()->counter->id());
   3839   data.GetParameter()->counter->increment();
   3840   data.GetParameter()->handle.Reset();
   3841 }
   3842 
   3843 
   3844 template<typename T>
   3845 static UniqueId MakeUniqueId(const Persistent<T>& p) {
   3846   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
   3847 }
   3848 
   3849 
   3850 THREADED_TEST(ApiObjectGroups) {
   3851   LocalContext env;
   3852   v8::Isolate* iso = env->GetIsolate();
   3853   HandleScope scope(iso);
   3854 
   3855   WeakCallCounter counter(1234);
   3856 
   3857   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   3858   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   3859   WeakCallCounterAndPersistent<Value> g1c1(&counter);
   3860   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   3861   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   3862   WeakCallCounterAndPersistent<Value> g2c1(&counter);
   3863 
   3864   {
   3865     HandleScope scope(iso);
   3866     g1s1.handle.Reset(iso, Object::New(iso));
   3867     g1s2.handle.Reset(iso, Object::New(iso));
   3868     g1c1.handle.Reset(iso, Object::New(iso));
   3869     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   3870     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   3871     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3872 
   3873     g2s1.handle.Reset(iso, Object::New(iso));
   3874     g2s2.handle.Reset(iso, Object::New(iso));
   3875     g2c1.handle.Reset(iso, Object::New(iso));
   3876     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   3877     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   3878     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3879   }
   3880 
   3881   WeakCallCounterAndPersistent<Value> root(&counter);
   3882   root.handle.Reset(iso, g1s1.handle);  // make a root.
   3883 
   3884   // Connect group 1 and 2, make a cycle.
   3885   {
   3886     HandleScope scope(iso);
   3887     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
   3888             Set(0, Local<Value>::New(iso, g2s2.handle)));
   3889     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
   3890             Set(0, Local<Value>::New(iso, g1s1.handle)));
   3891   }
   3892 
   3893   {
   3894     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3895     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3896     iso->SetObjectGroupId(g1s1.handle, id1);
   3897     iso->SetObjectGroupId(g1s2.handle, id1);
   3898     iso->SetReferenceFromGroup(id1, g1c1.handle);
   3899     iso->SetObjectGroupId(g2s1.handle, id2);
   3900     iso->SetObjectGroupId(g2s2.handle, id2);
   3901     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3902   }
   3903   // Do a single full GC, ensure incremental marking is stopped.
   3904   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   3905       iso)->heap();
   3906   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3907 
   3908   // All object should be alive.
   3909   CHECK_EQ(0, counter.NumberOfWeakCalls());
   3910 
   3911   // Weaken the root.
   3912   root.handle.SetWeak(&root, &WeakPointerCallback);
   3913   // But make children strong roots---all the objects (except for children)
   3914   // should be collectable now.
   3915   g1c1.handle.ClearWeak();
   3916   g2c1.handle.ClearWeak();
   3917 
   3918   // Groups are deleted, rebuild groups.
   3919   {
   3920     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3921     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3922     iso->SetObjectGroupId(g1s1.handle, id1);
   3923     iso->SetObjectGroupId(g1s2.handle, id1);
   3924     iso->SetReferenceFromGroup(id1, g1c1.handle);
   3925     iso->SetObjectGroupId(g2s1.handle, id2);
   3926     iso->SetObjectGroupId(g2s2.handle, id2);
   3927     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3928   }
   3929 
   3930   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3931 
   3932   // All objects should be gone. 5 global handles in total.
   3933   CHECK_EQ(5, counter.NumberOfWeakCalls());
   3934 
   3935   // And now make children weak again and collect them.
   3936   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3937   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3938 
   3939   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3940   CHECK_EQ(7, counter.NumberOfWeakCalls());
   3941 }
   3942 
   3943 
   3944 THREADED_TEST(ApiObjectGroupsForSubtypes) {
   3945   LocalContext env;
   3946   v8::Isolate* iso = env->GetIsolate();
   3947   HandleScope scope(iso);
   3948 
   3949   WeakCallCounter counter(1234);
   3950 
   3951   WeakCallCounterAndPersistent<Object> g1s1(&counter);
   3952   WeakCallCounterAndPersistent<String> g1s2(&counter);
   3953   WeakCallCounterAndPersistent<String> g1c1(&counter);
   3954   WeakCallCounterAndPersistent<Object> g2s1(&counter);
   3955   WeakCallCounterAndPersistent<String> g2s2(&counter);
   3956   WeakCallCounterAndPersistent<String> g2c1(&counter);
   3957 
   3958   {
   3959     HandleScope scope(iso);
   3960     g1s1.handle.Reset(iso, Object::New(iso));
   3961     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
   3962     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
   3963     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   3964     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   3965     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3966 
   3967     g2s1.handle.Reset(iso, Object::New(iso));
   3968     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
   3969     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
   3970     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   3971     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   3972     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3973   }
   3974 
   3975   WeakCallCounterAndPersistent<Value> root(&counter);
   3976   root.handle.Reset(iso, g1s1.handle);  // make a root.
   3977 
   3978   // Connect group 1 and 2, make a cycle.
   3979   {
   3980     HandleScope scope(iso);
   3981     CHECK(Local<Object>::New(iso, g1s1.handle)
   3982               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
   3983     CHECK(Local<Object>::New(iso, g2s1.handle)
   3984               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
   3985   }
   3986 
   3987   {
   3988     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3989     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3990     iso->SetObjectGroupId(g1s1.handle, id1);
   3991     iso->SetObjectGroupId(g1s2.handle, id1);
   3992     iso->SetReference(g1s1.handle, g1c1.handle);
   3993     iso->SetObjectGroupId(g2s1.handle, id2);
   3994     iso->SetObjectGroupId(g2s2.handle, id2);
   3995     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3996   }
   3997   // Do a single full GC, ensure incremental marking is stopped.
   3998   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   3999       iso)->heap();
   4000   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   4001 
   4002   // All object should be alive.
   4003   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4004 
   4005   // Weaken the root.
   4006   root.handle.SetWeak(&root, &WeakPointerCallback);
   4007   // But make children strong roots---all the objects (except for children)
   4008   // should be collectable now.
   4009   g1c1.handle.ClearWeak();
   4010   g2c1.handle.ClearWeak();
   4011 
   4012   // Groups are deleted, rebuild groups.
   4013   {
   4014     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4015     UniqueId id2 = MakeUniqueId(g2s2.handle);
   4016     iso->SetObjectGroupId(g1s1.handle, id1);
   4017     iso->SetObjectGroupId(g1s2.handle, id1);
   4018     iso->SetReference(g1s1.handle, g1c1.handle);
   4019     iso->SetObjectGroupId(g2s1.handle, id2);
   4020     iso->SetObjectGroupId(g2s2.handle, id2);
   4021     iso->SetReferenceFromGroup(id2, g2c1.handle);
   4022   }
   4023 
   4024   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   4025 
   4026   // All objects should be gone. 5 global handles in total.
   4027   CHECK_EQ(5, counter.NumberOfWeakCalls());
   4028 
   4029   // And now make children weak again and collect them.
   4030   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   4031   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   4032 
   4033   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   4034   CHECK_EQ(7, counter.NumberOfWeakCalls());
   4035 }
   4036 
   4037 
   4038 THREADED_TEST(ApiObjectGroupsCycle) {
   4039   LocalContext env;
   4040   v8::Isolate* iso = env->GetIsolate();
   4041   HandleScope scope(iso);
   4042 
   4043   WeakCallCounter counter(1234);
   4044 
   4045   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   4046   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   4047   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   4048   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   4049   WeakCallCounterAndPersistent<Value> g3s1(&counter);
   4050   WeakCallCounterAndPersistent<Value> g3s2(&counter);
   4051   WeakCallCounterAndPersistent<Value> g4s1(&counter);
   4052   WeakCallCounterAndPersistent<Value> g4s2(&counter);
   4053 
   4054   {
   4055     HandleScope scope(iso);
   4056     g1s1.handle.Reset(iso, Object::New(iso));
   4057     g1s2.handle.Reset(iso, Object::New(iso));
   4058     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   4059     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   4060     CHECK(g1s1.handle.IsWeak());
   4061     CHECK(g1s2.handle.IsWeak());
   4062 
   4063     g2s1.handle.Reset(iso, Object::New(iso));
   4064     g2s2.handle.Reset(iso, Object::New(iso));
   4065     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   4066     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   4067     CHECK(g2s1.handle.IsWeak());
   4068     CHECK(g2s2.handle.IsWeak());
   4069 
   4070     g3s1.handle.Reset(iso, Object::New(iso));
   4071     g3s2.handle.Reset(iso, Object::New(iso));
   4072     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
   4073     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
   4074     CHECK(g3s1.handle.IsWeak());
   4075     CHECK(g3s2.handle.IsWeak());
   4076 
   4077     g4s1.handle.Reset(iso, Object::New(iso));
   4078     g4s2.handle.Reset(iso, Object::New(iso));
   4079     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
   4080     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
   4081     CHECK(g4s1.handle.IsWeak());
   4082     CHECK(g4s2.handle.IsWeak());
   4083   }
   4084 
   4085   WeakCallCounterAndPersistent<Value> root(&counter);
   4086   root.handle.Reset(iso, g1s1.handle);  // make a root.
   4087 
   4088   // Connect groups.  We're building the following cycle:
   4089   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
   4090   // groups.
   4091   {
   4092     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4093     UniqueId id2 = MakeUniqueId(g2s1.handle);
   4094     UniqueId id3 = MakeUniqueId(g3s1.handle);
   4095     UniqueId id4 = MakeUniqueId(g4s1.handle);
   4096     iso->SetObjectGroupId(g1s1.handle, id1);
   4097     iso->SetObjectGroupId(g1s2.handle, id1);
   4098     iso->SetReferenceFromGroup(id1, g2s1.handle);
   4099     iso->SetObjectGroupId(g2s1.handle, id2);
   4100     iso->SetObjectGroupId(g2s2.handle, id2);
   4101     iso->SetReferenceFromGroup(id2, g3s1.handle);
   4102     iso->SetObjectGroupId(g3s1.handle, id3);
   4103     iso->SetObjectGroupId(g3s2.handle, id3);
   4104     iso->SetReferenceFromGroup(id3, g4s1.handle);
   4105     iso->SetObjectGroupId(g4s1.handle, id4);
   4106     iso->SetObjectGroupId(g4s2.handle, id4);
   4107     iso->SetReferenceFromGroup(id4, g1s1.handle);
   4108   }
   4109   // Do a single full GC
   4110   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   4111       iso)->heap();
   4112   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   4113 
   4114   // All object should be alive.
   4115   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4116 
   4117   // Weaken the root.
   4118   root.handle.SetWeak(&root, &WeakPointerCallback);
   4119 
   4120   // Groups are deleted, rebuild groups.
   4121   {
   4122     UniqueId id1 = MakeUniqueId(g1s1.handle);
   4123     UniqueId id2 = MakeUniqueId(g2s1.handle);
   4124     UniqueId id3 = MakeUniqueId(g3s1.handle);
   4125     UniqueId id4 = MakeUniqueId(g4s1.handle);
   4126     iso->SetObjectGroupId(g1s1.handle, id1);
   4127     iso->SetObjectGroupId(g1s2.handle, id1);
   4128     iso->SetReferenceFromGroup(id1, g2s1.handle);
   4129     iso->SetObjectGroupId(g2s1.handle, id2);
   4130     iso->SetObjectGroupId(g2s2.handle, id2);
   4131     iso->SetReferenceFromGroup(id2, g3s1.handle);
   4132     iso->SetObjectGroupId(g3s1.handle, id3);
   4133     iso->SetObjectGroupId(g3s2.handle, id3);
   4134     iso->SetReferenceFromGroup(id3, g4s1.handle);
   4135     iso->SetObjectGroupId(g4s1.handle, id4);
   4136     iso->SetObjectGroupId(g4s2.handle, id4);
   4137     iso->SetReferenceFromGroup(id4, g1s1.handle);
   4138   }
   4139 
   4140   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   4141 
   4142   // All objects should be gone. 9 global handles in total.
   4143   CHECK_EQ(9, counter.NumberOfWeakCalls());
   4144 }
   4145 
   4146 
   4147 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
   4148 // on the buildbots, so was made non-threaded for the time being.
   4149 TEST(ApiObjectGroupsCycleForScavenger) {
   4150   i::FLAG_stress_compaction = false;
   4151   i::FLAG_gc_global = false;
   4152   LocalContext env;
   4153   v8::Isolate* iso = env->GetIsolate();
   4154   HandleScope scope(iso);
   4155 
   4156   WeakCallCounter counter(1234);
   4157 
   4158   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   4159   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   4160   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   4161   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   4162   WeakCallCounterAndPersistent<Value> g3s1(&counter);
   4163   WeakCallCounterAndPersistent<Value> g3s2(&counter);
   4164 
   4165   {
   4166     HandleScope scope(iso);
   4167     g1s1.handle.Reset(iso, Object::New(iso));
   4168     g1s2.handle.Reset(iso, Object::New(iso));
   4169     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   4170     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   4171 
   4172     g2s1.handle.Reset(iso, Object::New(iso));
   4173     g2s2.handle.Reset(iso, Object::New(iso));
   4174     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   4175     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   4176 
   4177     g3s1.handle.Reset(iso, Object::New(iso));
   4178     g3s2.handle.Reset(iso, Object::New(iso));
   4179     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
   4180     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
   4181   }
   4182 
   4183   // Make a root.
   4184   WeakCallCounterAndPersistent<Value> root(&counter);
   4185   root.handle.Reset(iso, g1s1.handle);
   4186   root.handle.MarkPartiallyDependent();
   4187 
   4188   // Connect groups.  We're building the following cycle:
   4189   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
   4190   // groups.
   4191   {
   4192     HandleScope handle_scope(iso);
   4193     g1s1.handle.MarkPartiallyDependent();
   4194     g1s2.handle.MarkPartiallyDependent();
   4195     g2s1.handle.MarkPartiallyDependent();
   4196     g2s2.handle.MarkPartiallyDependent();
   4197     g3s1.handle.MarkPartiallyDependent();
   4198     g3s2.handle.MarkPartiallyDependent();
   4199     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
   4200     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
   4201     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
   4202         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
   4203     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
   4204     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
   4205     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
   4206         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
   4207     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
   4208     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
   4209     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
   4210         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
   4211   }
   4212 
   4213   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   4214       iso)->heap();
   4215   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
   4216 
   4217   // All objects should be alive.
   4218   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4219 
   4220   // Weaken the root.
   4221   root.handle.SetWeak(&root, &WeakPointerCallback);
   4222   root.handle.MarkPartiallyDependent();
   4223 
   4224   // Groups are deleted, rebuild groups.
   4225   {
   4226     HandleScope handle_scope(iso);
   4227     g1s1.handle.MarkPartiallyDependent();
   4228     g1s2.handle.MarkPartiallyDependent();
   4229     g2s1.handle.MarkPartiallyDependent();
   4230     g2s2.handle.MarkPartiallyDependent();
   4231     g3s1.handle.MarkPartiallyDependent();
   4232     g3s2.handle.MarkPartiallyDependent();
   4233     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
   4234     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
   4235     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
   4236         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
   4237     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
   4238     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
   4239     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
   4240         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
   4241     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
   4242     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
   4243     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
   4244         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
   4245   }
   4246 
   4247   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
   4248 
   4249   // All objects should be gone. 7 global handles in total.
   4250   CHECK_EQ(7, counter.NumberOfWeakCalls());
   4251 }
   4252 
   4253 
   4254 THREADED_TEST(ScriptException) {
   4255   LocalContext env;
   4256   v8::HandleScope scope(env->GetIsolate());
   4257   Local<Script> script = v8_compile("throw 'panama!';");
   4258   v8::TryCatch try_catch;
   4259   Local<Value> result = script->Run();
   4260   CHECK(result.IsEmpty());
   4261   CHECK(try_catch.HasCaught());
   4262   String::Utf8Value exception_value(try_catch.Exception());
   4263   CHECK_EQ(*exception_value, "panama!");
   4264 }
   4265 
   4266 
   4267 TEST(TryCatchCustomException) {
   4268   LocalContext env;
   4269   v8::HandleScope scope(env->GetIsolate());
   4270   v8::TryCatch try_catch;
   4271   CompileRun("function CustomError() { this.a = 'b'; }"
   4272              "(function f() { throw new CustomError(); })();");
   4273   CHECK(try_catch.HasCaught());
   4274   CHECK(try_catch.Exception()->ToObject()->
   4275             Get(v8_str("a"))->Equals(v8_str("b")));
   4276 }
   4277 
   4278 
   4279 bool message_received;
   4280 
   4281 
   4282 static void check_message_0(v8::Handle<v8::Message> message,
   4283                             v8::Handle<Value> data) {
   4284   CHECK_EQ(5.76, data->NumberValue());
   4285   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
   4286   CHECK(!message->IsSharedCrossOrigin());
   4287   message_received = true;
   4288 }
   4289 
   4290 
   4291 THREADED_TEST(MessageHandler0) {
   4292   message_received = false;
   4293   v8::HandleScope scope(CcTest::isolate());
   4294   CHECK(!message_received);
   4295   LocalContext context;
   4296   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
   4297   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
   4298   script->Run();
   4299   CHECK(message_received);
   4300   // clear out the message listener
   4301   v8::V8::RemoveMessageListeners(check_message_0);
   4302 }
   4303 
   4304 
   4305 static void check_message_1(v8::Handle<v8::Message> message,
   4306                             v8::Handle<Value> data) {
   4307   CHECK(data->IsNumber());
   4308   CHECK_EQ(1337, data->Int32Value());
   4309   CHECK(!message->IsSharedCrossOrigin());
   4310   message_received = true;
   4311 }
   4312 
   4313 
   4314 TEST(MessageHandler1) {
   4315   message_received = false;
   4316   v8::HandleScope scope(CcTest::isolate());
   4317   CHECK(!message_received);
   4318   v8::V8::AddMessageListener(check_message_1);
   4319   LocalContext context;
   4320   CompileRun("throw 1337;");
   4321   CHECK(message_received);
   4322   // clear out the message listener
   4323   v8::V8::RemoveMessageListeners(check_message_1);
   4324 }
   4325 
   4326 
   4327 static void check_message_2(v8::Handle<v8::Message> message,
   4328                             v8::Handle<Value> data) {
   4329   LocalContext context;
   4330   CHECK(data->IsObject());
   4331   v8::Local<v8::Value> hidden_property =
   4332       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
   4333   CHECK(v8_str("hidden value")->Equals(hidden_property));
   4334   CHECK(!message->IsSharedCrossOrigin());
   4335   message_received = true;
   4336 }
   4337 
   4338 
   4339 TEST(MessageHandler2) {
   4340   message_received = false;
   4341   v8::HandleScope scope(CcTest::isolate());
   4342   CHECK(!message_received);
   4343   v8::V8::AddMessageListener(check_message_2);
   4344   LocalContext context;
   4345   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
   4346   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
   4347                                            v8_str("hidden value"));
   4348   context->Global()->Set(v8_str("error"), error);
   4349   CompileRun("throw error;");
   4350   CHECK(message_received);
   4351   // clear out the message listener
   4352   v8::V8::RemoveMessageListeners(check_message_2);
   4353 }
   4354 
   4355 
   4356 static void check_message_3(v8::Handle<v8::Message> message,
   4357                             v8::Handle<Value> data) {
   4358   CHECK(message->IsSharedCrossOrigin());
   4359   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
   4360   message_received = true;
   4361 }
   4362 
   4363 
   4364 TEST(MessageHandler3) {
   4365   message_received = false;
   4366   v8::Isolate* isolate = CcTest::isolate();
   4367   v8::HandleScope scope(isolate);
   4368   CHECK(!message_received);
   4369   v8::V8::AddMessageListener(check_message_3);
   4370   LocalContext context;
   4371   v8::ScriptOrigin origin =
   4372       v8::ScriptOrigin(v8_str("6.75"),
   4373                        v8::Integer::New(isolate, 1),
   4374                        v8::Integer::New(isolate, 2),
   4375                        v8::True(isolate));
   4376   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   4377                                                   &origin);
   4378   script->Run();
   4379   CHECK(message_received);
   4380   // clear out the message listener
   4381   v8::V8::RemoveMessageListeners(check_message_3);
   4382 }
   4383 
   4384 
   4385 static void check_message_4(v8::Handle<v8::Message> message,
   4386                             v8::Handle<Value> data) {
   4387   CHECK(!message->IsSharedCrossOrigin());
   4388   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
   4389   message_received = true;
   4390 }
   4391 
   4392 
   4393 TEST(MessageHandler4) {
   4394   message_received = false;
   4395   v8::Isolate* isolate = CcTest::isolate();
   4396   v8::HandleScope scope(isolate);
   4397   CHECK(!message_received);
   4398   v8::V8::AddMessageListener(check_message_4);
   4399   LocalContext context;
   4400   v8::ScriptOrigin origin =
   4401       v8::ScriptOrigin(v8_str("6.75"),
   4402                        v8::Integer::New(isolate, 1),
   4403                        v8::Integer::New(isolate, 2),
   4404                        v8::False(isolate));
   4405   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   4406                                                   &origin);
   4407   script->Run();
   4408   CHECK(message_received);
   4409   // clear out the message listener
   4410   v8::V8::RemoveMessageListeners(check_message_4);
   4411 }
   4412 
   4413 
   4414 static void check_message_5a(v8::Handle<v8::Message> message,
   4415                             v8::Handle<Value> data) {
   4416   CHECK(message->IsSharedCrossOrigin());
   4417   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
   4418   message_received = true;
   4419 }
   4420 
   4421 
   4422 static void check_message_5b(v8::Handle<v8::Message> message,
   4423                             v8::Handle<Value> data) {
   4424   CHECK(!message->IsSharedCrossOrigin());
   4425   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
   4426   message_received = true;
   4427 }
   4428 
   4429 
   4430 TEST(MessageHandler5) {
   4431   message_received = false;
   4432   v8::Isolate* isolate = CcTest::isolate();
   4433   v8::HandleScope scope(isolate);
   4434   CHECK(!message_received);
   4435   v8::V8::AddMessageListener(check_message_5a);
   4436   LocalContext context;
   4437   v8::ScriptOrigin origin =
   4438       v8::ScriptOrigin(v8_str("6.75"),
   4439                        v8::Integer::New(isolate, 1),
   4440                        v8::Integer::New(isolate, 2),
   4441                        v8::True(isolate));
   4442   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   4443                                                   &origin);
   4444   script->Run();
   4445   CHECK(message_received);
   4446   // clear out the message listener
   4447   v8::V8::RemoveMessageListeners(check_message_5a);
   4448 
   4449   message_received = false;
   4450   v8::V8::AddMessageListener(check_message_5b);
   4451   origin =
   4452       v8::ScriptOrigin(v8_str("6.75"),
   4453                        v8::Integer::New(isolate, 1),
   4454                        v8::Integer::New(isolate, 2),
   4455                        v8::False(isolate));
   4456   script = Script::Compile(v8_str("throw 'error'"),
   4457                            &origin);
   4458   script->Run();
   4459   CHECK(message_received);
   4460   // clear out the message listener
   4461   v8::V8::RemoveMessageListeners(check_message_5b);
   4462 }
   4463 
   4464 
   4465 THREADED_TEST(GetSetProperty) {
   4466   LocalContext context;
   4467   v8::Isolate* isolate = context->GetIsolate();
   4468   v8::HandleScope scope(isolate);
   4469   context->Global()->Set(v8_str("foo"), v8_num(14));
   4470   context->Global()->Set(v8_str("12"), v8_num(92));
   4471   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
   4472   context->Global()->Set(v8_num(13), v8_num(56));
   4473   Local<Value> foo = CompileRun("this.foo");
   4474   CHECK_EQ(14, foo->Int32Value());
   4475   Local<Value> twelve = CompileRun("this[12]");
   4476   CHECK_EQ(92, twelve->Int32Value());
   4477   Local<Value> sixteen = CompileRun("this[16]");
   4478   CHECK_EQ(32, sixteen->Int32Value());
   4479   Local<Value> thirteen = CompileRun("this[13]");
   4480   CHECK_EQ(56, thirteen->Int32Value());
   4481   CHECK_EQ(92,
   4482            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
   4483   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
   4484   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
   4485   CHECK_EQ(32,
   4486            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
   4487   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
   4488   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
   4489   CHECK_EQ(56,
   4490            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
   4491   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
   4492   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
   4493 }
   4494 
   4495 
   4496 THREADED_TEST(PropertyAttributes) {
   4497   LocalContext context;
   4498   v8::HandleScope scope(context->GetIsolate());
   4499   // none
   4500   Local<String> prop = v8_str("none");
   4501   context->Global()->Set(prop, v8_num(7));
   4502   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
   4503   // read-only
   4504   prop = v8_str("read_only");
   4505   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
   4506   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   4507   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
   4508   CompileRun("read_only = 9");
   4509   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   4510   context->Global()->Set(prop, v8_num(10));
   4511   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   4512   // dont-delete
   4513   prop = v8_str("dont_delete");
   4514   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
   4515   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   4516   CompileRun("delete dont_delete");
   4517   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   4518   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
   4519   // dont-enum
   4520   prop = v8_str("dont_enum");
   4521   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
   4522   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
   4523   // absent
   4524   prop = v8_str("absent");
   4525   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
   4526   Local<Value> fake_prop = v8_num(1);
   4527   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
   4528   // exception
   4529   TryCatch try_catch;
   4530   Local<Value> exception =
   4531       CompileRun("({ toString: function() { throw 'exception';} })");
   4532   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
   4533   CHECK(try_catch.HasCaught());
   4534   String::Utf8Value exception_value(try_catch.Exception());
   4535   CHECK_EQ("exception", *exception_value);
   4536   try_catch.Reset();
   4537 }
   4538 
   4539 
   4540 THREADED_TEST(Array) {
   4541   LocalContext context;
   4542   v8::HandleScope scope(context->GetIsolate());
   4543   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
   4544   CHECK_EQ(0, array->Length());
   4545   CHECK(array->Get(0)->IsUndefined());
   4546   CHECK(!array->Has(0));
   4547   CHECK(array->Get(100)->IsUndefined());
   4548   CHECK(!array->Has(100));
   4549   array->Set(2, v8_num(7));
   4550   CHECK_EQ(3, array->Length());
   4551   CHECK(!array->Has(0));
   4552   CHECK(!array->Has(1));
   4553   CHECK(array->Has(2));
   4554   CHECK_EQ(7, array->Get(2)->Int32Value());
   4555   Local<Value> obj = CompileRun("[1, 2, 3]");
   4556   Local<v8::Array> arr = obj.As<v8::Array>();
   4557   CHECK_EQ(3, arr->Length());
   4558   CHECK_EQ(1, arr->Get(0)->Int32Value());
   4559   CHECK_EQ(2, arr->Get(1)->Int32Value());
   4560   CHECK_EQ(3, arr->Get(2)->Int32Value());
   4561   array = v8::Array::New(context->GetIsolate(), 27);
   4562   CHECK_EQ(27, array->Length());
   4563   array = v8::Array::New(context->GetIsolate(), -27);
   4564   CHECK_EQ(0, array->Length());
   4565 }
   4566 
   4567 
   4568 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4569   v8::EscapableHandleScope scope(args.GetIsolate());
   4570   ApiTestFuzzer::Fuzz();
   4571   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
   4572   for (int i = 0; i < args.Length(); i++)
   4573     result->Set(i, args[i]);
   4574   args.GetReturnValue().Set(scope.Escape(result));
   4575 }
   4576 
   4577 
   4578 THREADED_TEST(Vector) {
   4579   v8::Isolate* isolate = CcTest::isolate();
   4580   v8::HandleScope scope(isolate);
   4581   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
   4582   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
   4583   LocalContext context(0, global);
   4584 
   4585   const char* fun = "f()";
   4586   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
   4587   CHECK_EQ(0, a0->Length());
   4588 
   4589   const char* fun2 = "f(11)";
   4590   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
   4591   CHECK_EQ(1, a1->Length());
   4592   CHECK_EQ(11, a1->Get(0)->Int32Value());
   4593 
   4594   const char* fun3 = "f(12, 13)";
   4595   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
   4596   CHECK_EQ(2, a2->Length());
   4597   CHECK_EQ(12, a2->Get(0)->Int32Value());
   4598   CHECK_EQ(13, a2->Get(1)->Int32Value());
   4599 
   4600   const char* fun4 = "f(14, 15, 16)";
   4601   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
   4602   CHECK_EQ(3, a3->Length());
   4603   CHECK_EQ(14, a3->Get(0)->Int32Value());
   4604   CHECK_EQ(15, a3->Get(1)->Int32Value());
   4605   CHECK_EQ(16, a3->Get(2)->Int32Value());
   4606 
   4607   const char* fun5 = "f(17, 18, 19, 20)";
   4608   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
   4609   CHECK_EQ(4, a4->Length());
   4610   CHECK_EQ(17, a4->Get(0)->Int32Value());
   4611   CHECK_EQ(18, a4->Get(1)->Int32Value());
   4612   CHECK_EQ(19, a4->Get(2)->Int32Value());
   4613   CHECK_EQ(20, a4->Get(3)->Int32Value());
   4614 }
   4615 
   4616 
   4617 THREADED_TEST(FunctionCall) {
   4618   LocalContext context;
   4619   v8::Isolate* isolate = context->GetIsolate();
   4620   v8::HandleScope scope(isolate);
   4621   CompileRun(
   4622     "function Foo() {"
   4623     "  var result = [];"
   4624     "  for (var i = 0; i < arguments.length; i++) {"
   4625     "    result.push(arguments[i]);"
   4626     "  }"
   4627     "  return result;"
   4628     "}"
   4629     "function ReturnThisSloppy() {"
   4630     "  return this;"
   4631     "}"
   4632     "function ReturnThisStrict() {"
   4633     "  'use strict';"
   4634     "  return this;"
   4635     "}");
   4636   Local<Function> Foo =
   4637       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   4638   Local<Function> ReturnThisSloppy =
   4639       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
   4640   Local<Function> ReturnThisStrict =
   4641       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
   4642 
   4643   v8::Handle<Value>* args0 = NULL;
   4644   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
   4645   CHECK_EQ(0, a0->Length());
   4646 
   4647   v8::Handle<Value> args1[] = { v8_num(1.1) };
   4648   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
   4649   CHECK_EQ(1, a1->Length());
   4650   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4651 
   4652   v8::Handle<Value> args2[] = { v8_num(2.2),
   4653                                 v8_num(3.3) };
   4654   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
   4655   CHECK_EQ(2, a2->Length());
   4656   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4657   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4658 
   4659   v8::Handle<Value> args3[] = { v8_num(4.4),
   4660                                 v8_num(5.5),
   4661                                 v8_num(6.6) };
   4662   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
   4663   CHECK_EQ(3, a3->Length());
   4664   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4665   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4666   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4667 
   4668   v8::Handle<Value> args4[] = { v8_num(7.7),
   4669                                 v8_num(8.8),
   4670                                 v8_num(9.9),
   4671                                 v8_num(10.11) };
   4672   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
   4673   CHECK_EQ(4, a4->Length());
   4674   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4675   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4676   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4677   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
   4678 
   4679   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
   4680   CHECK(r1->StrictEquals(context->Global()));
   4681   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
   4682   CHECK(r2->StrictEquals(context->Global()));
   4683   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
   4684   CHECK(r3->IsNumberObject());
   4685   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
   4686   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
   4687   CHECK(r4->IsStringObject());
   4688   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
   4689   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
   4690   CHECK(r5->IsBooleanObject());
   4691   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
   4692 
   4693   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
   4694   CHECK(r6->IsUndefined());
   4695   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
   4696   CHECK(r7->IsNull());
   4697   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
   4698   CHECK(r8->StrictEquals(v8_num(42)));
   4699   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
   4700   CHECK(r9->StrictEquals(v8_str("hello")));
   4701   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
   4702   CHECK(r10->StrictEquals(v8::True(isolate)));
   4703 }
   4704 
   4705 
   4706 THREADED_TEST(ConstructCall) {
   4707   LocalContext context;
   4708   v8::Isolate* isolate = context->GetIsolate();
   4709   v8::HandleScope scope(isolate);
   4710   CompileRun(
   4711     "function Foo() {"
   4712     "  var result = [];"
   4713     "  for (var i = 0; i < arguments.length; i++) {"
   4714     "    result.push(arguments[i]);"
   4715     "  }"
   4716     "  return result;"
   4717     "}");
   4718   Local<Function> Foo =
   4719       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   4720 
   4721   v8::Handle<Value>* args0 = NULL;
   4722   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
   4723   CHECK_EQ(0, a0->Length());
   4724 
   4725   v8::Handle<Value> args1[] = { v8_num(1.1) };
   4726   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
   4727   CHECK_EQ(1, a1->Length());
   4728   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4729 
   4730   v8::Handle<Value> args2[] = { v8_num(2.2),
   4731                                 v8_num(3.3) };
   4732   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
   4733   CHECK_EQ(2, a2->Length());
   4734   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4735   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4736 
   4737   v8::Handle<Value> args3[] = { v8_num(4.4),
   4738                                 v8_num(5.5),
   4739                                 v8_num(6.6) };
   4740   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
   4741   CHECK_EQ(3, a3->Length());
   4742   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4743   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4744   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4745 
   4746   v8::Handle<Value> args4[] = { v8_num(7.7),
   4747                                 v8_num(8.8),
   4748                                 v8_num(9.9),
   4749                                 v8_num(10.11) };
   4750   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
   4751   CHECK_EQ(4, a4->Length());
   4752   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4753   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4754   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4755   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
   4756 }
   4757 
   4758 
   4759 static void CheckUncle(v8::TryCatch* try_catch) {
   4760   CHECK(try_catch->HasCaught());
   4761   String::Utf8Value str_value(try_catch->Exception());
   4762   CHECK_EQ(*str_value, "uncle?");
   4763   try_catch->Reset();
   4764 }
   4765 
   4766 
   4767 THREADED_TEST(ConversionNumber) {
   4768   LocalContext env;
   4769   v8::HandleScope scope(env->GetIsolate());
   4770   // Very large number.
   4771   CompileRun("var obj = Math.pow(2,32) * 1237;");
   4772   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   4773   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
   4774   CHECK_EQ(0, obj->ToInt32()->Value());
   4775   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
   4776   // Large number.
   4777   CompileRun("var obj = -1234567890123;");
   4778   obj = env->Global()->Get(v8_str("obj"));
   4779   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
   4780   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
   4781   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
   4782   // Small positive integer.
   4783   CompileRun("var obj = 42;");
   4784   obj = env->Global()->Get(v8_str("obj"));
   4785   CHECK_EQ(42.0, obj->ToNumber()->Value());
   4786   CHECK_EQ(42, obj->ToInt32()->Value());
   4787   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
   4788   // Negative integer.
   4789   CompileRun("var obj = -37;");
   4790   obj = env->Global()->Get(v8_str("obj"));
   4791   CHECK_EQ(-37.0, obj->ToNumber()->Value());
   4792   CHECK_EQ(-37, obj->ToInt32()->Value());
   4793   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
   4794   // Positive non-int32 integer.
   4795   CompileRun("var obj = 0x81234567;");
   4796   obj = env->Global()->Get(v8_str("obj"));
   4797   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
   4798   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
   4799   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
   4800   // Fraction.
   4801   CompileRun("var obj = 42.3;");
   4802   obj = env->Global()->Get(v8_str("obj"));
   4803   CHECK_EQ(42.3, obj->ToNumber()->Value());
   4804   CHECK_EQ(42, obj->ToInt32()->Value());
   4805   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
   4806   // Large negative fraction.
   4807   CompileRun("var obj = -5726623061.75;");
   4808   obj = env->Global()->Get(v8_str("obj"));
   4809   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
   4810   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
   4811   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
   4812 }
   4813 
   4814 
   4815 THREADED_TEST(isNumberType) {
   4816   LocalContext env;
   4817   v8::HandleScope scope(env->GetIsolate());
   4818   // Very large number.
   4819   CompileRun("var obj = Math.pow(2,32) * 1237;");
   4820   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   4821   CHECK(!obj->IsInt32());
   4822   CHECK(!obj->IsUint32());
   4823   // Large negative number.
   4824   CompileRun("var obj = -1234567890123;");
   4825   obj = env->Global()->Get(v8_str("obj"));
   4826   CHECK(!obj->IsInt32());
   4827   CHECK(!obj->IsUint32());
   4828   // Small positive integer.
   4829   CompileRun("var obj = 42;");
   4830   obj = env->Global()->Get(v8_str("obj"));
   4831   CHECK(obj->IsInt32());
   4832   CHECK(obj->IsUint32());
   4833   // Negative integer.
   4834   CompileRun("var obj = -37;");
   4835   obj = env->Global()->Get(v8_str("obj"));
   4836   CHECK(obj->IsInt32());
   4837   CHECK(!obj->IsUint32());
   4838   // Positive non-int32 integer.
   4839   CompileRun("var obj = 0x81234567;");
   4840   obj = env->Global()->Get(v8_str("obj"));
   4841   CHECK(!obj->IsInt32());
   4842   CHECK(obj->IsUint32());
   4843   // Fraction.
   4844   CompileRun("var obj = 42.3;");
   4845   obj = env->Global()->Get(v8_str("obj"));
   4846   CHECK(!obj->IsInt32());
   4847   CHECK(!obj->IsUint32());
   4848   // Large negative fraction.
   4849   CompileRun("var obj = -5726623061.75;");
   4850   obj = env->Global()->Get(v8_str("obj"));
   4851   CHECK(!obj->IsInt32());
   4852   CHECK(!obj->IsUint32());
   4853   // Positive zero
   4854   CompileRun("var obj = 0.0;");
   4855   obj = env->Global()->Get(v8_str("obj"));
   4856   CHECK(obj->IsInt32());
   4857   CHECK(obj->IsUint32());
   4858   // Positive zero
   4859   CompileRun("var obj = -0.0;");
   4860   obj = env->Global()->Get(v8_str("obj"));
   4861   CHECK(!obj->IsInt32());
   4862   CHECK(!obj->IsUint32());
   4863 }
   4864 
   4865 
   4866 THREADED_TEST(ConversionException) {
   4867   LocalContext env;
   4868   v8::Isolate* isolate = env->GetIsolate();
   4869   v8::HandleScope scope(isolate);
   4870   CompileRun(
   4871     "function TestClass() { };"
   4872     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
   4873     "var obj = new TestClass();");
   4874   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   4875 
   4876   v8::TryCatch try_catch;
   4877 
   4878   Local<Value> to_string_result = obj->ToString();
   4879   CHECK(to_string_result.IsEmpty());
   4880   CheckUncle(&try_catch);
   4881 
   4882   Local<Value> to_number_result = obj->ToNumber();
   4883   CHECK(to_number_result.IsEmpty());
   4884   CheckUncle(&try_catch);
   4885 
   4886   Local<Value> to_integer_result = obj->ToInteger();
   4887   CHECK(to_integer_result.IsEmpty());
   4888   CheckUncle(&try_catch);
   4889 
   4890   Local<Value> to_uint32_result = obj->ToUint32();
   4891   CHECK(to_uint32_result.IsEmpty());
   4892   CheckUncle(&try_catch);
   4893 
   4894   Local<Value> to_int32_result = obj->ToInt32();
   4895   CHECK(to_int32_result.IsEmpty());
   4896   CheckUncle(&try_catch);
   4897 
   4898   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
   4899   CHECK(to_object_result.IsEmpty());
   4900   CHECK(try_catch.HasCaught());
   4901   try_catch.Reset();
   4902 
   4903   int32_t int32_value = obj->Int32Value();
   4904   CHECK_EQ(0, int32_value);
   4905   CheckUncle(&try_catch);
   4906 
   4907   uint32_t uint32_value = obj->Uint32Value();
   4908   CHECK_EQ(0, uint32_value);
   4909   CheckUncle(&try_catch);
   4910 
   4911   double number_value = obj->NumberValue();
   4912   CHECK_NE(0, std::isnan(number_value));
   4913   CheckUncle(&try_catch);
   4914 
   4915   int64_t integer_value = obj->IntegerValue();
   4916   CHECK_EQ(0.0, static_cast<double>(integer_value));
   4917   CheckUncle(&try_catch);
   4918 }
   4919 
   4920 
   4921 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4922   ApiTestFuzzer::Fuzz();
   4923   args.GetIsolate()->ThrowException(v8_str("konto"));
   4924 }
   4925 
   4926 
   4927 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4928   if (args.Length() < 1) {
   4929     args.GetReturnValue().Set(false);
   4930     return;
   4931   }
   4932   v8::HandleScope scope(args.GetIsolate());
   4933   v8::TryCatch try_catch;
   4934   Local<Value> result = CompileRun(args[0]->ToString());
   4935   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   4936   args.GetReturnValue().Set(try_catch.HasCaught());
   4937 }
   4938 
   4939 
   4940 THREADED_TEST(APICatch) {
   4941   v8::Isolate* isolate = CcTest::isolate();
   4942   v8::HandleScope scope(isolate);
   4943   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4944   templ->Set(v8_str("ThrowFromC"),
   4945              v8::FunctionTemplate::New(isolate, ThrowFromC));
   4946   LocalContext context(0, templ);
   4947   CompileRun(
   4948     "var thrown = false;"
   4949     "try {"
   4950     "  ThrowFromC();"
   4951     "} catch (e) {"
   4952     "  thrown = true;"
   4953     "}");
   4954   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
   4955   CHECK(thrown->BooleanValue());
   4956 }
   4957 
   4958 
   4959 THREADED_TEST(APIThrowTryCatch) {
   4960   v8::Isolate* isolate = CcTest::isolate();
   4961   v8::HandleScope scope(isolate);
   4962   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4963   templ->Set(v8_str("ThrowFromC"),
   4964              v8::FunctionTemplate::New(isolate, ThrowFromC));
   4965   LocalContext context(0, templ);
   4966   v8::TryCatch try_catch;
   4967   CompileRun("ThrowFromC();");
   4968   CHECK(try_catch.HasCaught());
   4969 }
   4970 
   4971 
   4972 // Test that a try-finally block doesn't shadow a try-catch block
   4973 // when setting up an external handler.
   4974 //
   4975 // BUG(271): Some of the exception propagation does not work on the
   4976 // ARM simulator because the simulator separates the C++ stack and the
   4977 // JS stack.  This test therefore fails on the simulator.  The test is
   4978 // not threaded to allow the threading tests to run on the simulator.
   4979 TEST(TryCatchInTryFinally) {
   4980   v8::Isolate* isolate = CcTest::isolate();
   4981   v8::HandleScope scope(isolate);
   4982   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4983   templ->Set(v8_str("CCatcher"),
   4984              v8::FunctionTemplate::New(isolate, CCatcher));
   4985   LocalContext context(0, templ);
   4986   Local<Value> result = CompileRun("try {"
   4987                                    "  try {"
   4988                                    "    CCatcher('throw 7;');"
   4989                                    "  } finally {"
   4990                                    "  }"
   4991                                    "} catch (e) {"
   4992                                    "}");
   4993   CHECK(result->IsTrue());
   4994 }
   4995 
   4996 
   4997 static void check_reference_error_message(
   4998     v8::Handle<v8::Message> message,
   4999     v8::Handle<v8::Value> data) {
   5000   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
   5001   CHECK(message->Get()->Equals(v8_str(reference_error)));
   5002 }
   5003 
   5004 
   5005 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5006   ApiTestFuzzer::Fuzz();
   5007   CHECK(false);
   5008 }
   5009 
   5010 
   5011 // Test that overwritten methods are not invoked on uncaught exception
   5012 // formatting. However, they are invoked when performing normal error
   5013 // string conversions.
   5014 TEST(APIThrowMessageOverwrittenToString) {
   5015   v8::Isolate* isolate = CcTest::isolate();
   5016   v8::HandleScope scope(isolate);
   5017   v8::V8::AddMessageListener(check_reference_error_message);
   5018   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5019   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
   5020   LocalContext context(NULL, templ);
   5021   CompileRun("asdf;");
   5022   CompileRun("var limit = {};"
   5023              "limit.valueOf = fail;"
   5024              "Error.stackTraceLimit = limit;");
   5025   CompileRun("asdf");
   5026   CompileRun("Array.prototype.pop = fail;");
   5027   CompileRun("Object.prototype.hasOwnProperty = fail;");
   5028   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
   5029   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
   5030   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
   5031   CompileRun("ReferenceError.prototype.toString ="
   5032              "  function() { return 'Whoops' }");
   5033   CompileRun("asdf;");
   5034   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
   5035   CompileRun("asdf;");
   5036   CompileRun("ReferenceError.prototype.constructor = void 0;");
   5037   CompileRun("asdf;");
   5038   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
   5039   CompileRun("asdf;");
   5040   CompileRun("ReferenceError.prototype = new Object();");
   5041   CompileRun("asdf;");
   5042   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
   5043   CHECK(string->Equals(v8_str("Whoops")));
   5044   CompileRun("ReferenceError.prototype.constructor = new Object();"
   5045              "ReferenceError.prototype.constructor.name = 1;"
   5046              "Number.prototype.toString = function() { return 'Whoops'; };"
   5047              "ReferenceError.prototype.toString = Object.prototype.toString;");
   5048   CompileRun("asdf;");
   5049   v8::V8::RemoveMessageListeners(check_reference_error_message);
   5050 }
   5051 
   5052 
   5053 static void check_custom_error_tostring(
   5054     v8::Handle<v8::Message> message,
   5055     v8::Handle<v8::Value> data) {
   5056   const char* uncaught_error = "Uncaught MyError toString";
   5057   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
   5058 }
   5059 
   5060 
   5061 TEST(CustomErrorToString) {
   5062   LocalContext context;
   5063   v8::HandleScope scope(context->GetIsolate());
   5064   v8::V8::AddMessageListener(check_custom_error_tostring);
   5065   CompileRun(
   5066     "function MyError(name, message) {                   "
   5067     "  this.name = name;                                 "
   5068     "  this.message = message;                           "
   5069     "}                                                   "
   5070     "MyError.prototype = Object.create(Error.prototype); "
   5071     "MyError.prototype.toString = function() {           "
   5072     "  return 'MyError toString';                        "
   5073     "};                                                  "
   5074     "throw new MyError('my name', 'my message');         ");
   5075   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
   5076 }
   5077 
   5078 
   5079 static void check_custom_error_message(
   5080     v8::Handle<v8::Message> message,
   5081     v8::Handle<v8::Value> data) {
   5082   const char* uncaught_error = "Uncaught MyError: my message";
   5083   printf("%s\n", *v8::String::Utf8Value(message->Get()));
   5084   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
   5085 }
   5086 
   5087 
   5088 TEST(CustomErrorMessage) {
   5089   LocalContext context;
   5090   v8::HandleScope scope(context->GetIsolate());
   5091   v8::V8::AddMessageListener(check_custom_error_message);
   5092 
   5093   // Handlebars.
   5094   CompileRun(
   5095     "function MyError(msg) {                             "
   5096     "  this.name = 'MyError';                            "
   5097     "  this.message = msg;                               "
   5098     "}                                                   "
   5099     "MyError.prototype = new Error();                    "
   5100     "throw new MyError('my message');                    ");
   5101 
   5102   // Closure.
   5103   CompileRun(
   5104     "function MyError(msg) {                             "
   5105     "  this.name = 'MyError';                            "
   5106     "  this.message = msg;                               "
   5107     "}                                                   "
   5108     "inherits = function(childCtor, parentCtor) {        "
   5109     "    function tempCtor() {};                         "
   5110     "    tempCtor.prototype = parentCtor.prototype;      "
   5111     "    childCtor.superClass_ = parentCtor.prototype;   "
   5112     "    childCtor.prototype = new tempCtor();           "
   5113     "    childCtor.prototype.constructor = childCtor;    "
   5114     "};                                                  "
   5115     "inherits(MyError, Error);                           "
   5116     "throw new MyError('my message');                    ");
   5117 
   5118   // Object.create.
   5119   CompileRun(
   5120     "function MyError(msg) {                             "
   5121     "  this.name = 'MyError';                            "
   5122     "  this.message = msg;                               "
   5123     "}                                                   "
   5124     "MyError.prototype = Object.create(Error.prototype); "
   5125     "throw new MyError('my message');                    ");
   5126 
   5127   v8::V8::RemoveMessageListeners(check_custom_error_message);
   5128 }
   5129 
   5130 
   5131 static void receive_message(v8::Handle<v8::Message> message,
   5132                             v8::Handle<v8::Value> data) {
   5133   message->Get();
   5134   message_received = true;
   5135 }
   5136 
   5137 
   5138 TEST(APIThrowMessage) {
   5139   message_received = false;
   5140   v8::Isolate* isolate = CcTest::isolate();
   5141   v8::HandleScope scope(isolate);
   5142   v8::V8::AddMessageListener(receive_message);
   5143   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5144   templ->Set(v8_str("ThrowFromC"),
   5145              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5146   LocalContext context(0, templ);
   5147   CompileRun("ThrowFromC();");
   5148   CHECK(message_received);
   5149   v8::V8::RemoveMessageListeners(receive_message);
   5150 }
   5151 
   5152 
   5153 TEST(APIThrowMessageAndVerboseTryCatch) {
   5154   message_received = false;
   5155   v8::Isolate* isolate = CcTest::isolate();
   5156   v8::HandleScope scope(isolate);
   5157   v8::V8::AddMessageListener(receive_message);
   5158   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5159   templ->Set(v8_str("ThrowFromC"),
   5160              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5161   LocalContext context(0, templ);
   5162   v8::TryCatch try_catch;
   5163   try_catch.SetVerbose(true);
   5164   Local<Value> result = CompileRun("ThrowFromC();");
   5165   CHECK(try_catch.HasCaught());
   5166   CHECK(result.IsEmpty());
   5167   CHECK(message_received);
   5168   v8::V8::RemoveMessageListeners(receive_message);
   5169 }
   5170 
   5171 
   5172 TEST(APIStackOverflowAndVerboseTryCatch) {
   5173   message_received = false;
   5174   LocalContext context;
   5175   v8::HandleScope scope(context->GetIsolate());
   5176   v8::V8::AddMessageListener(receive_message);
   5177   v8::TryCatch try_catch;
   5178   try_catch.SetVerbose(true);
   5179   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
   5180   CHECK(try_catch.HasCaught());
   5181   CHECK(result.IsEmpty());
   5182   CHECK(message_received);
   5183   v8::V8::RemoveMessageListeners(receive_message);
   5184 }
   5185 
   5186 
   5187 THREADED_TEST(ExternalScriptException) {
   5188   v8::Isolate* isolate = CcTest::isolate();
   5189   v8::HandleScope scope(isolate);
   5190   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5191   templ->Set(v8_str("ThrowFromC"),
   5192              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5193   LocalContext context(0, templ);
   5194 
   5195   v8::TryCatch try_catch;
   5196   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
   5197   CHECK(result.IsEmpty());
   5198   CHECK(try_catch.HasCaught());
   5199   String::Utf8Value exception_value(try_catch.Exception());
   5200   CHECK_EQ("konto", *exception_value);
   5201 }
   5202 
   5203 
   5204 
   5205 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5206   ApiTestFuzzer::Fuzz();
   5207   CHECK_EQ(4, args.Length());
   5208   int count = args[0]->Int32Value();
   5209   int cInterval = args[2]->Int32Value();
   5210   if (count == 0) {
   5211     args.GetIsolate()->ThrowException(v8_str("FromC"));
   5212     return;
   5213   } else {
   5214     Local<v8::Object> global =
   5215         args.GetIsolate()->GetCurrentContext()->Global();
   5216     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
   5217     v8::Handle<Value> argv[] = { v8_num(count - 1),
   5218                                  args[1],
   5219                                  args[2],
   5220                                  args[3] };
   5221     if (count % cInterval == 0) {
   5222       v8::TryCatch try_catch;
   5223       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
   5224       int expected = args[3]->Int32Value();
   5225       if (try_catch.HasCaught()) {
   5226         CHECK_EQ(expected, count);
   5227         CHECK(result.IsEmpty());
   5228         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
   5229       } else {
   5230         CHECK_NE(expected, count);
   5231       }
   5232       args.GetReturnValue().Set(result);
   5233       return;
   5234     } else {
   5235       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
   5236       return;
   5237     }
   5238   }
   5239 }
   5240 
   5241 
   5242 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5243   ApiTestFuzzer::Fuzz();
   5244   CHECK_EQ(3, args.Length());
   5245   bool equality = args[0]->BooleanValue();
   5246   int count = args[1]->Int32Value();
   5247   int expected = args[2]->Int32Value();
   5248   if (equality) {
   5249     CHECK_EQ(count, expected);
   5250   } else {
   5251     CHECK_NE(count, expected);
   5252   }
   5253 }
   5254 
   5255 
   5256 THREADED_TEST(EvalInTryFinally) {
   5257   LocalContext context;
   5258   v8::HandleScope scope(context->GetIsolate());
   5259   v8::TryCatch try_catch;
   5260   CompileRun("(function() {"
   5261              "  try {"
   5262              "    eval('asldkf (*&^&*^');"
   5263              "  } finally {"
   5264              "    return;"
   5265              "  }"
   5266              "})()");
   5267   CHECK(!try_catch.HasCaught());
   5268 }
   5269 
   5270 
   5271 // This test works by making a stack of alternating JavaScript and C
   5272 // activations.  These activations set up exception handlers with regular
   5273 // intervals, one interval for C activations and another for JavaScript
   5274 // activations.  When enough activations have been created an exception is
   5275 // thrown and we check that the right activation catches the exception and that
   5276 // no other activations do.  The right activation is always the topmost one with
   5277 // a handler, regardless of whether it is in JavaScript or C.
   5278 //
   5279 // The notation used to describe a test case looks like this:
   5280 //
   5281 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
   5282 //
   5283 // Each entry is an activation, either JS or C.  The index is the count at that
   5284 // level.  Stars identify activations with exception handlers, the @ identifies
   5285 // the exception handler that should catch the exception.
   5286 //
   5287 // BUG(271): Some of the exception propagation does not work on the
   5288 // ARM simulator because the simulator separates the C++ stack and the
   5289 // JS stack.  This test therefore fails on the simulator.  The test is
   5290 // not threaded to allow the threading tests to run on the simulator.
   5291 TEST(ExceptionOrder) {
   5292   v8::Isolate* isolate = CcTest::isolate();
   5293   v8::HandleScope scope(isolate);
   5294   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5295   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
   5296   templ->Set(v8_str("CThrowCountDown"),
   5297              v8::FunctionTemplate::New(isolate, CThrowCountDown));
   5298   LocalContext context(0, templ);
   5299   CompileRun(
   5300     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
   5301     "  if (count == 0) throw 'FromJS';"
   5302     "  if (count % jsInterval == 0) {"
   5303     "    try {"
   5304     "      var value = CThrowCountDown(count - 1,"
   5305     "                                  jsInterval,"
   5306     "                                  cInterval,"
   5307     "                                  expected);"
   5308     "      check(false, count, expected);"
   5309     "      return value;"
   5310     "    } catch (e) {"
   5311     "      check(true, count, expected);"
   5312     "    }"
   5313     "  } else {"
   5314     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
   5315     "  }"
   5316     "}");
   5317   Local<Function> fun =
   5318       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
   5319 
   5320   const int argc = 4;
   5321   //                             count      jsInterval cInterval  expected
   5322 
   5323   // *JS[4] *C[3] @JS[2] C[1] JS[0]
   5324   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
   5325   fun->Call(fun, argc, a0);
   5326 
   5327   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
   5328   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
   5329   fun->Call(fun, argc, a1);
   5330 
   5331   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
   5332   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
   5333   fun->Call(fun, argc, a2);
   5334 
   5335   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
   5336   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
   5337   fun->Call(fun, argc, a3);
   5338 
   5339   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
   5340   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
   5341   fun->Call(fun, argc, a4);
   5342 
   5343   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
   5344   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
   5345   fun->Call(fun, argc, a5);
   5346 }
   5347 
   5348 
   5349 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5350   ApiTestFuzzer::Fuzz();
   5351   CHECK_EQ(1, args.Length());
   5352   args.GetIsolate()->ThrowException(args[0]);
   5353 }
   5354 
   5355 
   5356 THREADED_TEST(ThrowValues) {
   5357   v8::Isolate* isolate = CcTest::isolate();
   5358   v8::HandleScope scope(isolate);
   5359   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5360   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
   5361   LocalContext context(0, templ);
   5362   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   5363     "function Run(obj) {"
   5364     "  try {"
   5365     "    Throw(obj);"
   5366     "  } catch (e) {"
   5367     "    return e;"
   5368     "  }"
   5369     "  return 'no exception';"
   5370     "}"
   5371     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
   5372   CHECK_EQ(5, result->Length());
   5373   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
   5374   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
   5375   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
   5376   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
   5377   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
   5378   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
   5379   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
   5380 }
   5381 
   5382 
   5383 THREADED_TEST(CatchZero) {
   5384   LocalContext context;
   5385   v8::HandleScope scope(context->GetIsolate());
   5386   v8::TryCatch try_catch;
   5387   CHECK(!try_catch.HasCaught());
   5388   CompileRun("throw 10");
   5389   CHECK(try_catch.HasCaught());
   5390   CHECK_EQ(10, try_catch.Exception()->Int32Value());
   5391   try_catch.Reset();
   5392   CHECK(!try_catch.HasCaught());
   5393   CompileRun("throw 0");
   5394   CHECK(try_catch.HasCaught());
   5395   CHECK_EQ(0, try_catch.Exception()->Int32Value());
   5396 }
   5397 
   5398 
   5399 THREADED_TEST(CatchExceptionFromWith) {
   5400   LocalContext context;
   5401   v8::HandleScope scope(context->GetIsolate());
   5402   v8::TryCatch try_catch;
   5403   CHECK(!try_catch.HasCaught());
   5404   CompileRun("var o = {}; with (o) { throw 42; }");
   5405   CHECK(try_catch.HasCaught());
   5406 }
   5407 
   5408 
   5409 THREADED_TEST(TryCatchAndFinallyHidingException) {
   5410   LocalContext context;
   5411   v8::HandleScope scope(context->GetIsolate());
   5412   v8::TryCatch try_catch;
   5413   CHECK(!try_catch.HasCaught());
   5414   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
   5415   CompileRun("f({toString: function() { throw 42; }});");
   5416   CHECK(!try_catch.HasCaught());
   5417 }
   5418 
   5419 
   5420 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5421   v8::TryCatch try_catch;
   5422 }
   5423 
   5424 
   5425 THREADED_TEST(TryCatchAndFinally) {
   5426   LocalContext context;
   5427   v8::Isolate* isolate = context->GetIsolate();
   5428   v8::HandleScope scope(isolate);
   5429   context->Global()->Set(
   5430       v8_str("native_with_try_catch"),
   5431       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
   5432   v8::TryCatch try_catch;
   5433   CHECK(!try_catch.HasCaught());
   5434   CompileRun(
   5435       "try {\n"
   5436       "  throw new Error('a');\n"
   5437       "} finally {\n"
   5438       "  native_with_try_catch();\n"
   5439       "}\n");
   5440   CHECK(try_catch.HasCaught());
   5441 }
   5442 
   5443 
   5444 static void TryCatchNested1Helper(int depth) {
   5445   if (depth > 0) {
   5446     v8::TryCatch try_catch;
   5447     try_catch.SetVerbose(true);
   5448     TryCatchNested1Helper(depth - 1);
   5449     CHECK(try_catch.HasCaught());
   5450     try_catch.ReThrow();
   5451   } else {
   5452     CcTest::isolate()->ThrowException(v8_str("E1"));
   5453   }
   5454 }
   5455 
   5456 
   5457 static void TryCatchNested2Helper(int depth) {
   5458   if (depth > 0) {
   5459     v8::TryCatch try_catch;
   5460     try_catch.SetVerbose(true);
   5461     TryCatchNested2Helper(depth - 1);
   5462     CHECK(try_catch.HasCaught());
   5463     try_catch.ReThrow();
   5464   } else {
   5465     CompileRun("throw 'E2';");
   5466   }
   5467 }
   5468 
   5469 
   5470 TEST(TryCatchNested) {
   5471   v8::V8::Initialize();
   5472   LocalContext context;
   5473   v8::HandleScope scope(context->GetIsolate());
   5474 
   5475   {
   5476     // Test nested try-catch with a native throw in the end.
   5477     v8::TryCatch try_catch;
   5478     TryCatchNested1Helper(5);
   5479     CHECK(try_catch.HasCaught());
   5480     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
   5481   }
   5482 
   5483   {
   5484     // Test nested try-catch with a JavaScript throw in the end.
   5485     v8::TryCatch try_catch;
   5486     TryCatchNested2Helper(5);
   5487     CHECK(try_catch.HasCaught());
   5488     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
   5489   }
   5490 }
   5491 
   5492 
   5493 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
   5494   CHECK(try_catch->HasCaught());
   5495   Handle<Message> message = try_catch->Message();
   5496   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
   5497   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
   5498   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
   5499                      "Uncaught Error: a"));
   5500   CHECK_EQ(1, message->GetLineNumber());
   5501   CHECK_EQ(6, message->GetStartColumn());
   5502 }
   5503 
   5504 
   5505 void TryCatchMixedNestingHelper(
   5506     const v8::FunctionCallbackInfo<v8::Value>& args) {
   5507   ApiTestFuzzer::Fuzz();
   5508   v8::TryCatch try_catch;
   5509   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
   5510   CHECK(try_catch.HasCaught());
   5511   TryCatchMixedNestingCheck(&try_catch);
   5512   try_catch.ReThrow();
   5513 }
   5514 
   5515 
   5516 // This test ensures that an outer TryCatch in the following situation:
   5517 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
   5518 // does not clobber the Message object generated for the inner TryCatch.
   5519 // This exercises the ability of TryCatch.ReThrow() to restore the
   5520 // inner pending Message before throwing the exception again.
   5521 TEST(TryCatchMixedNesting) {
   5522   v8::Isolate* isolate = CcTest::isolate();
   5523   v8::HandleScope scope(isolate);
   5524   v8::V8::Initialize();
   5525   v8::TryCatch try_catch;
   5526   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5527   templ->Set(v8_str("TryCatchMixedNestingHelper"),
   5528              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
   5529   LocalContext context(0, templ);
   5530   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
   5531   TryCatchMixedNestingCheck(&try_catch);
   5532 }
   5533 
   5534 
   5535 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5536   ApiTestFuzzer::Fuzz();
   5537   v8::TryCatch try_catch;
   5538   args.GetIsolate()->ThrowException(v8_str("boom"));
   5539   CHECK(try_catch.HasCaught());
   5540 }
   5541 
   5542 
   5543 TEST(TryCatchNative) {
   5544   v8::Isolate* isolate = CcTest::isolate();
   5545   v8::HandleScope scope(isolate);
   5546   v8::V8::Initialize();
   5547   v8::TryCatch try_catch;
   5548   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5549   templ->Set(v8_str("TryCatchNativeHelper"),
   5550              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
   5551   LocalContext context(0, templ);
   5552   CompileRun("TryCatchNativeHelper();");
   5553   CHECK(!try_catch.HasCaught());
   5554 }
   5555 
   5556 
   5557 void TryCatchNativeResetHelper(
   5558     const v8::FunctionCallbackInfo<v8::Value>& args) {
   5559   ApiTestFuzzer::Fuzz();
   5560   v8::TryCatch try_catch;
   5561   args.GetIsolate()->ThrowException(v8_str("boom"));
   5562   CHECK(try_catch.HasCaught());
   5563   try_catch.Reset();
   5564   CHECK(!try_catch.HasCaught());
   5565 }
   5566 
   5567 
   5568 TEST(TryCatchNativeReset) {
   5569   v8::Isolate* isolate = CcTest::isolate();
   5570   v8::HandleScope scope(isolate);
   5571   v8::V8::Initialize();
   5572   v8::TryCatch try_catch;
   5573   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5574   templ->Set(v8_str("TryCatchNativeResetHelper"),
   5575              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
   5576   LocalContext context(0, templ);
   5577   CompileRun("TryCatchNativeResetHelper();");
   5578   CHECK(!try_catch.HasCaught());
   5579 }
   5580 
   5581 
   5582 THREADED_TEST(Equality) {
   5583   LocalContext context;
   5584   v8::Isolate* isolate = context->GetIsolate();
   5585   v8::HandleScope scope(context->GetIsolate());
   5586   // Check that equality works at all before relying on CHECK_EQ
   5587   CHECK(v8_str("a")->Equals(v8_str("a")));
   5588   CHECK(!v8_str("a")->Equals(v8_str("b")));
   5589 
   5590   CHECK_EQ(v8_str("a"), v8_str("a"));
   5591   CHECK_NE(v8_str("a"), v8_str("b"));
   5592   CHECK_EQ(v8_num(1), v8_num(1));
   5593   CHECK_EQ(v8_num(1.00), v8_num(1));
   5594   CHECK_NE(v8_num(1), v8_num(2));
   5595 
   5596   // Assume String is not internalized.
   5597   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
   5598   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
   5599   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
   5600   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
   5601   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
   5602   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
   5603   Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
   5604   CHECK(!not_a_number->StrictEquals(not_a_number));
   5605   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
   5606   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
   5607 
   5608   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   5609   v8::Persistent<v8::Object> alias(isolate, obj);
   5610   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
   5611   alias.Reset();
   5612 
   5613   CHECK(v8_str("a")->SameValue(v8_str("a")));
   5614   CHECK(!v8_str("a")->SameValue(v8_str("b")));
   5615   CHECK(!v8_str("5")->SameValue(v8_num(5)));
   5616   CHECK(v8_num(1)->SameValue(v8_num(1)));
   5617   CHECK(!v8_num(1)->SameValue(v8_num(2)));
   5618   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
   5619   CHECK(not_a_number->SameValue(not_a_number));
   5620   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
   5621   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
   5622 }
   5623 
   5624 
   5625 THREADED_TEST(MultiRun) {
   5626   LocalContext context;
   5627   v8::HandleScope scope(context->GetIsolate());
   5628   Local<Script> script = v8_compile("x");
   5629   for (int i = 0; i < 10; i++)
   5630     script->Run();
   5631 }
   5632 
   5633 
   5634 static void GetXValue(Local<String> name,
   5635                       const v8::PropertyCallbackInfo<v8::Value>& info) {
   5636   ApiTestFuzzer::Fuzz();
   5637   CHECK_EQ(info.Data(), v8_str("donut"));
   5638   CHECK_EQ(name, v8_str("x"));
   5639   info.GetReturnValue().Set(name);
   5640 }
   5641 
   5642 
   5643 THREADED_TEST(SimplePropertyRead) {
   5644   LocalContext context;
   5645   v8::Isolate* isolate = context->GetIsolate();
   5646   v8::HandleScope scope(isolate);
   5647   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5648   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   5649   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5650   Local<Script> script = v8_compile("obj.x");
   5651   for (int i = 0; i < 10; i++) {
   5652     Local<Value> result = script->Run();
   5653     CHECK_EQ(result, v8_str("x"));
   5654   }
   5655 }
   5656 
   5657 
   5658 THREADED_TEST(DefinePropertyOnAPIAccessor) {
   5659   LocalContext context;
   5660   v8::Isolate* isolate = context->GetIsolate();
   5661   v8::HandleScope scope(isolate);
   5662   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5663   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   5664   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5665 
   5666   // Uses getOwnPropertyDescriptor to check the configurable status
   5667   Local<Script> script_desc = v8_compile(
   5668       "var prop = Object.getOwnPropertyDescriptor( "
   5669       "obj, 'x');"
   5670       "prop.configurable;");
   5671   Local<Value> result = script_desc->Run();
   5672   CHECK_EQ(result->BooleanValue(), true);
   5673 
   5674   // Redefine get - but still configurable
   5675   Local<Script> script_define = v8_compile(
   5676       "var desc = { get: function(){return 42; },"
   5677       "            configurable: true };"
   5678       "Object.defineProperty(obj, 'x', desc);"
   5679       "obj.x");
   5680   result = script_define->Run();
   5681   CHECK_EQ(result, v8_num(42));
   5682 
   5683   // Check that the accessor is still configurable
   5684   result = script_desc->Run();
   5685   CHECK_EQ(result->BooleanValue(), true);
   5686 
   5687   // Redefine to a non-configurable
   5688   script_define = v8_compile(
   5689       "var desc = { get: function(){return 43; },"
   5690       "             configurable: false };"
   5691       "Object.defineProperty(obj, 'x', desc);"
   5692       "obj.x");
   5693   result = script_define->Run();
   5694   CHECK_EQ(result, v8_num(43));
   5695   result = script_desc->Run();
   5696   CHECK_EQ(result->BooleanValue(), false);
   5697 
   5698   // Make sure that it is not possible to redefine again
   5699   v8::TryCatch try_catch;
   5700   result = script_define->Run();
   5701   CHECK(try_catch.HasCaught());
   5702   String::Utf8Value exception_value(try_catch.Exception());
   5703   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5704 }
   5705 
   5706 
   5707 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
   5708   v8::Isolate* isolate = CcTest::isolate();
   5709   v8::HandleScope scope(isolate);
   5710   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5711   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   5712   LocalContext context;
   5713   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5714 
   5715   Local<Script> script_desc = v8_compile(
   5716       "var prop ="
   5717       "Object.getOwnPropertyDescriptor( "
   5718       "obj, 'x');"
   5719       "prop.configurable;");
   5720   Local<Value> result = script_desc->Run();
   5721   CHECK_EQ(result->BooleanValue(), true);
   5722 
   5723   Local<Script> script_define = v8_compile(
   5724       "var desc = {get: function(){return 42; },"
   5725       "            configurable: true };"
   5726       "Object.defineProperty(obj, 'x', desc);"
   5727       "obj.x");
   5728   result = script_define->Run();
   5729   CHECK_EQ(result, v8_num(42));
   5730 
   5731 
   5732   result = script_desc->Run();
   5733   CHECK_EQ(result->BooleanValue(), true);
   5734 
   5735 
   5736   script_define = v8_compile(
   5737       "var desc = {get: function(){return 43; },"
   5738       "            configurable: false };"
   5739       "Object.defineProperty(obj, 'x', desc);"
   5740       "obj.x");
   5741   result = script_define->Run();
   5742   CHECK_EQ(result, v8_num(43));
   5743   result = script_desc->Run();
   5744 
   5745   CHECK_EQ(result->BooleanValue(), false);
   5746 
   5747   v8::TryCatch try_catch;
   5748   result = script_define->Run();
   5749   CHECK(try_catch.HasCaught());
   5750   String::Utf8Value exception_value(try_catch.Exception());
   5751   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5752 }
   5753 
   5754 
   5755 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
   5756                                                 char const* name) {
   5757   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
   5758 }
   5759 
   5760 
   5761 THREADED_TEST(DefineAPIAccessorOnObject) {
   5762   v8::Isolate* isolate = CcTest::isolate();
   5763   v8::HandleScope scope(isolate);
   5764   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5765   LocalContext context;
   5766 
   5767   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   5768   CompileRun("var obj2 = {};");
   5769 
   5770   CHECK(CompileRun("obj1.x")->IsUndefined());
   5771   CHECK(CompileRun("obj2.x")->IsUndefined());
   5772 
   5773   CHECK(GetGlobalProperty(&context, "obj1")->
   5774       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5775 
   5776   ExpectString("obj1.x", "x");
   5777   CHECK(CompileRun("obj2.x")->IsUndefined());
   5778 
   5779   CHECK(GetGlobalProperty(&context, "obj2")->
   5780       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5781 
   5782   ExpectString("obj1.x", "x");
   5783   ExpectString("obj2.x", "x");
   5784 
   5785   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5786   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5787 
   5788   CompileRun("Object.defineProperty(obj1, 'x',"
   5789              "{ get: function() { return 'y'; }, configurable: true })");
   5790 
   5791   ExpectString("obj1.x", "y");
   5792   ExpectString("obj2.x", "x");
   5793 
   5794   CompileRun("Object.defineProperty(obj2, 'x',"
   5795              "{ get: function() { return 'y'; }, configurable: true })");
   5796 
   5797   ExpectString("obj1.x", "y");
   5798   ExpectString("obj2.x", "y");
   5799 
   5800   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5801   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5802 
   5803   CHECK(GetGlobalProperty(&context, "obj1")->
   5804       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5805   CHECK(GetGlobalProperty(&context, "obj2")->
   5806       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5807 
   5808   ExpectString("obj1.x", "x");
   5809   ExpectString("obj2.x", "x");
   5810 
   5811   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5812   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5813 
   5814   // Define getters/setters, but now make them not configurable.
   5815   CompileRun("Object.defineProperty(obj1, 'x',"
   5816              "{ get: function() { return 'z'; }, configurable: false })");
   5817   CompileRun("Object.defineProperty(obj2, 'x',"
   5818              "{ get: function() { return 'z'; }, configurable: false })");
   5819 
   5820   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5821   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5822 
   5823   ExpectString("obj1.x", "z");
   5824   ExpectString("obj2.x", "z");
   5825 
   5826   CHECK(!GetGlobalProperty(&context, "obj1")->
   5827       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5828   CHECK(!GetGlobalProperty(&context, "obj2")->
   5829       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5830 
   5831   ExpectString("obj1.x", "z");
   5832   ExpectString("obj2.x", "z");
   5833 }
   5834 
   5835 
   5836 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
   5837   v8::Isolate* isolate = CcTest::isolate();
   5838   v8::HandleScope scope(isolate);
   5839   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5840   LocalContext context;
   5841 
   5842   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   5843   CompileRun("var obj2 = {};");
   5844 
   5845   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
   5846         v8_str("x"),
   5847         GetXValue, NULL,
   5848         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
   5849   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
   5850         v8_str("x"),
   5851         GetXValue, NULL,
   5852         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
   5853 
   5854   ExpectString("obj1.x", "x");
   5855   ExpectString("obj2.x", "x");
   5856 
   5857   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5858   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5859 
   5860   CHECK(!GetGlobalProperty(&context, "obj1")->
   5861       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5862   CHECK(!GetGlobalProperty(&context, "obj2")->
   5863       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5864 
   5865   {
   5866     v8::TryCatch try_catch;
   5867     CompileRun("Object.defineProperty(obj1, 'x',"
   5868         "{get: function() { return 'func'; }})");
   5869     CHECK(try_catch.HasCaught());
   5870     String::Utf8Value exception_value(try_catch.Exception());
   5871     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5872   }
   5873   {
   5874     v8::TryCatch try_catch;
   5875     CompileRun("Object.defineProperty(obj2, 'x',"
   5876         "{get: function() { return 'func'; }})");
   5877     CHECK(try_catch.HasCaught());
   5878     String::Utf8Value exception_value(try_catch.Exception());
   5879     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5880   }
   5881 }
   5882 
   5883 
   5884 static void Get239Value(Local<String> name,
   5885                         const v8::PropertyCallbackInfo<v8::Value>& info) {
   5886   ApiTestFuzzer::Fuzz();
   5887   CHECK_EQ(info.Data(), v8_str("donut"));
   5888   CHECK_EQ(name, v8_str("239"));
   5889   info.GetReturnValue().Set(name);
   5890 }
   5891 
   5892 
   5893 THREADED_TEST(ElementAPIAccessor) {
   5894   v8::Isolate* isolate = CcTest::isolate();
   5895   v8::HandleScope scope(isolate);
   5896   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5897   LocalContext context;
   5898 
   5899   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   5900   CompileRun("var obj2 = {};");
   5901 
   5902   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
   5903         v8_str("239"),
   5904         Get239Value, NULL,
   5905         v8_str("donut")));
   5906   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
   5907         v8_str("239"),
   5908         Get239Value, NULL,
   5909         v8_str("donut")));
   5910 
   5911   ExpectString("obj1[239]", "239");
   5912   ExpectString("obj2[239]", "239");
   5913   ExpectString("obj1['239']", "239");
   5914   ExpectString("obj2['239']", "239");
   5915 }
   5916 
   5917 
   5918 v8::Persistent<Value> xValue;
   5919 
   5920 
   5921 static void SetXValue(Local<String> name,
   5922                       Local<Value> value,
   5923                       const v8::PropertyCallbackInfo<void>& info) {
   5924   CHECK_EQ(value, v8_num(4));
   5925   CHECK_EQ(info.Data(), v8_str("donut"));
   5926   CHECK_EQ(name, v8_str("x"));
   5927   CHECK(xValue.IsEmpty());
   5928   xValue.Reset(info.GetIsolate(), value);
   5929 }
   5930 
   5931 
   5932 THREADED_TEST(SimplePropertyWrite) {
   5933   v8::Isolate* isolate = CcTest::isolate();
   5934   v8::HandleScope scope(isolate);
   5935   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5936   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
   5937   LocalContext context;
   5938   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5939   Local<Script> script = v8_compile("obj.x = 4");
   5940   for (int i = 0; i < 10; i++) {
   5941     CHECK(xValue.IsEmpty());
   5942     script->Run();
   5943     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
   5944     xValue.Reset();
   5945   }
   5946 }
   5947 
   5948 
   5949 THREADED_TEST(SetterOnly) {
   5950   v8::Isolate* isolate = CcTest::isolate();
   5951   v8::HandleScope scope(isolate);
   5952   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5953   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
   5954   LocalContext context;
   5955   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5956   Local<Script> script = v8_compile("obj.x = 4; obj.x");
   5957   for (int i = 0; i < 10; i++) {
   5958     CHECK(xValue.IsEmpty());
   5959     script->Run();
   5960     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
   5961     xValue.Reset();
   5962   }
   5963 }
   5964 
   5965 
   5966 THREADED_TEST(NoAccessors) {
   5967   v8::Isolate* isolate = CcTest::isolate();
   5968   v8::HandleScope scope(isolate);
   5969   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5970   templ->SetAccessor(v8_str("x"),
   5971                      static_cast<v8::AccessorGetterCallback>(NULL),
   5972                      NULL,
   5973                      v8_str("donut"));
   5974   LocalContext context;
   5975   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5976   Local<Script> script = v8_compile("obj.x = 4; obj.x");
   5977   for (int i = 0; i < 10; i++) {
   5978     script->Run();
   5979   }
   5980 }
   5981 
   5982 
   5983 static void XPropertyGetter(Local<String> property,
   5984                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   5985   ApiTestFuzzer::Fuzz();
   5986   CHECK(info.Data()->IsUndefined());
   5987   info.GetReturnValue().Set(property);
   5988 }
   5989 
   5990 
   5991 THREADED_TEST(NamedInterceptorPropertyRead) {
   5992   v8::Isolate* isolate = CcTest::isolate();
   5993   v8::HandleScope scope(isolate);
   5994   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5995   templ->SetNamedPropertyHandler(XPropertyGetter);
   5996   LocalContext context;
   5997   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5998   Local<Script> script = v8_compile("obj.x");
   5999   for (int i = 0; i < 10; i++) {
   6000     Local<Value> result = script->Run();
   6001     CHECK_EQ(result, v8_str("x"));
   6002   }
   6003 }
   6004 
   6005 
   6006 THREADED_TEST(NamedInterceptorDictionaryIC) {
   6007   v8::Isolate* isolate = CcTest::isolate();
   6008   v8::HandleScope scope(isolate);
   6009   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6010   templ->SetNamedPropertyHandler(XPropertyGetter);
   6011   LocalContext context;
   6012   // Create an object with a named interceptor.
   6013   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
   6014   Local<Script> script = v8_compile("interceptor_obj.x");
   6015   for (int i = 0; i < 10; i++) {
   6016     Local<Value> result = script->Run();
   6017     CHECK_EQ(result, v8_str("x"));
   6018   }
   6019   // Create a slow case object and a function accessing a property in
   6020   // that slow case object (with dictionary probing in generated
   6021   // code). Then force object with a named interceptor into slow-case,
   6022   // pass it to the function, and check that the interceptor is called
   6023   // instead of accessing the local property.
   6024   Local<Value> result =
   6025       CompileRun("function get_x(o) { return o.x; };"
   6026                  "var obj = { x : 42, y : 0 };"
   6027                  "delete obj.y;"
   6028                  "for (var i = 0; i < 10; i++) get_x(obj);"
   6029                  "interceptor_obj.x = 42;"
   6030                  "interceptor_obj.y = 10;"
   6031                  "delete interceptor_obj.y;"
   6032                  "get_x(interceptor_obj)");
   6033   CHECK_EQ(result, v8_str("x"));
   6034 }
   6035 
   6036 
   6037 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
   6038   v8::Isolate* isolate = CcTest::isolate();
   6039   v8::HandleScope scope(isolate);
   6040   v8::Local<Context> context1 = Context::New(isolate);
   6041 
   6042   context1->Enter();
   6043   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6044   templ->SetNamedPropertyHandler(XPropertyGetter);
   6045   // Create an object with a named interceptor.
   6046   v8::Local<v8::Object> object = templ->NewInstance();
   6047   context1->Global()->Set(v8_str("interceptor_obj"), object);
   6048 
   6049   // Force the object into the slow case.
   6050   CompileRun("interceptor_obj.y = 0;"
   6051              "delete interceptor_obj.y;");
   6052   context1->Exit();
   6053 
   6054   {
   6055     // Introduce the object into a different context.
   6056     // Repeat named loads to exercise ICs.
   6057     LocalContext context2;
   6058     context2->Global()->Set(v8_str("interceptor_obj"), object);
   6059     Local<Value> result =
   6060       CompileRun("function get_x(o) { return o.x; }"
   6061                  "interceptor_obj.x = 42;"
   6062                  "for (var i=0; i != 10; i++) {"
   6063                  "  get_x(interceptor_obj);"
   6064                  "}"
   6065                  "get_x(interceptor_obj)");
   6066     // Check that the interceptor was actually invoked.
   6067     CHECK_EQ(result, v8_str("x"));
   6068   }
   6069 
   6070   // Return to the original context and force some object to the slow case
   6071   // to cause the NormalizedMapCache to verify.
   6072   context1->Enter();
   6073   CompileRun("var obj = { x : 0 }; delete obj.x;");
   6074   context1->Exit();
   6075 }
   6076 
   6077 
   6078 static void SetXOnPrototypeGetter(
   6079     Local<String> property,
   6080     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6081   // Set x on the prototype object and do not handle the get request.
   6082   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   6083   proto.As<v8::Object>()->Set(v8_str("x"),
   6084                               v8::Integer::New(info.GetIsolate(), 23));
   6085 }
   6086 
   6087 
   6088 // This is a regression test for http://crbug.com/20104. Map
   6089 // transitions should not interfere with post interceptor lookup.
   6090 THREADED_TEST(NamedInterceptorMapTransitionRead) {
   6091   v8::Isolate* isolate = CcTest::isolate();
   6092   v8::HandleScope scope(isolate);
   6093   Local<v8::FunctionTemplate> function_template =
   6094       v8::FunctionTemplate::New(isolate);
   6095   Local<v8::ObjectTemplate> instance_template
   6096       = function_template->InstanceTemplate();
   6097   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
   6098   LocalContext context;
   6099   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   6100   // Create an instance of F and introduce a map transition for x.
   6101   CompileRun("var o = new F(); o.x = 23;");
   6102   // Create an instance of F and invoke the getter. The result should be 23.
   6103   Local<Value> result = CompileRun("o = new F(); o.x");
   6104   CHECK_EQ(result->Int32Value(), 23);
   6105 }
   6106 
   6107 
   6108 static void IndexedPropertyGetter(
   6109     uint32_t index,
   6110     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6111   ApiTestFuzzer::Fuzz();
   6112   if (index == 37) {
   6113     info.GetReturnValue().Set(v8_num(625));
   6114   }
   6115 }
   6116 
   6117 
   6118 static void IndexedPropertySetter(
   6119     uint32_t index,
   6120     Local<Value> value,
   6121     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6122   ApiTestFuzzer::Fuzz();
   6123   if (index == 39) {
   6124     info.GetReturnValue().Set(value);
   6125   }
   6126 }
   6127 
   6128 
   6129 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
   6130   v8::Isolate* isolate = CcTest::isolate();
   6131   v8::HandleScope scope(isolate);
   6132   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6133   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
   6134                                    IndexedPropertySetter);
   6135   LocalContext context;
   6136   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6137   Local<Script> getter_script = v8_compile(
   6138       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
   6139   Local<Script> setter_script = v8_compile(
   6140       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
   6141       "obj[17] = 23;"
   6142       "obj.foo;");
   6143   Local<Script> interceptor_setter_script = v8_compile(
   6144       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
   6145       "obj[39] = 47;"
   6146       "obj.foo;");  // This setter should not run, due to the interceptor.
   6147   Local<Script> interceptor_getter_script = v8_compile(
   6148       "obj[37];");
   6149   Local<Value> result = getter_script->Run();
   6150   CHECK_EQ(v8_num(5), result);
   6151   result = setter_script->Run();
   6152   CHECK_EQ(v8_num(23), result);
   6153   result = interceptor_setter_script->Run();
   6154   CHECK_EQ(v8_num(23), result);
   6155   result = interceptor_getter_script->Run();
   6156   CHECK_EQ(v8_num(625), result);
   6157 }
   6158 
   6159 
   6160 static void UnboxedDoubleIndexedPropertyGetter(
   6161     uint32_t index,
   6162     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6163   ApiTestFuzzer::Fuzz();
   6164   if (index < 25) {
   6165     info.GetReturnValue().Set(v8_num(index));
   6166   }
   6167 }
   6168 
   6169 
   6170 static void UnboxedDoubleIndexedPropertySetter(
   6171     uint32_t index,
   6172     Local<Value> value,
   6173     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6174   ApiTestFuzzer::Fuzz();
   6175   if (index < 25) {
   6176     info.GetReturnValue().Set(v8_num(index));
   6177   }
   6178 }
   6179 
   6180 
   6181 void UnboxedDoubleIndexedPropertyEnumerator(
   6182     const v8::PropertyCallbackInfo<v8::Array>& info) {
   6183   // Force the list of returned keys to be stored in a FastDoubleArray.
   6184   Local<Script> indexed_property_names_script = v8_compile(
   6185       "keys = new Array(); keys[125000] = 1;"
   6186       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
   6187       "keys.length = 25; keys;");
   6188   Local<Value> result = indexed_property_names_script->Run();
   6189   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
   6190 }
   6191 
   6192 
   6193 // Make sure that the the interceptor code in the runtime properly handles
   6194 // merging property name lists for double-array-backed arrays.
   6195 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
   6196   v8::Isolate* isolate = CcTest::isolate();
   6197   v8::HandleScope scope(isolate);
   6198   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6199   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
   6200                                    UnboxedDoubleIndexedPropertySetter,
   6201                                    0,
   6202                                    0,
   6203                                    UnboxedDoubleIndexedPropertyEnumerator);
   6204   LocalContext context;
   6205   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6206   // When obj is created, force it to be Stored in a FastDoubleArray.
   6207   Local<Script> create_unboxed_double_script = v8_compile(
   6208       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
   6209       "key_count = 0; "
   6210       "for (x in obj) {key_count++;};"
   6211       "obj;");
   6212   Local<Value> result = create_unboxed_double_script->Run();
   6213   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
   6214   Local<Script> key_count_check = v8_compile("key_count;");
   6215   result = key_count_check->Run();
   6216   CHECK_EQ(v8_num(40013), result);
   6217 }
   6218 
   6219 
   6220 void SloppyArgsIndexedPropertyEnumerator(
   6221     const v8::PropertyCallbackInfo<v8::Array>& info) {
   6222   // Force the list of returned keys to be stored in a Arguments object.
   6223   Local<Script> indexed_property_names_script = v8_compile(
   6224       "function f(w,x) {"
   6225       " return arguments;"
   6226       "}"
   6227       "keys = f(0, 1, 2, 3);"
   6228       "keys;");
   6229   Local<Object> result =
   6230       Local<Object>::Cast(indexed_property_names_script->Run());
   6231   // Have to populate the handle manually, as it's not Cast-able.
   6232   i::Handle<i::JSObject> o =
   6233       v8::Utils::OpenHandle<Object, i::JSObject>(result);
   6234   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
   6235   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
   6236 }
   6237 
   6238 
   6239 static void SloppyIndexedPropertyGetter(
   6240     uint32_t index,
   6241     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6242   ApiTestFuzzer::Fuzz();
   6243   if (index < 4) {
   6244     info.GetReturnValue().Set(v8_num(index));
   6245   }
   6246 }
   6247 
   6248 
   6249 // Make sure that the the interceptor code in the runtime properly handles
   6250 // merging property name lists for non-string arguments arrays.
   6251 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
   6252   v8::Isolate* isolate = CcTest::isolate();
   6253   v8::HandleScope scope(isolate);
   6254   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6255   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
   6256                                    0,
   6257                                    0,
   6258                                    0,
   6259                                    SloppyArgsIndexedPropertyEnumerator);
   6260   LocalContext context;
   6261   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6262   Local<Script> create_args_script = v8_compile(
   6263       "var key_count = 0;"
   6264       "for (x in obj) {key_count++;} key_count;");
   6265   Local<Value> result = create_args_script->Run();
   6266   CHECK_EQ(v8_num(4), result);
   6267 }
   6268 
   6269 
   6270 static void IdentityIndexedPropertyGetter(
   6271     uint32_t index,
   6272     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6273   info.GetReturnValue().Set(index);
   6274 }
   6275 
   6276 
   6277 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
   6278   v8::Isolate* isolate = CcTest::isolate();
   6279   v8::HandleScope scope(isolate);
   6280   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6281   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6282 
   6283   LocalContext context;
   6284   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6285 
   6286   // Check fast object case.
   6287   const char* fast_case_code =
   6288       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
   6289   ExpectString(fast_case_code, "0");
   6290 
   6291   // Check slow case.
   6292   const char* slow_case_code =
   6293       "obj.x = 1; delete obj.x;"
   6294       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
   6295   ExpectString(slow_case_code, "1");
   6296 }
   6297 
   6298 
   6299 THREADED_TEST(IndexedInterceptorWithNoSetter) {
   6300   v8::Isolate* isolate = CcTest::isolate();
   6301   v8::HandleScope scope(isolate);
   6302   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6303   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6304 
   6305   LocalContext context;
   6306   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6307 
   6308   const char* code =
   6309       "try {"
   6310       "  obj[0] = 239;"
   6311       "  for (var i = 0; i < 100; i++) {"
   6312       "    var v = obj[0];"
   6313       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6314       "  }"
   6315       "  'PASSED'"
   6316       "} catch(e) {"
   6317       "  e"
   6318       "}";
   6319   ExpectString(code, "PASSED");
   6320 }
   6321 
   6322 
   6323 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
   6324   v8::Isolate* isolate = CcTest::isolate();
   6325   v8::HandleScope scope(isolate);
   6326   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6327   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6328 
   6329   LocalContext context;
   6330   Local<v8::Object> obj = templ->NewInstance();
   6331   obj->TurnOnAccessCheck();
   6332   context->Global()->Set(v8_str("obj"), obj);
   6333 
   6334   const char* code =
   6335       "var result = 'PASSED';"
   6336       "for (var i = 0; i < 100; i++) {"
   6337       "  try {"
   6338       "    var v = obj[0];"
   6339       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
   6340       "    break;"
   6341       "  } catch (e) {"
   6342       "    /* pass */"
   6343       "  }"
   6344       "}"
   6345       "result";
   6346   ExpectString(code, "PASSED");
   6347 }
   6348 
   6349 
   6350 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
   6351   i::FLAG_allow_natives_syntax = true;
   6352   v8::Isolate* isolate = CcTest::isolate();
   6353   v8::HandleScope scope(isolate);
   6354   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6355   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6356 
   6357   LocalContext context;
   6358   Local<v8::Object> obj = templ->NewInstance();
   6359   context->Global()->Set(v8_str("obj"), obj);
   6360 
   6361   const char* code =
   6362       "var result = 'PASSED';"
   6363       "for (var i = 0; i < 100; i++) {"
   6364       "  var expected = i;"
   6365       "  if (i == 5) {"
   6366       "    %EnableAccessChecks(obj);"
   6367       "  }"
   6368       "  try {"
   6369       "    var v = obj[i];"
   6370       "    if (i == 5) {"
   6371       "      result = 'Should not have reached this!';"
   6372       "      break;"
   6373       "    } else if (v != expected) {"
   6374       "      result = 'Wrong value ' + v + ' at iteration ' + i;"
   6375       "      break;"
   6376       "    }"
   6377       "  } catch (e) {"
   6378       "    if (i != 5) {"
   6379       "      result = e;"
   6380       "    }"
   6381       "  }"
   6382       "  if (i == 5) %DisableAccessChecks(obj);"
   6383       "}"
   6384       "result";
   6385   ExpectString(code, "PASSED");
   6386 }
   6387 
   6388 
   6389 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
   6390   v8::Isolate* isolate = CcTest::isolate();
   6391   v8::HandleScope scope(isolate);
   6392   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6393   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6394 
   6395   LocalContext context;
   6396   Local<v8::Object> obj = templ->NewInstance();
   6397   context->Global()->Set(v8_str("obj"), obj);
   6398 
   6399   const char* code =
   6400       "try {"
   6401       "  for (var i = 0; i < 100; i++) {"
   6402       "    var v = obj[i];"
   6403       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6404       "  }"
   6405       "  'PASSED'"
   6406       "} catch(e) {"
   6407       "  e"
   6408       "}";
   6409   ExpectString(code, "PASSED");
   6410 }
   6411 
   6412 
   6413 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
   6414   v8::Isolate* isolate = CcTest::isolate();
   6415   v8::HandleScope scope(isolate);
   6416   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6417   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6418 
   6419   LocalContext context;
   6420   Local<v8::Object> obj = templ->NewInstance();
   6421   context->Global()->Set(v8_str("obj"), obj);
   6422 
   6423   const char* code =
   6424       "try {"
   6425       "  for (var i = 0; i < 100; i++) {"
   6426       "    var expected = i;"
   6427       "    var key = i;"
   6428       "    if (i == 25) {"
   6429       "       key = -1;"
   6430       "       expected = undefined;"
   6431       "    }"
   6432       "    if (i == 50) {"
   6433       "       /* probe minimal Smi number on 32-bit platforms */"
   6434       "       key = -(1 << 30);"
   6435       "       expected = undefined;"
   6436       "    }"
   6437       "    if (i == 75) {"
   6438       "       /* probe minimal Smi number on 64-bit platforms */"
   6439       "       key = 1 << 31;"
   6440       "       expected = undefined;"
   6441       "    }"
   6442       "    var v = obj[key];"
   6443       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6444       "  }"
   6445       "  'PASSED'"
   6446       "} catch(e) {"
   6447       "  e"
   6448       "}";
   6449   ExpectString(code, "PASSED");
   6450 }
   6451 
   6452 
   6453 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
   6454   v8::Isolate* isolate = CcTest::isolate();
   6455   v8::HandleScope scope(isolate);
   6456   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6457   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6458 
   6459   LocalContext context;
   6460   Local<v8::Object> obj = templ->NewInstance();
   6461   context->Global()->Set(v8_str("obj"), obj);
   6462 
   6463   const char* code =
   6464       "try {"
   6465       "  for (var i = 0; i < 100; i++) {"
   6466       "    var expected = i;"
   6467       "    var key = i;"
   6468       "    if (i == 50) {"
   6469       "       key = 'foobar';"
   6470       "       expected = undefined;"
   6471       "    }"
   6472       "    var v = obj[key];"
   6473       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6474       "  }"
   6475       "  'PASSED'"
   6476       "} catch(e) {"
   6477       "  e"
   6478       "}";
   6479   ExpectString(code, "PASSED");
   6480 }
   6481 
   6482 
   6483 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
   6484   v8::Isolate* isolate = CcTest::isolate();
   6485   v8::HandleScope scope(isolate);
   6486   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6487   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6488 
   6489   LocalContext context;
   6490   Local<v8::Object> obj = templ->NewInstance();
   6491   context->Global()->Set(v8_str("obj"), obj);
   6492 
   6493   const char* code =
   6494       "var original = obj;"
   6495       "try {"
   6496       "  for (var i = 0; i < 100; i++) {"
   6497       "    var expected = i;"
   6498       "    if (i == 50) {"
   6499       "       obj = {50: 'foobar'};"
   6500       "       expected = 'foobar';"
   6501       "    }"
   6502       "    var v = obj[i];"
   6503       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6504       "    if (i == 50) obj = original;"
   6505       "  }"
   6506       "  'PASSED'"
   6507       "} catch(e) {"
   6508       "  e"
   6509       "}";
   6510   ExpectString(code, "PASSED");
   6511 }
   6512 
   6513 
   6514 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
   6515   v8::Isolate* isolate = CcTest::isolate();
   6516   v8::HandleScope scope(isolate);
   6517   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6518   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6519 
   6520   LocalContext context;
   6521   Local<v8::Object> obj = templ->NewInstance();
   6522   context->Global()->Set(v8_str("obj"), obj);
   6523 
   6524   const char* code =
   6525       "var original = obj;"
   6526       "try {"
   6527       "  for (var i = 0; i < 100; i++) {"
   6528       "    var expected = i;"
   6529       "    if (i == 5) {"
   6530       "       obj = 239;"
   6531       "       expected = undefined;"
   6532       "    }"
   6533       "    var v = obj[i];"
   6534       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6535       "    if (i == 5) obj = original;"
   6536       "  }"
   6537       "  'PASSED'"
   6538       "} catch(e) {"
   6539       "  e"
   6540       "}";
   6541   ExpectString(code, "PASSED");
   6542 }
   6543 
   6544 
   6545 THREADED_TEST(IndexedInterceptorOnProto) {
   6546   v8::Isolate* isolate = CcTest::isolate();
   6547   v8::HandleScope scope(isolate);
   6548   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6549   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6550 
   6551   LocalContext context;
   6552   Local<v8::Object> obj = templ->NewInstance();
   6553   context->Global()->Set(v8_str("obj"), obj);
   6554 
   6555   const char* code =
   6556       "var o = {__proto__: obj};"
   6557       "try {"
   6558       "  for (var i = 0; i < 100; i++) {"
   6559       "    var v = o[i];"
   6560       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6561       "  }"
   6562       "  'PASSED'"
   6563       "} catch(e) {"
   6564       "  e"
   6565       "}";
   6566   ExpectString(code, "PASSED");
   6567 }
   6568 
   6569 
   6570 THREADED_TEST(MultiContexts) {
   6571   v8::Isolate* isolate = CcTest::isolate();
   6572   v8::HandleScope scope(isolate);
   6573   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6574   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
   6575                                                         DummyCallHandler));
   6576 
   6577   Local<String> password = v8_str("Password");
   6578 
   6579   // Create an environment
   6580   LocalContext context0(0, templ);
   6581   context0->SetSecurityToken(password);
   6582   v8::Handle<v8::Object> global0 = context0->Global();
   6583   global0->Set(v8_str("custom"), v8_num(1234));
   6584   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   6585 
   6586   // Create an independent environment
   6587   LocalContext context1(0, templ);
   6588   context1->SetSecurityToken(password);
   6589   v8::Handle<v8::Object> global1 = context1->Global();
   6590   global1->Set(v8_str("custom"), v8_num(1234));
   6591   CHECK_NE(global0, global1);
   6592   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   6593   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
   6594 
   6595   // Now create a new context with the old global
   6596   LocalContext context2(0, templ, global1);
   6597   context2->SetSecurityToken(password);
   6598   v8::Handle<v8::Object> global2 = context2->Global();
   6599   CHECK_EQ(global1, global2);
   6600   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
   6601   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
   6602 }
   6603 
   6604 
   6605 THREADED_TEST(FunctionPrototypeAcrossContexts) {
   6606   // Make sure that functions created by cloning boilerplates cannot
   6607   // communicate through their __proto__ field.
   6608 
   6609   v8::HandleScope scope(CcTest::isolate());
   6610 
   6611   LocalContext env0;
   6612   v8::Handle<v8::Object> global0 =
   6613       env0->Global();
   6614   v8::Handle<v8::Object> object0 =
   6615       global0->Get(v8_str("Object")).As<v8::Object>();
   6616   v8::Handle<v8::Object> tostring0 =
   6617       object0->Get(v8_str("toString")).As<v8::Object>();
   6618   v8::Handle<v8::Object> proto0 =
   6619       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
   6620   proto0->Set(v8_str("custom"), v8_num(1234));
   6621 
   6622   LocalContext env1;
   6623   v8::Handle<v8::Object> global1 =
   6624       env1->Global();
   6625   v8::Handle<v8::Object> object1 =
   6626       global1->Get(v8_str("Object")).As<v8::Object>();
   6627   v8::Handle<v8::Object> tostring1 =
   6628       object1->Get(v8_str("toString")).As<v8::Object>();
   6629   v8::Handle<v8::Object> proto1 =
   6630       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
   6631   CHECK(!proto1->Has(v8_str("custom")));
   6632 }
   6633 
   6634 
   6635 THREADED_TEST(Regress892105) {
   6636   // Make sure that object and array literals created by cloning
   6637   // boilerplates cannot communicate through their __proto__
   6638   // field. This is rather difficult to check, but we try to add stuff
   6639   // to Object.prototype and Array.prototype and create a new
   6640   // environment. This should succeed.
   6641 
   6642   v8::HandleScope scope(CcTest::isolate());
   6643 
   6644   Local<String> source = v8_str("Object.prototype.obj = 1234;"
   6645                                 "Array.prototype.arr = 4567;"
   6646                                 "8901");
   6647 
   6648   LocalContext env0;
   6649   Local<Script> script0 = v8_compile(source);
   6650   CHECK_EQ(8901.0, script0->Run()->NumberValue());
   6651 
   6652   LocalContext env1;
   6653   Local<Script> script1 = v8_compile(source);
   6654   CHECK_EQ(8901.0, script1->Run()->NumberValue());
   6655 }
   6656 
   6657 
   6658 THREADED_TEST(UndetectableObject) {
   6659   LocalContext env;
   6660   v8::HandleScope scope(env->GetIsolate());
   6661 
   6662   Local<v8::FunctionTemplate> desc =
   6663       v8::FunctionTemplate::New(env->GetIsolate());
   6664   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   6665 
   6666   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   6667   env->Global()->Set(v8_str("undetectable"), obj);
   6668 
   6669   ExpectString("undetectable.toString()", "[object Object]");
   6670   ExpectString("typeof undetectable", "undefined");
   6671   ExpectString("typeof(undetectable)", "undefined");
   6672   ExpectBoolean("typeof undetectable == 'undefined'", true);
   6673   ExpectBoolean("typeof undetectable == 'object'", false);
   6674   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   6675   ExpectBoolean("!undetectable", true);
   6676 
   6677   ExpectObject("true&&undetectable", obj);
   6678   ExpectBoolean("false&&undetectable", false);
   6679   ExpectBoolean("true||undetectable", true);
   6680   ExpectObject("false||undetectable", obj);
   6681 
   6682   ExpectObject("undetectable&&true", obj);
   6683   ExpectObject("undetectable&&false", obj);
   6684   ExpectBoolean("undetectable||true", true);
   6685   ExpectBoolean("undetectable||false", false);
   6686 
   6687   ExpectBoolean("undetectable==null", true);
   6688   ExpectBoolean("null==undetectable", true);
   6689   ExpectBoolean("undetectable==undefined", true);
   6690   ExpectBoolean("undefined==undetectable", true);
   6691   ExpectBoolean("undetectable==undetectable", true);
   6692 
   6693 
   6694   ExpectBoolean("undetectable===null", false);
   6695   ExpectBoolean("null===undetectable", false);
   6696   ExpectBoolean("undetectable===undefined", false);
   6697   ExpectBoolean("undefined===undetectable", false);
   6698   ExpectBoolean("undetectable===undetectable", true);
   6699 }
   6700 
   6701 
   6702 THREADED_TEST(VoidLiteral) {
   6703   LocalContext env;
   6704   v8::Isolate* isolate = env->GetIsolate();
   6705   v8::HandleScope scope(isolate);
   6706 
   6707   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
   6708   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   6709 
   6710   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   6711   env->Global()->Set(v8_str("undetectable"), obj);
   6712 
   6713   ExpectBoolean("undefined == void 0", true);
   6714   ExpectBoolean("undetectable == void 0", true);
   6715   ExpectBoolean("null == void 0", true);
   6716   ExpectBoolean("undefined === void 0", true);
   6717   ExpectBoolean("undetectable === void 0", false);
   6718   ExpectBoolean("null === void 0", false);
   6719 
   6720   ExpectBoolean("void 0 == undefined", true);
   6721   ExpectBoolean("void 0 == undetectable", true);
   6722   ExpectBoolean("void 0 == null", true);
   6723   ExpectBoolean("void 0 === undefined", true);
   6724   ExpectBoolean("void 0 === undetectable", false);
   6725   ExpectBoolean("void 0 === null", false);
   6726 
   6727   ExpectString("(function() {"
   6728                "  try {"
   6729                "    return x === void 0;"
   6730                "  } catch(e) {"
   6731                "    return e.toString();"
   6732                "  }"
   6733                "})()",
   6734                "ReferenceError: x is not defined");
   6735   ExpectString("(function() {"
   6736                "  try {"
   6737                "    return void 0 === x;"
   6738                "  } catch(e) {"
   6739                "    return e.toString();"
   6740                "  }"
   6741                "})()",
   6742                "ReferenceError: x is not defined");
   6743 }
   6744 
   6745 
   6746 THREADED_TEST(ExtensibleOnUndetectable) {
   6747   LocalContext env;
   6748   v8::Isolate* isolate = env->GetIsolate();
   6749   v8::HandleScope scope(isolate);
   6750 
   6751   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
   6752   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   6753 
   6754   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   6755   env->Global()->Set(v8_str("undetectable"), obj);
   6756 
   6757   Local<String> source = v8_str("undetectable.x = 42;"
   6758                                 "undetectable.x");
   6759 
   6760   Local<Script> script = v8_compile(source);
   6761 
   6762   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
   6763 
   6764   ExpectBoolean("Object.isExtensible(undetectable)", true);
   6765 
   6766   source = v8_str("Object.preventExtensions(undetectable);");
   6767   script = v8_compile(source);
   6768   script->Run();
   6769   ExpectBoolean("Object.isExtensible(undetectable)", false);
   6770 
   6771   source = v8_str("undetectable.y = 2000;");
   6772   script = v8_compile(source);
   6773   script->Run();
   6774   ExpectBoolean("undetectable.y == undefined", true);
   6775 }
   6776 
   6777 
   6778 
   6779 THREADED_TEST(UndetectableString) {
   6780   LocalContext env;
   6781   v8::HandleScope scope(env->GetIsolate());
   6782 
   6783   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
   6784                                           String::kUndetectableString);
   6785   env->Global()->Set(v8_str("undetectable"), obj);
   6786 
   6787   ExpectString("undetectable", "foo");
   6788   ExpectString("typeof undetectable", "undefined");
   6789   ExpectString("typeof(undetectable)", "undefined");
   6790   ExpectBoolean("typeof undetectable == 'undefined'", true);
   6791   ExpectBoolean("typeof undetectable == 'string'", false);
   6792   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   6793   ExpectBoolean("!undetectable", true);
   6794 
   6795   ExpectObject("true&&undetectable", obj);
   6796   ExpectBoolean("false&&undetectable", false);
   6797   ExpectBoolean("true||undetectable", true);
   6798   ExpectObject("false||undetectable", obj);
   6799 
   6800   ExpectObject("undetectable&&true", obj);
   6801   ExpectObject("undetectable&&false", obj);
   6802   ExpectBoolean("undetectable||true", true);
   6803   ExpectBoolean("undetectable||false", false);
   6804 
   6805   ExpectBoolean("undetectable==null", true);
   6806   ExpectBoolean("null==undetectable", true);
   6807   ExpectBoolean("undetectable==undefined", true);
   6808   ExpectBoolean("undefined==undetectable", true);
   6809   ExpectBoolean("undetectable==undetectable", true);
   6810 
   6811 
   6812   ExpectBoolean("undetectable===null", false);
   6813   ExpectBoolean("null===undetectable", false);
   6814   ExpectBoolean("undetectable===undefined", false);
   6815   ExpectBoolean("undefined===undetectable", false);
   6816   ExpectBoolean("undetectable===undetectable", true);
   6817 }
   6818 
   6819 
   6820 TEST(UndetectableOptimized) {
   6821   i::FLAG_allow_natives_syntax = true;
   6822   LocalContext env;
   6823   v8::HandleScope scope(env->GetIsolate());
   6824 
   6825   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
   6826                                           String::kUndetectableString);
   6827   env->Global()->Set(v8_str("undetectable"), obj);
   6828   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
   6829 
   6830   ExpectString(
   6831       "function testBranch() {"
   6832       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
   6833       "  if (%_IsUndetectableObject(detectable)) throw 2;"
   6834       "}\n"
   6835       "function testBool() {"
   6836       "  var b1 = !%_IsUndetectableObject(undetectable);"
   6837       "  var b2 = %_IsUndetectableObject(detectable);"
   6838       "  if (b1) throw 3;"
   6839       "  if (b2) throw 4;"
   6840       "  return b1 == b2;"
   6841       "}\n"
   6842       "%OptimizeFunctionOnNextCall(testBranch);"
   6843       "%OptimizeFunctionOnNextCall(testBool);"
   6844       "for (var i = 0; i < 10; i++) {"
   6845       "  testBranch();"
   6846       "  testBool();"
   6847       "}\n"
   6848       "\"PASS\"",
   6849       "PASS");
   6850 }
   6851 
   6852 
   6853 // The point of this test is type checking. We run it only so compilers
   6854 // don't complain about an unused function.
   6855 TEST(PersistentHandles) {
   6856   LocalContext env;
   6857   v8::Isolate* isolate = CcTest::isolate();
   6858   v8::HandleScope scope(isolate);
   6859   Local<String> str = v8_str("foo");
   6860   v8::Persistent<String> p_str(isolate, str);
   6861   p_str.Reset();
   6862   Local<Script> scr = v8_compile("");
   6863   v8::Persistent<Script> p_scr(isolate, scr);
   6864   p_scr.Reset();
   6865   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6866   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
   6867   p_templ.Reset();
   6868 }
   6869 
   6870 
   6871 static void HandleLogDelegator(
   6872     const v8::FunctionCallbackInfo<v8::Value>& args) {
   6873   ApiTestFuzzer::Fuzz();
   6874 }
   6875 
   6876 
   6877 THREADED_TEST(GlobalObjectTemplate) {
   6878   v8::Isolate* isolate = CcTest::isolate();
   6879   v8::HandleScope handle_scope(isolate);
   6880   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
   6881   global_template->Set(v8_str("JSNI_Log"),
   6882                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
   6883   v8::Local<Context> context = Context::New(isolate, 0, global_template);
   6884   Context::Scope context_scope(context);
   6885   CompileRun("JSNI_Log('LOG')");
   6886 }
   6887 
   6888 
   6889 static const char* kSimpleExtensionSource =
   6890   "function Foo() {"
   6891   "  return 4;"
   6892   "}";
   6893 
   6894 
   6895 TEST(SimpleExtensions) {
   6896   v8::HandleScope handle_scope(CcTest::isolate());
   6897   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
   6898   const char* extension_names[] = { "simpletest" };
   6899   v8::ExtensionConfiguration extensions(1, extension_names);
   6900   v8::Handle<Context> context =
   6901       Context::New(CcTest::isolate(), &extensions);
   6902   Context::Scope lock(context);
   6903   v8::Handle<Value> result = CompileRun("Foo()");
   6904   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
   6905 }
   6906 
   6907 
   6908 static const char* kStackTraceFromExtensionSource =
   6909   "function foo() {"
   6910   "  throw new Error();"
   6911   "}"
   6912   "function bar() {"
   6913   "  foo();"
   6914   "}";
   6915 
   6916 
   6917 TEST(StackTraceInExtension) {
   6918   v8::HandleScope handle_scope(CcTest::isolate());
   6919   v8::RegisterExtension(new Extension("stacktracetest",
   6920                         kStackTraceFromExtensionSource));
   6921   const char* extension_names[] = { "stacktracetest" };
   6922   v8::ExtensionConfiguration extensions(1, extension_names);
   6923   v8::Handle<Context> context =
   6924       Context::New(CcTest::isolate(), &extensions);
   6925   Context::Scope lock(context);
   6926   CompileRun("function user() { bar(); }"
   6927              "var error;"
   6928              "try{ user(); } catch (e) { error = e; }");
   6929   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
   6930   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
   6931   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
   6932 }
   6933 
   6934 
   6935 TEST(NullExtensions) {
   6936   v8::HandleScope handle_scope(CcTest::isolate());
   6937   v8::RegisterExtension(new Extension("nulltest", NULL));
   6938   const char* extension_names[] = { "nulltest" };
   6939   v8::ExtensionConfiguration extensions(1, extension_names);
   6940   v8::Handle<Context> context =
   6941       Context::New(CcTest::isolate(), &extensions);
   6942   Context::Scope lock(context);
   6943   v8::Handle<Value> result = CompileRun("1+3");
   6944   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
   6945 }
   6946 
   6947 
   6948 static const char* kEmbeddedExtensionSource =
   6949     "function Ret54321(){return 54321;}~~@@$"
   6950     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
   6951 static const int kEmbeddedExtensionSourceValidLen = 34;
   6952 
   6953 
   6954 TEST(ExtensionMissingSourceLength) {
   6955   v8::HandleScope handle_scope(CcTest::isolate());
   6956   v8::RegisterExtension(new Extension("srclentest_fail",
   6957                                       kEmbeddedExtensionSource));
   6958   const char* extension_names[] = { "srclentest_fail" };
   6959   v8::ExtensionConfiguration extensions(1, extension_names);
   6960   v8::Handle<Context> context =
   6961       Context::New(CcTest::isolate(), &extensions);
   6962   CHECK_EQ(0, *context);
   6963 }
   6964 
   6965 
   6966 TEST(ExtensionWithSourceLength) {
   6967   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
   6968        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
   6969     v8::HandleScope handle_scope(CcTest::isolate());
   6970     i::ScopedVector<char> extension_name(32);
   6971     i::SNPrintF(extension_name, "ext #%d", source_len);
   6972     v8::RegisterExtension(new Extension(extension_name.start(),
   6973                                         kEmbeddedExtensionSource, 0, 0,
   6974                                         source_len));
   6975     const char* extension_names[1] = { extension_name.start() };
   6976     v8::ExtensionConfiguration extensions(1, extension_names);
   6977     v8::Handle<Context> context =
   6978       Context::New(CcTest::isolate(), &extensions);
   6979     if (source_len == kEmbeddedExtensionSourceValidLen) {
   6980       Context::Scope lock(context);
   6981       v8::Handle<Value> result = CompileRun("Ret54321()");
   6982       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
   6983     } else {
   6984       // Anything but exactly the right length should fail to compile.
   6985       CHECK_EQ(0, *context);
   6986     }
   6987   }
   6988 }
   6989 
   6990 
   6991 static const char* kEvalExtensionSource1 =
   6992   "function UseEval1() {"
   6993   "  var x = 42;"
   6994   "  return eval('x');"
   6995   "}";
   6996 
   6997 
   6998 static const char* kEvalExtensionSource2 =
   6999   "(function() {"
   7000   "  var x = 42;"
   7001   "  function e() {"
   7002   "    return eval('x');"
   7003   "  }"
   7004   "  this.UseEval2 = e;"
   7005   "})()";
   7006 
   7007 
   7008 TEST(UseEvalFromExtension) {
   7009   v8::HandleScope handle_scope(CcTest::isolate());
   7010   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
   7011   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
   7012   const char* extension_names[] = { "evaltest1", "evaltest2" };
   7013   v8::ExtensionConfiguration extensions(2, extension_names);
   7014   v8::Handle<Context> context =
   7015       Context::New(CcTest::isolate(), &extensions);
   7016   Context::Scope lock(context);
   7017   v8::Handle<Value> result = CompileRun("UseEval1()");
   7018   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
   7019   result = CompileRun("UseEval2()");
   7020   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
   7021 }
   7022 
   7023 
   7024 static const char* kWithExtensionSource1 =
   7025   "function UseWith1() {"
   7026   "  var x = 42;"
   7027   "  with({x:87}) { return x; }"
   7028   "}";
   7029 
   7030 
   7031 
   7032 static const char* kWithExtensionSource2 =
   7033   "(function() {"
   7034   "  var x = 42;"
   7035   "  function e() {"
   7036   "    with ({x:87}) { return x; }"
   7037   "  }"
   7038   "  this.UseWith2 = e;"
   7039   "})()";
   7040 
   7041 
   7042 TEST(UseWithFromExtension) {
   7043   v8::HandleScope handle_scope(CcTest::isolate());
   7044   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
   7045   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
   7046   const char* extension_names[] = { "withtest1", "withtest2" };
   7047   v8::ExtensionConfiguration extensions(2, extension_names);
   7048   v8::Handle<Context> context =
   7049       Context::New(CcTest::isolate(), &extensions);
   7050   Context::Scope lock(context);
   7051   v8::Handle<Value> result = CompileRun("UseWith1()");
   7052   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
   7053   result = CompileRun("UseWith2()");
   7054   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
   7055 }
   7056 
   7057 
   7058 TEST(AutoExtensions) {
   7059   v8::HandleScope handle_scope(CcTest::isolate());
   7060   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
   7061   extension->set_auto_enable(true);
   7062   v8::RegisterExtension(extension);
   7063   v8::Handle<Context> context =
   7064       Context::New(CcTest::isolate());
   7065   Context::Scope lock(context);
   7066   v8::Handle<Value> result = CompileRun("Foo()");
   7067   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
   7068 }
   7069 
   7070 
   7071 static const char* kSyntaxErrorInExtensionSource =
   7072     "[";
   7073 
   7074 
   7075 // Test that a syntax error in an extension does not cause a fatal
   7076 // error but results in an empty context.
   7077 TEST(SyntaxErrorExtensions) {
   7078   v8::HandleScope handle_scope(CcTest::isolate());
   7079   v8::RegisterExtension(new Extension("syntaxerror",
   7080                                       kSyntaxErrorInExtensionSource));
   7081   const char* extension_names[] = { "syntaxerror" };
   7082   v8::ExtensionConfiguration extensions(1, extension_names);
   7083   v8::Handle<Context> context =
   7084       Context::New(CcTest::isolate(), &extensions);
   7085   CHECK(context.IsEmpty());
   7086 }
   7087 
   7088 
   7089 static const char* kExceptionInExtensionSource =
   7090     "throw 42";
   7091 
   7092 
   7093 // Test that an exception when installing an extension does not cause
   7094 // a fatal error but results in an empty context.
   7095 TEST(ExceptionExtensions) {
   7096   v8::HandleScope handle_scope(CcTest::isolate());
   7097   v8::RegisterExtension(new Extension("exception",
   7098                                       kExceptionInExtensionSource));
   7099   const char* extension_names[] = { "exception" };
   7100   v8::ExtensionConfiguration extensions(1, extension_names);
   7101   v8::Handle<Context> context =
   7102       Context::New(CcTest::isolate(), &extensions);
   7103   CHECK(context.IsEmpty());
   7104 }
   7105 
   7106 
   7107 static const char* kNativeCallInExtensionSource =
   7108     "function call_runtime_last_index_of(x) {"
   7109     "  return %StringLastIndexOf(x, 'bob', 10);"
   7110     "}";
   7111 
   7112 
   7113 static const char* kNativeCallTest =
   7114     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
   7115 
   7116 // Test that a native runtime calls are supported in extensions.
   7117 TEST(NativeCallInExtensions) {
   7118   v8::HandleScope handle_scope(CcTest::isolate());
   7119   v8::RegisterExtension(new Extension("nativecall",
   7120                                       kNativeCallInExtensionSource));
   7121   const char* extension_names[] = { "nativecall" };
   7122   v8::ExtensionConfiguration extensions(1, extension_names);
   7123   v8::Handle<Context> context =
   7124       Context::New(CcTest::isolate(), &extensions);
   7125   Context::Scope lock(context);
   7126   v8::Handle<Value> result = CompileRun(kNativeCallTest);
   7127   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
   7128 }
   7129 
   7130 
   7131 class NativeFunctionExtension : public Extension {
   7132  public:
   7133   NativeFunctionExtension(const char* name,
   7134                           const char* source,
   7135                           v8::FunctionCallback fun = &Echo)
   7136       : Extension(name, source),
   7137         function_(fun) { }
   7138 
   7139   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
   7140       v8::Isolate* isolate,
   7141       v8::Handle<v8::String> name) {
   7142     return v8::FunctionTemplate::New(isolate, function_);
   7143   }
   7144 
   7145   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
   7146     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
   7147   }
   7148  private:
   7149   v8::FunctionCallback function_;
   7150 };
   7151 
   7152 
   7153 TEST(NativeFunctionDeclaration) {
   7154   v8::HandleScope handle_scope(CcTest::isolate());
   7155   const char* name = "nativedecl";
   7156   v8::RegisterExtension(new NativeFunctionExtension(name,
   7157                                                     "native function foo();"));
   7158   const char* extension_names[] = { name };
   7159   v8::ExtensionConfiguration extensions(1, extension_names);
   7160   v8::Handle<Context> context =
   7161       Context::New(CcTest::isolate(), &extensions);
   7162   Context::Scope lock(context);
   7163   v8::Handle<Value> result = CompileRun("foo(42);");
   7164   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
   7165 }
   7166 
   7167 
   7168 TEST(NativeFunctionDeclarationError) {
   7169   v8::HandleScope handle_scope(CcTest::isolate());
   7170   const char* name = "nativedeclerr";
   7171   // Syntax error in extension code.
   7172   v8::RegisterExtension(new NativeFunctionExtension(name,
   7173                                                     "native\nfunction foo();"));
   7174   const char* extension_names[] = { name };
   7175   v8::ExtensionConfiguration extensions(1, extension_names);
   7176   v8::Handle<Context> context =
   7177       Context::New(CcTest::isolate(), &extensions);
   7178   CHECK(context.IsEmpty());
   7179 }
   7180 
   7181 
   7182 TEST(NativeFunctionDeclarationErrorEscape) {
   7183   v8::HandleScope handle_scope(CcTest::isolate());
   7184   const char* name = "nativedeclerresc";
   7185   // Syntax error in extension code - escape code in "native" means that
   7186   // it's not treated as a keyword.
   7187   v8::RegisterExtension(new NativeFunctionExtension(
   7188       name,
   7189       "nativ\\u0065 function foo();"));
   7190   const char* extension_names[] = { name };
   7191   v8::ExtensionConfiguration extensions(1, extension_names);
   7192   v8::Handle<Context> context =
   7193       Context::New(CcTest::isolate(), &extensions);
   7194   CHECK(context.IsEmpty());
   7195 }
   7196 
   7197 
   7198 static void CheckDependencies(const char* name, const char* expected) {
   7199   v8::HandleScope handle_scope(CcTest::isolate());
   7200   v8::ExtensionConfiguration config(1, &name);
   7201   LocalContext context(&config);
   7202   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
   7203            context->Global()->Get(v8_str("loaded")));
   7204 }
   7205 
   7206 
   7207 /*
   7208  * Configuration:
   7209  *
   7210  *     /-- B <--\
   7211  * A <-          -- D <-- E
   7212  *     \-- C <--/
   7213  */
   7214 THREADED_TEST(ExtensionDependency) {
   7215   static const char* kEDeps[] = { "D" };
   7216   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
   7217   static const char* kDDeps[] = { "B", "C" };
   7218   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
   7219   static const char* kBCDeps[] = { "A" };
   7220   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
   7221   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
   7222   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
   7223   CheckDependencies("A", "undefinedA");
   7224   CheckDependencies("B", "undefinedAB");
   7225   CheckDependencies("C", "undefinedAC");
   7226   CheckDependencies("D", "undefinedABCD");
   7227   CheckDependencies("E", "undefinedABCDE");
   7228   v8::HandleScope handle_scope(CcTest::isolate());
   7229   static const char* exts[2] = { "C", "E" };
   7230   v8::ExtensionConfiguration config(2, exts);
   7231   LocalContext context(&config);
   7232   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
   7233 }
   7234 
   7235 
   7236 static const char* kExtensionTestScript =
   7237   "native function A();"
   7238   "native function B();"
   7239   "native function C();"
   7240   "function Foo(i) {"
   7241   "  if (i == 0) return A();"
   7242   "  if (i == 1) return B();"
   7243   "  if (i == 2) return C();"
   7244   "}";
   7245 
   7246 
   7247 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
   7248   ApiTestFuzzer::Fuzz();
   7249   if (args.IsConstructCall()) {
   7250     args.This()->Set(v8_str("data"), args.Data());
   7251     args.GetReturnValue().SetNull();
   7252     return;
   7253   }
   7254   args.GetReturnValue().Set(args.Data());
   7255 }
   7256 
   7257 
   7258 class FunctionExtension : public Extension {
   7259  public:
   7260   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
   7261   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
   7262       v8::Isolate* isolate,
   7263       v8::Handle<String> name);
   7264 };
   7265 
   7266 
   7267 static int lookup_count = 0;
   7268 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
   7269     v8::Isolate* isolate, v8::Handle<String> name) {
   7270   lookup_count++;
   7271   if (name->Equals(v8_str("A"))) {
   7272     return v8::FunctionTemplate::New(
   7273         isolate, CallFun, v8::Integer::New(isolate, 8));
   7274   } else if (name->Equals(v8_str("B"))) {
   7275     return v8::FunctionTemplate::New(
   7276         isolate, CallFun, v8::Integer::New(isolate, 7));
   7277   } else if (name->Equals(v8_str("C"))) {
   7278     return v8::FunctionTemplate::New(
   7279         isolate, CallFun, v8::Integer::New(isolate, 6));
   7280   } else {
   7281     return v8::Handle<v8::FunctionTemplate>();
   7282   }
   7283 }
   7284 
   7285 
   7286 THREADED_TEST(FunctionLookup) {
   7287   v8::RegisterExtension(new FunctionExtension());
   7288   v8::HandleScope handle_scope(CcTest::isolate());
   7289   static const char* exts[1] = { "functiontest" };
   7290   v8::ExtensionConfiguration config(1, exts);
   7291   LocalContext context(&config);
   7292   CHECK_EQ(3, lookup_count);
   7293   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
   7294            CompileRun("Foo(0)"));
   7295   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
   7296            CompileRun("Foo(1)"));
   7297   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
   7298            CompileRun("Foo(2)"));
   7299 }
   7300 
   7301 
   7302 THREADED_TEST(NativeFunctionConstructCall) {
   7303   v8::RegisterExtension(new FunctionExtension());
   7304   v8::HandleScope handle_scope(CcTest::isolate());
   7305   static const char* exts[1] = { "functiontest" };
   7306   v8::ExtensionConfiguration config(1, exts);
   7307   LocalContext context(&config);
   7308   for (int i = 0; i < 10; i++) {
   7309     // Run a few times to ensure that allocation of objects doesn't
   7310     // change behavior of a constructor function.
   7311     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
   7312              CompileRun("(new A()).data"));
   7313     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
   7314              CompileRun("(new B()).data"));
   7315     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
   7316              CompileRun("(new C()).data"));
   7317   }
   7318 }
   7319 
   7320 
   7321 static const char* last_location;
   7322 static const char* last_message;
   7323 void StoringErrorCallback(const char* location, const char* message) {
   7324   if (last_location == NULL) {
   7325     last_location = location;
   7326     last_message = message;
   7327   }
   7328 }
   7329 
   7330 
   7331 // ErrorReporting creates a circular extensions configuration and
   7332 // tests that the fatal error handler gets called.  This renders V8
   7333 // unusable and therefore this test cannot be run in parallel.
   7334 TEST(ErrorReporting) {
   7335   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   7336   static const char* aDeps[] = { "B" };
   7337   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
   7338   static const char* bDeps[] = { "A" };
   7339   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
   7340   last_location = NULL;
   7341   v8::ExtensionConfiguration config(1, bDeps);
   7342   v8::Handle<Context> context =
   7343       Context::New(CcTest::isolate(), &config);
   7344   CHECK(context.IsEmpty());
   7345   CHECK_NE(last_location, NULL);
   7346 }
   7347 
   7348 
   7349 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
   7350                                              v8::Handle<Value> data) {
   7351   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
   7352   CHECK_EQ(v8::Undefined(CcTest::isolate()),
   7353       message->GetScriptOrigin().ResourceName());
   7354   message->GetLineNumber();
   7355   message->GetSourceLine();
   7356 }
   7357 
   7358 
   7359 THREADED_TEST(ErrorWithMissingScriptInfo) {
   7360   LocalContext context;
   7361   v8::HandleScope scope(context->GetIsolate());
   7362   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
   7363   CompileRun("throw Error()");
   7364   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
   7365 }
   7366 
   7367 
   7368 struct FlagAndPersistent {
   7369   bool flag;
   7370   v8::Persistent<v8::Object> handle;
   7371 };
   7372 
   7373 
   7374 static void DisposeAndSetFlag(
   7375     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7376   data.GetParameter()->handle.Reset();
   7377   data.GetParameter()->flag = true;
   7378 }
   7379 
   7380 
   7381 THREADED_TEST(IndependentWeakHandle) {
   7382   v8::Isolate* iso = CcTest::isolate();
   7383   v8::HandleScope scope(iso);
   7384   v8::Handle<Context> context = Context::New(iso);
   7385   Context::Scope context_scope(context);
   7386 
   7387   FlagAndPersistent object_a, object_b;
   7388 
   7389   {
   7390     v8::HandleScope handle_scope(iso);
   7391     object_a.handle.Reset(iso, v8::Object::New(iso));
   7392     object_b.handle.Reset(iso, v8::Object::New(iso));
   7393   }
   7394 
   7395   object_a.flag = false;
   7396   object_b.flag = false;
   7397   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
   7398   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
   7399   CHECK(!object_b.handle.IsIndependent());
   7400   object_a.handle.MarkIndependent();
   7401   object_b.handle.MarkIndependent();
   7402   CHECK(object_b.handle.IsIndependent());
   7403   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   7404   CHECK(object_a.flag);
   7405   CHECK(object_b.flag);
   7406 }
   7407 
   7408 
   7409 static void InvokeScavenge() {
   7410   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   7411 }
   7412 
   7413 
   7414 static void InvokeMarkSweep() {
   7415   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   7416 }
   7417 
   7418 
   7419 static void ForceScavenge(
   7420     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7421   data.GetParameter()->handle.Reset();
   7422   data.GetParameter()->flag = true;
   7423   InvokeScavenge();
   7424 }
   7425 
   7426 
   7427 static void ForceMarkSweep(
   7428     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7429   data.GetParameter()->handle.Reset();
   7430   data.GetParameter()->flag = true;
   7431   InvokeMarkSweep();
   7432 }
   7433 
   7434 
   7435 THREADED_TEST(GCFromWeakCallbacks) {
   7436   v8::Isolate* isolate = CcTest::isolate();
   7437   v8::HandleScope scope(isolate);
   7438   v8::Handle<Context> context = Context::New(isolate);
   7439   Context::Scope context_scope(context);
   7440 
   7441   static const int kNumberOfGCTypes = 2;
   7442   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
   7443       Callback;
   7444   Callback gc_forcing_callback[kNumberOfGCTypes] =
   7445       {&ForceScavenge, &ForceMarkSweep};
   7446 
   7447   typedef void (*GCInvoker)();
   7448   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
   7449 
   7450   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
   7451     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
   7452       FlagAndPersistent object;
   7453       {
   7454         v8::HandleScope handle_scope(isolate);
   7455         object.handle.Reset(isolate, v8::Object::New(isolate));
   7456       }
   7457       object.flag = false;
   7458       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
   7459       object.handle.MarkIndependent();
   7460       invoke_gc[outer_gc]();
   7461       CHECK(object.flag);
   7462     }
   7463   }
   7464 }
   7465 
   7466 
   7467 static void RevivingCallback(
   7468     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7469   data.GetParameter()->handle.ClearWeak();
   7470   data.GetParameter()->flag = true;
   7471 }
   7472 
   7473 
   7474 THREADED_TEST(IndependentHandleRevival) {
   7475   v8::Isolate* isolate = CcTest::isolate();
   7476   v8::HandleScope scope(isolate);
   7477   v8::Handle<Context> context = Context::New(isolate);
   7478   Context::Scope context_scope(context);
   7479 
   7480   FlagAndPersistent object;
   7481   {
   7482     v8::HandleScope handle_scope(isolate);
   7483     v8::Local<v8::Object> o = v8::Object::New(isolate);
   7484     object.handle.Reset(isolate, o);
   7485     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
   7486     v8::Local<String> y_str = v8_str("y");
   7487     o->Set(y_str, y_str);
   7488   }
   7489   object.flag = false;
   7490   object.handle.SetWeak(&object, &RevivingCallback);
   7491   object.handle.MarkIndependent();
   7492   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   7493   CHECK(object.flag);
   7494   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   7495   {
   7496     v8::HandleScope handle_scope(isolate);
   7497     v8::Local<v8::Object> o =
   7498         v8::Local<v8::Object>::New(isolate, object.handle);
   7499     v8::Local<String> y_str = v8_str("y");
   7500     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
   7501     CHECK(o->Get(y_str)->Equals(y_str));
   7502   }
   7503 }
   7504 
   7505 
   7506 v8::Handle<Function> args_fun;
   7507 
   7508 
   7509 static void ArgumentsTestCallback(
   7510     const v8::FunctionCallbackInfo<v8::Value>& args) {
   7511   ApiTestFuzzer::Fuzz();
   7512   v8::Isolate* isolate = args.GetIsolate();
   7513   CHECK_EQ(args_fun, args.Callee());
   7514   CHECK_EQ(3, args.Length());
   7515   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
   7516   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
   7517   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
   7518   CHECK_EQ(v8::Undefined(isolate), args[3]);
   7519   v8::HandleScope scope(args.GetIsolate());
   7520   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   7521 }
   7522 
   7523 
   7524 THREADED_TEST(Arguments) {
   7525   v8::Isolate* isolate = CcTest::isolate();
   7526   v8::HandleScope scope(isolate);
   7527   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
   7528   global->Set(v8_str("f"),
   7529               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
   7530   LocalContext context(NULL, global);
   7531   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
   7532   v8_compile("f(1, 2, 3)")->Run();
   7533 }
   7534 
   7535 
   7536 static void NoBlockGetterX(Local<String> name,
   7537                            const v8::PropertyCallbackInfo<v8::Value>&) {
   7538 }
   7539 
   7540 
   7541 static void NoBlockGetterI(uint32_t index,
   7542                            const v8::PropertyCallbackInfo<v8::Value>&) {
   7543 }
   7544 
   7545 
   7546 static void PDeleter(Local<String> name,
   7547                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   7548   if (!name->Equals(v8_str("foo"))) {
   7549     return;  // not intercepted
   7550   }
   7551 
   7552   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
   7553 }
   7554 
   7555 
   7556 static void IDeleter(uint32_t index,
   7557                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   7558   if (index != 2) {
   7559     return;  // not intercepted
   7560   }
   7561 
   7562   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
   7563 }
   7564 
   7565 
   7566 THREADED_TEST(Deleter) {
   7567   v8::Isolate* isolate = CcTest::isolate();
   7568   v8::HandleScope scope(isolate);
   7569   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   7570   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
   7571   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
   7572   LocalContext context;
   7573   context->Global()->Set(v8_str("k"), obj->NewInstance());
   7574   CompileRun(
   7575     "k.foo = 'foo';"
   7576     "k.bar = 'bar';"
   7577     "k[2] = 2;"
   7578     "k[4] = 4;");
   7579   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
   7580   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
   7581 
   7582   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
   7583   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
   7584 
   7585   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
   7586   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
   7587 
   7588   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
   7589   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
   7590 }
   7591 
   7592 
   7593 static void GetK(Local<String> name,
   7594                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   7595   ApiTestFuzzer::Fuzz();
   7596   if (name->Equals(v8_str("foo")) ||
   7597       name->Equals(v8_str("bar")) ||
   7598       name->Equals(v8_str("baz"))) {
   7599     info.GetReturnValue().SetUndefined();
   7600   }
   7601 }
   7602 
   7603 
   7604 static void IndexedGetK(uint32_t index,
   7605                         const v8::PropertyCallbackInfo<v8::Value>& info) {
   7606   ApiTestFuzzer::Fuzz();
   7607   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
   7608 }
   7609 
   7610 
   7611 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
   7612   ApiTestFuzzer::Fuzz();
   7613   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
   7614   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
   7615   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
   7616   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
   7617   info.GetReturnValue().Set(result);
   7618 }
   7619 
   7620 
   7621 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
   7622   ApiTestFuzzer::Fuzz();
   7623   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   7624   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
   7625   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
   7626   info.GetReturnValue().Set(result);
   7627 }
   7628 
   7629 
   7630 THREADED_TEST(Enumerators) {
   7631   v8::Isolate* isolate = CcTest::isolate();
   7632   v8::HandleScope scope(isolate);
   7633   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   7634   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
   7635   obj->SetIndex