deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <map>
31 #include <string>
32
33 #include "test/cctest/test-api.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "include/v8-util.h"
40 #include "src/api.h"
41 #include "src/arguments.h"
42 #include "src/base/platform/platform.h"
43 #include "src/compilation-cache.h"
44 #include "src/execution.h"
45 #include "src/objects.h"
46 #include "src/parser.h"
47 #include "src/smart-pointers.h"
48 #include "src/unicode-inl.h"
49 #include "src/utils.h"
50 #include "src/vm-state.h"
51
52 static const bool kLogThreading = false;
53
54 using ::v8::Boolean;
55 using ::v8::BooleanObject;
56 using ::v8::Context;
57 using ::v8::Extension;
58 using ::v8::Function;
59 using ::v8::FunctionTemplate;
60 using ::v8::Handle;
61 using ::v8::HandleScope;
62 using ::v8::Local;
63 using ::v8::Maybe;
64 using ::v8::Message;
65 using ::v8::MessageCallback;
66 using ::v8::Name;
67 using ::v8::None;
68 using ::v8::Object;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
71 using ::v8::PropertyAttribute;
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(signature_expected_receiver->Equals(args.Holder()));
111   CHECK(signature_expected_receiver->Equals(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 Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
121   info.GetReturnValue().Set(42);
122 }
123
124
125 // Tests that call v8::V8::Dispose() cannot be threaded.
126 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
127   CHECK(v8::V8::Initialize());
128   CHECK(v8::V8::Dispose());
129 }
130
131
132 // Tests that call v8::V8::Dispose() cannot be threaded.
133 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
134   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
135   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
136   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
137   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
138   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
139 }
140
141
142 THREADED_TEST(Handles) {
143   v8::HandleScope scope(CcTest::isolate());
144   Local<Context> local_env;
145   {
146     LocalContext env;
147     local_env = env.local();
148   }
149
150   // Local context should still be live.
151   CHECK(!local_env.IsEmpty());
152   local_env->Enter();
153
154   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
155   CHECK(!undef.IsEmpty());
156   CHECK(undef->IsUndefined());
157
158   const char* source = "1 + 2 + 3";
159   Local<Script> script = v8_compile(source);
160   CHECK_EQ(6, script->Run()->Int32Value());
161
162   local_env->Exit();
163 }
164
165
166 THREADED_TEST(IsolateOfContext) {
167   v8::HandleScope scope(CcTest::isolate());
168   v8::Handle<Context> env = Context::New(CcTest::isolate());
169
170   CHECK(!env->GetIsolate()->InContext());
171   CHECK(env->GetIsolate() == CcTest::isolate());
172   env->Enter();
173   CHECK(env->GetIsolate()->InContext());
174   CHECK(env->GetIsolate() == CcTest::isolate());
175   env->Exit();
176   CHECK(!env->GetIsolate()->InContext());
177   CHECK(env->GetIsolate() == CcTest::isolate());
178 }
179
180
181 static void TestSignature(const char* loop_js, Local<Value> receiver,
182                           v8::Isolate* isolate) {
183   i::ScopedVector<char> source(200);
184   i::SNPrintF(source,
185               "for (var i = 0; i < 10; i++) {"
186               "  %s"
187               "}",
188               loop_js);
189   signature_callback_count = 0;
190   signature_expected_receiver = receiver;
191   bool expected_to_throw = receiver.IsEmpty();
192   v8::TryCatch try_catch;
193   CompileRun(source.start());
194   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
195   if (!expected_to_throw) {
196     CHECK_EQ(10, signature_callback_count);
197   } else {
198     CHECK(v8_str("TypeError: Illegal invocation")
199               ->Equals(try_catch.Exception()->ToString(isolate)));
200   }
201 }
202
203
204 THREADED_TEST(ReceiverSignature) {
205   LocalContext env;
206   v8::Isolate* isolate = env->GetIsolate();
207   v8::HandleScope scope(isolate);
208   // Setup templates.
209   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
210   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
211   v8::Handle<v8::FunctionTemplate> callback_sig =
212       v8::FunctionTemplate::New(
213           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
214   v8::Handle<v8::FunctionTemplate> callback =
215       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
216   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
217   sub_fun->Inherit(fun);
218   v8::Handle<v8::FunctionTemplate> unrel_fun =
219       v8::FunctionTemplate::New(isolate);
220   // Install properties.
221   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
222   fun_proto->Set(v8_str("prop_sig"), callback_sig);
223   fun_proto->Set(v8_str("prop"), callback);
224   fun_proto->SetAccessorProperty(
225       v8_str("accessor_sig"), callback_sig, callback_sig);
226   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
227   // Instantiate templates.
228   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
229   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
230   // Setup global variables.
231   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
232   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
233   env->Global()->Set(v8_str("fun_instance"), fun_instance);
234   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
235   CompileRun(
236       "var accessor_sig_key = 'accessor_sig';"
237       "var accessor_key = 'accessor';"
238       "var prop_sig_key = 'prop_sig';"
239       "var prop_key = 'prop';"
240       ""
241       "function copy_props(obj) {"
242       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
243       "  var source = Fun.prototype;"
244       "  for (var i in keys) {"
245       "    var key = keys[i];"
246       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
247       "    Object.defineProperty(obj, key, desc);"
248       "  }"
249       "}"
250       ""
251       "var obj = {};"
252       "copy_props(obj);"
253       "var unrel = new UnrelFun();"
254       "copy_props(unrel);");
255   // Test with and without ICs
256   const char* test_objects[] = {
257       "fun_instance", "sub_fun_instance", "obj", "unrel" };
258   unsigned bad_signature_start_offset = 2;
259   for (unsigned i = 0; i < arraysize(test_objects); i++) {
260     i::ScopedVector<char> source(200);
261     i::SNPrintF(
262         source, "var test_object = %s; test_object", test_objects[i]);
263     Local<Value> test_object = CompileRun(source.start());
264     TestSignature("test_object.prop();", test_object, isolate);
265     TestSignature("test_object.accessor;", test_object, isolate);
266     TestSignature("test_object[accessor_key];", test_object, isolate);
267     TestSignature("test_object.accessor = 1;", test_object, isolate);
268     TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
269     if (i >= bad_signature_start_offset) test_object = Local<Value>();
270     TestSignature("test_object.prop_sig();", test_object, isolate);
271     TestSignature("test_object.accessor_sig;", test_object, isolate);
272     TestSignature("test_object[accessor_sig_key];", test_object, isolate);
273     TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
274     TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
275   }
276 }
277
278
279 THREADED_TEST(HulIgennem) {
280   LocalContext env;
281   v8::Isolate* isolate = env->GetIsolate();
282   v8::HandleScope scope(isolate);
283   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
284   Local<String> undef_str = undef->ToString(isolate);
285   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
286   undef_str->WriteUtf8(value);
287   CHECK_EQ(0, strcmp(value, "undefined"));
288   i::DeleteArray(value);
289 }
290
291
292 THREADED_TEST(Access) {
293   LocalContext env;
294   v8::Isolate* isolate = env->GetIsolate();
295   v8::HandleScope scope(isolate);
296   Local<v8::Object> obj = v8::Object::New(isolate);
297   Local<Value> foo_before = obj->Get(v8_str("foo"));
298   CHECK(foo_before->IsUndefined());
299   Local<String> bar_str = v8_str("bar");
300   obj->Set(v8_str("foo"), bar_str);
301   Local<Value> foo_after = obj->Get(v8_str("foo"));
302   CHECK(!foo_after->IsUndefined());
303   CHECK(foo_after->IsString());
304   CHECK(bar_str->Equals(foo_after));
305 }
306
307
308 THREADED_TEST(AccessElement) {
309   LocalContext env;
310   v8::HandleScope scope(env->GetIsolate());
311   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
312   Local<Value> before = obj->Get(1);
313   CHECK(before->IsUndefined());
314   Local<String> bar_str = v8_str("bar");
315   obj->Set(1, bar_str);
316   Local<Value> after = obj->Get(1);
317   CHECK(!after->IsUndefined());
318   CHECK(after->IsString());
319   CHECK(bar_str->Equals(after));
320
321   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
322   CHECK(v8_str("a")->Equals(value->Get(0)));
323   CHECK(v8_str("b")->Equals(value->Get(1)));
324 }
325
326
327 THREADED_TEST(Script) {
328   LocalContext env;
329   v8::HandleScope scope(env->GetIsolate());
330   const char* source = "1 + 2 + 3";
331   Local<Script> script = v8_compile(source);
332   CHECK_EQ(6, script->Run()->Int32Value());
333 }
334
335
336 class TestResource: public String::ExternalStringResource {
337  public:
338   explicit TestResource(uint16_t* data, int* counter = NULL,
339                         bool owning_data = true)
340       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
341     while (data[length_]) ++length_;
342   }
343
344   ~TestResource() {
345     if (owning_data_) i::DeleteArray(data_);
346     if (counter_ != NULL) ++*counter_;
347   }
348
349   const uint16_t* data() const {
350     return data_;
351   }
352
353   size_t length() const {
354     return length_;
355   }
356
357  private:
358   uint16_t* data_;
359   size_t length_;
360   int* counter_;
361   bool owning_data_;
362 };
363
364
365 class TestOneByteResource : public String::ExternalOneByteStringResource {
366  public:
367   explicit TestOneByteResource(const char* data, int* counter = NULL,
368                                size_t offset = 0)
369       : orig_data_(data),
370         data_(data + offset),
371         length_(strlen(data) - offset),
372         counter_(counter) {}
373
374   ~TestOneByteResource() {
375     i::DeleteArray(orig_data_);
376     if (counter_ != NULL) ++*counter_;
377   }
378
379   const char* data() const {
380     return data_;
381   }
382
383   size_t length() const {
384     return length_;
385   }
386
387  private:
388   const char* orig_data_;
389   const char* data_;
390   size_t length_;
391   int* counter_;
392 };
393
394
395 THREADED_TEST(ScriptUsingStringResource) {
396   int dispose_count = 0;
397   const char* c_source = "1 + 2 * 3";
398   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
399   {
400     LocalContext env;
401     v8::HandleScope scope(env->GetIsolate());
402     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
403     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
404     Local<Script> script = v8_compile(source);
405     Local<Value> value = script->Run();
406     CHECK(value->IsNumber());
407     CHECK_EQ(7, value->Int32Value());
408     CHECK(source->IsExternal());
409     CHECK_EQ(resource,
410              static_cast<TestResource*>(source->GetExternalStringResource()));
411     String::Encoding encoding = String::UNKNOWN_ENCODING;
412     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
413              source->GetExternalStringResourceBase(&encoding));
414     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
415     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
416     CHECK_EQ(0, dispose_count);
417   }
418   CcTest::i_isolate()->compilation_cache()->Clear();
419   CcTest::heap()->CollectAllAvailableGarbage();
420   CHECK_EQ(1, dispose_count);
421 }
422
423
424 THREADED_TEST(ScriptUsingOneByteStringResource) {
425   int dispose_count = 0;
426   const char* c_source = "1 + 2 * 3";
427   {
428     LocalContext env;
429     v8::HandleScope scope(env->GetIsolate());
430     TestOneByteResource* resource =
431         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
432     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
433     CHECK(source->IsExternalOneByte());
434     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
435              source->GetExternalOneByteStringResource());
436     String::Encoding encoding = String::UNKNOWN_ENCODING;
437     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
438              source->GetExternalStringResourceBase(&encoding));
439     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
440     Local<Script> script = v8_compile(source);
441     Local<Value> value = script->Run();
442     CHECK(value->IsNumber());
443     CHECK_EQ(7, value->Int32Value());
444     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
445     CHECK_EQ(0, dispose_count);
446   }
447   CcTest::i_isolate()->compilation_cache()->Clear();
448   CcTest::heap()->CollectAllAvailableGarbage();
449   CHECK_EQ(1, dispose_count);
450 }
451
452
453 THREADED_TEST(ScriptMakingExternalString) {
454   int dispose_count = 0;
455   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
456   {
457     LocalContext env;
458     v8::HandleScope scope(env->GetIsolate());
459     Local<String> source =
460         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
461     // Trigger GCs so that the newly allocated string moves to old gen.
462     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
463     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
464     CHECK_EQ(source->IsExternal(), false);
465     CHECK_EQ(source->IsExternalOneByte(), false);
466     String::Encoding encoding = String::UNKNOWN_ENCODING;
467     CHECK(!source->GetExternalStringResourceBase(&encoding));
468     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
469     bool success = source->MakeExternal(new TestResource(two_byte_source,
470                                                          &dispose_count));
471     CHECK(success);
472     Local<Script> script = v8_compile(source);
473     Local<Value> value = script->Run();
474     CHECK(value->IsNumber());
475     CHECK_EQ(7, value->Int32Value());
476     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
477     CHECK_EQ(0, dispose_count);
478   }
479   CcTest::i_isolate()->compilation_cache()->Clear();
480   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
481   CHECK_EQ(1, dispose_count);
482 }
483
484
485 THREADED_TEST(ScriptMakingExternalOneByteString) {
486   int dispose_count = 0;
487   const char* c_source = "1 + 2 * 3";
488   {
489     LocalContext env;
490     v8::HandleScope scope(env->GetIsolate());
491     Local<String> source = v8_str(c_source);
492     // Trigger GCs so that the newly allocated string moves to old gen.
493     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
494     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
495     bool success = source->MakeExternal(
496         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
497     CHECK(success);
498     Local<Script> script = v8_compile(source);
499     Local<Value> value = script->Run();
500     CHECK(value->IsNumber());
501     CHECK_EQ(7, value->Int32Value());
502     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
503     CHECK_EQ(0, dispose_count);
504   }
505   CcTest::i_isolate()->compilation_cache()->Clear();
506   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
507   CHECK_EQ(1, dispose_count);
508 }
509
510
511 TEST(MakingExternalStringConditions) {
512   LocalContext env;
513   v8::HandleScope scope(env->GetIsolate());
514
515   // Free some space in the new space so that we can check freshness.
516   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
517   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
518
519   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
520   Local<String> small_string =
521       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
522   i::DeleteArray(two_byte_string);
523
524   // We should refuse to externalize newly created small string.
525   CHECK(!small_string->CanMakeExternal());
526   // Trigger GCs so that the newly allocated string moves to old gen.
527   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
528   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
529   // Old space strings should be accepted.
530   CHECK(small_string->CanMakeExternal());
531
532   two_byte_string = AsciiToTwoByteString("small string 2");
533   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
534   i::DeleteArray(two_byte_string);
535
536   // We should refuse externalizing newly created small string.
537   CHECK(!small_string->CanMakeExternal());
538   for (int i = 0; i < 100; i++) {
539     String::Value value(small_string);
540   }
541   // Frequently used strings should be accepted.
542   CHECK(small_string->CanMakeExternal());
543
544   const int buf_size = 10 * 1024;
545   char* buf = i::NewArray<char>(buf_size);
546   memset(buf, 'a', buf_size);
547   buf[buf_size - 1] = '\0';
548
549   two_byte_string = AsciiToTwoByteString(buf);
550   Local<String> large_string =
551       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
552   i::DeleteArray(buf);
553   i::DeleteArray(two_byte_string);
554   // Large strings should be immediately accepted.
555   CHECK(large_string->CanMakeExternal());
556 }
557
558
559 TEST(MakingExternalOneByteStringConditions) {
560   LocalContext env;
561   v8::HandleScope scope(env->GetIsolate());
562
563   // Free some space in the new space so that we can check freshness.
564   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
565   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
566
567   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
568   // We should refuse to externalize newly created small string.
569   CHECK(!small_string->CanMakeExternal());
570   // Trigger GCs so that the newly allocated string moves to old gen.
571   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
572   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
573   // Old space strings should be accepted.
574   CHECK(small_string->CanMakeExternal());
575
576   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
577   // We should refuse externalizing newly created small string.
578   CHECK(!small_string->CanMakeExternal());
579   for (int i = 0; i < 100; i++) {
580     String::Value value(small_string);
581   }
582   // Frequently used strings should be accepted.
583   CHECK(small_string->CanMakeExternal());
584
585   const int buf_size = 10 * 1024;
586   char* buf = i::NewArray<char>(buf_size);
587   memset(buf, 'a', buf_size);
588   buf[buf_size - 1] = '\0';
589   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
590   i::DeleteArray(buf);
591   // Large strings should be immediately accepted.
592   CHECK(large_string->CanMakeExternal());
593 }
594
595
596 TEST(MakingExternalUnalignedOneByteString) {
597   LocalContext env;
598   v8::HandleScope scope(env->GetIsolate());
599
600   CompileRun("function cons(a, b) { return a + b; }"
601              "function slice(a) { return a.substring(1); }");
602   // Create a cons string that will land in old pointer space.
603   Local<String> cons = Local<String>::Cast(CompileRun(
604       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
605   // Create a sliced string that will land in old pointer space.
606   Local<String> slice = Local<String>::Cast(CompileRun(
607       "slice('abcdefghijklmnopqrstuvwxyz');"));
608
609   // Trigger GCs so that the newly allocated string moves to old gen.
610   SimulateFullSpace(CcTest::heap()->old_pointer_space());
611   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
612   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
613
614   // Turn into external string with unaligned resource data.
615   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
616   bool success =
617       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
618   CHECK(success);
619   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
620   success =
621       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
622   CHECK(success);
623
624   // Trigger GCs and force evacuation.
625   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
626   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
627 }
628
629
630 THREADED_TEST(UsingExternalString) {
631   i::Factory* factory = CcTest::i_isolate()->factory();
632   {
633     v8::HandleScope scope(CcTest::isolate());
634     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
635     Local<String> string = String::NewExternal(
636         CcTest::isolate(), new TestResource(two_byte_string));
637     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
638     // Trigger GCs so that the newly allocated string moves to old gen.
639     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
640     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
641     i::Handle<i::String> isymbol =
642         factory->InternalizeString(istring);
643     CHECK(isymbol->IsInternalizedString());
644   }
645   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
646   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
647 }
648
649
650 THREADED_TEST(UsingExternalOneByteString) {
651   i::Factory* factory = CcTest::i_isolate()->factory();
652   {
653     v8::HandleScope scope(CcTest::isolate());
654     const char* one_byte_string = "test string";
655     Local<String> string = String::NewExternal(
656         CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
657     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
658     // Trigger GCs so that the newly allocated string moves to old gen.
659     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
660     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
661     i::Handle<i::String> isymbol =
662         factory->InternalizeString(istring);
663     CHECK(isymbol->IsInternalizedString());
664   }
665   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
666   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
667 }
668
669
670 class RandomLengthResource : public v8::String::ExternalStringResource {
671  public:
672   explicit RandomLengthResource(int length) : length_(length) {}
673   virtual const uint16_t* data() const { return string_; }
674   virtual size_t length() const { return length_; }
675
676  private:
677   uint16_t string_[10];
678   int length_;
679 };
680
681
682 class RandomLengthOneByteResource
683     : public v8::String::ExternalOneByteStringResource {
684  public:
685   explicit RandomLengthOneByteResource(int length) : length_(length) {}
686   virtual const char* data() const { return string_; }
687   virtual size_t length() const { return length_; }
688
689  private:
690   char string_[10];
691   int length_;
692 };
693
694
695 THREADED_TEST(NewExternalForVeryLongString) {
696   auto isolate = CcTest::isolate();
697   {
698     v8::HandleScope scope(isolate);
699     v8::TryCatch try_catch;
700     RandomLengthOneByteResource r(1 << 30);
701     v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
702     CHECK(str.IsEmpty());
703     CHECK(!try_catch.HasCaught());
704   }
705
706   {
707     v8::HandleScope scope(isolate);
708     v8::TryCatch try_catch;
709     RandomLengthResource r(1 << 30);
710     v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
711     CHECK(str.IsEmpty());
712     CHECK(!try_catch.HasCaught());
713   }
714 }
715
716
717 THREADED_TEST(ScavengeExternalString) {
718   i::FLAG_stress_compaction = false;
719   i::FLAG_gc_global = false;
720   int dispose_count = 0;
721   bool in_new_space = false;
722   {
723     v8::HandleScope scope(CcTest::isolate());
724     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
725     Local<String> string = String::NewExternal(
726         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
727     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
728     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
729     in_new_space = CcTest::heap()->InNewSpace(*istring);
730     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
731     CHECK_EQ(0, dispose_count);
732   }
733   CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE
734                                               : i::OLD_DATA_SPACE);
735   CHECK_EQ(1, dispose_count);
736 }
737
738
739 THREADED_TEST(ScavengeExternalOneByteString) {
740   i::FLAG_stress_compaction = false;
741   i::FLAG_gc_global = false;
742   int dispose_count = 0;
743   bool in_new_space = false;
744   {
745     v8::HandleScope scope(CcTest::isolate());
746     const char* one_byte_string = "test string";
747     Local<String> string = String::NewExternal(
748         CcTest::isolate(),
749         new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
750     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
751     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
752     in_new_space = CcTest::heap()->InNewSpace(*istring);
753     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
754     CHECK_EQ(0, dispose_count);
755   }
756   CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE
757                                               : i::OLD_DATA_SPACE);
758   CHECK_EQ(1, dispose_count);
759 }
760
761
762 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
763  public:
764   // Only used by non-threaded tests, so it can use static fields.
765   static int dispose_calls;
766   static int dispose_count;
767
768   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
769       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
770
771   void Dispose() {
772     ++dispose_calls;
773     if (dispose_) delete this;
774   }
775  private:
776   bool dispose_;
777 };
778
779
780 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
781 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
782
783
784 TEST(ExternalStringWithDisposeHandling) {
785   const char* c_source = "1 + 2 * 3";
786
787   // Use a stack allocated external string resource allocated object.
788   TestOneByteResourceWithDisposeControl::dispose_count = 0;
789   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
790   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
791   {
792     LocalContext env;
793     v8::HandleScope scope(env->GetIsolate());
794     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
795     Local<Script> script = v8_compile(source);
796     Local<Value> value = script->Run();
797     CHECK(value->IsNumber());
798     CHECK_EQ(7, value->Int32Value());
799     CcTest::heap()->CollectAllAvailableGarbage();
800     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
801   }
802   CcTest::i_isolate()->compilation_cache()->Clear();
803   CcTest::heap()->CollectAllAvailableGarbage();
804   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
805   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
806
807   // Use a heap allocated external string resource allocated object.
808   TestOneByteResourceWithDisposeControl::dispose_count = 0;
809   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
810   TestOneByteResource* res_heap =
811       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
812   {
813     LocalContext env;
814     v8::HandleScope scope(env->GetIsolate());
815     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
816     Local<Script> script = v8_compile(source);
817     Local<Value> value = script->Run();
818     CHECK(value->IsNumber());
819     CHECK_EQ(7, value->Int32Value());
820     CcTest::heap()->CollectAllAvailableGarbage();
821     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
822   }
823   CcTest::i_isolate()->compilation_cache()->Clear();
824   CcTest::heap()->CollectAllAvailableGarbage();
825   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
826   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
827 }
828
829
830 THREADED_TEST(StringConcat) {
831   {
832     LocalContext env;
833     v8::HandleScope scope(env->GetIsolate());
834     const char* one_byte_string_1 = "function a_times_t";
835     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
836     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
837     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
838     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
839     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
840     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
841     Local<String> left = v8_str(one_byte_string_1);
842
843     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
844     Local<String> right =
845         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
846     i::DeleteArray(two_byte_source);
847
848     Local<String> source = String::Concat(left, right);
849     right = String::NewExternal(
850         env->GetIsolate(),
851         new TestOneByteResource(i::StrDup(one_byte_extern_1)));
852     source = String::Concat(source, right);
853     right = String::NewExternal(
854         env->GetIsolate(),
855         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
856     source = String::Concat(source, right);
857     right = v8_str(one_byte_string_2);
858     source = String::Concat(source, right);
859
860     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
861     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
862     i::DeleteArray(two_byte_source);
863
864     source = String::Concat(source, right);
865     right = String::NewExternal(
866         env->GetIsolate(),
867         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
868     source = String::Concat(source, right);
869     Local<Script> script = v8_compile(source);
870     Local<Value> value = script->Run();
871     CHECK(value->IsNumber());
872     CHECK_EQ(68, value->Int32Value());
873   }
874   CcTest::i_isolate()->compilation_cache()->Clear();
875   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
876   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
877 }
878
879
880 THREADED_TEST(GlobalProperties) {
881   LocalContext env;
882   v8::HandleScope scope(env->GetIsolate());
883   v8::Handle<v8::Object> global = env->Global();
884   global->Set(v8_str("pi"), v8_num(3.1415926));
885   Local<Value> pi = global->Get(v8_str("pi"));
886   CHECK_EQ(3.1415926, pi->NumberValue());
887 }
888
889
890 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
891                                  i::Address callback) {
892   ApiTestFuzzer::Fuzz();
893   CheckReturnValue(info, callback);
894   info.GetReturnValue().Set(v8_str("bad value"));
895   info.GetReturnValue().Set(v8_num(102));
896 }
897
898
899 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
900   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
901 }
902
903
904 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
905   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
906 }
907
908 static void construct_callback(
909     const v8::FunctionCallbackInfo<Value>& info) {
910   ApiTestFuzzer::Fuzz();
911   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
912   info.This()->Set(v8_str("x"), v8_num(1));
913   info.This()->Set(v8_str("y"), v8_num(2));
914   info.GetReturnValue().Set(v8_str("bad value"));
915   info.GetReturnValue().Set(info.This());
916 }
917
918
919 static void Return239Callback(
920     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
921   ApiTestFuzzer::Fuzz();
922   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
923   info.GetReturnValue().Set(v8_str("bad value"));
924   info.GetReturnValue().Set(v8_num(239));
925 }
926
927
928 template<typename Handler>
929 static void TestFunctionTemplateInitializer(Handler handler,
930                                             Handler handler_2) {
931   // Test constructor calls.
932   {
933     LocalContext env;
934     v8::Isolate* isolate = env->GetIsolate();
935     v8::HandleScope scope(isolate);
936
937     Local<v8::FunctionTemplate> fun_templ =
938         v8::FunctionTemplate::New(isolate, handler);
939     Local<Function> fun = fun_templ->GetFunction();
940     env->Global()->Set(v8_str("obj"), fun);
941     Local<Script> script = v8_compile("obj()");
942     for (int i = 0; i < 30; i++) {
943       CHECK_EQ(102, script->Run()->Int32Value());
944     }
945   }
946   // Use SetCallHandler to initialize a function template, should work like
947   // the previous one.
948   {
949     LocalContext env;
950     v8::Isolate* isolate = env->GetIsolate();
951     v8::HandleScope scope(isolate);
952
953     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
954     fun_templ->SetCallHandler(handler_2);
955     Local<Function> fun = fun_templ->GetFunction();
956     env->Global()->Set(v8_str("obj"), fun);
957     Local<Script> script = v8_compile("obj()");
958     for (int i = 0; i < 30; i++) {
959       CHECK_EQ(102, script->Run()->Int32Value());
960     }
961   }
962 }
963
964
965 template<typename Constructor, typename Accessor>
966 static void TestFunctionTemplateAccessor(Constructor constructor,
967                                          Accessor accessor) {
968   LocalContext env;
969   v8::HandleScope scope(env->GetIsolate());
970
971   Local<v8::FunctionTemplate> fun_templ =
972       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
973   fun_templ->SetClassName(v8_str("funky"));
974   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
975   Local<Function> fun = fun_templ->GetFunction();
976   env->Global()->Set(v8_str("obj"), fun);
977   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
978   CHECK(v8_str("[object funky]")->Equals(result));
979   CompileRun("var obj_instance = new obj();");
980   Local<Script> script;
981   script = v8_compile("obj_instance.x");
982   for (int i = 0; i < 30; i++) {
983     CHECK_EQ(1, script->Run()->Int32Value());
984   }
985   script = v8_compile("obj_instance.m");
986   for (int i = 0; i < 30; i++) {
987     CHECK_EQ(239, script->Run()->Int32Value());
988   }
989 }
990
991
992 THREADED_PROFILED_TEST(FunctionTemplate) {
993   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
994   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
995 }
996
997
998 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
999   ApiTestFuzzer::Fuzz();
1000   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1001   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1002 }
1003
1004
1005 template<typename Callback>
1006 static void TestSimpleCallback(Callback callback) {
1007   LocalContext env;
1008   v8::Isolate* isolate = env->GetIsolate();
1009   v8::HandleScope scope(isolate);
1010
1011   v8::Handle<v8::ObjectTemplate> object_template =
1012       v8::ObjectTemplate::New(isolate);
1013   object_template->Set(isolate, "callback",
1014                        v8::FunctionTemplate::New(isolate, callback));
1015   v8::Local<v8::Object> object = object_template->NewInstance();
1016   (*env)->Global()->Set(v8_str("callback_object"), object);
1017   v8::Handle<v8::Script> script;
1018   script = v8_compile("callback_object.callback(17)");
1019   for (int i = 0; i < 30; i++) {
1020     CHECK_EQ(51424, script->Run()->Int32Value());
1021   }
1022   script = v8_compile("callback_object.callback(17, 24)");
1023   for (int i = 0; i < 30; i++) {
1024     CHECK_EQ(51425, script->Run()->Int32Value());
1025   }
1026 }
1027
1028
1029 THREADED_PROFILED_TEST(SimpleCallback) {
1030   TestSimpleCallback(SimpleCallback);
1031 }
1032
1033
1034 template<typename T>
1035 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1036
1037 // constant return values
1038 static int32_t fast_return_value_int32 = 471;
1039 static uint32_t fast_return_value_uint32 = 571;
1040 static const double kFastReturnValueDouble = 2.7;
1041 // variable return values
1042 static bool fast_return_value_bool = false;
1043 enum ReturnValueOddball {
1044   kNullReturnValue,
1045   kUndefinedReturnValue,
1046   kEmptyStringReturnValue
1047 };
1048 static ReturnValueOddball fast_return_value_void;
1049 static bool fast_return_value_object_is_empty = false;
1050
1051 // Helper function to avoid compiler error: insufficient contextual information
1052 // to determine type when applying FUNCTION_ADDR to a template function.
1053 static i::Address address_of(v8::FunctionCallback callback) {
1054   return FUNCTION_ADDR(callback);
1055 }
1056
1057 template<>
1058 void FastReturnValueCallback<int32_t>(
1059     const v8::FunctionCallbackInfo<v8::Value>& info) {
1060   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1061   info.GetReturnValue().Set(fast_return_value_int32);
1062 }
1063
1064 template<>
1065 void FastReturnValueCallback<uint32_t>(
1066     const v8::FunctionCallbackInfo<v8::Value>& info) {
1067   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1068   info.GetReturnValue().Set(fast_return_value_uint32);
1069 }
1070
1071 template<>
1072 void FastReturnValueCallback<double>(
1073     const v8::FunctionCallbackInfo<v8::Value>& info) {
1074   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1075   info.GetReturnValue().Set(kFastReturnValueDouble);
1076 }
1077
1078 template<>
1079 void FastReturnValueCallback<bool>(
1080     const v8::FunctionCallbackInfo<v8::Value>& info) {
1081   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1082   info.GetReturnValue().Set(fast_return_value_bool);
1083 }
1084
1085 template<>
1086 void FastReturnValueCallback<void>(
1087     const v8::FunctionCallbackInfo<v8::Value>& info) {
1088   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1089   switch (fast_return_value_void) {
1090     case kNullReturnValue:
1091       info.GetReturnValue().SetNull();
1092       break;
1093     case kUndefinedReturnValue:
1094       info.GetReturnValue().SetUndefined();
1095       break;
1096     case kEmptyStringReturnValue:
1097       info.GetReturnValue().SetEmptyString();
1098       break;
1099   }
1100 }
1101
1102 template<>
1103 void FastReturnValueCallback<Object>(
1104     const v8::FunctionCallbackInfo<v8::Value>& info) {
1105   v8::Handle<v8::Object> object;
1106   if (!fast_return_value_object_is_empty) {
1107     object = Object::New(info.GetIsolate());
1108   }
1109   info.GetReturnValue().Set(object);
1110 }
1111
1112 template<typename T>
1113 Handle<Value> TestFastReturnValues() {
1114   LocalContext env;
1115   v8::Isolate* isolate = env->GetIsolate();
1116   v8::EscapableHandleScope scope(isolate);
1117   v8::Handle<v8::ObjectTemplate> object_template =
1118       v8::ObjectTemplate::New(isolate);
1119   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1120   object_template->Set(isolate, "callback",
1121                        v8::FunctionTemplate::New(isolate, callback));
1122   v8::Local<v8::Object> object = object_template->NewInstance();
1123   (*env)->Global()->Set(v8_str("callback_object"), object);
1124   return scope.Escape(CompileRun("callback_object.callback()"));
1125 }
1126
1127
1128 THREADED_PROFILED_TEST(FastReturnValues) {
1129   LocalContext env;
1130   v8::Isolate* isolate = env->GetIsolate();
1131   v8::HandleScope scope(isolate);
1132   v8::Handle<v8::Value> value;
1133   // check int32_t and uint32_t
1134   int32_t int_values[] = {
1135       0, 234, -723,
1136       i::Smi::kMinValue, i::Smi::kMaxValue
1137   };
1138   for (size_t i = 0; i < arraysize(int_values); i++) {
1139     for (int modifier = -1; modifier <= 1; modifier++) {
1140       int int_value = int_values[i] + modifier;
1141       // check int32_t
1142       fast_return_value_int32 = int_value;
1143       value = TestFastReturnValues<int32_t>();
1144       CHECK(value->IsInt32());
1145       CHECK(fast_return_value_int32 == value->Int32Value());
1146       // check uint32_t
1147       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1148       value = TestFastReturnValues<uint32_t>();
1149       CHECK(value->IsUint32());
1150       CHECK(fast_return_value_uint32 == value->Uint32Value());
1151     }
1152   }
1153   // check double
1154   value = TestFastReturnValues<double>();
1155   CHECK(value->IsNumber());
1156   CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1157   // check bool values
1158   for (int i = 0; i < 2; i++) {
1159     fast_return_value_bool = i == 0;
1160     value = TestFastReturnValues<bool>();
1161     CHECK(value->IsBoolean());
1162     CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1163   }
1164   // check oddballs
1165   ReturnValueOddball oddballs[] = {
1166       kNullReturnValue,
1167       kUndefinedReturnValue,
1168       kEmptyStringReturnValue
1169   };
1170   for (size_t i = 0; i < arraysize(oddballs); i++) {
1171     fast_return_value_void = oddballs[i];
1172     value = TestFastReturnValues<void>();
1173     switch (fast_return_value_void) {
1174       case kNullReturnValue:
1175         CHECK(value->IsNull());
1176         break;
1177       case kUndefinedReturnValue:
1178         CHECK(value->IsUndefined());
1179         break;
1180       case kEmptyStringReturnValue:
1181         CHECK(value->IsString());
1182         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1183         break;
1184     }
1185   }
1186   // check handles
1187   fast_return_value_object_is_empty = false;
1188   value = TestFastReturnValues<Object>();
1189   CHECK(value->IsObject());
1190   fast_return_value_object_is_empty = true;
1191   value = TestFastReturnValues<Object>();
1192   CHECK(value->IsUndefined());
1193 }
1194
1195
1196 THREADED_TEST(FunctionTemplateSetLength) {
1197   LocalContext env;
1198   v8::Isolate* isolate = env->GetIsolate();
1199   v8::HandleScope scope(isolate);
1200   {
1201     Local<v8::FunctionTemplate> fun_templ =
1202         v8::FunctionTemplate::New(isolate,
1203                                   handle_callback,
1204                                   Handle<v8::Value>(),
1205                                   Handle<v8::Signature>(),
1206                                   23);
1207     Local<Function> fun = fun_templ->GetFunction();
1208     env->Global()->Set(v8_str("obj"), fun);
1209     Local<Script> script = v8_compile("obj.length");
1210     CHECK_EQ(23, script->Run()->Int32Value());
1211   }
1212   {
1213     Local<v8::FunctionTemplate> fun_templ =
1214         v8::FunctionTemplate::New(isolate, handle_callback);
1215     fun_templ->SetLength(22);
1216     Local<Function> fun = fun_templ->GetFunction();
1217     env->Global()->Set(v8_str("obj"), fun);
1218     Local<Script> script = v8_compile("obj.length");
1219     CHECK_EQ(22, script->Run()->Int32Value());
1220   }
1221   {
1222     // Without setting length it defaults to 0.
1223     Local<v8::FunctionTemplate> fun_templ =
1224         v8::FunctionTemplate::New(isolate, handle_callback);
1225     Local<Function> fun = fun_templ->GetFunction();
1226     env->Global()->Set(v8_str("obj"), fun);
1227     Local<Script> script = v8_compile("obj.length");
1228     CHECK_EQ(0, script->Run()->Int32Value());
1229   }
1230 }
1231
1232
1233 static void* expected_ptr;
1234 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1235   void* ptr = v8::External::Cast(*args.Data())->Value();
1236   CHECK_EQ(expected_ptr, ptr);
1237   args.GetReturnValue().Set(true);
1238 }
1239
1240
1241 static void TestExternalPointerWrapping() {
1242   LocalContext env;
1243   v8::Isolate* isolate = env->GetIsolate();
1244   v8::HandleScope scope(isolate);
1245
1246   v8::Handle<v8::Value> data =
1247       v8::External::New(isolate, expected_ptr);
1248
1249   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1250   obj->Set(v8_str("func"),
1251            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1252   env->Global()->Set(v8_str("obj"), obj);
1253
1254   CHECK(CompileRun(
1255         "function foo() {\n"
1256         "  for (var i = 0; i < 13; i++) obj.func();\n"
1257         "}\n"
1258         "foo(), true")->BooleanValue());
1259 }
1260
1261
1262 THREADED_TEST(ExternalWrap) {
1263   // Check heap allocated object.
1264   int* ptr = new int;
1265   expected_ptr = ptr;
1266   TestExternalPointerWrapping();
1267   delete ptr;
1268
1269   // Check stack allocated object.
1270   int foo;
1271   expected_ptr = &foo;
1272   TestExternalPointerWrapping();
1273
1274   // Check not aligned addresses.
1275   const int n = 100;
1276   char* s = new char[n];
1277   for (int i = 0; i < n; i++) {
1278     expected_ptr = s + i;
1279     TestExternalPointerWrapping();
1280   }
1281
1282   delete[] s;
1283
1284   // Check several invalid addresses.
1285   expected_ptr = reinterpret_cast<void*>(1);
1286   TestExternalPointerWrapping();
1287
1288   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1289   TestExternalPointerWrapping();
1290
1291   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1292   TestExternalPointerWrapping();
1293
1294 #if defined(V8_HOST_ARCH_X64)
1295   // Check a value with a leading 1 bit in x64 Smi encoding.
1296   expected_ptr = reinterpret_cast<void*>(0x400000000);
1297   TestExternalPointerWrapping();
1298
1299   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1300   TestExternalPointerWrapping();
1301
1302   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1303   TestExternalPointerWrapping();
1304 #endif
1305 }
1306
1307
1308 THREADED_TEST(FindInstanceInPrototypeChain) {
1309   LocalContext env;
1310   v8::Isolate* isolate = env->GetIsolate();
1311   v8::HandleScope scope(isolate);
1312
1313   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1314   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1315   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1316   derived->Inherit(base);
1317
1318   Local<v8::Function> base_function = base->GetFunction();
1319   Local<v8::Function> derived_function = derived->GetFunction();
1320   Local<v8::Function> other_function = other->GetFunction();
1321
1322   Local<v8::Object> base_instance = base_function->NewInstance();
1323   Local<v8::Object> derived_instance = derived_function->NewInstance();
1324   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1325   Local<v8::Object> other_instance = other_function->NewInstance();
1326   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1327   other_instance->Set(v8_str("__proto__"), derived_instance2);
1328
1329   // base_instance is only an instance of base.
1330   CHECK(
1331       base_instance->Equals(base_instance->FindInstanceInPrototypeChain(base)));
1332   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1333   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1334
1335   // derived_instance is an instance of base and derived.
1336   CHECK(derived_instance->Equals(
1337       derived_instance->FindInstanceInPrototypeChain(base)));
1338   CHECK(derived_instance->Equals(
1339       derived_instance->FindInstanceInPrototypeChain(derived)));
1340   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1341
1342   // other_instance is an instance of other and its immediate
1343   // prototype derived_instance2 is an instance of base and derived.
1344   // Note, derived_instance is an instance of base and derived too,
1345   // but it comes after derived_instance2 in the prototype chain of
1346   // other_instance.
1347   CHECK(derived_instance2->Equals(
1348       other_instance->FindInstanceInPrototypeChain(base)));
1349   CHECK(derived_instance2->Equals(
1350       other_instance->FindInstanceInPrototypeChain(derived)));
1351   CHECK(other_instance->Equals(
1352       other_instance->FindInstanceInPrototypeChain(other)));
1353 }
1354
1355
1356 THREADED_TEST(TinyInteger) {
1357   LocalContext env;
1358   v8::Isolate* isolate = env->GetIsolate();
1359   v8::HandleScope scope(isolate);
1360
1361   int32_t value = 239;
1362   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1363   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1364
1365   value_obj = v8::Integer::New(isolate, value);
1366   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1367 }
1368
1369
1370 THREADED_TEST(BigSmiInteger) {
1371   LocalContext env;
1372   v8::HandleScope scope(env->GetIsolate());
1373   v8::Isolate* isolate = CcTest::isolate();
1374
1375   int32_t value = i::Smi::kMaxValue;
1376   // We cannot add one to a Smi::kMaxValue without wrapping.
1377   if (i::SmiValuesAre31Bits()) {
1378     CHECK(i::Smi::IsValid(value));
1379     CHECK(!i::Smi::IsValid(value + 1));
1380
1381     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1382     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1383
1384     value_obj = v8::Integer::New(isolate, value);
1385     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1386   }
1387 }
1388
1389
1390 THREADED_TEST(BigInteger) {
1391   LocalContext env;
1392   v8::HandleScope scope(env->GetIsolate());
1393   v8::Isolate* isolate = CcTest::isolate();
1394
1395   // We cannot add one to a Smi::kMaxValue without wrapping.
1396   if (i::SmiValuesAre31Bits()) {
1397     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1398     // The code will not be run in that case, due to the "if" guard.
1399     int32_t value =
1400         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1401     CHECK(value > i::Smi::kMaxValue);
1402     CHECK(!i::Smi::IsValid(value));
1403
1404     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1405     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1406
1407     value_obj = v8::Integer::New(isolate, value);
1408     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1409   }
1410 }
1411
1412
1413 THREADED_TEST(TinyUnsignedInteger) {
1414   LocalContext env;
1415   v8::HandleScope scope(env->GetIsolate());
1416   v8::Isolate* isolate = CcTest::isolate();
1417
1418   uint32_t value = 239;
1419
1420   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1421   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1422
1423   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1424   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1425 }
1426
1427
1428 THREADED_TEST(BigUnsignedSmiInteger) {
1429   LocalContext env;
1430   v8::HandleScope scope(env->GetIsolate());
1431   v8::Isolate* isolate = CcTest::isolate();
1432
1433   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1434   CHECK(i::Smi::IsValid(value));
1435   CHECK(!i::Smi::IsValid(value + 1));
1436
1437   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1438   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1439
1440   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1441   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1442 }
1443
1444
1445 THREADED_TEST(BigUnsignedInteger) {
1446   LocalContext env;
1447   v8::HandleScope scope(env->GetIsolate());
1448   v8::Isolate* isolate = CcTest::isolate();
1449
1450   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1451   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1452   CHECK(!i::Smi::IsValid(value));
1453
1454   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1455   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1456
1457   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1458   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1459 }
1460
1461
1462 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1463   LocalContext env;
1464   v8::HandleScope scope(env->GetIsolate());
1465   v8::Isolate* isolate = CcTest::isolate();
1466
1467   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1468   uint32_t value = INT32_MAX_AS_UINT + 1;
1469   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1470
1471   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1472   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1473
1474   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1475   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1476 }
1477
1478
1479 THREADED_TEST(IsNativeError) {
1480   LocalContext env;
1481   v8::HandleScope scope(env->GetIsolate());
1482   v8::Handle<Value> syntax_error = CompileRun(
1483       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1484   CHECK(syntax_error->IsNativeError());
1485   v8::Handle<Value> not_error = CompileRun("{a:42}");
1486   CHECK(!not_error->IsNativeError());
1487   v8::Handle<Value> not_object = CompileRun("42");
1488   CHECK(!not_object->IsNativeError());
1489 }
1490
1491
1492 THREADED_TEST(IsGeneratorFunctionOrObject) {
1493   LocalContext env;
1494   v8::HandleScope scope(env->GetIsolate());
1495
1496   CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1497   v8::Handle<Value> gen = CompileRun("gen");
1498   v8::Handle<Value> genObj = CompileRun("gen()");
1499   v8::Handle<Value> object = CompileRun("{a:42}");
1500   v8::Handle<Value> func = CompileRun("func");
1501
1502   CHECK(gen->IsGeneratorFunction());
1503   CHECK(gen->IsFunction());
1504   CHECK(!gen->IsGeneratorObject());
1505
1506   CHECK(!genObj->IsGeneratorFunction());
1507   CHECK(!genObj->IsFunction());
1508   CHECK(genObj->IsGeneratorObject());
1509
1510   CHECK(!object->IsGeneratorFunction());
1511   CHECK(!object->IsFunction());
1512   CHECK(!object->IsGeneratorObject());
1513
1514   CHECK(!func->IsGeneratorFunction());
1515   CHECK(func->IsFunction());
1516   CHECK(!func->IsGeneratorObject());
1517 }
1518
1519
1520 THREADED_TEST(ArgumentsObject) {
1521   LocalContext env;
1522   v8::HandleScope scope(env->GetIsolate());
1523   v8::Handle<Value> arguments_object =
1524       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1525   CHECK(arguments_object->IsArgumentsObject());
1526   v8::Handle<Value> array = CompileRun("[1,2,3]");
1527   CHECK(!array->IsArgumentsObject());
1528   v8::Handle<Value> object = CompileRun("{a:42}");
1529   CHECK(!object->IsArgumentsObject());
1530 }
1531
1532
1533 THREADED_TEST(IsMapOrSet) {
1534   LocalContext env;
1535   v8::HandleScope scope(env->GetIsolate());
1536   v8::Handle<Value> map = CompileRun("new Map()");
1537   v8::Handle<Value> set = CompileRun("new Set()");
1538   v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1539   v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1540   CHECK(map->IsMap());
1541   CHECK(set->IsSet());
1542   CHECK(weak_map->IsWeakMap());
1543   CHECK(weak_set->IsWeakSet());
1544
1545   CHECK(!map->IsSet());
1546   CHECK(!map->IsWeakMap());
1547   CHECK(!map->IsWeakSet());
1548
1549   CHECK(!set->IsMap());
1550   CHECK(!set->IsWeakMap());
1551   CHECK(!set->IsWeakSet());
1552
1553   CHECK(!weak_map->IsMap());
1554   CHECK(!weak_map->IsSet());
1555   CHECK(!weak_map->IsWeakSet());
1556
1557   CHECK(!weak_set->IsMap());
1558   CHECK(!weak_set->IsSet());
1559   CHECK(!weak_set->IsWeakMap());
1560
1561   v8::Handle<Value> object = CompileRun("{a:42}");
1562   CHECK(!object->IsMap());
1563   CHECK(!object->IsSet());
1564   CHECK(!object->IsWeakMap());
1565   CHECK(!object->IsWeakSet());
1566 }
1567
1568
1569 THREADED_TEST(StringObject) {
1570   LocalContext env;
1571   v8::HandleScope scope(env->GetIsolate());
1572   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1573   CHECK(boxed_string->IsStringObject());
1574   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1575   CHECK(!unboxed_string->IsStringObject());
1576   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1577   CHECK(!boxed_not_string->IsStringObject());
1578   v8::Handle<Value> not_object = CompileRun("0");
1579   CHECK(!not_object->IsStringObject());
1580   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1581   CHECK(!as_boxed.IsEmpty());
1582   Local<v8::String> the_string = as_boxed->ValueOf();
1583   CHECK(!the_string.IsEmpty());
1584   ExpectObject("\"test\"", the_string);
1585   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1586   CHECK(new_boxed_string->IsStringObject());
1587   as_boxed = new_boxed_string.As<v8::StringObject>();
1588   the_string = as_boxed->ValueOf();
1589   CHECK(!the_string.IsEmpty());
1590   ExpectObject("\"test\"", the_string);
1591 }
1592
1593
1594 THREADED_TEST(NumberObject) {
1595   LocalContext env;
1596   v8::HandleScope scope(env->GetIsolate());
1597   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1598   CHECK(boxed_number->IsNumberObject());
1599   v8::Handle<Value> unboxed_number = CompileRun("42");
1600   CHECK(!unboxed_number->IsNumberObject());
1601   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1602   CHECK(!boxed_not_number->IsNumberObject());
1603   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1604   CHECK(!as_boxed.IsEmpty());
1605   double the_number = as_boxed->ValueOf();
1606   CHECK_EQ(42.0, the_number);
1607   v8::Handle<v8::Value> new_boxed_number =
1608       v8::NumberObject::New(env->GetIsolate(), 43);
1609   CHECK(new_boxed_number->IsNumberObject());
1610   as_boxed = new_boxed_number.As<v8::NumberObject>();
1611   the_number = as_boxed->ValueOf();
1612   CHECK_EQ(43.0, the_number);
1613 }
1614
1615
1616 THREADED_TEST(BooleanObject) {
1617   LocalContext env;
1618   v8::HandleScope scope(env->GetIsolate());
1619   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1620   CHECK(boxed_boolean->IsBooleanObject());
1621   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1622   CHECK(!unboxed_boolean->IsBooleanObject());
1623   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1624   CHECK(!boxed_not_boolean->IsBooleanObject());
1625   v8::Handle<v8::BooleanObject> as_boxed =
1626       boxed_boolean.As<v8::BooleanObject>();
1627   CHECK(!as_boxed.IsEmpty());
1628   bool the_boolean = as_boxed->ValueOf();
1629   CHECK_EQ(true, the_boolean);
1630   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1631   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1632   CHECK(boxed_true->IsBooleanObject());
1633   CHECK(boxed_false->IsBooleanObject());
1634   as_boxed = boxed_true.As<v8::BooleanObject>();
1635   CHECK_EQ(true, as_boxed->ValueOf());
1636   as_boxed = boxed_false.As<v8::BooleanObject>();
1637   CHECK_EQ(false, as_boxed->ValueOf());
1638 }
1639
1640
1641 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1642   LocalContext env;
1643   v8::HandleScope scope(env->GetIsolate());
1644
1645   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1646   CHECK(primitive_false->IsBoolean());
1647   CHECK(!primitive_false->IsBooleanObject());
1648   CHECK(!primitive_false->BooleanValue());
1649   CHECK(!primitive_false->IsTrue());
1650   CHECK(primitive_false->IsFalse());
1651
1652   Local<Value> false_value = BooleanObject::New(false);
1653   CHECK(!false_value->IsBoolean());
1654   CHECK(false_value->IsBooleanObject());
1655   CHECK(false_value->BooleanValue());
1656   CHECK(!false_value->IsTrue());
1657   CHECK(!false_value->IsFalse());
1658
1659   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1660   CHECK(!false_boolean_object->IsBoolean());
1661   CHECK(false_boolean_object->IsBooleanObject());
1662   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1663   // CHECK(false_boolean_object->BooleanValue());
1664   CHECK(!false_boolean_object->ValueOf());
1665   CHECK(!false_boolean_object->IsTrue());
1666   CHECK(!false_boolean_object->IsFalse());
1667
1668   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1669   CHECK(primitive_true->IsBoolean());
1670   CHECK(!primitive_true->IsBooleanObject());
1671   CHECK(primitive_true->BooleanValue());
1672   CHECK(primitive_true->IsTrue());
1673   CHECK(!primitive_true->IsFalse());
1674
1675   Local<Value> true_value = BooleanObject::New(true);
1676   CHECK(!true_value->IsBoolean());
1677   CHECK(true_value->IsBooleanObject());
1678   CHECK(true_value->BooleanValue());
1679   CHECK(!true_value->IsTrue());
1680   CHECK(!true_value->IsFalse());
1681
1682   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1683   CHECK(!true_boolean_object->IsBoolean());
1684   CHECK(true_boolean_object->IsBooleanObject());
1685   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1686   // CHECK(true_boolean_object->BooleanValue());
1687   CHECK(true_boolean_object->ValueOf());
1688   CHECK(!true_boolean_object->IsTrue());
1689   CHECK(!true_boolean_object->IsFalse());
1690 }
1691
1692
1693 THREADED_TEST(Number) {
1694   LocalContext env;
1695   v8::HandleScope scope(env->GetIsolate());
1696   double PI = 3.1415926;
1697   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1698   CHECK_EQ(PI, pi_obj->NumberValue());
1699 }
1700
1701
1702 THREADED_TEST(ToNumber) {
1703   LocalContext env;
1704   v8::Isolate* isolate = CcTest::isolate();
1705   v8::HandleScope scope(isolate);
1706   Local<String> str = v8_str("3.1415926");
1707   CHECK_EQ(3.1415926, str->NumberValue());
1708   v8::Handle<v8::Boolean> t = v8::True(isolate);
1709   CHECK_EQ(1.0, t->NumberValue());
1710   v8::Handle<v8::Boolean> f = v8::False(isolate);
1711   CHECK_EQ(0.0, f->NumberValue());
1712 }
1713
1714
1715 THREADED_TEST(Date) {
1716   LocalContext env;
1717   v8::HandleScope scope(env->GetIsolate());
1718   double PI = 3.1415926;
1719   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1720   CHECK_EQ(3.0, date->NumberValue());
1721   date.As<v8::Date>()->Set(v8_str("property"),
1722                            v8::Integer::New(env->GetIsolate(), 42));
1723   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1724 }
1725
1726
1727 THREADED_TEST(Boolean) {
1728   LocalContext env;
1729   v8::Isolate* isolate = env->GetIsolate();
1730   v8::HandleScope scope(isolate);
1731   v8::Handle<v8::Boolean> t = v8::True(isolate);
1732   CHECK(t->Value());
1733   v8::Handle<v8::Boolean> f = v8::False(isolate);
1734   CHECK(!f->Value());
1735   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1736   CHECK(!u->BooleanValue());
1737   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1738   CHECK(!n->BooleanValue());
1739   v8::Handle<String> str1 = v8_str("");
1740   CHECK(!str1->BooleanValue());
1741   v8::Handle<String> str2 = v8_str("x");
1742   CHECK(str2->BooleanValue());
1743   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1744   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1745   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1746   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1747   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1748 }
1749
1750
1751 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1752   ApiTestFuzzer::Fuzz();
1753   args.GetReturnValue().Set(v8_num(13.4));
1754 }
1755
1756
1757 static void GetM(Local<String> name,
1758                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1759   ApiTestFuzzer::Fuzz();
1760   info.GetReturnValue().Set(v8_num(876));
1761 }
1762
1763
1764 THREADED_TEST(GlobalPrototype) {
1765   v8::Isolate* isolate = CcTest::isolate();
1766   v8::HandleScope scope(isolate);
1767   v8::Handle<v8::FunctionTemplate> func_templ =
1768       v8::FunctionTemplate::New(isolate);
1769   func_templ->PrototypeTemplate()->Set(
1770       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1771   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1772   templ->Set(isolate, "x", v8_num(200));
1773   templ->SetAccessor(v8_str("m"), GetM);
1774   LocalContext env(0, templ);
1775   v8::Handle<Script> script(v8_compile("dummy()"));
1776   v8::Handle<Value> result(script->Run());
1777   CHECK_EQ(13.4, result->NumberValue());
1778   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1779   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1780 }
1781
1782
1783 THREADED_TEST(ObjectTemplate) {
1784   v8::Isolate* isolate = CcTest::isolate();
1785   v8::HandleScope scope(isolate);
1786   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1787   templ1->Set(isolate, "x", v8_num(10));
1788   templ1->Set(isolate, "y", v8_num(13));
1789   LocalContext env;
1790   Local<v8::Object> instance1 = templ1->NewInstance();
1791   env->Global()->Set(v8_str("p"), instance1);
1792   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1793   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1794   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1795   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1796   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1797   templ2->Set(isolate, "a", v8_num(12));
1798   templ2->Set(isolate, "b", templ1);
1799   Local<v8::Object> instance2 = templ2->NewInstance();
1800   env->Global()->Set(v8_str("q"), instance2);
1801   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1802   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1803   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1804   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1805 }
1806
1807
1808 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1809   ApiTestFuzzer::Fuzz();
1810   args.GetReturnValue().Set(v8_num(17.2));
1811 }
1812
1813
1814 static void GetKnurd(Local<String> property,
1815                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1816   ApiTestFuzzer::Fuzz();
1817   info.GetReturnValue().Set(v8_num(15.2));
1818 }
1819
1820
1821 THREADED_TEST(DescriptorInheritance) {
1822   v8::Isolate* isolate = CcTest::isolate();
1823   v8::HandleScope scope(isolate);
1824   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1825   super->PrototypeTemplate()->Set(isolate, "flabby",
1826                                   v8::FunctionTemplate::New(isolate,
1827                                                             GetFlabby));
1828   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1829
1830   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1831
1832   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1833   base1->Inherit(super);
1834   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1835
1836   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1837   base2->Inherit(super);
1838   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1839
1840   LocalContext env;
1841
1842   env->Global()->Set(v8_str("s"), super->GetFunction());
1843   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1844   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1845
1846   // Checks right __proto__ chain.
1847   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1848   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1849
1850   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1851
1852   // Instance accessor should not be visible on function object or its prototype
1853   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1854   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1855   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1856
1857   env->Global()->Set(v8_str("obj"),
1858                      base1->GetFunction()->NewInstance());
1859   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1860   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1861   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1862   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1863   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1864
1865   env->Global()->Set(v8_str("obj2"),
1866                      base2->GetFunction()->NewInstance());
1867   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1868   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1869   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1870   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1871   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1872
1873   // base1 and base2 cannot cross reference to each's prototype
1874   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1875   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1876 }
1877
1878
1879 // Helper functions for Interceptor/Accessor interaction tests
1880
1881 void SimpleAccessorGetter(Local<String> name,
1882                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1883   Handle<Object> self = Handle<Object>::Cast(info.This());
1884   info.GetReturnValue().Set(
1885       self->Get(String::Concat(v8_str("accessor_"), name)));
1886 }
1887
1888 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1889                           const v8::PropertyCallbackInfo<void>& info) {
1890   Handle<Object> self = Handle<Object>::Cast(info.This());
1891   self->Set(String::Concat(v8_str("accessor_"), name), value);
1892 }
1893
1894 void SymbolAccessorGetter(Local<Name> name,
1895                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1896   CHECK(name->IsSymbol());
1897   Local<Symbol> sym = Local<Symbol>::Cast(name);
1898   if (sym->Name()->IsUndefined())
1899     return;
1900   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
1901 }
1902
1903 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1904                           const v8::PropertyCallbackInfo<void>& info) {
1905   CHECK(name->IsSymbol());
1906   Local<Symbol> sym = Local<Symbol>::Cast(name);
1907   if (sym->Name()->IsUndefined())
1908     return;
1909   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
1910 }
1911
1912 void SymbolAccessorGetterReturnsDefault(
1913     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1914   CHECK(name->IsSymbol());
1915   Local<Symbol> sym = Local<Symbol>::Cast(name);
1916   if (sym->Name()->IsUndefined()) return;
1917   info.GetReturnValue().Set(info.Data());
1918 }
1919
1920 static void ThrowingSymbolAccessorGetter(
1921     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1922   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
1923 }
1924
1925
1926 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1927   v8::Isolate* isolate = CcTest::isolate();
1928   v8::HandleScope scope(isolate);
1929   LocalContext env;
1930   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1931   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1932   CHECK(a->map()->instance_descriptors()->IsFixedArray());
1933   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1934   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1935   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1936   // But we should still have an ExecutableAccessorInfo.
1937   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1938   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
1939   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
1940   CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
1941 }
1942
1943
1944 THREADED_TEST(UndefinedIsNotEnumerable) {
1945   LocalContext env;
1946   v8::HandleScope scope(env->GetIsolate());
1947   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
1948   CHECK(result->IsFalse());
1949 }
1950
1951
1952 v8::Handle<Script> call_recursively_script;
1953 static const int kTargetRecursionDepth = 200;  // near maximum
1954
1955
1956 static void CallScriptRecursivelyCall(
1957     const v8::FunctionCallbackInfo<v8::Value>& args) {
1958   ApiTestFuzzer::Fuzz();
1959   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1960   if (depth == kTargetRecursionDepth) return;
1961   args.This()->Set(v8_str("depth"),
1962                    v8::Integer::New(args.GetIsolate(), depth + 1));
1963   args.GetReturnValue().Set(call_recursively_script->Run());
1964 }
1965
1966
1967 static void CallFunctionRecursivelyCall(
1968     const v8::FunctionCallbackInfo<v8::Value>& args) {
1969   ApiTestFuzzer::Fuzz();
1970   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1971   if (depth == kTargetRecursionDepth) {
1972     printf("[depth = %d]\n", depth);
1973     return;
1974   }
1975   args.This()->Set(v8_str("depth"),
1976                    v8::Integer::New(args.GetIsolate(), depth + 1));
1977   v8::Handle<Value> function =
1978       args.This()->Get(v8_str("callFunctionRecursively"));
1979   args.GetReturnValue().Set(
1980       function.As<Function>()->Call(args.This(), 0, NULL));
1981 }
1982
1983
1984 THREADED_TEST(DeepCrossLanguageRecursion) {
1985   v8::Isolate* isolate = CcTest::isolate();
1986   v8::HandleScope scope(isolate);
1987   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
1988   global->Set(v8_str("callScriptRecursively"),
1989               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
1990   global->Set(v8_str("callFunctionRecursively"),
1991               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
1992   LocalContext env(NULL, global);
1993
1994   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
1995   call_recursively_script = v8_compile("callScriptRecursively()");
1996   call_recursively_script->Run();
1997   call_recursively_script = v8::Handle<Script>();
1998
1999   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2000   CompileRun("callFunctionRecursively()");
2001 }
2002
2003
2004 static void ThrowingPropertyHandlerGet(
2005     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2006   // Since this interceptor is used on "with" objects, the runtime will look up
2007   // @@unscopables.  Punt.
2008   if (key->IsSymbol()) return;
2009   ApiTestFuzzer::Fuzz();
2010   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2011 }
2012
2013
2014 static void ThrowingPropertyHandlerSet(
2015     Local<Name> key, Local<Value>,
2016     const v8::PropertyCallbackInfo<v8::Value>& info) {
2017   info.GetIsolate()->ThrowException(key);
2018   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2019 }
2020
2021
2022 THREADED_TEST(CallbackExceptionRegression) {
2023   v8::Isolate* isolate = CcTest::isolate();
2024   v8::HandleScope scope(isolate);
2025   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2026   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2027       ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2028   LocalContext env;
2029   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2030   v8::Handle<Value> otto =
2031       CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2032   CHECK(v8_str("otto")->Equals(otto));
2033   v8::Handle<Value> netto =
2034       CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2035   CHECK(v8_str("netto")->Equals(netto));
2036 }
2037
2038
2039 THREADED_TEST(FunctionPrototype) {
2040   v8::Isolate* isolate = CcTest::isolate();
2041   v8::HandleScope scope(isolate);
2042   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2043   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2044   LocalContext env;
2045   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2046   Local<Script> script = v8_compile("Foo.prototype.plak");
2047   CHECK_EQ(script->Run()->Int32Value(), 321);
2048 }
2049
2050
2051 THREADED_TEST(InternalFields) {
2052   LocalContext env;
2053   v8::Isolate* isolate = env->GetIsolate();
2054   v8::HandleScope scope(isolate);
2055
2056   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2057   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2058   instance_templ->SetInternalFieldCount(1);
2059   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2060   CHECK_EQ(1, obj->InternalFieldCount());
2061   CHECK(obj->GetInternalField(0)->IsUndefined());
2062   obj->SetInternalField(0, v8_num(17));
2063   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2064 }
2065
2066
2067 THREADED_TEST(GlobalObjectInternalFields) {
2068   v8::Isolate* isolate = CcTest::isolate();
2069   v8::HandleScope scope(isolate);
2070   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2071   global_template->SetInternalFieldCount(1);
2072   LocalContext env(NULL, global_template);
2073   v8::Handle<v8::Object> global_proxy = env->Global();
2074   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2075   CHECK_EQ(1, global->InternalFieldCount());
2076   CHECK(global->GetInternalField(0)->IsUndefined());
2077   global->SetInternalField(0, v8_num(17));
2078   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2079 }
2080
2081
2082 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2083   LocalContext env;
2084   v8::HandleScope scope(CcTest::isolate());
2085
2086   v8::Local<v8::Object> global = env->Global();
2087   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2088   CHECK(global->HasRealIndexedProperty(0));
2089 }
2090
2091
2092 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2093                                                void* value) {
2094   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2095   obj->SetAlignedPointerInInternalField(0, value);
2096   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2097   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2098 }
2099
2100
2101 THREADED_TEST(InternalFieldsAlignedPointers) {
2102   LocalContext env;
2103   v8::Isolate* isolate = env->GetIsolate();
2104   v8::HandleScope scope(isolate);
2105
2106   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2107   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2108   instance_templ->SetInternalFieldCount(1);
2109   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2110   CHECK_EQ(1, obj->InternalFieldCount());
2111
2112   CheckAlignedPointerInInternalField(obj, NULL);
2113
2114   int* heap_allocated = new int[100];
2115   CheckAlignedPointerInInternalField(obj, heap_allocated);
2116   delete[] heap_allocated;
2117
2118   int stack_allocated[100];
2119   CheckAlignedPointerInInternalField(obj, stack_allocated);
2120
2121   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2122   CheckAlignedPointerInInternalField(obj, huge);
2123
2124   v8::Global<v8::Object> persistent(isolate, obj);
2125   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2126   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2127 }
2128
2129
2130 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2131                                               void* value) {
2132   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2133   (*env)->SetAlignedPointerInEmbedderData(index, value);
2134   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2135   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2136 }
2137
2138
2139 static void* AlignedTestPointer(int i) {
2140   return reinterpret_cast<void*>(i * 1234);
2141 }
2142
2143
2144 THREADED_TEST(EmbedderDataAlignedPointers) {
2145   LocalContext env;
2146   v8::HandleScope scope(env->GetIsolate());
2147
2148   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2149
2150   int* heap_allocated = new int[100];
2151   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2152   delete[] heap_allocated;
2153
2154   int stack_allocated[100];
2155   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2156
2157   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2158   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2159
2160   // Test growing of the embedder data's backing store.
2161   for (int i = 0; i < 100; i++) {
2162     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2163   }
2164   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2165   for (int i = 0; i < 100; i++) {
2166     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2167   }
2168 }
2169
2170
2171 static void CheckEmbedderData(LocalContext* env, int index,
2172                               v8::Handle<Value> data) {
2173   (*env)->SetEmbedderData(index, data);
2174   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2175 }
2176
2177
2178 THREADED_TEST(EmbedderData) {
2179   LocalContext env;
2180   v8::Isolate* isolate = env->GetIsolate();
2181   v8::HandleScope scope(isolate);
2182
2183   CheckEmbedderData(
2184       &env, 3, v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2185   CheckEmbedderData(&env, 2,
2186                     v8::String::NewFromUtf8(isolate, "over the lazy dog."));
2187   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2188   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2189 }
2190
2191
2192 THREADED_TEST(GetIsolate) {
2193   LocalContext env;
2194   v8::Isolate* isolate = env->GetIsolate();
2195   v8::HandleScope scope(isolate);
2196   Local<v8::Object> obj = v8::Object::New(isolate);
2197   CHECK_EQ(isolate, obj->GetIsolate());
2198   CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2199 }
2200
2201
2202 THREADED_TEST(IdentityHash) {
2203   LocalContext env;
2204   v8::Isolate* isolate = env->GetIsolate();
2205   v8::HandleScope scope(isolate);
2206
2207   // Ensure that the test starts with an fresh heap to test whether the hash
2208   // code is based on the address.
2209   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2210   Local<v8::Object> obj = v8::Object::New(isolate);
2211   int hash = obj->GetIdentityHash();
2212   int hash1 = obj->GetIdentityHash();
2213   CHECK_EQ(hash, hash1);
2214   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2215   // Since the identity hash is essentially a random number two consecutive
2216   // objects should not be assigned the same hash code. If the test below fails
2217   // the random number generator should be evaluated.
2218   CHECK_NE(hash, hash2);
2219   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2220   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2221   // Make sure that the identity hash is not based on the initial address of
2222   // the object alone. If the test below fails the random number generator
2223   // should be evaluated.
2224   CHECK_NE(hash, hash3);
2225   int hash4 = obj->GetIdentityHash();
2226   CHECK_EQ(hash, hash4);
2227
2228   // Check identity hashes behaviour in the presence of JS accessors.
2229   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2230   {
2231     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2232     Local<v8::Object> o1 = v8::Object::New(isolate);
2233     Local<v8::Object> o2 = v8::Object::New(isolate);
2234     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2235   }
2236   {
2237     CompileRun(
2238         "function cnst() { return 42; };\n"
2239         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2240     Local<v8::Object> o1 = v8::Object::New(isolate);
2241     Local<v8::Object> o2 = v8::Object::New(isolate);
2242     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2243   }
2244 }
2245
2246
2247 THREADED_TEST(GlobalProxyIdentityHash) {
2248   LocalContext env;
2249   v8::Isolate* isolate = env->GetIsolate();
2250   v8::HandleScope scope(isolate);
2251   Handle<Object> global_proxy = env->Global();
2252   int hash1 = global_proxy->GetIdentityHash();
2253   // Hash should be retained after being detached.
2254   env->DetachGlobal();
2255   int hash2 = global_proxy->GetIdentityHash();
2256   CHECK_EQ(hash1, hash2);
2257   {
2258     // Re-attach global proxy to a new context, hash should stay the same.
2259     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2260     int hash3 = global_proxy->GetIdentityHash();
2261     CHECK_EQ(hash1, hash3);
2262   }
2263 }
2264
2265
2266 TEST(SymbolIdentityHash) {
2267   LocalContext env;
2268   v8::Isolate* isolate = env->GetIsolate();
2269   v8::HandleScope scope(isolate);
2270
2271   {
2272     Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2273     int hash = symbol->GetIdentityHash();
2274     int hash1 = symbol->GetIdentityHash();
2275     CHECK_EQ(hash, hash1);
2276     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2277     int hash3 = symbol->GetIdentityHash();
2278     CHECK_EQ(hash, hash3);
2279   }
2280
2281   {
2282     v8::Handle<v8::Symbol> js_symbol =
2283         CompileRun("Symbol('foo')").As<v8::Symbol>();
2284     int hash = js_symbol->GetIdentityHash();
2285     int hash1 = js_symbol->GetIdentityHash();
2286     CHECK_EQ(hash, hash1);
2287     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2288     int hash3 = js_symbol->GetIdentityHash();
2289     CHECK_EQ(hash, hash3);
2290   }
2291 }
2292
2293
2294 TEST(StringIdentityHash) {
2295   LocalContext env;
2296   v8::Isolate* isolate = env->GetIsolate();
2297   v8::HandleScope scope(isolate);
2298
2299   Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
2300   int hash = str->GetIdentityHash();
2301   int hash1 = str->GetIdentityHash();
2302   CHECK_EQ(hash, hash1);
2303   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2304   int hash3 = str->GetIdentityHash();
2305   CHECK_EQ(hash, hash3);
2306
2307   Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
2308   int hash4 = str2->GetIdentityHash();
2309   CHECK_EQ(hash, hash4);
2310 }
2311
2312
2313 THREADED_TEST(SymbolProperties) {
2314   LocalContext env;
2315   v8::Isolate* isolate = env->GetIsolate();
2316   v8::HandleScope scope(isolate);
2317
2318   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2319   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2320   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
2321   v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
2322
2323   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2324
2325   // Check basic symbol functionality.
2326   CHECK(sym1->IsSymbol());
2327   CHECK(sym2->IsSymbol());
2328   CHECK(!obj->IsSymbol());
2329
2330   CHECK(sym1->Equals(sym1));
2331   CHECK(sym2->Equals(sym2));
2332   CHECK(!sym1->Equals(sym2));
2333   CHECK(!sym2->Equals(sym1));
2334   CHECK(sym1->StrictEquals(sym1));
2335   CHECK(sym2->StrictEquals(sym2));
2336   CHECK(!sym1->StrictEquals(sym2));
2337   CHECK(!sym2->StrictEquals(sym1));
2338
2339   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2340
2341   v8::Local<v8::Value> sym_val = sym2;
2342   CHECK(sym_val->IsSymbol());
2343   CHECK(sym_val->Equals(sym2));
2344   CHECK(sym_val->StrictEquals(sym2));
2345   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2346
2347   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2348   CHECK(sym_obj->IsSymbolObject());
2349   CHECK(!sym2->IsSymbolObject());
2350   CHECK(!obj->IsSymbolObject());
2351   CHECK(!sym_obj->Equals(sym2));
2352   CHECK(!sym_obj->StrictEquals(sym2));
2353   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2354   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2355
2356   // Make sure delete of a non-existent symbol property works.
2357   CHECK(obj->Delete(sym1));
2358   CHECK(!obj->Has(sym1));
2359
2360   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2361   CHECK(obj->Has(sym1));
2362   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2363   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2364   CHECK(obj->Has(sym1));
2365   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2366   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2367
2368   CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2369   unsigned num_props = obj->GetPropertyNames()->Length();
2370   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2371                  v8::Integer::New(isolate, 20)));
2372   CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2373   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2374
2375   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2376
2377   CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2378   CHECK(obj->Get(sym3)->IsUndefined());
2379   CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2380   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2381   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2382             ->Equals(v8::Integer::New(isolate, 42)));
2383
2384   // Add another property and delete it afterwards to force the object in
2385   // slow case.
2386   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2387   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2388   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2389   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2390   CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2391
2392   CHECK(obj->Has(sym1));
2393   CHECK(obj->Has(sym2));
2394   CHECK(obj->Has(sym3));
2395   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2396   CHECK(obj->Delete(sym2));
2397   CHECK(obj->Has(sym1));
2398   CHECK(!obj->Has(sym2));
2399   CHECK(obj->Has(sym3));
2400   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2401   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2402   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2403   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2404             ->Equals(v8::Integer::New(isolate, 42)));
2405   CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2406
2407   // Symbol properties are inherited.
2408   v8::Local<v8::Object> child = v8::Object::New(isolate);
2409   child->SetPrototype(obj);
2410   CHECK(child->Has(sym1));
2411   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2412   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2413   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2414             ->Equals(v8::Integer::New(isolate, 42)));
2415   CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2416 }
2417
2418
2419 THREADED_TEST(SymbolTemplateProperties) {
2420   LocalContext env;
2421   v8::Isolate* isolate = env->GetIsolate();
2422   v8::HandleScope scope(isolate);
2423   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2424   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2425   CHECK(!name.IsEmpty());
2426   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2427   v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2428   CHECK(!new_instance.IsEmpty());
2429   CHECK(new_instance->Has(name));
2430 }
2431
2432
2433 THREADED_TEST(PrivateProperties) {
2434   LocalContext env;
2435   v8::Isolate* isolate = env->GetIsolate();
2436   v8::HandleScope scope(isolate);
2437
2438   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2439   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2440   v8::Local<v8::Private> priv2 =
2441       v8::Private::New(isolate, v8_str("my-private"));
2442
2443   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2444
2445   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2446
2447   // Make sure delete of a non-existent private symbol property works.
2448   CHECK(obj->DeletePrivate(priv1));
2449   CHECK(!obj->HasPrivate(priv1));
2450
2451   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2452   CHECK(obj->HasPrivate(priv1));
2453   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2454   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2455   CHECK(obj->HasPrivate(priv1));
2456   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2457
2458   CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2459   unsigned num_props = obj->GetPropertyNames()->Length();
2460   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2461                  v8::Integer::New(isolate, 20)));
2462   CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2463   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2464
2465   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2466
2467   // Add another property and delete it afterwards to force the object in
2468   // slow case.
2469   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2470   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2471   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2472   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2473   CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2474
2475   CHECK(obj->HasPrivate(priv1));
2476   CHECK(obj->HasPrivate(priv2));
2477   CHECK(obj->DeletePrivate(priv2));
2478   CHECK(obj->HasPrivate(priv1));
2479   CHECK(!obj->HasPrivate(priv2));
2480   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2481   CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2482
2483   // Private properties are inherited (for the time being).
2484   v8::Local<v8::Object> child = v8::Object::New(isolate);
2485   child->SetPrototype(obj);
2486   CHECK(child->HasPrivate(priv1));
2487   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2488   CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2489 }
2490
2491
2492 THREADED_TEST(GlobalSymbols) {
2493   LocalContext env;
2494   v8::Isolate* isolate = env->GetIsolate();
2495   v8::HandleScope scope(isolate);
2496
2497   v8::Local<String> name = v8_str("my-symbol");
2498   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2499   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2500   CHECK(glob2->SameValue(glob));
2501
2502   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2503   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2504   CHECK(glob_api2->SameValue(glob_api));
2505   CHECK(!glob_api->SameValue(glob));
2506
2507   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2508   CHECK(!sym->SameValue(glob));
2509
2510   CompileRun("var sym2 = Symbol.for('my-symbol')");
2511   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2512   CHECK(sym2->SameValue(glob));
2513   CHECK(!sym2->SameValue(glob_api));
2514 }
2515
2516
2517 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
2518                                  const char* name) {
2519   LocalContext env;
2520   v8::Isolate* isolate = env->GetIsolate();
2521   v8::HandleScope scope(isolate);
2522
2523   v8::Local<v8::Symbol> symbol = getter(isolate);
2524   std::string script = std::string("var sym = ") + name;
2525   CompileRun(script.c_str());
2526   v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
2527
2528   CHECK(!value.IsEmpty());
2529   CHECK(!symbol.IsEmpty());
2530   CHECK(value->SameValue(symbol));
2531 }
2532
2533
2534 THREADED_TEST(WellKnownSymbols) {
2535   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
2536   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
2537 }
2538
2539
2540 THREADED_TEST(GlobalPrivates) {
2541   LocalContext env;
2542   v8::Isolate* isolate = env->GetIsolate();
2543   v8::HandleScope scope(isolate);
2544
2545   v8::Local<String> name = v8_str("my-private");
2546   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2547   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2548   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2549
2550   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2551   CHECK(obj->HasPrivate(glob2));
2552
2553   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2554   CHECK(!obj->HasPrivate(priv));
2555
2556   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2557   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2558   CHECK(!obj->Has(intern));
2559 }
2560
2561
2562 class ScopedArrayBufferContents {
2563  public:
2564   explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
2565       : contents_(contents) {}
2566   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2567   void* Data() const { return contents_.Data(); }
2568   size_t ByteLength() const { return contents_.ByteLength(); }
2569
2570  private:
2571   const v8::ArrayBuffer::Contents contents_;
2572 };
2573
2574 template <typename T>
2575 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2576   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2577   for (int i = 0; i < value->InternalFieldCount(); i++) {
2578     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2579   }
2580 }
2581
2582
2583 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2584   LocalContext env;
2585   v8::Isolate* isolate = env->GetIsolate();
2586   v8::HandleScope handle_scope(isolate);
2587
2588   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2589   CheckInternalFieldsAreZero(ab);
2590   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2591   CHECK(!ab->IsExternal());
2592   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2593
2594   ScopedArrayBufferContents ab_contents(ab->Externalize());
2595   CHECK(ab->IsExternal());
2596
2597   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2598   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2599   DCHECK(data != NULL);
2600   env->Global()->Set(v8_str("ab"), ab);
2601
2602   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2603   CHECK_EQ(1024, result->Int32Value());
2604
2605   result = CompileRun(
2606       "var u8 = new Uint8Array(ab);"
2607       "u8[0] = 0xFF;"
2608       "u8[1] = 0xAA;"
2609       "u8.length");
2610   CHECK_EQ(1024, result->Int32Value());
2611   CHECK_EQ(0xFF, data[0]);
2612   CHECK_EQ(0xAA, data[1]);
2613   data[0] = 0xCC;
2614   data[1] = 0x11;
2615   result = CompileRun("u8[0] + u8[1]");
2616   CHECK_EQ(0xDD, result->Int32Value());
2617 }
2618
2619
2620 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2621   LocalContext env;
2622   v8::Isolate* isolate = env->GetIsolate();
2623   v8::HandleScope handle_scope(isolate);
2624
2625
2626   v8::Local<v8::Value> result = CompileRun(
2627       "var ab1 = new ArrayBuffer(2);"
2628       "var u8_a = new Uint8Array(ab1);"
2629       "u8_a[0] = 0xAA;"
2630       "u8_a[1] = 0xFF; u8_a.buffer");
2631   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2632   CheckInternalFieldsAreZero(ab1);
2633   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2634   CHECK(!ab1->IsExternal());
2635   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2636   CHECK(ab1->IsExternal());
2637
2638   result = CompileRun("ab1.byteLength");
2639   CHECK_EQ(2, result->Int32Value());
2640   result = CompileRun("u8_a[0]");
2641   CHECK_EQ(0xAA, result->Int32Value());
2642   result = CompileRun("u8_a[1]");
2643   CHECK_EQ(0xFF, result->Int32Value());
2644   result = CompileRun(
2645       "var u8_b = new Uint8Array(ab1);"
2646       "u8_b[0] = 0xBB;"
2647       "u8_a[0]");
2648   CHECK_EQ(0xBB, result->Int32Value());
2649   result = CompileRun("u8_b[1]");
2650   CHECK_EQ(0xFF, result->Int32Value());
2651
2652   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2653   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2654   CHECK_EQ(0xBB, ab1_data[0]);
2655   CHECK_EQ(0xFF, ab1_data[1]);
2656   ab1_data[0] = 0xCC;
2657   ab1_data[1] = 0x11;
2658   result = CompileRun("u8_a[0] + u8_a[1]");
2659   CHECK_EQ(0xDD, result->Int32Value());
2660 }
2661
2662
2663 THREADED_TEST(ArrayBuffer_External) {
2664   LocalContext env;
2665   v8::Isolate* isolate = env->GetIsolate();
2666   v8::HandleScope handle_scope(isolate);
2667
2668   i::ScopedVector<uint8_t> my_data(100);
2669   memset(my_data.start(), 0, 100);
2670   Local<v8::ArrayBuffer> ab3 =
2671       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2672   CheckInternalFieldsAreZero(ab3);
2673   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2674   CHECK(ab3->IsExternal());
2675
2676   env->Global()->Set(v8_str("ab3"), ab3);
2677
2678   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2679   CHECK_EQ(100, result->Int32Value());
2680
2681   result = CompileRun(
2682       "var u8_b = new Uint8Array(ab3);"
2683       "u8_b[0] = 0xBB;"
2684       "u8_b[1] = 0xCC;"
2685       "u8_b.length");
2686   CHECK_EQ(100, result->Int32Value());
2687   CHECK_EQ(0xBB, my_data[0]);
2688   CHECK_EQ(0xCC, my_data[1]);
2689   my_data[0] = 0xCC;
2690   my_data[1] = 0x11;
2691   result = CompileRun("u8_b[0] + u8_b[1]");
2692   CHECK_EQ(0xDD, result->Int32Value());
2693 }
2694
2695
2696 THREADED_TEST(ArrayBuffer_DisableNeuter) {
2697   LocalContext env;
2698   v8::Isolate* isolate = env->GetIsolate();
2699   v8::HandleScope handle_scope(isolate);
2700
2701   i::ScopedVector<uint8_t> my_data(100);
2702   memset(my_data.start(), 0, 100);
2703   Local<v8::ArrayBuffer> ab =
2704       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2705   CHECK(ab->IsNeuterable());
2706
2707   i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
2708   buf->set_is_neuterable(false);
2709
2710   CHECK(!ab->IsNeuterable());
2711 }
2712
2713
2714 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2715   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2716   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2717 }
2718
2719
2720 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2721   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2722   CHECK_EQ(0, static_cast<int>(ta->Length()));
2723   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2724 }
2725
2726
2727 static void CheckIsTypedArrayVarNeutered(const char* name) {
2728   i::ScopedVector<char> source(1024);
2729   i::SNPrintF(source,
2730               "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2731               name, name, name);
2732   CHECK(CompileRun(source.start())->IsTrue());
2733   v8::Handle<v8::TypedArray> ta =
2734       v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2735   CheckIsNeutered(ta);
2736 }
2737
2738
2739 template <typename TypedArray, int kElementSize>
2740 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2741                                          int byteOffset, int length) {
2742   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2743   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2744   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2745   CHECK_EQ(length, static_cast<int>(ta->Length()));
2746   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2747   return ta;
2748 }
2749
2750
2751 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2752   LocalContext env;
2753   v8::Isolate* isolate = env->GetIsolate();
2754   v8::HandleScope handle_scope(isolate);
2755
2756   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
2757
2758   v8::Handle<v8::Uint8Array> u8a =
2759       CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2760   v8::Handle<v8::Uint8ClampedArray> u8c =
2761       CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2762   v8::Handle<v8::Int8Array> i8a =
2763       CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2764
2765   v8::Handle<v8::Uint16Array> u16a =
2766       CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2767   v8::Handle<v8::Int16Array> i16a =
2768       CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2769
2770   v8::Handle<v8::Uint32Array> u32a =
2771       CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2772   v8::Handle<v8::Int32Array> i32a =
2773       CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2774
2775   v8::Handle<v8::Float32Array> f32a =
2776       CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2777   v8::Handle<v8::Float64Array> f64a =
2778       CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2779
2780   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2781   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2782   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2783   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2784
2785   ScopedArrayBufferContents contents(buffer->Externalize());
2786   buffer->Neuter();
2787   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2788   CheckIsNeutered(u8a);
2789   CheckIsNeutered(u8c);
2790   CheckIsNeutered(i8a);
2791   CheckIsNeutered(u16a);
2792   CheckIsNeutered(i16a);
2793   CheckIsNeutered(u32a);
2794   CheckIsNeutered(i32a);
2795   CheckIsNeutered(f32a);
2796   CheckIsNeutered(f64a);
2797   CheckDataViewIsNeutered(dv);
2798 }
2799
2800
2801 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2802   LocalContext env;
2803   v8::Isolate* isolate = env->GetIsolate();
2804   v8::HandleScope handle_scope(isolate);
2805
2806   CompileRun(
2807       "var ab = new ArrayBuffer(1024);"
2808       "var u8a = new Uint8Array(ab, 1, 1023);"
2809       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2810       "var i8a = new Int8Array(ab, 1, 1023);"
2811       "var u16a = new Uint16Array(ab, 2, 511);"
2812       "var i16a = new Int16Array(ab, 2, 511);"
2813       "var u32a = new Uint32Array(ab, 4, 255);"
2814       "var i32a = new Int32Array(ab, 4, 255);"
2815       "var f32a = new Float32Array(ab, 4, 255);"
2816       "var f64a = new Float64Array(ab, 8, 127);"
2817       "var dv = new DataView(ab, 1, 1023);");
2818
2819   v8::Handle<v8::ArrayBuffer> ab =
2820       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2821
2822   v8::Handle<v8::DataView> dv =
2823       v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2824
2825   ScopedArrayBufferContents contents(ab->Externalize());
2826   ab->Neuter();
2827   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2828   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2829
2830   CheckIsTypedArrayVarNeutered("u8a");
2831   CheckIsTypedArrayVarNeutered("u8c");
2832   CheckIsTypedArrayVarNeutered("i8a");
2833   CheckIsTypedArrayVarNeutered("u16a");
2834   CheckIsTypedArrayVarNeutered("i16a");
2835   CheckIsTypedArrayVarNeutered("u32a");
2836   CheckIsTypedArrayVarNeutered("i32a");
2837   CheckIsTypedArrayVarNeutered("f32a");
2838   CheckIsTypedArrayVarNeutered("f64a");
2839
2840   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2841   CheckDataViewIsNeutered(dv);
2842 }
2843
2844
2845 THREADED_TEST(HiddenProperties) {
2846   LocalContext env;
2847   v8::Isolate* isolate = env->GetIsolate();
2848   v8::HandleScope scope(isolate);
2849
2850   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2851   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2852   v8::Local<v8::String> empty = v8_str("");
2853   v8::Local<v8::String> prop_name = v8_str("prop_name");
2854
2855   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2856
2857   // Make sure delete of a non-existent hidden value works
2858   CHECK(obj->DeleteHiddenValue(key));
2859
2860   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
2861   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2862   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2863   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2864
2865   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2866
2867   // Make sure we do not find the hidden property.
2868   CHECK(!obj->Has(empty));
2869   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2870   CHECK(obj->Get(empty)->IsUndefined());
2871   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2872   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
2873   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2874   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2875
2876   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2877
2878   // Add another property and delete it afterwards to force the object in
2879   // slow case.
2880   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
2881   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2882   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2883   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2884   CHECK(obj->Delete(prop_name));
2885   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2886
2887   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2888
2889   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2890   CHECK(obj->GetHiddenValue(key).IsEmpty());
2891
2892   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2893   CHECK(obj->DeleteHiddenValue(key));
2894   CHECK(obj->GetHiddenValue(key).IsEmpty());
2895 }
2896
2897
2898 THREADED_TEST(Regress97784) {
2899   // Regression test for crbug.com/97784
2900   // Messing with the Object.prototype should not have effect on
2901   // hidden properties.
2902   LocalContext env;
2903   v8::HandleScope scope(env->GetIsolate());
2904
2905   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2906   v8::Local<v8::String> key = v8_str("hidden");
2907
2908   CompileRun(
2909       "set_called = false;"
2910       "Object.defineProperty("
2911       "    Object.prototype,"
2912       "    'hidden',"
2913       "    {get: function() { return 45; },"
2914       "     set: function() { set_called = true; }})");
2915
2916   CHECK(obj->GetHiddenValue(key).IsEmpty());
2917   // Make sure that the getter and setter from Object.prototype is not invoked.
2918   // If it did we would have full access to the hidden properties in
2919   // the accessor.
2920   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
2921   ExpectFalse("set_called");
2922   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2923 }
2924
2925
2926 THREADED_TEST(External) {
2927   v8::HandleScope scope(CcTest::isolate());
2928   int x = 3;
2929   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
2930   LocalContext env;
2931   env->Global()->Set(v8_str("ext"), ext);
2932   Local<Value> reext_obj = CompileRun("this.ext");
2933   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2934   int* ptr = static_cast<int*>(reext->Value());
2935   CHECK_EQ(x, 3);
2936   *ptr = 10;
2937   CHECK_EQ(x, 10);
2938
2939   // Make sure unaligned pointers are wrapped properly.
2940   char* data = i::StrDup("0123456789");
2941   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
2942   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
2943   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
2944   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
2945
2946   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
2947   CHECK_EQ('0', *char_ptr);
2948   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
2949   CHECK_EQ('1', *char_ptr);
2950   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
2951   CHECK_EQ('2', *char_ptr);
2952   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
2953   CHECK_EQ('3', *char_ptr);
2954   i::DeleteArray(data);
2955 }
2956
2957
2958 THREADED_TEST(GlobalHandle) {
2959   v8::Isolate* isolate = CcTest::isolate();
2960   v8::Persistent<String> global;
2961   {
2962     v8::HandleScope scope(isolate);
2963     global.Reset(isolate, v8_str("str"));
2964   }
2965   {
2966     v8::HandleScope scope(isolate);
2967     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2968   }
2969   global.Reset();
2970   {
2971     v8::HandleScope scope(isolate);
2972     global.Reset(isolate, v8_str("str"));
2973   }
2974   {
2975     v8::HandleScope scope(isolate);
2976     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2977   }
2978   global.Reset();
2979 }
2980
2981
2982 THREADED_TEST(ResettingGlobalHandle) {
2983   v8::Isolate* isolate = CcTest::isolate();
2984   v8::Persistent<String> global;
2985   {
2986     v8::HandleScope scope(isolate);
2987     global.Reset(isolate, v8_str("str"));
2988   }
2989   v8::internal::GlobalHandles* global_handles =
2990       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
2991   int initial_handle_count = global_handles->global_handles_count();
2992   {
2993     v8::HandleScope scope(isolate);
2994     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2995   }
2996   {
2997     v8::HandleScope scope(isolate);
2998     global.Reset(isolate, v8_str("longer"));
2999   }
3000   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3001   {
3002     v8::HandleScope scope(isolate);
3003     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3004   }
3005   global.Reset();
3006   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3007 }
3008
3009
3010 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3011   v8::Isolate* isolate = CcTest::isolate();
3012   v8::Persistent<String> global;
3013   {
3014     v8::HandleScope scope(isolate);
3015     global.Reset(isolate, v8_str("str"));
3016   }
3017   v8::internal::GlobalHandles* global_handles =
3018       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3019   int initial_handle_count = global_handles->global_handles_count();
3020   {
3021     v8::HandleScope scope(isolate);
3022     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3023   }
3024   {
3025     v8::HandleScope scope(isolate);
3026     Local<String> empty;
3027     global.Reset(isolate, empty);
3028   }
3029   CHECK(global.IsEmpty());
3030   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3031 }
3032
3033
3034 template <class T>
3035 static v8::Global<T> PassUnique(v8::Global<T> unique) {
3036   return unique.Pass();
3037 }
3038
3039
3040 template <class T>
3041 static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
3042                                   const v8::Persistent<T>& global) {
3043   v8::Global<String> unique(isolate, global);
3044   return unique.Pass();
3045 }
3046
3047
3048 THREADED_TEST(Global) {
3049   v8::Isolate* isolate = CcTest::isolate();
3050   v8::Persistent<String> global;
3051   {
3052     v8::HandleScope scope(isolate);
3053     global.Reset(isolate, v8_str("str"));
3054   }
3055   v8::internal::GlobalHandles* global_handles =
3056       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3057   int initial_handle_count = global_handles->global_handles_count();
3058   {
3059     v8::Global<String> unique(isolate, global);
3060     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3061     // Test assignment via Pass
3062     {
3063       v8::Global<String> copy = unique.Pass();
3064       CHECK(unique.IsEmpty());
3065       CHECK(copy == global);
3066       CHECK_EQ(initial_handle_count + 1,
3067                global_handles->global_handles_count());
3068       unique = copy.Pass();
3069     }
3070     // Test ctor via Pass
3071     {
3072       v8::Global<String> copy(unique.Pass());
3073       CHECK(unique.IsEmpty());
3074       CHECK(copy == global);
3075       CHECK_EQ(initial_handle_count + 1,
3076                global_handles->global_handles_count());
3077       unique = copy.Pass();
3078     }
3079     // Test pass through function call
3080     {
3081       v8::Global<String> copy = PassUnique(unique.Pass());
3082       CHECK(unique.IsEmpty());
3083       CHECK(copy == global);
3084       CHECK_EQ(initial_handle_count + 1,
3085                global_handles->global_handles_count());
3086       unique = copy.Pass();
3087     }
3088     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3089   }
3090   // Test pass from function call
3091   {
3092     v8::Global<String> unique = ReturnUnique(isolate, global);
3093     CHECK(unique == global);
3094     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3095   }
3096   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3097   global.Reset();
3098 }
3099
3100
3101 namespace {
3102
3103 class TwoPassCallbackData;
3104 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3105 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3106
3107
3108 class TwoPassCallbackData {
3109  public:
3110   TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
3111       : first_pass_called_(false),
3112         second_pass_called_(false),
3113         trigger_gc_(false),
3114         instance_counter_(instance_counter) {
3115     HandleScope scope(isolate);
3116     i::ScopedVector<char> buffer(40);
3117     i::SNPrintF(buffer, "%p", static_cast<void*>(this));
3118     auto string =
3119         v8::String::NewFromUtf8(isolate, buffer.start(),
3120                                 v8::NewStringType::kNormal).ToLocalChecked();
3121     cell_.Reset(isolate, string);
3122     (*instance_counter_)++;
3123   }
3124
3125   ~TwoPassCallbackData() {
3126     CHECK(first_pass_called_);
3127     CHECK(second_pass_called_);
3128     CHECK(cell_.IsEmpty());
3129     (*instance_counter_)--;
3130   }
3131
3132   void FirstPass() {
3133     CHECK(!first_pass_called_);
3134     CHECK(!second_pass_called_);
3135     CHECK(!cell_.IsEmpty());
3136     cell_.Reset();
3137     first_pass_called_ = true;
3138   }
3139
3140   void SecondPass() {
3141     CHECK(first_pass_called_);
3142     CHECK(!second_pass_called_);
3143     CHECK(cell_.IsEmpty());
3144     second_pass_called_ = true;
3145     delete this;
3146   }
3147
3148   void SetWeak() {
3149     cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
3150   }
3151
3152   void MarkTriggerGc() { trigger_gc_ = true; }
3153   bool trigger_gc() { return trigger_gc_; }
3154
3155   int* instance_counter() { return instance_counter_; }
3156
3157  private:
3158   bool first_pass_called_;
3159   bool second_pass_called_;
3160   bool trigger_gc_;
3161   v8::Global<v8::String> cell_;
3162   int* instance_counter_;
3163 };
3164
3165
3166 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3167   ApiTestFuzzer::Fuzz();
3168   bool trigger_gc = data.GetParameter()->trigger_gc();
3169   int* instance_counter = data.GetParameter()->instance_counter();
3170   data.GetParameter()->SecondPass();
3171   if (!trigger_gc) return;
3172   auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
3173   data_2->SetWeak();
3174   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3175 }
3176
3177
3178 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3179   data.GetParameter()->FirstPass();
3180   data.SetSecondPassCallback(SecondPassCallback);
3181 }
3182
3183 }  // namespace
3184
3185
3186 TEST(TwoPassPhantomCallbacks) {
3187   auto isolate = CcTest::isolate();
3188   const size_t kLength = 20;
3189   int instance_counter = 0;
3190   for (size_t i = 0; i < kLength; ++i) {
3191     auto data = new TwoPassCallbackData(isolate, &instance_counter);
3192     data->SetWeak();
3193   }
3194   CHECK_EQ(static_cast<int>(kLength), instance_counter);
3195   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3196   CHECK_EQ(0, instance_counter);
3197 }
3198
3199
3200 TEST(TwoPassPhantomCallbacksNestedGc) {
3201   auto isolate = CcTest::isolate();
3202   const size_t kLength = 20;
3203   TwoPassCallbackData* array[kLength];
3204   int instance_counter = 0;
3205   for (size_t i = 0; i < kLength; ++i) {
3206     array[i] = new TwoPassCallbackData(isolate, &instance_counter);
3207     array[i]->SetWeak();
3208   }
3209   array[5]->MarkTriggerGc();
3210   array[10]->MarkTriggerGc();
3211   array[15]->MarkTriggerGc();
3212   CHECK_EQ(static_cast<int>(kLength), instance_counter);
3213   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3214   CHECK_EQ(0, instance_counter);
3215 }
3216
3217
3218 template <typename K, typename V>
3219 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3220  public:
3221   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V>> MapType;
3222   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3223   struct WeakCallbackDataType {
3224     MapType* map;
3225     K key;
3226   };
3227   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3228                                                      Local<V> value) {
3229     WeakCallbackDataType* data = new WeakCallbackDataType;
3230     data->map = map;
3231     data->key = key;
3232     return data;
3233   }
3234   static MapType* MapFromWeakCallbackData(
3235       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3236     return data.GetParameter()->map;
3237   }
3238   static K KeyFromWeakCallbackData(
3239       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3240     return data.GetParameter()->key;
3241   }
3242   static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3243   static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {}
3244 };
3245
3246
3247 template <typename Map>
3248 static void TestPersistentValueMap() {
3249   LocalContext env;
3250   v8::Isolate* isolate = env->GetIsolate();
3251   Map map(isolate);
3252   v8::internal::GlobalHandles* global_handles =
3253       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3254   int initial_handle_count = global_handles->global_handles_count();
3255   CHECK_EQ(0, static_cast<int>(map.Size()));
3256   {
3257     HandleScope scope(isolate);
3258     Local<v8::Object> obj = map.Get(7);
3259     CHECK(obj.IsEmpty());
3260     Local<v8::Object> expected = v8::Object::New(isolate);
3261     map.Set(7, expected);
3262     CHECK_EQ(1, static_cast<int>(map.Size()));
3263     obj = map.Get(7);
3264     CHECK(expected->Equals(obj));
3265     {
3266       typename Map::PersistentValueReference ref = map.GetReference(7);
3267       CHECK(expected->Equals(ref.NewLocal(isolate)));
3268     }
3269     v8::Global<v8::Object> removed = map.Remove(7);
3270     CHECK_EQ(0, static_cast<int>(map.Size()));
3271     CHECK(expected == removed);
3272     removed = map.Remove(7);
3273     CHECK(removed.IsEmpty());
3274     map.Set(8, expected);
3275     CHECK_EQ(1, static_cast<int>(map.Size()));
3276     map.Set(8, expected);
3277     CHECK_EQ(1, static_cast<int>(map.Size()));
3278     {
3279       typename Map::PersistentValueReference ref;
3280       Local<v8::Object> expected2 = v8::Object::New(isolate);
3281       removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
3282       CHECK_EQ(1, static_cast<int>(map.Size()));
3283       CHECK(expected == removed);
3284       CHECK(expected2->Equals(ref.NewLocal(isolate)));
3285     }
3286   }
3287   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3288   if (map.IsWeak()) {
3289     reinterpret_cast<v8::internal::Isolate*>(isolate)
3290         ->heap()
3291         ->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3292   } else {
3293     map.Clear();
3294   }
3295   CHECK_EQ(0, static_cast<int>(map.Size()));
3296   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3297 }
3298
3299
3300 TEST(PersistentValueMap) {
3301   // Default case, w/o weak callbacks:
3302   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object>>();
3303
3304   // Custom traits with weak callbacks:
3305   typedef v8::PersistentValueMap<int, v8::Object,
3306                                  WeakStdMapTraits<int, v8::Object>>
3307       WeakPersistentValueMap;
3308   TestPersistentValueMap<WeakPersistentValueMap>();
3309 }
3310
3311
3312 namespace {
3313
3314 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
3315
3316
3317 Local<v8::Object> NewObjectForIntKey(
3318     v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
3319     int key) {
3320   auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
3321   auto obj = local->NewInstance();
3322   obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
3323   return obj;
3324 }
3325
3326
3327 template <typename K, typename V>
3328 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
3329  public:
3330   typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
3331   static const v8::PersistentContainerCallbackType kCallbackType =
3332       v8::kWeakWithInternalFields;
3333   struct WeakCallbackDataType {
3334     MapType* map;
3335     K key;
3336   };
3337   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3338                                                      Local<V> value) {
3339     WeakCallbackDataType* data = new WeakCallbackDataType;
3340     data->map = map;
3341     data->key = key;
3342     return data;
3343   }
3344   static MapType* MapFromWeakCallbackInfo(
3345       const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3346     return data.GetParameter()->map;
3347   }
3348   static K KeyFromWeakCallbackInfo(
3349       const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3350     return data.GetParameter()->key;
3351   }
3352   static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3353   static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
3354     CHECK_EQ(IntKeyToVoidPointer(key),
3355              v8::Object::GetAlignedPointerFromInternalField(value, 0));
3356   }
3357   static void DisposeWeak(
3358       v8::Isolate* isolate,
3359       const v8::WeakCallbackInfo<WeakCallbackDataType>& info, K key) {
3360     CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
3361     DisposeCallbackData(info.GetParameter());
3362   }
3363 };
3364
3365 }  // namespace
3366
3367
3368 TEST(GlobalValueMap) {
3369   typedef v8::GlobalValueMap<int, v8::Object,
3370                              PhantomStdMapTraits<int, v8::Object>> Map;
3371   LocalContext env;
3372   v8::Isolate* isolate = env->GetIsolate();
3373   v8::Global<ObjectTemplate> templ;
3374   {
3375     HandleScope scope(isolate);
3376     auto t = ObjectTemplate::New(isolate);
3377     t->SetInternalFieldCount(1);
3378     templ.Reset(isolate, t);
3379   }
3380   Map map(isolate);
3381   v8::internal::GlobalHandles* global_handles =
3382       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3383   int initial_handle_count = global_handles->global_handles_count();
3384   CHECK_EQ(0, static_cast<int>(map.Size()));
3385   {
3386     HandleScope scope(isolate);
3387     Local<v8::Object> obj = map.Get(7);
3388     CHECK(obj.IsEmpty());
3389     Local<v8::Object> expected = v8::Object::New(isolate);
3390     map.Set(7, expected);
3391     CHECK_EQ(1, static_cast<int>(map.Size()));
3392     obj = map.Get(7);
3393     CHECK(expected->Equals(obj));
3394     {
3395       Map::PersistentValueReference ref = map.GetReference(7);
3396       CHECK(expected->Equals(ref.NewLocal(isolate)));
3397     }
3398     v8::Global<v8::Object> removed = map.Remove(7);
3399     CHECK_EQ(0, static_cast<int>(map.Size()));
3400     CHECK(expected == removed);
3401     removed = map.Remove(7);
3402     CHECK(removed.IsEmpty());
3403     map.Set(8, expected);
3404     CHECK_EQ(1, static_cast<int>(map.Size()));
3405     map.Set(8, expected);
3406     CHECK_EQ(1, static_cast<int>(map.Size()));
3407     {
3408       Map::PersistentValueReference ref;
3409       Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
3410       removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
3411       CHECK_EQ(1, static_cast<int>(map.Size()));
3412       CHECK(expected == removed);
3413       CHECK(expected2->Equals(ref.NewLocal(isolate)));
3414     }
3415   }
3416   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3417   CcTest::i_isolate()->heap()->CollectAllGarbage(
3418       i::Heap::kAbortIncrementalMarkingMask);
3419   CHECK_EQ(0, static_cast<int>(map.Size()));
3420   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3421   {
3422     HandleScope scope(isolate);
3423     Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
3424     map.Set(9, value);
3425     map.Clear();
3426   }
3427   CHECK_EQ(0, static_cast<int>(map.Size()));
3428   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3429 }
3430
3431
3432 TEST(PersistentValueVector) {
3433   LocalContext env;
3434   v8::Isolate* isolate = env->GetIsolate();
3435   v8::internal::GlobalHandles* global_handles =
3436       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3437   int handle_count = global_handles->global_handles_count();
3438   HandleScope scope(isolate);
3439
3440   v8::PersistentValueVector<v8::Object> vector(isolate);
3441
3442   Local<v8::Object> obj1 = v8::Object::New(isolate);
3443   Local<v8::Object> obj2 = v8::Object::New(isolate);
3444   v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
3445
3446   CHECK(vector.IsEmpty());
3447   CHECK_EQ(0, static_cast<int>(vector.Size()));
3448
3449   vector.ReserveCapacity(3);
3450   CHECK(vector.IsEmpty());
3451
3452   vector.Append(obj1);
3453   vector.Append(obj2);
3454   vector.Append(obj1);
3455   vector.Append(obj3.Pass());
3456   vector.Append(obj1);
3457
3458   CHECK(!vector.IsEmpty());
3459   CHECK_EQ(5, static_cast<int>(vector.Size()));
3460   CHECK(obj3.IsEmpty());
3461   CHECK(obj1->Equals(vector.Get(0)));
3462   CHECK(obj1->Equals(vector.Get(2)));
3463   CHECK(obj1->Equals(vector.Get(4)));
3464   CHECK(obj2->Equals(vector.Get(1)));
3465
3466   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3467
3468   vector.Clear();
3469   CHECK(vector.IsEmpty());
3470   CHECK_EQ(0, static_cast<int>(vector.Size()));
3471   CHECK_EQ(handle_count, global_handles->global_handles_count());
3472 }
3473
3474
3475 THREADED_TEST(GlobalHandleUpcast) {
3476   v8::Isolate* isolate = CcTest::isolate();
3477   v8::HandleScope scope(isolate);
3478   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3479   v8::Persistent<String> global_string(isolate, local);
3480   v8::Persistent<Value>& global_value =
3481       v8::Persistent<Value>::Cast(global_string);
3482   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3483   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3484   global_string.Reset();
3485 }
3486
3487
3488 THREADED_TEST(HandleEquality) {
3489   v8::Isolate* isolate = CcTest::isolate();
3490   v8::Persistent<String> global1;
3491   v8::Persistent<String> global2;
3492   {
3493     v8::HandleScope scope(isolate);
3494     global1.Reset(isolate, v8_str("str"));
3495     global2.Reset(isolate, v8_str("str2"));
3496   }
3497   CHECK_EQ(global1 == global1, true);
3498   CHECK_EQ(global1 != global1, false);
3499   {
3500     v8::HandleScope scope(isolate);
3501     Local<String> local1 = Local<String>::New(isolate, global1);
3502     Local<String> local2 = Local<String>::New(isolate, global2);
3503
3504     CHECK_EQ(global1 == local1, true);
3505     CHECK_EQ(global1 != local1, false);
3506     CHECK_EQ(local1 == global1, true);
3507     CHECK_EQ(local1 != global1, false);
3508
3509     CHECK_EQ(global1 == local2, false);
3510     CHECK_EQ(global1 != local2, true);
3511     CHECK_EQ(local2 == global1, false);
3512     CHECK_EQ(local2 != global1, true);
3513
3514     CHECK_EQ(local1 == local2, false);
3515     CHECK_EQ(local1 != local2, true);
3516
3517     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3518     CHECK_EQ(local1 == anotherLocal1, true);
3519     CHECK_EQ(local1 != anotherLocal1, false);
3520   }
3521   global1.Reset();
3522   global2.Reset();
3523 }
3524
3525
3526 THREADED_TEST(LocalHandle) {
3527   v8::HandleScope scope(CcTest::isolate());
3528   v8::Local<String> local =
3529       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3530   CHECK_EQ(local->Length(), 3);
3531 }
3532
3533
3534 class WeakCallCounter {
3535  public:
3536   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
3537   int id() { return id_; }
3538   void increment() { number_of_weak_calls_++; }
3539   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3540
3541  private:
3542   int id_;
3543   int number_of_weak_calls_;
3544 };
3545
3546
3547 template <typename T>
3548 struct WeakCallCounterAndPersistent {
3549   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3550       : counter(counter) {}
3551   WeakCallCounter* counter;
3552   v8::Persistent<T> handle;
3553 };
3554
3555
3556 template <typename T>
3557 static void WeakPointerCallback(
3558     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T>>& data) {
3559   CHECK_EQ(1234, data.GetParameter()->counter->id());
3560   data.GetParameter()->counter->increment();
3561   data.GetParameter()->handle.Reset();
3562 }
3563
3564
3565 template <typename T>
3566 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3567   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3568 }
3569
3570
3571 THREADED_TEST(ApiObjectGroups) {
3572   LocalContext env;
3573   v8::Isolate* iso = env->GetIsolate();
3574   HandleScope scope(iso);
3575
3576   WeakCallCounter counter(1234);
3577
3578   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3579   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3580   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3581   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3582   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3583   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3584
3585   {
3586     HandleScope scope(iso);
3587     g1s1.handle.Reset(iso, Object::New(iso));
3588     g1s2.handle.Reset(iso, Object::New(iso));
3589     g1c1.handle.Reset(iso, Object::New(iso));
3590     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3591     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3592     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3593
3594     g2s1.handle.Reset(iso, Object::New(iso));
3595     g2s2.handle.Reset(iso, Object::New(iso));
3596     g2c1.handle.Reset(iso, Object::New(iso));
3597     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3598     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3599     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3600   }
3601
3602   WeakCallCounterAndPersistent<Value> root(&counter);
3603   root.handle.Reset(iso, g1s1.handle);  // make a root.
3604
3605   // Connect group 1 and 2, make a cycle.
3606   {
3607     HandleScope scope(iso);
3608     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
3609               ->Set(0, Local<Value>::New(iso, g2s2.handle)));
3610     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
3611               ->Set(0, Local<Value>::New(iso, g1s1.handle)));
3612   }
3613
3614   {
3615     UniqueId id1 = MakeUniqueId(g1s1.handle);
3616     UniqueId id2 = MakeUniqueId(g2s2.handle);
3617     iso->SetObjectGroupId(g1s1.handle, id1);
3618     iso->SetObjectGroupId(g1s2.handle, id1);
3619     iso->SetReferenceFromGroup(id1, g1c1.handle);
3620     iso->SetObjectGroupId(g2s1.handle, id2);
3621     iso->SetObjectGroupId(g2s2.handle, id2);
3622     iso->SetReferenceFromGroup(id2, g2c1.handle);
3623   }
3624   // Do a single full GC, ensure incremental marking is stopped.
3625   v8::internal::Heap* heap =
3626       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3627   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3628
3629   // All object should be alive.
3630   CHECK_EQ(0, counter.NumberOfWeakCalls());
3631
3632   // Weaken the root.
3633   root.handle.SetWeak(&root, &WeakPointerCallback);
3634   // But make children strong roots---all the objects (except for children)
3635   // should be collectable now.
3636   g1c1.handle.ClearWeak();
3637   g2c1.handle.ClearWeak();
3638
3639   // Groups are deleted, rebuild groups.
3640   {
3641     UniqueId id1 = MakeUniqueId(g1s1.handle);
3642     UniqueId id2 = MakeUniqueId(g2s2.handle);
3643     iso->SetObjectGroupId(g1s1.handle, id1);
3644     iso->SetObjectGroupId(g1s2.handle, id1);
3645     iso->SetReferenceFromGroup(id1, g1c1.handle);
3646     iso->SetObjectGroupId(g2s1.handle, id2);
3647     iso->SetObjectGroupId(g2s2.handle, id2);
3648     iso->SetReferenceFromGroup(id2, g2c1.handle);
3649   }
3650
3651   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3652
3653   // All objects should be gone. 5 global handles in total.
3654   CHECK_EQ(5, counter.NumberOfWeakCalls());
3655
3656   // And now make children weak again and collect them.
3657   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3658   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3659
3660   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3661   CHECK_EQ(7, counter.NumberOfWeakCalls());
3662 }
3663
3664
3665 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3666   LocalContext env;
3667   v8::Isolate* iso = env->GetIsolate();
3668   HandleScope scope(iso);
3669
3670   WeakCallCounter counter(1234);
3671
3672   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3673   WeakCallCounterAndPersistent<String> g1s2(&counter);
3674   WeakCallCounterAndPersistent<String> g1c1(&counter);
3675   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3676   WeakCallCounterAndPersistent<String> g2s2(&counter);
3677   WeakCallCounterAndPersistent<String> g2c1(&counter);
3678
3679   {
3680     HandleScope scope(iso);
3681     g1s1.handle.Reset(iso, Object::New(iso));
3682     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3683     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3684     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3685     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3686     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3687
3688     g2s1.handle.Reset(iso, Object::New(iso));
3689     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3690     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3691     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3692     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3693     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3694   }
3695
3696   WeakCallCounterAndPersistent<Value> root(&counter);
3697   root.handle.Reset(iso, g1s1.handle);  // make a root.
3698
3699   // Connect group 1 and 2, make a cycle.
3700   {
3701     HandleScope scope(iso);
3702     CHECK(Local<Object>::New(iso, g1s1.handle)
3703               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3704     CHECK(Local<Object>::New(iso, g2s1.handle)
3705               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3706   }
3707
3708   {
3709     UniqueId id1 = MakeUniqueId(g1s1.handle);
3710     UniqueId id2 = MakeUniqueId(g2s2.handle);
3711     iso->SetObjectGroupId(g1s1.handle, id1);
3712     iso->SetObjectGroupId(g1s2.handle, id1);
3713     iso->SetReference(g1s1.handle, g1c1.handle);
3714     iso->SetObjectGroupId(g2s1.handle, id2);
3715     iso->SetObjectGroupId(g2s2.handle, id2);
3716     iso->SetReferenceFromGroup(id2, g2c1.handle);
3717   }
3718   // Do a single full GC, ensure incremental marking is stopped.
3719   v8::internal::Heap* heap =
3720       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3721   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3722
3723   // All object should be alive.
3724   CHECK_EQ(0, counter.NumberOfWeakCalls());
3725
3726   // Weaken the root.
3727   root.handle.SetWeak(&root, &WeakPointerCallback);
3728   // But make children strong roots---all the objects (except for children)
3729   // should be collectable now.
3730   g1c1.handle.ClearWeak();
3731   g2c1.handle.ClearWeak();
3732
3733   // Groups are deleted, rebuild groups.
3734   {
3735     UniqueId id1 = MakeUniqueId(g1s1.handle);
3736     UniqueId id2 = MakeUniqueId(g2s2.handle);
3737     iso->SetObjectGroupId(g1s1.handle, id1);
3738     iso->SetObjectGroupId(g1s2.handle, id1);
3739     iso->SetReference(g1s1.handle, g1c1.handle);
3740     iso->SetObjectGroupId(g2s1.handle, id2);
3741     iso->SetObjectGroupId(g2s2.handle, id2);
3742     iso->SetReferenceFromGroup(id2, g2c1.handle);
3743   }
3744
3745   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3746
3747   // All objects should be gone. 5 global handles in total.
3748   CHECK_EQ(5, counter.NumberOfWeakCalls());
3749
3750   // And now make children weak again and collect them.
3751   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3752   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3753
3754   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3755   CHECK_EQ(7, counter.NumberOfWeakCalls());
3756 }
3757
3758
3759 THREADED_TEST(ApiObjectGroupsCycle) {
3760   LocalContext env;
3761   v8::Isolate* iso = env->GetIsolate();
3762   HandleScope scope(iso);
3763
3764   WeakCallCounter counter(1234);
3765
3766   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3767   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3768   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3769   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3770   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3771   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3772   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3773   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3774
3775   {
3776     HandleScope scope(iso);
3777     g1s1.handle.Reset(iso, Object::New(iso));
3778     g1s2.handle.Reset(iso, Object::New(iso));
3779     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3780     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3781     CHECK(g1s1.handle.IsWeak());
3782     CHECK(g1s2.handle.IsWeak());
3783
3784     g2s1.handle.Reset(iso, Object::New(iso));
3785     g2s2.handle.Reset(iso, Object::New(iso));
3786     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3787     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3788     CHECK(g2s1.handle.IsWeak());
3789     CHECK(g2s2.handle.IsWeak());
3790
3791     g3s1.handle.Reset(iso, Object::New(iso));
3792     g3s2.handle.Reset(iso, Object::New(iso));
3793     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3794     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3795     CHECK(g3s1.handle.IsWeak());
3796     CHECK(g3s2.handle.IsWeak());
3797
3798     g4s1.handle.Reset(iso, Object::New(iso));
3799     g4s2.handle.Reset(iso, Object::New(iso));
3800     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3801     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3802     CHECK(g4s1.handle.IsWeak());
3803     CHECK(g4s2.handle.IsWeak());
3804   }
3805
3806   WeakCallCounterAndPersistent<Value> root(&counter);
3807   root.handle.Reset(iso, g1s1.handle);  // make a root.
3808
3809   // Connect groups.  We're building the following cycle:
3810   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3811   // groups.
3812   {
3813     UniqueId id1 = MakeUniqueId(g1s1.handle);
3814     UniqueId id2 = MakeUniqueId(g2s1.handle);
3815     UniqueId id3 = MakeUniqueId(g3s1.handle);
3816     UniqueId id4 = MakeUniqueId(g4s1.handle);
3817     iso->SetObjectGroupId(g1s1.handle, id1);
3818     iso->SetObjectGroupId(g1s2.handle, id1);
3819     iso->SetReferenceFromGroup(id1, g2s1.handle);
3820     iso->SetObjectGroupId(g2s1.handle, id2);
3821     iso->SetObjectGroupId(g2s2.handle, id2);
3822     iso->SetReferenceFromGroup(id2, g3s1.handle);
3823     iso->SetObjectGroupId(g3s1.handle, id3);
3824     iso->SetObjectGroupId(g3s2.handle, id3);
3825     iso->SetReferenceFromGroup(id3, g4s1.handle);
3826     iso->SetObjectGroupId(g4s1.handle, id4);
3827     iso->SetObjectGroupId(g4s2.handle, id4);
3828     iso->SetReferenceFromGroup(id4, g1s1.handle);
3829   }
3830   // Do a single full GC
3831   v8::internal::Heap* heap =
3832       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3833   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3834
3835   // All object should be alive.
3836   CHECK_EQ(0, counter.NumberOfWeakCalls());
3837
3838   // Weaken the root.
3839   root.handle.SetWeak(&root, &WeakPointerCallback);
3840
3841   // Groups are deleted, rebuild groups.
3842   {
3843     UniqueId id1 = MakeUniqueId(g1s1.handle);
3844     UniqueId id2 = MakeUniqueId(g2s1.handle);
3845     UniqueId id3 = MakeUniqueId(g3s1.handle);
3846     UniqueId id4 = MakeUniqueId(g4s1.handle);
3847     iso->SetObjectGroupId(g1s1.handle, id1);
3848     iso->SetObjectGroupId(g1s2.handle, id1);
3849     iso->SetReferenceFromGroup(id1, g2s1.handle);
3850     iso->SetObjectGroupId(g2s1.handle, id2);
3851     iso->SetObjectGroupId(g2s2.handle, id2);
3852     iso->SetReferenceFromGroup(id2, g3s1.handle);
3853     iso->SetObjectGroupId(g3s1.handle, id3);
3854     iso->SetObjectGroupId(g3s2.handle, id3);
3855     iso->SetReferenceFromGroup(id3, g4s1.handle);
3856     iso->SetObjectGroupId(g4s1.handle, id4);
3857     iso->SetObjectGroupId(g4s2.handle, id4);
3858     iso->SetReferenceFromGroup(id4, g1s1.handle);
3859   }
3860
3861   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3862
3863   // All objects should be gone. 9 global handles in total.
3864   CHECK_EQ(9, counter.NumberOfWeakCalls());
3865 }
3866
3867
3868 THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
3869   LocalContext env;
3870   v8::Isolate* iso = env->GetIsolate();
3871   HandleScope scope(iso);
3872
3873   WeakCallCounter counter(1234);
3874
3875   WeakCallCounterAndPersistent<Value> weak_obj(&counter);
3876
3877   // Create a weak object that references a internalized string.
3878   {
3879     HandleScope scope(iso);
3880     weak_obj.handle.Reset(iso, Object::New(iso));
3881     weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
3882     CHECK(weak_obj.handle.IsWeak());
3883     Local<Object>::New(iso, weak_obj.handle.As<Object>())
3884         ->Set(v8_str("x"), String::NewFromUtf8(iso, "magic cookie",
3885                                                String::kInternalizedString));
3886   }
3887   // Do a single full GC
3888   i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
3889   i::Heap* heap = i_iso->heap();
3890   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3891
3892   // We should have received the weak callback.
3893   CHECK_EQ(1, counter.NumberOfWeakCalls());
3894
3895   // Check that the string is still alive.
3896   {
3897     HandleScope scope(iso);
3898     i::MaybeHandle<i::String> magic_string =
3899         i::StringTable::LookupStringIfExists(
3900             i_iso,
3901             v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
3902     magic_string.Check();
3903   }
3904 }
3905
3906
3907 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3908 // on the buildbots, so was made non-threaded for the time being.
3909 TEST(ApiObjectGroupsCycleForScavenger) {
3910   i::FLAG_stress_compaction = false;
3911   i::FLAG_gc_global = false;
3912   LocalContext env;
3913   v8::Isolate* iso = env->GetIsolate();
3914   HandleScope scope(iso);
3915
3916   WeakCallCounter counter(1234);
3917
3918   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3919   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3920   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3921   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3922   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3923   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3924
3925   {
3926     HandleScope scope(iso);
3927     g1s1.handle.Reset(iso, Object::New(iso));
3928     g1s2.handle.Reset(iso, Object::New(iso));
3929     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3930     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3931
3932     g2s1.handle.Reset(iso, Object::New(iso));
3933     g2s2.handle.Reset(iso, Object::New(iso));
3934     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3935     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3936
3937     g3s1.handle.Reset(iso, Object::New(iso));
3938     g3s2.handle.Reset(iso, Object::New(iso));
3939     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3940     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3941   }
3942
3943   // Make a root.
3944   WeakCallCounterAndPersistent<Value> root(&counter);
3945   root.handle.Reset(iso, g1s1.handle);
3946   root.handle.MarkPartiallyDependent();
3947
3948   // Connect groups.  We're building the following cycle:
3949   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3950   // groups.
3951   {
3952     HandleScope handle_scope(iso);
3953     g1s1.handle.MarkPartiallyDependent();
3954     g1s2.handle.MarkPartiallyDependent();
3955     g2s1.handle.MarkPartiallyDependent();
3956     g2s2.handle.MarkPartiallyDependent();
3957     g3s1.handle.MarkPartiallyDependent();
3958     g3s2.handle.MarkPartiallyDependent();
3959     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3960     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3961     Local<Object>::New(iso, g1s1.handle.As<Object>())
3962         ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3963     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3964     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3965     Local<Object>::New(iso, g2s1.handle.As<Object>())
3966         ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3967     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3968     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3969     Local<Object>::New(iso, g3s1.handle.As<Object>())
3970         ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3971   }
3972
3973   v8::internal::Heap* heap =
3974       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3975   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
3976
3977   // All objects should be alive.
3978   CHECK_EQ(0, counter.NumberOfWeakCalls());
3979
3980   // Weaken the root.
3981   root.handle.SetWeak(&root, &WeakPointerCallback);
3982   root.handle.MarkPartiallyDependent();
3983
3984   // Groups are deleted, rebuild groups.
3985   {
3986     HandleScope handle_scope(iso);
3987     g1s1.handle.MarkPartiallyDependent();
3988     g1s2.handle.MarkPartiallyDependent();
3989     g2s1.handle.MarkPartiallyDependent();
3990     g2s2.handle.MarkPartiallyDependent();
3991     g3s1.handle.MarkPartiallyDependent();
3992     g3s2.handle.MarkPartiallyDependent();
3993     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3994     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3995     Local<Object>::New(iso, g1s1.handle.As<Object>())
3996         ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3997     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3998     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3999     Local<Object>::New(iso, g2s1.handle.As<Object>())
4000         ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4001     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4002     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4003     Local<Object>::New(iso, g3s1.handle.As<Object>())
4004         ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4005   }
4006
4007   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4008
4009   // All objects should be gone. 7 global handles in total.
4010   CHECK_EQ(7, counter.NumberOfWeakCalls());
4011 }
4012
4013
4014 THREADED_TEST(ScriptException) {
4015   LocalContext env;
4016   v8::HandleScope scope(env->GetIsolate());
4017   Local<Script> script = v8_compile("throw 'panama!';");
4018   v8::TryCatch try_catch;
4019   Local<Value> result = script->Run();
4020   CHECK(result.IsEmpty());
4021   CHECK(try_catch.HasCaught());
4022   String::Utf8Value exception_value(try_catch.Exception());
4023   CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4024 }
4025
4026
4027 TEST(TryCatchCustomException) {
4028   LocalContext env;
4029   v8::Isolate* isolate = env->GetIsolate();
4030   v8::HandleScope scope(isolate);
4031   v8::TryCatch try_catch;
4032   CompileRun(
4033       "function CustomError() { this.a = 'b'; }"
4034       "(function f() { throw new CustomError(); })();");
4035   CHECK(try_catch.HasCaught());
4036   CHECK(try_catch.Exception()
4037             ->ToObject(isolate)
4038             ->Get(v8_str("a"))
4039             ->Equals(v8_str("b")));
4040 }
4041
4042
4043 bool message_received;
4044
4045
4046 static void check_message_0(v8::Handle<v8::Message> message,
4047                             v8::Handle<Value> data) {
4048   CHECK_EQ(5.76, data->NumberValue());
4049   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4050   CHECK(!message->IsSharedCrossOrigin());
4051   message_received = true;
4052 }
4053
4054
4055 THREADED_TEST(MessageHandler0) {
4056   message_received = false;
4057   v8::HandleScope scope(CcTest::isolate());
4058   CHECK(!message_received);
4059   LocalContext context;
4060   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4061   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4062   script->Run();
4063   CHECK(message_received);
4064   // clear out the message listener
4065   v8::V8::RemoveMessageListeners(check_message_0);
4066 }
4067
4068
4069 static void check_message_1(v8::Handle<v8::Message> message,
4070                             v8::Handle<Value> data) {
4071   CHECK(data->IsNumber());
4072   CHECK_EQ(1337, data->Int32Value());
4073   CHECK(!message->IsSharedCrossOrigin());
4074   message_received = true;
4075 }
4076
4077
4078 TEST(MessageHandler1) {
4079   message_received = false;
4080   v8::HandleScope scope(CcTest::isolate());
4081   CHECK(!message_received);
4082   v8::V8::AddMessageListener(check_message_1);
4083   LocalContext context;
4084   CompileRun("throw 1337;");
4085   CHECK(message_received);
4086   // clear out the message listener
4087   v8::V8::RemoveMessageListeners(check_message_1);
4088 }
4089
4090
4091 static void check_message_2(v8::Handle<v8::Message> message,
4092                             v8::Handle<Value> data) {
4093   LocalContext context;
4094   CHECK(data->IsObject());
4095   v8::Local<v8::Value> hidden_property =
4096       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4097   CHECK(v8_str("hidden value")->Equals(hidden_property));
4098   CHECK(!message->IsSharedCrossOrigin());
4099   message_received = true;
4100 }
4101
4102
4103 TEST(MessageHandler2) {
4104   message_received = false;
4105   v8::HandleScope scope(CcTest::isolate());
4106   CHECK(!message_received);
4107   v8::V8::AddMessageListener(check_message_2);
4108   LocalContext context;
4109   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4110   v8::Object::Cast(*error)
4111       ->SetHiddenValue(v8_str("hidden key"), v8_str("hidden value"));
4112   context->Global()->Set(v8_str("error"), error);
4113   CompileRun("throw error;");
4114   CHECK(message_received);
4115   // clear out the message listener
4116   v8::V8::RemoveMessageListeners(check_message_2);
4117 }
4118
4119
4120 static void check_message_3(v8::Handle<v8::Message> message,
4121                             v8::Handle<Value> data) {
4122   CHECK(message->IsSharedCrossOrigin());
4123   CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value());
4124   CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value());
4125   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4126   CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue());
4127   message_received = true;
4128 }
4129
4130
4131 TEST(MessageHandler3) {
4132   message_received = false;
4133   v8::Isolate* isolate = CcTest::isolate();
4134   v8::HandleScope scope(isolate);
4135   CHECK(!message_received);
4136   v8::V8::AddMessageListener(check_message_3);
4137   LocalContext context;
4138   v8::ScriptOrigin origin = v8::ScriptOrigin(
4139       v8_str("6.75"), v8::Integer::New(isolate, 1),
4140       v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(),
4141       v8::True(isolate), v8_str("7.40"));
4142   v8::Handle<v8::Script> script =
4143       Script::Compile(v8_str("throw 'error'"), &origin);
4144   script->Run();
4145   CHECK(message_received);
4146   // clear out the message listener
4147   v8::V8::RemoveMessageListeners(check_message_3);
4148 }
4149
4150
4151 static void check_message_4(v8::Handle<v8::Message> message,
4152                             v8::Handle<Value> data) {
4153   CHECK(!message->IsSharedCrossOrigin());
4154   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4155   message_received = true;
4156 }
4157
4158
4159 TEST(MessageHandler4) {
4160   message_received = false;
4161   v8::Isolate* isolate = CcTest::isolate();
4162   v8::HandleScope scope(isolate);
4163   CHECK(!message_received);
4164   v8::V8::AddMessageListener(check_message_4);
4165   LocalContext context;
4166   v8::ScriptOrigin origin =
4167       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4168                        v8::Integer::New(isolate, 2), v8::False(isolate));
4169   v8::Handle<v8::Script> script =
4170       Script::Compile(v8_str("throw 'error'"), &origin);
4171   script->Run();
4172   CHECK(message_received);
4173   // clear out the message listener
4174   v8::V8::RemoveMessageListeners(check_message_4);
4175 }
4176
4177
4178 static void check_message_5a(v8::Handle<v8::Message> message,
4179                              v8::Handle<Value> data) {
4180   CHECK(message->IsSharedCrossOrigin());
4181   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4182   message_received = true;
4183 }
4184
4185
4186 static void check_message_5b(v8::Handle<v8::Message> message,
4187                              v8::Handle<Value> data) {
4188   CHECK(!message->IsSharedCrossOrigin());
4189   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4190   message_received = true;
4191 }
4192
4193
4194 TEST(MessageHandler5) {
4195   message_received = false;
4196   v8::Isolate* isolate = CcTest::isolate();
4197   v8::HandleScope scope(isolate);
4198   CHECK(!message_received);
4199   v8::V8::AddMessageListener(check_message_5a);
4200   LocalContext context;
4201   v8::ScriptOrigin origin =
4202       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4203                        v8::Integer::New(isolate, 2), v8::True(isolate));
4204   v8::Handle<v8::Script> script =
4205       Script::Compile(v8_str("throw 'error'"), &origin);
4206   script->Run();
4207   CHECK(message_received);
4208   // clear out the message listener
4209   v8::V8::RemoveMessageListeners(check_message_5a);
4210
4211   message_received = false;
4212   v8::V8::AddMessageListener(check_message_5b);
4213   origin = v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4214                             v8::Integer::New(isolate, 2), v8::False(isolate));
4215   script = Script::Compile(v8_str("throw 'error'"), &origin);
4216   script->Run();
4217   CHECK(message_received);
4218   // clear out the message listener
4219   v8::V8::RemoveMessageListeners(check_message_5b);
4220 }
4221
4222
4223 TEST(NativeWeakMap) {
4224   v8::Isolate* isolate = CcTest::isolate();
4225   HandleScope scope(isolate);
4226   Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
4227   CHECK(!weak_map.IsEmpty());
4228
4229   LocalContext env;
4230   Local<Object> value = v8::Object::New(isolate);
4231
4232   Local<Object> local1 = v8::Object::New(isolate);
4233   CHECK(!weak_map->Has(local1));
4234   CHECK(weak_map->Get(local1)->IsUndefined());
4235   weak_map->Set(local1, value);
4236   CHECK(weak_map->Has(local1));
4237   CHECK(value->Equals(weak_map->Get(local1)));
4238
4239   WeakCallCounter counter(1234);
4240   WeakCallCounterAndPersistent<Value> o1(&counter);
4241   WeakCallCounterAndPersistent<Value> o2(&counter);
4242   WeakCallCounterAndPersistent<Value> s1(&counter);
4243   {
4244     HandleScope scope(isolate);
4245     Local<v8::Object> obj1 = v8::Object::New(isolate);
4246     Local<v8::Object> obj2 = v8::Object::New(isolate);
4247     Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
4248
4249     weak_map->Set(obj1, value);
4250     weak_map->Set(obj2, value);
4251     weak_map->Set(sym1, value);
4252
4253     o1.handle.Reset(isolate, obj1);
4254     o2.handle.Reset(isolate, obj2);
4255     s1.handle.Reset(isolate, sym1);
4256
4257     CHECK(weak_map->Has(local1));
4258     CHECK(weak_map->Has(obj1));
4259     CHECK(weak_map->Has(obj2));
4260     CHECK(weak_map->Has(sym1));
4261
4262     CHECK(value->Equals(weak_map->Get(local1)));
4263     CHECK(value->Equals(weak_map->Get(obj1)));
4264     CHECK(value->Equals(weak_map->Get(obj2)));
4265     CHECK(value->Equals(weak_map->Get(sym1)));
4266   }
4267   CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
4268   {
4269     HandleScope scope(isolate);
4270     CHECK(value->Equals(weak_map->Get(local1)));
4271     CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o1.handle))));
4272     CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o2.handle))));
4273     CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, s1.handle))));
4274   }
4275
4276   o1.handle.SetWeak(&o1, &WeakPointerCallback);
4277   o2.handle.SetWeak(&o2, &WeakPointerCallback);
4278   s1.handle.SetWeak(&s1, &WeakPointerCallback);
4279
4280   CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
4281   CHECK_EQ(3, counter.NumberOfWeakCalls());
4282
4283   CHECK(o1.handle.IsEmpty());
4284   CHECK(o2.handle.IsEmpty());
4285   CHECK(s1.handle.IsEmpty());
4286
4287   CHECK(value->Equals(weak_map->Get(local1)));
4288   CHECK(weak_map->Delete(local1));
4289   CHECK(!weak_map->Has(local1));
4290   CHECK(weak_map->Get(local1)->IsUndefined());
4291 }
4292
4293
4294 THREADED_TEST(GetSetProperty) {
4295   LocalContext context;
4296   v8::Isolate* isolate = context->GetIsolate();
4297   v8::HandleScope scope(isolate);
4298   context->Global()->Set(v8_str("foo"), v8_num(14));
4299   context->Global()->Set(v8_str("12"), v8_num(92));
4300   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4301   context->Global()->Set(v8_num(13), v8_num(56));
4302   Local<Value> foo = CompileRun("this.foo");
4303   CHECK_EQ(14, foo->Int32Value());
4304   Local<Value> twelve = CompileRun("this[12]");
4305   CHECK_EQ(92, twelve->Int32Value());
4306   Local<Value> sixteen = CompileRun("this[16]");
4307   CHECK_EQ(32, sixteen->Int32Value());
4308   Local<Value> thirteen = CompileRun("this[13]");
4309   CHECK_EQ(56, thirteen->Int32Value());
4310   CHECK_EQ(92,
4311            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4312   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4313   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4314   CHECK_EQ(32,
4315            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4316   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4317   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4318   CHECK_EQ(56,
4319            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4320   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4321   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4322 }
4323
4324
4325 THREADED_TEST(PropertyAttributes) {
4326   LocalContext context;
4327   v8::HandleScope scope(context->GetIsolate());
4328   // none
4329   Local<String> prop = v8_str("none");
4330   context->Global()->Set(prop, v8_num(7));
4331   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4332   // read-only
4333   prop = v8_str("read_only");
4334   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4335   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4336   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4337   CompileRun("read_only = 9");
4338   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4339   context->Global()->Set(prop, v8_num(10));
4340   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4341   // dont-delete
4342   prop = v8_str("dont_delete");
4343   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4344   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4345   CompileRun("delete dont_delete");
4346   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4347   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4348   // dont-enum
4349   prop = v8_str("dont_enum");
4350   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4351   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4352   // absent
4353   prop = v8_str("absent");
4354   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4355   Local<Value> fake_prop = v8_num(1);
4356   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4357   // exception
4358   TryCatch try_catch;
4359   Local<Value> exception =
4360       CompileRun("({ toString: function() { throw 'exception';} })");
4361   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4362   CHECK(try_catch.HasCaught());
4363   String::Utf8Value exception_value(try_catch.Exception());
4364   CHECK_EQ(0, strcmp("exception", *exception_value));
4365   try_catch.Reset();
4366 }
4367
4368
4369 THREADED_TEST(Array) {
4370   LocalContext context;
4371   v8::HandleScope scope(context->GetIsolate());
4372   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4373   CHECK_EQ(0u, array->Length());
4374   CHECK(array->Get(0)->IsUndefined());
4375   CHECK(!array->Has(0));
4376   CHECK(array->Get(100)->IsUndefined());
4377   CHECK(!array->Has(100));
4378   array->Set(2, v8_num(7));
4379   CHECK_EQ(3u, array->Length());
4380   CHECK(!array->Has(0));
4381   CHECK(!array->Has(1));
4382   CHECK(array->Has(2));
4383   CHECK_EQ(7, array->Get(2)->Int32Value());
4384   Local<Value> obj = CompileRun("[1, 2, 3]");
4385   Local<v8::Array> arr = obj.As<v8::Array>();
4386   CHECK_EQ(3u, arr->Length());
4387   CHECK_EQ(1, arr->Get(0)->Int32Value());
4388   CHECK_EQ(2, arr->Get(1)->Int32Value());
4389   CHECK_EQ(3, arr->Get(2)->Int32Value());
4390   array = v8::Array::New(context->GetIsolate(), 27);
4391   CHECK_EQ(27u, array->Length());
4392   array = v8::Array::New(context->GetIsolate(), -27);
4393   CHECK_EQ(0u, array->Length());
4394 }
4395
4396
4397 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4398   v8::EscapableHandleScope scope(args.GetIsolate());
4399   ApiTestFuzzer::Fuzz();
4400   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4401   for (int i = 0; i < args.Length(); i++) result->Set(i, args[i]);
4402   args.GetReturnValue().Set(scope.Escape(result));
4403 }
4404
4405
4406 THREADED_TEST(Vector) {
4407   v8::Isolate* isolate = CcTest::isolate();
4408   v8::HandleScope scope(isolate);
4409   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4410   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4411   LocalContext context(0, global);
4412
4413   const char* fun = "f()";
4414   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4415   CHECK_EQ(0u, a0->Length());
4416
4417   const char* fun2 = "f(11)";
4418   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4419   CHECK_EQ(1u, a1->Length());
4420   CHECK_EQ(11, a1->Get(0)->Int32Value());
4421
4422   const char* fun3 = "f(12, 13)";
4423   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4424   CHECK_EQ(2u, a2->Length());
4425   CHECK_EQ(12, a2->Get(0)->Int32Value());
4426   CHECK_EQ(13, a2->Get(1)->Int32Value());
4427
4428   const char* fun4 = "f(14, 15, 16)";
4429   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4430   CHECK_EQ(3u, a3->Length());
4431   CHECK_EQ(14, a3->Get(0)->Int32Value());
4432   CHECK_EQ(15, a3->Get(1)->Int32Value());
4433   CHECK_EQ(16, a3->Get(2)->Int32Value());
4434
4435   const char* fun5 = "f(17, 18, 19, 20)";
4436   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4437   CHECK_EQ(4u, a4->Length());
4438   CHECK_EQ(17, a4->Get(0)->Int32Value());
4439   CHECK_EQ(18, a4->Get(1)->Int32Value());
4440   CHECK_EQ(19, a4->Get(2)->Int32Value());
4441   CHECK_EQ(20, a4->Get(3)->Int32Value());
4442 }
4443
4444
4445 THREADED_TEST(FunctionCall) {
4446   LocalContext context;
4447   v8::Isolate* isolate = context->GetIsolate();
4448   v8::HandleScope scope(isolate);
4449   CompileRun(
4450       "function Foo() {"
4451       "  var result = [];"
4452       "  for (var i = 0; i < arguments.length; i++) {"
4453       "    result.push(arguments[i]);"
4454       "  }"
4455       "  return result;"
4456       "}"
4457       "function ReturnThisSloppy() {"
4458       "  return this;"
4459       "}"
4460       "function ReturnThisStrict() {"
4461       "  'use strict';"
4462       "  return this;"
4463       "}");
4464   Local<Function> Foo =
4465       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4466   Local<Function> ReturnThisSloppy =
4467       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4468   Local<Function> ReturnThisStrict =
4469       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4470
4471   v8::Handle<Value>* args0 = NULL;
4472   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4473   CHECK_EQ(0u, a0->Length());
4474
4475   v8::Handle<Value> args1[] = {v8_num(1.1)};
4476   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4477   CHECK_EQ(1u, a1->Length());
4478   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4479
4480   v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4481   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4482   CHECK_EQ(2u, a2->Length());
4483   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4484   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4485
4486   v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4487   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4488   CHECK_EQ(3u, a3->Length());
4489   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4490   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4491   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4492
4493   v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4494                                v8_num(10.11)};
4495   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4496   CHECK_EQ(4u, a4->Length());
4497   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4498   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4499   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4500   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4501
4502   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4503   CHECK(r1->StrictEquals(context->Global()));
4504   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4505   CHECK(r2->StrictEquals(context->Global()));
4506   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4507   CHECK(r3->IsNumberObject());
4508   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4509   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4510   CHECK(r4->IsStringObject());
4511   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4512   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4513   CHECK(r5->IsBooleanObject());
4514   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4515
4516   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4517   CHECK(r6->IsUndefined());
4518   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4519   CHECK(r7->IsNull());
4520   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4521   CHECK(r8->StrictEquals(v8_num(42)));
4522   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4523   CHECK(r9->StrictEquals(v8_str("hello")));
4524   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4525   CHECK(r10->StrictEquals(v8::True(isolate)));
4526 }
4527
4528
4529 THREADED_TEST(ConstructCall) {
4530   LocalContext context;
4531   v8::Isolate* isolate = context->GetIsolate();
4532   v8::HandleScope scope(isolate);
4533   CompileRun(
4534       "function Foo() {"
4535       "  var result = [];"
4536       "  for (var i = 0; i < arguments.length; i++) {"
4537       "    result.push(arguments[i]);"
4538       "  }"
4539       "  return result;"
4540       "}");
4541   Local<Function> Foo =
4542       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4543
4544   v8::Handle<Value>* args0 = NULL;
4545   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4546   CHECK_EQ(0u, a0->Length());
4547
4548   v8::Handle<Value> args1[] = {v8_num(1.1)};
4549   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4550   CHECK_EQ(1u, a1->Length());
4551   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4552
4553   v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4554   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4555   CHECK_EQ(2u, a2->Length());
4556   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4557   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4558
4559   v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4560   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4561   CHECK_EQ(3u, a3->Length());
4562   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4563   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4564   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4565
4566   v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4567                                v8_num(10.11)};
4568   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4569   CHECK_EQ(4u, a4->Length());
4570   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4571   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4572   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4573   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4574 }
4575
4576
4577 static void CheckUncle(v8::TryCatch* try_catch) {
4578   CHECK(try_catch->HasCaught());
4579   String::Utf8Value str_value(try_catch->Exception());
4580   CHECK_EQ(0, strcmp(*str_value, "uncle?"));
4581   try_catch->Reset();
4582 }
4583
4584
4585 THREADED_TEST(ConversionNumber) {
4586   LocalContext env;
4587   v8::Isolate* isolate = env->GetIsolate();
4588   v8::HandleScope scope(isolate);
4589   // Very large number.
4590   CompileRun("var obj = Math.pow(2,32) * 1237;");
4591   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4592   CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
4593   CHECK_EQ(0, obj->ToInt32(isolate)->Value());
4594   CHECK(0u ==
4595         obj->ToUint32(isolate)->Value());  // NOLINT - no CHECK_EQ for unsigned.
4596   // Large number.
4597   CompileRun("var obj = -1234567890123;");
4598   obj = env->Global()->Get(v8_str("obj"));
4599   CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
4600   CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
4601   CHECK(2382691125u == obj->ToUint32(isolate)->Value());  // NOLINT
4602   // Small positive integer.
4603   CompileRun("var obj = 42;");
4604   obj = env->Global()->Get(v8_str("obj"));
4605   CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
4606   CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4607   CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
4608   // Negative integer.
4609   CompileRun("var obj = -37;");
4610   obj = env->Global()->Get(v8_str("obj"));
4611   CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
4612   CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
4613   CHECK(4294967259u == obj->ToUint32(isolate)->Value());  // NOLINT
4614   // Positive non-int32 integer.
4615   CompileRun("var obj = 0x81234567;");
4616   obj = env->Global()->Get(v8_str("obj"));
4617   CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
4618   CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
4619   CHECK(2166572391u == obj->ToUint32(isolate)->Value());  // NOLINT
4620   // Fraction.
4621   CompileRun("var obj = 42.3;");
4622   obj = env->Global()->Get(v8_str("obj"));
4623   CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
4624   CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4625   CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
4626   // Large negative fraction.
4627   CompileRun("var obj = -5726623061.75;");
4628   obj = env->Global()->Get(v8_str("obj"));
4629   CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
4630   CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
4631   CHECK(2863311531u == obj->ToUint32(isolate)->Value());  // NOLINT
4632 }
4633
4634
4635 THREADED_TEST(isNumberType) {
4636   LocalContext env;
4637   v8::HandleScope scope(env->GetIsolate());
4638   // Very large number.
4639   CompileRun("var obj = Math.pow(2,32) * 1237;");
4640   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4641   CHECK(!obj->IsInt32());
4642   CHECK(!obj->IsUint32());
4643   // Large negative number.
4644   CompileRun("var obj = -1234567890123;");
4645   obj = env->Global()->Get(v8_str("obj"));
4646   CHECK(!obj->IsInt32());
4647   CHECK(!obj->IsUint32());
4648   // Small positive integer.
4649   CompileRun("var obj = 42;");
4650   obj = env->Global()->Get(v8_str("obj"));
4651   CHECK(obj->IsInt32());
4652   CHECK(obj->IsUint32());
4653   // Negative integer.
4654   CompileRun("var obj = -37;");
4655   obj = env->Global()->Get(v8_str("obj"));
4656   CHECK(obj->IsInt32());
4657   CHECK(!obj->IsUint32());
4658   // Positive non-int32 integer.
4659   CompileRun("var obj = 0x81234567;");
4660   obj = env->Global()->Get(v8_str("obj"));
4661   CHECK(!obj->IsInt32());
4662   CHECK(obj->IsUint32());
4663   // Fraction.
4664   CompileRun("var obj = 42.3;");
4665   obj = env->Global()->Get(v8_str("obj"));
4666   CHECK(!obj->IsInt32());
4667   CHECK(!obj->IsUint32());
4668   // Large negative fraction.
4669   CompileRun("var obj = -5726623061.75;");
4670   obj = env->Global()->Get(v8_str("obj"));
4671   CHECK(!obj->IsInt32());
4672   CHECK(!obj->IsUint32());
4673   // Positive zero
4674   CompileRun("var obj = 0.0;");
4675   obj = env->Global()->Get(v8_str("obj"));
4676   CHECK(obj->IsInt32());
4677   CHECK(obj->IsUint32());
4678   // Positive zero
4679   CompileRun("var obj = -0.0;");
4680   obj = env->Global()->Get(v8_str("obj"));
4681   CHECK(!obj->IsInt32());
4682   CHECK(!obj->IsUint32());
4683 }
4684
4685
4686 THREADED_TEST(ConversionException) {
4687   LocalContext env;
4688   v8::Isolate* isolate = env->GetIsolate();
4689   v8::HandleScope scope(isolate);
4690   CompileRun(
4691       "function TestClass() { };"
4692       "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4693       "var obj = new TestClass();");
4694   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4695
4696   v8::TryCatch try_catch(isolate);
4697
4698   Local<Value> to_string_result = obj->ToString(isolate);
4699   CHECK(to_string_result.IsEmpty());
4700   CheckUncle(&try_catch);
4701
4702   Local<Value> to_number_result = obj->ToNumber(isolate);
4703   CHECK(to_number_result.IsEmpty());
4704   CheckUncle(&try_catch);
4705
4706   Local<Value> to_integer_result = obj->ToInteger(isolate);
4707   CHECK(to_integer_result.IsEmpty());
4708   CheckUncle(&try_catch);
4709
4710   Local<Value> to_uint32_result = obj->ToUint32(isolate);
4711   CHECK(to_uint32_result.IsEmpty());
4712   CheckUncle(&try_catch);
4713
4714   Local<Value> to_int32_result = obj->ToInt32(isolate);
4715   CHECK(to_int32_result.IsEmpty());
4716   CheckUncle(&try_catch);
4717
4718   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
4719   CHECK(to_object_result.IsEmpty());
4720   CHECK(try_catch.HasCaught());
4721   try_catch.Reset();
4722
4723   int32_t int32_value = obj->Int32Value();
4724   CHECK_EQ(0, int32_value);
4725   CheckUncle(&try_catch);
4726
4727   uint32_t uint32_value = obj->Uint32Value();
4728   CHECK_EQ(0u, uint32_value);
4729   CheckUncle(&try_catch);
4730
4731   double number_value = obj->NumberValue();
4732   CHECK(std::isnan(number_value));
4733   CheckUncle(&try_catch);
4734
4735   int64_t integer_value = obj->IntegerValue();
4736   CHECK_EQ(0, integer_value);
4737   CheckUncle(&try_catch);
4738 }
4739
4740
4741 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4742   ApiTestFuzzer::Fuzz();
4743   args.GetIsolate()->ThrowException(v8_str("konto"));
4744 }
4745
4746
4747 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4748   if (args.Length() < 1) {
4749     args.GetReturnValue().Set(false);
4750     return;
4751   }
4752   v8::HandleScope scope(args.GetIsolate());
4753   v8::TryCatch try_catch;
4754   Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
4755   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4756   args.GetReturnValue().Set(try_catch.HasCaught());
4757 }
4758
4759
4760 THREADED_TEST(APICatch) {
4761   v8::Isolate* isolate = CcTest::isolate();
4762   v8::HandleScope scope(isolate);
4763   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4764   templ->Set(v8_str("ThrowFromC"),
4765              v8::FunctionTemplate::New(isolate, ThrowFromC));
4766   LocalContext context(0, templ);
4767   CompileRun(
4768       "var thrown = false;"
4769       "try {"
4770       "  ThrowFromC();"
4771       "} catch (e) {"
4772       "  thrown = true;"
4773       "}");
4774   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4775   CHECK(thrown->BooleanValue());
4776 }
4777
4778
4779 THREADED_TEST(APIThrowTryCatch) {
4780   v8::Isolate* isolate = CcTest::isolate();
4781   v8::HandleScope scope(isolate);
4782   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4783   templ->Set(v8_str("ThrowFromC"),
4784              v8::FunctionTemplate::New(isolate, ThrowFromC));
4785   LocalContext context(0, templ);
4786   v8::TryCatch try_catch;
4787   CompileRun("ThrowFromC();");
4788   CHECK(try_catch.HasCaught());
4789 }
4790
4791
4792 // Test that a try-finally block doesn't shadow a try-catch block
4793 // when setting up an external handler.
4794 //
4795 // BUG(271): Some of the exception propagation does not work on the
4796 // ARM simulator because the simulator separates the C++ stack and the
4797 // JS stack.  This test therefore fails on the simulator.  The test is
4798 // not threaded to allow the threading tests to run on the simulator.
4799 TEST(TryCatchInTryFinally) {
4800   v8::Isolate* isolate = CcTest::isolate();
4801   v8::HandleScope scope(isolate);
4802   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4803   templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
4804   LocalContext context(0, templ);
4805   Local<Value> result = CompileRun(
4806       "try {"
4807       "  try {"
4808       "    CCatcher('throw 7;');"
4809       "  } finally {"
4810       "  }"
4811       "} catch (e) {"
4812       "}");
4813   CHECK(result->IsTrue());
4814 }
4815
4816
4817 static void check_reference_error_message(v8::Handle<v8::Message> message,
4818                                           v8::Handle<v8::Value> data) {
4819   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4820   CHECK(message->Get()->Equals(v8_str(reference_error)));
4821 }
4822
4823
4824 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4825   ApiTestFuzzer::Fuzz();
4826   CHECK(false);
4827 }
4828
4829
4830 // Test that overwritten methods are not invoked on uncaught exception
4831 // formatting. However, they are invoked when performing normal error
4832 // string conversions.
4833 TEST(APIThrowMessageOverwrittenToString) {
4834   v8::Isolate* isolate = CcTest::isolate();
4835   v8::HandleScope scope(isolate);
4836   v8::V8::AddMessageListener(check_reference_error_message);
4837   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4838   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4839   LocalContext context(NULL, templ);
4840   CompileRun("asdf;");
4841   CompileRun(
4842       "var limit = {};"
4843       "limit.valueOf = fail;"
4844       "Error.stackTraceLimit = limit;");
4845   CompileRun("asdf");
4846   CompileRun("Array.prototype.pop = fail;");
4847   CompileRun("Object.prototype.hasOwnProperty = fail;");
4848   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4849   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4850   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4851   CompileRun(
4852       "ReferenceError.prototype.toString ="
4853       "  function() { return 'Whoops' }");
4854   CompileRun("asdf;");
4855   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4856   CompileRun("asdf;");
4857   CompileRun("ReferenceError.prototype.constructor = void 0;");
4858   CompileRun("asdf;");
4859   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4860   CompileRun("asdf;");
4861   CompileRun("ReferenceError.prototype = new Object();");
4862   CompileRun("asdf;");
4863   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4864   CHECK(string->Equals(v8_str("Whoops")));
4865   CompileRun(
4866       "ReferenceError.prototype.constructor = new Object();"
4867       "ReferenceError.prototype.constructor.name = 1;"
4868       "Number.prototype.toString = function() { return 'Whoops'; };"
4869       "ReferenceError.prototype.toString = Object.prototype.toString;");
4870   CompileRun("asdf;");
4871   v8::V8::RemoveMessageListeners(check_reference_error_message);
4872 }
4873
4874
4875 static void check_custom_error_tostring(v8::Handle<v8::Message> message,
4876                                         v8::Handle<v8::Value> data) {
4877   const char* uncaught_error = "Uncaught MyError toString";
4878   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4879 }
4880
4881
4882 TEST(CustomErrorToString) {
4883   LocalContext context;
4884   v8::HandleScope scope(context->GetIsolate());
4885   v8::V8::AddMessageListener(check_custom_error_tostring);
4886   CompileRun(
4887       "function MyError(name, message) {                   "
4888       "  this.name = name;                                 "
4889       "  this.message = message;                           "
4890       "}                                                   "
4891       "MyError.prototype = Object.create(Error.prototype); "
4892       "MyError.prototype.toString = function() {           "
4893       "  return 'MyError toString';                        "
4894       "};                                                  "
4895       "throw new MyError('my name', 'my message');         ");
4896   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4897 }
4898
4899
4900 static void check_custom_error_message(v8::Handle<v8::Message> message,
4901                                        v8::Handle<v8::Value> data) {
4902   const char* uncaught_error = "Uncaught MyError: my message";
4903   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4904   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4905 }
4906
4907
4908 TEST(CustomErrorMessage) {
4909   LocalContext context;
4910   v8::HandleScope scope(context->GetIsolate());
4911   v8::V8::AddMessageListener(check_custom_error_message);
4912
4913   // Handlebars.
4914   CompileRun(
4915       "function MyError(msg) {                             "
4916       "  this.name = 'MyError';                            "
4917       "  this.message = msg;                               "
4918       "}                                                   "
4919       "MyError.prototype = new Error();                    "
4920       "throw new MyError('my message');                    ");
4921
4922   // Closure.
4923   CompileRun(
4924       "function MyError(msg) {                             "
4925       "  this.name = 'MyError';                            "
4926       "  this.message = msg;                               "
4927       "}                                                   "
4928       "inherits = function(childCtor, parentCtor) {        "
4929       "    function tempCtor() {};                         "
4930       "    tempCtor.prototype = parentCtor.prototype;      "
4931       "    childCtor.superClass_ = parentCtor.prototype;   "
4932       "    childCtor.prototype = new tempCtor();           "
4933       "    childCtor.prototype.constructor = childCtor;    "
4934       "};                                                  "
4935       "inherits(MyError, Error);                           "
4936       "throw new MyError('my message');                    ");
4937
4938   // Object.create.
4939   CompileRun(
4940       "function MyError(msg) {                             "
4941       "  this.name = 'MyError';                            "
4942       "  this.message = msg;                               "
4943       "}                                                   "
4944       "MyError.prototype = Object.create(Error.prototype); "
4945       "throw new MyError('my message');                    ");
4946
4947   v8::V8::RemoveMessageListeners(check_custom_error_message);
4948 }
4949
4950
4951 static void receive_message(v8::Handle<v8::Message> message,
4952                             v8::Handle<v8::Value> data) {
4953   message->Get();
4954   message_received = true;
4955 }
4956
4957
4958 TEST(APIThrowMessage) {
4959   message_received = false;
4960   v8::Isolate* isolate = CcTest::isolate();
4961   v8::HandleScope scope(isolate);
4962   v8::V8::AddMessageListener(receive_message);
4963   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4964   templ->Set(v8_str("ThrowFromC"),
4965              v8::FunctionTemplate::New(isolate, ThrowFromC));
4966   LocalContext context(0, templ);
4967   CompileRun("ThrowFromC();");
4968   CHECK(message_received);
4969   v8::V8::RemoveMessageListeners(receive_message);
4970 }
4971
4972
4973 TEST(APIThrowMessageAndVerboseTryCatch) {
4974   message_received = false;
4975   v8::Isolate* isolate = CcTest::isolate();
4976   v8::HandleScope scope(isolate);
4977   v8::V8::AddMessageListener(receive_message);
4978   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4979   templ->Set(v8_str("ThrowFromC"),
4980              v8::FunctionTemplate::New(isolate, ThrowFromC));
4981   LocalContext context(0, templ);
4982   v8::TryCatch try_catch;
4983   try_catch.SetVerbose(true);
4984   Local<Value> result = CompileRun("ThrowFromC();");
4985   CHECK(try_catch.HasCaught());
4986   CHECK(result.IsEmpty());
4987   CHECK(message_received);
4988   v8::V8::RemoveMessageListeners(receive_message);
4989 }
4990
4991
4992 TEST(APIStackOverflowAndVerboseTryCatch) {
4993   message_received = false;
4994   LocalContext context;
4995   v8::HandleScope scope(context->GetIsolate());
4996   v8::V8::AddMessageListener(receive_message);
4997   v8::TryCatch try_catch;
4998   try_catch.SetVerbose(true);
4999   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5000   CHECK(try_catch.HasCaught());
5001   CHECK(result.IsEmpty());
5002   CHECK(message_received);
5003   v8::V8::RemoveMessageListeners(receive_message);
5004 }
5005
5006
5007 THREADED_TEST(ExternalScriptException) {
5008   v8::Isolate* isolate = CcTest::isolate();
5009   v8::HandleScope scope(isolate);
5010   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5011   templ->Set(v8_str("ThrowFromC"),
5012              v8::FunctionTemplate::New(isolate, ThrowFromC));
5013   LocalContext context(0, templ);
5014
5015   v8::TryCatch try_catch;
5016   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5017   CHECK(result.IsEmpty());
5018   CHECK(try_catch.HasCaught());
5019   String::Utf8Value exception_value(try_catch.Exception());
5020   CHECK_EQ(0, strcmp("konto", *exception_value));
5021 }
5022
5023
5024 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5025   ApiTestFuzzer::Fuzz();
5026   CHECK_EQ(4, args.Length());
5027   int count = args[0]->Int32Value();
5028   int cInterval = args[2]->Int32Value();
5029   if (count == 0) {
5030     args.GetIsolate()->ThrowException(v8_str("FromC"));
5031     return;
5032   } else {
5033     Local<v8::Object> global = args.GetIsolate()->GetCurrentContext()->Global();
5034     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5035     v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
5036     if (count % cInterval == 0) {
5037       v8::TryCatch try_catch;
5038       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5039       int expected = args[3]->Int32Value();
5040       if (try_catch.HasCaught()) {
5041         CHECK_EQ(expected, count);
5042         CHECK(result.IsEmpty());
5043         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5044       } else {
5045         CHECK_NE(expected, count);
5046       }
5047       args.GetReturnValue().Set(result);
5048       return;
5049     } else {
5050       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5051       return;
5052     }
5053   }
5054 }
5055
5056
5057 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5058   ApiTestFuzzer::Fuzz();
5059   CHECK_EQ(3, args.Length());
5060   bool equality = args[0]->BooleanValue();
5061   int count = args[1]->Int32Value();
5062   int expected = args[2]->Int32Value();
5063   if (equality) {
5064     CHECK_EQ(count, expected);
5065   } else {
5066     CHECK_NE(count, expected);
5067   }
5068 }
5069
5070
5071 THREADED_TEST(EvalInTryFinally) {
5072   LocalContext context;
5073   v8::HandleScope scope(context->GetIsolate());
5074   v8::TryCatch try_catch;
5075   CompileRun(
5076       "(function() {"
5077       "  try {"
5078       "    eval('asldkf (*&^&*^');"
5079       "  } finally {"
5080       "    return;"
5081       "  }"
5082       "})()");
5083   CHECK(!try_catch.HasCaught());
5084 }
5085
5086
5087 // This test works by making a stack of alternating JavaScript and C
5088 // activations.  These activations set up exception handlers with regular
5089 // intervals, one interval for C activations and another for JavaScript
5090 // activations.  When enough activations have been created an exception is
5091 // thrown and we check that the right activation catches the exception and that
5092 // no other activations do.  The right activation is always the topmost one with
5093 // a handler, regardless of whether it is in JavaScript or C.
5094 //
5095 // The notation used to describe a test case looks like this:
5096 //
5097 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5098 //
5099 // Each entry is an activation, either JS or C.  The index is the count at that
5100 // level.  Stars identify activations with exception handlers, the @ identifies
5101 // the exception handler that should catch the exception.
5102 //
5103 // BUG(271): Some of the exception propagation does not work on the
5104 // ARM simulator because the simulator separates the C++ stack and the
5105 // JS stack.  This test therefore fails on the simulator.  The test is
5106 // not threaded to allow the threading tests to run on the simulator.
5107 TEST(ExceptionOrder) {
5108   v8::Isolate* isolate = CcTest::isolate();
5109   v8::HandleScope scope(isolate);
5110   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5111   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5112   templ->Set(v8_str("CThrowCountDown"),
5113              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5114   LocalContext context(0, templ);
5115   CompileRun(
5116       "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5117       "  if (count == 0) throw 'FromJS';"
5118       "  if (count % jsInterval == 0) {"
5119       "    try {"
5120       "      var value = CThrowCountDown(count - 1,"
5121       "                                  jsInterval,"
5122       "                                  cInterval,"
5123       "                                  expected);"
5124       "      check(false, count, expected);"
5125       "      return value;"
5126       "    } catch (e) {"
5127       "      check(true, count, expected);"
5128       "    }"
5129       "  } else {"
5130       "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5131       "  }"
5132       "}");
5133   Local<Function> fun =
5134       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5135
5136   const int argc = 4;
5137   //                             count      jsInterval cInterval  expected
5138
5139   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5140   v8::Handle<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
5141   fun->Call(fun, argc, a0);
5142
5143   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5144   v8::Handle<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
5145   fun->Call(fun, argc, a1);
5146
5147   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5148   v8::Handle<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
5149   fun->Call(fun, argc, a2);
5150
5151   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5152   v8::Handle<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
5153   fun->Call(fun, argc, a3);
5154
5155   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5156   v8::Handle<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
5157   fun->Call(fun, argc, a4);
5158
5159   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5160   v8::Handle<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
5161   fun->Call(fun, argc, a5);
5162 }
5163
5164
5165 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5166   ApiTestFuzzer::Fuzz();
5167   CHECK_EQ(1, args.Length());
5168   args.GetIsolate()->ThrowException(args[0]);
5169 }
5170
5171
5172 THREADED_TEST(ThrowValues) {
5173   v8::Isolate* isolate = CcTest::isolate();
5174   v8::HandleScope scope(isolate);
5175   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5176   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5177   LocalContext context(0, templ);
5178   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5179       "function Run(obj) {"
5180       "  try {"
5181       "    Throw(obj);"
5182       "  } catch (e) {"
5183       "    return e;"
5184       "  }"
5185       "  return 'no exception';"
5186       "}"
5187       "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5188   CHECK_EQ(5u, result->Length());
5189   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5190   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5191   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5192   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5193   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5194   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5195   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5196 }
5197
5198
5199 THREADED_TEST(CatchZero) {
5200   LocalContext context;
5201   v8::HandleScope scope(context->GetIsolate());
5202   v8::TryCatch try_catch;
5203   CHECK(!try_catch.HasCaught());
5204   CompileRun("throw 10");
5205   CHECK(try_catch.HasCaught());
5206   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5207   try_catch.Reset();
5208   CHECK(!try_catch.HasCaught());
5209   CompileRun("throw 0");
5210   CHECK(try_catch.HasCaught());
5211   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5212 }
5213
5214
5215 THREADED_TEST(CatchExceptionFromWith) {
5216   LocalContext context;
5217   v8::HandleScope scope(context->GetIsolate());
5218   v8::TryCatch try_catch;
5219   CHECK(!try_catch.HasCaught());
5220   CompileRun("var o = {}; with (o) { throw 42; }");
5221   CHECK(try_catch.HasCaught());
5222 }
5223
5224
5225 THREADED_TEST(TryCatchAndFinallyHidingException) {
5226   LocalContext context;
5227   v8::HandleScope scope(context->GetIsolate());
5228   v8::TryCatch try_catch;
5229   CHECK(!try_catch.HasCaught());
5230   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5231   CompileRun("f({toString: function() { throw 42; }});");
5232   CHECK(!try_catch.HasCaught());
5233 }
5234
5235
5236 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5237   v8::TryCatch try_catch;
5238 }
5239
5240
5241 THREADED_TEST(TryCatchAndFinally) {
5242   LocalContext context;
5243   v8::Isolate* isolate = context->GetIsolate();
5244   v8::HandleScope scope(isolate);
5245   context->Global()->Set(
5246       v8_str("native_with_try_catch"),
5247       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5248   v8::TryCatch try_catch;
5249   CHECK(!try_catch.HasCaught());
5250   CompileRun(
5251       "try {\n"
5252       "  throw new Error('a');\n"
5253       "} finally {\n"
5254       "  native_with_try_catch();\n"
5255       "}\n");
5256   CHECK(try_catch.HasCaught());
5257 }
5258
5259
5260 static void TryCatchNested1Helper(int depth) {
5261   if (depth > 0) {
5262     v8::TryCatch try_catch;
5263     try_catch.SetVerbose(true);
5264     TryCatchNested1Helper(depth - 1);
5265     CHECK(try_catch.HasCaught());
5266     try_catch.ReThrow();
5267   } else {
5268     CcTest::isolate()->ThrowException(v8_str("E1"));
5269   }
5270 }
5271
5272
5273 static void TryCatchNested2Helper(int depth) {
5274   if (depth > 0) {
5275     v8::TryCatch try_catch;
5276     try_catch.SetVerbose(true);
5277     TryCatchNested2Helper(depth - 1);
5278     CHECK(try_catch.HasCaught());
5279     try_catch.ReThrow();
5280   } else {
5281     CompileRun("throw 'E2';");
5282   }
5283 }
5284
5285
5286 TEST(TryCatchNested) {
5287   v8::V8::Initialize();
5288   LocalContext context;
5289   v8::HandleScope scope(context->GetIsolate());
5290
5291   {
5292     // Test nested try-catch with a native throw in the end.
5293     v8::TryCatch try_catch;
5294     TryCatchNested1Helper(5);
5295     CHECK(try_catch.HasCaught());
5296     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5297   }
5298
5299   {
5300     // Test nested try-catch with a JavaScript throw in the end.
5301     v8::TryCatch try_catch;
5302     TryCatchNested2Helper(5);
5303     CHECK(try_catch.HasCaught());
5304     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5305   }
5306 }
5307
5308
5309 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5310   CHECK(try_catch->HasCaught());
5311   Handle<Message> message = try_catch->Message();
5312   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5313   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5314   CHECK_EQ(0,
5315            strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
5316   CHECK_EQ(1, message->GetLineNumber());
5317   CHECK_EQ(6, message->GetStartColumn());
5318 }
5319
5320
5321 void TryCatchMixedNestingHelper(
5322     const v8::FunctionCallbackInfo<v8::Value>& args) {
5323   ApiTestFuzzer::Fuzz();
5324   v8::TryCatch try_catch;
5325   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5326   CHECK(try_catch.HasCaught());
5327   TryCatchMixedNestingCheck(&try_catch);
5328   try_catch.ReThrow();
5329 }
5330
5331
5332 // This test ensures that an outer TryCatch in the following situation:
5333 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5334 // does not clobber the Message object generated for the inner TryCatch.
5335 // This exercises the ability of TryCatch.ReThrow() to restore the
5336 // inner pending Message before throwing the exception again.
5337 TEST(TryCatchMixedNesting) {
5338   v8::Isolate* isolate = CcTest::isolate();
5339   v8::HandleScope scope(isolate);
5340   v8::V8::Initialize();
5341   v8::TryCatch try_catch;
5342   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5343   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5344              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5345   LocalContext context(0, templ);
5346   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5347   TryCatchMixedNestingCheck(&try_catch);
5348 }
5349
5350
5351 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5352   ApiTestFuzzer::Fuzz();
5353   v8::TryCatch try_catch;
5354   args.GetIsolate()->ThrowException(v8_str("boom"));
5355   CHECK(try_catch.HasCaught());
5356 }
5357
5358
5359 TEST(TryCatchNative) {
5360   v8::Isolate* isolate = CcTest::isolate();
5361   v8::HandleScope scope(isolate);
5362   v8::V8::Initialize();
5363   v8::TryCatch try_catch;
5364   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5365   templ->Set(v8_str("TryCatchNativeHelper"),
5366              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5367   LocalContext context(0, templ);
5368   CompileRun("TryCatchNativeHelper();");
5369   CHECK(!try_catch.HasCaught());
5370 }
5371
5372
5373 void TryCatchNativeResetHelper(
5374     const v8::FunctionCallbackInfo<v8::Value>& args) {
5375   ApiTestFuzzer::Fuzz();
5376   v8::TryCatch try_catch;
5377   args.GetIsolate()->ThrowException(v8_str("boom"));
5378   CHECK(try_catch.HasCaught());
5379   try_catch.Reset();
5380   CHECK(!try_catch.HasCaught());
5381 }
5382
5383
5384 TEST(TryCatchNativeReset) {
5385   v8::Isolate* isolate = CcTest::isolate();
5386   v8::HandleScope scope(isolate);
5387   v8::V8::Initialize();
5388   v8::TryCatch try_catch;
5389   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5390   templ->Set(v8_str("TryCatchNativeResetHelper"),
5391              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5392   LocalContext context(0, templ);
5393   CompileRun("TryCatchNativeResetHelper();");
5394   CHECK(!try_catch.HasCaught());
5395 }
5396
5397
5398 THREADED_TEST(Equality) {
5399   LocalContext context;
5400   v8::Isolate* isolate = context->GetIsolate();
5401   v8::HandleScope scope(context->GetIsolate());
5402   // Check that equality works at all before relying on CHECK_EQ
5403   CHECK(v8_str("a")->Equals(v8_str("a")));
5404   CHECK(!v8_str("a")->Equals(v8_str("b")));
5405
5406   CHECK(v8_str("a")->Equals(v8_str("a")));
5407   CHECK(!v8_str("a")->Equals(v8_str("b")));
5408   CHECK(v8_num(1)->Equals(v8_num(1)));
5409   CHECK(v8_num(1.00)->Equals(v8_num(1)));
5410   CHECK(!v8_num(1)->Equals(v8_num(2)));
5411
5412   // Assume String is not internalized.
5413   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5414   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5415   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5416   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5417   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5418   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5419   Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
5420   CHECK(!not_a_number->StrictEquals(not_a_number));
5421   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5422   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5423
5424   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5425   v8::Persistent<v8::Object> alias(isolate, obj);
5426   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5427   alias.Reset();
5428
5429   CHECK(v8_str("a")->SameValue(v8_str("a")));
5430   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5431   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5432   CHECK(v8_num(1)->SameValue(v8_num(1)));
5433   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5434   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5435   CHECK(not_a_number->SameValue(not_a_number));
5436   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5437   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5438 }
5439
5440
5441 THREADED_TEST(MultiRun) {
5442   LocalContext context;
5443   v8::HandleScope scope(context->GetIsolate());
5444   Local<Script> script = v8_compile("x");
5445   for (int i = 0; i < 10; i++) script->Run();
5446 }
5447
5448
5449 static void GetXValue(Local<String> name,
5450                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5451   ApiTestFuzzer::Fuzz();
5452   CHECK(info.Data()->Equals(v8_str("donut")));
5453   CHECK(name->Equals(v8_str("x")));
5454   info.GetReturnValue().Set(name);
5455 }
5456
5457
5458 THREADED_TEST(SimplePropertyRead) {
5459   LocalContext context;
5460   v8::Isolate* isolate = context->GetIsolate();
5461   v8::HandleScope scope(isolate);
5462   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5463   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5464   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5465   Local<Script> script = v8_compile("obj.x");
5466   for (int i = 0; i < 10; i++) {
5467     Local<Value> result = script->Run();
5468     CHECK(result->Equals(v8_str("x")));
5469   }
5470 }
5471
5472
5473 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5474   LocalContext context;
5475   v8::Isolate* isolate = context->GetIsolate();
5476   v8::HandleScope scope(isolate);
5477   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5478   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5479   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5480
5481   // Uses getOwnPropertyDescriptor to check the configurable status
5482   Local<Script> script_desc = v8_compile(
5483       "var prop = Object.getOwnPropertyDescriptor( "
5484       "obj, 'x');"
5485       "prop.configurable;");
5486   Local<Value> result = script_desc->Run();
5487   CHECK_EQ(result->BooleanValue(), true);
5488
5489   // Redefine get - but still configurable
5490   Local<Script> script_define = v8_compile(
5491       "var desc = { get: function(){return 42; },"
5492       "            configurable: true };"
5493       "Object.defineProperty(obj, 'x', desc);"
5494       "obj.x");
5495   result = script_define->Run();
5496   CHECK(result->Equals(v8_num(42)));
5497
5498   // Check that the accessor is still configurable
5499   result = script_desc->Run();
5500   CHECK_EQ(result->BooleanValue(), true);
5501
5502   // Redefine to a non-configurable
5503   script_define = v8_compile(
5504       "var desc = { get: function(){return 43; },"
5505       "             configurable: false };"
5506       "Object.defineProperty(obj, 'x', desc);"
5507       "obj.x");
5508   result = script_define->Run();
5509   CHECK(result->Equals(v8_num(43)));
5510   result = script_desc->Run();
5511   CHECK_EQ(result->BooleanValue(), false);
5512
5513   // Make sure that it is not possible to redefine again
5514   v8::TryCatch try_catch;
5515   result = script_define->Run();
5516   CHECK(try_catch.HasCaught());
5517   String::Utf8Value exception_value(try_catch.Exception());
5518   CHECK_EQ(0,
5519            strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5520 }
5521
5522
5523 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5524   v8::Isolate* isolate = CcTest::isolate();
5525   v8::HandleScope scope(isolate);
5526   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5527   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5528   LocalContext context;
5529   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5530
5531   Local<Script> script_desc = v8_compile(
5532       "var prop ="
5533       "Object.getOwnPropertyDescriptor( "
5534       "obj, 'x');"
5535       "prop.configurable;");
5536   Local<Value> result = script_desc->Run();
5537   CHECK_EQ(result->BooleanValue(), true);
5538
5539   Local<Script> script_define = v8_compile(
5540       "var desc = {get: function(){return 42; },"
5541       "            configurable: true };"
5542       "Object.defineProperty(obj, 'x', desc);"
5543       "obj.x");
5544   result = script_define->Run();
5545   CHECK(result->Equals(v8_num(42)));
5546
5547
5548   result = script_desc->Run();
5549   CHECK_EQ(result->BooleanValue(), true);
5550
5551
5552   script_define = v8_compile(
5553       "var desc = {get: function(){return 43; },"
5554       "            configurable: false };"
5555       "Object.defineProperty(obj, 'x', desc);"
5556       "obj.x");
5557   result = script_define->Run();
5558   CHECK(result->Equals(v8_num(43)));
5559   result = script_desc->Run();
5560
5561   CHECK_EQ(result->BooleanValue(), false);
5562
5563   v8::TryCatch try_catch;
5564   result = script_define->Run();
5565   CHECK(try_catch.HasCaught());
5566   String::Utf8Value exception_value(try_catch.Exception());
5567   CHECK_EQ(0,
5568            strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5569 }
5570
5571
5572 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5573                                                 char const* name) {
5574   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5575 }
5576
5577
5578 THREADED_TEST(DefineAPIAccessorOnObject) {
5579   v8::Isolate* isolate = CcTest::isolate();
5580   v8::HandleScope scope(isolate);
5581   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5582   LocalContext context;
5583
5584   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5585   CompileRun("var obj2 = {};");
5586
5587   CHECK(CompileRun("obj1.x")->IsUndefined());
5588   CHECK(CompileRun("obj2.x")->IsUndefined());
5589
5590   CHECK(GetGlobalProperty(&context, "obj1")
5591             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5592
5593   ExpectString("obj1.x", "x");
5594   CHECK(CompileRun("obj2.x")->IsUndefined());
5595
5596   CHECK(GetGlobalProperty(&context, "obj2")
5597             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5598
5599   ExpectString("obj1.x", "x");
5600   ExpectString("obj2.x", "x");
5601
5602   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5603   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5604
5605   CompileRun(
5606       "Object.defineProperty(obj1, 'x',"
5607       "{ get: function() { return 'y'; }, configurable: true })");
5608
5609   ExpectString("obj1.x", "y");
5610   ExpectString("obj2.x", "x");
5611
5612   CompileRun(
5613       "Object.defineProperty(obj2, 'x',"
5614       "{ get: function() { return 'y'; }, configurable: true })");
5615
5616   ExpectString("obj1.x", "y");
5617   ExpectString("obj2.x", "y");
5618
5619   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5620   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5621
5622   CHECK(GetGlobalProperty(&context, "obj1")
5623             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5624   CHECK(GetGlobalProperty(&context, "obj2")
5625             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5626
5627   ExpectString("obj1.x", "x");
5628   ExpectString("obj2.x", "x");
5629
5630   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5631   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5632
5633   // Define getters/setters, but now make them not configurable.
5634   CompileRun(
5635       "Object.defineProperty(obj1, 'x',"
5636       "{ get: function() { return 'z'; }, configurable: false })");
5637   CompileRun(
5638       "Object.defineProperty(obj2, 'x',"
5639       "{ get: function() { return 'z'; }, configurable: false })");
5640
5641   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5642   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5643
5644   ExpectString("obj1.x", "z");
5645   ExpectString("obj2.x", "z");
5646
5647   CHECK(!GetGlobalProperty(&context, "obj1")
5648              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5649   CHECK(!GetGlobalProperty(&context, "obj2")
5650              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5651
5652   ExpectString("obj1.x", "z");
5653   ExpectString("obj2.x", "z");
5654 }
5655
5656
5657 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5658   v8::Isolate* isolate = CcTest::isolate();
5659   v8::HandleScope scope(isolate);
5660   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5661   LocalContext context;
5662
5663   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5664   CompileRun("var obj2 = {};");
5665
5666   CHECK(GetGlobalProperty(&context, "obj1")
5667             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5668                           v8::DEFAULT, v8::DontDelete));
5669   CHECK(GetGlobalProperty(&context, "obj2")
5670             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5671                           v8::DEFAULT, v8::DontDelete));
5672
5673   ExpectString("obj1.x", "x");
5674   ExpectString("obj2.x", "x");
5675
5676   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5677   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5678
5679   CHECK(!GetGlobalProperty(&context, "obj1")
5680              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5681   CHECK(!GetGlobalProperty(&context, "obj2")
5682              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5683
5684   {
5685     v8::TryCatch try_catch;
5686     CompileRun(
5687         "Object.defineProperty(obj1, 'x',"
5688         "{get: function() { return 'func'; }})");
5689     CHECK(try_catch.HasCaught());
5690     String::Utf8Value exception_value(try_catch.Exception());
5691     CHECK_EQ(
5692         0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5693   }
5694   {
5695     v8::TryCatch try_catch;
5696     CompileRun(
5697         "Object.defineProperty(obj2, 'x',"
5698         "{get: function() { return 'func'; }})");
5699     CHECK(try_catch.HasCaught());
5700     String::Utf8Value exception_value(try_catch.Exception());
5701     CHECK_EQ(
5702         0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5703   }
5704 }
5705
5706
5707 static void Get239Value(Local<String> name,
5708                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5709   ApiTestFuzzer::Fuzz();
5710   CHECK(info.Data()->Equals(v8_str("donut")));
5711   CHECK(name->Equals(v8_str("239")));
5712   info.GetReturnValue().Set(name);
5713 }
5714
5715
5716 THREADED_TEST(ElementAPIAccessor) {
5717   v8::Isolate* isolate = CcTest::isolate();
5718   v8::HandleScope scope(isolate);
5719   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5720   LocalContext context;
5721
5722   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5723   CompileRun("var obj2 = {};");
5724
5725   CHECK(GetGlobalProperty(&context, "obj1")
5726             ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5727   CHECK(GetGlobalProperty(&context, "obj2")
5728             ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5729
5730   ExpectString("obj1[239]", "239");
5731   ExpectString("obj2[239]", "239");
5732   ExpectString("obj1['239']", "239");
5733   ExpectString("obj2['239']", "239");
5734 }
5735
5736
5737 v8::Persistent<Value> xValue;
5738
5739
5740 static void SetXValue(Local<String> name, Local<Value> value,
5741                       const v8::PropertyCallbackInfo<void>& info) {
5742   CHECK(value->Equals(v8_num(4)));
5743   CHECK(info.Data()->Equals(v8_str("donut")));
5744   CHECK(name->Equals(v8_str("x")));
5745   CHECK(xValue.IsEmpty());
5746   xValue.Reset(info.GetIsolate(), value);
5747 }
5748
5749
5750 THREADED_TEST(SimplePropertyWrite) {
5751   v8::Isolate* isolate = CcTest::isolate();
5752   v8::HandleScope scope(isolate);
5753   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5754   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5755   LocalContext context;
5756   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5757   Local<Script> script = v8_compile("obj.x = 4");
5758   for (int i = 0; i < 10; i++) {
5759     CHECK(xValue.IsEmpty());
5760     script->Run();
5761     CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5762     xValue.Reset();
5763   }
5764 }
5765
5766
5767 THREADED_TEST(SetterOnly) {
5768   v8::Isolate* isolate = CcTest::isolate();
5769   v8::HandleScope scope(isolate);
5770   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5771   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5772   LocalContext context;
5773   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5774   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5775   for (int i = 0; i < 10; i++) {
5776     CHECK(xValue.IsEmpty());
5777     script->Run();
5778     CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5779     xValue.Reset();
5780   }
5781 }
5782
5783
5784 THREADED_TEST(NoAccessors) {
5785   v8::Isolate* isolate = CcTest::isolate();
5786   v8::HandleScope scope(isolate);
5787   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5788   templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL),
5789                      NULL, v8_str("donut"));
5790   LocalContext context;
5791   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5792   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5793   for (int i = 0; i < 10; i++) {
5794     script->Run();
5795   }
5796 }
5797
5798
5799 THREADED_TEST(MultiContexts) {
5800   v8::Isolate* isolate = CcTest::isolate();
5801   v8::HandleScope scope(isolate);
5802   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5803   templ->Set(v8_str("dummy"),
5804              v8::FunctionTemplate::New(isolate, DummyCallHandler));
5805
5806   Local<String> password = v8_str("Password");
5807
5808   // Create an environment
5809   LocalContext context0(0, templ);
5810   context0->SetSecurityToken(password);
5811   v8::Handle<v8::Object> global0 = context0->Global();
5812   global0->Set(v8_str("custom"), v8_num(1234));
5813   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5814
5815   // Create an independent environment
5816   LocalContext context1(0, templ);
5817   context1->SetSecurityToken(password);
5818   v8::Handle<v8::Object> global1 = context1->Global();
5819   global1->Set(v8_str("custom"), v8_num(1234));
5820   CHECK(!global0->Equals(global1));
5821   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5822   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5823
5824   // Now create a new context with the old global
5825   LocalContext context2(0, templ, global1);
5826   context2->SetSecurityToken(password);
5827   v8::Handle<v8::Object> global2 = context2->Global();
5828   CHECK(global1->Equals(global2));
5829   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5830   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5831 }
5832
5833
5834 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5835   // Make sure that functions created by cloning boilerplates cannot
5836   // communicate through their __proto__ field.
5837
5838   v8::HandleScope scope(CcTest::isolate());
5839
5840   LocalContext env0;
5841   v8::Handle<v8::Object> global0 = env0->Global();
5842   v8::Handle<v8::Object> object0 =
5843       global0->Get(v8_str("Object")).As<v8::Object>();
5844   v8::Handle<v8::Object> tostring0 =
5845       object0->Get(v8_str("toString")).As<v8::Object>();
5846   v8::Handle<v8::Object> proto0 =
5847       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5848   proto0->Set(v8_str("custom"), v8_num(1234));
5849
5850   LocalContext env1;
5851   v8::Handle<v8::Object> global1 = env1->Global();
5852   v8::Handle<v8::Object> object1 =
5853       global1->Get(v8_str("Object")).As<v8::Object>();
5854   v8::Handle<v8::Object> tostring1 =
5855       object1->Get(v8_str("toString")).As<v8::Object>();
5856   v8::Handle<v8::Object> proto1 =
5857       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5858   CHECK(!proto1->Has(v8_str("custom")));
5859 }
5860
5861
5862 THREADED_TEST(Regress892105) {
5863   // Make sure that object and array literals created by cloning
5864   // boilerplates cannot communicate through their __proto__
5865   // field. This is rather difficult to check, but we try to add stuff
5866   // to Object.prototype and Array.prototype and create a new
5867   // environment. This should succeed.
5868
5869   v8::HandleScope scope(CcTest::isolate());
5870
5871   Local<String> source = v8_str(
5872       "Object.prototype.obj = 1234;"
5873       "Array.prototype.arr = 4567;"
5874       "8901");
5875
5876   LocalContext env0;
5877   Local<Script> script0 = v8_compile(source);
5878   CHECK_EQ(8901.0, script0->Run()->NumberValue());
5879
5880   LocalContext env1;
5881   Local<Script> script1 = v8_compile(source);
5882   CHECK_EQ(8901.0, script1->Run()->NumberValue());
5883 }
5884
5885
5886 THREADED_TEST(UndetectableObject) {
5887   LocalContext env;
5888   v8::HandleScope scope(env->GetIsolate());
5889
5890   Local<v8::FunctionTemplate> desc =
5891       v8::FunctionTemplate::New(env->GetIsolate());
5892   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5893
5894   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5895   env->Global()->Set(v8_str("undetectable"), obj);
5896
5897   ExpectString("undetectable.toString()", "[object Object]");
5898   ExpectString("typeof undetectable", "undefined");
5899   ExpectString("typeof(undetectable)", "undefined");
5900   ExpectBoolean("typeof undetectable == 'undefined'", true);
5901   ExpectBoolean("typeof undetectable == 'object'", false);
5902   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5903   ExpectBoolean("!undetectable", true);
5904
5905   ExpectObject("true&&undetectable", obj);
5906   ExpectBoolean("false&&undetectable", false);
5907   ExpectBoolean("true||undetectable", true);
5908   ExpectObject("false||undetectable", obj);
5909
5910   ExpectObject("undetectable&&true", obj);
5911   ExpectObject("undetectable&&false", obj);
5912   ExpectBoolean("undetectable||true", true);
5913   ExpectBoolean("undetectable||false", false);
5914
5915   ExpectBoolean("undetectable==null", true);
5916   ExpectBoolean("null==undetectable", true);
5917   ExpectBoolean("undetectable==undefined", true);
5918   ExpectBoolean("undefined==undetectable", true);
5919   ExpectBoolean("undetectable==undetectable", true);
5920
5921
5922   ExpectBoolean("undetectable===null", false);
5923   ExpectBoolean("null===undetectable", false);
5924   ExpectBoolean("undetectable===undefined", false);
5925   ExpectBoolean("undefined===undetectable", false);
5926   ExpectBoolean("undetectable===undetectable", true);
5927 }
5928
5929
5930 THREADED_TEST(VoidLiteral) {
5931   LocalContext env;
5932   v8::Isolate* isolate = env->GetIsolate();
5933   v8::HandleScope scope(isolate);
5934
5935   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5936   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5937
5938   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5939   env->Global()->Set(v8_str("undetectable"), obj);
5940
5941   ExpectBoolean("undefined == void 0", true);
5942   ExpectBoolean("undetectable == void 0", true);
5943   ExpectBoolean("null == void 0", true);
5944   ExpectBoolean("undefined === void 0", true);
5945   ExpectBoolean("undetectable === void 0", false);
5946   ExpectBoolean("null === void 0", false);
5947
5948   ExpectBoolean("void 0 == undefined", true);
5949   ExpectBoolean("void 0 == undetectable", true);
5950   ExpectBoolean("void 0 == null", true);
5951   ExpectBoolean("void 0 === undefined", true);
5952   ExpectBoolean("void 0 === undetectable", false);
5953   ExpectBoolean("void 0 === null", false);
5954
5955   ExpectString(
5956       "(function() {"
5957       "  try {"
5958       "    return x === void 0;"
5959       "  } catch(e) {"
5960       "    return e.toString();"
5961       "  }"
5962       "})()",
5963       "ReferenceError: x is not defined");
5964   ExpectString(
5965       "(function() {"
5966       "  try {"
5967       "    return void 0 === x;"
5968       "  } catch(e) {"
5969       "    return e.toString();"
5970       "  }"
5971       "})()",
5972       "ReferenceError: x is not defined");
5973 }
5974
5975
5976 THREADED_TEST(ExtensibleOnUndetectable) {
5977   LocalContext env;
5978   v8::Isolate* isolate = env->GetIsolate();
5979   v8::HandleScope scope(isolate);
5980
5981   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5982   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5983
5984   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5985   env->Global()->Set(v8_str("undetectable"), obj);
5986
5987   Local<String> source = v8_str(
5988       "undetectable.x = 42;"
5989       "undetectable.x");
5990
5991   Local<Script> script = v8_compile(source);
5992
5993   CHECK(v8::Integer::New(isolate, 42)->Equals(script->Run()));
5994
5995   ExpectBoolean("Object.isExtensible(undetectable)", true);
5996
5997   source = v8_str("Object.preventExtensions(undetectable);");
5998   script = v8_compile(source);
5999   script->Run();
6000   ExpectBoolean("Object.isExtensible(undetectable)", false);
6001
6002   source = v8_str("undetectable.y = 2000;");
6003   script = v8_compile(source);
6004   script->Run();
6005   ExpectBoolean("undetectable.y == undefined", true);
6006 }
6007
6008
6009 // The point of this test is type checking. We run it only so compilers
6010 // don't complain about an unused function.
6011 TEST(PersistentHandles) {
6012   LocalContext env;
6013   v8::Isolate* isolate = CcTest::isolate();
6014   v8::HandleScope scope(isolate);
6015   Local<String> str = v8_str("foo");
6016   v8::Persistent<String> p_str(isolate, str);
6017   p_str.Reset();
6018   Local<Script> scr = v8_compile("");
6019   v8::Persistent<Script> p_scr(isolate, scr);
6020   p_scr.Reset();
6021   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6022   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6023   p_templ.Reset();
6024 }
6025
6026
6027 static void HandleLogDelegator(
6028     const v8::FunctionCallbackInfo<v8::Value>& args) {
6029   ApiTestFuzzer::Fuzz();
6030 }
6031
6032
6033 THREADED_TEST(GlobalObjectTemplate) {
6034   v8::Isolate* isolate = CcTest::isolate();
6035   v8::HandleScope handle_scope(isolate);
6036   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6037   global_template->Set(v8_str("JSNI_Log"),
6038                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6039   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6040   Context::Scope context_scope(context);
6041   CompileRun("JSNI_Log('LOG')");
6042 }
6043
6044
6045 static const char* kSimpleExtensionSource =
6046     "function Foo() {"
6047     "  return 4;"
6048     "}";
6049
6050
6051 TEST(SimpleExtensions) {
6052   v8::HandleScope handle_scope(CcTest::isolate());
6053   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6054   const char* extension_names[] = {"simpletest"};
6055   v8::ExtensionConfiguration extensions(1, extension_names);
6056   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6057   Context::Scope lock(context);
6058   v8::Handle<Value> result = CompileRun("Foo()");
6059   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6060 }
6061
6062
6063 static const char* kStackTraceFromExtensionSource =
6064     "function foo() {"
6065     "  throw new Error();"
6066     "}"
6067     "function bar() {"
6068     "  foo();"
6069     "}";
6070
6071
6072 TEST(StackTraceInExtension) {
6073   v8::HandleScope handle_scope(CcTest::isolate());
6074   v8::RegisterExtension(
6075       new Extension("stacktracetest", kStackTraceFromExtensionSource));
6076   const char* extension_names[] = {"stacktracetest"};
6077   v8::ExtensionConfiguration extensions(1, extension_names);
6078   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6079   Context::Scope lock(context);
6080   CompileRun(
6081       "function user() { bar(); }"
6082       "var error;"
6083       "try{ user(); } catch (e) { error = e; }");
6084   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6085   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6086   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6087 }
6088
6089
6090 TEST(NullExtensions) {
6091   v8::HandleScope handle_scope(CcTest::isolate());
6092   v8::RegisterExtension(new Extension("nulltest", NULL));
6093   const char* extension_names[] = {"nulltest"};
6094   v8::ExtensionConfiguration extensions(1, extension_names);
6095   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6096   Context::Scope lock(context);
6097   v8::Handle<Value> result = CompileRun("1+3");
6098   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6099 }
6100
6101
6102 static const char* kEmbeddedExtensionSource =
6103     "function Ret54321(){return 54321;}~~@@$"
6104     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6105 static const int kEmbeddedExtensionSourceValidLen = 34;
6106
6107
6108 TEST(ExtensionMissingSourceLength) {
6109   v8::HandleScope handle_scope(CcTest::isolate());
6110   v8::RegisterExtension(
6111       new Extension("srclentest_fail", kEmbeddedExtensionSource));
6112   const char* extension_names[] = {"srclentest_fail"};
6113   v8::ExtensionConfiguration extensions(1, extension_names);
6114   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6115   CHECK(0 == *context);
6116 }
6117
6118
6119 TEST(ExtensionWithSourceLength) {
6120   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6121        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6122     v8::HandleScope handle_scope(CcTest::isolate());
6123     i::ScopedVector<char> extension_name(32);
6124     i::SNPrintF(extension_name, "ext #%d", source_len);
6125     v8::RegisterExtension(new Extension(
6126         extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
6127     const char* extension_names[1] = {extension_name.start()};
6128     v8::ExtensionConfiguration extensions(1, extension_names);
6129     v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6130     if (source_len == kEmbeddedExtensionSourceValidLen) {
6131       Context::Scope lock(context);
6132       v8::Handle<Value> result = CompileRun("Ret54321()");
6133       CHECK(v8::Integer::New(CcTest::isolate(), 54321)->Equals(result));
6134     } else {
6135       // Anything but exactly the right length should fail to compile.
6136       CHECK(0 == *context);
6137     }
6138   }
6139 }
6140
6141
6142 static const char* kEvalExtensionSource1 =
6143     "function UseEval1() {"
6144     "  var x = 42;"
6145     "  return eval('x');"
6146     "}";
6147
6148
6149 static const char* kEvalExtensionSource2 =
6150     "(function() {"
6151     "  var x = 42;"
6152     "  function e() {"
6153     "    return eval('x');"
6154     "  }"
6155     "  this.UseEval2 = e;"
6156     "})()";
6157
6158
6159 TEST(UseEvalFromExtension) {
6160   v8::HandleScope handle_scope(CcTest::isolate());
6161   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6162   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6163   const char* extension_names[] = {"evaltest1", "evaltest2"};
6164   v8::ExtensionConfiguration extensions(2, extension_names);
6165   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6166   Context::Scope lock(context);
6167   v8::Handle<Value> result = CompileRun("UseEval1()");
6168   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6169   result = CompileRun("UseEval2()");
6170   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6171 }
6172
6173
6174 static const char* kWithExtensionSource1 =
6175     "function UseWith1() {"
6176     "  var x = 42;"
6177     "  with({x:87}) { return x; }"
6178     "}";
6179
6180
6181 static const char* kWithExtensionSource2 =
6182     "(function() {"
6183     "  var x = 42;"
6184     "  function e() {"
6185     "    with ({x:87}) { return x; }"
6186     "  }"
6187     "  this.UseWith2 = e;"
6188     "})()";
6189
6190
6191 TEST(UseWithFromExtension) {
6192   v8::HandleScope handle_scope(CcTest::isolate());
6193   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6194   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6195   const char* extension_names[] = {"withtest1", "withtest2"};
6196   v8::ExtensionConfiguration extensions(2, extension_names);
6197   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6198   Context::Scope lock(context);
6199   v8::Handle<Value> result = CompileRun("UseWith1()");
6200   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6201   result = CompileRun("UseWith2()");
6202   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6203 }
6204
6205
6206 TEST(AutoExtensions) {
6207   v8::HandleScope handle_scope(CcTest::isolate());
6208   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6209   extension->set_auto_enable(true);
6210   v8::RegisterExtension(extension);
6211   v8::Handle<Context> context = Context::New(CcTest::isolate());
6212   Context::Scope lock(context);
6213   v8::Handle<Value> result = CompileRun("Foo()");
6214   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6215 }
6216
6217
6218 static const char* kSyntaxErrorInExtensionSource = "[";
6219
6220
6221 // Test that a syntax error in an extension does not cause a fatal
6222 // error but results in an empty context.
6223 TEST(SyntaxErrorExtensions) {
6224   v8::HandleScope handle_scope(CcTest::isolate());
6225   v8::RegisterExtension(
6226       new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
6227   const char* extension_names[] = {"syntaxerror"};
6228   v8::ExtensionConfiguration extensions(1, extension_names);
6229   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6230   CHECK(context.IsEmpty());
6231 }
6232
6233
6234 static const char* kExceptionInExtensionSource = "throw 42";
6235
6236
6237 // Test that an exception when installing an extension does not cause
6238 // a fatal error but results in an empty context.
6239 TEST(ExceptionExtensions) {
6240   v8::HandleScope handle_scope(CcTest::isolate());
6241   v8::RegisterExtension(
6242       new Extension("exception", kExceptionInExtensionSource));
6243   const char* extension_names[] = {"exception"};
6244   v8::ExtensionConfiguration extensions(1, extension_names);
6245   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6246   CHECK(context.IsEmpty());
6247 }
6248
6249
6250 static const char* kNativeCallInExtensionSource =
6251     "function call_runtime_last_index_of(x) {"
6252     "  return %StringLastIndexOf(x, 'bob', 10);"
6253     "}";
6254
6255
6256 static const char* kNativeCallTest =
6257     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6258
6259 // Test that a native runtime calls are supported in extensions.
6260 TEST(NativeCallInExtensions) {
6261   v8::HandleScope handle_scope(CcTest::isolate());
6262   v8::RegisterExtension(
6263       new Extension("nativecall", kNativeCallInExtensionSource));
6264   const char* extension_names[] = {"nativecall"};
6265   v8::ExtensionConfiguration extensions(1, extension_names);
6266   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6267   Context::Scope lock(context);
6268   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6269   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 3)));
6270 }
6271
6272
6273 class NativeFunctionExtension : public Extension {
6274  public:
6275   NativeFunctionExtension(const char* name, const char* source,
6276                           v8::FunctionCallback fun = &Echo)
6277       : Extension(name, source), function_(fun) {}
6278
6279   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6280       v8::Isolate* isolate, v8::Handle<v8::String> name) {
6281     return v8::FunctionTemplate::New(isolate, function_);
6282   }
6283
6284   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6285     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6286   }
6287
6288  private:
6289   v8::FunctionCallback function_;
6290 };
6291
6292
6293 TEST(NativeFunctionDeclaration) {
6294   v8::HandleScope handle_scope(CcTest::isolate());
6295   const char* name = "nativedecl";
6296   v8::RegisterExtension(
6297       new NativeFunctionExtension(name, "native function foo();"));
6298   const char* extension_names[] = {name};
6299   v8::ExtensionConfiguration extensions(1, extension_names);
6300   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6301   Context::Scope lock(context);
6302   v8::Handle<Value> result = CompileRun("foo(42);");
6303   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6304 }
6305
6306
6307 TEST(NativeFunctionDeclarationError) {
6308   v8::HandleScope handle_scope(CcTest::isolate());
6309   const char* name = "nativedeclerr";
6310   // Syntax error in extension code.
6311   v8::RegisterExtension(
6312       new NativeFunctionExtension(name, "native\nfunction foo();"));
6313   const char* extension_names[] = {name};
6314   v8::ExtensionConfiguration extensions(1, extension_names);
6315   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6316   CHECK(context.IsEmpty());
6317 }
6318
6319
6320 TEST(NativeFunctionDeclarationErrorEscape) {
6321   v8::HandleScope handle_scope(CcTest::isolate());
6322   const char* name = "nativedeclerresc";
6323   // Syntax error in extension code - escape code in "native" means that
6324   // it's not treated as a keyword.
6325   v8::RegisterExtension(
6326       new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
6327   const char* extension_names[] = {name};
6328   v8::ExtensionConfiguration extensions(1, extension_names);
6329   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6330   CHECK(context.IsEmpty());
6331 }
6332
6333
6334 static void CheckDependencies(const char* name, const char* expected) {
6335   v8::HandleScope handle_scope(CcTest::isolate());
6336   v8::ExtensionConfiguration config(1, &name);
6337   LocalContext context(&config);
6338   CHECK(String::NewFromUtf8(CcTest::isolate(), expected)
6339             ->Equals(context->Global()->Get(v8_str("loaded"))));
6340 }
6341
6342
6343 /*
6344  * Configuration:
6345  *
6346  *     /-- B <--\
6347  * A <-          -- D <-- E
6348  *     \-- C <--/
6349  */
6350 THREADED_TEST(ExtensionDependency) {
6351   static const char* kEDeps[] = {"D"};
6352   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6353   static const char* kDDeps[] = {"B", "C"};
6354   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6355   static const char* kBCDeps[] = {"A"};
6356   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6357   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6358   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6359   CheckDependencies("A", "undefinedA");
6360   CheckDependencies("B", "undefinedAB");
6361   CheckDependencies("C", "undefinedAC");
6362   CheckDependencies("D", "undefinedABCD");
6363   CheckDependencies("E", "undefinedABCDE");
6364   v8::HandleScope handle_scope(CcTest::isolate());
6365   static const char* exts[2] = {"C", "E"};
6366   v8::ExtensionConfiguration config(2, exts);
6367   LocalContext context(&config);
6368   CHECK(v8_str("undefinedACBDE")
6369             ->Equals(context->Global()->Get(v8_str("loaded"))));
6370 }
6371
6372
6373 static const char* kExtensionTestScript =
6374     "native function A();"
6375     "native function B();"
6376     "native function C();"
6377     "function Foo(i) {"
6378     "  if (i == 0) return A();"
6379     "  if (i == 1) return B();"
6380     "  if (i == 2) return C();"
6381     "}";
6382
6383
6384 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6385   ApiTestFuzzer::Fuzz();
6386   if (args.IsConstructCall()) {
6387     args.This()->Set(v8_str("data"), args.Data());
6388     args.GetReturnValue().SetNull();
6389     return;
6390   }
6391   args.GetReturnValue().Set(args.Data());
6392 }
6393
6394
6395 class FunctionExtension : public Extension {
6396  public:
6397   FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
6398   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6399       v8::Isolate* isolate, v8::Handle<String> name);
6400 };
6401
6402
6403 static int lookup_count = 0;
6404 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6405     v8::Isolate* isolate, v8::Handle<String> name) {
6406   lookup_count++;
6407   if (name->Equals(v8_str("A"))) {
6408     return v8::FunctionTemplate::New(isolate, CallFun,
6409                                      v8::Integer::New(isolate, 8));
6410   } else if (name->Equals(v8_str("B"))) {
6411     return v8::FunctionTemplate::New(isolate, CallFun,
6412                                      v8::Integer::New(isolate, 7));
6413   } else if (name->Equals(v8_str("C"))) {
6414     return v8::FunctionTemplate::New(isolate, CallFun,
6415                                      v8::Integer::New(isolate, 6));
6416   } else {
6417     return v8::Handle<v8::FunctionTemplate>();
6418   }
6419 }
6420
6421
6422 THREADED_TEST(FunctionLookup) {
6423   v8::RegisterExtension(new FunctionExtension());
6424   v8::HandleScope handle_scope(CcTest::isolate());
6425   static const char* exts[1] = {"functiontest"};
6426   v8::ExtensionConfiguration config(1, exts);
6427   LocalContext context(&config);
6428   CHECK_EQ(3, lookup_count);
6429   CHECK(v8::Integer::New(CcTest::isolate(), 8)->Equals(CompileRun("Foo(0)")));
6430   CHECK(v8::Integer::New(CcTest::isolate(), 7)->Equals(CompileRun("Foo(1)")));
6431   CHECK(v8::Integer::New(CcTest::isolate(), 6)->Equals(CompileRun("Foo(2)")));
6432 }
6433
6434
6435 THREADED_TEST(NativeFunctionConstructCall) {
6436   v8::RegisterExtension(new FunctionExtension());
6437   v8::HandleScope handle_scope(CcTest::isolate());
6438   static const char* exts[1] = {"functiontest"};
6439   v8::ExtensionConfiguration config(1, exts);
6440   LocalContext context(&config);
6441   for (int i = 0; i < 10; i++) {
6442     // Run a few times to ensure that allocation of objects doesn't
6443     // change behavior of a constructor function.
6444     CHECK(v8::Integer::New(CcTest::isolate(), 8)
6445               ->Equals(CompileRun("(new A()).data")));
6446     CHECK(v8::Integer::New(CcTest::isolate(), 7)
6447               ->Equals(CompileRun("(new B()).data")));
6448     CHECK(v8::Integer::New(CcTest::isolate(), 6)
6449               ->Equals(CompileRun("(new C()).data")));
6450   }
6451 }
6452
6453
6454 static const char* last_location;
6455 static const char* last_message;
6456 void StoringErrorCallback(const char* location, const char* message) {
6457   if (last_location == NULL) {
6458     last_location = location;
6459     last_message = message;
6460   }
6461 }
6462
6463
6464 // ErrorReporting creates a circular extensions configuration and
6465 // tests that the fatal error handler gets called.  This renders V8
6466 // unusable and therefore this test cannot be run in parallel.
6467 TEST(ErrorReporting) {
6468   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6469   static const char* aDeps[] = {"B"};
6470   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6471   static const char* bDeps[] = {"A"};
6472   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6473   last_location = NULL;
6474   v8::ExtensionConfiguration config(1, bDeps);
6475   v8::Handle<Context> context = Context::New(CcTest::isolate(), &config);
6476   CHECK(context.IsEmpty());
6477   CHECK(last_location);
6478 }
6479
6480
6481 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6482                                              v8::Handle<Value> data) {
6483   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
6484   CHECK(v8::Undefined(CcTest::isolate())
6485             ->Equals(message->GetScriptOrigin().ResourceName()));
6486   message->GetLineNumber();
6487   message->GetSourceLine();
6488 }
6489
6490
6491 THREADED_TEST(ErrorWithMissingScriptInfo) {
6492   LocalContext context;
6493   v8::HandleScope scope(context->GetIsolate());
6494   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6495   CompileRun("throw Error()");
6496   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6497 }
6498
6499
6500 struct FlagAndPersistent {
6501   bool flag;
6502   v8::Global<v8::Object> handle;
6503 };
6504
6505
6506 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6507   data.GetParameter()->flag = true;
6508   data.GetParameter()->handle.Reset();
6509 }
6510
6511
6512 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
6513   v8::Isolate* iso = CcTest::isolate();
6514   v8::HandleScope scope(iso);
6515   v8::Handle<Context> context = Context::New(iso);
6516   Context::Scope context_scope(context);
6517
6518   FlagAndPersistent object_a, object_b;
6519
6520   intptr_t big_heap_size;
6521
6522   {
6523     v8::HandleScope handle_scope(iso);
6524     Local<Object> a(v8::Object::New(iso));
6525     Local<Object> b(v8::Object::New(iso));
6526     object_a.handle.Reset(iso, a);
6527     object_b.handle.Reset(iso, b);
6528     if (interlinked) {
6529       a->Set(v8_str("x"), b);
6530       b->Set(v8_str("x"), a);
6531     }
6532     if (global_gc) {
6533       CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6534     } else {
6535       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6536     }
6537     // We are relying on this creating a big flag array and reserving the space
6538     // up front.
6539     v8::Handle<Value> big_array = CompileRun("new Array(50000)");
6540     a->Set(v8_str("y"), big_array);
6541     big_heap_size = CcTest::heap()->SizeOfObjects();
6542   }
6543
6544   object_a.flag = false;
6545   object_b.flag = false;
6546   object_a.handle.SetWeak(&object_a, &SetFlag,
6547                           v8::WeakCallbackType::kParameter);
6548   object_b.handle.SetWeak(&object_b, &SetFlag,
6549                           v8::WeakCallbackType::kParameter);
6550   CHECK(!object_b.handle.IsIndependent());
6551   object_a.handle.MarkIndependent();
6552   object_b.handle.MarkIndependent();
6553   CHECK(object_b.handle.IsIndependent());
6554   if (global_gc) {
6555     CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6556   } else {
6557     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6558   }
6559   // A single GC should be enough to reclaim the memory, since we are using
6560   // phantom handles.
6561   CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
6562   CHECK(object_a.flag);
6563   CHECK(object_b.flag);
6564 }
6565
6566
6567 THREADED_TEST(IndependentWeakHandle) {
6568   IndependentWeakHandle(false, false);
6569   IndependentWeakHandle(false, true);
6570   IndependentWeakHandle(true, false);
6571   IndependentWeakHandle(true, true);
6572 }
6573
6574
6575 class Trivial {
6576  public:
6577   explicit Trivial(int x) : x_(x) {}
6578
6579   int x() { return x_; }
6580   void set_x(int x) { x_ = x; }
6581
6582  private:
6583   int x_;
6584 };
6585
6586
6587 class Trivial2 {
6588  public:
6589   Trivial2(int x, int y) : y_(y), x_(x) {}
6590
6591   int x() { return x_; }
6592   void set_x(int x) { x_ = x; }
6593
6594   int y() { return y_; }
6595   void set_y(int y) { y_ = y; }
6596
6597  private:
6598   int y_;
6599   int x_;
6600 };
6601
6602
6603 void CheckInternalFields(
6604     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
6605   v8::Persistent<v8::Object>* handle = data.GetParameter();
6606   handle->Reset();
6607   Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
6608   Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField2());
6609   CHECK_EQ(42, t1->x());
6610   CHECK_EQ(103, t2->x());
6611   t1->set_x(1729);
6612   t2->set_x(33550336);
6613 }
6614
6615
6616 void InternalFieldCallback(bool global_gc) {
6617   LocalContext env;
6618   v8::Isolate* isolate = env->GetIsolate();
6619   v8::HandleScope scope(isolate);
6620
6621   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
6622   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
6623   Trivial* t1;
6624   Trivial2* t2;
6625   instance_templ->SetInternalFieldCount(2);
6626   {
6627     v8::HandleScope scope(isolate);
6628     Local<v8::Object> obj = templ->GetFunction()->NewInstance();
6629     v8::Persistent<v8::Object> handle(isolate, obj);
6630     CHECK_EQ(2, obj->InternalFieldCount());
6631     CHECK(obj->GetInternalField(0)->IsUndefined());
6632     t1 = new Trivial(42);
6633     t2 = new Trivial2(103, 9);
6634
6635     obj->SetAlignedPointerInInternalField(0, t1);
6636     t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
6637     CHECK_EQ(42, t1->x());
6638
6639     obj->SetAlignedPointerInInternalField(1, t2);
6640     t2 =
6641         reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
6642     CHECK_EQ(103, t2->x());
6643
6644     handle.SetWeak<v8::Persistent<v8::Object>>(
6645         &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
6646     if (!global_gc) {
6647       handle.MarkIndependent();
6648     }
6649   }
6650   if (global_gc) {
6651     CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6652   } else {
6653     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6654   }
6655
6656   CHECK_EQ(1729, t1->x());
6657   CHECK_EQ(33550336, t2->x());
6658
6659   delete t1;
6660   delete t2;
6661 }
6662
6663
6664 THREADED_TEST(InternalFieldCallback) {
6665   InternalFieldCallback(false);
6666   InternalFieldCallback(true);
6667 }
6668
6669
6670 static void ResetUseValueAndSetFlag(
6671     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6672   // Blink will reset the handle, and then use the other handle, so they
6673   // can't use the same backing slot.
6674   data.GetParameter()->handle.Reset();
6675   data.GetValue()->IsBoolean();  // Make sure the handle still works.
6676   data.GetParameter()->flag = true;
6677 }
6678
6679
6680 static void ResetWeakHandle(bool global_gc) {
6681   v8::Isolate* iso = CcTest::isolate();
6682   v8::HandleScope scope(iso);
6683   v8::Handle<Context> context = Context::New(iso);
6684   Context::Scope context_scope(context);
6685
6686   FlagAndPersistent object_a, object_b;
6687
6688   {
6689     v8::HandleScope handle_scope(iso);
6690     Local<Object> a(v8::Object::New(iso));
6691     Local<Object> b(v8::Object::New(iso));
6692     object_a.handle.Reset(iso, a);
6693     object_b.handle.Reset(iso, b);
6694     if (global_gc) {
6695       CcTest::heap()->CollectAllGarbage(
6696           TestHeap::Heap::kAbortIncrementalMarkingMask);
6697     } else {
6698       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6699     }
6700   }
6701
6702   object_a.flag = false;
6703   object_b.flag = false;
6704   object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
6705   object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
6706   if (!global_gc) {
6707     object_a.handle.MarkIndependent();
6708     object_b.handle.MarkIndependent();
6709     CHECK(object_b.handle.IsIndependent());
6710   }
6711   if (global_gc) {
6712     CcTest::heap()->CollectAllGarbage(
6713         TestHeap::Heap::kAbortIncrementalMarkingMask);
6714   } else {
6715     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6716   }
6717   CHECK(object_a.flag);
6718   CHECK(object_b.flag);
6719 }
6720
6721
6722 THREADED_TEST(ResetWeakHandle) {
6723   ResetWeakHandle(false);
6724   ResetWeakHandle(true);
6725 }
6726
6727
6728 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
6729
6730
6731 static void InvokeMarkSweep() {
6732   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6733 }
6734
6735
6736 static void ForceScavenge(
6737     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6738   data.GetParameter()->handle.Reset();
6739   data.GetParameter()->flag = true;
6740   InvokeScavenge();
6741 }
6742
6743
6744 static void ForceMarkSweep(
6745     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6746   data.GetParameter()->handle.Reset();
6747   data.GetParameter()->flag = true;
6748   InvokeMarkSweep();
6749 }
6750
6751
6752 THREADED_TEST(GCFromWeakCallbacks) {
6753   v8::Isolate* isolate = CcTest::isolate();
6754   v8::HandleScope scope(isolate);
6755   v8::Handle<Context> context = Context::New(isolate);
6756   Context::Scope context_scope(context);
6757
6758   static const int kNumberOfGCTypes = 2;
6759   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
6760       Callback;
6761   Callback gc_forcing_callback[kNumberOfGCTypes] =
6762       {&ForceScavenge, &ForceMarkSweep};
6763
6764   typedef void (*GCInvoker)();
6765   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6766
6767   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6768     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6769       FlagAndPersistent object;
6770       {
6771         v8::HandleScope handle_scope(isolate);
6772         object.handle.Reset(isolate, v8::Object::New(isolate));
6773       }
6774       object.flag = false;
6775       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
6776       object.handle.MarkIndependent();
6777       invoke_gc[outer_gc]();
6778       CHECK(object.flag);
6779     }
6780   }
6781 }
6782
6783
6784 static void RevivingCallback(
6785     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6786   data.GetParameter()->handle.ClearWeak();
6787   data.GetParameter()->flag = true;
6788 }
6789
6790
6791 THREADED_TEST(IndependentHandleRevival) {
6792   v8::Isolate* isolate = CcTest::isolate();
6793   v8::HandleScope scope(isolate);
6794   v8::Handle<Context> context = Context::New(isolate);
6795   Context::Scope context_scope(context);
6796
6797   FlagAndPersistent object;
6798   {
6799     v8::HandleScope handle_scope(isolate);
6800     v8::Local<v8::Object> o = v8::Object::New(isolate);
6801     object.handle.Reset(isolate, o);
6802     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
6803     v8::Local<String> y_str = v8_str("y");
6804     o->Set(y_str, y_str);
6805   }
6806   object.flag = false;
6807   object.handle.SetWeak(&object, &RevivingCallback);
6808   object.handle.MarkIndependent();
6809   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6810   CHECK(object.flag);
6811   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
6812   {
6813     v8::HandleScope handle_scope(isolate);
6814     v8::Local<v8::Object> o =
6815         v8::Local<v8::Object>::New(isolate, object.handle);
6816     v8::Local<String> y_str = v8_str("y");
6817     CHECK(v8::Integer::New(isolate, 1)->Equals(o->Get(v8_str("x"))));
6818     CHECK(o->Get(y_str)->Equals(y_str));
6819   }
6820 }
6821
6822
6823 v8::Handle<Function> args_fun;
6824
6825
6826 static void ArgumentsTestCallback(
6827     const v8::FunctionCallbackInfo<v8::Value>& args) {
6828   ApiTestFuzzer::Fuzz();
6829   v8::Isolate* isolate = args.GetIsolate();
6830   CHECK(args_fun->Equals(args.Callee()));
6831   CHECK_EQ(3, args.Length());
6832   CHECK(v8::Integer::New(isolate, 1)->Equals(args[0]));
6833   CHECK(v8::Integer::New(isolate, 2)->Equals(args[1]));
6834   CHECK(v8::Integer::New(isolate, 3)->Equals(args[2]));
6835   CHECK(v8::Undefined(isolate)->Equals(args[3]));
6836   v8::HandleScope scope(args.GetIsolate());
6837   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6838 }
6839
6840
6841 THREADED_TEST(Arguments) {
6842   v8::Isolate* isolate = CcTest::isolate();
6843   v8::HandleScope scope(isolate);
6844   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
6845   global->Set(v8_str("f"),
6846               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
6847   LocalContext context(NULL, global);
6848   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6849   v8_compile("f(1, 2, 3)")->Run();
6850 }
6851
6852
6853 static int p_getter_count;
6854 static int p_getter_count2;
6855
6856
6857 static void PGetter(Local<String> name,
6858                     const v8::PropertyCallbackInfo<v8::Value>& info) {
6859   ApiTestFuzzer::Fuzz();
6860   p_getter_count++;
6861   v8::Handle<v8::Object> global =
6862       info.GetIsolate()->GetCurrentContext()->Global();
6863   CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6864   if (name->Equals(v8_str("p1"))) {
6865     CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6866   } else if (name->Equals(v8_str("p2"))) {
6867     CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6868   } else if (name->Equals(v8_str("p3"))) {
6869     CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6870   } else if (name->Equals(v8_str("p4"))) {
6871     CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6872   }
6873 }
6874
6875
6876 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6877   ApiTestFuzzer::Fuzz();
6878   LocalContext context;
6879   context->Global()->Set(v8_str("o1"), obj->NewInstance());
6880   CompileRun(
6881     "o1.__proto__ = { };"
6882     "var o2 = { __proto__: o1 };"
6883     "var o3 = { __proto__: o2 };"
6884     "var o4 = { __proto__: o3 };"
6885     "for (var i = 0; i < 10; i++) o4.p4;"
6886     "for (var i = 0; i < 10; i++) o3.p3;"
6887     "for (var i = 0; i < 10; i++) o2.p2;"
6888     "for (var i = 0; i < 10; i++) o1.p1;");
6889 }
6890
6891
6892 static void PGetter2(Local<Name> name,
6893                      const v8::PropertyCallbackInfo<v8::Value>& info) {
6894   ApiTestFuzzer::Fuzz();
6895   p_getter_count2++;
6896   v8::Handle<v8::Object> global =
6897       info.GetIsolate()->GetCurrentContext()->Global();
6898   CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6899   if (name->Equals(v8_str("p1"))) {
6900     CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6901   } else if (name->Equals(v8_str("p2"))) {
6902     CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6903   } else if (name->Equals(v8_str("p3"))) {
6904     CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6905   } else if (name->Equals(v8_str("p4"))) {
6906     CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6907   }
6908 }
6909
6910
6911 THREADED_TEST(GetterHolders) {
6912   v8::Isolate* isolate = CcTest::isolate();
6913   v8::HandleScope scope(isolate);
6914   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6915   obj->SetAccessor(v8_str("p1"), PGetter);
6916   obj->SetAccessor(v8_str("p2"), PGetter);
6917   obj->SetAccessor(v8_str("p3"), PGetter);
6918   obj->SetAccessor(v8_str("p4"), PGetter);
6919   p_getter_count = 0;
6920   RunHolderTest(obj);
6921   CHECK_EQ(40, p_getter_count);
6922 }
6923
6924
6925 THREADED_TEST(PreInterceptorHolders) {
6926   v8::Isolate* isolate = CcTest::isolate();
6927   v8::HandleScope scope(isolate);
6928   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6929   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
6930   p_getter_count2 = 0;
6931   RunHolderTest(obj);
6932   CHECK_EQ(40, p_getter_count2);
6933 }
6934
6935
6936 THREADED_TEST(ObjectInstantiation) {
6937   v8::Isolate* isolate = CcTest::isolate();
6938   v8::HandleScope scope(isolate);
6939   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
6940   templ->SetAccessor(v8_str("t"), PGetter2);
6941   LocalContext context;
6942   context->Global()->Set(v8_str("o"), templ->NewInstance());
6943   for (int i = 0; i < 100; i++) {
6944     v8::HandleScope inner_scope(CcTest::isolate());
6945     v8::Handle<v8::Object> obj = templ->NewInstance();
6946     CHECK(!obj->Equals(context->Global()->Get(v8_str("o"))));
6947     context->Global()->Set(v8_str("o2"), obj);
6948     v8::Handle<Value> value =
6949         CompileRun("o.__proto__ === o2.__proto__");
6950     CHECK(v8::True(isolate)->Equals(value));
6951     context->Global()->Set(v8_str("o"), obj);
6952   }
6953 }
6954
6955
6956 static int StrCmp16(uint16_t* a, uint16_t* b) {
6957   while (true) {
6958     if (*a == 0 && *b == 0) return 0;
6959     if (*a != *b) return 0 + *a - *b;
6960     a++;
6961     b++;
6962   }
6963 }
6964
6965
6966 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6967   while (true) {
6968     if (n-- == 0) return 0;
6969     if (*a == 0 && *b == 0) return 0;
6970     if (*a != *b) return 0 + *a - *b;
6971     a++;
6972     b++;
6973   }
6974 }
6975
6976
6977 int GetUtf8Length(Handle<String> str) {
6978   int len = str->Utf8Length();
6979   if (len < 0) {
6980     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6981     i::String::Flatten(istr);
6982     len = str->Utf8Length();
6983   }
6984   return len;
6985 }
6986
6987
6988 THREADED_TEST(StringWrite) {
6989   LocalContext context;
6990   v8::HandleScope scope(context->GetIsolate());
6991   v8::Handle<String> str = v8_str("abcde");
6992   // abc<Icelandic eth><Unicode snowman>.
6993   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6994   v8::Handle<String> str3 = v8::String::NewFromUtf8(
6995       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
6996   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
6997   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
6998   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
6999       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7000   // single lead surrogate
7001   uint16_t lead[1] = { 0xd800 };
7002   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7003       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7004   // single trail surrogate
7005   uint16_t trail[1] = { 0xdc00 };
7006   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7007       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7008   // surrogate pair
7009   uint16_t pair[2] = { 0xd800,  0xdc00 };
7010   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7011       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7012   const int kStride = 4;  // Must match stride in for loops in JS below.
7013   CompileRun(
7014       "var left = '';"
7015       "for (var i = 0; i < 0xd800; i += 4) {"
7016       "  left = left + String.fromCharCode(i);"
7017       "}");
7018   CompileRun(
7019       "var right = '';"
7020       "for (var i = 0; i < 0xd800; i += 4) {"
7021       "  right = String.fromCharCode(i) + right;"
7022       "}");
7023   v8::Handle<v8::Object> global = context->Global();
7024   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7025   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7026
7027   CHECK_EQ(5, str2->Length());
7028   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7029   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7030
7031   char buf[100];
7032   char utf8buf[0xd800 * 3];
7033   uint16_t wbuf[100];
7034   int len;
7035   int charlen;
7036
7037   memset(utf8buf, 0x1, 1000);
7038   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7039   CHECK_EQ(9, len);
7040   CHECK_EQ(5, charlen);
7041   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7042
7043   memset(utf8buf, 0x1, 1000);
7044   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7045   CHECK_EQ(8, len);
7046   CHECK_EQ(5, charlen);
7047   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7048
7049   memset(utf8buf, 0x1, 1000);
7050   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7051   CHECK_EQ(5, len);
7052   CHECK_EQ(4, charlen);
7053   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7054
7055   memset(utf8buf, 0x1, 1000);
7056   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7057   CHECK_EQ(5, len);
7058   CHECK_EQ(4, charlen);
7059   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7060
7061   memset(utf8buf, 0x1, 1000);
7062   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7063   CHECK_EQ(5, len);
7064   CHECK_EQ(4, charlen);
7065   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7066
7067   memset(utf8buf, 0x1, 1000);
7068   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7069   CHECK_EQ(3, len);
7070   CHECK_EQ(3, charlen);
7071   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7072
7073   memset(utf8buf, 0x1, 1000);
7074   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7075   CHECK_EQ(3, len);
7076   CHECK_EQ(3, charlen);
7077   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7078
7079   memset(utf8buf, 0x1, 1000);
7080   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7081   CHECK_EQ(2, len);
7082   CHECK_EQ(2, charlen);
7083   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7084
7085   // allow orphan surrogates by default
7086   memset(utf8buf, 0x1, 1000);
7087   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7088   CHECK_EQ(13, len);
7089   CHECK_EQ(8, charlen);
7090   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7091
7092   // replace orphan surrogates with unicode replacement character
7093   memset(utf8buf, 0x1, 1000);
7094   len = orphans_str->WriteUtf8(utf8buf,
7095                                sizeof(utf8buf),
7096                                &charlen,
7097                                String::REPLACE_INVALID_UTF8);
7098   CHECK_EQ(13, len);
7099   CHECK_EQ(8, charlen);
7100   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7101
7102   // replace single lead surrogate with unicode replacement character
7103   memset(utf8buf, 0x1, 1000);
7104   len = lead_str->WriteUtf8(utf8buf,
7105                             sizeof(utf8buf),
7106                             &charlen,
7107                             String::REPLACE_INVALID_UTF8);
7108   CHECK_EQ(4, len);
7109   CHECK_EQ(1, charlen);
7110   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7111
7112   // replace single trail surrogate with unicode replacement character
7113   memset(utf8buf, 0x1, 1000);
7114   len = trail_str->WriteUtf8(utf8buf,
7115                              sizeof(utf8buf),
7116                              &charlen,
7117                              String::REPLACE_INVALID_UTF8);
7118   CHECK_EQ(4, len);
7119   CHECK_EQ(1, charlen);
7120   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7121
7122   // do not replace / write anything if surrogate pair does not fit the buffer
7123   // space
7124   memset(utf8buf, 0x1, 1000);
7125   len = pair_str->WriteUtf8(utf8buf,
7126                              3,
7127                              &charlen,
7128                              String::REPLACE_INVALID_UTF8);
7129   CHECK_EQ(0, len);
7130   CHECK_EQ(0, charlen);
7131
7132   memset(utf8buf, 0x1, sizeof(utf8buf));
7133   len = GetUtf8Length(left_tree);
7134   int utf8_expected =
7135       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7136   CHECK_EQ(utf8_expected, len);
7137   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7138   CHECK_EQ(utf8_expected, len);
7139   CHECK_EQ(0xd800 / kStride, charlen);
7140   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7141   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7142   CHECK_EQ(0xc0 - kStride,
7143            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7144   CHECK_EQ(1, utf8buf[utf8_expected]);
7145
7146   memset(utf8buf, 0x1, sizeof(utf8buf));
7147   len = GetUtf8Length(right_tree);
7148   CHECK_EQ(utf8_expected, len);
7149   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7150   CHECK_EQ(utf8_expected, len);
7151   CHECK_EQ(0xd800 / kStride, charlen);
7152   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7153   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7154   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7155   CHECK_EQ(1, utf8buf[utf8_expected]);
7156
7157   memset(buf, 0x1, sizeof(buf));
7158   memset(wbuf, 0x1, sizeof(wbuf));
7159   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7160   CHECK_EQ(5, len);
7161   len = str->Write(wbuf);
7162   CHECK_EQ(5, len);
7163   CHECK_EQ(0, strcmp("abcde", buf));
7164   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7165   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7166
7167   memset(buf, 0x1, sizeof(buf));
7168   memset(wbuf, 0x1, sizeof(wbuf));
7169   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7170   CHECK_EQ(4, len);
7171   len = str->Write(wbuf, 0, 4);
7172   CHECK_EQ(4, len);
7173   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7174   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7175   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7176
7177   memset(buf, 0x1, sizeof(buf));
7178   memset(wbuf, 0x1, sizeof(wbuf));
7179   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7180   CHECK_EQ(5, len);
7181   len = str->Write(wbuf, 0, 5);
7182   CHECK_EQ(5, len);
7183   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7184   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7185   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7186
7187   memset(buf, 0x1, sizeof(buf));
7188   memset(wbuf, 0x1, sizeof(wbuf));
7189   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7190   CHECK_EQ(5, len);
7191   len = str->Write(wbuf, 0, 6);
7192   CHECK_EQ(5, len);
7193   CHECK_EQ(0, strcmp("abcde", buf));
7194   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7195   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7196
7197   memset(buf, 0x1, sizeof(buf));
7198   memset(wbuf, 0x1, sizeof(wbuf));
7199   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7200   CHECK_EQ(1, len);
7201   len = str->Write(wbuf, 4, -1);
7202   CHECK_EQ(1, len);
7203   CHECK_EQ(0, strcmp("e", buf));
7204   uint16_t answer5[] = {'e', '\0'};
7205   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7206
7207   memset(buf, 0x1, sizeof(buf));
7208   memset(wbuf, 0x1, sizeof(wbuf));
7209   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7210   CHECK_EQ(1, len);
7211   len = str->Write(wbuf, 4, 6);
7212   CHECK_EQ(1, len);
7213   CHECK_EQ(0, strcmp("e", buf));
7214   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7215
7216   memset(buf, 0x1, sizeof(buf));
7217   memset(wbuf, 0x1, sizeof(wbuf));
7218   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7219   CHECK_EQ(1, len);
7220   len = str->Write(wbuf, 4, 1);
7221   CHECK_EQ(1, len);
7222   CHECK_EQ(0, strncmp("e\1", buf, 2));
7223   uint16_t answer6[] = {'e', 0x101};
7224   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7225
7226   memset(buf, 0x1, sizeof(buf));
7227   memset(wbuf, 0x1, sizeof(wbuf));
7228   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7229   CHECK_EQ(1, len);
7230   len = str->Write(wbuf, 3, 1);
7231   CHECK_EQ(1, len);
7232   CHECK_EQ(0, strncmp("d\1", buf, 2));
7233   uint16_t answer7[] = {'d', 0x101};
7234   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7235
7236   memset(wbuf, 0x1, sizeof(wbuf));
7237   wbuf[5] = 'X';
7238   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7239   CHECK_EQ(5, len);
7240   CHECK_EQ('X', wbuf[5]);
7241   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7242   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7243   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7244   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7245   wbuf[5] = '\0';
7246   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7247
7248   memset(buf, 0x1, sizeof(buf));
7249   buf[5] = 'X';
7250   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7251                           0,
7252                           6,
7253                           String::NO_NULL_TERMINATION);
7254   CHECK_EQ(5, len);
7255   CHECK_EQ('X', buf[5]);
7256   CHECK_EQ(0, strncmp("abcde", buf, 5));
7257   CHECK_NE(0, strcmp("abcde", buf));
7258   buf[5] = '\0';
7259   CHECK_EQ(0, strcmp("abcde", buf));
7260
7261   memset(utf8buf, 0x1, sizeof(utf8buf));
7262   utf8buf[8] = 'X';
7263   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7264                         String::NO_NULL_TERMINATION);
7265   CHECK_EQ(8, len);
7266   CHECK_EQ('X', utf8buf[8]);
7267   CHECK_EQ(5, charlen);
7268   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7269   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7270   utf8buf[8] = '\0';
7271   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7272
7273   memset(utf8buf, 0x1, sizeof(utf8buf));
7274   utf8buf[5] = 'X';
7275   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7276                         String::NO_NULL_TERMINATION);
7277   CHECK_EQ(5, len);
7278   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7279   CHECK_EQ(5, charlen);
7280   utf8buf[5] = '\0';
7281   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7282
7283   memset(buf, 0x1, sizeof(buf));
7284   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7285   CHECK_EQ(7, len);
7286   CHECK_EQ(0, strcmp("abc", buf));
7287   CHECK_EQ(0, buf[3]);
7288   CHECK_EQ(0, strcmp("def", buf + 4));
7289
7290   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7291   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7292   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7293 }
7294
7295
7296 static void Utf16Helper(
7297     LocalContext& context,  // NOLINT
7298     const char* name,
7299     const char* lengths_name,
7300     int len) {
7301   Local<v8::Array> a =
7302       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7303   Local<v8::Array> alens =
7304       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7305   for (int i = 0; i < len; i++) {
7306     Local<v8::String> string =
7307       Local<v8::String>::Cast(a->Get(i));
7308     Local<v8::Number> expected_len =
7309       Local<v8::Number>::Cast(alens->Get(i));
7310     int length = GetUtf8Length(string);
7311     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7312   }
7313 }
7314
7315
7316 static uint16_t StringGet(Handle<String> str, int index) {
7317   i::Handle<i::String> istring =
7318       v8::Utils::OpenHandle(String::Cast(*str));
7319   return istring->Get(index);
7320 }
7321
7322
7323 static void WriteUtf8Helper(
7324     LocalContext& context,  // NOLINT
7325     const char* name,
7326     const char* lengths_name,
7327     int len) {
7328   Local<v8::Array> b =
7329       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7330   Local<v8::Array> alens =
7331       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7332   char buffer[1000];
7333   char buffer2[1000];
7334   for (int i = 0; i < len; i++) {
7335     Local<v8::String> string =
7336       Local<v8::String>::Cast(b->Get(i));
7337     Local<v8::Number> expected_len =
7338       Local<v8::Number>::Cast(alens->Get(i));
7339     int utf8_length = static_cast<int>(expected_len->Value());
7340     for (int j = utf8_length + 1; j >= 0; j--) {
7341       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7342       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7343       int nchars;
7344       int utf8_written =
7345           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7346       int utf8_written2 =
7347           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7348       CHECK_GE(utf8_length + 1, utf8_written);
7349       CHECK_GE(utf8_length, utf8_written2);
7350       for (int k = 0; k < utf8_written2; k++) {
7351         CHECK_EQ(buffer[k], buffer2[k]);
7352       }
7353       CHECK(nchars * 3 >= utf8_written - 1);
7354       CHECK(nchars <= utf8_written);
7355       if (j == utf8_length + 1) {
7356         CHECK_EQ(utf8_written2, utf8_length);
7357         CHECK_EQ(utf8_written2 + 1, utf8_written);
7358       }
7359       CHECK_EQ(buffer[utf8_written], 42);
7360       if (j > utf8_length) {
7361         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7362         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7363         Handle<String> roundtrip = v8_str(buffer);
7364         CHECK(roundtrip->Equals(string));
7365       } else {
7366         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7367       }
7368       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7369       if (nchars >= 2) {
7370         uint16_t trail = StringGet(string, nchars - 1);
7371         uint16_t lead = StringGet(string, nchars - 2);
7372         if (((lead & 0xfc00) == 0xd800) &&
7373             ((trail & 0xfc00) == 0xdc00)) {
7374           unsigned u1 = buffer2[utf8_written2 - 4];
7375           unsigned u2 = buffer2[utf8_written2 - 3];
7376           unsigned u3 = buffer2[utf8_written2 - 2];
7377           unsigned u4 = buffer2[utf8_written2 - 1];
7378           CHECK_EQ((u1 & 0xf8), 0xf0u);
7379           CHECK_EQ((u2 & 0xc0), 0x80u);
7380           CHECK_EQ((u3 & 0xc0), 0x80u);
7381           CHECK_EQ((u4 & 0xc0), 0x80u);
7382           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7383           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7384           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7385           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7386           CHECK_EQ((u1 & 0x3), c >> 18);
7387         }
7388       }
7389     }
7390   }
7391 }
7392
7393
7394 THREADED_TEST(Utf16) {
7395   LocalContext context;
7396   v8::HandleScope scope(context->GetIsolate());
7397   CompileRun(
7398       "var pad = '01234567890123456789';"
7399       "var p = [];"
7400       "var plens = [20, 3, 3];"
7401       "p.push('01234567890123456789');"
7402       "var lead = 0xd800;"
7403       "var trail = 0xdc00;"
7404       "p.push(String.fromCharCode(0xd800));"
7405       "p.push(String.fromCharCode(0xdc00));"
7406       "var a = [];"
7407       "var b = [];"
7408       "var c = [];"
7409       "var alens = [];"
7410       "for (var i = 0; i < 3; i++) {"
7411       "  p[1] = String.fromCharCode(lead++);"
7412       "  for (var j = 0; j < 3; j++) {"
7413       "    p[2] = String.fromCharCode(trail++);"
7414       "    a.push(p[i] + p[j]);"
7415       "    b.push(p[i] + p[j]);"
7416       "    c.push(p[i] + p[j]);"
7417       "    alens.push(plens[i] + plens[j]);"
7418       "  }"
7419       "}"
7420       "alens[5] -= 2;"  // Here the surrogate pairs match up.
7421       "var a2 = [];"
7422       "var b2 = [];"
7423       "var c2 = [];"
7424       "var a2lens = [];"
7425       "for (var m = 0; m < 9; m++) {"
7426       "  for (var n = 0; n < 9; n++) {"
7427       "    a2.push(a[m] + a[n]);"
7428       "    b2.push(b[m] + b[n]);"
7429       "    var newc = 'x' + c[m] + c[n] + 'y';"
7430       "    c2.push(newc.substring(1, newc.length - 1));"
7431       "    var utf = alens[m] + alens[n];"  // And here.
7432            // The 'n's that start with 0xdc.. are 6-8
7433            // The 'm's that end with 0xd8.. are 1, 4 and 7
7434       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
7435       "    a2lens.push(utf);"
7436       "  }"
7437       "}");
7438   Utf16Helper(context, "a", "alens", 9);
7439   Utf16Helper(context, "a2", "a2lens", 81);
7440   WriteUtf8Helper(context, "b", "alens", 9);
7441   WriteUtf8Helper(context, "b2", "a2lens", 81);
7442   WriteUtf8Helper(context, "c2", "a2lens", 81);
7443 }
7444
7445
7446 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7447   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7448   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7449   return *is1 == *is2;
7450 }
7451
7452 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
7453                              const char* b) {
7454   Handle<String> symbol1 =
7455       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
7456   Handle<String> symbol2 =
7457       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
7458   CHECK(SameSymbol(symbol1, symbol2));
7459 }
7460
7461
7462 THREADED_TEST(Utf16Symbol) {
7463   LocalContext context;
7464   v8::HandleScope scope(context->GetIsolate());
7465
7466   Handle<String> symbol1 = v8::String::NewFromUtf8(
7467       context->GetIsolate(), "abc", v8::String::kInternalizedString);
7468   Handle<String> symbol2 = v8::String::NewFromUtf8(
7469       context->GetIsolate(), "abc", v8::String::kInternalizedString);
7470   CHECK(SameSymbol(symbol1, symbol2));
7471
7472   SameSymbolHelper(context->GetIsolate(),
7473                    "\360\220\220\205",  // 4 byte encoding.
7474                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
7475   SameSymbolHelper(context->GetIsolate(),
7476                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
7477                    "\360\220\220\206");  // 4 byte encoding.
7478   SameSymbolHelper(context->GetIsolate(),
7479                    "x\360\220\220\205",  // 4 byte encoding.
7480                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
7481   SameSymbolHelper(context->GetIsolate(),
7482                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
7483                    "x\360\220\220\206");  // 4 byte encoding.
7484   CompileRun(
7485       "var sym0 = 'benedictus';"
7486       "var sym0b = 'S\303\270ren';"
7487       "var sym1 = '\355\240\201\355\260\207';"
7488       "var sym2 = '\360\220\220\210';"
7489       "var sym3 = 'x\355\240\201\355\260\207';"
7490       "var sym4 = 'x\360\220\220\210';"
7491       "if (sym1.length != 2) throw sym1;"
7492       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7493       "if (sym2.length != 2) throw sym2;"
7494       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7495       "if (sym3.length != 3) throw sym3;"
7496       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7497       "if (sym4.length != 3) throw sym4;"
7498       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7499   Handle<String> sym0 = v8::String::NewFromUtf8(
7500       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
7501   Handle<String> sym0b = v8::String::NewFromUtf8(
7502       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
7503   Handle<String> sym1 =
7504       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
7505                               v8::String::kInternalizedString);
7506   Handle<String> sym2 =
7507       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
7508                               v8::String::kInternalizedString);
7509   Handle<String> sym3 = v8::String::NewFromUtf8(
7510       context->GetIsolate(), "x\355\240\201\355\260\207",
7511       v8::String::kInternalizedString);
7512   Handle<String> sym4 =
7513       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
7514                               v8::String::kInternalizedString);
7515   v8::Local<v8::Object> global = context->Global();
7516   Local<Value> s0 = global->Get(v8_str("sym0"));
7517   Local<Value> s0b = global->Get(v8_str("sym0b"));
7518   Local<Value> s1 = global->Get(v8_str("sym1"));
7519   Local<Value> s2 = global->Get(v8_str("sym2"));
7520   Local<Value> s3 = global->Get(v8_str("sym3"));
7521   Local<Value> s4 = global->Get(v8_str("sym4"));
7522   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7523   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7524   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7525   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7526   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7527   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7528 }
7529
7530
7531 THREADED_TEST(ToArrayIndex) {
7532   LocalContext context;
7533   v8::Isolate* isolate = context->GetIsolate();
7534   v8::HandleScope scope(isolate);
7535
7536   v8::Handle<String> str = v8_str("42");
7537   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7538   CHECK(!index.IsEmpty());
7539   CHECK_EQ(42.0, index->Uint32Value());
7540   str = v8_str("42asdf");
7541   index = str->ToArrayIndex();
7542   CHECK(index.IsEmpty());
7543   str = v8_str("-42");
7544   index = str->ToArrayIndex();
7545   CHECK(index.IsEmpty());
7546   str = v8_str("4294967295");
7547   index = str->ToArrayIndex();
7548   CHECK(!index.IsEmpty());
7549   CHECK_EQ(4294967295.0, index->Uint32Value());
7550   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
7551   index = num->ToArrayIndex();
7552   CHECK(!index.IsEmpty());
7553   CHECK_EQ(1.0, index->Uint32Value());
7554   num = v8::Number::New(isolate, -1);
7555   index = num->ToArrayIndex();
7556   CHECK(index.IsEmpty());
7557   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
7558   index = obj->ToArrayIndex();
7559   CHECK(index.IsEmpty());
7560 }
7561
7562
7563 THREADED_TEST(ErrorConstruction) {
7564   LocalContext context;
7565   v8::HandleScope scope(context->GetIsolate());
7566
7567   v8::Handle<String> foo = v8_str("foo");
7568   v8::Handle<String> message = v8_str("message");
7569   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7570   CHECK(range_error->IsObject());
7571   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7572   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7573   CHECK(reference_error->IsObject());
7574   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7575   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7576   CHECK(syntax_error->IsObject());
7577   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7578   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7579   CHECK(type_error->IsObject());
7580   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7581   v8::Handle<Value> error = v8::Exception::Error(foo);
7582   CHECK(error->IsObject());
7583   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7584 }
7585
7586
7587 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
7588   ApiTestFuzzer::Fuzz();
7589   v8::Handle<String> foo = v8_str("foo");
7590   v8::Handle<String> message = v8_str("message");
7591   v8::Handle<Value> error = v8::Exception::Error(foo);
7592   CHECK(error->IsObject());
7593   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7594   info.GetIsolate()->ThrowException(error);
7595   info.GetReturnValue().SetUndefined();
7596 }
7597
7598
7599 THREADED_TEST(ExceptionCreateMessage) {
7600   LocalContext context;
7601   v8::HandleScope scope(context->GetIsolate());
7602   v8::Handle<String> foo_str = v8_str("foo");
7603   v8::Handle<String> message_str = v8_str("message");
7604
7605   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
7606
7607   Local<v8::FunctionTemplate> fun =
7608       v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
7609   v8::Local<v8::Object> global = context->Global();
7610   global->Set(v8_str("throwV8Exception"), fun->GetFunction());
7611
7612   TryCatch try_catch;
7613   CompileRun(
7614       "function f1() {\n"
7615       "  throwV8Exception();\n"
7616       "};\n"
7617       "f1();");
7618   CHECK(try_catch.HasCaught());
7619
7620   v8::Handle<v8::Value> error = try_catch.Exception();
7621   CHECK(error->IsObject());
7622   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7623
7624   v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
7625   CHECK(!message.IsEmpty());
7626   CHECK_EQ(2, message->GetLineNumber());
7627   CHECK_EQ(2, message->GetStartColumn());
7628
7629   v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
7630   CHECK(!stackTrace.IsEmpty());
7631   CHECK_EQ(2, stackTrace->GetFrameCount());
7632
7633   stackTrace = v8::Exception::GetStackTrace(error);
7634   CHECK(!stackTrace.IsEmpty());
7635   CHECK_EQ(2, stackTrace->GetFrameCount());
7636
7637   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
7638
7639   // Now check message location when SetCaptureStackTraceForUncaughtExceptions
7640   // is false.
7641   try_catch.Reset();
7642
7643   CompileRun(
7644       "function f2() {\n"
7645       "  return throwV8Exception();\n"
7646       "};\n"
7647       "f2();");
7648   CHECK(try_catch.HasCaught());
7649
7650   error = try_catch.Exception();
7651   CHECK(error->IsObject());
7652   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7653
7654   message = v8::Exception::CreateMessage(error);
7655   CHECK(!message.IsEmpty());
7656   CHECK_EQ(2, message->GetLineNumber());
7657   CHECK_EQ(9, message->GetStartColumn());
7658
7659   // Should be empty stack trace.
7660   stackTrace = message->GetStackTrace();
7661   CHECK(stackTrace.IsEmpty());
7662   CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
7663 }
7664
7665
7666 static void YGetter(Local<String> name,
7667                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7668   ApiTestFuzzer::Fuzz();
7669   info.GetReturnValue().Set(v8_num(10));
7670 }
7671
7672
7673 static void YSetter(Local<String> name,
7674                     Local<Value> value,
7675                     const v8::PropertyCallbackInfo<void>& info) {
7676   Local<Object> this_obj = Local<Object>::Cast(info.This());
7677   if (this_obj->Has(name)) this_obj->Delete(name);
7678   this_obj->Set(name, value);
7679 }
7680
7681
7682 THREADED_TEST(DeleteAccessor) {
7683   v8::Isolate* isolate = CcTest::isolate();
7684   v8::HandleScope scope(isolate);
7685   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7686   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7687   LocalContext context;
7688   v8::Handle<v8::Object> holder = obj->NewInstance();
7689   context->Global()->Set(v8_str("holder"), holder);
7690   v8::Handle<Value> result = CompileRun(
7691       "holder.y = 11; holder.y = 12; holder.y");
7692   CHECK_EQ(12u, result->Uint32Value());
7693 }
7694
7695
7696 THREADED_TEST(TypeSwitch) {
7697   v8::Isolate* isolate = CcTest::isolate();
7698   v8::HandleScope scope(isolate);
7699   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
7700   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
7701   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
7702   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7703   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7704   LocalContext context;
7705   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
7706   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7707   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7708   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7709   for (int i = 0; i < 10; i++) {
7710     CHECK_EQ(0, type_switch->match(obj0));
7711     CHECK_EQ(1, type_switch->match(obj1));
7712     CHECK_EQ(2, type_switch->match(obj2));
7713     CHECK_EQ(3, type_switch->match(obj3));
7714     CHECK_EQ(3, type_switch->match(obj3));
7715     CHECK_EQ(2, type_switch->match(obj2));
7716     CHECK_EQ(1, type_switch->match(obj1));
7717     CHECK_EQ(0, type_switch->match(obj0));
7718   }
7719 }
7720
7721
7722 static int trouble_nesting = 0;
7723 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7724   ApiTestFuzzer::Fuzz();
7725   trouble_nesting++;
7726
7727   // Call a JS function that throws an uncaught exception.
7728   Local<v8::Object> arg_this =
7729       args.GetIsolate()->GetCurrentContext()->Global();
7730   Local<Value> trouble_callee = (trouble_nesting == 3) ?
7731     arg_this->Get(v8_str("trouble_callee")) :
7732     arg_this->Get(v8_str("trouble_caller"));
7733   CHECK(trouble_callee->IsFunction());
7734   args.GetReturnValue().Set(
7735       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7736 }
7737
7738
7739 static int report_count = 0;
7740 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7741                                              v8::Handle<Value>) {
7742   report_count++;
7743 }
7744
7745
7746 // Counts uncaught exceptions, but other tests running in parallel
7747 // also have uncaught exceptions.
7748 TEST(ApiUncaughtException) {
7749   report_count = 0;
7750   LocalContext env;
7751   v8::Isolate* isolate = env->GetIsolate();
7752   v8::HandleScope scope(isolate);
7753   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7754
7755   Local<v8::FunctionTemplate> fun =
7756       v8::FunctionTemplate::New(isolate, TroubleCallback);
7757   v8::Local<v8::Object> global = env->Global();
7758   global->Set(v8_str("trouble"), fun->GetFunction());
7759
7760   CompileRun(
7761       "function trouble_callee() {"
7762       "  var x = null;"
7763       "  return x.foo;"
7764       "};"
7765       "function trouble_caller() {"
7766       "  trouble();"
7767       "};");
7768   Local<Value> trouble = global->Get(v8_str("trouble"));
7769   CHECK(trouble->IsFunction());
7770   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7771   CHECK(trouble_callee->IsFunction());
7772   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7773   CHECK(trouble_caller->IsFunction());
7774   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7775   CHECK_EQ(1, report_count);
7776   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7777 }
7778
7779
7780 TEST(ApiUncaughtExceptionInObjectObserve) {
7781   v8::internal::FLAG_stack_size = 150;
7782   report_count = 0;
7783   LocalContext env;
7784   v8::Isolate* isolate = env->GetIsolate();
7785   v8::HandleScope scope(isolate);
7786   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7787   CompileRun(
7788       "var obj = {};"
7789       "var observe_count = 0;"
7790       "function observer1() { ++observe_count; };"
7791       "function observer2() { ++observe_count; };"
7792       "function observer_throws() { throw new Error(); };"
7793       "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
7794       "Object.observe(obj, observer_throws.bind());"
7795       "Object.observe(obj, observer1);"
7796       "Object.observe(obj, stack_overflow);"
7797       "Object.observe(obj, observer2);"
7798       "Object.observe(obj, observer_throws.bind());"
7799       "obj.foo = 'bar';");
7800   CHECK_EQ(3, report_count);
7801   ExpectInt32("observe_count", 2);
7802   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7803 }
7804
7805
7806 static const char* script_resource_name = "ExceptionInNativeScript.js";
7807 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7808                                                 v8::Handle<Value>) {
7809   v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
7810   CHECK(!name_val.IsEmpty() && name_val->IsString());
7811   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
7812   CHECK_EQ(0, strcmp(script_resource_name, *name));
7813   CHECK_EQ(3, message->GetLineNumber());
7814   v8::String::Utf8Value source_line(message->GetSourceLine());
7815   CHECK_EQ(0, strcmp("  new o.foo();", *source_line));
7816 }
7817
7818
7819 TEST(ExceptionInNativeScript) {
7820   LocalContext env;
7821   v8::Isolate* isolate = env->GetIsolate();
7822   v8::HandleScope scope(isolate);
7823   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7824
7825   Local<v8::FunctionTemplate> fun =
7826       v8::FunctionTemplate::New(isolate, TroubleCallback);
7827   v8::Local<v8::Object> global = env->Global();
7828   global->Set(v8_str("trouble"), fun->GetFunction());
7829
7830   CompileRunWithOrigin(
7831       "function trouble() {\n"
7832       "  var o = {};\n"
7833       "  new o.foo();\n"
7834       "};",
7835       script_resource_name);
7836   Local<Value> trouble = global->Get(v8_str("trouble"));
7837   CHECK(trouble->IsFunction());
7838   Function::Cast(*trouble)->Call(global, 0, NULL);
7839   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7840 }
7841
7842
7843 TEST(CompilationErrorUsingTryCatchHandler) {
7844   LocalContext env;
7845   v8::HandleScope scope(env->GetIsolate());
7846   v8::TryCatch try_catch;
7847   v8_compile("This doesn't &*&@#$&*^ compile.");
7848   CHECK(*try_catch.Exception());
7849   CHECK(try_catch.HasCaught());
7850 }
7851
7852
7853 TEST(TryCatchFinallyUsingTryCatchHandler) {
7854   LocalContext env;
7855   v8::HandleScope scope(env->GetIsolate());
7856   v8::TryCatch try_catch;
7857   CompileRun("try { throw ''; } catch (e) {}");
7858   CHECK(!try_catch.HasCaught());
7859   CompileRun("try { throw ''; } finally {}");
7860   CHECK(try_catch.HasCaught());
7861   try_catch.Reset();
7862   CompileRun(
7863       "(function() {"
7864       "try { throw ''; } finally { return; }"
7865       "})()");
7866   CHECK(!try_catch.HasCaught());
7867   CompileRun(
7868       "(function()"
7869       "  { try { throw ''; } finally { throw 0; }"
7870       "})()");
7871   CHECK(try_catch.HasCaught());
7872 }
7873
7874
7875 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
7876   v8::HandleScope scope(args.GetIsolate());
7877   CompileRun(args[0]->ToString(args.GetIsolate()));
7878 }
7879
7880
7881 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
7882   v8::Isolate* isolate = CcTest::isolate();
7883   v8::HandleScope scope(isolate);
7884   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7885   templ->Set(v8_str("CEvaluate"),
7886              v8::FunctionTemplate::New(isolate, CEvaluate));
7887   LocalContext context(0, templ);
7888   v8::TryCatch try_catch;
7889   CompileRun("try {"
7890              "  CEvaluate('throw 1;');"
7891              "} finally {"
7892              "}");
7893   CHECK(try_catch.HasCaught());
7894   CHECK(!try_catch.Message().IsEmpty());
7895   String::Utf8Value exception_value(try_catch.Exception());
7896   CHECK_EQ(0, strcmp(*exception_value, "1"));
7897   try_catch.Reset();
7898   CompileRun("try {"
7899              "  CEvaluate('throw 1;');"
7900              "} finally {"
7901              "  throw 2;"
7902              "}");
7903   CHECK(try_catch.HasCaught());
7904   CHECK(!try_catch.Message().IsEmpty());
7905   String::Utf8Value finally_exception_value(try_catch.Exception());
7906   CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
7907 }
7908
7909
7910 // For use within the TestSecurityHandler() test.
7911 static bool g_security_callback_result = false;
7912 static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
7913                                  v8::AccessType type, Local<Value> data) {
7914   printf("a\n");
7915   return g_security_callback_result;
7916 }
7917
7918
7919 // SecurityHandler can't be run twice
7920 TEST(SecurityHandler) {
7921   v8::Isolate* isolate = CcTest::isolate();
7922   v8::HandleScope scope0(isolate);
7923   v8::Handle<v8::ObjectTemplate> global_template =
7924       v8::ObjectTemplate::New(isolate);
7925   global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL);
7926   // Create an environment
7927   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
7928   context0->Enter();
7929
7930   v8::Handle<v8::Object> global0 = context0->Global();
7931   v8::Handle<Script> script0 = v8_compile("foo = 111");
7932   script0->Run();
7933   global0->Set(v8_str("0"), v8_num(999));
7934   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7935   CHECK_EQ(111, foo0->Int32Value());
7936   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7937   CHECK_EQ(999, z0->Int32Value());
7938
7939   // Create another environment, should fail security checks.
7940   v8::HandleScope scope1(isolate);
7941
7942   v8::Handle<Context> context1 =
7943     Context::New(isolate, NULL, global_template);
7944   context1->Enter();
7945
7946   v8::Handle<v8::Object> global1 = context1->Global();
7947   global1->Set(v8_str("othercontext"), global0);
7948   // This set will fail the security check.
7949   v8::Handle<Script> script1 =
7950     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7951   script1->Run();
7952   g_security_callback_result = true;
7953   // This read will pass the security check.
7954   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7955   CHECK_EQ(111, foo1->Int32Value());
7956   // This read will pass the security check.
7957   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7958   CHECK_EQ(999, z1->Int32Value());
7959
7960   // Create another environment, should pass security checks.
7961   {
7962     v8::HandleScope scope2(isolate);
7963     LocalContext context2;
7964     v8::Handle<v8::Object> global2 = context2->Global();
7965     global2->Set(v8_str("othercontext"), global0);
7966     v8::Handle<Script> script2 =
7967         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7968     script2->Run();
7969     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7970     CHECK_EQ(333, foo2->Int32Value());
7971     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7972     CHECK_EQ(888, z2->Int32Value());
7973   }
7974
7975   context1->Exit();
7976   context0->Exit();
7977 }
7978
7979
7980 THREADED_TEST(SecurityChecks) {
7981   LocalContext env1;
7982   v8::HandleScope handle_scope(env1->GetIsolate());
7983   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7984
7985   Local<Value> foo = v8_str("foo");
7986   Local<Value> bar = v8_str("bar");
7987
7988   // Set to the same domain.
7989   env1->SetSecurityToken(foo);
7990
7991   // Create a function in env1.
7992   CompileRun("spy=function(){return spy;}");
7993   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7994   CHECK(spy->IsFunction());
7995
7996   // Create another function accessing global objects.
7997   CompileRun("spy2=function(){return new this.Array();}");
7998   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7999   CHECK(spy2->IsFunction());
8000
8001   // Switch to env2 in the same domain and invoke spy on env2.
8002   {
8003     env2->SetSecurityToken(foo);
8004     // Enter env2
8005     Context::Scope scope_env2(env2);
8006     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8007     CHECK(result->IsFunction());
8008   }
8009
8010   {
8011     env2->SetSecurityToken(bar);
8012     Context::Scope scope_env2(env2);
8013
8014     // Call cross_domain_call, it should throw an exception
8015     v8::TryCatch try_catch;
8016     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8017     CHECK(try_catch.HasCaught());
8018   }
8019 }
8020
8021
8022 // Regression test case for issue 1183439.
8023 THREADED_TEST(SecurityChecksForPrototypeChain) {
8024   LocalContext current;
8025   v8::HandleScope scope(current->GetIsolate());
8026   v8::Handle<Context> other = Context::New(current->GetIsolate());
8027
8028   // Change context to be able to get to the Object function in the
8029   // other context without hitting the security checks.
8030   v8::Local<Value> other_object;
8031   { Context::Scope scope(other);
8032     other_object = other->Global()->Get(v8_str("Object"));
8033     other->Global()->Set(v8_num(42), v8_num(87));
8034   }
8035
8036   current->Global()->Set(v8_str("other"), other->Global());
8037   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8038
8039   // Make sure the security check fails here and we get an undefined
8040   // result instead of getting the Object function. Repeat in a loop
8041   // to make sure to exercise the IC code.
8042   v8::Local<Script> access_other0 = v8_compile("other.Object");
8043   v8::Local<Script> access_other1 = v8_compile("other[42]");
8044   for (int i = 0; i < 5; i++) {
8045     CHECK(access_other0->Run().IsEmpty());
8046     CHECK(access_other1->Run().IsEmpty());
8047   }
8048
8049   // Create an object that has 'other' in its prototype chain and make
8050   // sure we cannot access the Object function indirectly through
8051   // that. Repeat in a loop to make sure to exercise the IC code.
8052   v8_compile("function F() { };"
8053              "F.prototype = other;"
8054              "var f = new F();")->Run();
8055   v8::Local<Script> access_f0 = v8_compile("f.Object");
8056   v8::Local<Script> access_f1 = v8_compile("f[42]");
8057   for (int j = 0; j < 5; j++) {
8058     CHECK(access_f0->Run().IsEmpty());
8059     CHECK(access_f1->Run().IsEmpty());
8060   }
8061
8062   // Now it gets hairy: Set the prototype for the other global object
8063   // to be the current global object. The prototype chain for 'f' now
8064   // goes through 'other' but ends up in the current global object.
8065   { Context::Scope scope(other);
8066     other->Global()->Set(v8_str("__proto__"), current->Global());
8067   }
8068   // Set a named and an index property on the current global
8069   // object. To force the lookup to go through the other global object,
8070   // the properties must not exist in the other global object.
8071   current->Global()->Set(v8_str("foo"), v8_num(100));
8072   current->Global()->Set(v8_num(99), v8_num(101));
8073   // Try to read the properties from f and make sure that the access
8074   // gets stopped by the security checks on the other global object.
8075   Local<Script> access_f2 = v8_compile("f.foo");
8076   Local<Script> access_f3 = v8_compile("f[99]");
8077   for (int k = 0; k < 5; k++) {
8078     CHECK(access_f2->Run().IsEmpty());
8079     CHECK(access_f3->Run().IsEmpty());
8080   }
8081 }
8082
8083
8084 static bool security_check_with_gc_called;
8085
8086 static bool SecurityTestCallbackWithGC(Local<v8::Object> global,
8087                                        Local<v8::Value> name,
8088                                        v8::AccessType type, Local<Value> data) {
8089   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8090   security_check_with_gc_called = true;
8091   return true;
8092 }
8093
8094
8095 TEST(SecurityTestGCAllowed) {
8096   v8::Isolate* isolate = CcTest::isolate();
8097   v8::HandleScope handle_scope(isolate);
8098   v8::Handle<v8::ObjectTemplate> object_template =
8099       v8::ObjectTemplate::New(isolate);
8100   object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL);
8101
8102   v8::Handle<Context> context = Context::New(isolate);
8103   v8::Context::Scope context_scope(context);
8104
8105   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8106
8107   security_check_with_gc_called = false;
8108   CompileRun("obj[0] = new String(1002);");
8109   CHECK(security_check_with_gc_called);
8110
8111   security_check_with_gc_called = false;
8112   CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
8113   CHECK(security_check_with_gc_called);
8114 }
8115
8116
8117 THREADED_TEST(CrossDomainDelete) {
8118   LocalContext env1;
8119   v8::HandleScope handle_scope(env1->GetIsolate());
8120   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8121
8122   Local<Value> foo = v8_str("foo");
8123   Local<Value> bar = v8_str("bar");
8124
8125   // Set to the same domain.
8126   env1->SetSecurityToken(foo);
8127   env2->SetSecurityToken(foo);
8128
8129   env1->Global()->Set(v8_str("prop"), v8_num(3));
8130   env2->Global()->Set(v8_str("env1"), env1->Global());
8131
8132   // Change env2 to a different domain and delete env1.prop.
8133   env2->SetSecurityToken(bar);
8134   {
8135     Context::Scope scope_env2(env2);
8136     Local<Value> result =
8137         CompileRun("delete env1.prop");
8138     CHECK(result.IsEmpty());
8139   }
8140
8141   // Check that env1.prop still exists.
8142   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8143   CHECK(v->IsNumber());
8144   CHECK_EQ(3, v->Int32Value());
8145 }
8146
8147
8148 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8149   LocalContext env1;
8150   v8::HandleScope handle_scope(env1->GetIsolate());
8151   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8152
8153   Local<Value> foo = v8_str("foo");
8154   Local<Value> bar = v8_str("bar");
8155
8156   // Set to the same domain.
8157   env1->SetSecurityToken(foo);
8158   env2->SetSecurityToken(foo);
8159
8160   env1->Global()->Set(v8_str("prop"), v8_num(3));
8161   env2->Global()->Set(v8_str("env1"), env1->Global());
8162
8163   // env1.prop is enumerable in env2.
8164   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8165   {
8166     Context::Scope scope_env2(env2);
8167     Local<Value> result = CompileRun(test);
8168     CHECK(result->IsTrue());
8169   }
8170
8171   // Change env2 to a different domain and test again.
8172   env2->SetSecurityToken(bar);
8173   {
8174     Context::Scope scope_env2(env2);
8175     Local<Value> result = CompileRun(test);
8176     CHECK(result.IsEmpty());
8177   }
8178 }
8179
8180
8181 THREADED_TEST(CrossDomainForIn) {
8182   LocalContext env1;
8183   v8::HandleScope handle_scope(env1->GetIsolate());
8184   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8185
8186   Local<Value> foo = v8_str("foo");
8187   Local<Value> bar = v8_str("bar");
8188
8189   // Set to the same domain.
8190   env1->SetSecurityToken(foo);
8191   env2->SetSecurityToken(foo);
8192
8193   env1->Global()->Set(v8_str("prop"), v8_num(3));
8194   env2->Global()->Set(v8_str("env1"), env1->Global());
8195
8196   // Change env2 to a different domain and set env1's global object
8197   // as the __proto__ of an object in env2 and enumerate properties
8198   // in for-in. It shouldn't enumerate properties on env1's global
8199   // object.
8200   env2->SetSecurityToken(bar);
8201   {
8202     Context::Scope scope_env2(env2);
8203     Local<Value> result = CompileRun(
8204         "(function() {"
8205         "  var obj = { '__proto__': env1 };"
8206         "  try {"
8207         "    for (var p in obj) {"
8208         "      if (p == 'prop') return false;"
8209         "    }"
8210         "    return false;"
8211         "  } catch (e) {"
8212         "    return true;"
8213         "  }"
8214         "})()");
8215     CHECK(result->IsTrue());
8216   }
8217 }
8218
8219
8220 TEST(ContextDetachGlobal) {
8221   LocalContext env1;
8222   v8::HandleScope handle_scope(env1->GetIsolate());
8223   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8224
8225   Local<v8::Object> global1 = env1->Global();
8226
8227   Local<Value> foo = v8_str("foo");
8228
8229   // Set to the same domain.
8230   env1->SetSecurityToken(foo);
8231   env2->SetSecurityToken(foo);
8232
8233   // Enter env2
8234   env2->Enter();
8235
8236   // Create a function in env2 and add a reference to it in env1.
8237   Local<v8::Object> global2 = env2->Global();
8238   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8239   CompileRun("function getProp() {return prop;}");
8240
8241   env1->Global()->Set(v8_str("getProp"),
8242                       global2->Get(v8_str("getProp")));
8243
8244   // Detach env2's global, and reuse the global object of env2
8245   env2->Exit();
8246   env2->DetachGlobal();
8247
8248   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8249                                           0,
8250                                           v8::Handle<v8::ObjectTemplate>(),
8251                                           global2);
8252   env3->SetSecurityToken(v8_str("bar"));
8253   env3->Enter();
8254
8255   Local<v8::Object> global3 = env3->Global();
8256   CHECK(global2->Equals(global3));
8257   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8258   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8259   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8260   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8261   env3->Exit();
8262
8263   // Call getProp in env1, and it should return the value 1
8264   {
8265     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8266     CHECK(get_prop->IsFunction());
8267     v8::TryCatch try_catch;
8268     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8269     CHECK(!try_catch.HasCaught());
8270     CHECK_EQ(1, r->Int32Value());
8271   }
8272
8273   // Check that env3 is not accessible from env1
8274   {
8275     Local<Value> r = global3->Get(v8_str("prop2"));
8276     CHECK(r.IsEmpty());
8277   }
8278 }
8279
8280
8281 TEST(DetachGlobal) {
8282   LocalContext env1;
8283   v8::HandleScope scope(env1->GetIsolate());
8284
8285   // Create second environment.
8286   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8287
8288   Local<Value> foo = v8_str("foo");
8289
8290   // Set same security token for env1 and env2.
8291   env1->SetSecurityToken(foo);
8292   env2->SetSecurityToken(foo);
8293
8294   // Create a property on the global object in env2.
8295   {
8296     v8::Context::Scope scope(env2);
8297     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8298   }
8299
8300   // Create a reference to env2 global from env1 global.
8301   env1->Global()->Set(v8_str("other"), env2->Global());
8302
8303   // Check that we have access to other.p in env2 from env1.
8304   Local<Value> result = CompileRun("other.p");
8305   CHECK(result->IsInt32());
8306   CHECK_EQ(42, result->Int32Value());
8307
8308   // Hold on to global from env2 and detach global from env2.
8309   Local<v8::Object> global2 = env2->Global();
8310   env2->DetachGlobal();
8311
8312   // Check that the global has been detached. No other.p property can
8313   // be found.
8314   result = CompileRun("other.p");
8315   CHECK(result.IsEmpty());
8316
8317   // Reuse global2 for env3.
8318   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8319                                           0,
8320                                           v8::Handle<v8::ObjectTemplate>(),
8321                                           global2);
8322   CHECK(global2->Equals(env3->Global()));
8323
8324   // Start by using the same security token for env3 as for env1 and env2.
8325   env3->SetSecurityToken(foo);
8326
8327   // Create a property on the global object in env3.
8328   {
8329     v8::Context::Scope scope(env3);
8330     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8331   }
8332
8333   // Check that other.p is now the property in env3 and that we have access.
8334   result = CompileRun("other.p");
8335   CHECK(result->IsInt32());
8336   CHECK_EQ(24, result->Int32Value());
8337
8338   // Change security token for env3 to something different from env1 and env2.
8339   env3->SetSecurityToken(v8_str("bar"));
8340
8341   // Check that we do not have access to other.p in env1. |other| is now
8342   // the global object for env3 which has a different security token,
8343   // so access should be blocked.
8344   result = CompileRun("other.p");
8345   CHECK(result.IsEmpty());
8346 }
8347
8348
8349 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8350   info.GetReturnValue().Set(
8351       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8352 }
8353
8354
8355 TEST(DetachedAccesses) {
8356   LocalContext env1;
8357   v8::HandleScope scope(env1->GetIsolate());
8358
8359   // Create second environment.
8360   Local<ObjectTemplate> inner_global_template =
8361       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8362   inner_global_template ->SetAccessorProperty(
8363       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8364   v8::Local<Context> env2 =
8365       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8366
8367   Local<Value> foo = v8_str("foo");
8368
8369   // Set same security token for env1 and env2.
8370   env1->SetSecurityToken(foo);
8371   env2->SetSecurityToken(foo);
8372
8373   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8374
8375   {
8376     v8::Context::Scope scope(env2);
8377     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8378     CompileRun(
8379         "function bound_x() { return x; }"
8380         "function get_x()   { return this.x; }"
8381         "function get_x_w() { return (function() {return this.x;})(); }");
8382     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8383     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8384     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8385     env1->Global()->Set(
8386         v8_str("this_x"),
8387         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8388   }
8389
8390   Local<Object> env2_global = env2->Global();
8391   env2_global->TurnOnAccessCheck();
8392   env2->DetachGlobal();
8393
8394   Local<Value> result;
8395   result = CompileRun("bound_x()");
8396   CHECK(v8_str("env2_x")->Equals(result));
8397   result = CompileRun("get_x()");
8398   CHECK(result.IsEmpty());
8399   result = CompileRun("get_x_w()");
8400   CHECK(result.IsEmpty());
8401   result = CompileRun("this_x()");
8402   CHECK(v8_str("env2_x")->Equals(result));
8403
8404   // Reattach env2's proxy
8405   env2 = Context::New(env1->GetIsolate(),
8406                       0,
8407                       v8::Handle<v8::ObjectTemplate>(),
8408                       env2_global);
8409   env2->SetSecurityToken(foo);
8410   {
8411     v8::Context::Scope scope(env2);
8412     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8413     env2->Global()->Set(v8_str("env1"), env1->Global());
8414     result = CompileRun(
8415         "results = [];"
8416         "for (var i = 0; i < 4; i++ ) {"
8417         "  results.push(env1.bound_x());"
8418         "  results.push(env1.get_x());"
8419         "  results.push(env1.get_x_w());"
8420         "  results.push(env1.this_x());"
8421         "}"
8422         "results");
8423     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8424     CHECK_EQ(16u, results->Length());
8425     for (int i = 0; i < 16; i += 4) {
8426       CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8427       CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8428       CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8429       CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8430     }
8431   }
8432
8433   result = CompileRun(
8434       "results = [];"
8435       "for (var i = 0; i < 4; i++ ) {"
8436       "  results.push(bound_x());"
8437       "  results.push(get_x());"
8438       "  results.push(get_x_w());"
8439       "  results.push(this_x());"
8440       "}"
8441       "results");
8442   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8443   CHECK_EQ(16u, results->Length());
8444   for (int i = 0; i < 16; i += 4) {
8445     CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8446     CHECK(v8_str("env3_x")->Equals(results->Get(i + 1)));
8447     CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8448     CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8449   }
8450
8451   result = CompileRun(
8452       "results = [];"
8453       "for (var i = 0; i < 4; i++ ) {"
8454       "  results.push(this.bound_x());"
8455       "  results.push(this.get_x());"
8456       "  results.push(this.get_x_w());"
8457       "  results.push(this.this_x());"
8458       "}"
8459       "results");
8460   results = Local<v8::Array>::Cast(result);
8461   CHECK_EQ(16u, results->Length());
8462   for (int i = 0; i < 16; i += 4) {
8463     CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8464     CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8465     CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8466     CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8467   }
8468 }
8469
8470
8471 static bool allowed_access = false;
8472 static bool AccessBlocker(Local<v8::Object> global, Local<Value> name,
8473                           v8::AccessType type, Local<Value> data) {
8474   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8475          allowed_access;
8476 }
8477
8478
8479 static int g_echo_value = -1;
8480
8481
8482 static void EchoGetter(
8483     Local<String> name,
8484     const v8::PropertyCallbackInfo<v8::Value>& info) {
8485   info.GetReturnValue().Set(v8_num(g_echo_value));
8486 }
8487
8488
8489 static void EchoSetter(Local<String> name,
8490                        Local<Value> value,
8491                        const v8::PropertyCallbackInfo<void>&) {
8492   if (value->IsNumber())
8493     g_echo_value = value->Int32Value();
8494 }
8495
8496
8497 static void UnreachableGetter(
8498     Local<String> name,
8499     const v8::PropertyCallbackInfo<v8::Value>& info) {
8500   CHECK(false);  // This function should not be called..
8501 }
8502
8503
8504 static void UnreachableSetter(Local<String>,
8505                               Local<Value>,
8506                               const v8::PropertyCallbackInfo<void>&) {
8507   CHECK(false);  // This function should nto be called.
8508 }
8509
8510
8511 static void UnreachableFunction(
8512     const v8::FunctionCallbackInfo<v8::Value>& info) {
8513   CHECK(false);  // This function should not be called..
8514 }
8515
8516
8517 TEST(AccessControl) {
8518   v8::Isolate* isolate = CcTest::isolate();
8519   v8::HandleScope handle_scope(isolate);
8520   v8::Handle<v8::ObjectTemplate> global_template =
8521       v8::ObjectTemplate::New(isolate);
8522
8523   global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8524
8525   // Add an accessor accessible by cross-domain JS code.
8526   global_template->SetAccessor(
8527       v8_str("accessible_prop"),
8528       EchoGetter, EchoSetter,
8529       v8::Handle<Value>(),
8530       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8531
8532
8533   // Add an accessor that is not accessible by cross-domain JS code.
8534   global_template->SetAccessor(v8_str("blocked_prop"),
8535                                UnreachableGetter, UnreachableSetter,
8536                                v8::Handle<Value>(),
8537                                v8::DEFAULT);
8538
8539   global_template->SetAccessorProperty(
8540       v8_str("blocked_js_prop"),
8541       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8542       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8543       v8::None,
8544       v8::DEFAULT);
8545
8546   // Create an environment
8547   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8548   context0->Enter();
8549
8550   v8::Handle<v8::Object> global0 = context0->Global();
8551
8552   // Define a property with JS getter and setter.
8553   CompileRun(
8554       "function getter() { return 'getter'; };\n"
8555       "function setter() { return 'setter'; }\n"
8556       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8557
8558   Local<Value> getter = global0->Get(v8_str("getter"));
8559   Local<Value> setter = global0->Get(v8_str("setter"));
8560
8561   // And define normal element.
8562   global0->Set(239, v8_str("239"));
8563
8564   // Define an element with JS getter and setter.
8565   CompileRun(
8566       "function el_getter() { return 'el_getter'; };\n"
8567       "function el_setter() { return 'el_setter'; };\n"
8568       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8569
8570   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8571   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8572
8573   v8::HandleScope scope1(isolate);
8574
8575   v8::Local<Context> context1 = Context::New(isolate);
8576   context1->Enter();
8577
8578   v8::Handle<v8::Object> global1 = context1->Global();
8579   global1->Set(v8_str("other"), global0);
8580
8581   // Access blocked property.
8582   CompileRun("other.blocked_prop = 1");
8583
8584   CHECK(CompileRun("other.blocked_prop").IsEmpty());
8585   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8586             .IsEmpty());
8587   CHECK(
8588       CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
8589
8590   // Access blocked element.
8591   CHECK(CompileRun("other[239] = 1").IsEmpty());
8592
8593   CHECK(CompileRun("other[239]").IsEmpty());
8594   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
8595   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
8596
8597   allowed_access = true;
8598   // Now we can enumerate the property.
8599   ExpectTrue("propertyIsEnumerable.call(other, '239')");
8600   allowed_access = false;
8601
8602   // Access a property with JS accessor.
8603   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
8604
8605   CHECK(CompileRun("other.js_accessor_p").IsEmpty());
8606   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
8607             .IsEmpty());
8608
8609   allowed_access = true;
8610
8611   ExpectString("other.js_accessor_p", "getter");
8612   ExpectObject(
8613       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8614   ExpectObject(
8615       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8616   ExpectUndefined(
8617       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8618
8619   allowed_access = false;
8620
8621   // Access an element with JS accessor.
8622   CHECK(CompileRun("other[42] = 2").IsEmpty());
8623
8624   CHECK(CompileRun("other[42]").IsEmpty());
8625   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
8626
8627   allowed_access = true;
8628
8629   ExpectString("other[42]", "el_getter");
8630   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8631   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8632   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8633
8634   allowed_access = false;
8635
8636   v8::Handle<Value> value;
8637
8638   // Access accessible property
8639   value = CompileRun("other.accessible_prop = 3");
8640   CHECK(value->IsNumber());
8641   CHECK_EQ(3, value->Int32Value());
8642   CHECK_EQ(3, g_echo_value);
8643
8644   value = CompileRun("other.accessible_prop");
8645   CHECK(value->IsNumber());
8646   CHECK_EQ(3, value->Int32Value());
8647
8648   value = CompileRun(
8649       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8650   CHECK(value->IsNumber());
8651   CHECK_EQ(3, value->Int32Value());
8652
8653   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8654   CHECK(value->IsTrue());
8655
8656   // Enumeration doesn't enumerate accessors from inaccessible objects in
8657   // the prototype chain even if the accessors are in themselves accessible.
8658   value = CompileRun(
8659       "(function() {"
8660       "  var obj = { '__proto__': other };"
8661       "  try {"
8662       "    for (var p in obj) {"
8663       "      if (p == 'accessible_prop' ||"
8664       "          p == 'blocked_js_prop' ||"
8665       "          p == 'blocked_js_prop') {"
8666       "        return false;"
8667       "      }"
8668       "    }"
8669       "    return false;"
8670       "  } catch (e) {"
8671       "    return true;"
8672       "  }"
8673       "})()");
8674   CHECK(value->IsTrue());
8675
8676   context1->Exit();
8677   context0->Exit();
8678 }
8679
8680
8681 TEST(AccessControlES5) {
8682   v8::Isolate* isolate = CcTest::isolate();
8683   v8::HandleScope handle_scope(isolate);
8684   v8::Handle<v8::ObjectTemplate> global_template =
8685       v8::ObjectTemplate::New(isolate);
8686
8687   global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8688
8689   // Add accessible accessor.
8690   global_template->SetAccessor(
8691       v8_str("accessible_prop"),
8692       EchoGetter, EchoSetter,
8693       v8::Handle<Value>(),
8694       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8695
8696
8697   // Add an accessor that is not accessible by cross-domain JS code.
8698   global_template->SetAccessor(v8_str("blocked_prop"),
8699                                UnreachableGetter, UnreachableSetter,
8700                                v8::Handle<Value>(),
8701                                v8::DEFAULT);
8702
8703   // Create an environment
8704   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8705   context0->Enter();
8706
8707   v8::Handle<v8::Object> global0 = context0->Global();
8708
8709   v8::Local<Context> context1 = Context::New(isolate);
8710   context1->Enter();
8711   v8::Handle<v8::Object> global1 = context1->Global();
8712   global1->Set(v8_str("other"), global0);
8713
8714   // Regression test for issue 1154.
8715   CHECK(CompileRun("Object.keys(other)").IsEmpty());
8716   CHECK(CompileRun("other.blocked_prop").IsEmpty());
8717
8718   // Regression test for issue 1027.
8719   CompileRun("Object.defineProperty(\n"
8720              "  other, 'blocked_prop', {configurable: false})");
8721   CHECK(CompileRun("other.blocked_prop").IsEmpty());
8722   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8723             .IsEmpty());
8724
8725   // Regression test for issue 1171.
8726   ExpectTrue("Object.isExtensible(other)");
8727   CompileRun("Object.preventExtensions(other)");
8728   ExpectTrue("Object.isExtensible(other)");
8729
8730   // Object.seal and Object.freeze.
8731   CompileRun("Object.freeze(other)");
8732   ExpectTrue("Object.isExtensible(other)");
8733
8734   CompileRun("Object.seal(other)");
8735   ExpectTrue("Object.isExtensible(other)");
8736
8737   // Regression test for issue 1250.
8738   // Make sure that we can set the accessible accessors value using normal
8739   // assignment.
8740   CompileRun("other.accessible_prop = 42");
8741   CHECK_EQ(42, g_echo_value);
8742
8743   v8::Handle<Value> value;
8744   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8745   value = CompileRun("other.accessible_prop == 42");
8746   CHECK(value->IsTrue());
8747 }
8748
8749
8750 static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name,
8751                                 v8::AccessType type, Local<Value> data) {
8752   i::PrintF("Access blocked.\n");
8753   return false;
8754 }
8755
8756
8757 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8758   v8::Isolate* isolate = CcTest::isolate();
8759   v8::HandleScope handle_scope(isolate);
8760   v8::Handle<v8::ObjectTemplate> obj_template =
8761       v8::ObjectTemplate::New(isolate);
8762
8763   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
8764   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8765
8766   // Create an environment
8767   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8768   context0->Enter();
8769
8770   v8::Handle<v8::Object> global0 = context0->Global();
8771
8772   v8::HandleScope scope1(CcTest::isolate());
8773
8774   v8::Local<Context> context1 = Context::New(isolate);
8775   context1->Enter();
8776
8777   v8::Handle<v8::Object> global1 = context1->Global();
8778   global1->Set(v8_str("other"), global0);
8779   global1->Set(v8_str("object"), obj_template->NewInstance());
8780
8781   v8::Handle<Value> value;
8782
8783   // Attempt to get the property names of the other global object and
8784   // of an object that requires access checks.  Accessing the other
8785   // global object should be blocked by access checks on the global
8786   // proxy object.  Accessing the object that requires access checks
8787   // is blocked by the access checks on the object itself.
8788   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8789   CHECK(value.IsEmpty());
8790
8791   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8792   CHECK(value.IsEmpty());
8793
8794   context1->Exit();
8795   context0->Exit();
8796 }
8797
8798
8799 TEST(SuperAccessControl) {
8800   i::FLAG_allow_natives_syntax = true;
8801   i::FLAG_harmony_classes = true;
8802   i::FLAG_harmony_object_literals = true;
8803   v8::Isolate* isolate = CcTest::isolate();
8804   v8::HandleScope handle_scope(isolate);
8805   v8::Handle<v8::ObjectTemplate> obj_template =
8806       v8::ObjectTemplate::New(isolate);
8807   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8808   LocalContext env;
8809   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8810
8811   {
8812     v8::TryCatch try_catch;
8813     CompileRun(
8814         "var f = { m() { return super.hasOwnProperty; } }.m;"
8815         "var m = %ToMethod(f, prohibited);"
8816         "m();");
8817     CHECK(try_catch.HasCaught());
8818   }
8819
8820   {
8821     v8::TryCatch try_catch;
8822     CompileRun(
8823         "var f = {m() { return super[42]; } }.m;"
8824         "var m = %ToMethod(f, prohibited);"
8825         "m();");
8826     CHECK(try_catch.HasCaught());
8827   }
8828
8829   {
8830     v8::TryCatch try_catch;
8831     CompileRun(
8832         "var f = {m() { super.hasOwnProperty = function () {}; } }.m;"
8833         "var m = %ToMethod(f, prohibited);"
8834         "m();");
8835     CHECK(try_catch.HasCaught());
8836   }
8837
8838   {
8839     v8::TryCatch try_catch;
8840     CompileRun(
8841         "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
8842         "var f = {"
8843         "  m() { "
8844         "    'use strict';"
8845         "    super.x = function () {};"
8846         "  }"
8847         "}.m;"
8848         "var m = %ToMethod(f, prohibited);"
8849         "m();");
8850     CHECK(try_catch.HasCaught());
8851   }
8852 }
8853
8854
8855 TEST(Regress470113) {
8856   i::FLAG_harmony_classes = true;
8857   i::FLAG_harmony_object_literals = true;
8858   v8::Isolate* isolate = CcTest::isolate();
8859   v8::HandleScope handle_scope(isolate);
8860   v8::Handle<v8::ObjectTemplate> obj_template =
8861       v8::ObjectTemplate::New(isolate);
8862   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8863   LocalContext env;
8864   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8865
8866   {
8867     v8::TryCatch try_catch;
8868     CompileRun(
8869         "'use strict';\n"
8870         "class C extends Object {\n"
8871         "   m() { super.powned = 'Powned!'; }\n"
8872         "}\n"
8873         "let c = new C();\n"
8874         "c.m.call(prohibited)");
8875
8876     CHECK(try_catch.HasCaught());
8877   }
8878 }
8879
8880
8881 static void ConstTenGetter(Local<String> name,
8882                            const v8::PropertyCallbackInfo<v8::Value>& info) {
8883   info.GetReturnValue().Set(v8_num(10));
8884 }
8885
8886
8887 THREADED_TEST(CrossDomainAccessors) {
8888   v8::Isolate* isolate = CcTest::isolate();
8889   v8::HandleScope handle_scope(isolate);
8890
8891   v8::Handle<v8::FunctionTemplate> func_template =
8892       v8::FunctionTemplate::New(isolate);
8893
8894   v8::Handle<v8::ObjectTemplate> global_template =
8895       func_template->InstanceTemplate();
8896
8897   v8::Handle<v8::ObjectTemplate> proto_template =
8898       func_template->PrototypeTemplate();
8899
8900   // Add an accessor to proto that's accessible by cross-domain JS code.
8901   proto_template->SetAccessor(v8_str("accessible"),
8902                               ConstTenGetter, 0,
8903                               v8::Handle<Value>(),
8904                               v8::ALL_CAN_READ);
8905
8906   // Add an accessor that is not accessible by cross-domain JS code.
8907   global_template->SetAccessor(v8_str("unreachable"),
8908                                UnreachableGetter, 0,
8909                                v8::Handle<Value>(),
8910                                v8::DEFAULT);
8911
8912   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8913   context0->Enter();
8914
8915   Local<v8::Object> global = context0->Global();
8916   // Add a normal property that shadows 'accessible'
8917   global->Set(v8_str("accessible"), v8_num(11));
8918
8919   // Enter a new context.
8920   v8::HandleScope scope1(CcTest::isolate());
8921   v8::Local<Context> context1 = Context::New(isolate);
8922   context1->Enter();
8923
8924   v8::Handle<v8::Object> global1 = context1->Global();
8925   global1->Set(v8_str("other"), global);
8926
8927   // Should return 10, instead of 11
8928   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8929   CHECK(value->IsNumber());
8930   CHECK_EQ(10, value->Int32Value());
8931
8932   value = v8_compile("other.unreachable")->Run();
8933   CHECK(value.IsEmpty());
8934
8935   context1->Exit();
8936   context0->Exit();
8937 }
8938
8939
8940 static int access_count = 0;
8941
8942 static bool AccessCounter(Local<v8::Object> global, Local<Value> name,
8943                           v8::AccessType type, Local<Value> data) {
8944   access_count++;
8945   return true;
8946 }
8947
8948
8949 // This one is too easily disturbed by other tests.
8950 TEST(AccessControlIC) {
8951   access_count = 0;
8952
8953   v8::Isolate* isolate = CcTest::isolate();
8954   v8::HandleScope handle_scope(isolate);
8955
8956   // Create an environment.
8957   v8::Local<Context> context0 = Context::New(isolate);
8958   context0->Enter();
8959
8960   // Create an object that requires access-check functions to be
8961   // called for cross-domain access.
8962   v8::Handle<v8::ObjectTemplate> object_template =
8963       v8::ObjectTemplate::New(isolate);
8964   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
8965   Local<v8::Object> object = object_template->NewInstance();
8966
8967   v8::HandleScope scope1(isolate);
8968
8969   // Create another environment.
8970   v8::Local<Context> context1 = Context::New(isolate);
8971   context1->Enter();
8972
8973   // Make easy access to the object from the other environment.
8974   v8::Handle<v8::Object> global1 = context1->Global();
8975   global1->Set(v8_str("obj"), object);
8976
8977   v8::Handle<Value> value;
8978
8979   // Check that the named access-control function is called every time.
8980   CompileRun("function testProp(obj) {"
8981              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
8982              "  for (var j = 0; j < 10; j++) obj.prop;"
8983              "  return obj.prop"
8984              "}");
8985   value = CompileRun("testProp(obj)");
8986   CHECK(value->IsNumber());
8987   CHECK_EQ(1, value->Int32Value());
8988   CHECK_EQ(21, access_count);
8989
8990   // Check that the named access-control function is called every time.
8991   CompileRun("var p = 'prop';"
8992              "function testKeyed(obj) {"
8993              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
8994              "  for (var j = 0; j < 10; j++) obj[p];"
8995              "  return obj[p];"
8996              "}");
8997   // Use obj which requires access checks.  No inline caching is used
8998   // in that case.
8999   value = CompileRun("testKeyed(obj)");
9000   CHECK(value->IsNumber());
9001   CHECK_EQ(1, value->Int32Value());
9002   CHECK_EQ(42, access_count);
9003   // Force the inline caches into generic state and try again.
9004   CompileRun("testKeyed({ a: 0 })");
9005   CompileRun("testKeyed({ b: 0 })");
9006   value = CompileRun("testKeyed(obj)");
9007   CHECK(value->IsNumber());
9008   CHECK_EQ(1, value->Int32Value());
9009   CHECK_EQ(63, access_count);
9010
9011   // Check that the indexed access-control function is called every time.
9012   access_count = 0;
9013
9014   CompileRun("function testIndexed(obj) {"
9015              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9016              "  for (var j = 0; j < 10; j++) obj[0];"
9017              "  return obj[0]"
9018              "}");
9019   value = CompileRun("testIndexed(obj)");
9020   CHECK(value->IsNumber());
9021   CHECK_EQ(1, value->Int32Value());
9022   CHECK_EQ(21, access_count);
9023   // Force the inline caches into generic state.
9024   CompileRun("testIndexed(new Array(1))");
9025   // Test that the indexed access check is called.
9026   value = CompileRun("testIndexed(obj)");
9027   CHECK(value->IsNumber());
9028   CHECK_EQ(1, value->Int32Value());
9029   CHECK_EQ(42, access_count);
9030
9031   access_count = 0;
9032   // Check that the named access check is called when invoking
9033   // functions on an object that requires access checks.
9034   CompileRun("obj.f = function() {}");
9035   CompileRun("function testCallNormal(obj) {"
9036              "  for (var i = 0; i < 10; i++) obj.f();"
9037              "}");
9038   CompileRun("testCallNormal(obj)");
9039   printf("%i\n", access_count);
9040   CHECK_EQ(11, access_count);
9041
9042   // Force obj into slow case.
9043   value = CompileRun("delete obj.prop");
9044   CHECK(value->BooleanValue());
9045   // Force inline caches into dictionary probing mode.
9046   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9047   // Test that the named access check is called.
9048   value = CompileRun("testProp(obj);");
9049   CHECK(value->IsNumber());
9050   CHECK_EQ(1, value->Int32Value());
9051   CHECK_EQ(33, access_count);
9052
9053   // Force the call inline cache into dictionary probing mode.
9054   CompileRun("o.f = function() {}; testCallNormal(o)");
9055   // Test that the named access check is still called for each
9056   // invocation of the function.
9057   value = CompileRun("testCallNormal(obj)");
9058   CHECK_EQ(43, access_count);
9059
9060   context1->Exit();
9061   context0->Exit();
9062 }
9063
9064
9065 THREADED_TEST(Version) { v8::V8::GetVersion(); }
9066
9067
9068 static void InstanceFunctionCallback(
9069     const v8::FunctionCallbackInfo<v8::Value>& args) {
9070   ApiTestFuzzer::Fuzz();
9071   args.GetReturnValue().Set(v8_num(12));
9072 }
9073
9074
9075 THREADED_TEST(InstanceProperties) {
9076   LocalContext context;
9077   v8::Isolate* isolate = context->GetIsolate();
9078   v8::HandleScope handle_scope(isolate);
9079
9080   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9081   Local<ObjectTemplate> instance = t->InstanceTemplate();
9082
9083   instance->Set(v8_str("x"), v8_num(42));
9084   instance->Set(v8_str("f"),
9085                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9086
9087   Local<Value> o = t->GetFunction()->NewInstance();
9088
9089   context->Global()->Set(v8_str("i"), o);
9090   Local<Value> value = CompileRun("i.x");
9091   CHECK_EQ(42, value->Int32Value());
9092
9093   value = CompileRun("i.f()");
9094   CHECK_EQ(12, value->Int32Value());
9095 }
9096
9097
9098 static void GlobalObjectInstancePropertiesGet(
9099     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
9100   ApiTestFuzzer::Fuzz();
9101 }
9102
9103
9104 THREADED_TEST(GlobalObjectInstanceProperties) {
9105   v8::Isolate* isolate = CcTest::isolate();
9106   v8::HandleScope handle_scope(isolate);
9107
9108   Local<Value> global_object;
9109
9110   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9111   t->InstanceTemplate()->SetHandler(
9112       v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
9113   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9114   instance_template->Set(v8_str("x"), v8_num(42));
9115   instance_template->Set(v8_str("f"),
9116                          v8::FunctionTemplate::New(isolate,
9117                                                    InstanceFunctionCallback));
9118
9119   // The script to check how Crankshaft compiles missing global function
9120   // invocations.  function g is not defined and should throw on call.
9121   const char* script =
9122       "function wrapper(call) {"
9123       "  var x = 0, y = 1;"
9124       "  for (var i = 0; i < 1000; i++) {"
9125       "    x += i * 100;"
9126       "    y += i * 100;"
9127       "  }"
9128       "  if (call) g();"
9129       "}"
9130       "for (var i = 0; i < 17; i++) wrapper(false);"
9131       "var thrown = 0;"
9132       "try { wrapper(true); } catch (e) { thrown = 1; };"
9133       "thrown";
9134
9135   {
9136     LocalContext env(NULL, instance_template);
9137     // Hold on to the global object so it can be used again in another
9138     // environment initialization.
9139     global_object = env->Global();
9140
9141     Local<Value> value = CompileRun("x");
9142     CHECK_EQ(42, value->Int32Value());
9143     value = CompileRun("f()");
9144     CHECK_EQ(12, value->Int32Value());
9145     value = CompileRun(script);
9146     CHECK_EQ(1, value->Int32Value());
9147   }
9148
9149   {
9150     // Create new environment reusing the global object.
9151     LocalContext env(NULL, instance_template, global_object);
9152     Local<Value> value = CompileRun("x");
9153     CHECK_EQ(42, value->Int32Value());
9154     value = CompileRun("f()");
9155     CHECK_EQ(12, value->Int32Value());
9156     value = CompileRun(script);
9157     CHECK_EQ(1, value->Int32Value());
9158   }
9159 }
9160
9161
9162 THREADED_TEST(CallKnownGlobalReceiver) {
9163   v8::Isolate* isolate = CcTest::isolate();
9164   v8::HandleScope handle_scope(isolate);
9165
9166   Local<Value> global_object;
9167
9168   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9169   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9170
9171   // The script to check that we leave global object not
9172   // global object proxy on stack when we deoptimize from inside
9173   // arguments evaluation.
9174   // To provoke error we need to both force deoptimization
9175   // from arguments evaluation and to force CallIC to take
9176   // CallIC_Miss code path that can't cope with global proxy.
9177   const char* script =
9178       "function bar(x, y) { try { } finally { } }"
9179       "function baz(x) { try { } finally { } }"
9180       "function bom(x) { try { } finally { } }"
9181       "function foo(x) { bar([x], bom(2)); }"
9182       "for (var i = 0; i < 10000; i++) foo(1);"
9183       "foo";
9184
9185   Local<Value> foo;
9186   {
9187     LocalContext env(NULL, instance_template);
9188     // Hold on to the global object so it can be used again in another
9189     // environment initialization.
9190     global_object = env->Global();
9191     foo = CompileRun(script);
9192   }
9193
9194   {
9195     // Create new environment reusing the global object.
9196     LocalContext env(NULL, instance_template, global_object);
9197     env->Global()->Set(v8_str("foo"), foo);
9198     CompileRun("foo()");
9199   }
9200 }
9201
9202
9203 static void ShadowFunctionCallback(
9204     const v8::FunctionCallbackInfo<v8::Value>& args) {
9205   ApiTestFuzzer::Fuzz();
9206   args.GetReturnValue().Set(v8_num(42));
9207 }
9208
9209
9210 static int shadow_y;
9211 static int shadow_y_setter_call_count;
9212 static int shadow_y_getter_call_count;
9213
9214
9215 static void ShadowYSetter(Local<String>,
9216                           Local<Value>,
9217                           const v8::PropertyCallbackInfo<void>&) {
9218   shadow_y_setter_call_count++;
9219   shadow_y = 42;
9220 }
9221
9222
9223 static void ShadowYGetter(Local<String> name,
9224                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9225   ApiTestFuzzer::Fuzz();
9226   shadow_y_getter_call_count++;
9227   info.GetReturnValue().Set(v8_num(shadow_y));
9228 }
9229
9230
9231 static void ShadowIndexedGet(uint32_t index,
9232                              const v8::PropertyCallbackInfo<v8::Value>&) {
9233 }
9234
9235
9236 static void ShadowNamedGet(Local<Name> key,
9237                            const v8::PropertyCallbackInfo<v8::Value>&) {}
9238
9239
9240 THREADED_TEST(ShadowObject) {
9241   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9242   v8::Isolate* isolate = CcTest::isolate();
9243   v8::HandleScope handle_scope(isolate);
9244
9245   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9246   LocalContext context(NULL, global_template);
9247
9248   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9249   t->InstanceTemplate()->SetHandler(
9250       v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
9251   t->InstanceTemplate()->SetHandler(
9252       v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
9253   Local<ObjectTemplate> proto = t->PrototypeTemplate();
9254   Local<ObjectTemplate> instance = t->InstanceTemplate();
9255
9256   proto->Set(v8_str("f"),
9257              v8::FunctionTemplate::New(isolate,
9258                                        ShadowFunctionCallback,
9259                                        Local<Value>()));
9260   proto->Set(v8_str("x"), v8_num(12));
9261
9262   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9263
9264   Local<Value> o = t->GetFunction()->NewInstance();
9265   context->Global()->Set(v8_str("__proto__"), o);
9266
9267   Local<Value> value =
9268       CompileRun("this.propertyIsEnumerable(0)");
9269   CHECK(value->IsBoolean());
9270   CHECK(!value->BooleanValue());
9271
9272   value = CompileRun("x");
9273   CHECK_EQ(12, value->Int32Value());
9274
9275   value = CompileRun("f()");
9276   CHECK_EQ(42, value->Int32Value());
9277
9278   CompileRun("y = 43");
9279   CHECK_EQ(1, shadow_y_setter_call_count);
9280   value = CompileRun("y");
9281   CHECK_EQ(1, shadow_y_getter_call_count);
9282   CHECK_EQ(42, value->Int32Value());
9283 }
9284
9285
9286 THREADED_TEST(HiddenPrototype) {
9287   LocalContext context;
9288   v8::Isolate* isolate = context->GetIsolate();
9289   v8::HandleScope handle_scope(isolate);
9290
9291   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9292   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9293   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9294   t1->SetHiddenPrototype(true);
9295   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9296   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9297   t2->SetHiddenPrototype(true);
9298   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9299   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9300   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9301
9302   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9303   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9304   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9305   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9306
9307   // Setting the prototype on an object skips hidden prototypes.
9308   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9309   o0->Set(v8_str("__proto__"), o1);
9310   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9311   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9312   o0->Set(v8_str("__proto__"), o2);
9313   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9314   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9315   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9316   o0->Set(v8_str("__proto__"), o3);
9317   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9318   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9319   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9320   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9321
9322   // Getting the prototype of o0 should get the first visible one
9323   // which is o3.  Therefore, z should not be defined on the prototype
9324   // object.
9325   Local<Value> proto = o0->Get(v8_str("__proto__"));
9326   CHECK(proto->IsObject());
9327   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9328 }
9329
9330
9331 THREADED_TEST(HiddenPrototypeSet) {
9332   LocalContext context;
9333   v8::Isolate* isolate = context->GetIsolate();
9334   v8::HandleScope handle_scope(isolate);
9335
9336   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
9337   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
9338   ht->SetHiddenPrototype(true);
9339   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
9340   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9341
9342   Local<v8::Object> o = ot->GetFunction()->NewInstance();
9343   Local<v8::Object> h = ht->GetFunction()->NewInstance();
9344   Local<v8::Object> p = pt->GetFunction()->NewInstance();
9345   o->Set(v8_str("__proto__"), h);
9346   h->Set(v8_str("__proto__"), p);
9347
9348   // Setting a property that exists on the hidden prototype goes there.
9349   o->Set(v8_str("x"), v8_num(7));
9350   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9351   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9352   CHECK(p->Get(v8_str("x"))->IsUndefined());
9353
9354   // Setting a new property should not be forwarded to the hidden prototype.
9355   o->Set(v8_str("y"), v8_num(6));
9356   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9357   CHECK(h->Get(v8_str("y"))->IsUndefined());
9358   CHECK(p->Get(v8_str("y"))->IsUndefined());
9359
9360   // Setting a property that only exists on a prototype of the hidden prototype
9361   // is treated normally again.
9362   p->Set(v8_str("z"), v8_num(8));
9363   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9364   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9365   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9366   o->Set(v8_str("z"), v8_num(9));
9367   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9368   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9369   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9370 }
9371
9372
9373 // Regression test for issue 2457.
9374 THREADED_TEST(HiddenPrototypeIdentityHash) {
9375   LocalContext context;
9376   v8::HandleScope handle_scope(context->GetIsolate());
9377
9378   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
9379   t->SetHiddenPrototype(true);
9380   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9381   Handle<Object> p = t->GetFunction()->NewInstance();
9382   Handle<Object> o = Object::New(context->GetIsolate());
9383   o->SetPrototype(p);
9384
9385   int hash = o->GetIdentityHash();
9386   USE(hash);
9387   o->Set(v8_str("foo"), v8_num(42));
9388   DCHECK_EQ(hash, o->GetIdentityHash());
9389 }
9390
9391
9392 THREADED_TEST(SetPrototype) {
9393   LocalContext context;
9394   v8::Isolate* isolate = context->GetIsolate();
9395   v8::HandleScope handle_scope(isolate);
9396
9397   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9398   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9399   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9400   t1->SetHiddenPrototype(true);
9401   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9402   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9403   t2->SetHiddenPrototype(true);
9404   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9405   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9406   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9407
9408   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9409   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9410   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9411   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9412
9413   // Setting the prototype on an object does not skip hidden prototypes.
9414   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9415   CHECK(o0->SetPrototype(o1));
9416   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9417   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9418   CHECK(o1->SetPrototype(o2));
9419   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9420   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9421   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9422   CHECK(o2->SetPrototype(o3));
9423   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9424   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9425   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9426   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9427
9428   // Getting the prototype of o0 should get the first visible one
9429   // which is o3.  Therefore, z should not be defined on the prototype
9430   // object.
9431   Local<Value> proto = o0->Get(v8_str("__proto__"));
9432   CHECK(proto->IsObject());
9433   CHECK(proto.As<v8::Object>()->Equals(o3));
9434
9435   // However, Object::GetPrototype ignores hidden prototype.
9436   Local<Value> proto0 = o0->GetPrototype();
9437   CHECK(proto0->IsObject());
9438   CHECK(proto0.As<v8::Object>()->Equals(o1));
9439
9440   Local<Value> proto1 = o1->GetPrototype();
9441   CHECK(proto1->IsObject());
9442   CHECK(proto1.As<v8::Object>()->Equals(o2));
9443
9444   Local<Value> proto2 = o2->GetPrototype();
9445   CHECK(proto2->IsObject());
9446   CHECK(proto2.As<v8::Object>()->Equals(o3));
9447 }
9448
9449
9450 // Getting property names of an object with a prototype chain that
9451 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
9452 // crash the runtime.
9453 THREADED_TEST(Regress91517) {
9454   i::FLAG_allow_natives_syntax = true;
9455   LocalContext context;
9456   v8::Isolate* isolate = context->GetIsolate();
9457   v8::HandleScope handle_scope(isolate);
9458
9459   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9460   t1->SetHiddenPrototype(true);
9461   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9462   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9463   t2->SetHiddenPrototype(true);
9464   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9465   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
9466   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9467   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9468   t3->SetHiddenPrototype(true);
9469   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9470   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
9471   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9472
9473   // Force dictionary-based properties.
9474   i::ScopedVector<char> name_buf(1024);
9475   for (int i = 1; i <= 1000; i++) {
9476     i::SNPrintF(name_buf, "sdf%d", i);
9477     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9478   }
9479
9480   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9481   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9482   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9483   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9484
9485   // Create prototype chain of hidden prototypes.
9486   CHECK(o4->SetPrototype(o3));
9487   CHECK(o3->SetPrototype(o2));
9488   CHECK(o2->SetPrototype(o1));
9489
9490   // Call the runtime version of GetOwnPropertyNames() on the natively
9491   // created object through JavaScript.
9492   context->Global()->Set(v8_str("obj"), o4);
9493   // PROPERTY_ATTRIBUTES_NONE = 0
9494   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9495
9496   ExpectInt32("names.length", 1006);
9497   ExpectTrue("names.indexOf(\"baz\") >= 0");
9498   ExpectTrue("names.indexOf(\"boo\") >= 0");
9499   ExpectTrue("names.indexOf(\"foo\") >= 0");
9500   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9501   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9502   ExpectFalse("names[1005] == undefined");
9503 }
9504
9505
9506 // Getting property names of an object with a hidden and inherited
9507 // prototype should not duplicate the accessor properties inherited.
9508 THREADED_TEST(Regress269562) {
9509   i::FLAG_allow_natives_syntax = true;
9510   LocalContext context;
9511   v8::HandleScope handle_scope(context->GetIsolate());
9512
9513   Local<v8::FunctionTemplate> t1 =
9514       v8::FunctionTemplate::New(context->GetIsolate());
9515   t1->SetHiddenPrototype(true);
9516
9517   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
9518   i1->SetAccessor(v8_str("foo"),
9519                   SimpleAccessorGetter, SimpleAccessorSetter);
9520   i1->SetAccessor(v8_str("bar"),
9521                   SimpleAccessorGetter, SimpleAccessorSetter);
9522   i1->SetAccessor(v8_str("baz"),
9523                   SimpleAccessorGetter, SimpleAccessorSetter);
9524   i1->Set(v8_str("n1"), v8_num(1));
9525   i1->Set(v8_str("n2"), v8_num(2));
9526
9527   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9528   Local<v8::FunctionTemplate> t2 =
9529       v8::FunctionTemplate::New(context->GetIsolate());
9530   t2->SetHiddenPrototype(true);
9531
9532   // Inherit from t1 and mark prototype as hidden.
9533   t2->Inherit(t1);
9534   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
9535
9536   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9537   CHECK(o2->SetPrototype(o1));
9538
9539   v8::Local<v8::Symbol> sym =
9540       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
9541   o1->Set(sym, v8_num(3));
9542   o1->SetHiddenValue(
9543       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
9544
9545   // Call the runtime version of GetOwnPropertyNames() on
9546   // the natively created object through JavaScript.
9547   context->Global()->Set(v8_str("obj"), o2);
9548   context->Global()->Set(v8_str("sym"), sym);
9549   // PROPERTY_ATTRIBUTES_NONE = 0
9550   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9551
9552   ExpectInt32("names.length", 7);
9553   ExpectTrue("names.indexOf(\"foo\") >= 0");
9554   ExpectTrue("names.indexOf(\"bar\") >= 0");
9555   ExpectTrue("names.indexOf(\"baz\") >= 0");
9556   ExpectTrue("names.indexOf(\"n1\") >= 0");
9557   ExpectTrue("names.indexOf(\"n2\") >= 0");
9558   ExpectTrue("names.indexOf(sym) >= 0");
9559   ExpectTrue("names.indexOf(\"mine\") >= 0");
9560 }
9561
9562
9563 THREADED_TEST(FunctionReadOnlyPrototype) {
9564   LocalContext context;
9565   v8::Isolate* isolate = context->GetIsolate();
9566   v8::HandleScope handle_scope(isolate);
9567
9568   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9569   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9570   t1->ReadOnlyPrototype();
9571   context->Global()->Set(v8_str("func1"), t1->GetFunction());
9572   // Configured value of ReadOnly flag.
9573   CHECK(CompileRun(
9574       "(function() {"
9575       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9576       "  return (descriptor['writable'] == false);"
9577       "})()")->BooleanValue());
9578   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9579   CHECK_EQ(42,
9580            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9581
9582   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9583   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9584   context->Global()->Set(v8_str("func2"), t2->GetFunction());
9585   // Default value of ReadOnly flag.
9586   CHECK(CompileRun(
9587       "(function() {"
9588       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9589       "  return (descriptor['writable'] == true);"
9590       "})()")->BooleanValue());
9591   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9592 }
9593
9594
9595 THREADED_TEST(SetPrototypeThrows) {
9596   LocalContext context;
9597   v8::Isolate* isolate = context->GetIsolate();
9598   v8::HandleScope handle_scope(isolate);
9599
9600   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9601
9602   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9603   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9604
9605   CHECK(o0->SetPrototype(o1));
9606   // If setting the prototype leads to the cycle, SetPrototype should
9607   // return false and keep VM in sane state.
9608   v8::TryCatch try_catch;
9609   CHECK(!o1->SetPrototype(o0));
9610   CHECK(!try_catch.HasCaught());
9611   DCHECK(!CcTest::i_isolate()->has_pending_exception());
9612
9613   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9614 }
9615
9616
9617 THREADED_TEST(FunctionRemovePrototype) {
9618   LocalContext context;
9619   v8::Isolate* isolate = context->GetIsolate();
9620   v8::HandleScope handle_scope(isolate);
9621
9622   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9623   t1->RemovePrototype();
9624   Local<v8::Function> fun = t1->GetFunction();
9625   context->Global()->Set(v8_str("fun"), fun);
9626   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9627
9628   v8::TryCatch try_catch;
9629   CompileRun("new fun()");
9630   CHECK(try_catch.HasCaught());
9631
9632   try_catch.Reset();
9633   fun->NewInstance();
9634   CHECK(try_catch.HasCaught());
9635 }
9636
9637
9638 THREADED_TEST(GetterSetterExceptions) {
9639   LocalContext context;
9640   v8::Isolate* isolate = context->GetIsolate();
9641   v8::HandleScope handle_scope(isolate);
9642   CompileRun(
9643       "function Foo() { };"
9644       "function Throw() { throw 5; };"
9645       "var x = { };"
9646       "x.__defineSetter__('set', Throw);"
9647       "x.__defineGetter__('get', Throw);");
9648   Local<v8::Object> x =
9649       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9650   v8::TryCatch try_catch;
9651   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9652   x->Get(v8_str("get"));
9653   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9654   x->Get(v8_str("get"));
9655   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9656   x->Get(v8_str("get"));
9657   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9658   x->Get(v8_str("get"));
9659 }
9660
9661
9662 THREADED_TEST(Constructor) {
9663   LocalContext context;
9664   v8::Isolate* isolate = context->GetIsolate();
9665   v8::HandleScope handle_scope(isolate);
9666   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9667   templ->SetClassName(v8_str("Fun"));
9668   Local<Function> cons = templ->GetFunction();
9669   context->Global()->Set(v8_str("Fun"), cons);
9670   Local<v8::Object> inst = cons->NewInstance();
9671   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9672   CHECK(obj->IsJSObject());
9673   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9674   CHECK(value->BooleanValue());
9675 }
9676
9677
9678 static void ConstructorCallback(
9679     const v8::FunctionCallbackInfo<v8::Value>& args) {
9680   ApiTestFuzzer::Fuzz();
9681   Local<Object> This;
9682
9683   if (args.IsConstructCall()) {
9684     Local<Object> Holder = args.Holder();
9685     This = Object::New(args.GetIsolate());
9686     Local<Value> proto = Holder->GetPrototype();
9687     if (proto->IsObject()) {
9688       This->SetPrototype(proto);
9689     }
9690   } else {
9691     This = args.This();
9692   }
9693
9694   This->Set(v8_str("a"), args[0]);
9695   args.GetReturnValue().Set(This);
9696 }
9697
9698
9699 static void FakeConstructorCallback(
9700     const v8::FunctionCallbackInfo<v8::Value>& args) {
9701   ApiTestFuzzer::Fuzz();
9702   args.GetReturnValue().Set(args[0]);
9703 }
9704
9705
9706 THREADED_TEST(ConstructorForObject) {
9707   LocalContext context;
9708   v8::Isolate* isolate = context->GetIsolate();
9709   v8::HandleScope handle_scope(isolate);
9710
9711   {
9712     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9713     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9714     Local<Object> instance = instance_template->NewInstance();
9715     context->Global()->Set(v8_str("obj"), instance);
9716     v8::TryCatch try_catch;
9717     Local<Value> value;
9718     CHECK(!try_catch.HasCaught());
9719
9720     // Call the Object's constructor with a 32-bit signed integer.
9721     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9722     CHECK(!try_catch.HasCaught());
9723     CHECK(value->IsInt32());
9724     CHECK_EQ(28, value->Int32Value());
9725
9726     Local<Value> args1[] = {v8_num(28)};
9727     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9728     CHECK(value_obj1->IsObject());
9729     Local<Object> object1 = Local<Object>::Cast(value_obj1);
9730     value = object1->Get(v8_str("a"));
9731     CHECK(value->IsInt32());
9732     CHECK(!try_catch.HasCaught());
9733     CHECK_EQ(28, value->Int32Value());
9734
9735     // Call the Object's constructor with a String.
9736     value =
9737         CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
9738     CHECK(!try_catch.HasCaught());
9739     CHECK(value->IsString());
9740     String::Utf8Value string_value1(value->ToString(isolate));
9741     CHECK_EQ(0, strcmp("tipli", *string_value1));
9742
9743     Local<Value> args2[] = {v8_str("tipli")};
9744     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9745     CHECK(value_obj2->IsObject());
9746     Local<Object> object2 = Local<Object>::Cast(value_obj2);
9747     value = object2->Get(v8_str("a"));
9748     CHECK(!try_catch.HasCaught());
9749     CHECK(value->IsString());
9750     String::Utf8Value string_value2(value->ToString(isolate));
9751     CHECK_EQ(0, strcmp("tipli", *string_value2));
9752
9753     // Call the Object's constructor with a Boolean.
9754     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9755     CHECK(!try_catch.HasCaught());
9756     CHECK(value->IsBoolean());
9757     CHECK_EQ(true, value->BooleanValue());
9758
9759     Handle<Value> args3[] = {v8::True(isolate)};
9760     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9761     CHECK(value_obj3->IsObject());
9762     Local<Object> object3 = Local<Object>::Cast(value_obj3);
9763     value = object3->Get(v8_str("a"));
9764     CHECK(!try_catch.HasCaught());
9765     CHECK(value->IsBoolean());
9766     CHECK_EQ(true, value->BooleanValue());
9767
9768     // Call the Object's constructor with undefined.
9769     Handle<Value> args4[] = {v8::Undefined(isolate)};
9770     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9771     CHECK(value_obj4->IsObject());
9772     Local<Object> object4 = Local<Object>::Cast(value_obj4);
9773     value = object4->Get(v8_str("a"));
9774     CHECK(!try_catch.HasCaught());
9775     CHECK(value->IsUndefined());
9776
9777     // Call the Object's constructor with null.
9778     Handle<Value> args5[] = {v8::Null(isolate)};
9779     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9780     CHECK(value_obj5->IsObject());
9781     Local<Object> object5 = Local<Object>::Cast(value_obj5);
9782     value = object5->Get(v8_str("a"));
9783     CHECK(!try_catch.HasCaught());
9784     CHECK(value->IsNull());
9785   }
9786
9787   // Check exception handling when there is no constructor set for the Object.
9788   {
9789     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9790     Local<Object> instance = instance_template->NewInstance();
9791     context->Global()->Set(v8_str("obj2"), instance);
9792     v8::TryCatch try_catch;
9793     Local<Value> value;
9794     CHECK(!try_catch.HasCaught());
9795
9796     value = CompileRun("new obj2(28)");
9797     CHECK(try_catch.HasCaught());
9798     String::Utf8Value exception_value1(try_catch.Exception());
9799     CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
9800     try_catch.Reset();
9801
9802     Local<Value> args[] = {v8_num(29)};
9803     value = instance->CallAsConstructor(1, args);
9804     CHECK(try_catch.HasCaught());
9805     String::Utf8Value exception_value2(try_catch.Exception());
9806     CHECK_EQ(
9807         0, strcmp("TypeError: #<Object> is not a function", *exception_value2));
9808     try_catch.Reset();
9809   }
9810
9811   // Check the case when constructor throws exception.
9812   {
9813     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9814     instance_template->SetCallAsFunctionHandler(ThrowValue);
9815     Local<Object> instance = instance_template->NewInstance();
9816     context->Global()->Set(v8_str("obj3"), instance);
9817     v8::TryCatch try_catch;
9818     Local<Value> value;
9819     CHECK(!try_catch.HasCaught());
9820
9821     value = CompileRun("new obj3(22)");
9822     CHECK(try_catch.HasCaught());
9823     String::Utf8Value exception_value1(try_catch.Exception());
9824     CHECK_EQ(0, strcmp("22", *exception_value1));
9825     try_catch.Reset();
9826
9827     Local<Value> args[] = {v8_num(23)};
9828     value = instance->CallAsConstructor(1, args);
9829     CHECK(try_catch.HasCaught());
9830     String::Utf8Value exception_value2(try_catch.Exception());
9831     CHECK_EQ(0, strcmp("23", *exception_value2));
9832     try_catch.Reset();
9833   }
9834
9835   // Check whether constructor returns with an object or non-object.
9836   {
9837     Local<FunctionTemplate> function_template =
9838         FunctionTemplate::New(isolate, FakeConstructorCallback);
9839     Local<Function> function = function_template->GetFunction();
9840     Local<Object> instance1 = function;
9841     context->Global()->Set(v8_str("obj4"), instance1);
9842     v8::TryCatch try_catch;
9843     Local<Value> value;
9844     CHECK(!try_catch.HasCaught());
9845
9846     CHECK(instance1->IsObject());
9847     CHECK(instance1->IsFunction());
9848
9849     value = CompileRun("new obj4(28)");
9850     CHECK(!try_catch.HasCaught());
9851     CHECK(value->IsObject());
9852
9853     Local<Value> args1[] = {v8_num(28)};
9854     value = instance1->CallAsConstructor(1, args1);
9855     CHECK(!try_catch.HasCaught());
9856     CHECK(value->IsObject());
9857
9858     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9859     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9860     Local<Object> instance2 = instance_template->NewInstance();
9861     context->Global()->Set(v8_str("obj5"), instance2);
9862     CHECK(!try_catch.HasCaught());
9863
9864     CHECK(instance2->IsObject());
9865     CHECK(!instance2->IsFunction());
9866
9867     value = CompileRun("new obj5(28)");
9868     CHECK(!try_catch.HasCaught());
9869     CHECK(!value->IsObject());
9870
9871     Local<Value> args2[] = {v8_num(28)};
9872     value = instance2->CallAsConstructor(1, args2);
9873     CHECK(!try_catch.HasCaught());
9874     CHECK(!value->IsObject());
9875   }
9876 }
9877
9878
9879 THREADED_TEST(FunctionDescriptorException) {
9880   LocalContext context;
9881   v8::Isolate* isolate = context->GetIsolate();
9882   v8::HandleScope handle_scope(isolate);
9883   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9884   templ->SetClassName(v8_str("Fun"));
9885   Local<Function> cons = templ->GetFunction();
9886   context->Global()->Set(v8_str("Fun"), cons);
9887   Local<Value> value = CompileRun(
9888       "function test() {"
9889       "  try {"
9890       "    (new Fun()).blah()"
9891       "  } catch (e) {"
9892       "    var str = String(e);"
9893       // "    if (str.indexOf('TypeError') == -1) return 1;"
9894       // "    if (str.indexOf('[object Fun]') != -1) return 2;"
9895       // "    if (str.indexOf('#<Fun>') == -1) return 3;"
9896       "    return 0;"
9897       "  }"
9898       "  return 4;"
9899       "}"
9900       "test();");
9901   CHECK_EQ(0, value->Int32Value());
9902 }
9903
9904
9905 THREADED_TEST(EvalAliasedDynamic) {
9906   LocalContext current;
9907   v8::HandleScope scope(current->GetIsolate());
9908
9909   // Tests where aliased eval can only be resolved dynamically.
9910   Local<Script> script = v8_compile(
9911       "function f(x) { "
9912       "  var foo = 2;"
9913       "  with (x) { return eval('foo'); }"
9914       "}"
9915       "foo = 0;"
9916       "result1 = f(new Object());"
9917       "result2 = f(this);"
9918       "var x = new Object();"
9919       "x.eval = function(x) { return 1; };"
9920       "result3 = f(x);");
9921   script->Run();
9922   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9923   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9924   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9925
9926   v8::TryCatch try_catch;
9927   script = v8_compile(
9928       "function f(x) { "
9929       "  var bar = 2;"
9930       "  with (x) { return eval('bar'); }"
9931       "}"
9932       "result4 = f(this)");
9933   script->Run();
9934   CHECK(!try_catch.HasCaught());
9935   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9936
9937   try_catch.Reset();
9938 }
9939
9940
9941 THREADED_TEST(CrossEval) {
9942   v8::HandleScope scope(CcTest::isolate());
9943   LocalContext other;
9944   LocalContext current;
9945
9946   Local<String> token = v8_str("<security token>");
9947   other->SetSecurityToken(token);
9948   current->SetSecurityToken(token);
9949
9950   // Set up reference from current to other.
9951   current->Global()->Set(v8_str("other"), other->Global());
9952
9953   // Check that new variables are introduced in other context.
9954   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
9955   script->Run();
9956   Local<Value> foo = other->Global()->Get(v8_str("foo"));
9957   CHECK_EQ(1234, foo->Int32Value());
9958   CHECK(!current->Global()->Has(v8_str("foo")));
9959
9960   // Check that writing to non-existing properties introduces them in
9961   // the other context.
9962   script = v8_compile("other.eval('na = 1234')");
9963   script->Run();
9964   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9965   CHECK(!current->Global()->Has(v8_str("na")));
9966
9967   // Check that global variables in current context are not visible in other
9968   // context.
9969   v8::TryCatch try_catch;
9970   script = v8_compile("var bar = 42; other.eval('bar');");
9971   Local<Value> result = script->Run();
9972   CHECK(try_catch.HasCaught());
9973   try_catch.Reset();
9974
9975   // Check that local variables in current context are not visible in other
9976   // context.
9977   script = v8_compile(
9978       "(function() { "
9979       "  var baz = 87;"
9980       "  return other.eval('baz');"
9981       "})();");
9982   result = script->Run();
9983   CHECK(try_catch.HasCaught());
9984   try_catch.Reset();
9985
9986   // Check that global variables in the other environment are visible
9987   // when evaluting code.
9988   other->Global()->Set(v8_str("bis"), v8_num(1234));
9989   script = v8_compile("other.eval('bis')");
9990   CHECK_EQ(1234, script->Run()->Int32Value());
9991   CHECK(!try_catch.HasCaught());
9992
9993   // Check that the 'this' pointer points to the global object evaluating
9994   // code.
9995   other->Global()->Set(v8_str("t"), other->Global());
9996   script = v8_compile("other.eval('this == t')");
9997   result = script->Run();
9998   CHECK(result->IsTrue());
9999   CHECK(!try_catch.HasCaught());
10000
10001   // Check that variables introduced in with-statement are not visible in
10002   // other context.
10003   script = v8_compile("with({x:2}){other.eval('x')}");
10004   result = script->Run();
10005   CHECK(try_catch.HasCaught());
10006   try_catch.Reset();
10007
10008   // Check that you cannot use 'eval.call' with another object than the
10009   // current global object.
10010   script = v8_compile("other.y = 1; eval.call(other, 'y')");
10011   result = script->Run();
10012   CHECK(try_catch.HasCaught());
10013 }
10014
10015
10016 // Test that calling eval in a context which has been detached from
10017 // its global proxy works.
10018 THREADED_TEST(EvalInDetachedGlobal) {
10019   v8::Isolate* isolate = CcTest::isolate();
10020   v8::HandleScope scope(isolate);
10021
10022   v8::Local<Context> context0 = Context::New(isolate);
10023   v8::Local<Context> context1 = Context::New(isolate);
10024
10025   // Set up function in context0 that uses eval from context0.
10026   context0->Enter();
10027   v8::Handle<v8::Value> fun = CompileRun(
10028       "var x = 42;"
10029       "(function() {"
10030       "  var e = eval;"
10031       "  return function(s) { return e(s); }"
10032       "})()");
10033   context0->Exit();
10034
10035   // Put the function into context1 and call it before and after
10036   // detaching the global.  Before detaching, the call succeeds and
10037   // after detaching and exception is thrown.
10038   context1->Enter();
10039   context1->Global()->Set(v8_str("fun"), fun);
10040   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10041   CHECK_EQ(42, x_value->Int32Value());
10042   context0->DetachGlobal();
10043   v8::TryCatch catcher;
10044   x_value = CompileRun("fun('x')");
10045   CHECK_EQ(42, x_value->Int32Value());
10046   context1->Exit();
10047 }
10048
10049
10050 THREADED_TEST(CrossLazyLoad) {
10051   v8::HandleScope scope(CcTest::isolate());
10052   LocalContext other;
10053   LocalContext current;
10054
10055   Local<String> token = v8_str("<security token>");
10056   other->SetSecurityToken(token);
10057   current->SetSecurityToken(token);
10058
10059   // Set up reference from current to other.
10060   current->Global()->Set(v8_str("other"), other->Global());
10061
10062   // Trigger lazy loading in other context.
10063   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10064   Local<Value> value = script->Run();
10065   CHECK_EQ(42.0, value->NumberValue());
10066 }
10067
10068
10069 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10070   ApiTestFuzzer::Fuzz();
10071   if (args.IsConstructCall()) {
10072     if (args[0]->IsInt32()) {
10073       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10074       return;
10075     }
10076   }
10077
10078   args.GetReturnValue().Set(args[0]);
10079 }
10080
10081
10082 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10083   args.GetReturnValue().Set(args.This());
10084 }
10085
10086
10087 // Test that a call handler can be set for objects which will allow
10088 // non-function objects created through the API to be called as
10089 // functions.
10090 THREADED_TEST(CallAsFunction) {
10091   LocalContext context;
10092   v8::Isolate* isolate = context->GetIsolate();
10093   v8::HandleScope scope(isolate);
10094
10095   {
10096     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10097     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10098     instance_template->SetCallAsFunctionHandler(call_as_function);
10099     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10100     context->Global()->Set(v8_str("obj"), instance);
10101     v8::TryCatch try_catch;
10102     Local<Value> value;
10103     CHECK(!try_catch.HasCaught());
10104
10105     value = CompileRun("obj(42)");
10106     CHECK(!try_catch.HasCaught());
10107     CHECK_EQ(42, value->Int32Value());
10108
10109     value = CompileRun("(function(o){return o(49)})(obj)");
10110     CHECK(!try_catch.HasCaught());
10111     CHECK_EQ(49, value->Int32Value());
10112
10113     // test special case of call as function
10114     value = CompileRun("[obj]['0'](45)");
10115     CHECK(!try_catch.HasCaught());
10116     CHECK_EQ(45, value->Int32Value());
10117
10118     value = CompileRun(
10119         "obj.call = Function.prototype.call;"
10120         "obj.call(null, 87)");
10121     CHECK(!try_catch.HasCaught());
10122     CHECK_EQ(87, value->Int32Value());
10123
10124     // Regression tests for bug #1116356: Calling call through call/apply
10125     // must work for non-function receivers.
10126     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10127     value = CompileRun(apply_99);
10128     CHECK(!try_catch.HasCaught());
10129     CHECK_EQ(99, value->Int32Value());
10130
10131     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10132     value = CompileRun(call_17);
10133     CHECK(!try_catch.HasCaught());
10134     CHECK_EQ(17, value->Int32Value());
10135
10136     // Check that the call-as-function handler can be called through
10137     // new.
10138     value = CompileRun("new obj(43)");
10139     CHECK(!try_catch.HasCaught());
10140     CHECK_EQ(-43, value->Int32Value());
10141
10142     // Check that the call-as-function handler can be called through
10143     // the API.
10144     v8::Handle<Value> args[] = {v8_num(28)};
10145     value = instance->CallAsFunction(instance, 1, args);
10146     CHECK(!try_catch.HasCaught());
10147     CHECK_EQ(28, value->Int32Value());
10148   }
10149
10150   {
10151     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10152     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10153     USE(instance_template);
10154     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10155     context->Global()->Set(v8_str("obj2"), instance);
10156     v8::TryCatch try_catch;
10157     Local<Value> value;
10158     CHECK(!try_catch.HasCaught());
10159
10160     // Call an object without call-as-function handler through the JS
10161     value = CompileRun("obj2(28)");
10162     CHECK(value.IsEmpty());
10163     CHECK(try_catch.HasCaught());
10164     String::Utf8Value exception_value1(try_catch.Exception());
10165     // TODO(verwaest): Better message
10166     CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
10167     try_catch.Reset();
10168
10169     // Call an object without call-as-function handler through the API
10170     value = CompileRun("obj2(28)");
10171     v8::Handle<Value> args[] = {v8_num(28)};
10172     value = instance->CallAsFunction(instance, 1, args);
10173     CHECK(value.IsEmpty());
10174     CHECK(try_catch.HasCaught());
10175     String::Utf8Value exception_value2(try_catch.Exception());
10176     CHECK_EQ(0, strcmp("TypeError: [object Object] is not a function",
10177                        *exception_value2));
10178     try_catch.Reset();
10179   }
10180
10181   {
10182     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10183     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10184     instance_template->SetCallAsFunctionHandler(ThrowValue);
10185     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10186     context->Global()->Set(v8_str("obj3"), instance);
10187     v8::TryCatch try_catch;
10188     Local<Value> value;
10189     CHECK(!try_catch.HasCaught());
10190
10191     // Catch the exception which is thrown by call-as-function handler
10192     value = CompileRun("obj3(22)");
10193     CHECK(try_catch.HasCaught());
10194     String::Utf8Value exception_value1(try_catch.Exception());
10195     CHECK_EQ(0, strcmp("22", *exception_value1));
10196     try_catch.Reset();
10197
10198     v8::Handle<Value> args[] = {v8_num(23)};
10199     value = instance->CallAsFunction(instance, 1, args);
10200     CHECK(try_catch.HasCaught());
10201     String::Utf8Value exception_value2(try_catch.Exception());
10202     CHECK_EQ(0, strcmp("23", *exception_value2));
10203     try_catch.Reset();
10204   }
10205
10206   {
10207     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10208     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10209     instance_template->SetCallAsFunctionHandler(ReturnThis);
10210     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10211
10212     Local<v8::Value> a1 =
10213         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10214     CHECK(a1->StrictEquals(instance));
10215     Local<v8::Value> a2 = instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10216     CHECK(a2->StrictEquals(instance));
10217     Local<v8::Value> a3 = instance->CallAsFunction(v8_num(42), 0, NULL);
10218     CHECK(a3->StrictEquals(instance));
10219     Local<v8::Value> a4 = instance->CallAsFunction(v8_str("hello"), 0, NULL);
10220     CHECK(a4->StrictEquals(instance));
10221     Local<v8::Value> a5 = instance->CallAsFunction(v8::True(isolate), 0, NULL);
10222     CHECK(a5->StrictEquals(instance));
10223   }
10224
10225   {
10226     CompileRun(
10227         "function ReturnThisSloppy() {"
10228         "  return this;"
10229         "}"
10230         "function ReturnThisStrict() {"
10231         "  'use strict';"
10232         "  return this;"
10233         "}");
10234     Local<Function> ReturnThisSloppy = Local<Function>::Cast(
10235         context->Global()->Get(v8_str("ReturnThisSloppy")));
10236     Local<Function> ReturnThisStrict = Local<Function>::Cast(
10237         context->Global()->Get(v8_str("ReturnThisStrict")));
10238
10239     Local<v8::Value> a1 =
10240         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10241     CHECK(a1->StrictEquals(context->Global()));
10242     Local<v8::Value> a2 =
10243         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10244     CHECK(a2->StrictEquals(context->Global()));
10245     Local<v8::Value> a3 = ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10246     CHECK(a3->IsNumberObject());
10247     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10248     Local<v8::Value> a4 =
10249         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10250     CHECK(a4->IsStringObject());
10251     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10252     Local<v8::Value> a5 =
10253         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10254     CHECK(a5->IsBooleanObject());
10255     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10256
10257     Local<v8::Value> a6 =
10258         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10259     CHECK(a6->IsUndefined());
10260     Local<v8::Value> a7 =
10261         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10262     CHECK(a7->IsNull());
10263     Local<v8::Value> a8 = ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10264     CHECK(a8->StrictEquals(v8_num(42)));
10265     Local<v8::Value> a9 =
10266         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10267     CHECK(a9->StrictEquals(v8_str("hello")));
10268     Local<v8::Value> a10 =
10269         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10270     CHECK(a10->StrictEquals(v8::True(isolate)));
10271   }
10272 }
10273
10274
10275 // Check whether a non-function object is callable.
10276 THREADED_TEST(CallableObject) {
10277   LocalContext context;
10278   v8::Isolate* isolate = context->GetIsolate();
10279   v8::HandleScope scope(isolate);
10280
10281   {
10282     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10283     instance_template->SetCallAsFunctionHandler(call_as_function);
10284     Local<Object> instance = instance_template->NewInstance();
10285     v8::TryCatch try_catch;
10286
10287     CHECK(instance->IsCallable());
10288     CHECK(!try_catch.HasCaught());
10289   }
10290
10291   {
10292     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10293     Local<Object> instance = instance_template->NewInstance();
10294     v8::TryCatch try_catch;
10295
10296     CHECK(!instance->IsCallable());
10297     CHECK(!try_catch.HasCaught());
10298   }
10299
10300   {
10301     Local<FunctionTemplate> function_template =
10302         FunctionTemplate::New(isolate, call_as_function);
10303     Local<Function> function = function_template->GetFunction();
10304     Local<Object> instance = function;
10305     v8::TryCatch try_catch;
10306
10307     CHECK(instance->IsCallable());
10308     CHECK(!try_catch.HasCaught());
10309   }
10310
10311   {
10312     Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10313     Local<Function> function = function_template->GetFunction();
10314     Local<Object> instance = function;
10315     v8::TryCatch try_catch;
10316
10317     CHECK(instance->IsCallable());
10318     CHECK(!try_catch.HasCaught());
10319   }
10320 }
10321
10322
10323 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
10324   v8::HandleScope scope(isolate);
10325   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
10326   for (int i = 0; i < iterations; i++) {
10327     Local<v8::Number> n(v8::Integer::New(isolate, 42));
10328   }
10329   return Recurse(isolate, depth - 1, iterations);
10330 }
10331
10332
10333 THREADED_TEST(HandleIteration) {
10334   static const int kIterations = 500;
10335   static const int kNesting = 200;
10336   LocalContext context;
10337   v8::Isolate* isolate = context->GetIsolate();
10338   v8::HandleScope scope0(isolate);
10339   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10340   {
10341     v8::HandleScope scope1(isolate);
10342     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10343     for (int i = 0; i < kIterations; i++) {
10344       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10345       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
10346     }
10347
10348     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10349     {
10350       v8::HandleScope scope2(CcTest::isolate());
10351       for (int j = 0; j < kIterations; j++) {
10352         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10353         CHECK_EQ(j + 1 + kIterations,
10354                  v8::HandleScope::NumberOfHandles(isolate));
10355       }
10356     }
10357     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10358   }
10359   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10360   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
10361 }
10362
10363
10364 static void InterceptorCallICFastApi(
10365     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
10366   ApiTestFuzzer::Fuzz();
10367   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10368   int* call_count =
10369       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10370   ++(*call_count);
10371   if ((*call_count) % 20 == 0) {
10372     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
10373   }
10374 }
10375
10376 static void FastApiCallback_TrivialSignature(
10377     const v8::FunctionCallbackInfo<v8::Value>& args) {
10378   ApiTestFuzzer::Fuzz();
10379   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10380   v8::Isolate* isolate = CcTest::isolate();
10381   CHECK_EQ(isolate, args.GetIsolate());
10382   CHECK(args.This()->Equals(args.Holder()));
10383   CHECK(args.Data()->Equals(v8_str("method_data")));
10384   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10385 }
10386
10387 static void FastApiCallback_SimpleSignature(
10388     const v8::FunctionCallbackInfo<v8::Value>& args) {
10389   ApiTestFuzzer::Fuzz();
10390   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10391   v8::Isolate* isolate = CcTest::isolate();
10392   CHECK_EQ(isolate, args.GetIsolate());
10393   CHECK(args.This()->GetPrototype()->Equals(args.Holder()));
10394   CHECK(args.Data()->Equals(v8_str("method_data")));
10395   // Note, we're using HasRealNamedProperty instead of Has to avoid
10396   // invoking the interceptor again.
10397   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10398   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10399 }
10400
10401
10402 // Helper to maximize the odds of object moving.
10403 static void GenerateSomeGarbage() {
10404   CompileRun(
10405       "var garbage;"
10406       "for (var i = 0; i < 1000; i++) {"
10407       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10408       "}"
10409       "garbage = undefined;");
10410 }
10411
10412
10413 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10414   static int count = 0;
10415   if (count++ % 3 == 0) {
10416     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10417         // This should move the stub
10418     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
10419   }
10420 }
10421
10422
10423 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10424   LocalContext context;
10425   v8::Isolate* isolate = context->GetIsolate();
10426   v8::HandleScope scope(isolate);
10427   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10428       v8::ObjectTemplate::New(isolate);
10429   nativeobject_templ->Set(isolate, "callback",
10430                           v8::FunctionTemplate::New(isolate,
10431                                                     DirectApiCallback));
10432   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10433   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10434   // call the api function multiple times to ensure direct call stub creation.
10435   CompileRun(
10436         "function f() {"
10437         "  for (var i = 1; i <= 30; i++) {"
10438         "    nativeobject.callback();"
10439         "  }"
10440         "}"
10441         "f();");
10442 }
10443
10444
10445 void ThrowingDirectApiCallback(
10446     const v8::FunctionCallbackInfo<v8::Value>& args) {
10447   args.GetIsolate()->ThrowException(v8_str("g"));
10448 }
10449
10450
10451 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10452   LocalContext context;
10453   v8::Isolate* isolate = context->GetIsolate();
10454   v8::HandleScope scope(isolate);
10455   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10456       v8::ObjectTemplate::New(isolate);
10457   nativeobject_templ->Set(isolate, "callback",
10458                           v8::FunctionTemplate::New(isolate,
10459                                                     ThrowingDirectApiCallback));
10460   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10461   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10462   // call the api function multiple times to ensure direct call stub creation.
10463   v8::Handle<Value> result = CompileRun(
10464       "var result = '';"
10465       "function f() {"
10466       "  for (var i = 1; i <= 5; i++) {"
10467       "    try { nativeobject.callback(); } catch (e) { result += e; }"
10468       "  }"
10469       "}"
10470       "f(); result;");
10471   CHECK(v8_str("ggggg")->Equals(result));
10472 }
10473
10474
10475 static int p_getter_count_3;
10476
10477
10478 static Handle<Value> DoDirectGetter() {
10479   if (++p_getter_count_3 % 3 == 0) {
10480     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10481     GenerateSomeGarbage();
10482   }
10483   return v8_str("Direct Getter Result");
10484 }
10485
10486
10487 static void DirectGetterCallback(
10488     Local<String> name,
10489     const v8::PropertyCallbackInfo<v8::Value>& info) {
10490   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10491   info.GetReturnValue().Set(DoDirectGetter());
10492 }
10493
10494
10495 template<typename Accessor>
10496 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10497   LocalContext context;
10498   v8::Isolate* isolate = context->GetIsolate();
10499   v8::HandleScope scope(isolate);
10500   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10501   obj->SetAccessor(v8_str("p1"), accessor);
10502   context->Global()->Set(v8_str("o1"), obj->NewInstance());
10503   p_getter_count_3 = 0;
10504   v8::Handle<v8::Value> result = CompileRun(
10505       "function f() {"
10506       "  for (var i = 0; i < 30; i++) o1.p1;"
10507       "  return o1.p1"
10508       "}"
10509       "f();");
10510   CHECK(v8_str("Direct Getter Result")->Equals(result));
10511   CHECK_EQ(31, p_getter_count_3);
10512 }
10513
10514
10515 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10516   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10517 }
10518
10519
10520 void ThrowingDirectGetterCallback(
10521     Local<String> name,
10522     const v8::PropertyCallbackInfo<v8::Value>& info) {
10523   info.GetIsolate()->ThrowException(v8_str("g"));
10524 }
10525
10526
10527 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10528   LocalContext context;
10529   v8::Isolate* isolate = context->GetIsolate();
10530   v8::HandleScope scope(isolate);
10531   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10532   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10533   context->Global()->Set(v8_str("o1"), obj->NewInstance());
10534   v8::Handle<Value> result = CompileRun(
10535       "var result = '';"
10536       "for (var i = 0; i < 5; i++) {"
10537       "    try { o1.p1; } catch (e) { result += e; }"
10538       "}"
10539       "result;");
10540   CHECK(v8_str("ggggg")->Equals(result));
10541 }
10542
10543
10544 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10545   int interceptor_call_count = 0;
10546   v8::Isolate* isolate = CcTest::isolate();
10547   v8::HandleScope scope(isolate);
10548   v8::Handle<v8::FunctionTemplate> fun_templ =
10549       v8::FunctionTemplate::New(isolate);
10550   v8::Handle<v8::FunctionTemplate> method_templ =
10551       v8::FunctionTemplate::New(isolate,
10552                                 FastApiCallback_TrivialSignature,
10553                                 v8_str("method_data"),
10554                                 v8::Handle<v8::Signature>());
10555   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10556   proto_templ->Set(v8_str("method"), method_templ);
10557   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10558   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10559       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10560       v8::External::New(isolate, &interceptor_call_count)));
10561   LocalContext context;
10562   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10563   GenerateSomeGarbage();
10564   context->Global()->Set(v8_str("o"), fun->NewInstance());
10565   CompileRun(
10566       "var result = 0;"
10567       "for (var i = 0; i < 100; i++) {"
10568       "  result = o.method(41);"
10569       "}");
10570   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10571   CHECK_EQ(100, interceptor_call_count);
10572 }
10573
10574
10575 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10576   int interceptor_call_count = 0;
10577   v8::Isolate* isolate = CcTest::isolate();
10578   v8::HandleScope scope(isolate);
10579   v8::Handle<v8::FunctionTemplate> fun_templ =
10580       v8::FunctionTemplate::New(isolate);
10581   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10582       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10583       v8::Signature::New(isolate, fun_templ));
10584   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10585   proto_templ->Set(v8_str("method"), method_templ);
10586   fun_templ->SetHiddenPrototype(true);
10587   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10588   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10589       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10590       v8::External::New(isolate, &interceptor_call_count)));
10591   LocalContext context;
10592   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10593   GenerateSomeGarbage();
10594   context->Global()->Set(v8_str("o"), fun->NewInstance());
10595   CompileRun(
10596       "o.foo = 17;"
10597       "var receiver = {};"
10598       "receiver.__proto__ = o;"
10599       "var result = 0;"
10600       "for (var i = 0; i < 100; i++) {"
10601       "  result = receiver.method(41);"
10602       "}");
10603   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10604   CHECK_EQ(100, interceptor_call_count);
10605 }
10606
10607
10608 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10609   int interceptor_call_count = 0;
10610   v8::Isolate* isolate = CcTest::isolate();
10611   v8::HandleScope scope(isolate);
10612   v8::Handle<v8::FunctionTemplate> fun_templ =
10613       v8::FunctionTemplate::New(isolate);
10614   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10615       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10616       v8::Signature::New(isolate, fun_templ));
10617   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10618   proto_templ->Set(v8_str("method"), method_templ);
10619   fun_templ->SetHiddenPrototype(true);
10620   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10621   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10622       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10623       v8::External::New(isolate, &interceptor_call_count)));
10624   LocalContext context;
10625   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10626   GenerateSomeGarbage();
10627   context->Global()->Set(v8_str("o"), fun->NewInstance());
10628   CompileRun(
10629       "o.foo = 17;"
10630       "var receiver = {};"
10631       "receiver.__proto__ = o;"
10632       "var result = 0;"
10633       "var saved_result = 0;"
10634       "for (var i = 0; i < 100; i++) {"
10635       "  result = receiver.method(41);"
10636       "  if (i == 50) {"
10637       "    saved_result = result;"
10638       "    receiver = {method: function(x) { return x - 1 }};"
10639       "  }"
10640       "}");
10641   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10642   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10643   CHECK_GE(interceptor_call_count, 50);
10644 }
10645
10646
10647 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
10648   int interceptor_call_count = 0;
10649   v8::Isolate* isolate = CcTest::isolate();
10650   v8::HandleScope scope(isolate);
10651   v8::Handle<v8::FunctionTemplate> fun_templ =
10652       v8::FunctionTemplate::New(isolate);
10653   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10654       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10655       v8::Signature::New(isolate, fun_templ));
10656   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10657   proto_templ->Set(v8_str("method"), method_templ);
10658   fun_templ->SetHiddenPrototype(true);
10659   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10660   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10661       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10662       v8::External::New(isolate, &interceptor_call_count)));
10663   LocalContext context;
10664   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10665   GenerateSomeGarbage();
10666   context->Global()->Set(v8_str("o"), fun->NewInstance());
10667   CompileRun(
10668       "o.foo = 17;"
10669       "var receiver = {};"
10670       "receiver.__proto__ = o;"
10671       "var result = 0;"
10672       "var saved_result = 0;"
10673       "for (var i = 0; i < 100; i++) {"
10674       "  result = receiver.method(41);"
10675       "  if (i == 50) {"
10676       "    saved_result = result;"
10677       "    o.method = function(x) { return x - 1 };"
10678       "  }"
10679       "}");
10680   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10681   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10682   CHECK_GE(interceptor_call_count, 50);
10683 }
10684
10685
10686 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10687   int interceptor_call_count = 0;
10688   v8::Isolate* isolate = CcTest::isolate();
10689   v8::HandleScope scope(isolate);
10690   v8::Handle<v8::FunctionTemplate> fun_templ =
10691       v8::FunctionTemplate::New(isolate);
10692   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10693       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10694       v8::Signature::New(isolate, fun_templ));
10695   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10696   proto_templ->Set(v8_str("method"), method_templ);
10697   fun_templ->SetHiddenPrototype(true);
10698   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10699   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10700       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10701       v8::External::New(isolate, &interceptor_call_count)));
10702   LocalContext context;
10703   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10704   GenerateSomeGarbage();
10705   context->Global()->Set(v8_str("o"), fun->NewInstance());
10706   v8::TryCatch try_catch;
10707   CompileRun(
10708       "o.foo = 17;"
10709       "var receiver = {};"
10710       "receiver.__proto__ = o;"
10711       "var result = 0;"
10712       "var saved_result = 0;"
10713       "for (var i = 0; i < 100; i++) {"
10714       "  result = receiver.method(41);"
10715       "  if (i == 50) {"
10716       "    saved_result = result;"
10717       "    receiver = 333;"
10718       "  }"
10719       "}");
10720   CHECK(try_catch.HasCaught());
10721   // TODO(verwaest): Adjust message.
10722   CHECK(v8_str("TypeError: receiver.method is not a function")
10723             ->Equals(try_catch.Exception()->ToString(isolate)));
10724   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10725   CHECK_GE(interceptor_call_count, 50);
10726 }
10727
10728
10729 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10730   int interceptor_call_count = 0;
10731   v8::Isolate* isolate = CcTest::isolate();
10732   v8::HandleScope scope(isolate);
10733   v8::Handle<v8::FunctionTemplate> fun_templ =
10734       v8::FunctionTemplate::New(isolate);
10735   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10736       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10737       v8::Signature::New(isolate, fun_templ));
10738   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10739   proto_templ->Set(v8_str("method"), method_templ);
10740   fun_templ->SetHiddenPrototype(true);
10741   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10742   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10743       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10744       v8::External::New(isolate, &interceptor_call_count)));
10745   LocalContext context;
10746   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10747   GenerateSomeGarbage();
10748   context->Global()->Set(v8_str("o"), fun->NewInstance());
10749   v8::TryCatch try_catch;
10750   CompileRun(
10751       "o.foo = 17;"
10752       "var receiver = {};"
10753       "receiver.__proto__ = o;"
10754       "var result = 0;"
10755       "var saved_result = 0;"
10756       "for (var i = 0; i < 100; i++) {"
10757       "  result = receiver.method(41);"
10758       "  if (i == 50) {"
10759       "    saved_result = result;"
10760       "    receiver = {method: receiver.method};"
10761       "  }"
10762       "}");
10763   CHECK(try_catch.HasCaught());
10764   CHECK(v8_str("TypeError: Illegal invocation")
10765             ->Equals(try_catch.Exception()->ToString(isolate)));
10766   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10767   CHECK_GE(interceptor_call_count, 50);
10768 }
10769
10770
10771 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
10772   v8::Isolate* isolate = CcTest::isolate();
10773   v8::HandleScope scope(isolate);
10774   v8::Handle<v8::FunctionTemplate> fun_templ =
10775       v8::FunctionTemplate::New(isolate);
10776   v8::Handle<v8::FunctionTemplate> method_templ =
10777       v8::FunctionTemplate::New(isolate,
10778                                 FastApiCallback_TrivialSignature,
10779                                 v8_str("method_data"),
10780                                 v8::Handle<v8::Signature>());
10781   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10782   proto_templ->Set(v8_str("method"), method_templ);
10783   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10784   USE(templ);
10785   LocalContext context;
10786   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10787   GenerateSomeGarbage();
10788   context->Global()->Set(v8_str("o"), fun->NewInstance());
10789   CompileRun(
10790       "var result = 0;"
10791       "for (var i = 0; i < 100; i++) {"
10792       "  result = o.method(41);"
10793       "}");
10794
10795   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10796 }
10797
10798
10799 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
10800   v8::Isolate* isolate = CcTest::isolate();
10801   v8::HandleScope scope(isolate);
10802   v8::Handle<v8::FunctionTemplate> fun_templ =
10803       v8::FunctionTemplate::New(isolate);
10804   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10805       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10806       v8::Signature::New(isolate, fun_templ));
10807   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10808   proto_templ->Set(v8_str("method"), method_templ);
10809   fun_templ->SetHiddenPrototype(true);
10810   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10811   CHECK(!templ.IsEmpty());
10812   LocalContext context;
10813   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10814   GenerateSomeGarbage();
10815   context->Global()->Set(v8_str("o"), fun->NewInstance());
10816   CompileRun(
10817       "o.foo = 17;"
10818       "var receiver = {};"
10819       "receiver.__proto__ = o;"
10820       "var result = 0;"
10821       "for (var i = 0; i < 100; i++) {"
10822       "  result = receiver.method(41);"
10823       "}");
10824
10825   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10826 }
10827
10828
10829 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
10830   v8::Isolate* isolate = CcTest::isolate();
10831   v8::HandleScope scope(isolate);
10832   v8::Handle<v8::FunctionTemplate> fun_templ =
10833       v8::FunctionTemplate::New(isolate);
10834   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10835       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10836       v8::Signature::New(isolate, fun_templ));
10837   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10838   proto_templ->Set(v8_str("method"), method_templ);
10839   fun_templ->SetHiddenPrototype(true);
10840   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10841   CHECK(!templ.IsEmpty());
10842   LocalContext context;
10843   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10844   GenerateSomeGarbage();
10845   context->Global()->Set(v8_str("o"), fun->NewInstance());
10846   CompileRun(
10847       "o.foo = 17;"
10848       "var receiver = {};"
10849       "receiver.__proto__ = o;"
10850       "var result = 0;"
10851       "var saved_result = 0;"
10852       "for (var i = 0; i < 100; i++) {"
10853       "  result = receiver.method(41);"
10854       "  if (i == 50) {"
10855       "    saved_result = result;"
10856       "    receiver = {method: function(x) { return x - 1 }};"
10857       "  }"
10858       "}");
10859   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10860   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10861 }
10862
10863
10864 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10865   v8::Isolate* isolate = CcTest::isolate();
10866   v8::HandleScope scope(isolate);
10867   v8::Handle<v8::FunctionTemplate> fun_templ =
10868       v8::FunctionTemplate::New(isolate);
10869   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10870       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10871       v8::Signature::New(isolate, fun_templ));
10872   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10873   proto_templ->Set(v8_str("method"), method_templ);
10874   fun_templ->SetHiddenPrototype(true);
10875   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10876   CHECK(!templ.IsEmpty());
10877   LocalContext context;
10878   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10879   GenerateSomeGarbage();
10880   context->Global()->Set(v8_str("o"), fun->NewInstance());
10881   v8::TryCatch try_catch;
10882   CompileRun(
10883       "o.foo = 17;"
10884       "var receiver = {};"
10885       "receiver.__proto__ = o;"
10886       "var result = 0;"
10887       "var saved_result = 0;"
10888       "for (var i = 0; i < 100; i++) {"
10889       "  result = receiver.method(41);"
10890       "  if (i == 50) {"
10891       "    saved_result = result;"
10892       "    receiver = 333;"
10893       "  }"
10894       "}");
10895   CHECK(try_catch.HasCaught());
10896   // TODO(verwaest): Adjust message.
10897   CHECK(v8_str("TypeError: receiver.method is not a function")
10898             ->Equals(try_catch.Exception()->ToString(isolate)));
10899   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10900 }
10901
10902
10903 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
10904   v8::Isolate* isolate = CcTest::isolate();
10905   v8::HandleScope scope(isolate);
10906   v8::Handle<v8::FunctionTemplate> fun_templ =
10907       v8::FunctionTemplate::New(isolate);
10908   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10909       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10910       v8::Signature::New(isolate, fun_templ));
10911   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10912   proto_templ->Set(v8_str("method"), method_templ);
10913   fun_templ->SetHiddenPrototype(true);
10914   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10915   CHECK(!templ.IsEmpty());
10916   LocalContext context;
10917   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10918   GenerateSomeGarbage();
10919   context->Global()->Set(v8_str("o"), fun->NewInstance());
10920   v8::TryCatch try_catch;
10921   CompileRun(
10922       "o.foo = 17;"
10923       "var receiver = {};"
10924       "receiver.__proto__ = o;"
10925       "var result = 0;"
10926       "var saved_result = 0;"
10927       "for (var i = 0; i < 100; i++) {"
10928       "  result = receiver.method(41);"
10929       "  if (i == 50) {"
10930       "    saved_result = result;"
10931       "    receiver = Object.create(receiver);"
10932       "  }"
10933       "}");
10934   CHECK(try_catch.HasCaught());
10935   CHECK(v8_str("TypeError: Illegal invocation")
10936             ->Equals(try_catch.Exception()->ToString(isolate)));
10937   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10938 }
10939
10940
10941 static void ThrowingGetter(Local<String> name,
10942                            const v8::PropertyCallbackInfo<v8::Value>& info) {
10943   ApiTestFuzzer::Fuzz();
10944   info.GetIsolate()->ThrowException(Handle<Value>());
10945   info.GetReturnValue().SetUndefined();
10946 }
10947
10948
10949 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10950   LocalContext context;
10951   HandleScope scope(context->GetIsolate());
10952
10953   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
10954   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10955   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10956
10957   Local<Object> instance = templ->GetFunction()->NewInstance();
10958
10959   Local<Object> another = Object::New(context->GetIsolate());
10960   another->SetPrototype(instance);
10961
10962   Local<Object> with_js_getter = CompileRun(
10963       "o = {};\n"
10964       "o.__defineGetter__('f', function() { throw undefined; });\n"
10965       "o\n").As<Object>();
10966   CHECK(!with_js_getter.IsEmpty());
10967
10968   TryCatch try_catch;
10969
10970   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10971   CHECK(try_catch.HasCaught());
10972   try_catch.Reset();
10973   CHECK(result.IsEmpty());
10974
10975   Maybe<PropertyAttribute> attr =
10976       instance->GetRealNamedPropertyAttributes(v8_str("f"));
10977   CHECK(!try_catch.HasCaught());
10978   CHECK(Just(None) == attr);
10979
10980   result = another->GetRealNamedProperty(v8_str("f"));
10981   CHECK(try_catch.HasCaught());
10982   try_catch.Reset();
10983   CHECK(result.IsEmpty());
10984
10985   attr = another->GetRealNamedPropertyAttributes(v8_str("f"));
10986   CHECK(!try_catch.HasCaught());
10987   CHECK(Just(None) == attr);
10988
10989   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10990   CHECK(try_catch.HasCaught());
10991   try_catch.Reset();
10992   CHECK(result.IsEmpty());
10993
10994   attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f"));
10995   CHECK(!try_catch.HasCaught());
10996   CHECK(Just(None) == attr);
10997
10998   result = another->Get(v8_str("f"));
10999   CHECK(try_catch.HasCaught());
11000   try_catch.Reset();
11001   CHECK(result.IsEmpty());
11002
11003   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
11004   CHECK(try_catch.HasCaught());
11005   try_catch.Reset();
11006   CHECK(result.IsEmpty());
11007
11008   attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f"));
11009   CHECK(!try_catch.HasCaught());
11010   CHECK(Just(None) == attr);
11011
11012   result = with_js_getter->Get(v8_str("f"));
11013   CHECK(try_catch.HasCaught());
11014   try_catch.Reset();
11015   CHECK(result.IsEmpty());
11016 }
11017
11018
11019 static void ThrowingCallbackWithTryCatch(
11020     const v8::FunctionCallbackInfo<v8::Value>& args) {
11021   TryCatch try_catch;
11022   // Verboseness is important: it triggers message delivery which can call into
11023   // external code.
11024   try_catch.SetVerbose(true);
11025   CompileRun("throw 'from JS';");
11026   CHECK(try_catch.HasCaught());
11027   CHECK(!CcTest::i_isolate()->has_pending_exception());
11028   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
11029 }
11030
11031
11032 static int call_depth;
11033
11034
11035 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
11036   TryCatch try_catch;
11037 }
11038
11039
11040 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
11041   if (--call_depth) CompileRun("throw 'ThrowInJS';");
11042 }
11043
11044
11045 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
11046   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
11047 }
11048
11049
11050 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
11051   Handle<String> errorMessageString = message->Get();
11052   CHECK(!errorMessageString.IsEmpty());
11053   message->GetStackTrace();
11054   message->GetScriptOrigin().ResourceName();
11055 }
11056
11057
11058 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
11059   LocalContext context;
11060   v8::Isolate* isolate = context->GetIsolate();
11061   HandleScope scope(isolate);
11062
11063   Local<Function> func =
11064       FunctionTemplate::New(isolate,
11065                             ThrowingCallbackWithTryCatch)->GetFunction();
11066   context->Global()->Set(v8_str("func"), func);
11067
11068   MessageCallback callbacks[] =
11069       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
11070   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
11071     MessageCallback callback = callbacks[i];
11072     if (callback != NULL) {
11073       V8::AddMessageListener(callback);
11074     }
11075     // Some small number to control number of times message handler should
11076     // throw an exception.
11077     call_depth = 5;
11078     ExpectFalse(
11079         "var thrown = false;\n"
11080         "try { func(); } catch(e) { thrown = true; }\n"
11081         "thrown\n");
11082     if (callback != NULL) {
11083       V8::RemoveMessageListeners(callback);
11084     }
11085   }
11086 }
11087
11088
11089 static void ParentGetter(Local<String> name,
11090                          const v8::PropertyCallbackInfo<v8::Value>& info) {
11091   ApiTestFuzzer::Fuzz();
11092   info.GetReturnValue().Set(v8_num(1));
11093 }
11094
11095
11096 static void ChildGetter(Local<String> name,
11097                         const v8::PropertyCallbackInfo<v8::Value>& info) {
11098   ApiTestFuzzer::Fuzz();
11099   info.GetReturnValue().Set(v8_num(42));
11100 }
11101
11102
11103 THREADED_TEST(Overriding) {
11104   LocalContext context;
11105   v8::Isolate* isolate = context->GetIsolate();
11106   v8::HandleScope scope(isolate);
11107
11108   // Parent template.
11109   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
11110   Local<ObjectTemplate> parent_instance_templ =
11111       parent_templ->InstanceTemplate();
11112   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
11113
11114   // Template that inherits from the parent template.
11115   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
11116   Local<ObjectTemplate> child_instance_templ =
11117       child_templ->InstanceTemplate();
11118   child_templ->Inherit(parent_templ);
11119   // Override 'f'.  The child version of 'f' should get called for child
11120   // instances.
11121   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11122   // Add 'g' twice.  The 'g' added last should get called for instances.
11123   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11124   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11125
11126   // Add 'h' as an accessor to the proto template with ReadOnly attributes
11127   // so 'h' can be shadowed on the instance object.
11128   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11129   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11130       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11131
11132   // Add 'i' as an accessor to the instance template with ReadOnly attributes
11133   // but the attribute does not have effect because it is duplicated with
11134   // NULL setter.
11135   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11136       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11137
11138
11139
11140   // Instantiate the child template.
11141   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11142
11143   // Check that the child function overrides the parent one.
11144   context->Global()->Set(v8_str("o"), instance);
11145   Local<Value> value = v8_compile("o.f")->Run();
11146   // Check that the 'g' that was added last is hit.
11147   CHECK_EQ(42, value->Int32Value());
11148   value = v8_compile("o.g")->Run();
11149   CHECK_EQ(42, value->Int32Value());
11150
11151   // Check that 'h' cannot be shadowed.
11152   value = v8_compile("o.h = 3; o.h")->Run();
11153   CHECK_EQ(1, value->Int32Value());
11154
11155   // Check that 'i' cannot be shadowed or changed.
11156   value = v8_compile("o.i = 3; o.i")->Run();
11157   CHECK_EQ(42, value->Int32Value());
11158 }
11159
11160
11161 static void IsConstructHandler(
11162     const v8::FunctionCallbackInfo<v8::Value>& args) {
11163   ApiTestFuzzer::Fuzz();
11164   args.GetReturnValue().Set(args.IsConstructCall());
11165 }
11166
11167
11168 THREADED_TEST(IsConstructCall) {
11169   v8::Isolate* isolate = CcTest::isolate();
11170   v8::HandleScope scope(isolate);
11171
11172   // Function template with call handler.
11173   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11174   templ->SetCallHandler(IsConstructHandler);
11175
11176   LocalContext context;
11177
11178   context->Global()->Set(v8_str("f"), templ->GetFunction());
11179   Local<Value> value = v8_compile("f()")->Run();
11180   CHECK(!value->BooleanValue());
11181   value = v8_compile("new f()")->Run();
11182   CHECK(value->BooleanValue());
11183 }
11184
11185
11186 THREADED_TEST(ObjectProtoToString) {
11187   v8::Isolate* isolate = CcTest::isolate();
11188   v8::HandleScope scope(isolate);
11189   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11190   templ->SetClassName(v8_str("MyClass"));
11191
11192   LocalContext context;
11193
11194   Local<String> customized_tostring = v8_str("customized toString");
11195
11196   // Replace Object.prototype.toString
11197   v8_compile("Object.prototype.toString = function() {"
11198                   "  return 'customized toString';"
11199                   "}")->Run();
11200
11201   // Normal ToString call should call replaced Object.prototype.toString
11202   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11203   Local<String> value = instance->ToString(isolate);
11204   CHECK(value->IsString() && value->Equals(customized_tostring));
11205
11206   // ObjectProtoToString should not call replace toString function.
11207   value = instance->ObjectProtoToString();
11208   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11209
11210   // Check global
11211   value = context->Global()->ObjectProtoToString();
11212   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11213
11214   // Check ordinary object
11215   Local<Value> object = v8_compile("new Object()")->Run();
11216   value = object.As<v8::Object>()->ObjectProtoToString();
11217   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11218 }
11219
11220
11221 TEST(ObjectProtoToStringES6) {
11222   // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
11223   i::FLAG_harmony_tostring = true;
11224   LocalContext context;
11225   v8::Isolate* isolate = CcTest::isolate();
11226   v8::HandleScope scope(isolate);
11227   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11228   templ->SetClassName(v8_str("MyClass"));
11229
11230   Local<String> customized_tostring = v8_str("customized toString");
11231
11232   // Replace Object.prototype.toString
11233   CompileRun(
11234       "Object.prototype.toString = function() {"
11235       "  return 'customized toString';"
11236       "}");
11237
11238   // Normal ToString call should call replaced Object.prototype.toString
11239   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11240   Local<String> value = instance->ToString(isolate);
11241   CHECK(value->IsString() && value->Equals(customized_tostring));
11242
11243   // ObjectProtoToString should not call replace toString function.
11244   value = instance->ObjectProtoToString();
11245   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11246
11247   // Check global
11248   value = context->Global()->ObjectProtoToString();
11249   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11250
11251   // Check ordinary object
11252   Local<Value> object = CompileRun("new Object()");
11253   value = object.As<v8::Object>()->ObjectProtoToString();
11254   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11255
11256   // Check that ES6 semantics using @@toStringTag work
11257   Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
11258
11259 #define TEST_TOSTRINGTAG(type, tag, expected)                \
11260   do {                                                       \
11261     object = CompileRun("new " #type "()");                  \
11262     object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
11263     value = object.As<v8::Object>()->ObjectProtoToString();  \
11264     CHECK(value->IsString() &&                               \
11265           value->Equals(v8_str("[object " #expected "]")));  \
11266   } while (0)
11267
11268   TEST_TOSTRINGTAG(Array, Object, Object);
11269   TEST_TOSTRINGTAG(Object, Arguments, Arguments);
11270   TEST_TOSTRINGTAG(Object, Array, Array);
11271   TEST_TOSTRINGTAG(Object, Boolean, Boolean);
11272   TEST_TOSTRINGTAG(Object, Date, Date);
11273   TEST_TOSTRINGTAG(Object, Error, Error);
11274   TEST_TOSTRINGTAG(Object, Function, Function);
11275   TEST_TOSTRINGTAG(Object, Number, Number);
11276   TEST_TOSTRINGTAG(Object, RegExp, RegExp);
11277   TEST_TOSTRINGTAG(Object, String, String);
11278   TEST_TOSTRINGTAG(Object, Foo, Foo);
11279
11280 #undef TEST_TOSTRINGTAG
11281
11282   Local<v8::RegExp> valueRegExp = v8::RegExp::New(v8_str("^$"),
11283                                                   v8::RegExp::kNone);
11284   Local<Value> valueNumber = v8_num(123);
11285   Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
11286   Local<v8::Function> valueFunction =
11287       CompileRun("(function fn() {})").As<v8::Function>();
11288   Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
11289   Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
11290   Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
11291
11292 #define TEST_TOSTRINGTAG(type, tagValue, expected)          \
11293   do {                                                      \
11294     object = CompileRun("new " #type "()");                 \
11295     object.As<v8::Object>()->Set(toStringTag, tagValue);    \
11296     value = object.As<v8::Object>()->ObjectProtoToString(); \
11297     CHECK(value->IsString() &&                              \
11298           value->Equals(v8_str("[object " #expected "]"))); \
11299   } while (0)
11300
11301 #define TEST_TOSTRINGTAG_TYPES(tagValue)                    \
11302   TEST_TOSTRINGTAG(Array, tagValue, Array);                 \
11303   TEST_TOSTRINGTAG(Object, tagValue, Object);               \
11304   TEST_TOSTRINGTAG(Function, tagValue, Function);           \
11305   TEST_TOSTRINGTAG(Date, tagValue, Date);                   \
11306   TEST_TOSTRINGTAG(RegExp, tagValue, RegExp);               \
11307   TEST_TOSTRINGTAG(Error, tagValue, Error);                 \
11308
11309   // Test non-String-valued @@toStringTag
11310   TEST_TOSTRINGTAG_TYPES(valueRegExp);
11311   TEST_TOSTRINGTAG_TYPES(valueNumber);
11312   TEST_TOSTRINGTAG_TYPES(valueSymbol);
11313   TEST_TOSTRINGTAG_TYPES(valueFunction);
11314   TEST_TOSTRINGTAG_TYPES(valueObject);
11315   TEST_TOSTRINGTAG_TYPES(valueNull);
11316   TEST_TOSTRINGTAG_TYPES(valueUndef);
11317
11318 #undef TEST_TOSTRINGTAG
11319 #undef TEST_TOSTRINGTAG_TYPES
11320
11321   // @@toStringTag getter throws
11322   Local<Value> obj = v8::Object::New(isolate);
11323   obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
11324   {
11325     TryCatch try_catch;
11326     value = obj.As<v8::Object>()->ObjectProtoToString();
11327     CHECK(value.IsEmpty());
11328     CHECK(try_catch.HasCaught());
11329   }
11330
11331   // @@toStringTag getter does not throw
11332   obj = v8::Object::New(isolate);
11333   obj.As<v8::Object>()->SetAccessor(
11334       toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
11335   {
11336     TryCatch try_catch;
11337     value = obj.As<v8::Object>()->ObjectProtoToString();
11338     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11339     CHECK(!try_catch.HasCaught());
11340   }
11341
11342   // JS @@toStringTag value
11343   obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
11344   {
11345     TryCatch try_catch;
11346     value = obj.As<v8::Object>()->ObjectProtoToString();
11347     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11348     CHECK(!try_catch.HasCaught());
11349   }
11350
11351   // JS @@toStringTag getter throws
11352   obj = CompileRun(
11353       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11354       "  get: function() { throw 'Test'; }"
11355       "}); obj");
11356   {
11357     TryCatch try_catch;
11358     value = obj.As<v8::Object>()->ObjectProtoToString();
11359     CHECK(value.IsEmpty());
11360     CHECK(try_catch.HasCaught());
11361   }
11362
11363   // JS @@toStringTag getter does not throw
11364   obj = CompileRun(
11365       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11366       "  get: function() { return 'Test'; }"
11367       "}); obj");
11368   {
11369     TryCatch try_catch;
11370     value = obj.As<v8::Object>()->ObjectProtoToString();
11371     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11372     CHECK(!try_catch.HasCaught());
11373   }
11374 }
11375
11376
11377 THREADED_TEST(ObjectGetConstructorName) {
11378   v8::Isolate* isolate = CcTest::isolate();
11379   LocalContext context;
11380   v8::HandleScope scope(isolate);
11381   v8_compile("function Parent() {};"
11382              "function Child() {};"
11383              "Child.prototype = new Parent();"
11384              "var outer = { inner: function() { } };"
11385              "var p = new Parent();"
11386              "var c = new Child();"
11387              "var x = new outer.inner();")->Run();
11388
11389   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11390   CHECK(p->IsObject() &&
11391         p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
11392
11393   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11394   CHECK(c->IsObject() &&
11395         c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
11396
11397   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11398   CHECK(x->IsObject() &&
11399         x->ToObject(isolate)->GetConstructorName()->Equals(
11400             v8_str("outer.inner")));
11401 }
11402
11403
11404 bool ApiTestFuzzer::fuzzing_ = false;
11405 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
11406 int ApiTestFuzzer::active_tests_;
11407 int ApiTestFuzzer::tests_being_run_;
11408 int ApiTestFuzzer::current_;
11409
11410
11411 // We are in a callback and want to switch to another thread (if we
11412 // are currently running the thread fuzzing test).
11413 void ApiTestFuzzer::Fuzz() {
11414   if (!fuzzing_) return;
11415   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11416   test->ContextSwitch();
11417 }
11418
11419
11420 // Let the next thread go.  Since it is also waiting on the V8 lock it may
11421 // not start immediately.
11422 bool ApiTestFuzzer::NextThread() {
11423   int test_position = GetNextTestNumber();
11424   const char* test_name = RegisterThreadedTest::nth(current_)->name();
11425   if (test_position == current_) {
11426     if (kLogThreading)
11427       printf("Stay with %s\n", test_name);
11428     return false;
11429   }
11430   if (kLogThreading) {
11431     printf("Switch from %s to %s\n",
11432            test_name,
11433            RegisterThreadedTest::nth(test_position)->name());
11434   }
11435   current_ = test_position;
11436   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
11437   return true;
11438 }
11439
11440
11441 void ApiTestFuzzer::Run() {
11442   // When it is our turn...
11443   gate_.Wait();
11444   {
11445     // ... get the V8 lock and start running the test.
11446     v8::Locker locker(CcTest::isolate());
11447     CallTest();
11448   }
11449   // This test finished.
11450   active_ = false;
11451   active_tests_--;
11452   // If it was the last then signal that fact.
11453   if (active_tests_ == 0) {
11454     all_tests_done_.Signal();
11455   } else {
11456     // Otherwise select a new test and start that.
11457     NextThread();
11458   }
11459 }
11460
11461
11462 static unsigned linear_congruential_generator;
11463
11464
11465 void ApiTestFuzzer::SetUp(PartOfTest part) {
11466   linear_congruential_generator = i::FLAG_testing_prng_seed;
11467   fuzzing_ = true;
11468   int count = RegisterThreadedTest::count();
11469   int start =  count * part / (LAST_PART + 1);
11470   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11471   active_tests_ = tests_being_run_ = end - start + 1;
11472   for (int i = 0; i < tests_being_run_; i++) {
11473     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
11474   }
11475   for (int i = 0; i < active_tests_; i++) {
11476     RegisterThreadedTest::nth(i)->fuzzer_->Start();
11477   }
11478 }
11479
11480
11481 static void CallTestNumber(int test_number) {
11482   (RegisterThreadedTest::nth(test_number)->callback())();
11483 }
11484
11485
11486 void ApiTestFuzzer::RunAllTests() {
11487   // Set off the first test.
11488   current_ = -1;
11489   NextThread();
11490   // Wait till they are all done.
11491   all_tests_done_.Wait();
11492 }
11493
11494
11495 int ApiTestFuzzer::GetNextTestNumber() {
11496   int next_test;
11497   do {
11498     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11499     linear_congruential_generator *= 1664525u;
11500     linear_congruential_generator += 1013904223u;
11501   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11502   return next_test;
11503 }
11504
11505
11506 void ApiTestFuzzer::ContextSwitch() {
11507   // If the new thread is the same as the current thread there is nothing to do.
11508   if (NextThread()) {
11509     // Now it can start.
11510     v8::Unlocker unlocker(CcTest::isolate());
11511     // Wait till someone starts us again.
11512     gate_.Wait();
11513     // And we're off.
11514   }
11515 }
11516
11517
11518 void ApiTestFuzzer::TearDown() {
11519   fuzzing_ = false;
11520   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11521     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11522     if (fuzzer != NULL) fuzzer->Join();
11523   }
11524 }
11525
11526
11527 // Lets not be needlessly self-referential.
11528 TEST(Threading1) {
11529   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
11530   ApiTestFuzzer::RunAllTests();
11531   ApiTestFuzzer::TearDown();
11532 }
11533
11534
11535 TEST(Threading2) {
11536   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
11537   ApiTestFuzzer::RunAllTests();
11538   ApiTestFuzzer::TearDown();
11539 }
11540
11541
11542 TEST(Threading3) {
11543   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
11544   ApiTestFuzzer::RunAllTests();
11545   ApiTestFuzzer::TearDown();
11546 }
11547
11548
11549 TEST(Threading4) {
11550   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
11551   ApiTestFuzzer::RunAllTests();
11552   ApiTestFuzzer::TearDown();
11553 }
11554
11555
11556 void ApiTestFuzzer::CallTest() {
11557   v8::Isolate::Scope scope(CcTest::isolate());
11558   if (kLogThreading)
11559     printf("Start test %d\n", test_number_);
11560   CallTestNumber(test_number_);
11561   if (kLogThreading)
11562     printf("End test %d\n", test_number_);
11563 }
11564
11565
11566 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
11567   v8::Isolate* isolate = args.GetIsolate();
11568   CHECK(v8::Locker::IsLocked(isolate));
11569   ApiTestFuzzer::Fuzz();
11570   v8::Unlocker unlocker(isolate);
11571   const char* code = "throw 7;";
11572   {
11573     v8::Locker nested_locker(isolate);
11574     v8::HandleScope scope(isolate);
11575     v8::Handle<Value> exception;
11576     { v8::TryCatch try_catch;
11577       v8::Handle<Value> value = CompileRun(code);
11578       CHECK(value.IsEmpty());
11579       CHECK(try_catch.HasCaught());
11580       // Make sure to wrap the exception in a new handle because
11581       // the handle returned from the TryCatch is destroyed
11582       // when the TryCatch is destroyed.
11583       exception = Local<Value>::New(isolate, try_catch.Exception());
11584     }
11585     args.GetIsolate()->ThrowException(exception);
11586   }
11587 }
11588
11589
11590 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
11591   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11592   ApiTestFuzzer::Fuzz();
11593   v8::Unlocker unlocker(CcTest::isolate());
11594   const char* code = "throw 7;";
11595   {
11596     v8::Locker nested_locker(CcTest::isolate());
11597     v8::HandleScope scope(args.GetIsolate());
11598     v8::Handle<Value> value = CompileRun(code);
11599     CHECK(value.IsEmpty());
11600     args.GetReturnValue().Set(v8_str("foo"));
11601   }
11602 }
11603
11604
11605 // These are locking tests that don't need to be run again
11606 // as part of the locking aggregation tests.
11607 TEST(NestedLockers) {
11608   v8::Isolate* isolate = CcTest::isolate();
11609   v8::Locker locker(isolate);
11610   CHECK(v8::Locker::IsLocked(isolate));
11611   LocalContext env;
11612   v8::HandleScope scope(env->GetIsolate());
11613   Local<v8::FunctionTemplate> fun_templ =
11614       v8::FunctionTemplate::New(isolate, ThrowInJS);
11615   Local<Function> fun = fun_templ->GetFunction();
11616   env->Global()->Set(v8_str("throw_in_js"), fun);
11617   Local<Script> script = v8_compile("(function () {"
11618                                     "  try {"
11619                                     "    throw_in_js();"
11620                                     "    return 42;"
11621                                     "  } catch (e) {"
11622                                     "    return e * 13;"
11623                                     "  }"
11624                                     "})();");
11625   CHECK_EQ(91, script->Run()->Int32Value());
11626 }
11627
11628
11629 // These are locking tests that don't need to be run again
11630 // as part of the locking aggregation tests.
11631 TEST(NestedLockersNoTryCatch) {
11632   v8::Locker locker(CcTest::isolate());
11633   LocalContext env;
11634   v8::HandleScope scope(env->GetIsolate());
11635   Local<v8::FunctionTemplate> fun_templ =
11636       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
11637   Local<Function> fun = fun_templ->GetFunction();
11638   env->Global()->Set(v8_str("throw_in_js"), fun);
11639   Local<Script> script = v8_compile("(function () {"
11640                                     "  try {"
11641                                     "    throw_in_js();"
11642                                     "    return 42;"
11643                                     "  } catch (e) {"
11644                                     "    return e * 13;"
11645                                     "  }"
11646                                     "})();");
11647   CHECK_EQ(91, script->Run()->Int32Value());
11648 }
11649
11650
11651 THREADED_TEST(RecursiveLocking) {
11652   v8::Locker locker(CcTest::isolate());
11653   {
11654     v8::Locker locker2(CcTest::isolate());
11655     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11656   }
11657 }
11658
11659
11660 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
11661   ApiTestFuzzer::Fuzz();
11662   v8::Unlocker unlocker(CcTest::isolate());
11663 }
11664
11665
11666 THREADED_TEST(LockUnlockLock) {
11667   {
11668     v8::Locker locker(CcTest::isolate());
11669     v8::HandleScope scope(CcTest::isolate());
11670     LocalContext env;
11671     Local<v8::FunctionTemplate> fun_templ =
11672         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11673     Local<Function> fun = fun_templ->GetFunction();
11674     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11675     Local<Script> script = v8_compile("(function () {"
11676                                       "  unlock_for_a_moment();"
11677                                       "  return 42;"
11678                                       "})();");
11679     CHECK_EQ(42, script->Run()->Int32Value());
11680   }
11681   {
11682     v8::Locker locker(CcTest::isolate());
11683     v8::HandleScope scope(CcTest::isolate());
11684     LocalContext env;
11685     Local<v8::FunctionTemplate> fun_templ =
11686         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11687     Local<Function> fun = fun_templ->GetFunction();
11688     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11689     Local<Script> script = v8_compile("(function () {"
11690                                       "  unlock_for_a_moment();"
11691                                       "  return 42;"
11692                                       "})();");
11693     CHECK_EQ(42, script->Run()->Int32Value());
11694   }
11695 }
11696
11697
11698 static int GetGlobalObjectsCount() {
11699   int count = 0;
11700   i::HeapIterator it(CcTest::heap());
11701   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11702     if (object->IsJSGlobalObject()) count++;
11703   return count;
11704 }
11705
11706
11707 static void CheckSurvivingGlobalObjectsCount(int expected) {
11708   // We need to collect all garbage twice to be sure that everything
11709   // has been collected.  This is because inline caches are cleared in
11710   // the first garbage collection but some of the maps have already
11711   // been marked at that point.  Therefore some of the maps are not
11712   // collected until the second garbage collection.
11713   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11714   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
11715   int count = GetGlobalObjectsCount();
11716 #ifdef DEBUG
11717   if (count != expected) CcTest::heap()->TracePathToGlobal();
11718 #endif
11719   CHECK_EQ(expected, count);
11720 }
11721
11722
11723 TEST(DontLeakGlobalObjects) {
11724   // Regression test for issues 1139850 and 1174891.
11725
11726   i::FLAG_expose_gc = true;
11727   v8::V8::Initialize();
11728
11729   for (int i = 0; i < 5; i++) {
11730     { v8::HandleScope scope(CcTest::isolate());
11731       LocalContext context;
11732     }
11733     CcTest::isolate()->ContextDisposedNotification();
11734     CheckSurvivingGlobalObjectsCount(0);
11735
11736     { v8::HandleScope scope(CcTest::isolate());
11737       LocalContext context;
11738       v8_compile("Date")->Run();
11739     }
11740     CcTest::isolate()->ContextDisposedNotification();
11741     CheckSurvivingGlobalObjectsCount(0);
11742
11743     { v8::HandleScope scope(CcTest::isolate());
11744       LocalContext context;
11745       v8_compile("/aaa/")->Run();
11746     }
11747     CcTest::isolate()->ContextDisposedNotification();
11748     CheckSurvivingGlobalObjectsCount(0);
11749
11750     { v8::HandleScope scope(CcTest::isolate());
11751       const char* extension_list[] = { "v8/gc" };
11752       v8::ExtensionConfiguration extensions(1, extension_list);
11753       LocalContext context(&extensions);
11754       v8_compile("gc();")->Run();
11755     }
11756     CcTest::isolate()->ContextDisposedNotification();
11757     CheckSurvivingGlobalObjectsCount(0);
11758   }
11759 }
11760
11761
11762 TEST(CopyablePersistent) {
11763   LocalContext context;
11764   v8::Isolate* isolate = context->GetIsolate();
11765   i::GlobalHandles* globals =
11766       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11767   int initial_handles = globals->global_handles_count();
11768   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
11769       CopyableObject;
11770   {
11771     CopyableObject handle1;
11772     {
11773       v8::HandleScope scope(isolate);
11774       handle1.Reset(isolate, v8::Object::New(isolate));
11775     }
11776     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
11777     CopyableObject  handle2;
11778     handle2 = handle1;
11779     CHECK(handle1 == handle2);
11780     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
11781     CopyableObject handle3(handle2);
11782     CHECK(handle1 == handle3);
11783     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
11784   }
11785   // Verify autodispose
11786   CHECK_EQ(initial_handles, globals->global_handles_count());
11787 }
11788
11789
11790 static void WeakApiCallback(
11791     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
11792   Local<Value> value = data.GetValue()->Get(v8_str("key"));
11793   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
11794   data.GetParameter()->Reset();
11795   delete data.GetParameter();
11796 }
11797
11798
11799 TEST(WeakCallbackApi) {
11800   LocalContext context;
11801   v8::Isolate* isolate = context->GetIsolate();
11802   i::GlobalHandles* globals =
11803       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11804   int initial_handles = globals->global_handles_count();
11805   {
11806     v8::HandleScope scope(isolate);
11807     v8::Local<v8::Object> obj = v8::Object::New(isolate);
11808     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
11809     v8::Persistent<v8::Object>* handle =
11810         new v8::Persistent<v8::Object>(isolate, obj);
11811     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
11812                                                              WeakApiCallback);
11813   }
11814   reinterpret_cast<i::Isolate*>(isolate)->heap()->
11815       CollectAllGarbage(i::Heap::kNoGCFlags);
11816   // Verify disposed.
11817   CHECK_EQ(initial_handles, globals->global_handles_count());
11818 }
11819
11820
11821 v8::Persistent<v8::Object> some_object;
11822 v8::Persistent<v8::Object> bad_handle;
11823
11824 void NewPersistentHandleCallback(
11825     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11826   v8::HandleScope scope(data.GetIsolate());
11827   bad_handle.Reset(data.GetIsolate(), some_object);
11828   data.GetParameter()->Reset();
11829 }
11830
11831
11832 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11833   LocalContext context;
11834   v8::Isolate* isolate = context->GetIsolate();
11835
11836   v8::Persistent<v8::Object> handle1, handle2;
11837   {
11838     v8::HandleScope scope(isolate);
11839     some_object.Reset(isolate, v8::Object::New(isolate));
11840     handle1.Reset(isolate, v8::Object::New(isolate));
11841     handle2.Reset(isolate, v8::Object::New(isolate));
11842   }
11843   // Note: order is implementation dependent alas: currently
11844   // global handle nodes are processed by PostGarbageCollectionProcessing
11845   // in reverse allocation order, so if second allocated handle is deleted,
11846   // weak callback of the first handle would be able to 'reallocate' it.
11847   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
11848   handle2.Reset();
11849   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11850 }
11851
11852
11853 v8::Persistent<v8::Object> to_be_disposed;
11854
11855 void DisposeAndForceGcCallback(
11856     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11857   to_be_disposed.Reset();
11858   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11859   data.GetParameter()->Reset();
11860 }
11861
11862
11863 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11864   LocalContext context;
11865   v8::Isolate* isolate = context->GetIsolate();
11866
11867   v8::Persistent<v8::Object> handle1, handle2;
11868   {
11869     v8::HandleScope scope(isolate);
11870     handle1.Reset(isolate, v8::Object::New(isolate));
11871     handle2.Reset(isolate, v8::Object::New(isolate));
11872   }
11873   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
11874   to_be_disposed.Reset(isolate, handle2);
11875   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11876 }
11877
11878 void DisposingCallback(
11879     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11880   data.GetParameter()->Reset();
11881 }
11882
11883 void HandleCreatingCallback(
11884     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11885   v8::HandleScope scope(data.GetIsolate());
11886   v8::Persistent<v8::Object>(data.GetIsolate(),
11887                              v8::Object::New(data.GetIsolate()));
11888   data.GetParameter()->Reset();
11889 }
11890
11891
11892 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11893   LocalContext context;
11894   v8::Isolate* isolate = context->GetIsolate();
11895
11896   v8::Persistent<v8::Object> handle1, handle2, handle3;
11897   {
11898     v8::HandleScope scope(isolate);
11899     handle3.Reset(isolate, v8::Object::New(isolate));
11900     handle2.Reset(isolate, v8::Object::New(isolate));
11901     handle1.Reset(isolate, v8::Object::New(isolate));
11902   }
11903   handle2.SetWeak(&handle2, DisposingCallback);
11904   handle3.SetWeak(&handle3, HandleCreatingCallback);
11905   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11906 }
11907
11908
11909 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11910   v8::V8::Initialize();
11911
11912   const int nof = 2;
11913   const char* sources[nof] = {
11914     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11915     "Object()"
11916   };
11917
11918   for (int i = 0; i < nof; i++) {
11919     const char* source = sources[i];
11920     { v8::HandleScope scope(CcTest::isolate());
11921       LocalContext context;
11922       CompileRun(source);
11923     }
11924     { v8::HandleScope scope(CcTest::isolate());
11925       LocalContext context;
11926       CompileRun(source);
11927     }
11928   }
11929 }
11930
11931
11932 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
11933   v8::EscapableHandleScope inner(env->GetIsolate());
11934   env->Enter();
11935   v8::Local<Value> three = v8_num(3);
11936   v8::Local<Value> value = inner.Escape(three);
11937   env->Exit();
11938   return value;
11939 }
11940
11941
11942 THREADED_TEST(NestedHandleScopeAndContexts) {
11943   v8::Isolate* isolate = CcTest::isolate();
11944   v8::HandleScope outer(isolate);
11945   v8::Local<Context> env = Context::New(isolate);
11946   env->Enter();
11947   v8::Handle<Value> value = NestedScope(env);
11948   v8::Handle<String> str(value->ToString(isolate));
11949   CHECK(!str.IsEmpty());
11950   env->Exit();
11951 }
11952
11953
11954 static bool MatchPointers(void* key1, void* key2) {
11955   return key1 == key2;
11956 }
11957
11958
11959 struct SymbolInfo {
11960   size_t id;
11961   size_t size;
11962   std::string name;
11963 };
11964
11965
11966 class SetFunctionEntryHookTest {
11967  public:
11968   SetFunctionEntryHookTest() {
11969     CHECK(instance_ == NULL);
11970     instance_ = this;
11971   }
11972   ~SetFunctionEntryHookTest() {
11973     CHECK(instance_ == this);
11974     instance_ = NULL;
11975   }
11976   void Reset() {
11977     symbols_.clear();
11978     symbol_locations_.clear();
11979     invocations_.clear();
11980   }
11981   void RunTest();
11982   void OnJitEvent(const v8::JitCodeEvent* event);
11983   static void JitEvent(const v8::JitCodeEvent* event) {
11984     CHECK(instance_ != NULL);
11985     instance_->OnJitEvent(event);
11986   }
11987
11988   void OnEntryHook(uintptr_t function,
11989                    uintptr_t return_addr_location);
11990   static void EntryHook(uintptr_t function,
11991                         uintptr_t return_addr_location) {
11992     CHECK(instance_ != NULL);
11993     instance_->OnEntryHook(function, return_addr_location);
11994   }
11995
11996   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11997     CHECK(instance_ != NULL);
11998     args.GetReturnValue().Set(v8_num(42));
11999   }
12000   void RunLoopInNewEnv(v8::Isolate* isolate);
12001
12002   // Records addr as location of symbol.
12003   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
12004
12005   // Finds the symbol containing addr
12006   SymbolInfo* FindSymbolForAddr(i::Address addr);
12007   // Returns the number of invocations where the caller name contains
12008   // \p caller_name and the function name contains \p function_name.
12009   int CountInvocations(const char* caller_name,
12010                        const char* function_name);
12011
12012   i::Handle<i::JSFunction> foo_func_;
12013   i::Handle<i::JSFunction> bar_func_;
12014
12015   typedef std::map<size_t, SymbolInfo> SymbolMap;
12016   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
12017   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
12018   SymbolMap symbols_;
12019   SymbolLocationMap symbol_locations_;
12020   InvocationMap invocations_;
12021
12022   static SetFunctionEntryHookTest* instance_;
12023 };
12024 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12025
12026
12027 // Returns true if addr is in the range [start, start+len).
12028 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12029   if (start <= addr && start + len > addr)
12030     return true;
12031
12032   return false;
12033 }
12034
12035 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12036                                               SymbolInfo* symbol) {
12037   // Insert the symbol at the new location.
12038   SymbolLocationMap::iterator it =
12039       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12040   // Now erase symbols to the left and right that overlap this one.
12041   while (it != symbol_locations_.begin()) {
12042     SymbolLocationMap::iterator left = it;
12043     --left;
12044     if (!Overlaps(left->first, left->second->size, addr))
12045       break;
12046     symbol_locations_.erase(left);
12047   }
12048
12049   // Now erase symbols to the left and right that overlap this one.
12050   while (true) {
12051     SymbolLocationMap::iterator right = it;
12052     ++right;
12053     if (right == symbol_locations_.end())
12054         break;
12055     if (!Overlaps(addr, symbol->size, right->first))
12056       break;
12057     symbol_locations_.erase(right);
12058   }
12059 }
12060
12061
12062 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12063   switch (event->type) {
12064     case v8::JitCodeEvent::CODE_ADDED: {
12065         CHECK(event->code_start != NULL);
12066         CHECK_NE(0, static_cast<int>(event->code_len));
12067         CHECK(event->name.str != NULL);
12068         size_t symbol_id = symbols_.size();
12069
12070         // Record the new symbol.
12071         SymbolInfo& info = symbols_[symbol_id];
12072         info.id = symbol_id;
12073         info.size = event->code_len;
12074         info.name.assign(event->name.str, event->name.str + event->name.len);
12075
12076         // And record it's location.
12077         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
12078       }
12079       break;
12080
12081     case v8::JitCodeEvent::CODE_MOVED: {
12082         // We would like to never see code move that we haven't seen before,
12083         // but the code creation event does not happen until the line endings
12084         // have been calculated (this is so that we can report the line in the
12085         // script at which the function source is found, see
12086         // Compiler::RecordFunctionCompilation) and the line endings
12087         // calculations can cause a GC, which can move the newly created code
12088         // before its existence can be logged.
12089         SymbolLocationMap::iterator it(
12090             symbol_locations_.find(
12091                 reinterpret_cast<i::Address>(event->code_start)));
12092         if (it != symbol_locations_.end()) {
12093           // Found a symbol at this location, move it.
12094           SymbolInfo* info = it->second;
12095           symbol_locations_.erase(it);
12096           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
12097                          info);
12098         }
12099       }
12100     default:
12101       break;
12102   }
12103 }
12104
12105 void SetFunctionEntryHookTest::OnEntryHook(
12106     uintptr_t function, uintptr_t return_addr_location) {
12107   // Get the function's code object.
12108   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
12109       reinterpret_cast<i::Address>(function));
12110   CHECK(function_code != NULL);
12111
12112   // Then try and look up the caller's code object.
12113   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
12114
12115   // Count the invocation.
12116   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
12117   SymbolInfo* function_symbol =
12118       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
12119   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12120
12121   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12122     // Check that we have a symbol for the "bar" function at the right location.
12123     SymbolLocationMap::iterator it(
12124         symbol_locations_.find(function_code->instruction_start()));
12125     CHECK(it != symbol_locations_.end());
12126   }
12127
12128   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12129     // Check that we have a symbol for "foo" at the right location.
12130     SymbolLocationMap::iterator it(
12131         symbol_locations_.find(function_code->instruction_start()));
12132     CHECK(it != symbol_locations_.end());
12133   }
12134 }
12135
12136
12137 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12138   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12139   // Do we have a direct hit on a symbol?
12140   if (it != symbol_locations_.end()) {
12141     if (it->first == addr)
12142       return it->second;
12143   }
12144
12145   // If not a direct hit, it'll have to be the previous symbol.
12146   if (it == symbol_locations_.begin())
12147     return NULL;
12148
12149   --it;
12150   size_t offs = addr - it->first;
12151   if (offs < it->second->size)
12152     return it->second;
12153
12154   return NULL;
12155 }
12156
12157
12158 int SetFunctionEntryHookTest::CountInvocations(
12159     const char* caller_name, const char* function_name) {
12160   InvocationMap::iterator it(invocations_.begin());
12161   int invocations = 0;
12162   for (; it != invocations_.end(); ++it) {
12163     SymbolInfo* caller = it->first.first;
12164     SymbolInfo* function = it->first.second;
12165
12166     // Filter out non-matching functions.
12167     if (function_name != NULL) {
12168       if (function->name.find(function_name) == std::string::npos)
12169         continue;
12170     }
12171
12172     // Filter out non-matching callers.
12173     if (caller_name != NULL) {
12174       if (caller == NULL)
12175         continue;
12176       if (caller->name.find(caller_name) == std::string::npos)
12177         continue;
12178     }
12179
12180     // It matches add the invocation count to the tally.
12181     invocations += it->second;
12182   }
12183
12184   return invocations;
12185 }
12186
12187
12188 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12189   v8::HandleScope outer(isolate);
12190   v8::Local<Context> env = Context::New(isolate);
12191   env->Enter();
12192
12193   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12194   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
12195   env->Global()->Set(v8_str("obj"), t->NewInstance());
12196
12197   const char* script =
12198       "function bar() {\n"
12199       "  var sum = 0;\n"
12200       "  for (i = 0; i < 100; ++i)\n"
12201       "    sum = foo(i);\n"
12202       "  return sum;\n"
12203       "}\n"
12204       "function foo(i) { return i * i; }\n"
12205       "// Invoke on the runtime function.\n"
12206       "obj.asdf()";
12207   CompileRun(script);
12208   bar_func_ = i::Handle<i::JSFunction>::cast(
12209           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12210   DCHECK(!bar_func_.is_null());
12211
12212   foo_func_ =
12213       i::Handle<i::JSFunction>::cast(
12214            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12215   DCHECK(!foo_func_.is_null());
12216
12217   v8::Handle<v8::Value> value = CompileRun("bar();");
12218   CHECK(value->IsNumber());
12219   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12220
12221   // Test the optimized codegen path.
12222   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12223                      "bar();");
12224   CHECK(value->IsNumber());
12225   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12226
12227   env->Exit();
12228 }
12229
12230
12231 void SetFunctionEntryHookTest::RunTest() {
12232   // Work in a new isolate throughout.
12233   v8::Isolate::CreateParams create_params;
12234   create_params.entry_hook = EntryHook;
12235   create_params.code_event_handler = JitEvent;
12236   v8::Isolate* isolate = v8::Isolate::New(create_params);
12237
12238   {
12239     v8::Isolate::Scope scope(isolate);
12240
12241     RunLoopInNewEnv(isolate);
12242
12243     // Check the exepected invocation counts.
12244     CHECK_EQ(2, CountInvocations(NULL, "bar"));
12245     CHECK_EQ(200, CountInvocations("bar", "foo"));
12246     CHECK_EQ(200, CountInvocations(NULL, "foo"));
12247
12248     // Verify that we have an entry hook on some specific stubs.
12249     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12250     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12251     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12252   }
12253   isolate->Dispose();
12254
12255   Reset();
12256
12257   // Make sure a second isolate is unaffected by the previous entry hook.
12258   isolate = v8::Isolate::New();
12259   {
12260     v8::Isolate::Scope scope(isolate);
12261
12262     // Reset the entry count to zero and set the entry hook.
12263     RunLoopInNewEnv(isolate);
12264
12265     // We should record no invocations in this isolate.
12266     CHECK_EQ(0, static_cast<int>(invocations_.size()));
12267   }
12268
12269   isolate->Dispose();
12270 }
12271
12272
12273 TEST(SetFunctionEntryHook) {
12274   // FunctionEntryHook does not work well with experimental natives.
12275   // Experimental natives are compiled during snapshot deserialization.
12276   // This test breaks because InstallGetter (function from snapshot that
12277   // only gets called from experimental natives) is compiled with entry hooks.
12278   i::FLAG_allow_natives_syntax = true;
12279   i::FLAG_use_inlining = false;
12280
12281   SetFunctionEntryHookTest test;
12282   test.RunTest();
12283 }
12284
12285
12286 static i::HashMap* code_map = NULL;
12287 static i::HashMap* jitcode_line_info = NULL;
12288 static int saw_bar = 0;
12289 static int move_events = 0;
12290
12291
12292 static bool FunctionNameIs(const char* expected,
12293                            const v8::JitCodeEvent* event) {
12294   // Log lines for functions are of the general form:
12295   // "LazyCompile:<type><function_name>", where the type is one of
12296   // "*", "~" or "".
12297   static const char kPreamble[] = "LazyCompile:";
12298   static size_t kPreambleLen = sizeof(kPreamble) - 1;
12299
12300   if (event->name.len < sizeof(kPreamble) - 1 ||
12301       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12302     return false;
12303   }
12304
12305   const char* tail = event->name.str + kPreambleLen;
12306   size_t tail_len = event->name.len - kPreambleLen;
12307   size_t expected_len = strlen(expected);
12308   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12309     --tail_len;
12310     ++tail;
12311   }
12312
12313   // Check for tails like 'bar :1'.
12314   if (tail_len > expected_len + 2 &&
12315       tail[expected_len] == ' ' &&
12316       tail[expected_len + 1] == ':' &&
12317       tail[expected_len + 2] &&
12318       !strncmp(tail, expected, expected_len)) {
12319     return true;
12320   }
12321
12322   if (tail_len != expected_len)
12323     return false;
12324
12325   return strncmp(tail, expected, expected_len) == 0;
12326 }
12327
12328
12329 static void event_handler(const v8::JitCodeEvent* event) {
12330   CHECK(event != NULL);
12331   CHECK(code_map != NULL);
12332   CHECK(jitcode_line_info != NULL);
12333
12334   class DummyJitCodeLineInfo {
12335   };
12336
12337   switch (event->type) {
12338     case v8::JitCodeEvent::CODE_ADDED: {
12339         CHECK(event->code_start != NULL);
12340         CHECK_NE(0, static_cast<int>(event->code_len));
12341         CHECK(event->name.str != NULL);
12342         i::HashMap::Entry* entry =
12343             code_map->Lookup(event->code_start,
12344                              i::ComputePointerHash(event->code_start),
12345                              true);
12346         entry->value = reinterpret_cast<void*>(event->code_len);
12347
12348         if (FunctionNameIs("bar", event)) {
12349           ++saw_bar;
12350         }
12351       }
12352       break;
12353
12354     case v8::JitCodeEvent::CODE_MOVED: {
12355         uint32_t hash = i::ComputePointerHash(event->code_start);
12356         // We would like to never see code move that we haven't seen before,
12357         // but the code creation event does not happen until the line endings
12358         // have been calculated (this is so that we can report the line in the
12359         // script at which the function source is found, see
12360         // Compiler::RecordFunctionCompilation) and the line endings
12361         // calculations can cause a GC, which can move the newly created code
12362         // before its existence can be logged.
12363         i::HashMap::Entry* entry =
12364             code_map->Lookup(event->code_start, hash, false);
12365         if (entry != NULL) {
12366           ++move_events;
12367
12368           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12369           code_map->Remove(event->code_start, hash);
12370
12371           entry = code_map->Lookup(event->new_code_start,
12372                                    i::ComputePointerHash(event->new_code_start),
12373                                    true);
12374           CHECK(entry != NULL);
12375           entry->value = reinterpret_cast<void*>(event->code_len);
12376         }
12377       }
12378       break;
12379
12380     case v8::JitCodeEvent::CODE_REMOVED:
12381       // Object/code removal events are currently not dispatched from the GC.
12382       CHECK(false);
12383       break;
12384
12385     // For CODE_START_LINE_INFO_RECORDING event, we will create one
12386     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12387     // record it in jitcode_line_info.
12388     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12389         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12390         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12391         temp_event->user_data = line_info;
12392         i::HashMap::Entry* entry =
12393             jitcode_line_info->Lookup(line_info,
12394                                       i::ComputePointerHash(line_info),
12395                                       true);
12396         entry->value = reinterpret_cast<void*>(line_info);
12397       }
12398       break;
12399     // For these two events, we will check whether the event->user_data
12400     // data structure is created before during CODE_START_LINE_INFO_RECORDING
12401     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12402     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12403         CHECK(event->user_data != NULL);
12404         uint32_t hash = i::ComputePointerHash(event->user_data);
12405         i::HashMap::Entry* entry =
12406             jitcode_line_info->Lookup(event->user_data, hash, false);
12407         CHECK(entry != NULL);
12408         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12409       }
12410       break;
12411
12412     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12413         CHECK(event->user_data != NULL);
12414         uint32_t hash = i::ComputePointerHash(event->user_data);
12415         i::HashMap::Entry* entry =
12416             jitcode_line_info->Lookup(event->user_data, hash, false);
12417         CHECK(entry != NULL);
12418       }
12419       break;
12420
12421     default:
12422       // Impossible event.
12423       CHECK(false);
12424       break;
12425   }
12426 }
12427
12428
12429 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
12430   i::FLAG_stress_compaction = true;
12431   i::FLAG_incremental_marking = false;
12432   if (i::FLAG_never_compact) return;
12433   const char* script =
12434       "function bar() {"
12435       "  var sum = 0;"
12436       "  for (i = 0; i < 10; ++i)"
12437       "    sum = foo(i);"
12438       "  return sum;"
12439       "}"
12440       "function foo(i) { return i; };"
12441       "bar();";
12442
12443   // Run this test in a new isolate to make sure we don't
12444   // have remnants of state from other code.
12445   v8::Isolate* isolate = v8::Isolate::New();
12446   isolate->Enter();
12447   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
12448   i::Heap* heap = i_isolate->heap();
12449
12450   // Start with a clean slate.
12451   heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare");
12452
12453   {
12454     v8::HandleScope scope(isolate);
12455     i::HashMap code(MatchPointers);
12456     code_map = &code;
12457
12458     i::HashMap lineinfo(MatchPointers);
12459     jitcode_line_info = &lineinfo;
12460
12461     saw_bar = 0;
12462     move_events = 0;
12463
12464     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12465
12466     // Generate new code objects sparsely distributed across several
12467     // different fragmented code-space pages.
12468     const int kIterations = 10;
12469     for (int i = 0; i < kIterations; ++i) {
12470       LocalContext env(isolate);
12471       i::AlwaysAllocateScope always_allocate(i_isolate);
12472       SimulateFullSpace(heap->code_space());
12473       CompileRun(script);
12474
12475       // Keep a strong reference to the code object in the handle scope.
12476       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12477           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12478       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12479           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
12480
12481       // Clear the compilation cache to get more wastage.
12482       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
12483     }
12484
12485     // Force code movement.
12486     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move");
12487
12488     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12489
12490     CHECK_LE(kIterations, saw_bar);
12491     CHECK_LT(0, move_events);
12492
12493     code_map = NULL;
12494     jitcode_line_info = NULL;
12495   }
12496
12497   isolate->Exit();
12498   isolate->Dispose();
12499
12500   // Do this in a new isolate.
12501   isolate = v8::Isolate::New();
12502   isolate->Enter();
12503
12504   // Verify that we get callbacks for existing code objects when we
12505   // request enumeration of existing code.
12506   {
12507     v8::HandleScope scope(isolate);
12508     LocalContext env(isolate);
12509     CompileRun(script);
12510
12511     // Now get code through initial iteration.
12512     i::HashMap code(MatchPointers);
12513     code_map = &code;
12514
12515     i::HashMap lineinfo(MatchPointers);
12516     jitcode_line_info = &lineinfo;
12517
12518     isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
12519                                     event_handler);
12520     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12521
12522     jitcode_line_info = NULL;
12523     // We expect that we got some events. Note that if we could get code removal
12524     // notifications, we could compare two collections, one created by listening
12525     // from the time of creation of an isolate, and the other by subscribing
12526     // with EnumExisting.
12527     CHECK_LT(0u, code.occupancy());
12528
12529     code_map = NULL;
12530   }
12531
12532   isolate->Exit();
12533   isolate->Dispose();
12534 }
12535
12536
12537 THREADED_TEST(ExternalAllocatedMemory) {
12538   v8::Isolate* isolate = CcTest::isolate();
12539   v8::HandleScope outer(isolate);
12540   v8::Local<Context> env(Context::New(isolate));
12541   CHECK(!env.IsEmpty());
12542   const int64_t kSize = 1024*1024;
12543   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
12544   CHECK_EQ(baseline + kSize,
12545            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
12546   CHECK_EQ(baseline,
12547            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
12548   const int64_t kTriggerGCSize =
12549       v8::internal::Internals::kExternalAllocationLimit + 1;
12550   CHECK_EQ(baseline + kTriggerGCSize,
12551            isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
12552   CHECK_EQ(baseline,
12553            isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
12554 }
12555
12556
12557 // Regression test for issue 54, object templates with internal fields
12558 // but no accessors or interceptors did not get their internal field
12559 // count set on instances.
12560 THREADED_TEST(Regress54) {
12561   LocalContext context;
12562   v8::Isolate* isolate = context->GetIsolate();
12563   v8::HandleScope outer(isolate);
12564   static v8::Persistent<v8::ObjectTemplate> templ;
12565   if (templ.IsEmpty()) {
12566     v8::EscapableHandleScope inner(isolate);
12567     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
12568     local->SetInternalFieldCount(1);
12569     templ.Reset(isolate, inner.Escape(local));
12570   }
12571   v8::Handle<v8::Object> result =
12572       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
12573   CHECK_EQ(1, result->InternalFieldCount());
12574 }
12575
12576
12577 // If part of the threaded tests, this test makes ThreadingTest fail
12578 // on mac.
12579 TEST(CatchStackOverflow) {
12580   LocalContext context;
12581   v8::HandleScope scope(context->GetIsolate());
12582   v8::TryCatch try_catch;
12583   v8::Handle<v8::Value> result = CompileRun(
12584     "function f() {"
12585     "  return f();"
12586     "}"
12587     ""
12588     "f();");
12589   CHECK(result.IsEmpty());
12590 }
12591
12592
12593 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
12594                                     const char* resource_name,
12595                                     int line_offset) {
12596   v8::HandleScope scope(CcTest::isolate());
12597   v8::TryCatch try_catch;
12598   v8::Handle<v8::Value> result = script->Run();
12599   CHECK(result.IsEmpty());
12600   CHECK(try_catch.HasCaught());
12601   v8::Handle<v8::Message> message = try_catch.Message();
12602   CHECK(!message.IsEmpty());
12603   CHECK_EQ(10 + line_offset, message->GetLineNumber());
12604   CHECK_EQ(91, message->GetStartPosition());
12605   CHECK_EQ(92, message->GetEndPosition());
12606   CHECK_EQ(2, message->GetStartColumn());
12607   CHECK_EQ(3, message->GetEndColumn());
12608   v8::String::Utf8Value line(message->GetSourceLine());
12609   CHECK_EQ(0, strcmp("  throw 'nirk';", *line));
12610   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
12611   CHECK_EQ(0, strcmp(resource_name, *name));
12612 }
12613
12614
12615 THREADED_TEST(TryCatchSourceInfo) {
12616   LocalContext context;
12617   v8::HandleScope scope(context->GetIsolate());
12618   v8::Local<v8::String> source = v8_str(
12619       "function Foo() {\n"
12620       "  return Bar();\n"
12621       "}\n"
12622       "\n"
12623       "function Bar() {\n"
12624       "  return Baz();\n"
12625       "}\n"
12626       "\n"
12627       "function Baz() {\n"
12628       "  throw 'nirk';\n"
12629       "}\n"
12630       "\n"
12631       "Foo();\n");
12632
12633   const char* resource_name;
12634   v8::Handle<v8::Script> script;
12635   resource_name = "test.js";
12636   script = CompileWithOrigin(source, resource_name);
12637   CheckTryCatchSourceInfo(script, resource_name, 0);
12638
12639   resource_name = "test1.js";
12640   v8::ScriptOrigin origin1(
12641       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
12642   script = v8::Script::Compile(source, &origin1);
12643   CheckTryCatchSourceInfo(script, resource_name, 0);
12644
12645   resource_name = "test2.js";
12646   v8::ScriptOrigin origin2(
12647       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
12648       v8::Integer::New(context->GetIsolate(), 7));
12649   script = v8::Script::Compile(source, &origin2);
12650   CheckTryCatchSourceInfo(script, resource_name, 7);
12651 }
12652
12653
12654 THREADED_TEST(CompilationCache) {
12655   LocalContext context;
12656   v8::HandleScope scope(context->GetIsolate());
12657   v8::Handle<v8::String> source0 =
12658       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12659   v8::Handle<v8::String> source1 =
12660       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12661   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
12662   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
12663   v8::Handle<v8::Script> script2 =
12664       v8::Script::Compile(source0);  // different origin
12665   CHECK_EQ(1234, script0->Run()->Int32Value());
12666   CHECK_EQ(1234, script1->Run()->Int32Value());
12667   CHECK_EQ(1234, script2->Run()->Int32Value());
12668 }
12669
12670
12671 static void FunctionNameCallback(
12672     const v8::FunctionCallbackInfo<v8::Value>& args) {
12673   ApiTestFuzzer::Fuzz();
12674   args.GetReturnValue().Set(v8_num(42));
12675 }
12676
12677
12678 THREADED_TEST(CallbackFunctionName) {
12679   LocalContext context;
12680   v8::Isolate* isolate = context->GetIsolate();
12681   v8::HandleScope scope(isolate);
12682   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12683   t->Set(v8_str("asdf"),
12684          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
12685   context->Global()->Set(v8_str("obj"), t->NewInstance());
12686   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
12687   CHECK(value->IsString());
12688   v8::String::Utf8Value name(value);
12689   CHECK_EQ(0, strcmp("asdf", *name));
12690 }
12691
12692
12693 THREADED_TEST(DateAccess) {
12694   LocalContext context;
12695   v8::HandleScope scope(context->GetIsolate());
12696   v8::Handle<v8::Value> date =
12697       v8::Date::New(context->GetIsolate(), 1224744689038.0);
12698   CHECK(date->IsDate());
12699   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
12700 }
12701
12702
12703 void CheckProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12704                      unsigned elmc, const char* elmv[]) {
12705   v8::Handle<v8::Object> obj = val.As<v8::Object>();
12706   v8::Handle<v8::Array> props = obj->GetPropertyNames();
12707   CHECK_EQ(elmc, props->Length());
12708   for (unsigned i = 0; i < elmc; i++) {
12709     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12710     CHECK_EQ(0, strcmp(elmv[i], *elm));
12711   }
12712 }
12713
12714
12715 void CheckOwnProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12716                         unsigned elmc, const char* elmv[]) {
12717   v8::Handle<v8::Object> obj = val.As<v8::Object>();
12718   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
12719   CHECK_EQ(elmc, props->Length());
12720   for (unsigned i = 0; i < elmc; i++) {
12721     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12722     CHECK_EQ(0, strcmp(elmv[i], *elm));
12723   }
12724 }
12725
12726
12727 THREADED_TEST(PropertyEnumeration) {
12728   LocalContext context;
12729   v8::Isolate* isolate = context->GetIsolate();
12730   v8::HandleScope scope(isolate);
12731   v8::Handle<v8::Value> obj = CompileRun(
12732       "var result = [];"
12733       "result[0] = {};"
12734       "result[1] = {a: 1, b: 2};"
12735       "result[2] = [1, 2, 3];"
12736       "var proto = {x: 1, y: 2, z: 3};"
12737       "var x = { __proto__: proto, w: 0, z: 1 };"
12738       "result[3] = x;"
12739       "result;");
12740   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12741   CHECK_EQ(4u, elms->Length());
12742   int elmc0 = 0;
12743   const char** elmv0 = NULL;
12744   CheckProperties(
12745       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12746   CheckOwnProperties(
12747       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12748   int elmc1 = 2;
12749   const char* elmv1[] = {"a", "b"};
12750   CheckProperties(
12751       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12752   CheckOwnProperties(
12753       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12754   int elmc2 = 3;
12755   const char* elmv2[] = {"0", "1", "2"};
12756   CheckProperties(
12757       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12758   CheckOwnProperties(
12759       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12760   int elmc3 = 4;
12761   const char* elmv3[] = {"w", "z", "x", "y"};
12762   CheckProperties(
12763       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
12764   int elmc4 = 2;
12765   const char* elmv4[] = {"w", "z"};
12766   CheckOwnProperties(
12767       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
12768 }
12769
12770
12771 THREADED_TEST(PropertyEnumeration2) {
12772   LocalContext context;
12773   v8::Isolate* isolate = context->GetIsolate();
12774   v8::HandleScope scope(isolate);
12775   v8::Handle<v8::Value> obj = CompileRun(
12776       "var result = [];"
12777       "result[0] = {};"
12778       "result[1] = {a: 1, b: 2};"
12779       "result[2] = [1, 2, 3];"
12780       "var proto = {x: 1, y: 2, z: 3};"
12781       "var x = { __proto__: proto, w: 0, z: 1 };"
12782       "result[3] = x;"
12783       "result;");
12784   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12785   CHECK_EQ(4u, elms->Length());
12786   int elmc0 = 0;
12787   const char** elmv0 = NULL;
12788   CheckProperties(isolate,
12789                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12790
12791   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
12792   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
12793   CHECK_EQ(0u, props->Length());
12794   for (uint32_t i = 0; i < props->Length(); i++) {
12795     printf("p[%u]\n", i);
12796   }
12797 }
12798
12799
12800 THREADED_TEST(AccessChecksReenabledCorrectly) {
12801   LocalContext context;
12802   v8::Isolate* isolate = context->GetIsolate();
12803   v8::HandleScope scope(isolate);
12804   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12805   templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
12806   templ->Set(v8_str("a"), v8_str("a"));
12807   // Add more than 8 (see kMaxFastProperties) properties
12808   // so that the constructor will force copying map.
12809   // Cannot sprintf, gcc complains unsafety.
12810   char buf[4];
12811   for (char i = '0'; i <= '9' ; i++) {
12812     buf[0] = i;
12813     for (char j = '0'; j <= '9'; j++) {
12814       buf[1] = j;
12815       for (char k = '0'; k <= '9'; k++) {
12816         buf[2] = k;
12817         buf[3] = 0;
12818         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
12819       }
12820     }
12821   }
12822
12823   Local<v8::Object> instance_1 = templ->NewInstance();
12824   context->Global()->Set(v8_str("obj_1"), instance_1);
12825
12826   Local<Value> value_1 = CompileRun("obj_1.a");
12827   CHECK(value_1.IsEmpty());
12828
12829   Local<v8::Object> instance_2 = templ->NewInstance();
12830   context->Global()->Set(v8_str("obj_2"), instance_2);
12831
12832   Local<Value> value_2 = CompileRun("obj_2.a");
12833   CHECK(value_2.IsEmpty());
12834 }
12835
12836
12837 THREADED_TEST(TurnOnAccessCheck) {
12838   v8::Isolate* isolate = CcTest::isolate();
12839   v8::HandleScope handle_scope(isolate);
12840
12841   // Create an environment with access check to the global object disabled by
12842   // default.
12843   v8::Handle<v8::ObjectTemplate> global_template =
12844       v8::ObjectTemplate::New(isolate);
12845   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
12846                                            v8::Handle<v8::Value>(), false);
12847   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
12848   Context::Scope context_scope(context);
12849
12850   // Set up a property and a number of functions.
12851   context->Global()->Set(v8_str("a"), v8_num(1));
12852   CompileRun("function f1() {return a;}"
12853              "function f2() {return a;}"
12854              "function g1() {return h();}"
12855              "function g2() {return h();}"
12856              "function h() {return 1;}");
12857   Local<Function> f1 =
12858       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12859   Local<Function> f2 =
12860       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12861   Local<Function> g1 =
12862       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12863   Local<Function> g2 =
12864       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12865   Local<Function> h =
12866       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12867
12868   // Get the global object.
12869   v8::Handle<v8::Object> global = context->Global();
12870
12871   // Call f1 one time and f2 a number of times. This will ensure that f1 still
12872   // uses the runtime system to retreive property a whereas f2 uses global load
12873   // inline cache.
12874   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12875   for (int i = 0; i < 4; i++) {
12876     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12877   }
12878
12879   // Same for g1 and g2.
12880   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12881   for (int i = 0; i < 4; i++) {
12882     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12883   }
12884
12885   // Detach the global and turn on access check.
12886   Local<Object> hidden_global = Local<Object>::Cast(
12887       context->Global()->GetPrototype());
12888   context->DetachGlobal();
12889   hidden_global->TurnOnAccessCheck();
12890
12891   // Failing access check results in exception.
12892   CHECK(f1->Call(global, 0, NULL).IsEmpty());
12893   CHECK(f2->Call(global, 0, NULL).IsEmpty());
12894   CHECK(g1->Call(global, 0, NULL).IsEmpty());
12895   CHECK(g2->Call(global, 0, NULL).IsEmpty());
12896
12897   // No failing access check when just returning a constant.
12898   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12899 }
12900
12901
12902 // Tests that ScriptData can be serialized and deserialized.
12903 TEST(PreCompileSerialization) {
12904   v8::V8::Initialize();
12905   LocalContext env;
12906   v8::Isolate* isolate = env->GetIsolate();
12907   HandleScope handle_scope(isolate);
12908
12909   i::FLAG_min_preparse_length = 0;
12910   const char* script = "function foo(a) { return a+1; }";
12911   v8::ScriptCompiler::Source source(v8_str(script));
12912   v8::ScriptCompiler::Compile(isolate, &source,
12913                               v8::ScriptCompiler::kProduceParserCache);
12914   // Serialize.
12915   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
12916   i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
12917   i::MemCopy(serialized_data, cd->data, cd->length);
12918
12919   // Deserialize.
12920   i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
12921
12922   // Verify that the original is the same as the deserialized.
12923   CHECK_EQ(cd->length, deserialized->length());
12924   CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
12925
12926   delete deserialized;
12927   i::DeleteArray(serialized_data);
12928 }
12929
12930
12931 // This tests that we do not allow dictionary load/call inline caches
12932 // to use functions that have not yet been compiled.  The potential
12933 // problem of loading a function that has not yet been compiled can
12934 // arise because we share code between contexts via the compilation
12935 // cache.
12936 THREADED_TEST(DictionaryICLoadedFunction) {
12937   v8::HandleScope scope(CcTest::isolate());
12938   // Test LoadIC.
12939   for (int i = 0; i < 2; i++) {
12940     LocalContext context;
12941     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12942     context->Global()->Delete(v8_str("tmp"));
12943     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12944   }
12945   // Test CallIC.
12946   for (int i = 0; i < 2; i++) {
12947     LocalContext context;
12948     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12949     context->Global()->Delete(v8_str("tmp"));
12950     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12951   }
12952 }
12953
12954
12955 // Test that cross-context new calls use the context of the callee to
12956 // create the new JavaScript object.
12957 THREADED_TEST(CrossContextNew) {
12958   v8::Isolate* isolate = CcTest::isolate();
12959   v8::HandleScope scope(isolate);
12960   v8::Local<Context> context0 = Context::New(isolate);
12961   v8::Local<Context> context1 = Context::New(isolate);
12962
12963   // Allow cross-domain access.
12964   Local<String> token = v8_str("<security token>");
12965   context0->SetSecurityToken(token);
12966   context1->SetSecurityToken(token);
12967
12968   // Set an 'x' property on the Object prototype and define a
12969   // constructor function in context0.
12970   context0->Enter();
12971   CompileRun("Object.prototype.x = 42; function C() {};");
12972   context0->Exit();
12973
12974   // Call the constructor function from context0 and check that the
12975   // result has the 'x' property.
12976   context1->Enter();
12977   context1->Global()->Set(v8_str("other"), context0->Global());
12978   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12979   CHECK(value->IsInt32());
12980   CHECK_EQ(42, value->Int32Value());
12981   context1->Exit();
12982 }
12983
12984
12985 // Verify that we can clone an object
12986 TEST(ObjectClone) {
12987   LocalContext env;
12988   v8::Isolate* isolate = env->GetIsolate();
12989   v8::HandleScope scope(isolate);
12990
12991   const char* sample =
12992     "var rv = {};"      \
12993     "rv.alpha = 'hello';" \
12994     "rv.beta = 123;"     \
12995     "rv;";
12996
12997   // Create an object, verify basics.
12998   Local<Value> val = CompileRun(sample);
12999   CHECK(val->IsObject());
13000   Local<v8::Object> obj = val.As<v8::Object>();
13001   obj->Set(v8_str("gamma"), v8_str("cloneme"));
13002
13003   CHECK(v8_str("hello")->Equals(obj->Get(v8_str("alpha"))));
13004   CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
13005   CHECK(v8_str("cloneme")->Equals(obj->Get(v8_str("gamma"))));
13006
13007   // Clone it.
13008   Local<v8::Object> clone = obj->Clone();
13009   CHECK(v8_str("hello")->Equals(clone->Get(v8_str("alpha"))));
13010   CHECK(v8::Integer::New(isolate, 123)->Equals(clone->Get(v8_str("beta"))));
13011   CHECK(v8_str("cloneme")->Equals(clone->Get(v8_str("gamma"))));
13012
13013   // Set a property on the clone, verify each object.
13014   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
13015   CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
13016   CHECK(v8::Integer::New(isolate, 456)->Equals(clone->Get(v8_str("beta"))));
13017 }
13018
13019
13020 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
13021  public:
13022   explicit OneByteVectorResource(i::Vector<const char> vector)
13023       : data_(vector) {}
13024   virtual ~OneByteVectorResource() {}
13025   virtual size_t length() const { return data_.length(); }
13026   virtual const char* data() const { return data_.start(); }
13027  private:
13028   i::Vector<const char> data_;
13029 };
13030
13031
13032 class UC16VectorResource : public v8::String::ExternalStringResource {
13033  public:
13034   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
13035       : data_(vector) {}
13036   virtual ~UC16VectorResource() {}
13037   virtual size_t length() const { return data_.length(); }
13038   virtual const i::uc16* data() const { return data_.start(); }
13039  private:
13040   i::Vector<const i::uc16> data_;
13041 };
13042
13043
13044 static void MorphAString(i::String* string,
13045                          OneByteVectorResource* one_byte_resource,
13046                          UC16VectorResource* uc16_resource) {
13047   CHECK(i::StringShape(string).IsExternal());
13048   if (string->IsOneByteRepresentation()) {
13049     // Check old map is not internalized or long.
13050     CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
13051     // Morph external string to be TwoByte string.
13052     string->set_map(CcTest::heap()->external_string_map());
13053     i::ExternalTwoByteString* morphed =
13054          i::ExternalTwoByteString::cast(string);
13055     morphed->set_resource(uc16_resource);
13056   } else {
13057     // Check old map is not internalized or long.
13058     CHECK(string->map() == CcTest::heap()->external_string_map());
13059     // Morph external string to be one-byte string.
13060     string->set_map(CcTest::heap()->external_one_byte_string_map());
13061     i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
13062     morphed->set_resource(one_byte_resource);
13063   }
13064 }
13065
13066
13067 // Test that we can still flatten a string if the components it is built up
13068 // from have been turned into 16 bit strings in the mean time.
13069 THREADED_TEST(MorphCompositeStringTest) {
13070   char utf_buffer[129];
13071   const char* c_string = "Now is the time for all good men"
13072                          " to come to the aid of the party";
13073   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
13074   {
13075     LocalContext env;
13076     i::Factory* factory = CcTest::i_isolate()->factory();
13077     v8::HandleScope scope(env->GetIsolate());
13078     OneByteVectorResource one_byte_resource(
13079         i::Vector<const char>(c_string, i::StrLength(c_string)));
13080     UC16VectorResource uc16_resource(
13081         i::Vector<const uint16_t>(two_byte_string,
13082                                   i::StrLength(c_string)));
13083
13084     Local<String> lhs(
13085         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13086                                         &one_byte_resource).ToHandleChecked()));
13087     Local<String> rhs(
13088         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13089                                         &one_byte_resource).ToHandleChecked()));
13090
13091     env->Global()->Set(v8_str("lhs"), lhs);
13092     env->Global()->Set(v8_str("rhs"), rhs);
13093
13094     CompileRun(
13095         "var cons = lhs + rhs;"
13096         "var slice = lhs.substring(1, lhs.length - 1);"
13097         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
13098
13099     CHECK(lhs->IsOneByte());
13100     CHECK(rhs->IsOneByte());
13101
13102     MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
13103                  &uc16_resource);
13104     MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
13105                  &uc16_resource);
13106
13107     // This should UTF-8 without flattening, since everything is ASCII.
13108     Handle<String> cons = v8_compile("cons")->Run().As<String>();
13109     CHECK_EQ(128, cons->Utf8Length());
13110     int nchars = -1;
13111     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
13112     CHECK_EQ(128, nchars);
13113     CHECK_EQ(0, strcmp(
13114         utf_buffer,
13115         "Now is the time for all good men to come to the aid of the party"
13116         "Now is the time for all good men to come to the aid of the party"));
13117
13118     // Now do some stuff to make sure the strings are flattened, etc.
13119     CompileRun(
13120         "/[^a-z]/.test(cons);"
13121         "/[^a-z]/.test(slice);"
13122         "/[^a-z]/.test(slice_on_cons);");
13123     const char* expected_cons =
13124         "Now is the time for all good men to come to the aid of the party"
13125         "Now is the time for all good men to come to the aid of the party";
13126     const char* expected_slice =
13127         "ow is the time for all good men to come to the aid of the part";
13128     const char* expected_slice_on_cons =
13129         "ow is the time for all good men to come to the aid of the party"
13130         "Now is the time for all good men to come to the aid of the part";
13131     CHECK(String::NewFromUtf8(env->GetIsolate(), expected_cons)
13132               ->Equals(env->Global()->Get(v8_str("cons"))));
13133     CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice)
13134               ->Equals(env->Global()->Get(v8_str("slice"))));
13135     CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons)
13136               ->Equals(env->Global()->Get(v8_str("slice_on_cons"))));
13137   }
13138   i::DeleteArray(two_byte_string);
13139 }
13140
13141
13142 TEST(CompileExternalTwoByteSource) {
13143   LocalContext context;
13144   v8::HandleScope scope(context->GetIsolate());
13145
13146   // This is a very short list of sources, which currently is to check for a
13147   // regression caused by r2703.
13148   const char* one_byte_sources[] = {
13149       "0.5",
13150       "-0.5",   // This mainly testes PushBack in the Scanner.
13151       "--0.5",  // This mainly testes PushBack in the Scanner.
13152       NULL};
13153
13154   // Compile the sources as external two byte strings.
13155   for (int i = 0; one_byte_sources[i] != NULL; i++) {
13156     uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
13157     TestResource* uc16_resource = new TestResource(two_byte_string);
13158     v8::Local<v8::String> source =
13159         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
13160     v8::Script::Compile(source);
13161   }
13162 }
13163
13164
13165 #ifndef V8_INTERPRETED_REGEXP
13166
13167 struct RegExpInterruptionData {
13168   v8::base::Atomic32 loop_count;
13169   UC16VectorResource* string_resource;
13170   v8::Persistent<v8::String> string;
13171 } regexp_interruption_data;
13172
13173
13174 class RegExpInterruptionThread : public v8::base::Thread {
13175  public:
13176   explicit RegExpInterruptionThread(v8::Isolate* isolate)
13177       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
13178
13179   virtual void Run() {
13180     for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
13181          v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
13182          v8::base::NoBarrier_AtomicIncrement(
13183              &regexp_interruption_data.loop_count, 1)) {
13184       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
13185       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
13186     }
13187     v8::base::OS::Sleep(50);  // Wait a bit before terminating.
13188     v8::V8::TerminateExecution(isolate_);
13189   }
13190
13191  private:
13192   v8::Isolate* isolate_;
13193 };
13194
13195
13196 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
13197   if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
13198     return;
13199   }
13200   v8::HandleScope scope(CcTest::isolate());
13201   v8::Local<v8::String> string = v8::Local<v8::String>::New(
13202       CcTest::isolate(), regexp_interruption_data.string);
13203   string->MakeExternal(regexp_interruption_data.string_resource);
13204 }
13205
13206
13207 // Test that RegExp execution can be interrupted.  Specifically, we test
13208 // * interrupting with GC
13209 // * turn the subject string from one-byte internal to two-byte external string
13210 // * force termination
13211 TEST(RegExpInterruption) {
13212   v8::HandleScope scope(CcTest::isolate());
13213   LocalContext env;
13214
13215   RegExpInterruptionThread timeout_thread(CcTest::isolate());
13216
13217   v8::V8::AddGCPrologueCallback(RunBeforeGC);
13218   static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
13219   i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
13220   v8::Local<v8::String> string = v8_str(one_byte_content);
13221
13222   CcTest::global()->Set(v8_str("a"), string);
13223   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
13224   regexp_interruption_data.string_resource = new UC16VectorResource(
13225       i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
13226
13227   v8::TryCatch try_catch;
13228   timeout_thread.Start();
13229
13230   CompileRun("/((a*)*)*b/.exec(a)");
13231   CHECK(try_catch.HasTerminated());
13232
13233   timeout_thread.Join();
13234
13235   regexp_interruption_data.string.Reset();
13236   i::DeleteArray(uc16_content);
13237 }
13238
13239 #endif  // V8_INTERPRETED_REGEXP
13240
13241
13242 // Test that we cannot set a property on the global object if there
13243 // is a read-only property in the prototype chain.
13244 TEST(ReadOnlyPropertyInGlobalProto) {
13245   v8::Isolate* isolate = CcTest::isolate();
13246   v8::HandleScope scope(isolate);
13247   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13248   LocalContext context(0, templ);
13249   v8::Handle<v8::Object> global = context->Global();
13250   v8::Handle<v8::Object> global_proto =
13251       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13252   global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
13253                          v8::ReadOnly);
13254   global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
13255                          v8::ReadOnly);
13256   // Check without 'eval' or 'with'.
13257   v8::Handle<v8::Value> res =
13258       CompileRun("function f() { x = 42; return x; }; f()");
13259   CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13260   // Check with 'eval'.
13261   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13262   CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13263   // Check with 'with'.
13264   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13265   CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13266 }
13267
13268 static int force_set_set_count = 0;
13269 static int force_set_get_count = 0;
13270 bool pass_on_get = false;
13271
13272 static void ForceSetGetter(v8::Local<v8::String> name,
13273                            const v8::PropertyCallbackInfo<v8::Value>& info) {
13274   force_set_get_count++;
13275   if (pass_on_get) {
13276     return;
13277   }
13278   info.GetReturnValue().Set(3);
13279 }
13280
13281 static void ForceSetSetter(v8::Local<v8::String> name,
13282                            v8::Local<v8::Value> value,
13283                            const v8::PropertyCallbackInfo<void>& info) {
13284   force_set_set_count++;
13285 }
13286
13287 static void ForceSetInterceptGetter(
13288     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13289   CHECK(name->IsString());
13290   ForceSetGetter(Local<String>::Cast(name), info);
13291 }
13292
13293 static void ForceSetInterceptSetter(
13294     v8::Local<v8::Name> name, v8::Local<v8::Value> value,
13295     const v8::PropertyCallbackInfo<v8::Value>& info) {
13296   force_set_set_count++;
13297   info.GetReturnValue().SetUndefined();
13298 }
13299
13300
13301 TEST(ForceSet) {
13302   force_set_get_count = 0;
13303   force_set_set_count = 0;
13304   pass_on_get = false;
13305
13306   v8::Isolate* isolate = CcTest::isolate();
13307   v8::HandleScope scope(isolate);
13308   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13309   v8::Handle<v8::String> access_property =
13310       v8::String::NewFromUtf8(isolate, "a");
13311   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13312   LocalContext context(NULL, templ);
13313   v8::Handle<v8::Object> global = context->Global();
13314
13315   // Ordinary properties
13316   v8::Handle<v8::String> simple_property =
13317       v8::String::NewFromUtf8(isolate, "p");
13318   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
13319   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13320   // This should fail because the property is read-only
13321   global->Set(simple_property, v8::Int32::New(isolate, 5));
13322   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13323   // This should succeed even though the property is read-only
13324   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
13325   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13326
13327   // Accessors
13328   CHECK_EQ(0, force_set_set_count);
13329   CHECK_EQ(0, force_set_get_count);
13330   CHECK_EQ(3, global->Get(access_property)->Int32Value());
13331   // CHECK_EQ the property shouldn't override it, just call the setter
13332   // which in this case does nothing.
13333   global->Set(access_property, v8::Int32::New(isolate, 7));
13334   CHECK_EQ(3, global->Get(access_property)->Int32Value());
13335   CHECK_EQ(1, force_set_set_count);
13336   CHECK_EQ(2, force_set_get_count);
13337   // Forcing the property to be set should override the accessor without
13338   // calling it
13339   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
13340   CHECK_EQ(8, global->Get(access_property)->Int32Value());
13341   CHECK_EQ(1, force_set_set_count);
13342   CHECK_EQ(2, force_set_get_count);
13343 }
13344
13345
13346 TEST(ForceSetWithInterceptor) {
13347   force_set_get_count = 0;
13348   force_set_set_count = 0;
13349   pass_on_get = false;
13350
13351   v8::Isolate* isolate = CcTest::isolate();
13352   v8::HandleScope scope(isolate);
13353   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13354   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13355       ForceSetInterceptGetter, ForceSetInterceptSetter));
13356   LocalContext context(NULL, templ);
13357   v8::Handle<v8::Object> global = context->Global();
13358
13359   v8::Handle<v8::String> some_property =
13360       v8::String::NewFromUtf8(isolate, "a");
13361   CHECK_EQ(0, force_set_set_count);
13362   CHECK_EQ(0, force_set_get_count);
13363   CHECK_EQ(3, global->Get(some_property)->Int32Value());
13364   // Setting the property shouldn't override it, just call the setter
13365   // which in this case does nothing.
13366   global->Set(some_property, v8::Int32::New(isolate, 7));
13367   CHECK_EQ(3, global->Get(some_property)->Int32Value());
13368   CHECK_EQ(1, force_set_set_count);
13369   CHECK_EQ(2, force_set_get_count);
13370   // Getting the property when the interceptor returns an empty handle
13371   // should yield undefined, since the property isn't present on the
13372   // object itself yet.
13373   pass_on_get = true;
13374   CHECK(global->Get(some_property)->IsUndefined());
13375   CHECK_EQ(1, force_set_set_count);
13376   CHECK_EQ(3, force_set_get_count);
13377   // Forcing the property to be set should cause the value to be
13378   // set locally without calling the interceptor.
13379   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
13380   CHECK_EQ(8, global->Get(some_property)->Int32Value());
13381   CHECK_EQ(1, force_set_set_count);
13382   CHECK_EQ(4, force_set_get_count);
13383   // Reenabling the interceptor should cause it to take precedence over
13384   // the property
13385   pass_on_get = false;
13386   CHECK_EQ(3, global->Get(some_property)->Int32Value());
13387   CHECK_EQ(1, force_set_set_count);
13388   CHECK_EQ(5, force_set_get_count);
13389   // The interceptor should also work for other properties
13390   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
13391                   ->Int32Value());
13392   CHECK_EQ(1, force_set_set_count);
13393   CHECK_EQ(6, force_set_get_count);
13394 }
13395
13396
13397 static v8::Local<Context> calling_context0;
13398 static v8::Local<Context> calling_context1;
13399 static v8::Local<Context> calling_context2;
13400
13401
13402 // Check that the call to the callback is initiated in
13403 // calling_context2, the directly calling context is calling_context1
13404 // and the callback itself is in calling_context0.
13405 static void GetCallingContextCallback(
13406     const v8::FunctionCallbackInfo<v8::Value>& args) {
13407   ApiTestFuzzer::Fuzz();
13408   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
13409   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
13410   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
13411   args.GetReturnValue().Set(42);
13412 }
13413
13414
13415 THREADED_TEST(GetCurrentContextWhenNotInContext) {
13416   i::Isolate* isolate = CcTest::i_isolate();
13417   CHECK(isolate != NULL);
13418   CHECK(isolate->context() == NULL);
13419   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
13420   v8::HandleScope scope(v8_isolate);
13421   // The following should not crash, but return an empty handle.
13422   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
13423   CHECK(current.IsEmpty());
13424 }
13425
13426
13427 THREADED_TEST(GetCallingContext) {
13428   v8::Isolate* isolate = CcTest::isolate();
13429   v8::HandleScope scope(isolate);
13430
13431   Local<Context> calling_context0(Context::New(isolate));
13432   Local<Context> calling_context1(Context::New(isolate));
13433   Local<Context> calling_context2(Context::New(isolate));
13434   ::calling_context0 = calling_context0;
13435   ::calling_context1 = calling_context1;
13436   ::calling_context2 = calling_context2;
13437
13438   // Allow cross-domain access.
13439   Local<String> token = v8_str("<security token>");
13440   calling_context0->SetSecurityToken(token);
13441   calling_context1->SetSecurityToken(token);
13442   calling_context2->SetSecurityToken(token);
13443
13444   // Create an object with a C++ callback in context0.
13445   calling_context0->Enter();
13446   Local<v8::FunctionTemplate> callback_templ =
13447       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
13448   calling_context0->Global()->Set(v8_str("callback"),
13449                                   callback_templ->GetFunction());
13450   calling_context0->Exit();
13451
13452   // Expose context0 in context1 and set up a function that calls the
13453   // callback function.
13454   calling_context1->Enter();
13455   calling_context1->Global()->Set(v8_str("context0"),
13456                                   calling_context0->Global());
13457   CompileRun("function f() { context0.callback() }");
13458   calling_context1->Exit();
13459
13460   // Expose context1 in context2 and call the callback function in
13461   // context0 indirectly through f in context1.
13462   calling_context2->Enter();
13463   calling_context2->Global()->Set(v8_str("context1"),
13464                                   calling_context1->Global());
13465   CompileRun("context1.f()");
13466   calling_context2->Exit();
13467   ::calling_context0.Clear();
13468   ::calling_context1.Clear();
13469   ::calling_context2.Clear();
13470 }
13471
13472
13473 // Check that a variable declaration with no explicit initialization
13474 // value does shadow an existing property in the prototype chain.
13475 THREADED_TEST(InitGlobalVarInProtoChain) {
13476   LocalContext context;
13477   v8::HandleScope scope(context->GetIsolate());
13478   // Introduce a variable in the prototype chain.
13479   CompileRun("__proto__.x = 42");
13480   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13481   CHECK(!result->IsUndefined());
13482   CHECK_EQ(43, result->Int32Value());
13483 }
13484
13485
13486 // Regression test for issue 398.
13487 // If a function is added to an object, creating a constant function
13488 // field, and the result is cloned, replacing the constant function on the
13489 // original should not affect the clone.
13490 // See http://code.google.com/p/v8/issues/detail?id=398
13491 THREADED_TEST(ReplaceConstantFunction) {
13492   LocalContext context;
13493   v8::Isolate* isolate = context->GetIsolate();
13494   v8::HandleScope scope(isolate);
13495   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
13496   v8::Handle<v8::FunctionTemplate> func_templ =
13497       v8::FunctionTemplate::New(isolate);
13498   v8::Handle<v8::String> foo_string =
13499       v8::String::NewFromUtf8(isolate, "foo");
13500   obj->Set(foo_string, func_templ->GetFunction());
13501   v8::Handle<v8::Object> obj_clone = obj->Clone();
13502   obj_clone->Set(foo_string,
13503                  v8::String::NewFromUtf8(isolate, "Hello"));
13504   CHECK(!obj->Get(foo_string)->IsUndefined());
13505 }
13506
13507
13508 static void CheckElementValue(i::Isolate* isolate,
13509                               int expected,
13510                               i::Handle<i::Object> obj,
13511                               int offset) {
13512   i::Object* element =
13513       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
13514   CHECK_EQ(expected, i::Smi::cast(element)->value());
13515 }
13516
13517
13518 THREADED_TEST(PixelArray) {
13519   LocalContext context;
13520   i::Isolate* isolate = CcTest::i_isolate();
13521   i::Factory* factory = isolate->factory();
13522   v8::HandleScope scope(context->GetIsolate());
13523   const int kElementCount = 260;
13524   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13525   i::Handle<i::ExternalUint8ClampedArray> pixels =
13526       i::Handle<i::ExternalUint8ClampedArray>::cast(
13527           factory->NewExternalArray(kElementCount,
13528                                     v8::kExternalUint8ClampedArray,
13529                                     pixel_data));
13530   // Force GC to trigger verification.
13531   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13532   for (int i = 0; i < kElementCount; i++) {
13533     pixels->set(i, i % 256);
13534   }
13535   // Force GC to trigger verification.
13536   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13537   for (int i = 0; i < kElementCount; i++) {
13538     CHECK_EQ(i % 256, pixels->get_scalar(i));
13539     CHECK_EQ(i % 256, pixel_data[i]);
13540   }
13541
13542   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
13543   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13544   // Set the elements to be the pixels.
13545   // jsobj->set_elements(*pixels);
13546   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13547   CheckElementValue(isolate, 1, jsobj, 1);
13548   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
13549   context->Global()->Set(v8_str("pixels"), obj);
13550   v8::Handle<v8::Value> result = CompileRun("pixels.field");
13551   CHECK_EQ(1503, result->Int32Value());
13552   result = CompileRun("pixels[1]");
13553   CHECK_EQ(1, result->Int32Value());
13554
13555   result = CompileRun("var sum = 0;"
13556                       "for (var i = 0; i < 8; i++) {"
13557                       "  sum += pixels[i] = pixels[i] = -i;"
13558                       "}"
13559                       "sum;");
13560   CHECK_EQ(-28, result->Int32Value());
13561
13562   result = CompileRun("var sum = 0;"
13563                       "for (var i = 0; i < 8; i++) {"
13564                       "  sum += pixels[i] = pixels[i] = 0;"
13565                       "}"
13566                       "sum;");
13567   CHECK_EQ(0, result->Int32Value());
13568
13569   result = CompileRun("var sum = 0;"
13570                       "for (var i = 0; i < 8; i++) {"
13571                       "  sum += pixels[i] = pixels[i] = 255;"
13572                       "}"
13573                       "sum;");
13574   CHECK_EQ(8 * 255, result->Int32Value());
13575
13576   result = CompileRun("var sum = 0;"
13577                       "for (var i = 0; i < 8; i++) {"
13578                       "  sum += pixels[i] = pixels[i] = 256 + i;"
13579                       "}"
13580                       "sum;");
13581   CHECK_EQ(2076, result->Int32Value());
13582
13583   result = CompileRun("var sum = 0;"
13584                       "for (var i = 0; i < 8; i++) {"
13585                       "  sum += pixels[i] = pixels[i] = i;"
13586                       "}"
13587                       "sum;");
13588   CHECK_EQ(28, result->Int32Value());
13589
13590   result = CompileRun("var sum = 0;"
13591                       "for (var i = 0; i < 8; i++) {"
13592                       "  sum += pixels[i];"
13593                       "}"
13594                       "sum;");
13595   CHECK_EQ(28, result->Int32Value());
13596
13597   i::Handle<i::Smi> value(i::Smi::FromInt(2),
13598                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
13599   i::Handle<i::Object> no_failure;
13600   no_failure = i::JSObject::SetElement(
13601       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13602   DCHECK(!no_failure.is_null());
13603   USE(no_failure);
13604   CheckElementValue(isolate, 2, jsobj, 1);
13605   *value.location() = i::Smi::FromInt(256);
13606   no_failure = i::JSObject::SetElement(
13607       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13608   DCHECK(!no_failure.is_null());
13609   USE(no_failure);
13610   CheckElementValue(isolate, 255, jsobj, 1);
13611   *value.location() = i::Smi::FromInt(-1);
13612   no_failure = i::JSObject::SetElement(
13613       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13614   DCHECK(!no_failure.is_null());
13615   USE(no_failure);
13616   CheckElementValue(isolate, 0, jsobj, 1);
13617
13618   result = CompileRun("for (var i = 0; i < 8; i++) {"
13619                       "  pixels[i] = (i * 65) - 109;"
13620                       "}"
13621                       "pixels[1] + pixels[6];");
13622   CHECK_EQ(255, result->Int32Value());
13623   CheckElementValue(isolate, 0, jsobj, 0);
13624   CheckElementValue(isolate, 0, jsobj, 1);
13625   CheckElementValue(isolate, 21, jsobj, 2);
13626   CheckElementValue(isolate, 86, jsobj, 3);
13627   CheckElementValue(isolate, 151, jsobj, 4);
13628   CheckElementValue(isolate, 216, jsobj, 5);
13629   CheckElementValue(isolate, 255, jsobj, 6);
13630   CheckElementValue(isolate, 255, jsobj, 7);
13631   result = CompileRun("var sum = 0;"
13632                       "for (var i = 0; i < 8; i++) {"
13633                       "  sum += pixels[i];"
13634                       "}"
13635                       "sum;");
13636   CHECK_EQ(984, result->Int32Value());
13637
13638   result = CompileRun("for (var i = 0; i < 8; i++) {"
13639                       "  pixels[i] = (i * 1.1);"
13640                       "}"
13641                       "pixels[1] + pixels[6];");
13642   CHECK_EQ(8, result->Int32Value());
13643   CheckElementValue(isolate, 0, jsobj, 0);
13644   CheckElementValue(isolate, 1, jsobj, 1);
13645   CheckElementValue(isolate, 2, jsobj, 2);
13646   CheckElementValue(isolate, 3, jsobj, 3);
13647   CheckElementValue(isolate, 4, jsobj, 4);
13648   CheckElementValue(isolate, 6, jsobj, 5);
13649   CheckElementValue(isolate, 7, jsobj, 6);
13650   CheckElementValue(isolate, 8, jsobj, 7);
13651
13652   result = CompileRun("for (var i = 0; i < 8; i++) {"
13653                       "  pixels[7] = undefined;"
13654                       "}"
13655                       "pixels[7];");
13656   CHECK_EQ(0, result->Int32Value());
13657   CheckElementValue(isolate, 0, jsobj, 7);
13658
13659   result = CompileRun("for (var i = 0; i < 8; i++) {"
13660                       "  pixels[6] = '2.3';"
13661                       "}"
13662                       "pixels[6];");
13663   CHECK_EQ(2, result->Int32Value());
13664   CheckElementValue(isolate, 2, jsobj, 6);
13665
13666   result = CompileRun("for (var i = 0; i < 8; i++) {"
13667                       "  pixels[5] = NaN;"
13668                       "}"
13669                       "pixels[5];");
13670   CHECK_EQ(0, result->Int32Value());
13671   CheckElementValue(isolate, 0, jsobj, 5);
13672
13673   result = CompileRun("for (var i = 0; i < 8; i++) {"
13674                       "  pixels[8] = Infinity;"
13675                       "}"
13676                       "pixels[8];");
13677   CHECK_EQ(255, result->Int32Value());
13678   CheckElementValue(isolate, 255, jsobj, 8);
13679
13680   result = CompileRun("for (var i = 0; i < 8; i++) {"
13681                       "  pixels[9] = -Infinity;"
13682                       "}"
13683                       "pixels[9];");
13684   CHECK_EQ(0, result->Int32Value());
13685   CheckElementValue(isolate, 0, jsobj, 9);
13686
13687   result = CompileRun("pixels[3] = 33;"
13688                       "delete pixels[3];"
13689                       "pixels[3];");
13690   CHECK_EQ(33, result->Int32Value());
13691
13692   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13693                       "pixels[2] = 12; pixels[3] = 13;"
13694                       "pixels.__defineGetter__('2',"
13695                       "function() { return 120; });"
13696                       "pixels[2];");
13697   CHECK_EQ(12, result->Int32Value());
13698
13699   result = CompileRun("var js_array = new Array(40);"
13700                       "js_array[0] = 77;"
13701                       "js_array;");
13702   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13703
13704   result = CompileRun("pixels[1] = 23;"
13705                       "pixels.__proto__ = [];"
13706                       "js_array.__proto__ = pixels;"
13707                       "js_array.concat(pixels);");
13708   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13709   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13710
13711   result = CompileRun("pixels[1] = 23;");
13712   CHECK_EQ(23, result->Int32Value());
13713
13714   // Test for index greater than 255.  Regression test for:
13715   // http://code.google.com/p/chromium/issues/detail?id=26337.
13716   result = CompileRun("pixels[256] = 255;");
13717   CHECK_EQ(255, result->Int32Value());
13718   result = CompileRun("var i = 0;"
13719                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13720                       "i");
13721   CHECK_EQ(255, result->Int32Value());
13722
13723   // Make sure that pixel array ICs recognize when a non-pixel array
13724   // is passed to it.
13725   result = CompileRun("function pa_load(p) {"
13726                       "  var sum = 0;"
13727                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
13728                       "  return sum;"
13729                       "}"
13730                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13731                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13732                       "just_ints = new Object();"
13733                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13734                       "for (var i = 0; i < 10; ++i) {"
13735                       "  result = pa_load(just_ints);"
13736                       "}"
13737                       "result");
13738   CHECK_EQ(32640, result->Int32Value());
13739
13740   // Make sure that pixel array ICs recognize out-of-bound accesses.
13741   result = CompileRun("function pa_load(p, start) {"
13742                       "  var sum = 0;"
13743                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
13744                       "  return sum;"
13745                       "}"
13746                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13747                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13748                       "for (var i = 0; i < 10; ++i) {"
13749                       "  result = pa_load(pixels,-10);"
13750                       "}"
13751                       "result");
13752   CHECK_EQ(0, result->Int32Value());
13753
13754   // Make sure that generic ICs properly handles a pixel array.
13755   result = CompileRun("function pa_load(p) {"
13756                       "  var sum = 0;"
13757                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
13758                       "  return sum;"
13759                       "}"
13760                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13761                       "just_ints = new Object();"
13762                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13763                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13764                       "for (var i = 0; i < 10; ++i) {"
13765                       "  result = pa_load(pixels);"
13766                       "}"
13767                       "result");
13768   CHECK_EQ(32640, result->Int32Value());
13769
13770   // Make sure that generic load ICs recognize out-of-bound accesses in
13771   // pixel arrays.
13772   result = CompileRun("function pa_load(p, start) {"
13773                       "  var sum = 0;"
13774                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
13775                       "  return sum;"
13776                       "}"
13777                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13778                       "just_ints = new Object();"
13779                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13780                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13781                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13782                       "for (var i = 0; i < 10; ++i) {"
13783                       "  result = pa_load(pixels,-10);"
13784                       "}"
13785                       "result");
13786   CHECK_EQ(0, result->Int32Value());
13787
13788   // Make sure that generic ICs properly handles other types than pixel
13789   // arrays (that the inlined fast pixel array test leaves the right information
13790   // in the right registers).
13791   result = CompileRun("function pa_load(p) {"
13792                       "  var sum = 0;"
13793                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
13794                       "  return sum;"
13795                       "}"
13796                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13797                       "just_ints = new Object();"
13798                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13799                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13800                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13801                       "sparse_array = new Object();"
13802                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13803                       "sparse_array[1000000] = 3;"
13804                       "for (var i = 0; i < 10; ++i) {"
13805                       "  result = pa_load(sparse_array);"
13806                       "}"
13807                       "result");
13808   CHECK_EQ(32640, result->Int32Value());
13809
13810   // Make sure that pixel array store ICs clamp values correctly.
13811   result = CompileRun("function pa_store(p) {"
13812                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13813                       "}"
13814                       "pa_store(pixels);"
13815                       "var sum = 0;"
13816                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13817                       "sum");
13818   CHECK_EQ(48896, result->Int32Value());
13819
13820   // Make sure that pixel array stores correctly handle accesses outside
13821   // of the pixel array..
13822   result = CompileRun("function pa_store(p,start) {"
13823                       "  for (var j = 0; j < 256; j++) {"
13824                       "    p[j+start] = j * 2;"
13825                       "  }"
13826                       "}"
13827                       "pa_store(pixels,0);"
13828                       "pa_store(pixels,-128);"
13829                       "var sum = 0;"
13830                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13831                       "sum");
13832   CHECK_EQ(65280, result->Int32Value());
13833
13834   // Make sure that the generic store stub correctly handle accesses outside
13835   // of the pixel array..
13836   result = CompileRun("function pa_store(p,start) {"
13837                       "  for (var j = 0; j < 256; j++) {"
13838                       "    p[j+start] = j * 2;"
13839                       "  }"
13840                       "}"
13841                       "pa_store(pixels,0);"
13842                       "just_ints = new Object();"
13843                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13844                       "pa_store(just_ints, 0);"
13845                       "pa_store(pixels,-128);"
13846                       "var sum = 0;"
13847                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13848                       "sum");
13849   CHECK_EQ(65280, result->Int32Value());
13850
13851   // Make sure that the generic keyed store stub clamps pixel array values
13852   // correctly.
13853   result = CompileRun("function pa_store(p) {"
13854                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13855                       "}"
13856                       "pa_store(pixels);"
13857                       "just_ints = new Object();"
13858                       "pa_store(just_ints);"
13859                       "pa_store(pixels);"
13860                       "var sum = 0;"
13861                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13862                       "sum");
13863   CHECK_EQ(48896, result->Int32Value());
13864
13865   // Make sure that pixel array loads are optimized by crankshaft.
13866   result = CompileRun("function pa_load(p) {"
13867                       "  var sum = 0;"
13868                       "  for (var i=0; i<256; ++i) {"
13869                       "    sum += p[i];"
13870                       "  }"
13871                       "  return sum; "
13872                       "}"
13873                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13874                       "for (var i = 0; i < 5000; ++i) {"
13875                       "  result = pa_load(pixels);"
13876                       "}"
13877                       "result");
13878   CHECK_EQ(32640, result->Int32Value());
13879
13880   // Make sure that pixel array stores are optimized by crankshaft.
13881   result = CompileRun("function pa_init(p) {"
13882                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13883                       "}"
13884                       "function pa_load(p) {"
13885                       "  var sum = 0;"
13886                       "  for (var i=0; i<256; ++i) {"
13887                       "    sum += p[i];"
13888                       "  }"
13889                       "  return sum; "
13890                       "}"
13891                       "for (var i = 0; i < 5000; ++i) {"
13892                       "  pa_init(pixels);"
13893                       "}"
13894                       "result = pa_load(pixels);"
13895                       "result");
13896   CHECK_EQ(32640, result->Int32Value());
13897
13898   free(pixel_data);
13899 }
13900
13901
13902 THREADED_TEST(PixelArrayInfo) {
13903   LocalContext context;
13904   v8::HandleScope scope(context->GetIsolate());
13905   for (int size = 0; size < 100; size += 10) {
13906     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13907     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
13908     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13909     CHECK(obj->HasIndexedPropertiesInPixelData());
13910     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13911     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13912     free(pixel_data);
13913   }
13914 }
13915
13916
13917 static void NotHandledIndexedPropertyGetter(
13918     uint32_t index,
13919     const v8::PropertyCallbackInfo<v8::Value>& info) {
13920   ApiTestFuzzer::Fuzz();
13921 }
13922
13923
13924 static void NotHandledIndexedPropertySetter(
13925     uint32_t index,
13926     Local<Value> value,
13927     const v8::PropertyCallbackInfo<v8::Value>& info) {
13928   ApiTestFuzzer::Fuzz();
13929 }
13930
13931
13932 THREADED_TEST(PixelArrayWithInterceptor) {
13933   LocalContext context;
13934   i::Factory* factory = CcTest::i_isolate()->factory();
13935   v8::Isolate* isolate = context->GetIsolate();
13936   v8::HandleScope scope(isolate);
13937   const int kElementCount = 260;
13938   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13939   i::Handle<i::ExternalUint8ClampedArray> pixels =
13940       i::Handle<i::ExternalUint8ClampedArray>::cast(
13941           factory->NewExternalArray(kElementCount,
13942                                     v8::kExternalUint8ClampedArray,
13943                                     pixel_data));
13944   for (int i = 0; i < kElementCount; i++) {
13945     pixels->set(i, i % 256);
13946   }
13947   v8::Handle<v8::ObjectTemplate> templ =
13948       v8::ObjectTemplate::New(context->GetIsolate());
13949   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
13950       NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
13951   v8::Handle<v8::Object> obj = templ->NewInstance();
13952   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13953   context->Global()->Set(v8_str("pixels"), obj);
13954   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13955   CHECK_EQ(1, result->Int32Value());
13956   result = CompileRun("var sum = 0;"
13957                       "for (var i = 0; i < 8; i++) {"
13958                       "  sum += pixels[i] = pixels[i] = -i;"
13959                       "}"
13960                       "sum;");
13961   CHECK_EQ(-28, result->Int32Value());
13962   result = CompileRun("pixels.hasOwnProperty('1')");
13963   CHECK(result->BooleanValue());
13964   free(pixel_data);
13965 }
13966
13967
13968 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13969   switch (array_type) {
13970     case v8::kExternalInt8Array:
13971     case v8::kExternalUint8Array:
13972     case v8::kExternalUint8ClampedArray:
13973       return 1;
13974       break;
13975     case v8::kExternalInt16Array:
13976     case v8::kExternalUint16Array:
13977       return 2;
13978       break;
13979     case v8::kExternalInt32Array:
13980     case v8::kExternalUint32Array:
13981     case v8::kExternalFloat32Array:
13982       return 4;
13983       break;
13984     case v8::kExternalFloat64Array:
13985       return 8;
13986       break;
13987     default:
13988       UNREACHABLE();
13989       return -1;
13990   }
13991   UNREACHABLE();
13992   return -1;
13993 }
13994
13995
13996 template <class ExternalArrayClass, class ElementType>
13997 static void ObjectWithExternalArrayTestHelper(
13998     Handle<Context> context,
13999     v8::Handle<Object> obj,
14000     int element_count,
14001     v8::ExternalArrayType array_type,
14002     int64_t low, int64_t high) {
14003   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14004   i::Isolate* isolate = jsobj->GetIsolate();
14005   obj->Set(v8_str("field"),
14006            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
14007   context->Global()->Set(v8_str("ext_array"), obj);
14008   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
14009   CHECK_EQ(1503, result->Int32Value());
14010   result = CompileRun("ext_array[1]");
14011   CHECK_EQ(1, result->Int32Value());
14012
14013   // Check assigned smis
14014   result = CompileRun("for (var i = 0; i < 8; i++) {"
14015                       "  ext_array[i] = i;"
14016                       "}"
14017                       "var sum = 0;"
14018                       "for (var i = 0; i < 8; i++) {"
14019                       "  sum += ext_array[i];"
14020                       "}"
14021                       "sum;");
14022
14023   CHECK_EQ(28, result->Int32Value());
14024   // Check pass through of assigned smis
14025   result = CompileRun("var sum = 0;"
14026                       "for (var i = 0; i < 8; i++) {"
14027                       "  sum += ext_array[i] = ext_array[i] = -i;"
14028                       "}"
14029                       "sum;");
14030   CHECK_EQ(-28, result->Int32Value());
14031
14032
14033   // Check assigned smis in reverse order
14034   result = CompileRun("for (var i = 8; --i >= 0; ) {"
14035                       "  ext_array[i] = i;"
14036                       "}"
14037                       "var sum = 0;"
14038                       "for (var i = 0; i < 8; i++) {"
14039                       "  sum += ext_array[i];"
14040                       "}"
14041                       "sum;");
14042   CHECK_EQ(28, result->Int32Value());
14043
14044   // Check pass through of assigned HeapNumbers
14045   result = CompileRun("var sum = 0;"
14046                       "for (var i = 0; i < 16; i+=2) {"
14047                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
14048                       "}"
14049                       "sum;");
14050   CHECK_EQ(-28, result->Int32Value());
14051
14052   // Check assigned HeapNumbers
14053   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
14054                       "  ext_array[i] = (i * 0.5);"
14055                       "}"
14056                       "var sum = 0;"
14057                       "for (var i = 0; i < 16; i+=2) {"
14058                       "  sum += ext_array[i];"
14059                       "}"
14060                       "sum;");
14061   CHECK_EQ(28, result->Int32Value());
14062
14063   // Check assigned HeapNumbers in reverse order
14064   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
14065                       "  ext_array[i] = (i * 0.5);"
14066                       "}"
14067                       "var sum = 0;"
14068                       "for (var i = 0; i < 16; i+=2) {"
14069                       "  sum += ext_array[i];"
14070                       "}"
14071                       "sum;");
14072   CHECK_EQ(28, result->Int32Value());
14073
14074   i::ScopedVector<char> test_buf(1024);
14075
14076   // Check legal boundary conditions.
14077   // The repeated loads and stores ensure the ICs are exercised.
14078   const char* boundary_program =
14079       "var res = 0;"
14080       "for (var i = 0; i < 16; i++) {"
14081       "  ext_array[i] = %lld;"
14082       "  if (i > 8) {"
14083       "    res = ext_array[i];"
14084       "  }"
14085       "}"
14086       "res;";
14087   i::SNPrintF(test_buf,
14088               boundary_program,
14089               low);
14090   result = CompileRun(test_buf.start());
14091   CHECK_EQ(low, result->IntegerValue());
14092
14093   i::SNPrintF(test_buf,
14094               boundary_program,
14095               high);
14096   result = CompileRun(test_buf.start());
14097   CHECK_EQ(high, result->IntegerValue());
14098
14099   // Check misprediction of type in IC.
14100   result = CompileRun("var tmp_array = ext_array;"
14101                       "var sum = 0;"
14102                       "for (var i = 0; i < 8; i++) {"
14103                       "  tmp_array[i] = i;"
14104                       "  sum += tmp_array[i];"
14105                       "  if (i == 4) {"
14106                       "    tmp_array = {};"
14107                       "  }"
14108                       "}"
14109                       "sum;");
14110   // Force GC to trigger verification.
14111   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14112   CHECK_EQ(28, result->Int32Value());
14113
14114   // Make sure out-of-range loads do not throw.
14115   i::SNPrintF(test_buf,
14116               "var caught_exception = false;"
14117               "try {"
14118               "  ext_array[%d];"
14119               "} catch (e) {"
14120               "  caught_exception = true;"
14121               "}"
14122               "caught_exception;",
14123               element_count);
14124   result = CompileRun(test_buf.start());
14125   CHECK_EQ(false, result->BooleanValue());
14126
14127   // Make sure out-of-range stores do not throw.
14128   i::SNPrintF(test_buf,
14129               "var caught_exception = false;"
14130               "try {"
14131               "  ext_array[%d] = 1;"
14132               "} catch (e) {"
14133               "  caught_exception = true;"
14134               "}"
14135               "caught_exception;",
14136               element_count);
14137   result = CompileRun(test_buf.start());
14138   CHECK_EQ(false, result->BooleanValue());
14139
14140   // Check other boundary conditions, values and operations.
14141   result = CompileRun("for (var i = 0; i < 8; i++) {"
14142                       "  ext_array[7] = undefined;"
14143                       "}"
14144                       "ext_array[7];");
14145   CHECK_EQ(0, result->Int32Value());
14146   if (array_type == v8::kExternalFloat64Array ||
14147       array_type == v8::kExternalFloat32Array) {
14148     CHECK(std::isnan(
14149         i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
14150   } else {
14151     CheckElementValue(isolate, 0, jsobj, 7);
14152   }
14153
14154   result = CompileRun("for (var i = 0; i < 8; i++) {"
14155                       "  ext_array[6] = '2.3';"
14156                       "}"
14157                       "ext_array[6];");
14158   CHECK_EQ(2, result->Int32Value());
14159   CHECK_EQ(2,
14160            static_cast<int>(
14161                i::Object::GetElement(
14162                    isolate, jsobj, 6).ToHandleChecked()->Number()));
14163
14164   if (array_type != v8::kExternalFloat32Array &&
14165       array_type != v8::kExternalFloat64Array) {
14166     // Though the specification doesn't state it, be explicit about
14167     // converting NaNs and +/-Infinity to zero.
14168     result = CompileRun("for (var i = 0; i < 8; i++) {"
14169                         "  ext_array[i] = 5;"
14170                         "}"
14171                         "for (var i = 0; i < 8; i++) {"
14172                         "  ext_array[i] = NaN;"
14173                         "}"
14174                         "ext_array[5];");
14175     CHECK_EQ(0, result->Int32Value());
14176     CheckElementValue(isolate, 0, jsobj, 5);
14177
14178     result = CompileRun("for (var i = 0; i < 8; i++) {"
14179                         "  ext_array[i] = 5;"
14180                         "}"
14181                         "for (var i = 0; i < 8; i++) {"
14182                         "  ext_array[i] = Infinity;"
14183                         "}"
14184                         "ext_array[5];");
14185     int expected_value =
14186         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
14187     CHECK_EQ(expected_value, result->Int32Value());
14188     CheckElementValue(isolate, expected_value, jsobj, 5);
14189
14190     result = CompileRun("for (var i = 0; i < 8; i++) {"
14191                         "  ext_array[i] = 5;"
14192                         "}"
14193                         "for (var i = 0; i < 8; i++) {"
14194                         "  ext_array[i] = -Infinity;"
14195                         "}"
14196                         "ext_array[5];");
14197     CHECK_EQ(0, result->Int32Value());
14198     CheckElementValue(isolate, 0, jsobj, 5);
14199
14200     // Check truncation behavior of integral arrays.
14201     const char* unsigned_data =
14202         "var source_data = [0.6, 10.6];"
14203         "var expected_results = [0, 10];";
14204     const char* signed_data =
14205         "var source_data = [0.6, 10.6, -0.6, -10.6];"
14206         "var expected_results = [0, 10, 0, -10];";
14207     const char* pixel_data =
14208         "var source_data = [0.6, 10.6];"
14209         "var expected_results = [1, 11];";
14210     bool is_unsigned =
14211         (array_type == v8::kExternalUint8Array ||
14212          array_type == v8::kExternalUint16Array ||
14213          array_type == v8::kExternalUint32Array);
14214     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
14215
14216     i::SNPrintF(test_buf,
14217                 "%s"
14218                 "var all_passed = true;"
14219                 "for (var i = 0; i < source_data.length; i++) {"
14220                 "  for (var j = 0; j < 8; j++) {"
14221                 "    ext_array[j] = source_data[i];"
14222                 "  }"
14223                 "  all_passed = all_passed &&"
14224                 "               (ext_array[5] == expected_results[i]);"
14225                 "}"
14226                 "all_passed;",
14227                 (is_unsigned ?
14228                      unsigned_data :
14229                      (is_pixel_data ? pixel_data : signed_data)));
14230     result = CompileRun(test_buf.start());
14231     CHECK_EQ(true, result->BooleanValue());
14232   }
14233
14234   i::Handle<ExternalArrayClass> array(
14235       ExternalArrayClass::cast(jsobj->elements()));
14236   for (int i = 0; i < element_count; i++) {
14237     array->set(i, static_cast<ElementType>(i));
14238   }
14239
14240   // Test complex assignments
14241   result = CompileRun("function ee_op_test_complex_func(sum) {"
14242                       " for (var i = 0; i < 40; ++i) {"
14243                       "   sum += (ext_array[i] += 1);"
14244                       "   sum += (ext_array[i] -= 1);"
14245                       " } "
14246                       " return sum;"
14247                       "}"
14248                       "sum=0;"
14249                       "for (var i=0;i<10000;++i) {"
14250                       "  sum=ee_op_test_complex_func(sum);"
14251                       "}"
14252                       "sum;");
14253   CHECK_EQ(16000000, result->Int32Value());
14254
14255   // Test count operations
14256   result = CompileRun("function ee_op_test_count_func(sum) {"
14257                       " for (var i = 0; i < 40; ++i) {"
14258                       "   sum += (++ext_array[i]);"
14259                       "   sum += (--ext_array[i]);"
14260                       " } "
14261                       " return sum;"
14262                       "}"
14263                       "sum=0;"
14264                       "for (var i=0;i<10000;++i) {"
14265                       "  sum=ee_op_test_count_func(sum);"
14266                       "}"
14267                       "sum;");
14268   CHECK_EQ(16000000, result->Int32Value());
14269
14270   result = CompileRun("ext_array[3] = 33;"
14271                       "delete ext_array[3];"
14272                       "ext_array[3];");
14273   CHECK_EQ(33, result->Int32Value());
14274
14275   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14276                       "ext_array[2] = 12; ext_array[3] = 13;"
14277                       "ext_array.__defineGetter__('2',"
14278                       "function() { return 120; });"
14279                       "ext_array[2];");
14280   CHECK_EQ(12, result->Int32Value());
14281
14282   result = CompileRun("var js_array = new Array(40);"
14283                       "js_array[0] = 77;"
14284                       "js_array;");
14285   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14286
14287   result = CompileRun("ext_array[1] = 23;"
14288                       "ext_array.__proto__ = [];"
14289                       "js_array.__proto__ = ext_array;"
14290                       "js_array.concat(ext_array);");
14291   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14292   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14293
14294   result = CompileRun("ext_array[1] = 23;");
14295   CHECK_EQ(23, result->Int32Value());
14296 }
14297
14298
14299 template <class FixedTypedArrayClass,
14300           i::ElementsKind elements_kind,
14301           class ElementType>
14302 static void FixedTypedArrayTestHelper(
14303     v8::ExternalArrayType array_type,
14304     ElementType low,
14305     ElementType high) {
14306   i::FLAG_allow_natives_syntax = true;
14307   LocalContext context;
14308   i::Isolate* isolate = CcTest::i_isolate();
14309   i::Factory* factory = isolate->factory();
14310   v8::HandleScope scope(context->GetIsolate());
14311   const int kElementCount = 260;
14312   i::Handle<FixedTypedArrayClass> fixed_array =
14313     i::Handle<FixedTypedArrayClass>::cast(
14314         factory->NewFixedTypedArray(kElementCount, array_type));
14315   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
14316            fixed_array->map()->instance_type());
14317   CHECK_EQ(kElementCount, fixed_array->length());
14318   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14319   for (int i = 0; i < kElementCount; i++) {
14320     fixed_array->set(i, static_cast<ElementType>(i));
14321   }
14322   // Force GC to trigger verification.
14323   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14324   for (int i = 0; i < kElementCount; i++) {
14325     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
14326              static_cast<int64_t>(fixed_array->get_scalar(i)));
14327   }
14328   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
14329   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14330   i::Handle<i::Map> fixed_array_map =
14331       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
14332   jsobj->set_map(*fixed_array_map);
14333   jsobj->set_elements(*fixed_array);
14334
14335   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
14336       context.local(), obj, kElementCount, array_type,
14337       static_cast<int64_t>(low),
14338       static_cast<int64_t>(high));
14339 }
14340
14341
14342 THREADED_TEST(FixedUint8Array) {
14343   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
14344     v8::kExternalUint8Array,
14345     0x0, 0xFF);
14346 }
14347
14348
14349 THREADED_TEST(FixedUint8ClampedArray) {
14350   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
14351                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
14352     v8::kExternalUint8ClampedArray,
14353     0x0, 0xFF);
14354 }
14355
14356
14357 THREADED_TEST(FixedInt8Array) {
14358   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
14359     v8::kExternalInt8Array,
14360     -0x80, 0x7F);
14361 }
14362
14363
14364 THREADED_TEST(FixedUint16Array) {
14365   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
14366     v8::kExternalUint16Array,
14367     0x0, 0xFFFF);
14368 }
14369
14370
14371 THREADED_TEST(FixedInt16Array) {
14372   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
14373     v8::kExternalInt16Array,
14374     -0x8000, 0x7FFF);
14375 }
14376
14377
14378 THREADED_TEST(FixedUint32Array) {
14379   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
14380     v8::kExternalUint32Array,
14381     0x0, UINT_MAX);
14382 }
14383
14384
14385 THREADED_TEST(FixedInt32Array) {
14386   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
14387     v8::kExternalInt32Array,
14388     INT_MIN, INT_MAX);
14389 }
14390
14391
14392 THREADED_TEST(FixedFloat32Array) {
14393   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
14394     v8::kExternalFloat32Array,
14395     -500, 500);
14396 }
14397
14398
14399 THREADED_TEST(FixedFloat64Array) {
14400   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
14401     v8::kExternalFloat64Array,
14402     -500, 500);
14403 }
14404
14405
14406 template <class ExternalArrayClass, class ElementType>
14407 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
14408                                     int64_t low,
14409                                     int64_t high) {
14410   LocalContext context;
14411   i::Isolate* isolate = CcTest::i_isolate();
14412   i::Factory* factory = isolate->factory();
14413   v8::HandleScope scope(context->GetIsolate());
14414   const int kElementCount = 40;
14415   int element_size = ExternalArrayElementSize(array_type);
14416   ElementType* array_data =
14417       static_cast<ElementType*>(malloc(kElementCount * element_size));
14418   i::Handle<ExternalArrayClass> array =
14419       i::Handle<ExternalArrayClass>::cast(
14420           factory->NewExternalArray(kElementCount, array_type, array_data));
14421   // Force GC to trigger verification.
14422   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14423   for (int i = 0; i < kElementCount; i++) {
14424     array->set(i, static_cast<ElementType>(i));
14425   }
14426   // Force GC to trigger verification.
14427   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14428   for (int i = 0; i < kElementCount; i++) {
14429     CHECK_EQ(static_cast<int64_t>(i),
14430              static_cast<int64_t>(array->get_scalar(i)));
14431     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
14432   }
14433
14434   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
14435   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14436   // Set the elements to be the external array.
14437   obj->SetIndexedPropertiesToExternalArrayData(array_data,
14438                                                array_type,
14439                                                kElementCount);
14440   CHECK_EQ(1,
14441            static_cast<int>(
14442                i::Object::GetElement(
14443                    isolate, jsobj, 1).ToHandleChecked()->Number()));
14444
14445   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14446       context.local(), obj, kElementCount, array_type, low, high);
14447
14448   v8::Handle<v8::Value> result;
14449
14450   // Test more complex manipulations which cause eax to contain values
14451   // that won't be completely overwritten by loads from the arrays.
14452   // This catches bugs in the instructions used for the KeyedLoadIC
14453   // for byte and word types.
14454   {
14455     const int kXSize = 300;
14456     const int kYSize = 300;
14457     const int kLargeElementCount = kXSize * kYSize * 4;
14458     ElementType* large_array_data =
14459         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
14460     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
14461     // Set the elements to be the external array.
14462     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14463                                                        array_type,
14464                                                        kLargeElementCount);
14465     context->Global()->Set(v8_str("large_array"), large_obj);
14466     // Initialize contents of a few rows.
14467     for (int x = 0; x < 300; x++) {
14468       int row = 0;
14469       int offset = row * 300 * 4;
14470       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14471       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14472       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14473       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14474       row = 150;
14475       offset = row * 300 * 4;
14476       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14477       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14478       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14479       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14480       row = 298;
14481       offset = row * 300 * 4;
14482       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14483       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14484       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14485       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14486     }
14487     // The goal of the code below is to make "offset" large enough
14488     // that the computation of the index (which goes into eax) has
14489     // high bits set which will not be overwritten by a byte or short
14490     // load.
14491     result = CompileRun("var failed = false;"
14492                         "var offset = 0;"
14493                         "for (var i = 0; i < 300; i++) {"
14494                         "  if (large_array[4 * i] != 127 ||"
14495                         "      large_array[4 * i + 1] != 0 ||"
14496                         "      large_array[4 * i + 2] != 0 ||"
14497                         "      large_array[4 * i + 3] != 127) {"
14498                         "    failed = true;"
14499                         "  }"
14500                         "}"
14501                         "offset = 150 * 300 * 4;"
14502                         "for (var i = 0; i < 300; i++) {"
14503                         "  if (large_array[offset + 4 * i] != 127 ||"
14504                         "      large_array[offset + 4 * i + 1] != 0 ||"
14505                         "      large_array[offset + 4 * i + 2] != 0 ||"
14506                         "      large_array[offset + 4 * i + 3] != 127) {"
14507                         "    failed = true;"
14508                         "  }"
14509                         "}"
14510                         "offset = 298 * 300 * 4;"
14511                         "for (var i = 0; i < 300; i++) {"
14512                         "  if (large_array[offset + 4 * i] != 127 ||"
14513                         "      large_array[offset + 4 * i + 1] != 0 ||"
14514                         "      large_array[offset + 4 * i + 2] != 0 ||"
14515                         "      large_array[offset + 4 * i + 3] != 127) {"
14516                         "    failed = true;"
14517                         "  }"
14518                         "}"
14519                         "!failed;");
14520     CHECK_EQ(true, result->BooleanValue());
14521     free(large_array_data);
14522   }
14523
14524   // The "" property descriptor is overloaded to store information about
14525   // the external array. Ensure that setting and accessing the "" property
14526   // works (it should overwrite the information cached about the external
14527   // array in the DescriptorArray) in various situations.
14528   result = CompileRun("ext_array[''] = 23; ext_array['']");
14529   CHECK_EQ(23, result->Int32Value());
14530
14531   // Property "" set after the external array is associated with the object.
14532   {
14533     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14534     obj2->Set(v8_str("ee_test_field"),
14535               v8::Int32::New(context->GetIsolate(), 256));
14536     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
14537     // Set the elements to be the external array.
14538     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14539                                                   array_type,
14540                                                   kElementCount);
14541     context->Global()->Set(v8_str("ext_array"), obj2);
14542     result = CompileRun("ext_array['']");
14543     CHECK_EQ(1503, result->Int32Value());
14544   }
14545
14546   // Property "" set after the external array is associated with the object.
14547   {
14548     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14549     obj2->Set(v8_str("ee_test_field_2"),
14550               v8::Int32::New(context->GetIsolate(), 256));
14551     // Set the elements to be the external array.
14552     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14553                                                   array_type,
14554                                                   kElementCount);
14555     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
14556     context->Global()->Set(v8_str("ext_array"), obj2);
14557     result = CompileRun("ext_array['']");
14558     CHECK_EQ(1503, result->Int32Value());
14559   }
14560
14561   // Should reuse the map from previous test.
14562   {
14563     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14564     obj2->Set(v8_str("ee_test_field_2"),
14565               v8::Int32::New(context->GetIsolate(), 256));
14566     // Set the elements to be the external array. Should re-use the map
14567     // from previous test.
14568     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14569                                                   array_type,
14570                                                   kElementCount);
14571     context->Global()->Set(v8_str("ext_array"), obj2);
14572     result = CompileRun("ext_array['']");
14573   }
14574
14575   // Property "" is a constant function that shouldn't not be interfered with
14576   // when an external array is set.
14577   {
14578     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14579     // Start
14580     obj2->Set(v8_str("ee_test_field3"),
14581               v8::Int32::New(context->GetIsolate(), 256));
14582
14583     // Add a constant function to an object.
14584     context->Global()->Set(v8_str("ext_array"), obj2);
14585     result = CompileRun("ext_array[''] = function() {return 1503;};"
14586                         "ext_array['']();");
14587
14588     // Add an external array transition to the same map that
14589     // has the constant transition.
14590     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
14591     obj3->Set(v8_str("ee_test_field3"),
14592               v8::Int32::New(context->GetIsolate(), 256));
14593     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14594                                                   array_type,
14595                                                   kElementCount);
14596     context->Global()->Set(v8_str("ext_array"), obj3);
14597   }
14598
14599   // If a external array transition is in the map, it should get clobbered
14600   // by a constant function.
14601   {
14602     // Add an external array transition.
14603     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
14604     obj3->Set(v8_str("ee_test_field4"),
14605               v8::Int32::New(context->GetIsolate(), 256));
14606     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14607                                                   array_type,
14608                                                   kElementCount);
14609
14610     // Add a constant function to the same map that just got an external array
14611     // transition.
14612     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14613     obj2->Set(v8_str("ee_test_field4"),
14614               v8::Int32::New(context->GetIsolate(), 256));
14615     context->Global()->Set(v8_str("ext_array"), obj2);
14616     result = CompileRun("ext_array[''] = function() {return 1503;};"
14617                         "ext_array['']();");
14618   }
14619
14620   free(array_data);
14621 }
14622
14623
14624 THREADED_TEST(ExternalInt8Array) {
14625   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
14626       v8::kExternalInt8Array,
14627       -128,
14628       127);
14629 }
14630
14631
14632 THREADED_TEST(ExternalUint8Array) {
14633   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
14634       v8::kExternalUint8Array,
14635       0,
14636       255);
14637 }
14638
14639
14640 THREADED_TEST(ExternalUint8ClampedArray) {
14641   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
14642       v8::kExternalUint8ClampedArray,
14643       0,
14644       255);
14645 }
14646
14647
14648 THREADED_TEST(ExternalInt16Array) {
14649   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
14650       v8::kExternalInt16Array,
14651       -32768,
14652       32767);
14653 }
14654
14655
14656 THREADED_TEST(ExternalUint16Array) {
14657   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
14658       v8::kExternalUint16Array,
14659       0,
14660       65535);
14661 }
14662
14663
14664 THREADED_TEST(ExternalInt32Array) {
14665   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
14666       v8::kExternalInt32Array,
14667       INT_MIN,   // -2147483648
14668       INT_MAX);  //  2147483647
14669 }
14670
14671
14672 THREADED_TEST(ExternalUint32Array) {
14673   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
14674       v8::kExternalUint32Array,
14675       0,
14676       UINT_MAX);  // 4294967295
14677 }
14678
14679
14680 THREADED_TEST(ExternalFloat32Array) {
14681   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
14682       v8::kExternalFloat32Array,
14683       -500,
14684       500);
14685 }
14686
14687
14688 THREADED_TEST(ExternalFloat64Array) {
14689   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
14690       v8::kExternalFloat64Array,
14691       -500,
14692       500);
14693 }
14694
14695
14696 THREADED_TEST(ExternalArrays) {
14697   TestExternalInt8Array();
14698   TestExternalUint8Array();
14699   TestExternalInt16Array();
14700   TestExternalUint16Array();
14701   TestExternalInt32Array();
14702   TestExternalUint32Array();
14703   TestExternalFloat32Array();
14704 }
14705
14706
14707 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14708   LocalContext context;
14709   v8::HandleScope scope(context->GetIsolate());
14710   for (int size = 0; size < 100; size += 10) {
14711     int element_size = ExternalArrayElementSize(array_type);
14712     void* external_data = malloc(size * element_size);
14713     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
14714     obj->SetIndexedPropertiesToExternalArrayData(
14715         external_data, array_type, size);
14716     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14717     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14718     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14719     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14720     free(external_data);
14721   }
14722 }
14723
14724
14725 THREADED_TEST(ExternalArrayInfo) {
14726   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
14727   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
14728   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
14729   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
14730   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
14731   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
14732   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
14733   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
14734   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
14735 }
14736
14737
14738 void ExtArrayLimitsHelper(v8::Isolate* isolate,
14739                           v8::ExternalArrayType array_type,
14740                           int size) {
14741   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
14742   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14743   last_location = last_message = NULL;
14744   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14745   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14746   CHECK(last_location);
14747   CHECK(last_message);
14748 }
14749
14750
14751 TEST(ExternalArrayLimits) {
14752   LocalContext context;
14753   v8::Isolate* isolate = context->GetIsolate();
14754   v8::HandleScope scope(isolate);
14755   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
14756   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
14757   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
14758   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
14759   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
14760   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
14761   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
14762   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
14763   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
14764   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
14765   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
14766   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
14767   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
14768   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
14769   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
14770   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
14771   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
14772   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
14773 }
14774
14775
14776 template <typename ElementType, typename TypedArray,
14777           class ExternalArrayClass>
14778 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
14779                           int64_t low, int64_t high) {
14780   const int kElementCount = 50;
14781
14782   i::ScopedVector<ElementType> backing_store(kElementCount+2);
14783
14784   LocalContext env;
14785   v8::Isolate* isolate = env->GetIsolate();
14786   v8::HandleScope handle_scope(isolate);
14787
14788   Local<v8::ArrayBuffer> ab =
14789       v8::ArrayBuffer::New(isolate, backing_store.start(),
14790                            (kElementCount + 2) * sizeof(ElementType));
14791   Local<TypedArray> ta =
14792       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
14793   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
14794   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
14795   CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
14796   CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
14797   CHECK(ab->Equals(ta->Buffer()));
14798
14799   ElementType* data = backing_store.start() + 2;
14800   for (int i = 0; i < kElementCount; i++) {
14801     data[i] = static_cast<ElementType>(i);
14802   }
14803
14804   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14805       env.local(), ta, kElementCount, array_type, low, high);
14806 }
14807
14808
14809 THREADED_TEST(Uint8Array) {
14810   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
14811       v8::kExternalUint8Array, 0, 0xFF);
14812 }
14813
14814
14815 THREADED_TEST(Int8Array) {
14816   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
14817       v8::kExternalInt8Array, -0x80, 0x7F);
14818 }
14819
14820
14821 THREADED_TEST(Uint16Array) {
14822   TypedArrayTestHelper<uint16_t,
14823                        v8::Uint16Array,
14824                        i::ExternalUint16Array>(
14825       v8::kExternalUint16Array, 0, 0xFFFF);
14826 }
14827
14828
14829 THREADED_TEST(Int16Array) {
14830   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
14831       v8::kExternalInt16Array, -0x8000, 0x7FFF);
14832 }
14833
14834
14835 THREADED_TEST(Uint32Array) {
14836   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
14837       v8::kExternalUint32Array, 0, UINT_MAX);
14838 }
14839
14840
14841 THREADED_TEST(Int32Array) {
14842   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
14843       v8::kExternalInt32Array, INT_MIN, INT_MAX);
14844 }
14845
14846
14847 THREADED_TEST(Float32Array) {
14848   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
14849       v8::kExternalFloat32Array, -500, 500);
14850 }
14851
14852
14853 THREADED_TEST(Float64Array) {
14854   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
14855       v8::kExternalFloat64Array, -500, 500);
14856 }
14857
14858
14859 THREADED_TEST(Uint8ClampedArray) {
14860   TypedArrayTestHelper<uint8_t,
14861                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
14862       v8::kExternalUint8ClampedArray, 0, 0xFF);
14863 }
14864
14865
14866 THREADED_TEST(DataView) {
14867   const int kSize = 50;
14868
14869   i::ScopedVector<uint8_t> backing_store(kSize+2);
14870
14871   LocalContext env;
14872   v8::Isolate* isolate = env->GetIsolate();
14873   v8::HandleScope handle_scope(isolate);
14874
14875   Local<v8::ArrayBuffer> ab =
14876       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14877   Local<v8::DataView> dv =
14878       v8::DataView::New(ab, 2, kSize);
14879   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14880   CHECK_EQ(2u, dv->ByteOffset());
14881   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14882   CHECK(ab->Equals(dv->Buffer()));
14883 }
14884
14885
14886 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
14887   THREADED_TEST(Is##View) {                                                   \
14888     LocalContext env;                                                         \
14889     v8::Isolate* isolate = env->GetIsolate();                                 \
14890     v8::HandleScope handle_scope(isolate);                                    \
14891                                                                               \
14892     Handle<Value> result = CompileRun(                                        \
14893         "var ab = new ArrayBuffer(128);"                                      \
14894         "new " #View "(ab)");                                                 \
14895     CHECK(result->IsArrayBufferView());                                       \
14896     CHECK(result->Is##View());                                                \
14897     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
14898   }
14899
14900 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
14901 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
14902 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
14903 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
14904 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
14905 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
14906 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
14907 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
14908 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
14909 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
14910
14911 #undef IS_ARRAY_BUFFER_VIEW_TEST
14912
14913
14914
14915 THREADED_TEST(ScriptContextDependence) {
14916   LocalContext c1;
14917   v8::HandleScope scope(c1->GetIsolate());
14918   const char *source = "foo";
14919   v8::Handle<v8::Script> dep = v8_compile(source);
14920   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
14921       c1->GetIsolate(), source));
14922   v8::Handle<v8::UnboundScript> indep =
14923       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
14924   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
14925                     v8::Integer::New(c1->GetIsolate(), 100));
14926   CHECK_EQ(dep->Run()->Int32Value(), 100);
14927   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
14928   LocalContext c2;
14929   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
14930                     v8::Integer::New(c2->GetIsolate(), 101));
14931   CHECK_EQ(dep->Run()->Int32Value(), 100);
14932   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
14933 }
14934
14935
14936 THREADED_TEST(StackTrace) {
14937   LocalContext context;
14938   v8::HandleScope scope(context->GetIsolate());
14939   v8::TryCatch try_catch;
14940   const char *source = "function foo() { FAIL.FAIL; }; foo();";
14941   v8::Handle<v8::String> src =
14942       v8::String::NewFromUtf8(context->GetIsolate(), source);
14943   v8::Handle<v8::String> origin =
14944       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
14945   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
14946   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
14947       ->BindToCurrentContext()
14948       ->Run();
14949   CHECK(try_catch.HasCaught());
14950   v8::String::Utf8Value stack(try_catch.StackTrace());
14951   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14952 }
14953
14954
14955 // Checks that a StackFrame has certain expected values.
14956 void checkStackFrame(const char* expected_script_name,
14957     const char* expected_func_name, int expected_line_number,
14958     int expected_column, bool is_eval, bool is_constructor,
14959     v8::Handle<v8::StackFrame> frame) {
14960   v8::HandleScope scope(CcTest::isolate());
14961   v8::String::Utf8Value func_name(frame->GetFunctionName());
14962   v8::String::Utf8Value script_name(frame->GetScriptName());
14963   if (*script_name == NULL) {
14964     // The situation where there is no associated script, like for evals.
14965     CHECK(expected_script_name == NULL);
14966   } else {
14967     CHECK(strstr(*script_name, expected_script_name) != NULL);
14968   }
14969   CHECK(strstr(*func_name, expected_func_name) != NULL);
14970   CHECK_EQ(expected_line_number, frame->GetLineNumber());
14971   CHECK_EQ(expected_column, frame->GetColumn());
14972   CHECK_EQ(is_eval, frame->IsEval());
14973   CHECK_EQ(is_constructor, frame->IsConstructor());
14974 }
14975
14976
14977 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
14978   v8::HandleScope scope(args.GetIsolate());
14979   const char* origin = "capture-stack-trace-test";
14980   const int kOverviewTest = 1;
14981   const int kDetailedTest = 2;
14982
14983   DCHECK(args.Length() == 1);
14984
14985   int testGroup = args[0]->Int32Value();
14986   if (testGroup == kOverviewTest) {
14987     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14988         args.GetIsolate(), 10, v8::StackTrace::kOverview);
14989     CHECK_EQ(4, stackTrace->GetFrameCount());
14990     checkStackFrame(origin, "bar", 2, 10, false, false,
14991                     stackTrace->GetFrame(0));
14992     checkStackFrame(origin, "foo", 6, 3, false, false,
14993                     stackTrace->GetFrame(1));
14994     // This is the source string inside the eval which has the call to foo.
14995     checkStackFrame(NULL, "", 1, 5, false, false,
14996                     stackTrace->GetFrame(2));
14997     // The last frame is an anonymous function which has the initial eval call.
14998     checkStackFrame(origin, "", 8, 7, false, false,
14999                     stackTrace->GetFrame(3));
15000
15001     CHECK(stackTrace->AsArray()->IsArray());
15002   } else if (testGroup == kDetailedTest) {
15003     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15004         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15005     CHECK_EQ(4, stackTrace->GetFrameCount());
15006     checkStackFrame(origin, "bat", 4, 22, false, false,
15007                     stackTrace->GetFrame(0));
15008     checkStackFrame(origin, "baz", 8, 3, false, true,
15009                     stackTrace->GetFrame(1));
15010     bool is_eval = true;
15011     // This is the source string inside the eval which has the call to baz.
15012     checkStackFrame(NULL, "", 1, 5, is_eval, false,
15013                     stackTrace->GetFrame(2));
15014     // The last frame is an anonymous function which has the initial eval call.
15015     checkStackFrame(origin, "", 10, 1, false, false,
15016                     stackTrace->GetFrame(3));
15017
15018     CHECK(stackTrace->AsArray()->IsArray());
15019   }
15020 }
15021
15022
15023 // Tests the C++ StackTrace API.
15024 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
15025 // THREADED_TEST(CaptureStackTrace) {
15026 TEST(CaptureStackTrace) {
15027   v8::Isolate* isolate = CcTest::isolate();
15028   v8::HandleScope scope(isolate);
15029   v8::Handle<v8::String> origin =
15030       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
15031   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15032   templ->Set(v8_str("AnalyzeStackInNativeCode"),
15033              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
15034   LocalContext context(0, templ);
15035
15036   // Test getting OVERVIEW information. Should ignore information that is not
15037   // script name, function name, line number, and column offset.
15038   const char *overview_source =
15039     "function bar() {\n"
15040     "  var y; AnalyzeStackInNativeCode(1);\n"
15041     "}\n"
15042     "function foo() {\n"
15043     "\n"
15044     "  bar();\n"
15045     "}\n"
15046     "var x;eval('new foo();');";
15047   v8::Handle<v8::String> overview_src =
15048       v8::String::NewFromUtf8(isolate, overview_source);
15049   v8::ScriptCompiler::Source script_source(overview_src,
15050                                            v8::ScriptOrigin(origin));
15051   v8::Handle<Value> overview_result(
15052       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
15053           ->BindToCurrentContext()
15054           ->Run());
15055   CHECK(!overview_result.IsEmpty());
15056   CHECK(overview_result->IsObject());
15057
15058   // Test getting DETAILED information.
15059   const char *detailed_source =
15060     "function bat() {AnalyzeStackInNativeCode(2);\n"
15061     "}\n"
15062     "\n"
15063     "function baz() {\n"
15064     "  bat();\n"
15065     "}\n"
15066     "eval('new baz();');";
15067   v8::Handle<v8::String> detailed_src =
15068       v8::String::NewFromUtf8(isolate, detailed_source);
15069   // Make the script using a non-zero line and column offset.
15070   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
15071   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
15072   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
15073   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
15074   v8::Handle<v8::UnboundScript> detailed_script(
15075       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
15076   v8::Handle<Value> detailed_result(
15077       detailed_script->BindToCurrentContext()->Run());
15078   CHECK(!detailed_result.IsEmpty());
15079   CHECK(detailed_result->IsObject());
15080 }
15081
15082
15083 static void StackTraceForUncaughtExceptionListener(
15084     v8::Handle<v8::Message> message,
15085     v8::Handle<Value>) {
15086   report_count++;
15087   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15088   CHECK_EQ(2, stack_trace->GetFrameCount());
15089   checkStackFrame("origin", "foo", 2, 3, false, false,
15090                   stack_trace->GetFrame(0));
15091   checkStackFrame("origin", "bar", 5, 3, false, false,
15092                   stack_trace->GetFrame(1));
15093 }
15094
15095
15096 TEST(CaptureStackTraceForUncaughtException) {
15097   report_count = 0;
15098   LocalContext env;
15099   v8::HandleScope scope(env->GetIsolate());
15100   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
15101   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15102
15103   CompileRunWithOrigin(
15104       "function foo() {\n"
15105       "  throw 1;\n"
15106       "};\n"
15107       "function bar() {\n"
15108       "  foo();\n"
15109       "};",
15110       "origin");
15111   v8::Local<v8::Object> global = env->Global();
15112   Local<Value> trouble = global->Get(v8_str("bar"));
15113   CHECK(trouble->IsFunction());
15114   Function::Cast(*trouble)->Call(global, 0, NULL);
15115   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15116   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
15117   CHECK_EQ(1, report_count);
15118 }
15119
15120
15121 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
15122   report_count = 0;
15123   LocalContext env;
15124   v8::HandleScope scope(env->GetIsolate());
15125
15126   // Create an Error object first.
15127   CompileRunWithOrigin(
15128       "function foo() {\n"
15129       "e=new Error('err');\n"
15130       "};\n"
15131       "function bar() {\n"
15132       "  foo();\n"
15133       "};\n"
15134       "var e;",
15135       "origin");
15136   v8::Local<v8::Object> global = env->Global();
15137   Local<Value> trouble = global->Get(v8_str("bar"));
15138   CHECK(trouble->IsFunction());
15139   Function::Cast(*trouble)->Call(global, 0, NULL);
15140
15141   // Enable capturing detailed stack trace late, and throw the exception.
15142   // The detailed stack trace should be extracted from the simple stack.
15143   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
15144   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15145   CompileRunWithOrigin("throw e", "origin");
15146   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15147   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
15148   CHECK_EQ(1, report_count);
15149 }
15150
15151
15152 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
15153   LocalContext env;
15154   v8::HandleScope scope(env->GetIsolate());
15155   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
15156                                                     1024,
15157                                                     v8::StackTrace::kDetailed);
15158
15159   CompileRun(
15160       "var setters = ['column', 'lineNumber', 'scriptName',\n"
15161       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
15162       "    'isConstructor'];\n"
15163       "for (var i = 0; i < setters.length; i++) {\n"
15164       "  var prop = setters[i];\n"
15165       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
15166       "}\n");
15167   CompileRun("throw 'exception';");
15168   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15169 }
15170
15171
15172 static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
15173                                            v8::Handle<Value>) {
15174   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15175   CHECK_EQ(5, stack_trace->GetFrameCount());
15176   checkStackFrame("origin", "foo:0", 4, 7, false, false,
15177                   stack_trace->GetFrame(0));
15178   checkStackFrame("origin", "foo:1", 5, 27, false, false,
15179                   stack_trace->GetFrame(1));
15180   checkStackFrame("origin", "foo", 5, 27, false, false,
15181                   stack_trace->GetFrame(2));
15182   checkStackFrame("origin", "foo", 5, 27, false, false,
15183                   stack_trace->GetFrame(3));
15184   checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
15185 }
15186
15187
15188 TEST(GetStackTraceContainsFunctionsWithFunctionName) {
15189   LocalContext env;
15190   v8::HandleScope scope(env->GetIsolate());
15191
15192   CompileRunWithOrigin(
15193       "function gen(name, counter) {\n"
15194       "  var f = function foo() {\n"
15195       "    if (counter === 0)\n"
15196       "      throw 1;\n"
15197       "    gen(name, counter - 1)();\n"
15198       "  };\n"
15199       "  if (counter == 3) {\n"
15200       "    Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
15201       "  } else {\n"
15202       "    Object.defineProperty(f, 'name', {writable:true});\n"
15203       "    if (counter == 2)\n"
15204       "      f.name = 42;\n"
15205       "    else\n"
15206       "      f.name = name + ':' + counter;\n"
15207       "  }\n"
15208       "  return f;\n"
15209       "};",
15210       "origin");
15211
15212   v8::V8::AddMessageListener(StackTraceFunctionNameListener);
15213   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15214   CompileRunWithOrigin("gen('foo', 3)();", "origin");
15215   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15216   v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
15217 }
15218
15219
15220 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
15221                                      v8::Handle<v8::Value> data) {
15222   // Use the frame where JavaScript is called from.
15223   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15224   CHECK(!stack_trace.IsEmpty());
15225   int frame_count = stack_trace->GetFrameCount();
15226   CHECK_EQ(3, frame_count);
15227   int line_number[] = {1, 2, 5};
15228   for (int i = 0; i < frame_count; i++) {
15229     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
15230   }
15231 }
15232
15233
15234 // Test that we only return the stack trace at the site where the exception
15235 // is first thrown (not where it is rethrown).
15236 TEST(RethrowStackTrace) {
15237   LocalContext env;
15238   v8::HandleScope scope(env->GetIsolate());
15239   // We make sure that
15240   // - the stack trace of the ReferenceError in g() is reported.
15241   // - the stack trace is not overwritten when e1 is rethrown by t().
15242   // - the stack trace of e2 does not overwrite that of e1.
15243   const char* source =
15244       "function g() { error; }          \n"
15245       "function f() { g(); }            \n"
15246       "function t(e) { throw e; }       \n"
15247       "try {                            \n"
15248       "  f();                           \n"
15249       "} catch (e1) {                   \n"
15250       "  try {                          \n"
15251       "    error;                       \n"
15252       "  } catch (e2) {                 \n"
15253       "    t(e1);                       \n"
15254       "  }                              \n"
15255       "}                                \n";
15256   v8::V8::AddMessageListener(RethrowStackTraceHandler);
15257   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15258   CompileRun(source);
15259   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15260   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
15261 }
15262
15263
15264 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
15265                                               v8::Handle<v8::Value> data) {
15266   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15267   CHECK(!stack_trace.IsEmpty());
15268   int frame_count = stack_trace->GetFrameCount();
15269   CHECK_EQ(2, frame_count);
15270   int line_number[] = {3, 7};
15271   for (int i = 0; i < frame_count; i++) {
15272     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
15273   }
15274 }
15275
15276
15277 // Test that we do not recognize identity for primitive exceptions.
15278 TEST(RethrowPrimitiveStackTrace) {
15279   LocalContext env;
15280   v8::HandleScope scope(env->GetIsolate());
15281   // We do not capture stack trace for non Error objects on creation time.
15282   // Instead, we capture the stack trace on last throw.
15283   const char* source =
15284       "function g() { throw 404; }      \n"
15285       "function f() { g(); }            \n"
15286       "function t(e) { throw e; }       \n"
15287       "try {                            \n"
15288       "  f();                           \n"
15289       "} catch (e1) {                   \n"
15290       "  t(e1)                          \n"
15291       "}                                \n";
15292   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
15293   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15294   CompileRun(source);
15295   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15296   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
15297 }
15298
15299
15300 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
15301                                               v8::Handle<v8::Value> data) {
15302   // Use the frame where JavaScript is called from.
15303   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15304   CHECK(!stack_trace.IsEmpty());
15305   CHECK_EQ(1, stack_trace->GetFrameCount());
15306   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
15307 }
15308
15309
15310 // Test that the stack trace is captured when the error object is created and
15311 // not where it is thrown.
15312 TEST(RethrowExistingStackTrace) {
15313   LocalContext env;
15314   v8::HandleScope scope(env->GetIsolate());
15315   const char* source =
15316       "var e = new Error();           \n"
15317       "throw e;                       \n";
15318   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
15319   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15320   CompileRun(source);
15321   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15322   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
15323 }
15324
15325
15326 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
15327                                                v8::Handle<v8::Value> data) {
15328   // Use the frame where JavaScript is called from.
15329   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15330   CHECK(!stack_trace.IsEmpty());
15331   CHECK_EQ(1, stack_trace->GetFrameCount());
15332   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
15333 }
15334
15335
15336 // Test that the stack trace is captured where the bogus Error object is thrown.
15337 TEST(RethrowBogusErrorStackTrace) {
15338   LocalContext env;
15339   v8::HandleScope scope(env->GetIsolate());
15340   const char* source =
15341       "var e = {__proto__: new Error()} \n"
15342       "throw e;                         \n";
15343   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
15344   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15345   CompileRun(source);
15346   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15347   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
15348 }
15349
15350
15351 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
15352 int promise_reject_counter = 0;
15353 int promise_revoke_counter = 0;
15354 int promise_reject_msg_line_number = -1;
15355 int promise_reject_msg_column_number = -1;
15356 int promise_reject_line_number = -1;
15357 int promise_reject_column_number = -1;
15358 int promise_reject_frame_count = -1;
15359
15360 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
15361   if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
15362     promise_reject_counter++;
15363     CcTest::global()->Set(v8_str("rejected"), reject_message.GetPromise());
15364     CcTest::global()->Set(v8_str("value"), reject_message.GetValue());
15365     v8::Handle<v8::Message> message =
15366         v8::Exception::CreateMessage(reject_message.GetValue());
15367     v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15368
15369     promise_reject_msg_line_number = message->GetLineNumber();
15370     promise_reject_msg_column_number = message->GetStartColumn() + 1;
15371
15372     if (!stack_trace.IsEmpty()) {
15373       promise_reject_frame_count = stack_trace->GetFrameCount();
15374       if (promise_reject_frame_count > 0) {
15375         CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
15376         promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
15377         promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
15378       } else {
15379         promise_reject_line_number = -1;
15380         promise_reject_column_number = -1;
15381       }
15382     }
15383   } else {
15384     promise_revoke_counter++;
15385     CcTest::global()->Set(v8_str("revoked"), reject_message.GetPromise());
15386     CHECK(reject_message.GetValue().IsEmpty());
15387   }
15388 }
15389
15390
15391 v8::Handle<v8::Promise> GetPromise(const char* name) {
15392   return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
15393 }
15394
15395
15396 v8::Handle<v8::Value> RejectValue() {
15397   return CcTest::global()->Get(v8_str("value"));
15398 }
15399
15400
15401 void ResetPromiseStates() {
15402   promise_reject_counter = 0;
15403   promise_revoke_counter = 0;
15404   promise_reject_msg_line_number = -1;
15405   promise_reject_msg_column_number = -1;
15406   promise_reject_line_number = -1;
15407   promise_reject_column_number = -1;
15408   promise_reject_frame_count = -1;
15409   CcTest::global()->Set(v8_str("rejected"), v8_str(""));
15410   CcTest::global()->Set(v8_str("value"), v8_str(""));
15411   CcTest::global()->Set(v8_str("revoked"), v8_str(""));
15412 }
15413
15414
15415 TEST(PromiseRejectCallback) {
15416   LocalContext env;
15417   v8::Isolate* isolate = env->GetIsolate();
15418   v8::HandleScope scope(isolate);
15419
15420   isolate->SetPromiseRejectCallback(PromiseRejectCallback);
15421
15422   ResetPromiseStates();
15423
15424   // Create promise p0.
15425   CompileRun(
15426       "var reject;            \n"
15427       "var p0 = new Promise(  \n"
15428       "  function(res, rej) { \n"
15429       "    reject = rej;      \n"
15430       "  }                    \n"
15431       ");                     \n");
15432   CHECK(!GetPromise("p0")->HasHandler());
15433   CHECK_EQ(0, promise_reject_counter);
15434   CHECK_EQ(0, promise_revoke_counter);
15435
15436   // Add resolve handler (and default reject handler) to p0.
15437   CompileRun("var p1 = p0.then(function(){});");
15438   CHECK(GetPromise("p0")->HasHandler());
15439   CHECK(!GetPromise("p1")->HasHandler());
15440   CHECK_EQ(0, promise_reject_counter);
15441   CHECK_EQ(0, promise_revoke_counter);
15442
15443   // Reject p0.
15444   CompileRun("reject('ppp');");
15445   CHECK(GetPromise("p0")->HasHandler());
15446   CHECK(!GetPromise("p1")->HasHandler());
15447   CHECK_EQ(1, promise_reject_counter);
15448   CHECK_EQ(0, promise_revoke_counter);
15449   CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
15450   CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
15451   CHECK(RejectValue()->Equals(v8_str("ppp")));
15452
15453   // Reject p0 again. Callback is not triggered again.
15454   CompileRun("reject();");
15455   CHECK(GetPromise("p0")->HasHandler());
15456   CHECK(!GetPromise("p1")->HasHandler());
15457   CHECK_EQ(1, promise_reject_counter);
15458   CHECK_EQ(0, promise_revoke_counter);
15459
15460   // Add resolve handler to p1.
15461   CompileRun("var p2 = p1.then(function(){});");
15462   CHECK(GetPromise("p0")->HasHandler());
15463   CHECK(GetPromise("p1")->HasHandler());
15464   CHECK(!GetPromise("p2")->HasHandler());
15465   CHECK_EQ(2, promise_reject_counter);
15466   CHECK_EQ(1, promise_revoke_counter);
15467   CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
15468   CHECK(RejectValue()->Equals(v8_str("ppp")));
15469   CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
15470
15471   ResetPromiseStates();
15472
15473   // Create promise q0.
15474   CompileRun(
15475       "var q0 = new Promise(  \n"
15476       "  function(res, rej) { \n"
15477       "    reject = rej;      \n"
15478       "  }                    \n"
15479       ");                     \n");
15480   CHECK(!GetPromise("q0")->HasHandler());
15481   CHECK_EQ(0, promise_reject_counter);
15482   CHECK_EQ(0, promise_revoke_counter);
15483
15484   // Add reject handler to q0.
15485   CompileRun("var q1 = q0.catch(function() {});");
15486   CHECK(GetPromise("q0")->HasHandler());
15487   CHECK(!GetPromise("q1")->HasHandler());
15488   CHECK_EQ(0, promise_reject_counter);
15489   CHECK_EQ(0, promise_revoke_counter);
15490
15491   // Reject q0.
15492   CompileRun("reject('qq')");
15493   CHECK(GetPromise("q0")->HasHandler());
15494   CHECK(!GetPromise("q1")->HasHandler());
15495   CHECK_EQ(0, promise_reject_counter);
15496   CHECK_EQ(0, promise_revoke_counter);
15497
15498   // Add a new reject handler, which rejects by returning Promise.reject().
15499   // The returned promise q_ triggers a reject callback at first, only to
15500   // revoke it when returning it causes q2 to be rejected.
15501   CompileRun(
15502       "var q_;"
15503       "var q2 = q0.catch(               \n"
15504       "   function() {                  \n"
15505       "     q_ = Promise.reject('qqq'); \n"
15506       "     return q_;                  \n"
15507       "   }                             \n"
15508       ");                               \n");
15509   CHECK(GetPromise("q0")->HasHandler());
15510   CHECK(!GetPromise("q1")->HasHandler());
15511   CHECK(!GetPromise("q2")->HasHandler());
15512   CHECK(GetPromise("q_")->HasHandler());
15513   CHECK_EQ(2, promise_reject_counter);
15514   CHECK_EQ(1, promise_revoke_counter);
15515   CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
15516   CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
15517   CHECK(RejectValue()->Equals(v8_str("qqq")));
15518
15519   // Add a reject handler to the resolved q1, which rejects by throwing.
15520   CompileRun(
15521       "var q3 = q1.then(  \n"
15522       "   function() {    \n"
15523       "     throw 'qqqq'; \n"
15524       "   }               \n"
15525       ");                 \n");
15526   CHECK(GetPromise("q0")->HasHandler());
15527   CHECK(GetPromise("q1")->HasHandler());
15528   CHECK(!GetPromise("q2")->HasHandler());
15529   CHECK(!GetPromise("q3")->HasHandler());
15530   CHECK_EQ(3, promise_reject_counter);
15531   CHECK_EQ(1, promise_revoke_counter);
15532   CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
15533   CHECK(RejectValue()->Equals(v8_str("qqqq")));
15534
15535   ResetPromiseStates();
15536
15537   // Create promise r0, which has three handlers, two of which handle rejects.
15538   CompileRun(
15539       "var r0 = new Promise(             \n"
15540       "  function(res, rej) {            \n"
15541       "    reject = rej;                 \n"
15542       "  }                               \n"
15543       ");                                \n"
15544       "var r1 = r0.catch(function() {}); \n"
15545       "var r2 = r0.then(function() {});  \n"
15546       "var r3 = r0.then(function() {},   \n"
15547       "                 function() {});  \n");
15548   CHECK(GetPromise("r0")->HasHandler());
15549   CHECK(!GetPromise("r1")->HasHandler());
15550   CHECK(!GetPromise("r2")->HasHandler());
15551   CHECK(!GetPromise("r3")->HasHandler());
15552   CHECK_EQ(0, promise_reject_counter);
15553   CHECK_EQ(0, promise_revoke_counter);
15554
15555   // Reject r0.
15556   CompileRun("reject('rrr')");
15557   CHECK(GetPromise("r0")->HasHandler());
15558   CHECK(!GetPromise("r1")->HasHandler());
15559   CHECK(!GetPromise("r2")->HasHandler());
15560   CHECK(!GetPromise("r3")->HasHandler());
15561   CHECK_EQ(1, promise_reject_counter);
15562   CHECK_EQ(0, promise_revoke_counter);
15563   CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
15564   CHECK(RejectValue()->Equals(v8_str("rrr")));
15565
15566   // Add reject handler to r2.
15567   CompileRun("var r4 = r2.catch(function() {});");
15568   CHECK(GetPromise("r0")->HasHandler());
15569   CHECK(!GetPromise("r1")->HasHandler());
15570   CHECK(GetPromise("r2")->HasHandler());
15571   CHECK(!GetPromise("r3")->HasHandler());
15572   CHECK(!GetPromise("r4")->HasHandler());
15573   CHECK_EQ(1, promise_reject_counter);
15574   CHECK_EQ(1, promise_revoke_counter);
15575   CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
15576   CHECK(RejectValue()->Equals(v8_str("rrr")));
15577
15578   // Add reject handlers to r4.
15579   CompileRun("var r5 = r4.then(function() {}, function() {});");
15580   CHECK(GetPromise("r0")->HasHandler());
15581   CHECK(!GetPromise("r1")->HasHandler());
15582   CHECK(GetPromise("r2")->HasHandler());
15583   CHECK(!GetPromise("r3")->HasHandler());
15584   CHECK(GetPromise("r4")->HasHandler());
15585   CHECK(!GetPromise("r5")->HasHandler());
15586   CHECK_EQ(1, promise_reject_counter);
15587   CHECK_EQ(1, promise_revoke_counter);
15588
15589   ResetPromiseStates();
15590
15591   // Create promise s0, which has three handlers, none of which handle rejects.
15592   CompileRun(
15593       "var s0 = new Promise(            \n"
15594       "  function(res, rej) {           \n"
15595       "    reject = rej;                \n"
15596       "  }                              \n"
15597       ");                               \n"
15598       "var s1 = s0.then(function() {}); \n"
15599       "var s2 = s0.then(function() {}); \n"
15600       "var s3 = s0.then(function() {}); \n");
15601   CHECK(GetPromise("s0")->HasHandler());
15602   CHECK(!GetPromise("s1")->HasHandler());
15603   CHECK(!GetPromise("s2")->HasHandler());
15604   CHECK(!GetPromise("s3")->HasHandler());
15605   CHECK_EQ(0, promise_reject_counter);
15606   CHECK_EQ(0, promise_revoke_counter);
15607
15608   // Reject s0.
15609   CompileRun("reject('sss')");
15610   CHECK(GetPromise("s0")->HasHandler());
15611   CHECK(!GetPromise("s1")->HasHandler());
15612   CHECK(!GetPromise("s2")->HasHandler());
15613   CHECK(!GetPromise("s3")->HasHandler());
15614   CHECK_EQ(3, promise_reject_counter);
15615   CHECK_EQ(0, promise_revoke_counter);
15616   CHECK(RejectValue()->Equals(v8_str("sss")));
15617
15618   // Test stack frames.
15619   V8::SetCaptureStackTraceForUncaughtExceptions(true);
15620
15621   ResetPromiseStates();
15622
15623   // Create promise t0, which is rejected in the constructor with an error.
15624   CompileRunWithOrigin(
15625       "var t0 = new Promise(  \n"
15626       "  function(res, rej) { \n"
15627       "    reference_error;   \n"
15628       "  }                    \n"
15629       ");                     \n",
15630       "pro", 0, 0);
15631   CHECK(!GetPromise("t0")->HasHandler());
15632   CHECK_EQ(1, promise_reject_counter);
15633   CHECK_EQ(0, promise_revoke_counter);
15634   CHECK_EQ(2, promise_reject_frame_count);
15635   CHECK_EQ(3, promise_reject_line_number);
15636   CHECK_EQ(5, promise_reject_column_number);
15637   CHECK_EQ(3, promise_reject_msg_line_number);
15638   CHECK_EQ(5, promise_reject_msg_column_number);
15639
15640   ResetPromiseStates();
15641
15642   // Create promise u0 and chain u1 to it, which is rejected via throw.
15643   CompileRunWithOrigin(
15644       "var u0 = Promise.resolve();        \n"
15645       "var u1 = u0.then(                  \n"
15646       "           function() {            \n"
15647       "             (function() {         \n"
15648       "                throw new Error(); \n"
15649       "              })();                \n"
15650       "           }                       \n"
15651       "         );                        \n",
15652       "pro", 0, 0);
15653   CHECK(GetPromise("u0")->HasHandler());
15654   CHECK(!GetPromise("u1")->HasHandler());
15655   CHECK_EQ(1, promise_reject_counter);
15656   CHECK_EQ(0, promise_revoke_counter);
15657   CHECK_EQ(2, promise_reject_frame_count);
15658   CHECK_EQ(5, promise_reject_line_number);
15659   CHECK_EQ(23, promise_reject_column_number);
15660   CHECK_EQ(5, promise_reject_msg_line_number);
15661   CHECK_EQ(23, promise_reject_msg_column_number);
15662
15663   // Throw in u3, which handles u1's rejection.
15664   CompileRunWithOrigin(
15665       "function f() {                \n"
15666       "  return (function() {        \n"
15667       "    return new Error();       \n"
15668       "  })();                       \n"
15669       "}                             \n"
15670       "var u2 = Promise.reject(f()); \n"
15671       "var u3 = u1.catch(            \n"
15672       "           function() {       \n"
15673       "             return u2;       \n"
15674       "           }                  \n"
15675       "         );                   \n",
15676       "pro", 0, 0);
15677   CHECK(GetPromise("u0")->HasHandler());
15678   CHECK(GetPromise("u1")->HasHandler());
15679   CHECK(GetPromise("u2")->HasHandler());
15680   CHECK(!GetPromise("u3")->HasHandler());
15681   CHECK_EQ(3, promise_reject_counter);
15682   CHECK_EQ(2, promise_revoke_counter);
15683   CHECK_EQ(3, promise_reject_frame_count);
15684   CHECK_EQ(3, promise_reject_line_number);
15685   CHECK_EQ(12, promise_reject_column_number);
15686   CHECK_EQ(3, promise_reject_msg_line_number);
15687   CHECK_EQ(12, promise_reject_msg_column_number);
15688
15689   ResetPromiseStates();
15690
15691   // Create promise rejected promise v0, which is incorrectly handled by v1
15692   // via chaining cycle.
15693   CompileRunWithOrigin(
15694       "var v0 = Promise.reject(); \n"
15695       "var v1 = v0.catch(         \n"
15696       "           function() {    \n"
15697       "             return v1;    \n"
15698       "           }               \n"
15699       "         );                \n",
15700       "pro", 0, 0);
15701   CHECK(GetPromise("v0")->HasHandler());
15702   CHECK(!GetPromise("v1")->HasHandler());
15703   CHECK_EQ(2, promise_reject_counter);
15704   CHECK_EQ(1, promise_revoke_counter);
15705   CHECK_EQ(0, promise_reject_frame_count);
15706   CHECK_EQ(-1, promise_reject_line_number);
15707   CHECK_EQ(-1, promise_reject_column_number);
15708
15709   ResetPromiseStates();
15710
15711   // Create promise t1, which rejects by throwing syntax error from eval.
15712   CompileRunWithOrigin(
15713       "var t1 = new Promise(   \n"
15714       "  function(res, rej) {  \n"
15715       "    var content = '\\n\\\n"
15716       "      }';               \n"
15717       "    eval(content);      \n"
15718       "  }                     \n"
15719       ");                      \n",
15720       "pro", 0, 0);
15721   CHECK(!GetPromise("t1")->HasHandler());
15722   CHECK_EQ(1, promise_reject_counter);
15723   CHECK_EQ(0, promise_revoke_counter);
15724   CHECK_EQ(2, promise_reject_frame_count);
15725   CHECK_EQ(5, promise_reject_line_number);
15726   CHECK_EQ(10, promise_reject_column_number);
15727   CHECK_EQ(2, promise_reject_msg_line_number);
15728   CHECK_EQ(7, promise_reject_msg_column_number);
15729 }
15730
15731
15732 void AnalyzeStackOfEvalWithSourceURL(
15733     const v8::FunctionCallbackInfo<v8::Value>& args) {
15734   v8::HandleScope scope(args.GetIsolate());
15735   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15736       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15737   CHECK_EQ(5, stackTrace->GetFrameCount());
15738   v8::Handle<v8::String> url = v8_str("eval_url");
15739   for (int i = 0; i < 3; i++) {
15740     v8::Handle<v8::String> name =
15741         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15742     CHECK(!name.IsEmpty());
15743     CHECK(url->Equals(name));
15744   }
15745 }
15746
15747
15748 TEST(SourceURLInStackTrace) {
15749   v8::Isolate* isolate = CcTest::isolate();
15750   v8::HandleScope scope(isolate);
15751   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15752   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
15753              v8::FunctionTemplate::New(isolate,
15754                                        AnalyzeStackOfEvalWithSourceURL));
15755   LocalContext context(0, templ);
15756
15757   const char *source =
15758     "function outer() {\n"
15759     "function bar() {\n"
15760     "  AnalyzeStackOfEvalWithSourceURL();\n"
15761     "}\n"
15762     "function foo() {\n"
15763     "\n"
15764     "  bar();\n"
15765     "}\n"
15766     "foo();\n"
15767     "}\n"
15768     "eval('(' + outer +')()%s');";
15769
15770   i::ScopedVector<char> code(1024);
15771   i::SNPrintF(code, source, "//# sourceURL=eval_url");
15772   CHECK(CompileRun(code.start())->IsUndefined());
15773   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
15774   CHECK(CompileRun(code.start())->IsUndefined());
15775 }
15776
15777
15778 static int scriptIdInStack[2];
15779
15780 void AnalyzeScriptIdInStack(
15781     const v8::FunctionCallbackInfo<v8::Value>& args) {
15782   v8::HandleScope scope(args.GetIsolate());
15783   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15784       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
15785   CHECK_EQ(2, stackTrace->GetFrameCount());
15786   for (int i = 0; i < 2; i++) {
15787     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
15788   }
15789 }
15790
15791
15792 TEST(ScriptIdInStackTrace) {
15793   v8::Isolate* isolate = CcTest::isolate();
15794   v8::HandleScope scope(isolate);
15795   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15796   templ->Set(v8_str("AnalyzeScriptIdInStack"),
15797              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
15798   LocalContext context(0, templ);
15799
15800   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
15801     isolate,
15802     "function foo() {\n"
15803     "  AnalyzeScriptIdInStack();"
15804     "}\n"
15805     "foo();\n");
15806   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
15807   script->Run();
15808   for (int i = 0; i < 2; i++) {
15809     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
15810     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
15811   }
15812 }
15813
15814
15815 void AnalyzeStackOfInlineScriptWithSourceURL(
15816     const v8::FunctionCallbackInfo<v8::Value>& args) {
15817   v8::HandleScope scope(args.GetIsolate());
15818   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15819       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15820   CHECK_EQ(4, stackTrace->GetFrameCount());
15821   v8::Handle<v8::String> url = v8_str("url");
15822   for (int i = 0; i < 3; i++) {
15823     v8::Handle<v8::String> name =
15824         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15825     CHECK(!name.IsEmpty());
15826     CHECK(url->Equals(name));
15827   }
15828 }
15829
15830
15831 TEST(InlineScriptWithSourceURLInStackTrace) {
15832   v8::Isolate* isolate = CcTest::isolate();
15833   v8::HandleScope scope(isolate);
15834   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15835   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15836              v8::FunctionTemplate::New(
15837                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
15838   LocalContext context(0, templ);
15839
15840   const char *source =
15841     "function outer() {\n"
15842     "function bar() {\n"
15843     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
15844     "}\n"
15845     "function foo() {\n"
15846     "\n"
15847     "  bar();\n"
15848     "}\n"
15849     "foo();\n"
15850     "}\n"
15851     "outer()\n%s";
15852
15853   i::ScopedVector<char> code(1024);
15854   i::SNPrintF(code, source, "//# sourceURL=source_url");
15855   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15856   i::SNPrintF(code, source, "//@ sourceURL=source_url");
15857   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15858 }
15859
15860
15861 void AnalyzeStackOfDynamicScriptWithSourceURL(
15862     const v8::FunctionCallbackInfo<v8::Value>& args) {
15863   v8::HandleScope scope(args.GetIsolate());
15864   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15865       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15866   CHECK_EQ(4, stackTrace->GetFrameCount());
15867   v8::Handle<v8::String> url = v8_str("source_url");
15868   for (int i = 0; i < 3; i++) {
15869     v8::Handle<v8::String> name =
15870         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15871     CHECK(!name.IsEmpty());
15872     CHECK(url->Equals(name));
15873   }
15874 }
15875
15876
15877 TEST(DynamicWithSourceURLInStackTrace) {
15878   v8::Isolate* isolate = CcTest::isolate();
15879   v8::HandleScope scope(isolate);
15880   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15881   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15882              v8::FunctionTemplate::New(
15883                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
15884   LocalContext context(0, templ);
15885
15886   const char *source =
15887     "function outer() {\n"
15888     "function bar() {\n"
15889     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15890     "}\n"
15891     "function foo() {\n"
15892     "\n"
15893     "  bar();\n"
15894     "}\n"
15895     "foo();\n"
15896     "}\n"
15897     "outer()\n%s";
15898
15899   i::ScopedVector<char> code(1024);
15900   i::SNPrintF(code, source, "//# sourceURL=source_url");
15901   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15902   i::SNPrintF(code, source, "//@ sourceURL=source_url");
15903   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15904 }
15905
15906
15907 TEST(DynamicWithSourceURLInStackTraceString) {
15908   LocalContext context;
15909   v8::HandleScope scope(context->GetIsolate());
15910
15911   const char *source =
15912     "function outer() {\n"
15913     "  function foo() {\n"
15914     "    FAIL.FAIL;\n"
15915     "  }\n"
15916     "  foo();\n"
15917     "}\n"
15918     "outer()\n%s";
15919
15920   i::ScopedVector<char> code(1024);
15921   i::SNPrintF(code, source, "//# sourceURL=source_url");
15922   v8::TryCatch try_catch;
15923   CompileRunWithOrigin(code.start(), "", 0, 0);
15924   CHECK(try_catch.HasCaught());
15925   v8::String::Utf8Value stack(try_catch.StackTrace());
15926   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
15927 }
15928
15929
15930 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15931   LocalContext context;
15932   v8::HandleScope scope(context->GetIsolate());
15933
15934   const char *source =
15935     "function outer() {\n"
15936     "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
15937     "  //# sourceURL=source_url\";\n"
15938     "  eval(scriptContents);\n"
15939     "  foo(); }\n"
15940     "outer();\n"
15941     "//# sourceURL=outer_url";
15942
15943   v8::TryCatch try_catch;
15944   CompileRun(source);
15945   CHECK(try_catch.HasCaught());
15946
15947   Local<v8::Message> message = try_catch.Message();
15948   Handle<Value> sourceURL =
15949     message->GetScriptOrigin().ResourceName();
15950   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15951 }
15952
15953
15954 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15955   LocalContext context;
15956   v8::HandleScope scope(context->GetIsolate());
15957
15958   const char *source =
15959     "function outer() {\n"
15960     "  var scriptContents = \"function boo(){ boo(); }\\\n"
15961     "  //# sourceURL=source_url\";\n"
15962     "  eval(scriptContents);\n"
15963     "  boo(); }\n"
15964     "outer();\n"
15965     "//# sourceURL=outer_url";
15966
15967   v8::TryCatch try_catch;
15968   CompileRun(source);
15969   CHECK(try_catch.HasCaught());
15970
15971   Local<v8::Message> message = try_catch.Message();
15972   Handle<Value> sourceURL =
15973     message->GetScriptOrigin().ResourceName();
15974   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15975 }
15976
15977
15978 static void CreateGarbageInOldSpace() {
15979   i::Factory* factory = CcTest::i_isolate()->factory();
15980   v8::HandleScope scope(CcTest::isolate());
15981   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
15982   for (int i = 0; i < 1000; i++) {
15983     factory->NewFixedArray(1000, i::TENURED);
15984   }
15985 }
15986
15987
15988 // Test that idle notification can be handled and eventually collects garbage.
15989 TEST(TestIdleNotification) {
15990   const intptr_t MB = 1024 * 1024;
15991   const double IdlePauseInSeconds = 1.0;
15992   LocalContext env;
15993   v8::HandleScope scope(env->GetIsolate());
15994   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
15995   CreateGarbageInOldSpace();
15996   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
15997   CHECK_GT(size_with_garbage, initial_size + MB);
15998   bool finished = false;
15999   for (int i = 0; i < 200 && !finished; i++) {
16000     finished = env->GetIsolate()->IdleNotificationDeadline(
16001         (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
16002          static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
16003         IdlePauseInSeconds);
16004   }
16005   intptr_t final_size = CcTest::heap()->SizeOfObjects();
16006   CHECK(finished);
16007   CHECK_LT(final_size, initial_size + 1);
16008 }
16009
16010
16011 TEST(Regress2333) {
16012   LocalContext env;
16013   for (int i = 0; i < 3; i++) {
16014     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
16015   }
16016 }
16017
16018 static uint32_t* stack_limit;
16019
16020 static void GetStackLimitCallback(
16021     const v8::FunctionCallbackInfo<v8::Value>& args) {
16022   stack_limit = reinterpret_cast<uint32_t*>(
16023       CcTest::i_isolate()->stack_guard()->real_climit());
16024 }
16025
16026
16027 // Uses the address of a local variable to determine the stack top now.
16028 // Given a size, returns an address that is that far from the current
16029 // top of stack.
16030 static uint32_t* ComputeStackLimit(uint32_t size) {
16031   uint32_t* answer = &size - (size / sizeof(size));
16032   // If the size is very large and the stack is very near the bottom of
16033   // memory then the calculation above may wrap around and give an address
16034   // that is above the (downwards-growing) stack.  In that case we return
16035   // a very low address.
16036   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
16037   return answer;
16038 }
16039
16040
16041 // We need at least 165kB for an x64 debug build with clang and ASAN.
16042 static const int stack_breathing_room = 256 * i::KB;
16043
16044
16045 TEST(SetStackLimit) {
16046   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
16047
16048   // Set stack limit.
16049   CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
16050
16051   // Execute a script.
16052   LocalContext env;
16053   v8::HandleScope scope(env->GetIsolate());
16054   Local<v8::FunctionTemplate> fun_templ =
16055       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
16056   Local<Function> fun = fun_templ->GetFunction();
16057   env->Global()->Set(v8_str("get_stack_limit"), fun);
16058   CompileRun("get_stack_limit();");
16059
16060   CHECK(stack_limit == set_limit);
16061 }
16062
16063
16064 TEST(SetStackLimitInThread) {
16065   uint32_t* set_limit;
16066   {
16067     v8::Locker locker(CcTest::isolate());
16068     set_limit = ComputeStackLimit(stack_breathing_room);
16069
16070     // Set stack limit.
16071     CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
16072
16073     // Execute a script.
16074     v8::HandleScope scope(CcTest::isolate());
16075     LocalContext env;
16076     Local<v8::FunctionTemplate> fun_templ =
16077         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
16078     Local<Function> fun = fun_templ->GetFunction();
16079     env->Global()->Set(v8_str("get_stack_limit"), fun);
16080     CompileRun("get_stack_limit();");
16081
16082     CHECK(stack_limit == set_limit);
16083   }
16084   {
16085     v8::Locker locker(CcTest::isolate());
16086     CHECK(stack_limit == set_limit);
16087   }
16088 }
16089
16090
16091 THREADED_TEST(GetHeapStatistics) {
16092   LocalContext c1;
16093   v8::HandleScope scope(c1->GetIsolate());
16094   v8::HeapStatistics heap_statistics;
16095   CHECK_EQ(0u, heap_statistics.total_heap_size());
16096   CHECK_EQ(0u, heap_statistics.used_heap_size());
16097   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
16098   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
16099   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
16100 }
16101
16102
16103 class VisitorImpl : public v8::ExternalResourceVisitor {
16104  public:
16105   explicit VisitorImpl(TestResource** resource) {
16106     for (int i = 0; i < 4; i++) {
16107       resource_[i] = resource[i];
16108       found_resource_[i] = false;
16109     }
16110   }
16111   virtual ~VisitorImpl() {}
16112   virtual void VisitExternalString(v8::Handle<v8::String> string) {
16113     if (!string->IsExternal()) {
16114       CHECK(string->IsExternalOneByte());
16115       return;
16116     }
16117     v8::String::ExternalStringResource* resource =
16118         string->GetExternalStringResource();
16119     CHECK(resource);
16120     for (int i = 0; i < 4; i++) {
16121       if (resource_[i] == resource) {
16122         CHECK(!found_resource_[i]);
16123         found_resource_[i] = true;
16124       }
16125     }
16126   }
16127   void CheckVisitedResources() {
16128     for (int i = 0; i < 4; i++) {
16129       CHECK(found_resource_[i]);
16130     }
16131   }
16132
16133  private:
16134   v8::String::ExternalStringResource* resource_[4];
16135   bool found_resource_[4];
16136 };
16137
16138
16139 TEST(ExternalizeOldSpaceTwoByteCons) {
16140   v8::Isolate* isolate = CcTest::isolate();
16141   LocalContext env;
16142   v8::HandleScope scope(isolate);
16143   v8::Local<v8::String> cons =
16144       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
16145   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
16146   CcTest::heap()->CollectAllAvailableGarbage();
16147   CHECK(CcTest::heap()->old_pointer_space()->Contains(
16148       *v8::Utils::OpenHandle(*cons)));
16149
16150   TestResource* resource = new TestResource(
16151       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
16152   cons->MakeExternal(resource);
16153
16154   CHECK(cons->IsExternal());
16155   CHECK_EQ(resource, cons->GetExternalStringResource());
16156   String::Encoding encoding;
16157   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
16158   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
16159 }
16160
16161
16162 TEST(ExternalizeOldSpaceOneByteCons) {
16163   v8::Isolate* isolate = CcTest::isolate();
16164   LocalContext env;
16165   v8::HandleScope scope(isolate);
16166   v8::Local<v8::String> cons =
16167       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
16168   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
16169   CcTest::heap()->CollectAllAvailableGarbage();
16170   CHECK(CcTest::heap()->old_pointer_space()->Contains(
16171       *v8::Utils::OpenHandle(*cons)));
16172
16173   TestOneByteResource* resource =
16174       new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
16175   cons->MakeExternal(resource);
16176
16177   CHECK(cons->IsExternalOneByte());
16178   CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
16179   String::Encoding encoding;
16180   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
16181   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
16182 }
16183
16184
16185 TEST(VisitExternalStrings) {
16186   v8::Isolate* isolate = CcTest::isolate();
16187   LocalContext env;
16188   v8::HandleScope scope(isolate);
16189   const char* string = "Some string";
16190   uint16_t* two_byte_string = AsciiToTwoByteString(string);
16191   TestResource* resource[4];
16192   resource[0] = new TestResource(two_byte_string);
16193   v8::Local<v8::String> string0 =
16194       v8::String::NewExternal(env->GetIsolate(), resource[0]);
16195   resource[1] = new TestResource(two_byte_string, NULL, false);
16196   v8::Local<v8::String> string1 =
16197       v8::String::NewExternal(env->GetIsolate(), resource[1]);
16198
16199   // Externalized symbol.
16200   resource[2] = new TestResource(two_byte_string, NULL, false);
16201   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
16202       env->GetIsolate(), string, v8::String::kInternalizedString);
16203   CHECK(string2->MakeExternal(resource[2]));
16204
16205   // Symbolized External.
16206   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
16207   v8::Local<v8::String> string3 =
16208       v8::String::NewExternal(env->GetIsolate(), resource[3]);
16209   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
16210   // Turn into a symbol.
16211   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
16212   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
16213       string3_i).is_null());
16214   CHECK(string3_i->IsInternalizedString());
16215
16216   // We need to add usages for string* to avoid warnings in GCC 4.7
16217   CHECK(string0->IsExternal());
16218   CHECK(string1->IsExternal());
16219   CHECK(string2->IsExternal());
16220   CHECK(string3->IsExternal());
16221
16222   VisitorImpl visitor(resource);
16223   v8::V8::VisitExternalResources(&visitor);
16224   visitor.CheckVisitedResources();
16225 }
16226
16227
16228 TEST(ExternalStringCollectedAtTearDown) {
16229   int destroyed = 0;
16230   v8::Isolate* isolate = v8::Isolate::New();
16231   { v8::Isolate::Scope isolate_scope(isolate);
16232     v8::HandleScope handle_scope(isolate);
16233     const char* s = "One string to test them all, one string to find them.";
16234     TestOneByteResource* inscription =
16235         new TestOneByteResource(i::StrDup(s), &destroyed);
16236     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
16237     // Ring is still alive.  Orcs are roaming freely across our lands.
16238     CHECK_EQ(0, destroyed);
16239     USE(ring);
16240   }
16241
16242   isolate->Dispose();
16243   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
16244   CHECK_EQ(1, destroyed);
16245 }
16246
16247
16248 TEST(ExternalInternalizedStringCollectedAtTearDown) {
16249   int destroyed = 0;
16250   v8::Isolate* isolate = v8::Isolate::New();
16251   { v8::Isolate::Scope isolate_scope(isolate);
16252     LocalContext env(isolate);
16253     v8::HandleScope handle_scope(isolate);
16254     CompileRun("var ring = 'One string to test them all';");
16255     const char* s = "One string to test them all";
16256     TestOneByteResource* inscription =
16257         new TestOneByteResource(i::StrDup(s), &destroyed);
16258     v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
16259     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
16260     ring->MakeExternal(inscription);
16261     // Ring is still alive.  Orcs are roaming freely across our lands.
16262     CHECK_EQ(0, destroyed);
16263     USE(ring);
16264   }
16265
16266   isolate->Dispose();
16267   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
16268   CHECK_EQ(1, destroyed);
16269 }
16270
16271
16272 TEST(ExternalInternalizedStringCollectedAtGC) {
16273   // TODO(mvstanton): vector ics need weak support.
16274   if (i::FLAG_vector_ics) return;
16275
16276   int destroyed = 0;
16277   { LocalContext env;
16278     v8::HandleScope handle_scope(env->GetIsolate());
16279     CompileRun("var ring = 'One string to test them all';");
16280     const char* s = "One string to test them all";
16281     TestOneByteResource* inscription =
16282         new TestOneByteResource(i::StrDup(s), &destroyed);
16283     v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
16284     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
16285     ring->MakeExternal(inscription);
16286     // Ring is still alive.  Orcs are roaming freely across our lands.
16287     CHECK_EQ(0, destroyed);
16288     USE(ring);
16289   }
16290
16291   // Garbage collector deals swift blows to evil.
16292   CcTest::i_isolate()->compilation_cache()->Clear();
16293   CcTest::heap()->CollectAllAvailableGarbage();
16294
16295   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
16296   CHECK_EQ(1, destroyed);
16297 }
16298
16299
16300 static double DoubleFromBits(uint64_t value) {
16301   double target;
16302   i::MemCopy(&target, &value, sizeof(target));
16303   return target;
16304 }
16305
16306
16307 static uint64_t DoubleToBits(double value) {
16308   uint64_t target;
16309   i::MemCopy(&target, &value, sizeof(target));
16310   return target;
16311 }
16312
16313
16314 static double DoubleToDateTime(double input) {
16315   double date_limit = 864e13;
16316   if (std::isnan(input) || input < -date_limit || input > date_limit) {
16317     return std::numeric_limits<double>::quiet_NaN();
16318   }
16319   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
16320 }
16321
16322
16323 // We don't have a consistent way to write 64-bit constants syntactically, so we
16324 // split them into two 32-bit constants and combine them programmatically.
16325 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
16326   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
16327 }
16328
16329
16330 THREADED_TEST(QuietSignalingNaNs) {
16331   LocalContext context;
16332   v8::Isolate* isolate = context->GetIsolate();
16333   v8::HandleScope scope(isolate);
16334   v8::TryCatch try_catch;
16335
16336   // Special double values.
16337   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
16338   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
16339   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
16340   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
16341   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
16342   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
16343   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
16344
16345   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
16346   // on either side of the epoch.
16347   double date_limit = 864e13;
16348
16349   double test_values[] = {
16350       snan,
16351       qnan,
16352       infinity,
16353       max_normal,
16354       date_limit + 1,
16355       date_limit,
16356       min_normal,
16357       max_denormal,
16358       min_denormal,
16359       0,
16360       -0,
16361       -min_denormal,
16362       -max_denormal,
16363       -min_normal,
16364       -date_limit,
16365       -date_limit - 1,
16366       -max_normal,
16367       -infinity,
16368       -qnan,
16369       -snan
16370   };
16371   int num_test_values = 20;
16372
16373   for (int i = 0; i < num_test_values; i++) {
16374     double test_value = test_values[i];
16375
16376     // Check that Number::New preserves non-NaNs and quiets SNaNs.
16377     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
16378     double stored_number = number->NumberValue();
16379     if (!std::isnan(test_value)) {
16380       CHECK_EQ(test_value, stored_number);
16381     } else {
16382       uint64_t stored_bits = DoubleToBits(stored_number);
16383       // Check if quiet nan (bits 51..62 all set).
16384 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
16385     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
16386       // Most significant fraction bit for quiet nan is set to 0
16387       // on MIPS architecture. Allowed by IEEE-754.
16388       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16389 #else
16390       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16391 #endif
16392     }
16393
16394     // Check that Date::New preserves non-NaNs in the date range and
16395     // quiets SNaNs.
16396     v8::Handle<v8::Value> date =
16397         v8::Date::New(isolate, test_value);
16398     double expected_stored_date = DoubleToDateTime(test_value);
16399     double stored_date = date->NumberValue();
16400     if (!std::isnan(expected_stored_date)) {
16401       CHECK_EQ(expected_stored_date, stored_date);
16402     } else {
16403       uint64_t stored_bits = DoubleToBits(stored_date);
16404       // Check if quiet nan (bits 51..62 all set).
16405 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
16406     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
16407       // Most significant fraction bit for quiet nan is set to 0
16408       // on MIPS architecture. Allowed by IEEE-754.
16409       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16410 #else
16411       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16412 #endif
16413     }
16414   }
16415 }
16416
16417
16418 static void SpaghettiIncident(
16419     const v8::FunctionCallbackInfo<v8::Value>& args) {
16420   v8::HandleScope scope(args.GetIsolate());
16421   v8::TryCatch tc;
16422   v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
16423   USE(str);
16424   if (tc.HasCaught())
16425     tc.ReThrow();
16426 }
16427
16428
16429 // Test that an exception can be propagated down through a spaghetti
16430 // stack using ReThrow.
16431 THREADED_TEST(SpaghettiStackReThrow) {
16432   v8::Isolate* isolate = CcTest::isolate();
16433   v8::HandleScope scope(isolate);
16434   LocalContext context;
16435   context->Global()->Set(
16436       v8::String::NewFromUtf8(isolate, "s"),
16437       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
16438   v8::TryCatch try_catch;
16439   CompileRun(
16440       "var i = 0;"
16441       "var o = {"
16442       "  toString: function () {"
16443       "    if (i == 10) {"
16444       "      throw 'Hey!';"
16445       "    } else {"
16446       "      i++;"
16447       "      return s(o);"
16448       "    }"
16449       "  }"
16450       "};"
16451       "s(o);");
16452   CHECK(try_catch.HasCaught());
16453   v8::String::Utf8Value value(try_catch.Exception());
16454   CHECK_EQ(0, strcmp(*value, "Hey!"));
16455 }
16456
16457
16458 TEST(Regress528) {
16459   v8::V8::Initialize();
16460   v8::Isolate* isolate = CcTest::isolate();
16461   i::FLAG_retain_maps_for_n_gc = 0;
16462   v8::HandleScope scope(isolate);
16463   v8::Local<Context> other_context;
16464   int gc_count;
16465
16466   // Create a context used to keep the code from aging in the compilation
16467   // cache.
16468   other_context = Context::New(isolate);
16469
16470   // Context-dependent context data creates reference from the compilation
16471   // cache to the global object.
16472   const char* source_simple = "1";
16473   {
16474     v8::HandleScope scope(isolate);
16475     v8::Local<Context> context = Context::New(isolate);
16476
16477     context->Enter();
16478     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
16479     context->SetEmbedderData(0, obj);
16480     CompileRun(source_simple);
16481     context->Exit();
16482   }
16483   isolate->ContextDisposedNotification();
16484   for (gc_count = 1; gc_count < 10; gc_count++) {
16485     other_context->Enter();
16486     CompileRun(source_simple);
16487     other_context->Exit();
16488     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16489     if (GetGlobalObjectsCount() == 1) break;
16490   }
16491   CHECK_GE(2, gc_count);
16492   CHECK_EQ(1, GetGlobalObjectsCount());
16493
16494   // Eval in a function creates reference from the compilation cache to the
16495   // global object.
16496   const char* source_eval = "function f(){eval('1')}; f()";
16497   {
16498     v8::HandleScope scope(isolate);
16499     v8::Local<Context> context = Context::New(isolate);
16500
16501     context->Enter();
16502     CompileRun(source_eval);
16503     context->Exit();
16504   }
16505   isolate->ContextDisposedNotification();
16506   for (gc_count = 1; gc_count < 10; gc_count++) {
16507     other_context->Enter();
16508     CompileRun(source_eval);
16509     other_context->Exit();
16510     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16511     if (GetGlobalObjectsCount() == 1) break;
16512   }
16513   CHECK_GE(2, gc_count);
16514   CHECK_EQ(1, GetGlobalObjectsCount());
16515
16516   // Looking up the line number for an exception creates reference from the
16517   // compilation cache to the global object.
16518   const char* source_exception = "function f(){throw 1;} f()";
16519   {
16520     v8::HandleScope scope(isolate);
16521     v8::Local<Context> context = Context::New(isolate);
16522
16523     context->Enter();
16524     v8::TryCatch try_catch;
16525     CompileRun(source_exception);
16526     CHECK(try_catch.HasCaught());
16527     v8::Handle<v8::Message> message = try_catch.Message();
16528     CHECK(!message.IsEmpty());
16529     CHECK_EQ(1, message->GetLineNumber());
16530     context->Exit();
16531   }
16532   isolate->ContextDisposedNotification();
16533   for (gc_count = 1; gc_count < 10; gc_count++) {
16534     other_context->Enter();
16535     CompileRun(source_exception);
16536     other_context->Exit();
16537     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16538     if (GetGlobalObjectsCount() == 1) break;
16539   }
16540   CHECK_GE(2, gc_count);
16541   CHECK_EQ(1, GetGlobalObjectsCount());
16542
16543   isolate->ContextDisposedNotification();
16544 }
16545
16546
16547 THREADED_TEST(ScriptOrigin) {
16548   LocalContext env;
16549   v8::HandleScope scope(env->GetIsolate());
16550   v8::ScriptOrigin origin = v8::ScriptOrigin(
16551       v8::String::NewFromUtf8(env->GetIsolate(), "test"),
16552       v8::Integer::New(env->GetIsolate(), 1),
16553       v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
16554       v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
16555       v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"));
16556   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16557       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16558   v8::Script::Compile(script, &origin)->Run();
16559   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16560       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16561   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16562       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16563
16564   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
16565   CHECK_EQ(0, strcmp("test",
16566                      *v8::String::Utf8Value(script_origin_f.ResourceName())));
16567   CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
16568   CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value());
16569   CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value());
16570   printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
16571
16572   CHECK_EQ(0, strcmp("http://sourceMapUrl",
16573                      *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
16574
16575   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
16576   CHECK_EQ(0, strcmp("test",
16577                      *v8::String::Utf8Value(script_origin_g.ResourceName())));
16578   CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
16579   CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value());
16580   CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value());
16581   CHECK_EQ(0, strcmp("http://sourceMapUrl",
16582                      *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
16583 }
16584
16585
16586 THREADED_TEST(FunctionGetInferredName) {
16587   LocalContext env;
16588   v8::HandleScope scope(env->GetIsolate());
16589   v8::ScriptOrigin origin =
16590       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16591   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16592       env->GetIsolate(),
16593       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
16594   v8::Script::Compile(script, &origin)->Run();
16595   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16596       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16597   CHECK_EQ(0,
16598            strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
16599 }
16600
16601
16602 THREADED_TEST(FunctionGetDisplayName) {
16603   LocalContext env;
16604   v8::HandleScope scope(env->GetIsolate());
16605   const char* code = "var error = false;"
16606                      "function a() { this.x = 1; };"
16607                      "a.displayName = 'display_a';"
16608                      "var b = (function() {"
16609                      "  var f = function() { this.x = 2; };"
16610                      "  f.displayName = 'display_b';"
16611                      "  return f;"
16612                      "})();"
16613                      "var c = function() {};"
16614                      "c.__defineGetter__('displayName', function() {"
16615                      "  error = true;"
16616                      "  throw new Error();"
16617                      "});"
16618                      "function d() {};"
16619                      "d.__defineGetter__('displayName', function() {"
16620                      "  error = true;"
16621                      "  return 'wrong_display_name';"
16622                      "});"
16623                      "function e() {};"
16624                      "e.displayName = 'wrong_display_name';"
16625                      "e.__defineSetter__('displayName', function() {"
16626                      "  error = true;"
16627                      "  throw new Error();"
16628                      "});"
16629                      "function f() {};"
16630                      "f.displayName = { 'foo': 6, toString: function() {"
16631                      "  error = true;"
16632                      "  return 'wrong_display_name';"
16633                      "}};"
16634                      "var g = function() {"
16635                      "  arguments.callee.displayName = 'set_in_runtime';"
16636                      "}; g();"
16637                      ;
16638   v8::ScriptOrigin origin =
16639       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16640   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
16641       ->Run();
16642   v8::Local<v8::Value> error =
16643       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
16644   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
16645       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
16646   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
16647       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
16648   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
16649       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
16650   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
16651       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
16652   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
16653       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
16654   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16655       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16656   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16657       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16658   CHECK_EQ(false, error->BooleanValue());
16659   CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
16660   CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
16661   CHECK(c->GetDisplayName()->IsUndefined());
16662   CHECK(d->GetDisplayName()->IsUndefined());
16663   CHECK(e->GetDisplayName()->IsUndefined());
16664   CHECK(f->GetDisplayName()->IsUndefined());
16665   CHECK_EQ(
16666       0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
16667 }
16668
16669
16670 THREADED_TEST(ScriptLineNumber) {
16671   LocalContext env;
16672   v8::HandleScope scope(env->GetIsolate());
16673   v8::ScriptOrigin origin =
16674       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16675   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16676       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16677   v8::Script::Compile(script, &origin)->Run();
16678   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16679       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16680   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16681       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16682   CHECK_EQ(0, f->GetScriptLineNumber());
16683   CHECK_EQ(2, g->GetScriptLineNumber());
16684 }
16685
16686
16687 THREADED_TEST(ScriptColumnNumber) {
16688   LocalContext env;
16689   v8::Isolate* isolate = env->GetIsolate();
16690   v8::HandleScope scope(isolate);
16691   v8::ScriptOrigin origin =
16692       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16693                        v8::Integer::New(isolate, 3),
16694                        v8::Integer::New(isolate, 2));
16695   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16696       isolate, "function foo() {}\n\n     function bar() {}");
16697   v8::Script::Compile(script, &origin)->Run();
16698   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16699       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16700   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16701       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16702   CHECK_EQ(14, foo->GetScriptColumnNumber());
16703   CHECK_EQ(17, bar->GetScriptColumnNumber());
16704 }
16705
16706
16707 THREADED_TEST(FunctionIsBuiltin) {
16708   LocalContext env;
16709   v8::Isolate* isolate = env->GetIsolate();
16710   v8::HandleScope scope(isolate);
16711   v8::Local<v8::Function> f;
16712   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
16713   CHECK(f->IsBuiltin());
16714   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
16715   CHECK(f->IsBuiltin());
16716   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
16717   CHECK(f->IsBuiltin());
16718   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
16719   CHECK(f->IsBuiltin());
16720   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
16721   CHECK(!f->IsBuiltin());
16722 }
16723
16724
16725 THREADED_TEST(FunctionGetScriptId) {
16726   LocalContext env;
16727   v8::Isolate* isolate = env->GetIsolate();
16728   v8::HandleScope scope(isolate);
16729   v8::ScriptOrigin origin =
16730       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16731                        v8::Integer::New(isolate, 3),
16732                        v8::Integer::New(isolate, 2));
16733   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
16734       isolate, "function foo() {}\n\n     function bar() {}");
16735   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16736   script->Run();
16737   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16738       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16739   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16740       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16741   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
16742   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
16743 }
16744
16745
16746 THREADED_TEST(FunctionGetBoundFunction) {
16747   LocalContext env;
16748   v8::HandleScope scope(env->GetIsolate());
16749   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
16750       env->GetIsolate(), "test"));
16751   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16752       env->GetIsolate(),
16753       "var a = new Object();\n"
16754       "a.x = 1;\n"
16755       "function f () { return this.x };\n"
16756       "var g = f.bind(a);\n"
16757       "var b = g();");
16758   v8::Script::Compile(script, &origin)->Run();
16759   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16760       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16761   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16762       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16763   CHECK(g->GetBoundFunction()->IsFunction());
16764   Local<v8::Function> original_function = Local<v8::Function>::Cast(
16765       g->GetBoundFunction());
16766   CHECK(f->GetName()->Equals(original_function->GetName()));
16767   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
16768   CHECK_EQ(f->GetScriptColumnNumber(),
16769            original_function->GetScriptColumnNumber());
16770 }
16771
16772
16773 static void GetterWhichReturns42(
16774     Local<String> name,
16775     const v8::PropertyCallbackInfo<v8::Value>& info) {
16776   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16777   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16778   info.GetReturnValue().Set(v8_num(42));
16779 }
16780
16781
16782 static void SetterWhichSetsYOnThisTo23(
16783     Local<String> name,
16784     Local<Value> value,
16785     const v8::PropertyCallbackInfo<void>& info) {
16786   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16787   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16788   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16789 }
16790
16791
16792 void FooGetInterceptor(Local<Name> name,
16793                        const v8::PropertyCallbackInfo<v8::Value>& info) {
16794   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16795   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16796   if (!name->Equals(v8_str("foo"))) return;
16797   info.GetReturnValue().Set(v8_num(42));
16798 }
16799
16800
16801 void FooSetInterceptor(Local<Name> name, Local<Value> value,
16802                        const v8::PropertyCallbackInfo<v8::Value>& info) {
16803   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16804   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16805   if (!name->Equals(v8_str("foo"))) return;
16806   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16807   info.GetReturnValue().Set(v8_num(23));
16808 }
16809
16810
16811 TEST(SetterOnConstructorPrototype) {
16812   v8::Isolate* isolate = CcTest::isolate();
16813   v8::HandleScope scope(isolate);
16814   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16815   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16816                      SetterWhichSetsYOnThisTo23);
16817   LocalContext context;
16818   context->Global()->Set(v8_str("P"), templ->NewInstance());
16819   CompileRun("function C1() {"
16820              "  this.x = 23;"
16821              "};"
16822              "C1.prototype = P;"
16823              "function C2() {"
16824              "  this.x = 23"
16825              "};"
16826              "C2.prototype = { };"
16827              "C2.prototype.__proto__ = P;");
16828
16829   v8::Local<v8::Script> script;
16830   script = v8_compile("new C1();");
16831   for (int i = 0; i < 10; i++) {
16832     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16833     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16834     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16835   }
16836
16837 script = v8_compile("new C2();");
16838   for (int i = 0; i < 10; i++) {
16839     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16840     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
16841     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
16842   }
16843 }
16844
16845
16846 static void NamedPropertyGetterWhichReturns42(
16847     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16848   info.GetReturnValue().Set(v8_num(42));
16849 }
16850
16851
16852 static void NamedPropertySetterWhichSetsYOnThisTo23(
16853     Local<Name> name, Local<Value> value,
16854     const v8::PropertyCallbackInfo<v8::Value>& info) {
16855   if (name->Equals(v8_str("x"))) {
16856     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16857   }
16858 }
16859
16860
16861 THREADED_TEST(InterceptorOnConstructorPrototype) {
16862   v8::Isolate* isolate = CcTest::isolate();
16863   v8::HandleScope scope(isolate);
16864   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16865   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16866       NamedPropertyGetterWhichReturns42,
16867       NamedPropertySetterWhichSetsYOnThisTo23));
16868   LocalContext context;
16869   context->Global()->Set(v8_str("P"), templ->NewInstance());
16870   CompileRun("function C1() {"
16871              "  this.x = 23;"
16872              "};"
16873              "C1.prototype = P;"
16874              "function C2() {"
16875              "  this.x = 23"
16876              "};"
16877              "C2.prototype = { };"
16878              "C2.prototype.__proto__ = P;");
16879
16880   v8::Local<v8::Script> script;
16881   script = v8_compile("new C1();");
16882   for (int i = 0; i < 10; i++) {
16883     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16884     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16885     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16886   }
16887
16888   script = v8_compile("new C2();");
16889   for (int i = 0; i < 10; i++) {
16890     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16891     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
16892     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
16893   }
16894 }
16895
16896
16897 TEST(Regress618) {
16898   const char* source = "function C1() {"
16899                        "  this.x = 23;"
16900                        "};"
16901                        "C1.prototype = P;";
16902
16903   LocalContext context;
16904   v8::Isolate* isolate = context->GetIsolate();
16905   v8::HandleScope scope(isolate);
16906   v8::Local<v8::Script> script;
16907
16908   // Use a simple object as prototype.
16909   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
16910   prototype->Set(v8_str("y"), v8_num(42));
16911   context->Global()->Set(v8_str("P"), prototype);
16912
16913   // This compile will add the code to the compilation cache.
16914   CompileRun(source);
16915
16916   script = v8_compile("new C1();");
16917   // Allow enough iterations for the inobject slack tracking logic
16918   // to finalize instance size and install the fast construct stub.
16919   for (int i = 0; i < 256; i++) {
16920     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16921     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16922     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16923   }
16924
16925   // Use an API object with accessors as prototype.
16926   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16927   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16928                      SetterWhichSetsYOnThisTo23);
16929   context->Global()->Set(v8_str("P"), templ->NewInstance());
16930
16931   // This compile will get the code from the compilation cache.
16932   CompileRun(source);
16933
16934   script = v8_compile("new C1();");
16935   for (int i = 0; i < 10; i++) {
16936     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16937     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16938     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16939   }
16940 }
16941
16942 v8::Isolate* gc_callbacks_isolate = NULL;
16943 int prologue_call_count = 0;
16944 int epilogue_call_count = 0;
16945 int prologue_call_count_second = 0;
16946 int epilogue_call_count_second = 0;
16947 int prologue_call_count_alloc = 0;
16948 int epilogue_call_count_alloc = 0;
16949
16950 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16951   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16952   ++prologue_call_count;
16953 }
16954
16955
16956 void PrologueCallback(v8::Isolate* isolate,
16957                       v8::GCType,
16958                       v8::GCCallbackFlags flags) {
16959   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16960   CHECK_EQ(gc_callbacks_isolate, isolate);
16961   ++prologue_call_count;
16962 }
16963
16964
16965 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16966   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16967   ++epilogue_call_count;
16968 }
16969
16970
16971 void EpilogueCallback(v8::Isolate* isolate,
16972                       v8::GCType,
16973                       v8::GCCallbackFlags flags) {
16974   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16975   CHECK_EQ(gc_callbacks_isolate, isolate);
16976   ++epilogue_call_count;
16977 }
16978
16979
16980 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16981   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16982   ++prologue_call_count_second;
16983 }
16984
16985
16986 void PrologueCallbackSecond(v8::Isolate* isolate,
16987                             v8::GCType,
16988                             v8::GCCallbackFlags flags) {
16989   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16990   CHECK_EQ(gc_callbacks_isolate, isolate);
16991   ++prologue_call_count_second;
16992 }
16993
16994
16995 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16996   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16997   ++epilogue_call_count_second;
16998 }
16999
17000
17001 void EpilogueCallbackSecond(v8::Isolate* isolate,
17002                             v8::GCType,
17003                             v8::GCCallbackFlags flags) {
17004   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17005   CHECK_EQ(gc_callbacks_isolate, isolate);
17006   ++epilogue_call_count_second;
17007 }
17008
17009
17010 void PrologueCallbackAlloc(v8::Isolate* isolate,
17011                            v8::GCType,
17012                            v8::GCCallbackFlags flags) {
17013   v8::HandleScope scope(isolate);
17014
17015   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17016   CHECK_EQ(gc_callbacks_isolate, isolate);
17017   ++prologue_call_count_alloc;
17018
17019   // Simulate full heap to see if we will reenter this callback
17020   SimulateFullSpace(CcTest::heap()->new_space());
17021
17022   Local<Object> obj = Object::New(isolate);
17023   CHECK(!obj.IsEmpty());
17024
17025   CcTest::heap()->CollectAllGarbage(
17026       i::Heap::kAbortIncrementalMarkingMask);
17027 }
17028
17029
17030 void EpilogueCallbackAlloc(v8::Isolate* isolate,
17031                            v8::GCType,
17032                            v8::GCCallbackFlags flags) {
17033   v8::HandleScope scope(isolate);
17034
17035   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17036   CHECK_EQ(gc_callbacks_isolate, isolate);
17037   ++epilogue_call_count_alloc;
17038
17039   // Simulate full heap to see if we will reenter this callback
17040   SimulateFullSpace(CcTest::heap()->new_space());
17041
17042   Local<Object> obj = Object::New(isolate);
17043   CHECK(!obj.IsEmpty());
17044
17045   CcTest::heap()->CollectAllGarbage(
17046       i::Heap::kAbortIncrementalMarkingMask);
17047 }
17048
17049
17050 TEST(GCCallbacksOld) {
17051   LocalContext context;
17052
17053   v8::V8::AddGCPrologueCallback(PrologueCallback);
17054   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17055   CHECK_EQ(0, prologue_call_count);
17056   CHECK_EQ(0, epilogue_call_count);
17057   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17058   CHECK_EQ(1, prologue_call_count);
17059   CHECK_EQ(1, epilogue_call_count);
17060   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17061   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17062   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17063   CHECK_EQ(2, prologue_call_count);
17064   CHECK_EQ(2, epilogue_call_count);
17065   CHECK_EQ(1, prologue_call_count_second);
17066   CHECK_EQ(1, epilogue_call_count_second);
17067   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17068   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17069   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17070   CHECK_EQ(2, prologue_call_count);
17071   CHECK_EQ(2, epilogue_call_count);
17072   CHECK_EQ(2, prologue_call_count_second);
17073   CHECK_EQ(2, epilogue_call_count_second);
17074   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17075   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17076   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17077   CHECK_EQ(2, prologue_call_count);
17078   CHECK_EQ(2, epilogue_call_count);
17079   CHECK_EQ(2, prologue_call_count_second);
17080   CHECK_EQ(2, epilogue_call_count_second);
17081 }
17082
17083
17084 TEST(GCCallbacks) {
17085   LocalContext context;
17086   v8::Isolate* isolate = context->GetIsolate();
17087   gc_callbacks_isolate = isolate;
17088   isolate->AddGCPrologueCallback(PrologueCallback);
17089   isolate->AddGCEpilogueCallback(EpilogueCallback);
17090   CHECK_EQ(0, prologue_call_count);
17091   CHECK_EQ(0, epilogue_call_count);
17092   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17093   CHECK_EQ(1, prologue_call_count);
17094   CHECK_EQ(1, epilogue_call_count);
17095   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
17096   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
17097   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17098   CHECK_EQ(2, prologue_call_count);
17099   CHECK_EQ(2, epilogue_call_count);
17100   CHECK_EQ(1, prologue_call_count_second);
17101   CHECK_EQ(1, epilogue_call_count_second);
17102   isolate->RemoveGCPrologueCallback(PrologueCallback);
17103   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
17104   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17105   CHECK_EQ(2, prologue_call_count);
17106   CHECK_EQ(2, epilogue_call_count);
17107   CHECK_EQ(2, prologue_call_count_second);
17108   CHECK_EQ(2, epilogue_call_count_second);
17109   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
17110   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17111   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17112   CHECK_EQ(2, prologue_call_count);
17113   CHECK_EQ(2, epilogue_call_count);
17114   CHECK_EQ(2, prologue_call_count_second);
17115   CHECK_EQ(2, epilogue_call_count_second);
17116
17117   CHECK_EQ(0, prologue_call_count_alloc);
17118   CHECK_EQ(0, epilogue_call_count_alloc);
17119   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
17120   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
17121   CcTest::heap()->CollectAllGarbage(
17122       i::Heap::kAbortIncrementalMarkingMask);
17123   CHECK_EQ(1, prologue_call_count_alloc);
17124   CHECK_EQ(1, epilogue_call_count_alloc);
17125   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
17126   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
17127 }
17128
17129
17130 THREADED_TEST(AddToJSFunctionResultCache) {
17131   i::FLAG_stress_compaction = false;
17132   i::FLAG_allow_natives_syntax = true;
17133   v8::HandleScope scope(CcTest::isolate());
17134
17135   LocalContext context;
17136
17137   const char* code =
17138       "(function() {"
17139       "  var key0 = 'a';"
17140       "  var key1 = 'b';"
17141       "  var r0 = %_GetFromCache(0, key0);"
17142       "  var r1 = %_GetFromCache(0, key1);"
17143       "  var r0_ = %_GetFromCache(0, key0);"
17144       "  if (r0 !== r0_)"
17145       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17146       "  var r1_ = %_GetFromCache(0, key1);"
17147       "  if (r1 !== r1_)"
17148       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17149       "  return 'PASSED';"
17150       "})()";
17151   CcTest::heap()->ClearJSFunctionResultCaches();
17152   ExpectString(code, "PASSED");
17153 }
17154
17155
17156 THREADED_TEST(FillJSFunctionResultCache) {
17157   i::FLAG_allow_natives_syntax = true;
17158   LocalContext context;
17159   v8::HandleScope scope(context->GetIsolate());
17160
17161   const char* code =
17162       "(function() {"
17163       "  var k = 'a';"
17164       "  var r = %_GetFromCache(0, k);"
17165       "  for (var i = 0; i < 16; i++) {"
17166       "    %_GetFromCache(0, 'a' + i);"
17167       "  };"
17168       "  if (r === %_GetFromCache(0, k))"
17169       "    return 'FAILED: k0CacheSize is too small';"
17170       "  return 'PASSED';"
17171       "})()";
17172   CcTest::heap()->ClearJSFunctionResultCaches();
17173   ExpectString(code, "PASSED");
17174 }
17175
17176
17177 THREADED_TEST(RoundRobinGetFromCache) {
17178   i::FLAG_allow_natives_syntax = true;
17179   LocalContext context;
17180   v8::HandleScope scope(context->GetIsolate());
17181
17182   const char* code =
17183       "(function() {"
17184       "  var keys = [];"
17185       "  for (var i = 0; i < 16; i++) keys.push(i);"
17186       "  var values = [];"
17187       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17188       "  for (var i = 0; i < 16; i++) {"
17189       "    var v = %_GetFromCache(0, keys[i]);"
17190       "    if (v.toString() !== values[i].toString())"
17191       "      return 'Wrong value for ' + "
17192       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
17193       "  };"
17194       "  return 'PASSED';"
17195       "})()";
17196   CcTest::heap()->ClearJSFunctionResultCaches();
17197   ExpectString(code, "PASSED");
17198 }
17199
17200
17201 THREADED_TEST(ReverseGetFromCache) {
17202   i::FLAG_allow_natives_syntax = true;
17203   LocalContext context;
17204   v8::HandleScope scope(context->GetIsolate());
17205
17206   const char* code =
17207       "(function() {"
17208       "  var keys = [];"
17209       "  for (var i = 0; i < 16; i++) keys.push(i);"
17210       "  var values = [];"
17211       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17212       "  for (var i = 15; i >= 16; i--) {"
17213       "    var v = %_GetFromCache(0, keys[i]);"
17214       "    if (v !== values[i])"
17215       "      return 'Wrong value for ' + "
17216       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
17217       "  };"
17218       "  return 'PASSED';"
17219       "})()";
17220   CcTest::heap()->ClearJSFunctionResultCaches();
17221   ExpectString(code, "PASSED");
17222 }
17223
17224
17225 THREADED_TEST(TestEviction) {
17226   i::FLAG_allow_natives_syntax = true;
17227   LocalContext context;
17228   v8::HandleScope scope(context->GetIsolate());
17229
17230   const char* code =
17231       "(function() {"
17232       "  for (var i = 0; i < 2*16; i++) {"
17233       "    %_GetFromCache(0, 'a' + i);"
17234       "  };"
17235       "  return 'PASSED';"
17236       "})()";
17237   CcTest::heap()->ClearJSFunctionResultCaches();
17238   ExpectString(code, "PASSED");
17239 }
17240
17241
17242 THREADED_TEST(TwoByteStringInOneByteCons) {
17243   // See Chromium issue 47824.
17244   LocalContext context;
17245   v8::HandleScope scope(context->GetIsolate());
17246
17247   const char* init_code =
17248       "var str1 = 'abelspendabel';"
17249       "var str2 = str1 + str1 + str1;"
17250       "str2;";
17251   Local<Value> result = CompileRun(init_code);
17252
17253   Local<Value> indexof = CompileRun("str2.indexOf('els')");
17254   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
17255
17256   CHECK(result->IsString());
17257   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
17258   int length = string->length();
17259   CHECK(string->IsOneByteRepresentation());
17260
17261   i::Handle<i::String> flat_string = i::String::Flatten(string);
17262
17263   CHECK(string->IsOneByteRepresentation());
17264   CHECK(flat_string->IsOneByteRepresentation());
17265
17266   // Create external resource.
17267   uint16_t* uc16_buffer = new uint16_t[length + 1];
17268
17269   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
17270   uc16_buffer[length] = 0;
17271
17272   TestResource resource(uc16_buffer);
17273
17274   flat_string->MakeExternal(&resource);
17275
17276   CHECK(flat_string->IsTwoByteRepresentation());
17277
17278   // If the cons string has been short-circuited, skip the following checks.
17279   if (!string.is_identical_to(flat_string)) {
17280     // At this point, we should have a Cons string which is flat and one-byte,
17281     // with a first half that is a two-byte string (although it only contains
17282     // one-byte characters). This is a valid sequence of steps, and it can
17283     // happen in real pages.
17284     CHECK(string->IsOneByteRepresentation());
17285     i::ConsString* cons = i::ConsString::cast(*string);
17286     CHECK_EQ(0, cons->second()->length());
17287     CHECK(cons->first()->IsTwoByteRepresentation());
17288   }
17289
17290   // Check that some string operations work.
17291
17292   // Atom RegExp.
17293   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
17294   CHECK_EQ(6, reresult->Int32Value());
17295
17296   // Nonatom RegExp.
17297   reresult = CompileRun("str2.match(/abe./g).length;");
17298   CHECK_EQ(6, reresult->Int32Value());
17299
17300   reresult = CompileRun("str2.search(/bel/g);");
17301   CHECK_EQ(1, reresult->Int32Value());
17302
17303   reresult = CompileRun("str2.search(/be./g);");
17304   CHECK_EQ(1, reresult->Int32Value());
17305
17306   ExpectTrue("/bel/g.test(str2);");
17307
17308   ExpectTrue("/be./g.test(str2);");
17309
17310   reresult = CompileRun("/bel/g.exec(str2);");
17311   CHECK(!reresult->IsNull());
17312
17313   reresult = CompileRun("/be./g.exec(str2);");
17314   CHECK(!reresult->IsNull());
17315
17316   ExpectString("str2.substring(2, 10);", "elspenda");
17317
17318   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
17319
17320   ExpectString("str2.charAt(2);", "e");
17321
17322   ExpectObject("str2.indexOf('els');", indexof);
17323
17324   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
17325
17326   reresult = CompileRun("str2.charCodeAt(2);");
17327   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
17328 }
17329
17330
17331 TEST(ContainsOnlyOneByte) {
17332   v8::V8::Initialize();
17333   v8::Isolate* isolate = CcTest::isolate();
17334   v8::HandleScope scope(isolate);
17335   // Make a buffer long enough that it won't automatically be converted.
17336   const int length = 512;
17337   // Ensure word aligned assignment.
17338   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
17339   i::SmartArrayPointer<uintptr_t>
17340   aligned_contents(new uintptr_t[aligned_length]);
17341   uint16_t* string_contents =
17342       reinterpret_cast<uint16_t*>(aligned_contents.get());
17343   // Set to contain only one byte.
17344   for (int i = 0; i < length-1; i++) {
17345     string_contents[i] = 0x41;
17346   }
17347   string_contents[length-1] = 0;
17348   // Simple case.
17349   Handle<String> string =
17350       String::NewExternal(isolate,
17351                           new TestResource(string_contents, NULL, false));
17352   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17353   // Counter example.
17354   string = String::NewFromTwoByte(isolate, string_contents);
17355   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17356   // Test left right and balanced cons strings.
17357   Handle<String> base = String::NewFromUtf8(isolate, "a");
17358   Handle<String> left = base;
17359   Handle<String> right = base;
17360   for (int i = 0; i < 1000; i++) {
17361     left = String::Concat(base, left);
17362     right = String::Concat(right, base);
17363   }
17364   Handle<String> balanced = String::Concat(left, base);
17365   balanced = String::Concat(balanced, right);
17366   Handle<String> cons_strings[] = {left, balanced, right};
17367   Handle<String> two_byte =
17368       String::NewExternal(isolate,
17369                           new TestResource(string_contents, NULL, false));
17370   USE(two_byte); USE(cons_strings);
17371   for (size_t i = 0; i < arraysize(cons_strings); i++) {
17372     // Base assumptions.
17373     string = cons_strings[i];
17374     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17375     // Test left and right concatentation.
17376     string = String::Concat(two_byte, cons_strings[i]);
17377     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17378     string = String::Concat(cons_strings[i], two_byte);
17379     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17380   }
17381   // Set bits in different positions
17382   // for strings of different lengths and alignments.
17383   for (int alignment = 0; alignment < 7; alignment++) {
17384     for (int size = 2; alignment + size < length; size *= 2) {
17385       int zero_offset = size + alignment;
17386       string_contents[zero_offset] = 0;
17387       for (int i = 0; i < size; i++) {
17388         int shift = 8 + (i % 7);
17389         string_contents[alignment + i] = 1 << shift;
17390         string = String::NewExternal(
17391             isolate,
17392             new TestResource(string_contents + alignment, NULL, false));
17393         CHECK_EQ(size, string->Length());
17394         CHECK(!string->ContainsOnlyOneByte());
17395         string_contents[alignment + i] = 0x41;
17396       }
17397       string_contents[zero_offset] = 0x41;
17398     }
17399   }
17400 }
17401
17402
17403 // Failed access check callback that performs a GC on each invocation.
17404 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
17405                                  v8::AccessType type,
17406                                  Local<v8::Value> data) {
17407   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17408 }
17409
17410
17411 TEST(GCInFailedAccessCheckCallback) {
17412   // Install a failed access check callback that performs a GC on each
17413   // invocation. Then force the callback to be called from va
17414
17415   v8::V8::Initialize();
17416   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
17417
17418   v8::Isolate* isolate = CcTest::isolate();
17419   v8::HandleScope scope(isolate);
17420
17421   // Create an ObjectTemplate for global objects and install access
17422   // check callbacks that will block access.
17423   v8::Handle<v8::ObjectTemplate> global_template =
17424       v8::ObjectTemplate::New(isolate);
17425   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
17426                                            v8::Handle<v8::Value>(), false);
17427
17428   // Create a context and set an x property on it's global object.
17429   LocalContext context0(NULL, global_template);
17430   context0->Global()->Set(v8_str("x"), v8_num(42));
17431   v8::Handle<v8::Object> global0 = context0->Global();
17432
17433   // Create a context with a different security token so that the
17434   // failed access check callback will be called on each access.
17435   LocalContext context1(NULL, global_template);
17436   context1->Global()->Set(v8_str("other"), global0);
17437
17438   // Get property with failed access check.
17439   ExpectUndefined("other.x");
17440
17441   // Get element with failed access check.
17442   ExpectUndefined("other[0]");
17443
17444   // Set property with failed access check.
17445   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
17446   CHECK(result->IsObject());
17447
17448   // Set element with failed access check.
17449   result = CompileRun("other[0] = new Object()");
17450   CHECK(result->IsObject());
17451
17452   // Get property attribute with failed access check.
17453   ExpectFalse("\'x\' in other");
17454
17455   // Get property attribute for element with failed access check.
17456   ExpectFalse("0 in other");
17457
17458   // Delete property.
17459   ExpectFalse("delete other.x");
17460
17461   // Delete element.
17462   CHECK_EQ(false, global0->Delete(0));
17463
17464   // DefineAccessor.
17465   CHECK_EQ(false,
17466            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
17467
17468   // Define JavaScript accessor.
17469   ExpectUndefined("Object.prototype.__defineGetter__.call("
17470                   "    other, \'x\', function() { return 42; })");
17471
17472   // LookupAccessor.
17473   ExpectUndefined("Object.prototype.__lookupGetter__.call("
17474                   "    other, \'x\')");
17475
17476   // HasOwnElement.
17477   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
17478
17479   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
17480   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
17481   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
17482
17483   // Reset the failed access check callback so it does not influence
17484   // the other tests.
17485   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
17486 }
17487
17488
17489 TEST(IsolateNewDispose) {
17490   v8::Isolate* current_isolate = CcTest::isolate();
17491   v8::Isolate* isolate = v8::Isolate::New();
17492   CHECK(isolate != NULL);
17493   CHECK(current_isolate != isolate);
17494   CHECK(current_isolate == CcTest::isolate());
17495
17496   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17497   last_location = last_message = NULL;
17498   isolate->Dispose();
17499   CHECK(!last_location);
17500   CHECK(!last_message);
17501 }
17502
17503
17504 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
17505   v8::Isolate* isolate = v8::Isolate::New();
17506   {
17507     v8::Isolate::Scope i_scope(isolate);
17508     v8::HandleScope scope(isolate);
17509     LocalContext context(isolate);
17510     // Run something in this isolate.
17511     ExpectTrue("true");
17512     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17513     last_location = last_message = NULL;
17514     // Still entered, should fail.
17515     isolate->Dispose();
17516     CHECK(last_location);
17517     CHECK(last_message);
17518   }
17519   isolate->Dispose();
17520 }
17521
17522
17523 TEST(RunTwoIsolatesOnSingleThread) {
17524   // Run isolate 1.
17525   v8::Isolate* isolate1 = v8::Isolate::New();
17526   isolate1->Enter();
17527   v8::Persistent<v8::Context> context1;
17528   {
17529     v8::HandleScope scope(isolate1);
17530     context1.Reset(isolate1, Context::New(isolate1));
17531   }
17532
17533   {
17534     v8::HandleScope scope(isolate1);
17535     v8::Local<v8::Context> context =
17536         v8::Local<v8::Context>::New(isolate1, context1);
17537     v8::Context::Scope context_scope(context);
17538     // Run something in new isolate.
17539     CompileRun("var foo = 'isolate 1';");
17540     ExpectString("function f() { return foo; }; f()", "isolate 1");
17541   }
17542
17543   // Run isolate 2.
17544   v8::Isolate* isolate2 = v8::Isolate::New();
17545   v8::Persistent<v8::Context> context2;
17546
17547   {
17548     v8::Isolate::Scope iscope(isolate2);
17549     v8::HandleScope scope(isolate2);
17550     context2.Reset(isolate2, Context::New(isolate2));
17551     v8::Local<v8::Context> context =
17552         v8::Local<v8::Context>::New(isolate2, context2);
17553     v8::Context::Scope context_scope(context);
17554
17555     // Run something in new isolate.
17556     CompileRun("var foo = 'isolate 2';");
17557     ExpectString("function f() { return foo; }; f()", "isolate 2");
17558   }
17559
17560   {
17561     v8::HandleScope scope(isolate1);
17562     v8::Local<v8::Context> context =
17563         v8::Local<v8::Context>::New(isolate1, context1);
17564     v8::Context::Scope context_scope(context);
17565     // Now again in isolate 1
17566     ExpectString("function f() { return foo; }; f()", "isolate 1");
17567   }
17568
17569   isolate1->Exit();
17570
17571   // Run some stuff in default isolate.
17572   v8::Persistent<v8::Context> context_default;
17573   {
17574     v8::Isolate* isolate = CcTest::isolate();
17575     v8::Isolate::Scope iscope(isolate);
17576     v8::HandleScope scope(isolate);
17577     context_default.Reset(isolate, Context::New(isolate));
17578   }
17579
17580   {
17581     v8::HandleScope scope(CcTest::isolate());
17582     v8::Local<v8::Context> context =
17583         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17584     v8::Context::Scope context_scope(context);
17585     // Variables in other isolates should be not available, verify there
17586     // is an exception.
17587     ExpectTrue("function f() {"
17588                "  try {"
17589                "    foo;"
17590                "    return false;"
17591                "  } catch(e) {"
17592                "    return true;"
17593                "  }"
17594                "};"
17595                "var isDefaultIsolate = true;"
17596                "f()");
17597   }
17598
17599   isolate1->Enter();
17600
17601   {
17602     v8::Isolate::Scope iscope(isolate2);
17603     v8::HandleScope scope(isolate2);
17604     v8::Local<v8::Context> context =
17605         v8::Local<v8::Context>::New(isolate2, context2);
17606     v8::Context::Scope context_scope(context);
17607     ExpectString("function f() { return foo; }; f()", "isolate 2");
17608   }
17609
17610   {
17611     v8::HandleScope scope(v8::Isolate::GetCurrent());
17612     v8::Local<v8::Context> context =
17613         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17614     v8::Context::Scope context_scope(context);
17615     ExpectString("function f() { return foo; }; f()", "isolate 1");
17616   }
17617
17618   {
17619     v8::Isolate::Scope iscope(isolate2);
17620     context2.Reset();
17621   }
17622
17623   context1.Reset();
17624   isolate1->Exit();
17625
17626   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17627   last_location = last_message = NULL;
17628
17629   isolate1->Dispose();
17630   CHECK(!last_location);
17631   CHECK(!last_message);
17632
17633   isolate2->Dispose();
17634   CHECK(!last_location);
17635   CHECK(!last_message);
17636
17637   // Check that default isolate still runs.
17638   {
17639     v8::HandleScope scope(CcTest::isolate());
17640     v8::Local<v8::Context> context =
17641         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17642     v8::Context::Scope context_scope(context);
17643     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17644   }
17645 }
17646
17647
17648 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17649   v8::Isolate::Scope isolate_scope(isolate);
17650   v8::HandleScope scope(isolate);
17651   LocalContext context(isolate);
17652   i::ScopedVector<char> code(1024);
17653   i::SNPrintF(code, "function fib(n) {"
17654                     "  if (n <= 2) return 1;"
17655                     "  return fib(n-1) + fib(n-2);"
17656                     "}"
17657                     "fib(%d)", limit);
17658   Local<Value> value = CompileRun(code.start());
17659   CHECK(value->IsNumber());
17660   return static_cast<int>(value->NumberValue());
17661 }
17662
17663 class IsolateThread : public v8::base::Thread {
17664  public:
17665   explicit IsolateThread(int fib_limit)
17666       : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
17667
17668   void Run() {
17669     v8::Isolate* isolate = v8::Isolate::New();
17670     result_ = CalcFibonacci(isolate, fib_limit_);
17671     isolate->Dispose();
17672   }
17673
17674   int result() { return result_; }
17675
17676  private:
17677   int fib_limit_;
17678   int result_;
17679 };
17680
17681
17682 TEST(MultipleIsolatesOnIndividualThreads) {
17683   IsolateThread thread1(21);
17684   IsolateThread thread2(12);
17685
17686   // Compute some fibonacci numbers on 3 threads in 3 isolates.
17687   thread1.Start();
17688   thread2.Start();
17689
17690   int result1 = CalcFibonacci(CcTest::isolate(), 21);
17691   int result2 = CalcFibonacci(CcTest::isolate(), 12);
17692
17693   thread1.Join();
17694   thread2.Join();
17695
17696   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17697   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17698   CHECK_EQ(result1, 10946);
17699   CHECK_EQ(result2, 144);
17700   CHECK_EQ(result1, thread1.result());
17701   CHECK_EQ(result2, thread2.result());
17702 }
17703
17704
17705 TEST(IsolateDifferentContexts) {
17706   v8::Isolate* isolate = v8::Isolate::New();
17707   Local<v8::Context> context;
17708   {
17709     v8::Isolate::Scope isolate_scope(isolate);
17710     v8::HandleScope handle_scope(isolate);
17711     context = v8::Context::New(isolate);
17712     v8::Context::Scope context_scope(context);
17713     Local<Value> v = CompileRun("2");
17714     CHECK(v->IsNumber());
17715     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
17716   }
17717   {
17718     v8::Isolate::Scope isolate_scope(isolate);
17719     v8::HandleScope handle_scope(isolate);
17720     context = v8::Context::New(isolate);
17721     v8::Context::Scope context_scope(context);
17722     Local<Value> v = CompileRun("22");
17723     CHECK(v->IsNumber());
17724     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
17725   }
17726   isolate->Dispose();
17727 }
17728
17729 class InitDefaultIsolateThread : public v8::base::Thread {
17730  public:
17731   enum TestCase {
17732     SetResourceConstraints,
17733     SetFatalHandler,
17734     SetCounterFunction,
17735     SetCreateHistogramFunction,
17736     SetAddHistogramSampleFunction
17737   };
17738
17739   explicit InitDefaultIsolateThread(TestCase testCase)
17740       : Thread(Options("InitDefaultIsolateThread")),
17741         testCase_(testCase),
17742         result_(false) {}
17743
17744   void Run() {
17745     v8::Isolate::CreateParams create_params;
17746     switch (testCase_) {
17747       case SetResourceConstraints: {
17748         create_params.constraints.set_max_semi_space_size(1);
17749         create_params.constraints.set_max_old_space_size(4);
17750         break;
17751       }
17752       default:
17753         break;
17754     }
17755     v8::Isolate* isolate = v8::Isolate::New(create_params);
17756     isolate->Enter();
17757     switch (testCase_) {
17758       case SetResourceConstraints:
17759         // Already handled in pre-Isolate-creation block.
17760         break;
17761
17762       case SetFatalHandler:
17763         v8::V8::SetFatalErrorHandler(NULL);
17764         break;
17765
17766       case SetCounterFunction:
17767         CcTest::isolate()->SetCounterFunction(NULL);
17768         break;
17769
17770       case SetCreateHistogramFunction:
17771         CcTest::isolate()->SetCreateHistogramFunction(NULL);
17772         break;
17773
17774       case SetAddHistogramSampleFunction:
17775         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
17776         break;
17777     }
17778     isolate->Exit();
17779     isolate->Dispose();
17780     result_ = true;
17781   }
17782
17783   bool result() { return result_; }
17784
17785  private:
17786   TestCase testCase_;
17787   bool result_;
17788 };
17789
17790
17791 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
17792   InitDefaultIsolateThread thread(testCase);
17793   thread.Start();
17794   thread.Join();
17795   CHECK_EQ(thread.result(), true);
17796 }
17797
17798
17799 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
17800   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
17801 }
17802
17803
17804 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
17805   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
17806 }
17807
17808
17809 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
17810   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
17811 }
17812
17813
17814 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
17815   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
17816 }
17817
17818
17819 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
17820   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
17821 }
17822
17823
17824 TEST(StringCheckMultipleContexts) {
17825   const char* code =
17826       "(function() { return \"a\".charAt(0); })()";
17827
17828   {
17829     // Run the code twice in the first context to initialize the call IC.
17830     LocalContext context1;
17831     v8::HandleScope scope(context1->GetIsolate());
17832     ExpectString(code, "a");
17833     ExpectString(code, "a");
17834   }
17835
17836   {
17837     // Change the String.prototype in the second context and check
17838     // that the right function gets called.
17839     LocalContext context2;
17840     v8::HandleScope scope(context2->GetIsolate());
17841     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
17842     ExpectString(code, "not a");
17843   }
17844 }
17845
17846
17847 TEST(NumberCheckMultipleContexts) {
17848   const char* code =
17849       "(function() { return (42).toString(); })()";
17850
17851   {
17852     // Run the code twice in the first context to initialize the call IC.
17853     LocalContext context1;
17854     v8::HandleScope scope(context1->GetIsolate());
17855     ExpectString(code, "42");
17856     ExpectString(code, "42");
17857   }
17858
17859   {
17860     // Change the Number.prototype in the second context and check
17861     // that the right function gets called.
17862     LocalContext context2;
17863     v8::HandleScope scope(context2->GetIsolate());
17864     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
17865     ExpectString(code, "not 42");
17866   }
17867 }
17868
17869
17870 TEST(BooleanCheckMultipleContexts) {
17871   const char* code =
17872       "(function() { return true.toString(); })()";
17873
17874   {
17875     // Run the code twice in the first context to initialize the call IC.
17876     LocalContext context1;
17877     v8::HandleScope scope(context1->GetIsolate());
17878     ExpectString(code, "true");
17879     ExpectString(code, "true");
17880   }
17881
17882   {
17883     // Change the Boolean.prototype in the second context and check
17884     // that the right function gets called.
17885     LocalContext context2;
17886     v8::HandleScope scope(context2->GetIsolate());
17887     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
17888     ExpectString(code, "");
17889   }
17890 }
17891
17892
17893 TEST(DontDeleteCellLoadIC) {
17894   const char* function_code =
17895       "function readCell() { while (true) { return cell; } }";
17896
17897   {
17898     // Run the code twice in the first context to initialize the load
17899     // IC for a don't delete cell.
17900     LocalContext context1;
17901     v8::HandleScope scope(context1->GetIsolate());
17902     CompileRun("var cell = \"first\";");
17903     ExpectBoolean("delete cell", false);
17904     CompileRun(function_code);
17905     ExpectString("readCell()", "first");
17906     ExpectString("readCell()", "first");
17907   }
17908
17909   {
17910     // Use a deletable cell in the second context.
17911     LocalContext context2;
17912     v8::HandleScope scope(context2->GetIsolate());
17913     CompileRun("cell = \"second\";");
17914     CompileRun(function_code);
17915     ExpectString("readCell()", "second");
17916     ExpectBoolean("delete cell", true);
17917     ExpectString("(function() {"
17918                  "  try {"
17919                  "    return readCell();"
17920                  "  } catch(e) {"
17921                  "    return e.toString();"
17922                  "  }"
17923                  "})()",
17924                  "ReferenceError: cell is not defined");
17925     CompileRun("cell = \"new_second\";");
17926     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17927     ExpectString("readCell()", "new_second");
17928     ExpectString("readCell()", "new_second");
17929   }
17930 }
17931
17932
17933 class Visitor42 : public v8::PersistentHandleVisitor {
17934  public:
17935   explicit Visitor42(v8::Persistent<v8::Object>* object)
17936       : counter_(0), object_(object) { }
17937
17938   virtual void VisitPersistentHandle(Persistent<Value>* value,
17939                                      uint16_t class_id) {
17940     if (class_id != 42) return;
17941     CHECK_EQ(42, value->WrapperClassId());
17942     v8::Isolate* isolate = CcTest::isolate();
17943     v8::HandleScope handle_scope(isolate);
17944     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
17945     v8::Handle<v8::Value> object =
17946         v8::Local<v8::Object>::New(isolate, *object_);
17947     CHECK(handle->IsObject());
17948     CHECK(Handle<Object>::Cast(handle)->Equals(object));
17949     ++counter_;
17950   }
17951
17952   int counter_;
17953   v8::Persistent<v8::Object>* object_;
17954 };
17955
17956
17957 TEST(PersistentHandleVisitor) {
17958   LocalContext context;
17959   v8::Isolate* isolate = context->GetIsolate();
17960   v8::HandleScope scope(isolate);
17961   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17962   CHECK_EQ(0, object.WrapperClassId());
17963   object.SetWrapperClassId(42);
17964   CHECK_EQ(42, object.WrapperClassId());
17965
17966   Visitor42 visitor(&object);
17967   v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
17968   CHECK_EQ(1, visitor.counter_);
17969
17970   object.Reset();
17971 }
17972
17973
17974 TEST(WrapperClassId) {
17975   LocalContext context;
17976   v8::Isolate* isolate = context->GetIsolate();
17977   v8::HandleScope scope(isolate);
17978   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17979   CHECK_EQ(0, object.WrapperClassId());
17980   object.SetWrapperClassId(65535);
17981   CHECK_EQ(65535, object.WrapperClassId());
17982   object.Reset();
17983 }
17984
17985
17986 TEST(PersistentHandleInNewSpaceVisitor) {
17987   LocalContext context;
17988   v8::Isolate* isolate = context->GetIsolate();
17989   v8::HandleScope scope(isolate);
17990   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
17991   CHECK_EQ(0, object1.WrapperClassId());
17992   object1.SetWrapperClassId(42);
17993   CHECK_EQ(42, object1.WrapperClassId());
17994
17995   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17996   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17997
17998   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
17999   CHECK_EQ(0, object2.WrapperClassId());
18000   object2.SetWrapperClassId(42);
18001   CHECK_EQ(42, object2.WrapperClassId());
18002
18003   Visitor42 visitor(&object2);
18004   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18005   CHECK_EQ(1, visitor.counter_);
18006
18007   object1.Reset();
18008   object2.Reset();
18009 }
18010
18011
18012 TEST(RegExp) {
18013   LocalContext context;
18014   v8::HandleScope scope(context->GetIsolate());
18015
18016   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18017   CHECK(re->IsRegExp());
18018   CHECK(re->GetSource()->Equals(v8_str("foo")));
18019   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18020
18021   re = v8::RegExp::New(v8_str("bar"),
18022                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18023                                                       v8::RegExp::kGlobal));
18024   CHECK(re->IsRegExp());
18025   CHECK(re->GetSource()->Equals(v8_str("bar")));
18026   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18027            static_cast<int>(re->GetFlags()));
18028
18029   re = v8::RegExp::New(v8_str("baz"),
18030                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18031                                                       v8::RegExp::kMultiline));
18032   CHECK(re->IsRegExp());
18033   CHECK(re->GetSource()->Equals(v8_str("baz")));
18034   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18035            static_cast<int>(re->GetFlags()));
18036
18037   re = CompileRun("/quux/").As<v8::RegExp>();
18038   CHECK(re->IsRegExp());
18039   CHECK(re->GetSource()->Equals(v8_str("quux")));
18040   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18041
18042   re = CompileRun("/quux/gm").As<v8::RegExp>();
18043   CHECK(re->IsRegExp());
18044   CHECK(re->GetSource()->Equals(v8_str("quux")));
18045   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18046            static_cast<int>(re->GetFlags()));
18047
18048   // Override the RegExp constructor and check the API constructor
18049   // still works.
18050   CompileRun("RegExp = function() {}");
18051
18052   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18053   CHECK(re->IsRegExp());
18054   CHECK(re->GetSource()->Equals(v8_str("foobar")));
18055   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18056
18057   re = v8::RegExp::New(v8_str("foobarbaz"),
18058                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18059                                                       v8::RegExp::kMultiline));
18060   CHECK(re->IsRegExp());
18061   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18062   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18063            static_cast<int>(re->GetFlags()));
18064
18065   context->Global()->Set(v8_str("re"), re);
18066   ExpectTrue("re.test('FoobarbaZ')");
18067
18068   // RegExps are objects on which you can set properties.
18069   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
18070   v8::Handle<v8::Value> value(CompileRun("re.property"));
18071   CHECK_EQ(32, value->Int32Value());
18072
18073   v8::TryCatch try_catch;
18074   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18075   CHECK(re.IsEmpty());
18076   CHECK(try_catch.HasCaught());
18077   context->Global()->Set(v8_str("ex"), try_catch.Exception());
18078   ExpectTrue("ex instanceof SyntaxError");
18079 }
18080
18081
18082 THREADED_TEST(Equals) {
18083   LocalContext localContext;
18084   v8::HandleScope handleScope(localContext->GetIsolate());
18085
18086   v8::Handle<v8::Object> globalProxy = localContext->Global();
18087   v8::Handle<Value> global = globalProxy->GetPrototype();
18088
18089   CHECK(global->StrictEquals(global));
18090   CHECK(!global->StrictEquals(globalProxy));
18091   CHECK(!globalProxy->StrictEquals(global));
18092   CHECK(globalProxy->StrictEquals(globalProxy));
18093
18094   CHECK(global->Equals(global));
18095   CHECK(!global->Equals(globalProxy));
18096   CHECK(!globalProxy->Equals(global));
18097   CHECK(globalProxy->Equals(globalProxy));
18098 }
18099
18100
18101 static void Getter(v8::Local<v8::Name> property,
18102                    const v8::PropertyCallbackInfo<v8::Value>& info) {
18103   info.GetReturnValue().Set(v8_str("42!"));
18104 }
18105
18106
18107 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18108   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
18109   result->Set(0, v8_str("universalAnswer"));
18110   info.GetReturnValue().Set(result);
18111 }
18112
18113
18114 TEST(NamedEnumeratorAndForIn) {
18115   LocalContext context;
18116   v8::Isolate* isolate = context->GetIsolate();
18117   v8::HandleScope handle_scope(isolate);
18118   v8::Context::Scope context_scope(context.local());
18119
18120   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
18121   tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
18122                                                          NULL, Enumerator));
18123   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
18124   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
18125         "var result = []; for (var k in o) result.push(k); result"));
18126   CHECK_EQ(1u, result->Length());
18127   CHECK(v8_str("universalAnswer")->Equals(result->Get(0)));
18128 }
18129
18130
18131 TEST(DefinePropertyPostDetach) {
18132   LocalContext context;
18133   v8::HandleScope scope(context->GetIsolate());
18134   v8::Handle<v8::Object> proxy = context->Global();
18135   v8::Handle<v8::Function> define_property =
18136       CompileRun("(function() {"
18137                  "  Object.defineProperty("
18138                  "    this,"
18139                  "    1,"
18140                  "    { configurable: true, enumerable: true, value: 3 });"
18141                  "})").As<Function>();
18142   context->DetachGlobal();
18143   define_property->Call(proxy, 0, NULL);
18144 }
18145
18146
18147 static void InstallContextId(v8::Handle<Context> context, int id) {
18148   Context::Scope scope(context);
18149   CompileRun("Object.prototype").As<Object>()->
18150       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
18151 }
18152
18153
18154 static void CheckContextId(v8::Handle<Object> object, int expected) {
18155   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
18156 }
18157
18158
18159 THREADED_TEST(CreationContext) {
18160   v8::Isolate* isolate = CcTest::isolate();
18161   HandleScope handle_scope(isolate);
18162   Handle<Context> context1 = Context::New(isolate);
18163   InstallContextId(context1, 1);
18164   Handle<Context> context2 = Context::New(isolate);
18165   InstallContextId(context2, 2);
18166   Handle<Context> context3 = Context::New(isolate);
18167   InstallContextId(context3, 3);
18168
18169   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
18170
18171   Local<Object> object1;
18172   Local<Function> func1;
18173   {
18174     Context::Scope scope(context1);
18175     object1 = Object::New(isolate);
18176     func1 = tmpl->GetFunction();
18177   }
18178
18179   Local<Object> object2;
18180   Local<Function> func2;
18181   {
18182     Context::Scope scope(context2);
18183     object2 = Object::New(isolate);
18184     func2 = tmpl->GetFunction();
18185   }
18186
18187   Local<Object> instance1;
18188   Local<Object> instance2;
18189
18190   {
18191     Context::Scope scope(context3);
18192     instance1 = func1->NewInstance();
18193     instance2 = func2->NewInstance();
18194   }
18195
18196   {
18197     Handle<Context> other_context = Context::New(isolate);
18198     Context::Scope scope(other_context);
18199     CHECK(object1->CreationContext() == context1);
18200     CheckContextId(object1, 1);
18201     CHECK(func1->CreationContext() == context1);
18202     CheckContextId(func1, 1);
18203     CHECK(instance1->CreationContext() == context1);
18204     CheckContextId(instance1, 1);
18205     CHECK(object2->CreationContext() == context2);
18206     CheckContextId(object2, 2);
18207     CHECK(func2->CreationContext() == context2);
18208     CheckContextId(func2, 2);
18209     CHECK(instance2->CreationContext() == context2);
18210     CheckContextId(instance2, 2);
18211   }
18212
18213   {
18214     Context::Scope scope(context1);
18215     CHECK(object1->CreationContext() == context1);
18216     CheckContextId(object1, 1);
18217     CHECK(func1->CreationContext() == context1);
18218     CheckContextId(func1, 1);
18219     CHECK(instance1->CreationContext() == context1);
18220     CheckContextId(instance1, 1);
18221     CHECK(object2->CreationContext() == context2);
18222     CheckContextId(object2, 2);
18223     CHECK(func2->CreationContext() == context2);
18224     CheckContextId(func2, 2);
18225     CHECK(instance2->CreationContext() == context2);
18226     CheckContextId(instance2, 2);
18227   }
18228
18229   {
18230     Context::Scope scope(context2);
18231     CHECK(object1->CreationContext() == context1);
18232     CheckContextId(object1, 1);
18233     CHECK(func1->CreationContext() == context1);
18234     CheckContextId(func1, 1);
18235     CHECK(instance1->CreationContext() == context1);
18236     CheckContextId(instance1, 1);
18237     CHECK(object2->CreationContext() == context2);
18238     CheckContextId(object2, 2);
18239     CHECK(func2->CreationContext() == context2);
18240     CheckContextId(func2, 2);
18241     CHECK(instance2->CreationContext() == context2);
18242     CheckContextId(instance2, 2);
18243   }
18244 }
18245
18246
18247 THREADED_TEST(CreationContextOfJsFunction) {
18248   HandleScope handle_scope(CcTest::isolate());
18249   Handle<Context> context = Context::New(CcTest::isolate());
18250   InstallContextId(context, 1);
18251
18252   Local<Object> function;
18253   {
18254     Context::Scope scope(context);
18255     function = CompileRun("function foo() {}; foo").As<Object>();
18256   }
18257
18258   Handle<Context> other_context = Context::New(CcTest::isolate());
18259   Context::Scope scope(other_context);
18260   CHECK(function->CreationContext() == context);
18261   CheckContextId(function, 1);
18262 }
18263
18264
18265 void HasOwnPropertyIndexedPropertyGetter(
18266     uint32_t index,
18267     const v8::PropertyCallbackInfo<v8::Value>& info) {
18268   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
18269 }
18270
18271
18272 void HasOwnPropertyNamedPropertyGetter(
18273     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
18274   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
18275 }
18276
18277
18278 void HasOwnPropertyIndexedPropertyQuery(
18279     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18280   if (index == 42) info.GetReturnValue().Set(1);
18281 }
18282
18283
18284 void HasOwnPropertyNamedPropertyQuery(
18285     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18286   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
18287 }
18288
18289
18290 void HasOwnPropertyNamedPropertyQuery2(
18291     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18292   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
18293 }
18294
18295
18296 void HasOwnPropertyAccessorGetter(
18297     Local<String> property,
18298     const v8::PropertyCallbackInfo<v8::Value>& info) {
18299   info.GetReturnValue().Set(v8_str("yes"));
18300 }
18301
18302
18303 TEST(HasOwnProperty) {
18304   LocalContext env;
18305   v8::Isolate* isolate = env->GetIsolate();
18306   v8::HandleScope scope(isolate);
18307   { // Check normal properties and defined getters.
18308     Handle<Value> value = CompileRun(
18309         "function Foo() {"
18310         "    this.foo = 11;"
18311         "    this.__defineGetter__('baz', function() { return 1; });"
18312         "};"
18313         "function Bar() { "
18314         "    this.bar = 13;"
18315         "    this.__defineGetter__('bla', function() { return 2; });"
18316         "};"
18317         "Bar.prototype = new Foo();"
18318         "new Bar();");
18319     CHECK(value->IsObject());
18320     Handle<Object> object = value->ToObject(isolate);
18321     CHECK(object->Has(v8_str("foo")));
18322     CHECK(!object->HasOwnProperty(v8_str("foo")));
18323     CHECK(object->HasOwnProperty(v8_str("bar")));
18324     CHECK(object->Has(v8_str("baz")));
18325     CHECK(!object->HasOwnProperty(v8_str("baz")));
18326     CHECK(object->HasOwnProperty(v8_str("bla")));
18327   }
18328   { // Check named getter interceptors.
18329     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18330     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18331         HasOwnPropertyNamedPropertyGetter));
18332     Handle<Object> instance = templ->NewInstance();
18333     CHECK(!instance->HasOwnProperty(v8_str("42")));
18334     CHECK(instance->HasOwnProperty(v8_str("foo")));
18335     CHECK(!instance->HasOwnProperty(v8_str("bar")));
18336   }
18337   { // Check indexed getter interceptors.
18338     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18339     templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18340         HasOwnPropertyIndexedPropertyGetter));
18341     Handle<Object> instance = templ->NewInstance();
18342     CHECK(instance->HasOwnProperty(v8_str("42")));
18343     CHECK(!instance->HasOwnProperty(v8_str("43")));
18344     CHECK(!instance->HasOwnProperty(v8_str("foo")));
18345   }
18346   { // Check named query interceptors.
18347     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18348     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18349         0, 0, HasOwnPropertyNamedPropertyQuery));
18350     Handle<Object> instance = templ->NewInstance();
18351     CHECK(instance->HasOwnProperty(v8_str("foo")));
18352     CHECK(!instance->HasOwnProperty(v8_str("bar")));
18353   }
18354   { // Check indexed query interceptors.
18355     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18356     templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18357         0, 0, HasOwnPropertyIndexedPropertyQuery));
18358     Handle<Object> instance = templ->NewInstance();
18359     CHECK(instance->HasOwnProperty(v8_str("42")));
18360     CHECK(!instance->HasOwnProperty(v8_str("41")));
18361   }
18362   { // Check callbacks.
18363     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18364     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
18365     Handle<Object> instance = templ->NewInstance();
18366     CHECK(instance->HasOwnProperty(v8_str("foo")));
18367     CHECK(!instance->HasOwnProperty(v8_str("bar")));
18368   }
18369   { // Check that query wins on disagreement.
18370     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18371     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18372         HasOwnPropertyNamedPropertyGetter, 0,
18373         HasOwnPropertyNamedPropertyQuery2));
18374     Handle<Object> instance = templ->NewInstance();
18375     CHECK(!instance->HasOwnProperty(v8_str("foo")));
18376     CHECK(instance->HasOwnProperty(v8_str("bar")));
18377   }
18378 }
18379
18380
18381 TEST(IndexedInterceptorWithStringProto) {
18382   v8::Isolate* isolate = CcTest::isolate();
18383   v8::HandleScope scope(isolate);
18384   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18385   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18386       NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
18387   LocalContext context;
18388   context->Global()->Set(v8_str("obj"), templ->NewInstance());
18389   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
18390   // These should be intercepted.
18391   CHECK(CompileRun("42 in obj")->BooleanValue());
18392   CHECK(CompileRun("'42' in obj")->BooleanValue());
18393   // These should fall through to the String prototype.
18394   CHECK(CompileRun("0 in obj")->BooleanValue());
18395   CHECK(CompileRun("'0' in obj")->BooleanValue());
18396   // And these should both fail.
18397   CHECK(!CompileRun("32 in obj")->BooleanValue());
18398   CHECK(!CompileRun("'32' in obj")->BooleanValue());
18399 }
18400
18401
18402 void CheckCodeGenerationAllowed() {
18403   Handle<Value> result = CompileRun("eval('42')");
18404   CHECK_EQ(42, result->Int32Value());
18405   result = CompileRun("(function(e) { return e('42'); })(eval)");
18406   CHECK_EQ(42, result->Int32Value());
18407   result = CompileRun("var f = new Function('return 42'); f()");
18408   CHECK_EQ(42, result->Int32Value());
18409 }
18410
18411
18412 void CheckCodeGenerationDisallowed() {
18413   TryCatch try_catch;
18414
18415   Handle<Value> result = CompileRun("eval('42')");
18416   CHECK(result.IsEmpty());
18417   CHECK(try_catch.HasCaught());
18418   try_catch.Reset();
18419
18420   result = CompileRun("(function(e) { return e('42'); })(eval)");
18421   CHECK(result.IsEmpty());
18422   CHECK(try_catch.HasCaught());
18423   try_catch.Reset();
18424
18425   result = CompileRun("var f = new Function('return 42'); f()");
18426   CHECK(result.IsEmpty());
18427   CHECK(try_catch.HasCaught());
18428 }
18429
18430
18431 bool CodeGenerationAllowed(Local<Context> context) {
18432   ApiTestFuzzer::Fuzz();
18433   return true;
18434 }
18435
18436
18437 bool CodeGenerationDisallowed(Local<Context> context) {
18438   ApiTestFuzzer::Fuzz();
18439   return false;
18440 }
18441
18442
18443 THREADED_TEST(AllowCodeGenFromStrings) {
18444   LocalContext context;
18445   v8::HandleScope scope(context->GetIsolate());
18446
18447   // eval and the Function constructor allowed by default.
18448   CHECK(context->IsCodeGenerationFromStringsAllowed());
18449   CheckCodeGenerationAllowed();
18450
18451   // Disallow eval and the Function constructor.
18452   context->AllowCodeGenerationFromStrings(false);
18453   CHECK(!context->IsCodeGenerationFromStringsAllowed());
18454   CheckCodeGenerationDisallowed();
18455
18456   // Allow again.
18457   context->AllowCodeGenerationFromStrings(true);
18458   CheckCodeGenerationAllowed();
18459
18460   // Disallow but setting a global callback that will allow the calls.
18461   context->AllowCodeGenerationFromStrings(false);
18462   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
18463   CHECK(!context->IsCodeGenerationFromStringsAllowed());
18464   CheckCodeGenerationAllowed();
18465
18466   // Set a callback that disallows the code generation.
18467   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18468   CHECK(!context->IsCodeGenerationFromStringsAllowed());
18469   CheckCodeGenerationDisallowed();
18470 }
18471
18472
18473 TEST(SetErrorMessageForCodeGenFromStrings) {
18474   LocalContext context;
18475   v8::HandleScope scope(context->GetIsolate());
18476   TryCatch try_catch;
18477
18478   Handle<String> message = v8_str("Message") ;
18479   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
18480   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18481   context->AllowCodeGenerationFromStrings(false);
18482   context->SetErrorMessageForCodeGenerationFromStrings(message);
18483   Handle<Value> result = CompileRun("eval('42')");
18484   CHECK(result.IsEmpty());
18485   CHECK(try_catch.HasCaught());
18486   Handle<String> actual_message = try_catch.Message()->Get();
18487   CHECK(expected_message->Equals(actual_message));
18488 }
18489
18490
18491 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
18492 }
18493
18494
18495 THREADED_TEST(CallAPIFunctionOnNonObject) {
18496   LocalContext context;
18497   v8::Isolate* isolate = context->GetIsolate();
18498   v8::HandleScope scope(isolate);
18499   Handle<FunctionTemplate> templ =
18500       v8::FunctionTemplate::New(isolate, NonObjectThis);
18501   Handle<Function> function = templ->GetFunction();
18502   context->Global()->Set(v8_str("f"), function);
18503   TryCatch try_catch;
18504   CompileRun("f.call(2)");
18505 }
18506
18507
18508 // Regression test for issue 1470.
18509 THREADED_TEST(ReadOnlyIndexedProperties) {
18510   v8::Isolate* isolate = CcTest::isolate();
18511   v8::HandleScope scope(isolate);
18512   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18513
18514   LocalContext context;
18515   Local<v8::Object> obj = templ->NewInstance();
18516   context->Global()->Set(v8_str("obj"), obj);
18517   obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18518   obj->Set(v8_str("1"), v8_str("foobar"));
18519   CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("1"))));
18520   obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18521   obj->Set(v8_num(2), v8_str("foobar"));
18522   CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_num(2))));
18523
18524   // Test non-smi case.
18525   obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18526   obj->Set(v8_str("2000000000"), v8_str("foobar"));
18527   CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("2000000000"))));
18528 }
18529
18530
18531 static int CountLiveMapsInMapCache(i::Context* context) {
18532   i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
18533   int length = map_cache->length();
18534   int count = 0;
18535   for (int i = 0; i < length; i++) {
18536     i::Object* value = map_cache->get(i);
18537     if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
18538   }
18539   return count;
18540 }
18541
18542
18543 THREADED_TEST(Regress1516) {
18544   LocalContext context;
18545   v8::HandleScope scope(context->GetIsolate());
18546
18547   // Object with 20 properties is not a common case, so it should be removed
18548   // from the cache after GC.
18549   { v8::HandleScope temp_scope(context->GetIsolate());
18550     CompileRun(
18551         "({"
18552         "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
18553         "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
18554         "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
18555         "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
18556         "})");
18557   }
18558
18559   int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
18560   CHECK_LE(1, elements);
18561
18562   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
18563
18564   CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
18565 }
18566
18567
18568 THREADED_TEST(Regress93759) {
18569   v8::Isolate* isolate = CcTest::isolate();
18570   HandleScope scope(isolate);
18571
18572   // Template for object with security check.
18573   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
18574   no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
18575
18576   // Templates for objects with hidden prototypes and possibly security check.
18577   Local<FunctionTemplate> hidden_proto_template =
18578       v8::FunctionTemplate::New(isolate);
18579   hidden_proto_template->SetHiddenPrototype(true);
18580
18581   Local<FunctionTemplate> protected_hidden_proto_template =
18582       v8::FunctionTemplate::New(isolate);
18583   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18584       AccessAlwaysBlocked, NULL);
18585   protected_hidden_proto_template->SetHiddenPrototype(true);
18586
18587   // Context for "foreign" objects used in test.
18588   Local<Context> context = v8::Context::New(isolate);
18589   context->Enter();
18590
18591   // Plain object, no security check.
18592   Local<Object> simple_object = Object::New(isolate);
18593
18594   // Object with explicit security check.
18595   Local<Object> protected_object = no_proto_template->NewInstance();
18596
18597   // JSGlobalProxy object, always have security check.
18598   Local<Object> proxy_object = context->Global();
18599
18600   // Global object, the  prototype of proxy_object. No security checks.
18601   Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
18602
18603   // Hidden prototype without security check.
18604   Local<Object> hidden_prototype =
18605       hidden_proto_template->GetFunction()->NewInstance();
18606   Local<Object> object_with_hidden =
18607     Object::New(isolate);
18608   object_with_hidden->SetPrototype(hidden_prototype);
18609
18610   // Hidden prototype with security check on the hidden prototype.
18611   Local<Object> protected_hidden_prototype =
18612       protected_hidden_proto_template->GetFunction()->NewInstance();
18613   Local<Object> object_with_protected_hidden =
18614     Object::New(isolate);
18615   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18616
18617   context->Exit();
18618
18619   // Template for object for second context. Values to test are put on it as
18620   // properties.
18621   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
18622   global_template->Set(v8_str("simple"), simple_object);
18623   global_template->Set(v8_str("protected"), protected_object);
18624   global_template->Set(v8_str("global"), global_object);
18625   global_template->Set(v8_str("proxy"), proxy_object);
18626   global_template->Set(v8_str("hidden"), object_with_hidden);
18627   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18628
18629   LocalContext context2(NULL, global_template);
18630
18631   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18632   CHECK(result1->Equals(simple_object->GetPrototype()));
18633
18634   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18635   CHECK(result2.IsEmpty());
18636
18637   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18638   CHECK(result3->Equals(global_object->GetPrototype()));
18639
18640   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18641   CHECK(result4.IsEmpty());
18642
18643   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18644   CHECK(result5->Equals(
18645       object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
18646
18647   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18648   CHECK(result6.IsEmpty());
18649 }
18650
18651
18652 static void TestReceiver(Local<Value> expected_result,
18653                          Local<Value> expected_receiver,
18654                          const char* code) {
18655   Local<Value> result = CompileRun(code);
18656   CHECK(result->IsObject());
18657   CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
18658   CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
18659 }
18660
18661
18662 THREADED_TEST(ForeignFunctionReceiver) {
18663   v8::Isolate* isolate = CcTest::isolate();
18664   HandleScope scope(isolate);
18665
18666   // Create two contexts with different "id" properties ('i' and 'o').
18667   // Call a function both from its own context and from a the foreign
18668   // context, and see what "this" is bound to (returning both "this"
18669   // and "this.id" for comparison).
18670
18671   Local<Context> foreign_context = v8::Context::New(isolate);
18672   foreign_context->Enter();
18673   Local<Value> foreign_function =
18674     CompileRun("function func() { return { 0: this.id, "
18675                "                           1: this, "
18676                "                           toString: function() { "
18677                "                               return this[0];"
18678                "                           }"
18679                "                         };"
18680                "}"
18681                "var id = 'i';"
18682                "func;");
18683   CHECK(foreign_function->IsFunction());
18684   foreign_context->Exit();
18685
18686   LocalContext context;
18687
18688   Local<String> password = v8_str("Password");
18689   // Don't get hit by security checks when accessing foreign_context's
18690   // global receiver (aka. global proxy).
18691   context->SetSecurityToken(password);
18692   foreign_context->SetSecurityToken(password);
18693
18694   Local<String> i = v8_str("i");
18695   Local<String> o = v8_str("o");
18696   Local<String> id = v8_str("id");
18697
18698   CompileRun("function ownfunc() { return { 0: this.id, "
18699              "                              1: this, "
18700              "                              toString: function() { "
18701              "                                  return this[0];"
18702              "                              }"
18703              "                             };"
18704              "}"
18705              "var id = 'o';"
18706              "ownfunc");
18707   context->Global()->Set(v8_str("func"), foreign_function);
18708
18709   // Sanity check the contexts.
18710   CHECK(i->Equals(foreign_context->Global()->Get(id)));
18711   CHECK(o->Equals(context->Global()->Get(id)));
18712
18713   // Checking local function's receiver.
18714   // Calling function using its call/apply methods.
18715   TestReceiver(o, context->Global(), "ownfunc.call()");
18716   TestReceiver(o, context->Global(), "ownfunc.apply()");
18717   // Making calls through built-in functions.
18718   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
18719   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
18720   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
18721   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
18722   // Calling with environment record as base.
18723   TestReceiver(o, context->Global(), "ownfunc()");
18724   // Calling with no base.
18725   TestReceiver(o, context->Global(), "(1,ownfunc)()");
18726
18727   // Checking foreign function return value.
18728   // Calling function using its call/apply methods.
18729   TestReceiver(i, foreign_context->Global(), "func.call()");
18730   TestReceiver(i, foreign_context->Global(), "func.apply()");
18731   // Calling function using another context's call/apply methods.
18732   TestReceiver(i, foreign_context->Global(),
18733                "Function.prototype.call.call(func)");
18734   TestReceiver(i, foreign_context->Global(),
18735                "Function.prototype.call.apply(func)");
18736   TestReceiver(i, foreign_context->Global(),
18737                "Function.prototype.apply.call(func)");
18738   TestReceiver(i, foreign_context->Global(),
18739                "Function.prototype.apply.apply(func)");
18740   // Making calls through built-in functions.
18741   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
18742   // ToString(func()) is func()[0], i.e., the returned this.id.
18743   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
18744   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
18745   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
18746
18747   // Calling with environment record as base.
18748   TestReceiver(i, foreign_context->Global(), "func()");
18749   // Calling with no base.
18750   TestReceiver(i, foreign_context->Global(), "(1,func)()");
18751 }
18752
18753
18754 uint8_t callback_fired = 0;
18755
18756
18757 void CallCompletedCallback1() {
18758   v8::base::OS::Print("Firing callback 1.\n");
18759   callback_fired ^= 1;  // Toggle first bit.
18760 }
18761
18762
18763 void CallCompletedCallback2() {
18764   v8::base::OS::Print("Firing callback 2.\n");
18765   callback_fired ^= 2;  // Toggle second bit.
18766 }
18767
18768
18769 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
18770   int32_t level = args[0]->Int32Value();
18771   if (level < 3) {
18772     level++;
18773     v8::base::OS::Print("Entering recursion level %d.\n", level);
18774     char script[64];
18775     i::Vector<char> script_vector(script, sizeof(script));
18776     i::SNPrintF(script_vector, "recursion(%d)", level);
18777     CompileRun(script_vector.start());
18778     v8::base::OS::Print("Leaving recursion level %d.\n", level);
18779     CHECK_EQ(0, callback_fired);
18780   } else {
18781     v8::base::OS::Print("Recursion ends.\n");
18782     CHECK_EQ(0, callback_fired);
18783   }
18784 }
18785
18786
18787 TEST(CallCompletedCallback) {
18788   LocalContext env;
18789   v8::HandleScope scope(env->GetIsolate());
18790   v8::Handle<v8::FunctionTemplate> recursive_runtime =
18791       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
18792   env->Global()->Set(v8_str("recursion"),
18793                      recursive_runtime->GetFunction());
18794   // Adding the same callback a second time has no effect.
18795   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18796   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18797   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
18798   v8::base::OS::Print("--- Script (1) ---\n");
18799   Local<Script> script = v8::Script::Compile(
18800       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
18801   script->Run();
18802   CHECK_EQ(3, callback_fired);
18803
18804   v8::base::OS::Print("\n--- Script (2) ---\n");
18805   callback_fired = 0;
18806   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
18807   script->Run();
18808   CHECK_EQ(2, callback_fired);
18809
18810   v8::base::OS::Print("\n--- Function ---\n");
18811   callback_fired = 0;
18812   Local<Function> recursive_function =
18813       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
18814   v8::Handle<Value> args[] = { v8_num(0) };
18815   recursive_function->Call(env->Global(), 1, args);
18816   CHECK_EQ(2, callback_fired);
18817 }
18818
18819
18820 void CallCompletedCallbackNoException() {
18821   v8::HandleScope scope(CcTest::isolate());
18822   CompileRun("1+1;");
18823 }
18824
18825
18826 void CallCompletedCallbackException() {
18827   v8::HandleScope scope(CcTest::isolate());
18828   CompileRun("throw 'second exception';");
18829 }
18830
18831
18832 TEST(CallCompletedCallbackOneException) {
18833   LocalContext env;
18834   v8::HandleScope scope(env->GetIsolate());
18835   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
18836   CompileRun("throw 'exception';");
18837 }
18838
18839
18840 TEST(CallCompletedCallbackTwoExceptions) {
18841   LocalContext env;
18842   v8::HandleScope scope(env->GetIsolate());
18843   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
18844   CompileRun("throw 'first exception';");
18845 }
18846
18847
18848 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
18849   v8::HandleScope scope(info.GetIsolate());
18850   CompileRun("ext1Calls++;");
18851 }
18852
18853
18854 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
18855   v8::HandleScope scope(info.GetIsolate());
18856   CompileRun("ext2Calls++;");
18857 }
18858
18859
18860 void* g_passed_to_three = NULL;
18861
18862
18863 static void MicrotaskThree(void* data) {
18864   g_passed_to_three = data;
18865 }
18866
18867
18868 TEST(EnqueueMicrotask) {
18869   LocalContext env;
18870   v8::HandleScope scope(env->GetIsolate());
18871   CompileRun(
18872       "var ext1Calls = 0;"
18873       "var ext2Calls = 0;");
18874   CompileRun("1+1;");
18875   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18876   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18877
18878   env->GetIsolate()->EnqueueMicrotask(
18879       Function::New(env->GetIsolate(), MicrotaskOne));
18880   CompileRun("1+1;");
18881   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18882   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18883
18884   env->GetIsolate()->EnqueueMicrotask(
18885       Function::New(env->GetIsolate(), MicrotaskOne));
18886   env->GetIsolate()->EnqueueMicrotask(
18887       Function::New(env->GetIsolate(), MicrotaskTwo));
18888   CompileRun("1+1;");
18889   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18890   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18891
18892   env->GetIsolate()->EnqueueMicrotask(
18893       Function::New(env->GetIsolate(), MicrotaskTwo));
18894   CompileRun("1+1;");
18895   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18896   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18897
18898   CompileRun("1+1;");
18899   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18900   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18901
18902   g_passed_to_three = NULL;
18903   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
18904   CompileRun("1+1;");
18905   CHECK(!g_passed_to_three);
18906   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18907   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18908
18909   int dummy;
18910   env->GetIsolate()->EnqueueMicrotask(
18911       Function::New(env->GetIsolate(), MicrotaskOne));
18912   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
18913   env->GetIsolate()->EnqueueMicrotask(
18914       Function::New(env->GetIsolate(), MicrotaskTwo));
18915   CompileRun("1+1;");
18916   CHECK_EQ(&dummy, g_passed_to_three);
18917   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
18918   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18919   g_passed_to_three = NULL;
18920 }
18921
18922
18923 static void MicrotaskExceptionOne(
18924     const v8::FunctionCallbackInfo<Value>& info) {
18925   v8::HandleScope scope(info.GetIsolate());
18926   CompileRun("exception1Calls++;");
18927   info.GetIsolate()->ThrowException(
18928       v8::Exception::Error(v8_str("first")));
18929 }
18930
18931
18932 static void MicrotaskExceptionTwo(
18933     const v8::FunctionCallbackInfo<Value>& info) {
18934   v8::HandleScope scope(info.GetIsolate());
18935   CompileRun("exception2Calls++;");
18936   info.GetIsolate()->ThrowException(
18937       v8::Exception::Error(v8_str("second")));
18938 }
18939
18940
18941 TEST(RunMicrotasksIgnoresThrownExceptions) {
18942   LocalContext env;
18943   v8::Isolate* isolate = env->GetIsolate();
18944   v8::HandleScope scope(isolate);
18945   CompileRun(
18946       "var exception1Calls = 0;"
18947       "var exception2Calls = 0;");
18948   isolate->EnqueueMicrotask(
18949       Function::New(isolate, MicrotaskExceptionOne));
18950   isolate->EnqueueMicrotask(
18951       Function::New(isolate, MicrotaskExceptionTwo));
18952   TryCatch try_catch;
18953   CompileRun("1+1;");
18954   CHECK(!try_catch.HasCaught());
18955   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
18956   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
18957 }
18958
18959
18960 TEST(SetAutorunMicrotasks) {
18961   LocalContext env;
18962   v8::HandleScope scope(env->GetIsolate());
18963   CompileRun(
18964       "var ext1Calls = 0;"
18965       "var ext2Calls = 0;");
18966   CompileRun("1+1;");
18967   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18968   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18969
18970   env->GetIsolate()->EnqueueMicrotask(
18971       Function::New(env->GetIsolate(), MicrotaskOne));
18972   CompileRun("1+1;");
18973   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18974   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18975
18976   env->GetIsolate()->SetAutorunMicrotasks(false);
18977   env->GetIsolate()->EnqueueMicrotask(
18978       Function::New(env->GetIsolate(), MicrotaskOne));
18979   env->GetIsolate()->EnqueueMicrotask(
18980       Function::New(env->GetIsolate(), MicrotaskTwo));
18981   CompileRun("1+1;");
18982   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18983   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18984
18985   env->GetIsolate()->RunMicrotasks();
18986   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18987   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18988
18989   env->GetIsolate()->EnqueueMicrotask(
18990       Function::New(env->GetIsolate(), MicrotaskTwo));
18991   CompileRun("1+1;");
18992   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18993   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18994
18995   env->GetIsolate()->RunMicrotasks();
18996   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18997   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18998
18999   env->GetIsolate()->SetAutorunMicrotasks(true);
19000   env->GetIsolate()->EnqueueMicrotask(
19001       Function::New(env->GetIsolate(), MicrotaskTwo));
19002   CompileRun("1+1;");
19003   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19004   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
19005
19006   env->GetIsolate()->EnqueueMicrotask(
19007       Function::New(env->GetIsolate(), MicrotaskTwo));
19008   {
19009     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
19010     CompileRun("1+1;");
19011     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19012     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
19013   }
19014
19015   CompileRun("1+1;");
19016   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19017   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
19018 }
19019
19020
19021 TEST(RunMicrotasksWithoutEnteringContext) {
19022   v8::Isolate* isolate = CcTest::isolate();
19023   HandleScope handle_scope(isolate);
19024   isolate->SetAutorunMicrotasks(false);
19025   Handle<Context> context = Context::New(isolate);
19026   {
19027     Context::Scope context_scope(context);
19028     CompileRun("var ext1Calls = 0;");
19029     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
19030   }
19031   isolate->RunMicrotasks();
19032   {
19033     Context::Scope context_scope(context);
19034     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
19035   }
19036   isolate->SetAutorunMicrotasks(true);
19037 }
19038
19039
19040 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
19041   v8::DebugEvent event = event_details.GetEvent();
19042   if (event != v8::Break) return;
19043   Handle<Object> exec_state = event_details.GetExecutionState();
19044   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
19045   CompileRun("function f(id) { new FrameDetails(id, 0); }");
19046   Handle<Function> fun =
19047       Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
19048   fun->Call(CcTest::global(), 1, &break_id);
19049 }
19050
19051
19052 TEST(Regress385349) {
19053   i::FLAG_allow_natives_syntax = true;
19054   v8::Isolate* isolate = CcTest::isolate();
19055   HandleScope handle_scope(isolate);
19056   isolate->SetAutorunMicrotasks(false);
19057   Handle<Context> context = Context::New(isolate);
19058   v8::Debug::SetDebugEventListener(DebugEventInObserver);
19059   {
19060     Context::Scope context_scope(context);
19061     CompileRun("var obj = {};"
19062                "Object.observe(obj, function(changes) { debugger; });"
19063                "obj.a = 0;");
19064   }
19065   isolate->RunMicrotasks();
19066   isolate->SetAutorunMicrotasks(true);
19067   v8::Debug::SetDebugEventListener(NULL);
19068 }
19069
19070
19071 #ifdef ENABLE_DISASSEMBLER
19072 static int probes_counter = 0;
19073 static int misses_counter = 0;
19074 static int updates_counter = 0;
19075
19076
19077 static int* LookupCounter(const char* name) {
19078   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19079     return &probes_counter;
19080   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19081     return &misses_counter;
19082   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19083     return &updates_counter;
19084   }
19085   return NULL;
19086 }
19087
19088
19089 static const char* kMegamorphicTestProgram =
19090     "function ClassA() { };"
19091     "function ClassB() { };"
19092     "ClassA.prototype.foo = function() { };"
19093     "ClassB.prototype.foo = function() { };"
19094     "function fooify(obj) { obj.foo(); };"
19095     "var a = new ClassA();"
19096     "var b = new ClassB();"
19097     "for (var i = 0; i < 10000; i++) {"
19098     "  fooify(a);"
19099     "  fooify(b);"
19100     "}";
19101 #endif
19102
19103
19104 static void StubCacheHelper(bool primary) {
19105 #ifdef ENABLE_DISASSEMBLER
19106   i::FLAG_native_code_counters = true;
19107   if (primary) {
19108     i::FLAG_test_primary_stub_cache = true;
19109   } else {
19110     i::FLAG_test_secondary_stub_cache = true;
19111   }
19112   i::FLAG_crankshaft = false;
19113   LocalContext env;
19114   env->GetIsolate()->SetCounterFunction(LookupCounter);
19115   v8::HandleScope scope(env->GetIsolate());
19116   int initial_probes = probes_counter;
19117   int initial_misses = misses_counter;
19118   int initial_updates = updates_counter;
19119   CompileRun(kMegamorphicTestProgram);
19120   int probes = probes_counter - initial_probes;
19121   int misses = misses_counter - initial_misses;
19122   int updates = updates_counter - initial_updates;
19123   CHECK_LT(updates, 10);
19124   CHECK_LT(misses, 10);
19125   // TODO(verwaest): Update this test to overflow the degree of polymorphism
19126   // before megamorphism. The number of probes will only work once we teach the
19127   // serializer to embed references to counters in the stubs, given that the
19128   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
19129   CHECK_GE(probes, 0);
19130 #endif
19131 }
19132
19133
19134 TEST(SecondaryStubCache) {
19135   StubCacheHelper(true);
19136 }
19137
19138
19139 TEST(PrimaryStubCache) {
19140   StubCacheHelper(false);
19141 }
19142
19143
19144 #ifdef DEBUG
19145 static int cow_arrays_created_runtime = 0;
19146
19147
19148 static int* LookupCounterCOWArrays(const char* name) {
19149   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
19150     return &cow_arrays_created_runtime;
19151   }
19152   return NULL;
19153 }
19154 #endif
19155
19156
19157 TEST(CheckCOWArraysCreatedRuntimeCounter) {
19158 #ifdef DEBUG
19159   i::FLAG_native_code_counters = true;
19160   LocalContext env;
19161   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
19162   v8::HandleScope scope(env->GetIsolate());
19163   int initial_cow_arrays = cow_arrays_created_runtime;
19164   CompileRun("var o = [1, 2, 3];");
19165   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
19166   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
19167   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
19168   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
19169   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
19170 #endif
19171 }
19172
19173
19174 TEST(StaticGetters) {
19175   LocalContext context;
19176   i::Factory* factory = CcTest::i_isolate()->factory();
19177   v8::Isolate* isolate = CcTest::isolate();
19178   v8::HandleScope scope(isolate);
19179   i::Handle<i::Object> undefined_value = factory->undefined_value();
19180   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19181   i::Handle<i::Object> null_value = factory->null_value();
19182   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19183   i::Handle<i::Object> true_value = factory->true_value();
19184   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19185   i::Handle<i::Object> false_value = factory->false_value();
19186   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19187 }
19188
19189
19190 UNINITIALIZED_TEST(IsolateEmbedderData) {
19191   CcTest::DisableAutomaticDispose();
19192   v8::Isolate* isolate = v8::Isolate::New();
19193   isolate->Enter();
19194   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19195   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19196     CHECK(!isolate->GetData(slot));
19197     CHECK(!i_isolate->GetData(slot));
19198   }
19199   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19200     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
19201     isolate->SetData(slot, data);
19202   }
19203   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19204     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
19205     CHECK_EQ(data, isolate->GetData(slot));
19206     CHECK_EQ(data, i_isolate->GetData(slot));
19207   }
19208   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19209     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
19210     isolate->SetData(slot, data);
19211   }
19212   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19213     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
19214     CHECK_EQ(data, isolate->GetData(slot));
19215     CHECK_EQ(data, i_isolate->GetData(slot));
19216   }
19217   isolate->Exit();
19218   isolate->Dispose();
19219 }
19220
19221
19222 TEST(StringEmpty) {
19223   LocalContext context;
19224   i::Factory* factory = CcTest::i_isolate()->factory();
19225   v8::Isolate* isolate = CcTest::isolate();
19226   v8::HandleScope scope(isolate);
19227   i::Handle<i::Object> empty_string = factory->empty_string();
19228   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19229 }
19230
19231
19232 static int instance_checked_getter_count = 0;
19233 static void InstanceCheckedGetter(
19234     Local<String> name,
19235     const v8::PropertyCallbackInfo<v8::Value>& info) {
19236   CHECK(name->Equals(v8_str("foo")));
19237   instance_checked_getter_count++;
19238   info.GetReturnValue().Set(v8_num(11));
19239 }
19240
19241
19242 static int instance_checked_setter_count = 0;
19243 static void InstanceCheckedSetter(Local<String> name,
19244                       Local<Value> value,
19245                       const v8::PropertyCallbackInfo<void>& info) {
19246   CHECK(name->Equals(v8_str("foo")));
19247   CHECK(value->Equals(v8_num(23)));
19248   instance_checked_setter_count++;
19249 }
19250
19251
19252 static void CheckInstanceCheckedResult(int getters, int setters,
19253                                        bool expects_callbacks,
19254                                        TryCatch* try_catch) {
19255   if (expects_callbacks) {
19256     CHECK(!try_catch->HasCaught());
19257     CHECK_EQ(getters, instance_checked_getter_count);
19258     CHECK_EQ(setters, instance_checked_setter_count);
19259   } else {
19260     CHECK(try_catch->HasCaught());
19261     CHECK_EQ(0, instance_checked_getter_count);
19262     CHECK_EQ(0, instance_checked_setter_count);
19263   }
19264   try_catch->Reset();
19265 }
19266
19267
19268 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19269   instance_checked_getter_count = 0;
19270   instance_checked_setter_count = 0;
19271   TryCatch try_catch;
19272
19273   // Test path through generic runtime code.
19274   CompileRun("obj.foo");
19275   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19276   CompileRun("obj.foo = 23");
19277   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19278
19279   // Test path through generated LoadIC and StoredIC.
19280   CompileRun("function test_get(o) { o.foo; }"
19281              "test_get(obj);");
19282   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19283   CompileRun("test_get(obj);");
19284   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19285   CompileRun("test_get(obj);");
19286   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19287   CompileRun("function test_set(o) { o.foo = 23; }"
19288              "test_set(obj);");
19289   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19290   CompileRun("test_set(obj);");
19291   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19292   CompileRun("test_set(obj);");
19293   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19294
19295   // Test path through optimized code.
19296   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19297              "test_get(obj);");
19298   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19299   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19300              "test_set(obj);");
19301   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19302
19303   // Cleanup so that closures start out fresh in next check.
19304   CompileRun("%DeoptimizeFunction(test_get);"
19305              "%ClearFunctionTypeFeedback(test_get);"
19306              "%DeoptimizeFunction(test_set);"
19307              "%ClearFunctionTypeFeedback(test_set);");
19308 }
19309
19310
19311 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19312   v8::internal::FLAG_allow_natives_syntax = true;
19313   LocalContext context;
19314   v8::HandleScope scope(context->GetIsolate());
19315
19316   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19317   Local<ObjectTemplate> inst = templ->InstanceTemplate();
19318   inst->SetAccessor(v8_str("foo"),
19319                     InstanceCheckedGetter, InstanceCheckedSetter,
19320                     Handle<Value>(),
19321                     v8::DEFAULT,
19322                     v8::None,
19323                     v8::AccessorSignature::New(context->GetIsolate(), templ));
19324   context->Global()->Set(v8_str("f"), templ->GetFunction());
19325
19326   printf("Testing positive ...\n");
19327   CompileRun("var obj = new f();");
19328   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19329   CheckInstanceCheckedAccessors(true);
19330
19331   printf("Testing negative ...\n");
19332   CompileRun("var obj = {};"
19333              "obj.__proto__ = new f();");
19334   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19335   CheckInstanceCheckedAccessors(false);
19336 }
19337
19338
19339 static void EmptyInterceptorGetter(
19340     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
19341
19342
19343 static void EmptyInterceptorSetter(
19344     Local<String> name, Local<Value> value,
19345     const v8::PropertyCallbackInfo<v8::Value>& info) {}
19346
19347
19348 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19349   v8::internal::FLAG_allow_natives_syntax = true;
19350   LocalContext context;
19351   v8::HandleScope scope(context->GetIsolate());
19352
19353   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19354   Local<ObjectTemplate> inst = templ->InstanceTemplate();
19355   templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
19356                                                      EmptyInterceptorSetter);
19357   inst->SetAccessor(v8_str("foo"),
19358                     InstanceCheckedGetter, InstanceCheckedSetter,
19359                     Handle<Value>(),
19360                     v8::DEFAULT,
19361                     v8::None,
19362                     v8::AccessorSignature::New(context->GetIsolate(), templ));
19363   context->Global()->Set(v8_str("f"), templ->GetFunction());
19364
19365   printf("Testing positive ...\n");
19366   CompileRun("var obj = new f();");
19367   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19368   CheckInstanceCheckedAccessors(true);
19369
19370   printf("Testing negative ...\n");
19371   CompileRun("var obj = {};"
19372              "obj.__proto__ = new f();");
19373   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19374   CheckInstanceCheckedAccessors(false);
19375 }
19376
19377
19378 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
19379   v8::internal::FLAG_allow_natives_syntax = true;
19380   LocalContext context;
19381   v8::HandleScope scope(context->GetIsolate());
19382
19383   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19384   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
19385   proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
19386                      InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
19387                      v8::None,
19388                      v8::AccessorSignature::New(context->GetIsolate(), templ));
19389   context->Global()->Set(v8_str("f"), templ->GetFunction());
19390
19391   printf("Testing positive ...\n");
19392   CompileRun("var obj = new f();");
19393   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19394   CheckInstanceCheckedAccessors(true);
19395
19396   printf("Testing negative ...\n");
19397   CompileRun("var obj = {};"
19398              "obj.__proto__ = new f();");
19399   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19400   CheckInstanceCheckedAccessors(false);
19401
19402   printf("Testing positive with modified prototype chain ...\n");
19403   CompileRun("var obj = new f();"
19404              "var pro = {};"
19405              "pro.__proto__ = obj.__proto__;"
19406              "obj.__proto__ = pro;");
19407   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19408   CheckInstanceCheckedAccessors(true);
19409 }
19410
19411
19412 TEST(TryFinallyMessage) {
19413   LocalContext context;
19414   v8::HandleScope scope(context->GetIsolate());
19415   {
19416     // Test that the original error message is not lost if there is a
19417     // recursive call into Javascript is done in the finally block, e.g. to
19418     // initialize an IC. (crbug.com/129171)
19419     TryCatch try_catch;
19420     const char* trigger_ic =
19421         "try {                      \n"
19422         "  throw new Error('test'); \n"
19423         "} finally {                \n"
19424         "  var x = 0;               \n"
19425         "  x++;                     \n"  // Trigger an IC initialization here.
19426         "}                          \n";
19427     CompileRun(trigger_ic);
19428     CHECK(try_catch.HasCaught());
19429     Local<Message> message = try_catch.Message();
19430     CHECK(!message.IsEmpty());
19431     CHECK_EQ(2, message->GetLineNumber());
19432   }
19433
19434   {
19435     // Test that the original exception message is indeed overwritten if
19436     // a new error is thrown in the finally block.
19437     TryCatch try_catch;
19438     const char* throw_again =
19439         "try {                       \n"
19440         "  throw new Error('test');  \n"
19441         "} finally {                 \n"
19442         "  var x = 0;                \n"
19443         "  x++;                      \n"
19444         "  throw new Error('again'); \n"  // This is the new uncaught error.
19445         "}                           \n";
19446     CompileRun(throw_again);
19447     CHECK(try_catch.HasCaught());
19448     Local<Message> message = try_catch.Message();
19449     CHECK(!message.IsEmpty());
19450     CHECK_EQ(6, message->GetLineNumber());
19451   }
19452 }
19453
19454
19455 static void Helper137002(bool do_store,
19456                          bool polymorphic,
19457                          bool remove_accessor,
19458                          bool interceptor) {
19459   LocalContext context;
19460   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
19461   if (interceptor) {
19462     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
19463                                                             FooSetInterceptor));
19464   } else {
19465     templ->SetAccessor(v8_str("foo"),
19466                        GetterWhichReturns42,
19467                        SetterWhichSetsYOnThisTo23);
19468   }
19469   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19470
19471   // Turn monomorphic on slow object with native accessor, then turn
19472   // polymorphic, finally optimize to create negative lookup and fail.
19473   CompileRun(do_store ?
19474              "function f(x) { x.foo = void 0; }" :
19475              "function f(x) { return x.foo; }");
19476   CompileRun("obj.y = void 0;");
19477   if (!interceptor) {
19478     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
19479   }
19480   CompileRun("obj.__proto__ = null;"
19481              "f(obj); f(obj); f(obj);");
19482   if (polymorphic) {
19483     CompileRun("f({});");
19484   }
19485   CompileRun("obj.y = void 0;"
19486              "%OptimizeFunctionOnNextCall(f);");
19487   if (remove_accessor) {
19488     CompileRun("delete obj.foo;");
19489   }
19490   CompileRun("var result = f(obj);");
19491   if (do_store) {
19492     CompileRun("result = obj.y;");
19493   }
19494   if (remove_accessor && !interceptor) {
19495     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
19496   } else {
19497     CHECK_EQ(do_store ? 23 : 42,
19498              context->Global()->Get(v8_str("result"))->Int32Value());
19499   }
19500 }
19501
19502
19503 THREADED_TEST(Regress137002a) {
19504   i::FLAG_allow_natives_syntax = true;
19505   i::FLAG_compilation_cache = false;
19506   v8::HandleScope scope(CcTest::isolate());
19507   for (int i = 0; i < 16; i++) {
19508     Helper137002(i & 8, i & 4, i & 2, i & 1);
19509   }
19510 }
19511
19512
19513 THREADED_TEST(Regress137002b) {
19514   i::FLAG_allow_natives_syntax = true;
19515   LocalContext context;
19516   v8::Isolate* isolate = context->GetIsolate();
19517   v8::HandleScope scope(isolate);
19518   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19519   templ->SetAccessor(v8_str("foo"),
19520                      GetterWhichReturns42,
19521                      SetterWhichSetsYOnThisTo23);
19522   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19523
19524   // Turn monomorphic on slow object with native accessor, then just
19525   // delete the property and fail.
19526   CompileRun("function load(x) { return x.foo; }"
19527              "function store(x) { x.foo = void 0; }"
19528              "function keyed_load(x, key) { return x[key]; }"
19529              // Second version of function has a different source (add void 0)
19530              // so that it does not share code with the first version.  This
19531              // ensures that the ICs are monomorphic.
19532              "function load2(x) { void 0; return x.foo; }"
19533              "function store2(x) { void 0; x.foo = void 0; }"
19534              "function keyed_load2(x, key) { void 0; return x[key]; }"
19535
19536              "obj.y = void 0;"
19537              "obj.__proto__ = null;"
19538              "var subobj = {};"
19539              "subobj.y = void 0;"
19540              "subobj.__proto__ = obj;"
19541              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19542
19543              // Make the ICs monomorphic.
19544              "load(obj); load(obj);"
19545              "load2(subobj); load2(subobj);"
19546              "store(obj); store(obj);"
19547              "store2(subobj); store2(subobj);"
19548              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19549              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19550
19551              // Actually test the shiny new ICs and better not crash. This
19552              // serves as a regression test for issue 142088 as well.
19553              "load(obj);"
19554              "load2(subobj);"
19555              "store(obj);"
19556              "store2(subobj);"
19557              "keyed_load(obj, 'foo');"
19558              "keyed_load2(subobj, 'foo');"
19559
19560              // Delete the accessor.  It better not be called any more now.
19561              "delete obj.foo;"
19562              "obj.y = void 0;"
19563              "subobj.y = void 0;"
19564
19565              "var load_result = load(obj);"
19566              "var load_result2 = load2(subobj);"
19567              "var keyed_load_result = keyed_load(obj, 'foo');"
19568              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19569              "store(obj);"
19570              "store2(subobj);"
19571              "var y_from_obj = obj.y;"
19572              "var y_from_subobj = subobj.y;");
19573   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19574   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19575   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19576   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19577   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19578   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19579 }
19580
19581
19582 THREADED_TEST(Regress142088) {
19583   i::FLAG_allow_natives_syntax = true;
19584   LocalContext context;
19585   v8::Isolate* isolate = context->GetIsolate();
19586   v8::HandleScope scope(isolate);
19587   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19588   templ->SetAccessor(v8_str("foo"),
19589                      GetterWhichReturns42,
19590                      SetterWhichSetsYOnThisTo23);
19591   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19592
19593   CompileRun("function load(x) { return x.foo; }"
19594              "var o = Object.create(obj);"
19595              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19596              "load(o); load(o); load(o); load(o);");
19597 }
19598
19599
19600 THREADED_TEST(Regress3337) {
19601   LocalContext context;
19602   v8::Isolate* isolate = context->GetIsolate();
19603   v8::HandleScope scope(isolate);
19604   Local<v8::Object> o1 = Object::New(isolate);
19605   Local<v8::Object> o2 = Object::New(isolate);
19606   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
19607   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
19608   CHECK(io1->map() == io2->map());
19609   o1->SetIndexedPropertiesToExternalArrayData(
19610       NULL, v8::kExternalUint32Array, 0);
19611   o2->SetIndexedPropertiesToExternalArrayData(
19612       NULL, v8::kExternalUint32Array, 0);
19613   CHECK(io1->map() == io2->map());
19614 }
19615
19616
19617 THREADED_TEST(Regress137496) {
19618   i::FLAG_expose_gc = true;
19619   LocalContext context;
19620   v8::HandleScope scope(context->GetIsolate());
19621
19622   // Compile a try-finally clause where the finally block causes a GC
19623   // while there still is a message pending for external reporting.
19624   TryCatch try_catch;
19625   try_catch.SetVerbose(true);
19626   CompileRun("try { throw new Error(); } finally { gc(); }");
19627   CHECK(try_catch.HasCaught());
19628 }
19629
19630
19631 THREADED_TEST(Regress157124) {
19632   LocalContext context;
19633   v8::Isolate* isolate = context->GetIsolate();
19634   v8::HandleScope scope(isolate);
19635   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19636   Local<Object> obj = templ->NewInstance();
19637   obj->GetIdentityHash();
19638   obj->DeleteHiddenValue(v8_str("Bug"));
19639 }
19640
19641
19642 THREADED_TEST(Regress2535) {
19643   LocalContext context;
19644   v8::HandleScope scope(context->GetIsolate());
19645   Local<Value> set_value = CompileRun("new Set();");
19646   Local<Object> set_object(Local<Object>::Cast(set_value));
19647   CHECK_EQ(0, set_object->InternalFieldCount());
19648   Local<Value> map_value = CompileRun("new Map();");
19649   Local<Object> map_object(Local<Object>::Cast(map_value));
19650   CHECK_EQ(0, map_object->InternalFieldCount());
19651 }
19652
19653
19654 THREADED_TEST(Regress2746) {
19655   LocalContext context;
19656   v8::Isolate* isolate = context->GetIsolate();
19657   v8::HandleScope scope(isolate);
19658   Local<Object> obj = Object::New(isolate);
19659   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
19660   obj->SetHiddenValue(key, v8::Undefined(isolate));
19661   Local<Value> value = obj->GetHiddenValue(key);
19662   CHECK(!value.IsEmpty());
19663   CHECK(value->IsUndefined());
19664 }
19665
19666
19667 THREADED_TEST(Regress260106) {
19668   LocalContext context;
19669   v8::Isolate* isolate = context->GetIsolate();
19670   v8::HandleScope scope(isolate);
19671   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
19672                                                         DummyCallHandler);
19673   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19674   Local<Function> function = templ->GetFunction();
19675   CHECK(!function.IsEmpty());
19676   CHECK(function->IsFunction());
19677 }
19678
19679
19680 THREADED_TEST(JSONParseObject) {
19681   LocalContext context;
19682   HandleScope scope(context->GetIsolate());
19683   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
19684   Handle<Object> global = context->Global();
19685   global->Set(v8_str("obj"), obj);
19686   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
19687 }
19688
19689
19690 THREADED_TEST(JSONParseNumber) {
19691   LocalContext context;
19692   HandleScope scope(context->GetIsolate());
19693   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
19694   Handle<Object> global = context->Global();
19695   global->Set(v8_str("obj"), obj);
19696   ExpectString("JSON.stringify(obj)", "42");
19697 }
19698
19699
19700 #if V8_OS_POSIX && !V8_OS_NACL
19701 class ThreadInterruptTest {
19702  public:
19703   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
19704   ~ThreadInterruptTest() {}
19705
19706   void RunTest() {
19707     InterruptThread i_thread(this);
19708     i_thread.Start();
19709
19710     sem_.Wait();
19711     CHECK_EQ(kExpectedValue, sem_value_);
19712   }
19713
19714  private:
19715   static const int kExpectedValue = 1;
19716
19717   class InterruptThread : public v8::base::Thread {
19718    public:
19719     explicit InterruptThread(ThreadInterruptTest* test)
19720         : Thread(Options("InterruptThread")), test_(test) {}
19721
19722     virtual void Run() {
19723       struct sigaction action;
19724
19725       // Ensure that we'll enter waiting condition
19726       v8::base::OS::Sleep(100);
19727
19728       // Setup signal handler
19729       memset(&action, 0, sizeof(action));
19730       action.sa_handler = SignalHandler;
19731       sigaction(SIGCHLD, &action, NULL);
19732
19733       // Send signal
19734       kill(getpid(), SIGCHLD);
19735
19736       // Ensure that if wait has returned because of error
19737       v8::base::OS::Sleep(100);
19738
19739       // Set value and signal semaphore
19740       test_->sem_value_ = 1;
19741       test_->sem_.Signal();
19742     }
19743
19744     static void SignalHandler(int signal) {
19745     }
19746
19747    private:
19748      ThreadInterruptTest* test_;
19749   };
19750
19751   v8::base::Semaphore sem_;
19752   volatile int sem_value_;
19753 };
19754
19755
19756 THREADED_TEST(SemaphoreInterruption) {
19757   ThreadInterruptTest().RunTest();
19758 }
19759
19760
19761 #endif  // V8_OS_POSIX
19762
19763
19764 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19765   CHECK(false);
19766 }
19767
19768
19769 TEST(JSONStringifyAccessCheck) {
19770   v8::V8::Initialize();
19771   v8::Isolate* isolate = CcTest::isolate();
19772   v8::HandleScope scope(isolate);
19773
19774   // Create an ObjectTemplate for global objects and install access
19775   // check callbacks that will block access.
19776   v8::Handle<v8::ObjectTemplate> global_template =
19777       v8::ObjectTemplate::New(isolate);
19778   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19779
19780   // Create a context and set an x property on it's global object.
19781   LocalContext context0(NULL, global_template);
19782   v8::Handle<v8::Object> global0 = context0->Global();
19783   global0->Set(v8_str("x"), v8_num(42));
19784   ExpectString("JSON.stringify(this)", "{\"x\":42}");
19785
19786   for (int i = 0; i < 2; i++) {
19787     if (i == 1) {
19788       // Install a toJSON function on the second run.
19789       v8::Handle<v8::FunctionTemplate> toJSON =
19790           v8::FunctionTemplate::New(isolate, UnreachableCallback);
19791
19792       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19793     }
19794     // Create a context with a different security token so that the
19795     // failed access check callback will be called on each access.
19796     LocalContext context1(NULL, global_template);
19797     context1->Global()->Set(v8_str("other"), global0);
19798
19799     CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
19800     CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
19801     CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
19802
19803     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
19804     array->Set(0, v8_str("a"));
19805     array->Set(1, v8_str("b"));
19806     context1->Global()->Set(v8_str("array"), array);
19807     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
19808     array->TurnOnAccessCheck();
19809     CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
19810     CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
19811     CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
19812   }
19813 }
19814
19815
19816 bool access_check_fail_thrown = false;
19817 bool catch_callback_called = false;
19818
19819
19820 // Failed access check callback that performs a GC on each invocation.
19821 void FailedAccessCheckThrows(Local<v8::Object> target,
19822                              v8::AccessType type,
19823                              Local<v8::Value> data) {
19824   access_check_fail_thrown = true;
19825   i::PrintF("Access check failed. Error thrown.\n");
19826   CcTest::isolate()->ThrowException(
19827       v8::Exception::Error(v8_str("cross context")));
19828 }
19829
19830
19831 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19832   for (int i = 0; i < args.Length(); i++) {
19833     i::PrintF("%s\n", *String::Utf8Value(args[i]));
19834   }
19835   catch_callback_called = true;
19836 }
19837
19838
19839 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19840   args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
19841       args[1]->ToString(args.GetIsolate()));
19842 }
19843
19844
19845 void CheckCorrectThrow(const char* script) {
19846   // Test that the script, when wrapped into a try-catch, triggers the catch
19847   // clause due to failed access check throwing an exception.
19848   // The subsequent try-catch should run without any exception.
19849   access_check_fail_thrown = false;
19850   catch_callback_called = false;
19851   i::ScopedVector<char> source(1024);
19852   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19853   CompileRun(source.start());
19854   CHECK(access_check_fail_thrown);
19855   CHECK(catch_callback_called);
19856
19857   access_check_fail_thrown = false;
19858   catch_callback_called = false;
19859   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19860   CHECK(!access_check_fail_thrown);
19861   CHECK(!catch_callback_called);
19862 }
19863
19864
19865 TEST(AccessCheckThrows) {
19866   i::FLAG_allow_natives_syntax = true;
19867   v8::V8::Initialize();
19868   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19869   v8::Isolate* isolate = CcTest::isolate();
19870   v8::HandleScope scope(isolate);
19871
19872   // Create an ObjectTemplate for global objects and install access
19873   // check callbacks that will block access.
19874   v8::Handle<v8::ObjectTemplate> global_template =
19875       v8::ObjectTemplate::New(isolate);
19876   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19877
19878   // Create a context and set an x property on it's global object.
19879   LocalContext context0(NULL, global_template);
19880   v8::Handle<v8::Object> global0 = context0->Global();
19881
19882   // Create a context with a different security token so that the
19883   // failed access check callback will be called on each access.
19884   LocalContext context1(NULL, global_template);
19885   context1->Global()->Set(v8_str("other"), global0);
19886
19887   v8::Handle<v8::FunctionTemplate> catcher_fun =
19888       v8::FunctionTemplate::New(isolate, CatcherCallback);
19889   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19890
19891   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19892       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
19893   context1->Global()->Set(v8_str("has_own_property"),
19894                           has_own_property_fun->GetFunction());
19895
19896   { v8::TryCatch try_catch;
19897     access_check_fail_thrown = false;
19898     CompileRun("other.x;");
19899     CHECK(access_check_fail_thrown);
19900     CHECK(try_catch.HasCaught());
19901   }
19902
19903   CheckCorrectThrow("other.x");
19904   CheckCorrectThrow("other[1]");
19905   CheckCorrectThrow("JSON.stringify(other)");
19906   CheckCorrectThrow("has_own_property(other, 'x')");
19907   CheckCorrectThrow("%GetProperty(other, 'x')");
19908   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
19909   CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
19910   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19911   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19912   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
19913   CheckCorrectThrow("%HasProperty(other, 'x')");
19914   CheckCorrectThrow("%HasElement(other, 1)");
19915   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19916   CheckCorrectThrow("%GetPropertyNames(other)");
19917   // PROPERTY_ATTRIBUTES_NONE = 0
19918   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
19919   CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
19920                         "other, 'x', null, null, 1)");
19921
19922   // Reset the failed access check callback so it does not influence
19923   // the other tests.
19924   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19925 }
19926
19927
19928 class RequestInterruptTestBase {
19929  public:
19930   RequestInterruptTestBase()
19931       : env_(),
19932         isolate_(env_->GetIsolate()),
19933         sem_(0),
19934         warmup_(20000),
19935         should_continue_(true) {
19936   }
19937
19938   virtual ~RequestInterruptTestBase() { }
19939
19940   virtual void StartInterruptThread() = 0;
19941
19942   virtual void TestBody() = 0;
19943
19944   void RunTest() {
19945     StartInterruptThread();
19946
19947     v8::HandleScope handle_scope(isolate_);
19948
19949     TestBody();
19950
19951     // Verify we arrived here because interruptor was called
19952     // not due to a bug causing us to exit the loop too early.
19953     CHECK(!should_continue());
19954   }
19955
19956   void WakeUpInterruptor() {
19957     sem_.Signal();
19958   }
19959
19960   bool should_continue() const { return should_continue_; }
19961
19962   bool ShouldContinue() {
19963     if (warmup_ > 0) {
19964       if (--warmup_ == 0) {
19965         WakeUpInterruptor();
19966       }
19967     }
19968
19969     return should_continue_;
19970   }
19971
19972   static void ShouldContinueCallback(
19973       const v8::FunctionCallbackInfo<Value>& info) {
19974     RequestInterruptTestBase* test =
19975         reinterpret_cast<RequestInterruptTestBase*>(
19976             info.Data().As<v8::External>()->Value());
19977     info.GetReturnValue().Set(test->ShouldContinue());
19978   }
19979
19980   LocalContext env_;
19981   v8::Isolate* isolate_;
19982   v8::base::Semaphore sem_;
19983   int warmup_;
19984   bool should_continue_;
19985 };
19986
19987
19988 class RequestInterruptTestBaseWithSimpleInterrupt
19989     : public RequestInterruptTestBase {
19990  public:
19991   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
19992
19993   virtual void StartInterruptThread() {
19994     i_thread.Start();
19995   }
19996
19997  private:
19998   class InterruptThread : public v8::base::Thread {
19999    public:
20000     explicit InterruptThread(RequestInterruptTestBase* test)
20001         : Thread(Options("RequestInterruptTest")), test_(test) {}
20002
20003     virtual void Run() {
20004       test_->sem_.Wait();
20005       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
20006     }
20007
20008     static void OnInterrupt(v8::Isolate* isolate, void* data) {
20009       reinterpret_cast<RequestInterruptTestBase*>(data)->
20010           should_continue_ = false;
20011     }
20012
20013    private:
20014      RequestInterruptTestBase* test_;
20015   };
20016
20017   InterruptThread i_thread;
20018 };
20019
20020
20021 class RequestInterruptTestWithFunctionCall
20022     : public RequestInterruptTestBaseWithSimpleInterrupt {
20023  public:
20024   virtual void TestBody() {
20025     Local<Function> func = Function::New(
20026         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
20027     env_->Global()->Set(v8_str("ShouldContinue"), func);
20028
20029     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20030     CompileRun("while (ShouldContinue()) { }");
20031   }
20032 };
20033
20034
20035 class RequestInterruptTestWithMethodCall
20036     : public RequestInterruptTestBaseWithSimpleInterrupt {
20037  public:
20038   virtual void TestBody() {
20039     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20040     v8::Local<v8::Template> proto = t->PrototypeTemplate();
20041     proto->Set(v8_str("shouldContinue"), Function::New(
20042         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20043     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20044
20045     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20046     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
20047   }
20048 };
20049
20050
20051 class RequestInterruptTestWithAccessor
20052     : public RequestInterruptTestBaseWithSimpleInterrupt {
20053  public:
20054   virtual void TestBody() {
20055     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20056     v8::Local<v8::Template> proto = t->PrototypeTemplate();
20057     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
20058         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20059     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20060
20061     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20062     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
20063   }
20064 };
20065
20066
20067 class RequestInterruptTestWithNativeAccessor
20068     : public RequestInterruptTestBaseWithSimpleInterrupt {
20069  public:
20070   virtual void TestBody() {
20071     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20072     t->InstanceTemplate()->SetNativeDataProperty(
20073         v8_str("shouldContinue"),
20074         &ShouldContinueNativeGetter,
20075         NULL,
20076         v8::External::New(isolate_, this));
20077     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20078
20079     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20080     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
20081   }
20082
20083  private:
20084   static void ShouldContinueNativeGetter(
20085       Local<String> property,
20086       const v8::PropertyCallbackInfo<v8::Value>& info) {
20087     RequestInterruptTestBase* test =
20088         reinterpret_cast<RequestInterruptTestBase*>(
20089             info.Data().As<v8::External>()->Value());
20090     info.GetReturnValue().Set(test->ShouldContinue());
20091   }
20092 };
20093
20094
20095 class RequestInterruptTestWithMethodCallAndInterceptor
20096     : public RequestInterruptTestBaseWithSimpleInterrupt {
20097  public:
20098   virtual void TestBody() {
20099     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20100     v8::Local<v8::Template> proto = t->PrototypeTemplate();
20101     proto->Set(v8_str("shouldContinue"), Function::New(
20102         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20103     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
20104     instance_template->SetHandler(
20105         v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
20106
20107     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20108
20109     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20110     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
20111   }
20112
20113  private:
20114   static void EmptyInterceptor(
20115       Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
20116 };
20117
20118
20119 class RequestInterruptTestWithMathAbs
20120     : public RequestInterruptTestBaseWithSimpleInterrupt {
20121  public:
20122   virtual void TestBody() {
20123     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
20124         isolate_,
20125         WakeUpInterruptorCallback,
20126         v8::External::New(isolate_, this)));
20127
20128     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
20129         isolate_,
20130         ShouldContinueCallback,
20131         v8::External::New(isolate_, this)));
20132
20133     i::FLAG_allow_natives_syntax = true;
20134     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20135     CompileRun("function loopish(o) {"
20136                "  var pre = 10;"
20137                "  while (o.abs(1) > 0) {"
20138                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
20139                "    if (pre > 0) {"
20140                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
20141                "    }"
20142                "  }"
20143                "}"
20144                "var i = 50;"
20145                "var obj = {abs: function () { return i-- }, x: null};"
20146                "delete obj.x;"
20147                "loopish(obj);"
20148                "%OptimizeFunctionOnNextCall(loopish);"
20149                "loopish(Math);");
20150
20151     i::FLAG_allow_natives_syntax = false;
20152   }
20153
20154  private:
20155   static void WakeUpInterruptorCallback(
20156       const v8::FunctionCallbackInfo<Value>& info) {
20157     if (!info[0]->BooleanValue()) return;
20158
20159     RequestInterruptTestBase* test =
20160         reinterpret_cast<RequestInterruptTestBase*>(
20161             info.Data().As<v8::External>()->Value());
20162     test->WakeUpInterruptor();
20163   }
20164
20165   static void ShouldContinueCallback(
20166       const v8::FunctionCallbackInfo<Value>& info) {
20167     RequestInterruptTestBase* test =
20168         reinterpret_cast<RequestInterruptTestBase*>(
20169             info.Data().As<v8::External>()->Value());
20170     info.GetReturnValue().Set(test->should_continue());
20171   }
20172 };
20173
20174
20175 TEST(RequestInterruptTestWithFunctionCall) {
20176   RequestInterruptTestWithFunctionCall().RunTest();
20177 }
20178
20179
20180 TEST(RequestInterruptTestWithMethodCall) {
20181   RequestInterruptTestWithMethodCall().RunTest();
20182 }
20183
20184
20185 TEST(RequestInterruptTestWithAccessor) {
20186   RequestInterruptTestWithAccessor().RunTest();
20187 }
20188
20189
20190 TEST(RequestInterruptTestWithNativeAccessor) {
20191   RequestInterruptTestWithNativeAccessor().RunTest();
20192 }
20193
20194
20195 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
20196   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
20197 }
20198
20199
20200 TEST(RequestInterruptTestWithMathAbs) {
20201   RequestInterruptTestWithMathAbs().RunTest();
20202 }
20203
20204
20205 class RequestMultipleInterrupts : public RequestInterruptTestBase {
20206  public:
20207   RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
20208
20209   virtual void StartInterruptThread() {
20210     i_thread.Start();
20211   }
20212
20213   virtual void TestBody() {
20214     Local<Function> func = Function::New(
20215         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
20216     env_->Global()->Set(v8_str("ShouldContinue"), func);
20217
20218     i::FLAG_turbo_osr = false;  // TODO(titzer): interrupts in TF loops.
20219     CompileRun("while (ShouldContinue()) { }");
20220   }
20221
20222  private:
20223   class InterruptThread : public v8::base::Thread {
20224    public:
20225     enum { NUM_INTERRUPTS = 10 };
20226     explicit InterruptThread(RequestMultipleInterrupts* test)
20227         : Thread(Options("RequestInterruptTest")), test_(test) {}
20228
20229     virtual void Run() {
20230       test_->sem_.Wait();
20231       for (int i = 0; i < NUM_INTERRUPTS; i++) {
20232         test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
20233       }
20234     }
20235
20236     static void OnInterrupt(v8::Isolate* isolate, void* data) {
20237       RequestMultipleInterrupts* test =
20238           reinterpret_cast<RequestMultipleInterrupts*>(data);
20239       test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
20240     }
20241
20242    private:
20243     RequestMultipleInterrupts* test_;
20244   };
20245
20246   InterruptThread i_thread;
20247   int counter_;
20248 };
20249
20250
20251 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
20252
20253
20254 static Local<Value> function_new_expected_env;
20255 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
20256   CHECK(function_new_expected_env->Equals(info.Data()));
20257   info.GetReturnValue().Set(17);
20258 }
20259
20260
20261 THREADED_TEST(FunctionNew) {
20262   LocalContext env;
20263   v8::Isolate* isolate = env->GetIsolate();
20264   v8::HandleScope scope(isolate);
20265   Local<Object> data = v8::Object::New(isolate);
20266   function_new_expected_env = data;
20267   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
20268   env->Global()->Set(v8_str("func"), func);
20269   Local<Value> result = CompileRun("func();");
20270   CHECK(v8::Integer::New(isolate, 17)->Equals(result));
20271   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20272   // Verify function not cached
20273   auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
20274                                                ->shared()
20275                                                ->get_api_func_data()
20276                                                ->serial_number()),
20277                               i_isolate);
20278   auto cache = i_isolate->function_cache();
20279   CHECK(cache->Lookup(serial_number)->IsTheHole());
20280   // Verify that each Function::New creates a new function instance
20281   Local<Object> data2 = v8::Object::New(isolate);
20282   function_new_expected_env = data2;
20283   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
20284   CHECK(!func2->IsNull());
20285   CHECK(!func->Equals(func2));
20286   env->Global()->Set(v8_str("func2"), func2);
20287   Local<Value> result2 = CompileRun("func2();");
20288   CHECK(v8::Integer::New(isolate, 17)->Equals(result2));
20289 }
20290
20291
20292 TEST(EscapeableHandleScope) {
20293   HandleScope outer_scope(CcTest::isolate());
20294   LocalContext context;
20295   const int runs = 10;
20296   Local<String> values[runs];
20297   for (int i = 0; i < runs; i++) {
20298     v8::EscapableHandleScope inner_scope(CcTest::isolate());
20299     Local<String> value;
20300     if (i != 0) value = v8_str("escape value");
20301     values[i] = inner_scope.Escape(value);
20302   }
20303   for (int i = 0; i < runs; i++) {
20304     Local<String> expected;
20305     if (i != 0) {
20306       CHECK(v8_str("escape value")->Equals(values[i]));
20307     } else {
20308       CHECK(values[i].IsEmpty());
20309     }
20310   }
20311 }
20312
20313
20314 static void SetterWhichExpectsThisAndHolderToDiffer(
20315     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
20316   CHECK(info.Holder() != info.This());
20317 }
20318
20319
20320 TEST(Regress239669) {
20321   LocalContext context;
20322   v8::Isolate* isolate = context->GetIsolate();
20323   v8::HandleScope scope(isolate);
20324   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20325   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
20326   context->Global()->Set(v8_str("P"), templ->NewInstance());
20327   CompileRun(
20328       "function C1() {"
20329       "  this.x = 23;"
20330       "};"
20331       "C1.prototype = P;"
20332       "for (var i = 0; i < 4; i++ ) {"
20333       "  new C1();"
20334       "}");
20335 }
20336
20337
20338 class ApiCallOptimizationChecker {
20339  private:
20340   static Local<Object> data;
20341   static Local<Object> receiver;
20342   static Local<Object> holder;
20343   static Local<Object> callee;
20344   static int count;
20345
20346   static void OptimizationCallback(
20347       const v8::FunctionCallbackInfo<v8::Value>& info) {
20348     CHECK(callee == info.Callee());
20349     CHECK(data == info.Data());
20350     CHECK(receiver == info.This());
20351     if (info.Length() == 1) {
20352       CHECK(v8_num(1)->Equals(info[0]));
20353     }
20354     CHECK(holder == info.Holder());
20355     count++;
20356     info.GetReturnValue().Set(v8_str("returned"));
20357   }
20358
20359  public:
20360   enum SignatureType {
20361     kNoSignature,
20362     kSignatureOnReceiver,
20363     kSignatureOnPrototype
20364   };
20365
20366   void RunAll() {
20367     SignatureType signature_types[] =
20368       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
20369     for (unsigned i = 0; i < arraysize(signature_types); i++) {
20370       SignatureType signature_type = signature_types[i];
20371       for (int j = 0; j < 2; j++) {
20372         bool global = j == 0;
20373         int key = signature_type +
20374             arraysize(signature_types) * (global ? 1 : 0);
20375         Run(signature_type, global, key);
20376       }
20377     }
20378   }
20379
20380   void Run(SignatureType signature_type, bool global, int key) {
20381     v8::Isolate* isolate = CcTest::isolate();
20382     v8::HandleScope scope(isolate);
20383     // Build a template for signature checks.
20384     Local<v8::ObjectTemplate> signature_template;
20385     Local<v8::Signature> signature;
20386     {
20387       Local<v8::FunctionTemplate> parent_template =
20388         FunctionTemplate::New(isolate);
20389       parent_template->SetHiddenPrototype(true);
20390       Local<v8::FunctionTemplate> function_template
20391           = FunctionTemplate::New(isolate);
20392       function_template->Inherit(parent_template);
20393       switch (signature_type) {
20394         case kNoSignature:
20395           break;
20396         case kSignatureOnReceiver:
20397           signature = v8::Signature::New(isolate, function_template);
20398           break;
20399         case kSignatureOnPrototype:
20400           signature = v8::Signature::New(isolate, parent_template);
20401           break;
20402       }
20403       signature_template = function_template->InstanceTemplate();
20404     }
20405     // Global object must pass checks.
20406     Local<v8::Context> context =
20407         v8::Context::New(isolate, NULL, signature_template);
20408     v8::Context::Scope context_scope(context);
20409     // Install regular object that can pass signature checks.
20410     Local<Object> function_receiver = signature_template->NewInstance();
20411     context->Global()->Set(v8_str("function_receiver"), function_receiver);
20412     // Get the holder objects.
20413     Local<Object> inner_global =
20414         Local<Object>::Cast(context->Global()->GetPrototype());
20415     // Install functions on hidden prototype object if there is one.
20416     data = Object::New(isolate);
20417     Local<FunctionTemplate> function_template = FunctionTemplate::New(
20418         isolate, OptimizationCallback, data, signature);
20419     Local<Function> function = function_template->GetFunction();
20420     Local<Object> global_holder = inner_global;
20421     Local<Object> function_holder = function_receiver;
20422     if (signature_type == kSignatureOnPrototype) {
20423       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
20424       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
20425     }
20426     global_holder->Set(v8_str("g_f"), function);
20427     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
20428     function_holder->Set(v8_str("f"), function);
20429     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
20430     // Initialize expected values.
20431     callee = function;
20432     count = 0;
20433     if (global) {
20434       receiver = context->Global();
20435       holder = inner_global;
20436     } else {
20437       holder = function_receiver;
20438       // If not using a signature, add something else to the prototype chain
20439       // to test the case that holder != receiver
20440       if (signature_type == kNoSignature) {
20441         receiver = Local<Object>::Cast(CompileRun(
20442             "var receiver_subclass = {};\n"
20443             "receiver_subclass.__proto__ = function_receiver;\n"
20444             "receiver_subclass"));
20445       } else {
20446         receiver = Local<Object>::Cast(CompileRun(
20447           "var receiver_subclass = function_receiver;\n"
20448           "receiver_subclass"));
20449       }
20450     }
20451     // With no signature, the holder is not set.
20452     if (signature_type == kNoSignature) holder = receiver;
20453     // build wrap_function
20454     i::ScopedVector<char> wrap_function(200);
20455     if (global) {
20456       i::SNPrintF(
20457           wrap_function,
20458           "function wrap_f_%d() { var f = g_f; return f(); }\n"
20459           "function wrap_get_%d() { return this.g_acc; }\n"
20460           "function wrap_set_%d() { return this.g_acc = 1; }\n",
20461           key, key, key);
20462     } else {
20463       i::SNPrintF(
20464           wrap_function,
20465           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
20466           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
20467           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
20468           key, key, key);
20469     }
20470     // build source string
20471     i::ScopedVector<char> source(1000);
20472     i::SNPrintF(
20473         source,
20474         "%s\n"  // wrap functions
20475         "function wrap_f() { return wrap_f_%d(); }\n"
20476         "function wrap_get() { return wrap_get_%d(); }\n"
20477         "function wrap_set() { return wrap_set_%d(); }\n"
20478         "check = function(returned) {\n"
20479         "  if (returned !== 'returned') { throw returned; }\n"
20480         "}\n"
20481         "\n"
20482         "check(wrap_f());\n"
20483         "check(wrap_f());\n"
20484         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
20485         "check(wrap_f());\n"
20486         "\n"
20487         "check(wrap_get());\n"
20488         "check(wrap_get());\n"
20489         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
20490         "check(wrap_get());\n"
20491         "\n"
20492         "check = function(returned) {\n"
20493         "  if (returned !== 1) { throw returned; }\n"
20494         "}\n"
20495         "check(wrap_set());\n"
20496         "check(wrap_set());\n"
20497         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
20498         "check(wrap_set());\n",
20499         wrap_function.start(), key, key, key, key, key, key);
20500     v8::TryCatch try_catch;
20501     CompileRun(source.start());
20502     DCHECK(!try_catch.HasCaught());
20503     CHECK_EQ(9, count);
20504   }
20505 };
20506
20507
20508 Local<Object> ApiCallOptimizationChecker::data;
20509 Local<Object> ApiCallOptimizationChecker::receiver;
20510 Local<Object> ApiCallOptimizationChecker::holder;
20511 Local<Object> ApiCallOptimizationChecker::callee;
20512 int ApiCallOptimizationChecker::count = 0;
20513
20514
20515 TEST(FunctionCallOptimization) {
20516   i::FLAG_allow_natives_syntax = true;
20517   ApiCallOptimizationChecker checker;
20518   checker.RunAll();
20519 }
20520
20521
20522 TEST(FunctionCallOptimizationMultipleArgs) {
20523   i::FLAG_allow_natives_syntax = true;
20524   LocalContext context;
20525   v8::Isolate* isolate = context->GetIsolate();
20526   v8::HandleScope scope(isolate);
20527   Handle<Object> global = context->Global();
20528   Local<v8::Function> function = Function::New(isolate, Returns42);
20529   global->Set(v8_str("x"), function);
20530   CompileRun(
20531       "function x_wrap() {\n"
20532       "  for (var i = 0; i < 5; i++) {\n"
20533       "    x(1,2,3);\n"
20534       "  }\n"
20535       "}\n"
20536       "x_wrap();\n"
20537       "%OptimizeFunctionOnNextCall(x_wrap);"
20538       "x_wrap();\n");
20539 }
20540
20541
20542 static void ReturnsSymbolCallback(
20543     const v8::FunctionCallbackInfo<v8::Value>& info) {
20544   info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
20545 }
20546
20547
20548 TEST(ApiCallbackCanReturnSymbols) {
20549   i::FLAG_allow_natives_syntax = true;
20550   LocalContext context;
20551   v8::Isolate* isolate = context->GetIsolate();
20552   v8::HandleScope scope(isolate);
20553   Handle<Object> global = context->Global();
20554   Local<v8::Function> function = Function::New(isolate, ReturnsSymbolCallback);
20555   global->Set(v8_str("x"), function);
20556   CompileRun(
20557       "function x_wrap() {\n"
20558       "  for (var i = 0; i < 5; i++) {\n"
20559       "    x();\n"
20560       "  }\n"
20561       "}\n"
20562       "x_wrap();\n"
20563       "%OptimizeFunctionOnNextCall(x_wrap);"
20564       "x_wrap();\n");
20565 }
20566
20567
20568 TEST(EmptyApiCallback) {
20569   LocalContext context;
20570   auto isolate = context->GetIsolate();
20571   v8::HandleScope scope(isolate);
20572   auto global = context->Global();
20573   auto function = FunctionTemplate::New(isolate)->GetFunction();
20574   global->Set(v8_str("x"), function);
20575
20576   auto result = CompileRun("x()");
20577   CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20578
20579   result = CompileRun("x(1,2,3)");
20580   CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20581
20582   result = CompileRun("7 + x.call(3) + 11");
20583   CHECK(result->IsInt32());
20584   CHECK_EQ(21, result->Int32Value());
20585
20586   result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
20587   CHECK(result->IsInt32());
20588   CHECK_EQ(21, result->Int32Value());
20589
20590   result = CompileRun("var y = []; x.call(y)");
20591   CHECK(result->IsArray());
20592
20593   result = CompileRun("x.call(y, 1, 2, 3, 4)");
20594   CHECK(result->IsArray());
20595 }
20596
20597
20598 TEST(SimpleSignatureCheck) {
20599   LocalContext context;
20600   auto isolate = context->GetIsolate();
20601   v8::HandleScope scope(isolate);
20602   auto global = context->Global();
20603   auto sig_obj = FunctionTemplate::New(isolate);
20604   auto sig = v8::Signature::New(isolate, sig_obj);
20605   auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20606   global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20607   global->Set(v8_str("x"), x->GetFunction());
20608   CompileRun("var s = new sig_obj();");
20609   {
20610     TryCatch try_catch(isolate);
20611     CompileRun("x()");
20612     CHECK(try_catch.HasCaught());
20613   }
20614   {
20615     TryCatch try_catch(isolate);
20616     CompileRun("x.call(1)");
20617     CHECK(try_catch.HasCaught());
20618   }
20619   {
20620     TryCatch try_catch(isolate);
20621     auto result = CompileRun("s.x = x; s.x()");
20622     CHECK(!try_catch.HasCaught());
20623     CHECK_EQ(42, result->Int32Value());
20624   }
20625   {
20626     TryCatch try_catch(isolate);
20627     auto result = CompileRun("x.call(s)");
20628     CHECK(!try_catch.HasCaught());
20629     CHECK_EQ(42, result->Int32Value());
20630   }
20631 }
20632
20633
20634 TEST(ChainSignatureCheck) {
20635   LocalContext context;
20636   auto isolate = context->GetIsolate();
20637   v8::HandleScope scope(isolate);
20638   auto global = context->Global();
20639   auto sig_obj = FunctionTemplate::New(isolate);
20640   auto sig = v8::Signature::New(isolate, sig_obj);
20641   for (int i = 0; i < 4; ++i) {
20642     auto temp = FunctionTemplate::New(isolate);
20643     temp->Inherit(sig_obj);
20644     sig_obj = temp;
20645   }
20646   auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20647   global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20648   global->Set(v8_str("x"), x->GetFunction());
20649   CompileRun("var s = new sig_obj();");
20650   {
20651     TryCatch try_catch(isolate);
20652     CompileRun("x()");
20653     CHECK(try_catch.HasCaught());
20654   }
20655   {
20656     TryCatch try_catch(isolate);
20657     CompileRun("x.call(1)");
20658     CHECK(try_catch.HasCaught());
20659   }
20660   {
20661     TryCatch try_catch(isolate);
20662     auto result = CompileRun("s.x = x; s.x()");
20663     CHECK(!try_catch.HasCaught());
20664     CHECK_EQ(42, result->Int32Value());
20665   }
20666   {
20667     TryCatch try_catch(isolate);
20668     auto result = CompileRun("x.call(s)");
20669     CHECK(!try_catch.HasCaught());
20670     CHECK_EQ(42, result->Int32Value());
20671   }
20672 }
20673
20674
20675 TEST(PrototypeSignatureCheck) {
20676   LocalContext context;
20677   auto isolate = context->GetIsolate();
20678   v8::HandleScope scope(isolate);
20679   auto global = context->Global();
20680   auto sig_obj = FunctionTemplate::New(isolate);
20681   sig_obj->SetHiddenPrototype(true);
20682   auto sig = v8::Signature::New(isolate, sig_obj);
20683   auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20684   global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20685   global->Set(v8_str("x"), x->GetFunction());
20686   CompileRun("s = {}; s.__proto__ = new sig_obj();");
20687   {
20688     TryCatch try_catch(isolate);
20689     CompileRun("x()");
20690     CHECK(try_catch.HasCaught());
20691   }
20692   {
20693     TryCatch try_catch(isolate);
20694     CompileRun("x.call(1)");
20695     CHECK(try_catch.HasCaught());
20696   }
20697   {
20698     TryCatch try_catch(isolate);
20699     auto result = CompileRun("s.x = x; s.x()");
20700     CHECK(!try_catch.HasCaught());
20701     CHECK_EQ(42, result->Int32Value());
20702   }
20703   {
20704     TryCatch try_catch(isolate);
20705     auto result = CompileRun("x.call(s)");
20706     CHECK(!try_catch.HasCaught());
20707     CHECK_EQ(42, result->Int32Value());
20708   }
20709 }
20710
20711
20712 static const char* last_event_message;
20713 static int last_event_status;
20714 void StoringEventLoggerCallback(const char* message, int status) {
20715     last_event_message = message;
20716     last_event_status = status;
20717 }
20718
20719
20720 TEST(EventLogging) {
20721   v8::Isolate* isolate = CcTest::isolate();
20722   isolate->SetEventLogger(StoringEventLoggerCallback);
20723   v8::internal::HistogramTimer histogramTimer(
20724       "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
20725       reinterpret_cast<v8::internal::Isolate*>(isolate));
20726   histogramTimer.Start();
20727   CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20728   CHECK_EQ(0, last_event_status);
20729   histogramTimer.Stop();
20730   CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20731   CHECK_EQ(1, last_event_status);
20732 }
20733
20734
20735 TEST(Promises) {
20736   LocalContext context;
20737   v8::Isolate* isolate = context->GetIsolate();
20738   v8::HandleScope scope(isolate);
20739   Handle<Object> global = context->Global();
20740
20741   // Creation.
20742   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20743   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
20744   Handle<v8::Promise> p = pr->GetPromise();
20745   Handle<v8::Promise> r = rr->GetPromise();
20746   CHECK_EQ(isolate, p->GetIsolate());
20747
20748   // IsPromise predicate.
20749   CHECK(p->IsPromise());
20750   CHECK(r->IsPromise());
20751   Handle<Value> o = v8::Object::New(isolate);
20752   CHECK(!o->IsPromise());
20753
20754   // Resolution and rejection.
20755   pr->Resolve(v8::Integer::New(isolate, 1));
20756   CHECK(p->IsPromise());
20757   rr->Reject(v8::Integer::New(isolate, 2));
20758   CHECK(r->IsPromise());
20759
20760   // Chaining non-pending promises.
20761   CompileRun(
20762       "var x1 = 0;\n"
20763       "var x2 = 0;\n"
20764       "function f1(x) { x1 = x; return x+1 };\n"
20765       "function f2(x) { x2 = x; return x+1 };\n");
20766   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20767   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20768
20769   p->Chain(f1);
20770   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20771   isolate->RunMicrotasks();
20772   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20773
20774   p->Catch(f2);
20775   isolate->RunMicrotasks();
20776   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20777
20778   r->Catch(f2);
20779   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20780   isolate->RunMicrotasks();
20781   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20782
20783   r->Chain(f1);
20784   isolate->RunMicrotasks();
20785   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20786
20787   // Chaining pending promises.
20788   CompileRun("x1 = x2 = 0;");
20789   pr = v8::Promise::Resolver::New(isolate);
20790   rr = v8::Promise::Resolver::New(isolate);
20791
20792   pr->GetPromise()->Chain(f1);
20793   rr->GetPromise()->Catch(f2);
20794   isolate->RunMicrotasks();
20795   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20796   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20797
20798   pr->Resolve(v8::Integer::New(isolate, 1));
20799   rr->Reject(v8::Integer::New(isolate, 2));
20800   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20801   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20802
20803   isolate->RunMicrotasks();
20804   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20805   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20806
20807   // Multi-chaining.
20808   CompileRun("x1 = x2 = 0;");
20809   pr = v8::Promise::Resolver::New(isolate);
20810   pr->GetPromise()->Chain(f1)->Chain(f2);
20811   pr->Resolve(v8::Integer::New(isolate, 3));
20812   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20813   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20814   isolate->RunMicrotasks();
20815   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20816   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20817
20818   CompileRun("x1 = x2 = 0;");
20819   rr = v8::Promise::Resolver::New(isolate);
20820   rr->GetPromise()->Catch(f1)->Chain(f2);
20821   rr->Reject(v8::Integer::New(isolate, 3));
20822   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20823   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20824   isolate->RunMicrotasks();
20825   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20826   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20827 }
20828
20829
20830 TEST(PromiseThen) {
20831   LocalContext context;
20832   v8::Isolate* isolate = context->GetIsolate();
20833   v8::HandleScope scope(isolate);
20834   Handle<Object> global = context->Global();
20835
20836   // Creation.
20837   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20838   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
20839   Handle<v8::Promise> p = pr->GetPromise();
20840   Handle<v8::Promise> q = qr->GetPromise();
20841
20842   CHECK(p->IsPromise());
20843   CHECK(q->IsPromise());
20844
20845   pr->Resolve(v8::Integer::New(isolate, 1));
20846   qr->Resolve(p);
20847
20848   // Chaining non-pending promises.
20849   CompileRun(
20850       "var x1 = 0;\n"
20851       "var x2 = 0;\n"
20852       "function f1(x) { x1 = x; return x+1 };\n"
20853       "function f2(x) { x2 = x; return x+1 };\n");
20854   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20855   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20856
20857   // Chain
20858   q->Chain(f1);
20859   CHECK(global->Get(v8_str("x1"))->IsNumber());
20860   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20861   isolate->RunMicrotasks();
20862   CHECK(!global->Get(v8_str("x1"))->IsNumber());
20863   CHECK(p->Equals(global->Get(v8_str("x1"))));
20864
20865   // Then
20866   CompileRun("x1 = x2 = 0;");
20867   q->Then(f1);
20868   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20869   isolate->RunMicrotasks();
20870   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20871
20872   // Then
20873   CompileRun("x1 = x2 = 0;");
20874   pr = v8::Promise::Resolver::New(isolate);
20875   qr = v8::Promise::Resolver::New(isolate);
20876
20877   qr->Resolve(pr);
20878   qr->GetPromise()->Then(f1)->Then(f2);
20879
20880   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20881   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20882   isolate->RunMicrotasks();
20883   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20884   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20885
20886   pr->Resolve(v8::Integer::New(isolate, 3));
20887
20888   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20889   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20890   isolate->RunMicrotasks();
20891   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20892   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20893 }
20894
20895
20896 TEST(DisallowJavascriptExecutionScope) {
20897   LocalContext context;
20898   v8::Isolate* isolate = context->GetIsolate();
20899   v8::HandleScope scope(isolate);
20900   v8::Isolate::DisallowJavascriptExecutionScope no_js(
20901       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20902   CompileRun("2+2");
20903 }
20904
20905
20906 TEST(AllowJavascriptExecutionScope) {
20907   LocalContext context;
20908   v8::Isolate* isolate = context->GetIsolate();
20909   v8::HandleScope scope(isolate);
20910   v8::Isolate::DisallowJavascriptExecutionScope no_js(
20911       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20912   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20913       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20914   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
20915     CompileRun("1+1");
20916   }
20917 }
20918
20919
20920 TEST(ThrowOnJavascriptExecution) {
20921   LocalContext context;
20922   v8::Isolate* isolate = context->GetIsolate();
20923   v8::HandleScope scope(isolate);
20924   v8::TryCatch try_catch;
20925   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20926       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20927   CompileRun("1+1");
20928   CHECK(try_catch.HasCaught());
20929 }
20930
20931
20932 TEST(Regress354123) {
20933   LocalContext current;
20934   v8::Isolate* isolate = current->GetIsolate();
20935   v8::HandleScope scope(isolate);
20936
20937   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
20938   templ->SetAccessCheckCallbacks(AccessCounter, NULL);
20939   current->Global()->Set(v8_str("friend"), templ->NewInstance());
20940
20941   // Test access using __proto__ from the prototype chain.
20942   access_count = 0;
20943   CompileRun("friend.__proto__ = {};");
20944   CHECK_EQ(2, access_count);
20945   CompileRun("friend.__proto__;");
20946   CHECK_EQ(4, access_count);
20947
20948   // Test access using __proto__ as a hijacked function (A).
20949   access_count = 0;
20950   CompileRun("var p = Object.prototype;"
20951              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
20952              "f.call(friend, {});");
20953   CHECK_EQ(1, access_count);
20954   CompileRun("var p = Object.prototype;"
20955              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
20956              "f.call(friend);");
20957   CHECK_EQ(2, access_count);
20958
20959   // Test access using __proto__ as a hijacked function (B).
20960   access_count = 0;
20961   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
20962              "f.call(friend, {});");
20963   CHECK_EQ(1, access_count);
20964   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
20965              "f.call(friend);");
20966   CHECK_EQ(2, access_count);
20967
20968   // Test access using Object.setPrototypeOf reflective method.
20969   access_count = 0;
20970   CompileRun("Object.setPrototypeOf(friend, {});");
20971   CHECK_EQ(1, access_count);
20972   CompileRun("Object.getPrototypeOf(friend);");
20973   CHECK_EQ(2, access_count);
20974 }
20975
20976
20977 TEST(CaptureStackTraceForStackOverflow) {
20978   v8::internal::FLAG_stack_size = 150;
20979   LocalContext current;
20980   v8::Isolate* isolate = current->GetIsolate();
20981   v8::HandleScope scope(isolate);
20982   V8::SetCaptureStackTraceForUncaughtExceptions(
20983       true, 10, v8::StackTrace::kDetailed);
20984   v8::TryCatch try_catch;
20985   CompileRun("(function f(x) { f(x+1); })(0)");
20986   CHECK(try_catch.HasCaught());
20987 }
20988
20989
20990 TEST(ScriptNameAndLineNumber) {
20991   LocalContext env;
20992   v8::Isolate* isolate = env->GetIsolate();
20993   v8::HandleScope scope(isolate);
20994   const char* url = "http://www.foo.com/foo.js";
20995   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
20996   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
20997   Local<Script> script = v8::ScriptCompiler::Compile(
20998       isolate, &script_source);
20999   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
21000   CHECK(!script_name.IsEmpty());
21001   CHECK(script_name->IsString());
21002   String::Utf8Value utf8_name(script_name);
21003   CHECK_EQ(0, strcmp(url, *utf8_name));
21004   int line_number = script->GetUnboundScript()->GetLineNumber(0);
21005   CHECK_EQ(13, line_number);
21006 }
21007
21008 void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
21009                         const char* expected_source_mapping_url) {
21010   if (expected_source_url != NULL) {
21011     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
21012     CHECK_EQ(0, strcmp(expected_source_url, *url));
21013   } else {
21014     CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
21015   }
21016   if (expected_source_mapping_url != NULL) {
21017     v8::String::Utf8Value url(
21018         script->GetUnboundScript()->GetSourceMappingURL());
21019     CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
21020   } else {
21021     CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
21022   }
21023 }
21024
21025 void SourceURLHelper(const char* source, const char* expected_source_url,
21026                      const char* expected_source_mapping_url) {
21027   Local<Script> script = v8_compile(source);
21028   CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
21029 }
21030
21031
21032 TEST(ScriptSourceURLAndSourceMappingURL) {
21033   LocalContext env;
21034   v8::Isolate* isolate = env->GetIsolate();
21035   v8::HandleScope scope(isolate);
21036   SourceURLHelper("function foo() {}\n"
21037                   "//# sourceURL=bar1.js\n", "bar1.js", NULL);
21038   SourceURLHelper("function foo() {}\n"
21039                   "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
21040
21041   // Both sourceURL and sourceMappingURL.
21042   SourceURLHelper("function foo() {}\n"
21043                   "//# sourceURL=bar3.js\n"
21044                   "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
21045
21046   // Two source URLs; the first one is ignored.
21047   SourceURLHelper("function foo() {}\n"
21048                   "//# sourceURL=ignoreme.js\n"
21049                   "//# sourceURL=bar5.js\n", "bar5.js", NULL);
21050   SourceURLHelper("function foo() {}\n"
21051                   "//# sourceMappingURL=ignoreme.js\n"
21052                   "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
21053
21054   // SourceURL or sourceMappingURL in the middle of the script.
21055   SourceURLHelper("function foo() {}\n"
21056                   "//# sourceURL=bar7.js\n"
21057                   "function baz() {}\n", "bar7.js", NULL);
21058   SourceURLHelper("function foo() {}\n"
21059                   "//# sourceMappingURL=bar8.js\n"
21060                   "function baz() {}\n", NULL, "bar8.js");
21061
21062   // Too much whitespace.
21063   SourceURLHelper("function foo() {}\n"
21064                   "//#  sourceURL=bar9.js\n"
21065                   "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
21066   SourceURLHelper("function foo() {}\n"
21067                   "//# sourceURL =bar11.js\n"
21068                   "//# sourceMappingURL =bar12.js\n", NULL, NULL);
21069
21070   // Disallowed characters in value.
21071   SourceURLHelper("function foo() {}\n"
21072                   "//# sourceURL=bar13 .js   \n"
21073                   "//# sourceMappingURL=bar14 .js \n",
21074                   NULL, NULL);
21075   SourceURLHelper("function foo() {}\n"
21076                   "//# sourceURL=bar15\t.js   \n"
21077                   "//# sourceMappingURL=bar16\t.js \n",
21078                   NULL, NULL);
21079   SourceURLHelper("function foo() {}\n"
21080                   "//# sourceURL=bar17'.js   \n"
21081                   "//# sourceMappingURL=bar18'.js \n",
21082                   NULL, NULL);
21083   SourceURLHelper("function foo() {}\n"
21084                   "//# sourceURL=bar19\".js   \n"
21085                   "//# sourceMappingURL=bar20\".js \n",
21086                   NULL, NULL);
21087
21088   // Not too much whitespace.
21089   SourceURLHelper("function foo() {}\n"
21090                   "//# sourceURL=  bar21.js   \n"
21091                   "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
21092 }
21093
21094
21095 TEST(GetOwnPropertyDescriptor) {
21096   LocalContext env;
21097   v8::Isolate* isolate = env->GetIsolate();
21098   v8::HandleScope scope(isolate);
21099   CompileRun(
21100     "var x = { value : 13};"
21101     "Object.defineProperty(x, 'p0', {value : 12});"
21102     "Object.defineProperty(x, 'p1', {"
21103     "  set : function(value) { this.value = value; },"
21104     "  get : function() { return this.value; },"
21105     "});");
21106   Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
21107   Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
21108   CHECK(desc->IsUndefined());
21109   desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
21110   CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
21111   desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
21112   Local<Function> set =
21113     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
21114   Local<Function> get =
21115     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
21116   CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
21117   Handle<Value> args[] = { v8_num(14) };
21118   set->Call(x, 1, args);
21119   CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
21120 }
21121
21122
21123 TEST(Regress411877) {
21124   v8::Isolate* isolate = CcTest::isolate();
21125   v8::HandleScope handle_scope(isolate);
21126   v8::Handle<v8::ObjectTemplate> object_template =
21127       v8::ObjectTemplate::New(isolate);
21128   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
21129
21130   v8::Handle<Context> context = Context::New(isolate);
21131   v8::Context::Scope context_scope(context);
21132
21133   context->Global()->Set(v8_str("o"), object_template->NewInstance());
21134   CompileRun("Object.getOwnPropertyNames(o)");
21135 }
21136
21137
21138 TEST(GetHiddenPropertyTableAfterAccessCheck) {
21139   v8::Isolate* isolate = CcTest::isolate();
21140   v8::HandleScope handle_scope(isolate);
21141   v8::Handle<v8::ObjectTemplate> object_template =
21142       v8::ObjectTemplate::New(isolate);
21143   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
21144
21145   v8::Handle<Context> context = Context::New(isolate);
21146   v8::Context::Scope context_scope(context);
21147
21148   v8::Handle<v8::Object> obj = object_template->NewInstance();
21149   obj->Set(v8_str("key"), v8_str("value"));
21150   obj->Delete(v8_str("key"));
21151
21152   obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
21153 }
21154
21155
21156 TEST(Regress411793) {
21157   v8::Isolate* isolate = CcTest::isolate();
21158   v8::HandleScope handle_scope(isolate);
21159   v8::Handle<v8::ObjectTemplate> object_template =
21160       v8::ObjectTemplate::New(isolate);
21161   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
21162
21163   v8::Handle<Context> context = Context::New(isolate);
21164   v8::Context::Scope context_scope(context);
21165
21166   context->Global()->Set(v8_str("o"), object_template->NewInstance());
21167   CompileRun(
21168       "Object.defineProperty(o, 'key', "
21169       "    { get: function() {}, set: function() {} });");
21170 }
21171
21172 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
21173  public:
21174   explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
21175
21176   virtual size_t GetMoreData(const uint8_t** src) {
21177     // Unlike in real use cases, this function will never block.
21178     if (chunks_[index_] == NULL) {
21179       return 0;
21180     }
21181     // Copy the data, since the caller takes ownership of it.
21182     size_t len = strlen(chunks_[index_]);
21183     // We don't need to zero-terminate since we return the length.
21184     uint8_t* copy = new uint8_t[len];
21185     memcpy(copy, chunks_[index_], len);
21186     *src = copy;
21187     ++index_;
21188     return len;
21189   }
21190
21191   // Helper for constructing a string from chunks (the compilation needs it
21192   // too).
21193   static char* FullSourceString(const char** chunks) {
21194     size_t total_len = 0;
21195     for (size_t i = 0; chunks[i] != NULL; ++i) {
21196       total_len += strlen(chunks[i]);
21197     }
21198     char* full_string = new char[total_len + 1];
21199     size_t offset = 0;
21200     for (size_t i = 0; chunks[i] != NULL; ++i) {
21201       size_t len = strlen(chunks[i]);
21202       memcpy(full_string + offset, chunks[i], len);
21203       offset += len;
21204     }
21205     full_string[total_len] = 0;
21206     return full_string;
21207   }
21208
21209  private:
21210   const char** chunks_;
21211   unsigned index_;
21212 };
21213
21214
21215 // Helper function for running streaming tests.
21216 void RunStreamingTest(const char** chunks,
21217                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
21218                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
21219                       bool expected_success = true,
21220                       const char* expected_source_url = NULL,
21221                       const char* expected_source_mapping_url = NULL) {
21222   LocalContext env;
21223   v8::Isolate* isolate = env->GetIsolate();
21224   v8::HandleScope scope(isolate);
21225   v8::TryCatch try_catch;
21226
21227   v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
21228                                             encoding);
21229   v8::ScriptCompiler::ScriptStreamingTask* task =
21230       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21231
21232   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21233   // task here in the main thread.
21234   task->Run();
21235   delete task;
21236
21237   // Possible errors are only produced while compiling.
21238   CHECK_EQ(false, try_catch.HasCaught());
21239
21240   v8::ScriptOrigin origin(v8_str("http://foo.com"));
21241   char* full_source = TestSourceStream::FullSourceString(chunks);
21242   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21243       isolate, &source, v8_str(full_source), origin);
21244   if (expected_success) {
21245     CHECK(!script.IsEmpty());
21246     v8::Handle<Value> result(script->Run());
21247     // All scripts are supposed to return the fixed value 13 when ran.
21248     CHECK_EQ(13, result->Int32Value());
21249     CheckMagicComments(script, expected_source_url,
21250                        expected_source_mapping_url);
21251   } else {
21252     CHECK(script.IsEmpty());
21253     CHECK(try_catch.HasCaught());
21254   }
21255   delete[] full_source;
21256 }
21257
21258
21259 TEST(StreamingSimpleScript) {
21260   // This script is unrealistically small, since no one chunk is enough to fill
21261   // the backing buffer of Scanner, let alone overflow it.
21262   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21263                           NULL};
21264   RunStreamingTest(chunks);
21265 }
21266
21267
21268 TEST(StreamingBiggerScript) {
21269   const char* chunk1 =
21270       "function foo() {\n"
21271       "  // Make this chunk sufficiently long so that it will overflow the\n"
21272       "  // backing buffer of the Scanner.\n"
21273       "  var i = 0;\n"
21274       "  var result = 0;\n"
21275       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21276       "  result = 0;\n"
21277       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21278       "  result = 0;\n"
21279       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21280       "  result = 0;\n"
21281       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21282       "  return result;\n"
21283       "}\n";
21284   const char* chunks[] = {chunk1, "foo(); ", NULL};
21285   RunStreamingTest(chunks);
21286 }
21287
21288
21289 TEST(StreamingScriptWithParseError) {
21290   // Test that parse errors from streamed scripts are propagated correctly.
21291   {
21292     char chunk1[] =
21293         "  // This will result in a parse error.\n"
21294         "  var if else then foo";
21295     char chunk2[] = "  13\n";
21296     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21297
21298     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
21299                      false);
21300   }
21301   // Test that the next script succeeds normally.
21302   {
21303     char chunk1[] =
21304         "  // This will be parsed successfully.\n"
21305         "  function foo() { return ";
21306     char chunk2[] = "  13; }\n";
21307     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21308
21309     RunStreamingTest(chunks);
21310   }
21311 }
21312
21313
21314 TEST(StreamingUtf8Script) {
21315   // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
21316   // don't like it.
21317   const char* chunk1 =
21318       "function foo() {\n"
21319       "  // This function will contain an UTF-8 character which is not in\n"
21320       "  // ASCII.\n"
21321       "  var foob\xec\x92\x81r = 13;\n"
21322       "  return foob\xec\x92\x81r;\n"
21323       "}\n";
21324   const char* chunks[] = {chunk1, "foo(); ", NULL};
21325   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21326 }
21327
21328
21329 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
21330   // A sanity check to prove that the approach of splitting UTF-8
21331   // characters is correct. Here is an UTF-8 character which will take three
21332   // bytes.
21333   const char* reference = "\xec\x92\x81";
21334   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
21335
21336   char chunk1[] =
21337       "function foo() {\n"
21338       "  // This function will contain an UTF-8 character which is not in\n"
21339       "  // ASCII.\n"
21340       "  var foob";
21341   char chunk2[] =
21342       "XXXr = 13;\n"
21343       "  return foob\xec\x92\x81r;\n"
21344       "}\n";
21345   for (int i = 0; i < 3; ++i) {
21346     chunk2[i] = reference[i];
21347   }
21348   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21349   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21350 }
21351
21352
21353 TEST(StreamingUtf8ScriptWithSplitCharacters) {
21354   // Stream data where a multi-byte UTF-8 character is split between two data
21355   // chunks.
21356   const char* reference = "\xec\x92\x81";
21357   char chunk1[] =
21358       "function foo() {\n"
21359       "  // This function will contain an UTF-8 character which is not in\n"
21360       "  // ASCII.\n"
21361       "  var foobX";
21362   char chunk2[] =
21363       "XXr = 13;\n"
21364       "  return foob\xec\x92\x81r;\n"
21365       "}\n";
21366   chunk1[strlen(chunk1) - 1] = reference[0];
21367   chunk2[0] = reference[1];
21368   chunk2[1] = reference[2];
21369   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21370   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21371 }
21372
21373
21374 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
21375   // Tests edge cases which should still be decoded correctly.
21376
21377   // Case 1: a chunk contains only bytes for a split character (and no other
21378   // data). This kind of a chunk would be exceptionally small, but we should
21379   // still decode it correctly.
21380   const char* reference = "\xec\x92\x81";
21381   // The small chunk is at the beginning of the split character
21382   {
21383     char chunk1[] =
21384         "function foo() {\n"
21385         "  // This function will contain an UTF-8 character which is not in\n"
21386         "  // ASCII.\n"
21387         "  var foob";
21388     char chunk2[] = "XX";
21389     char chunk3[] =
21390         "Xr = 13;\n"
21391         "  return foob\xec\x92\x81r;\n"
21392         "}\n";
21393     chunk2[0] = reference[0];
21394     chunk2[1] = reference[1];
21395     chunk3[0] = reference[2];
21396     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21397     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21398   }
21399   // The small chunk is at the end of a character
21400   {
21401     char chunk1[] =
21402         "function foo() {\n"
21403         "  // This function will contain an UTF-8 character which is not in\n"
21404         "  // ASCII.\n"
21405         "  var foobX";
21406     char chunk2[] = "XX";
21407     char chunk3[] =
21408         "r = 13;\n"
21409         "  return foob\xec\x92\x81r;\n"
21410         "}\n";
21411     chunk1[strlen(chunk1) - 1] = reference[0];
21412     chunk2[0] = reference[1];
21413     chunk2[1] = reference[2];
21414     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21415     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21416   }
21417   // Case 2: the script ends with a multi-byte character. Make sure that it's
21418   // decoded correctly and not just ignored.
21419   {
21420     char chunk1[] =
21421         "var foob\xec\x92\x81 = 13;\n"
21422         "foob\xec\x92\x81";
21423     const char* chunks[] = {chunk1, NULL};
21424     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21425   }
21426 }
21427
21428
21429 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
21430   // Test cases where a UTF-8 character is split over several chunks. Those
21431   // cases are not supported (the embedder should give the data in big enough
21432   // chunks), but we shouldn't crash, just produce a parse error.
21433   const char* reference = "\xec\x92\x81";
21434   char chunk1[] =
21435       "function foo() {\n"
21436       "  // This function will contain an UTF-8 character which is not in\n"
21437       "  // ASCII.\n"
21438       "  var foobX";
21439   char chunk2[] = "X";
21440   char chunk3[] =
21441       "Xr = 13;\n"
21442       "  return foob\xec\x92\x81r;\n"
21443       "}\n";
21444   chunk1[strlen(chunk1) - 1] = reference[0];
21445   chunk2[0] = reference[1];
21446   chunk3[0] = reference[2];
21447   const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21448
21449   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21450 }
21451
21452
21453 TEST(StreamingProducesParserCache) {
21454   i::FLAG_min_preparse_length = 0;
21455   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21456                           NULL};
21457
21458   LocalContext env;
21459   v8::Isolate* isolate = env->GetIsolate();
21460   v8::HandleScope scope(isolate);
21461
21462   v8::ScriptCompiler::StreamedSource source(
21463       new TestSourceStream(chunks),
21464       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21465   v8::ScriptCompiler::ScriptStreamingTask* task =
21466       v8::ScriptCompiler::StartStreamingScript(
21467           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21468
21469   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21470   // task here in the main thread.
21471   task->Run();
21472   delete task;
21473
21474   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
21475   CHECK(cached_data != NULL);
21476   CHECK(cached_data->data != NULL);
21477   CHECK(!cached_data->rejected);
21478   CHECK_GT(cached_data->length, 0);
21479 }
21480
21481
21482 TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
21483   // If the debugger is active, we should just not produce parser cache at
21484   // all. This is a regeression test: We used to produce a parser cache without
21485   // any data in it (just headers).
21486   i::FLAG_min_preparse_length = 0;
21487   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21488                           NULL};
21489
21490   LocalContext env;
21491   v8::Isolate* isolate = env->GetIsolate();
21492   v8::HandleScope scope(isolate);
21493
21494   // Make the debugger active by setting a breakpoint.
21495   CompileRun("function break_here() { }");
21496   i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
21497       v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
21498   v8::internal::Debug* debug = CcTest::i_isolate()->debug();
21499   int position = 0;
21500   debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
21501                                                   CcTest::i_isolate()),
21502                        &position);
21503
21504   v8::ScriptCompiler::StreamedSource source(
21505       new TestSourceStream(chunks),
21506       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21507   v8::ScriptCompiler::ScriptStreamingTask* task =
21508       v8::ScriptCompiler::StartStreamingScript(
21509           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21510
21511   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21512   // task here in the main thread.
21513   task->Run();
21514   delete task;
21515
21516   // Check that we got no cached data.
21517   CHECK(source.GetCachedData() == NULL);
21518 }
21519
21520
21521 TEST(StreamingScriptWithInvalidUtf8) {
21522   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
21523   // chunk don't produce a crash.
21524   const char* reference = "\xec\x92\x81\x80\x80";
21525   char chunk1[] =
21526       "function foo() {\n"
21527       "  // This function will contain an UTF-8 character which is not in\n"
21528       "  // ASCII.\n"
21529       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
21530   char chunk2[] =
21531       "r = 13;\n"
21532       "  return foob\xec\x92\x81\x80\x80r;\n"
21533       "}\n";
21534   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
21535
21536   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21537   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21538 }
21539
21540
21541 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
21542   // Regression test: Stream data where there are several multi-byte UTF-8
21543   // characters in a sequence and one of them is split between two data chunks.
21544   const char* reference = "\xec\x92\x81";
21545   char chunk1[] =
21546       "function foo() {\n"
21547       "  // This function will contain an UTF-8 character which is not in\n"
21548       "  // ASCII.\n"
21549       "  var foob\xec\x92\x81X";
21550   char chunk2[] =
21551       "XXr = 13;\n"
21552       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
21553       "}\n";
21554   chunk1[strlen(chunk1) - 1] = reference[0];
21555   chunk2[0] = reference[1];
21556   chunk2[1] = reference[2];
21557   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21558   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21559 }
21560
21561
21562 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
21563   // Another regression test, similar to the previous one. The difference is
21564   // that the split character is not the last one in the sequence.
21565   const char* reference = "\xec\x92\x81";
21566   char chunk1[] =
21567       "function foo() {\n"
21568       "  // This function will contain an UTF-8 character which is not in\n"
21569       "  // ASCII.\n"
21570       "  var foobX";
21571   char chunk2[] =
21572       "XX\xec\x92\x81r = 13;\n"
21573       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
21574       "}\n";
21575   chunk1[strlen(chunk1) - 1] = reference[0];
21576   chunk2[0] = reference[1];
21577   chunk2[1] = reference[2];
21578   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21579   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21580 }
21581
21582
21583 TEST(StreamingWithHarmonyScopes) {
21584   // Don't use RunStreamingTest here so that both scripts get to use the same
21585   // LocalContext and HandleScope.
21586   LocalContext env;
21587   v8::Isolate* isolate = env->GetIsolate();
21588   v8::HandleScope scope(isolate);
21589
21590   // First, run a script with a let variable.
21591   CompileRun("\"use strict\"; let x = 1;");
21592
21593   // Then stream a script which (erroneously) tries to introduce the same
21594   // variable again.
21595   const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
21596
21597   v8::TryCatch try_catch;
21598   v8::ScriptCompiler::StreamedSource source(
21599       new TestSourceStream(chunks),
21600       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21601   v8::ScriptCompiler::ScriptStreamingTask* task =
21602       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21603   task->Run();
21604   delete task;
21605
21606   // Parsing should succeed (the script will be parsed and compiled in a context
21607   // independent way, so the error is not detected).
21608   CHECK_EQ(false, try_catch.HasCaught());
21609
21610   v8::ScriptOrigin origin(v8_str("http://foo.com"));
21611   char* full_source = TestSourceStream::FullSourceString(chunks);
21612   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21613       isolate, &source, v8_str(full_source), origin);
21614   CHECK(!script.IsEmpty());
21615   CHECK_EQ(false, try_catch.HasCaught());
21616
21617   // Running the script exposes the error.
21618   v8::Handle<Value> result(script->Run());
21619   CHECK(result.IsEmpty());
21620   CHECK(try_catch.HasCaught());
21621   delete[] full_source;
21622 }
21623
21624
21625 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
21626   const char* garbage = "garbage garbage garbage garbage garbage garbage";
21627   const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
21628   int length = 16;
21629   v8::ScriptCompiler::CachedData* cached_data =
21630       new v8::ScriptCompiler::CachedData(data, length);
21631   DCHECK(!cached_data->rejected);
21632   v8::ScriptOrigin origin(v8_str("origin"));
21633   v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
21634   v8::Handle<v8::Script> script =
21635       v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
21636   CHECK(cached_data->rejected);
21637   CHECK_EQ(42, script->Run()->Int32Value());
21638 }
21639
21640
21641 TEST(InvalidCacheData) {
21642   v8::V8::Initialize();
21643   v8::HandleScope scope(CcTest::isolate());
21644   LocalContext context;
21645   TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
21646   TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
21647 }
21648
21649
21650 TEST(ParserCacheRejectedGracefully) {
21651   i::FLAG_min_preparse_length = 0;
21652   v8::V8::Initialize();
21653   v8::HandleScope scope(CcTest::isolate());
21654   LocalContext context;
21655   // Produce valid cached data.
21656   v8::ScriptOrigin origin(v8_str("origin"));
21657   v8::Local<v8::String> source_str = v8_str("function foo() {}");
21658   v8::ScriptCompiler::Source source(source_str, origin);
21659   v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
21660       CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
21661   CHECK(!script.IsEmpty());
21662   const v8::ScriptCompiler::CachedData* original_cached_data =
21663       source.GetCachedData();
21664   CHECK(original_cached_data != NULL);
21665   CHECK(original_cached_data->data != NULL);
21666   CHECK(!original_cached_data->rejected);
21667   CHECK_GT(original_cached_data->length, 0);
21668   // Recompiling the same script with it won't reject the data.
21669   {
21670     v8::ScriptCompiler::Source source_with_cached_data(
21671         source_str, origin,
21672         new v8::ScriptCompiler::CachedData(original_cached_data->data,
21673                                            original_cached_data->length));
21674     v8::Handle<v8::Script> script =
21675         v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21676                                     v8::ScriptCompiler::kConsumeParserCache);
21677     CHECK(!script.IsEmpty());
21678     const v8::ScriptCompiler::CachedData* new_cached_data =
21679         source_with_cached_data.GetCachedData();
21680     CHECK(new_cached_data != NULL);
21681     CHECK(!new_cached_data->rejected);
21682   }
21683   // Compile an incompatible script with the cached data. The new script doesn't
21684   // have the same starting position for the function as the old one, so the old
21685   // cached data will be incompatible with it and will be rejected.
21686   {
21687     v8::Local<v8::String> incompatible_source_str =
21688         v8_str("   function foo() {}");
21689     v8::ScriptCompiler::Source source_with_cached_data(
21690         incompatible_source_str, origin,
21691         new v8::ScriptCompiler::CachedData(original_cached_data->data,
21692                                            original_cached_data->length));
21693     v8::Handle<v8::Script> script =
21694         v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21695                                     v8::ScriptCompiler::kConsumeParserCache);
21696     CHECK(!script.IsEmpty());
21697     const v8::ScriptCompiler::CachedData* new_cached_data =
21698         source_with_cached_data.GetCachedData();
21699     CHECK(new_cached_data != NULL);
21700     CHECK(new_cached_data->rejected);
21701   }
21702 }
21703
21704
21705 TEST(StringConcatOverflow) {
21706   v8::V8::Initialize();
21707   v8::HandleScope scope(CcTest::isolate());
21708   RandomLengthOneByteResource* r =
21709       new RandomLengthOneByteResource(i::String::kMaxLength);
21710   v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
21711   CHECK(!str.IsEmpty());
21712   v8::TryCatch try_catch;
21713   v8::Local<v8::String> result = v8::String::Concat(str, str);
21714   CHECK(result.IsEmpty());
21715   CHECK(!try_catch.HasCaught());
21716 }
21717
21718
21719 TEST(TurboAsmDisablesNeuter) {
21720   v8::V8::Initialize();
21721   v8::HandleScope scope(CcTest::isolate());
21722   LocalContext context;
21723 #if V8_TURBOFAN_TARGET
21724   bool should_be_neuterable = !i::FLAG_turbo_asm;
21725 #else
21726   bool should_be_neuterable = true;
21727 #endif
21728   const char* load =
21729       "function Module(stdlib, foreign, heap) {"
21730       "  'use asm';"
21731       "  var MEM32 = new stdlib.Int32Array(heap);"
21732       "  function load() { return MEM32[0]; }"
21733       "  return { load: load };"
21734       "}"
21735       "var buffer = new ArrayBuffer(4);"
21736       "Module(this, {}, buffer).load();"
21737       "buffer";
21738
21739   i::FLAG_turbo_osr = false;  // TODO(titzer): test requires eager TF.
21740   v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
21741   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21742
21743   const char* store =
21744       "function Module(stdlib, foreign, heap) {"
21745       "  'use asm';"
21746       "  var MEM32 = new stdlib.Int32Array(heap);"
21747       "  function store() { MEM32[0] = 0; }"
21748       "  return { store: store };"
21749       "}"
21750       "var buffer = new ArrayBuffer(4);"
21751       "Module(this, {}, buffer).store();"
21752       "buffer";
21753
21754   i::FLAG_turbo_osr = false;  // TODO(titzer): test requires eager TF.
21755   result = CompileRun(store).As<v8::ArrayBuffer>();
21756   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21757 }
21758
21759
21760 TEST(GetPrototypeAccessControl) {
21761   i::FLAG_allow_natives_syntax = true;
21762   v8::Isolate* isolate = CcTest::isolate();
21763   v8::HandleScope handle_scope(isolate);
21764   LocalContext env;
21765
21766   v8::Handle<v8::ObjectTemplate> obj_template =
21767       v8::ObjectTemplate::New(isolate);
21768   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
21769
21770   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
21771
21772   {
21773     v8::TryCatch try_catch;
21774     CompileRun(
21775         "function f() { %_GetPrototype(prohibited); }"
21776         "%OptimizeFunctionOnNextCall(f);"
21777         "f();");
21778     CHECK(try_catch.HasCaught());
21779   }
21780 }
21781
21782
21783 TEST(GetPrototypeHidden) {
21784   i::FLAG_allow_natives_syntax = true;
21785   v8::Isolate* isolate = CcTest::isolate();
21786   v8::HandleScope handle_scope(isolate);
21787   LocalContext env;
21788
21789   Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
21790   t->SetHiddenPrototype(true);
21791   Handle<Object> proto = t->GetFunction()->NewInstance();
21792   Handle<Object> object = Object::New(isolate);
21793   Handle<Object> proto2 = Object::New(isolate);
21794   object->SetPrototype(proto);
21795   proto->SetPrototype(proto2);
21796
21797   env->Global()->Set(v8_str("object"), object);
21798   env->Global()->Set(v8_str("proto"), proto);
21799   env->Global()->Set(v8_str("proto2"), proto2);
21800
21801   v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
21802   CHECK(result->Equals(proto2));
21803
21804   result = CompileRun(
21805       "function f() { return %_GetPrototype(object); }"
21806       "%OptimizeFunctionOnNextCall(f);"
21807       "f()");
21808   CHECK(result->Equals(proto2));
21809 }
21810
21811
21812 TEST(ClassPrototypeCreationContext) {
21813   i::FLAG_harmony_classes = true;
21814   v8::Isolate* isolate = CcTest::isolate();
21815   v8::HandleScope handle_scope(isolate);
21816   LocalContext env;
21817
21818   Handle<Object> result = Handle<Object>::Cast(
21819       CompileRun("'use strict'; class Example { }; Example.prototype"));
21820   CHECK(env.local() == result->CreationContext());
21821 }
21822
21823
21824 TEST(SimpleStreamingScriptWithSourceURL) {
21825   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
21826                           "//# sourceURL=bar2.js\n", NULL};
21827   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21828                    "bar2.js");
21829 }
21830
21831
21832 TEST(StreamingScriptWithSplitSourceURL) {
21833   const char* chunks[] = {"function foo() { ret", "urn 13; } f",
21834                           "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
21835   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21836                    "bar2.js");
21837 }
21838
21839
21840 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
21841   const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
21842                           " sourceMappingURL=bar2.js\n", "foo();", NULL};
21843   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
21844                    "bar2.js");
21845 }
21846
21847
21848 TEST(NewStringRangeError) {
21849   v8::Isolate* isolate = CcTest::isolate();
21850   v8::HandleScope handle_scope(isolate);
21851   const int length = i::String::kMaxLength + 1;
21852   const int buffer_size = length * sizeof(uint16_t);
21853   void* buffer = malloc(buffer_size);
21854   if (buffer == NULL) return;
21855   memset(buffer, 'A', buffer_size);
21856   {
21857     v8::TryCatch try_catch;
21858     char* data = reinterpret_cast<char*>(buffer);
21859     CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
21860                                   length).IsEmpty());
21861     CHECK(!try_catch.HasCaught());
21862   }
21863   {
21864     v8::TryCatch try_catch;
21865     uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
21866     CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
21867                                      length).IsEmpty());
21868     CHECK(!try_catch.HasCaught());
21869   }
21870   {
21871     v8::TryCatch try_catch;
21872     uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
21873     CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
21874                                      length).IsEmpty());
21875     CHECK(!try_catch.HasCaught());
21876   }
21877   free(buffer);
21878 }
21879
21880
21881 TEST(SealHandleScope) {
21882   v8::Isolate* isolate = CcTest::isolate();
21883   v8::HandleScope handle_scope(isolate);
21884   LocalContext env;
21885
21886   v8::SealHandleScope seal(isolate);
21887
21888   // Should fail
21889   v8::Local<v8::Object> obj = v8::Object::New(isolate);
21890
21891   USE(obj);
21892 }
21893
21894
21895 TEST(SealHandleScopeNested) {
21896   v8::Isolate* isolate = CcTest::isolate();
21897   v8::HandleScope handle_scope(isolate);
21898   LocalContext env;
21899
21900   v8::SealHandleScope seal(isolate);
21901
21902   {
21903     v8::HandleScope handle_scope(isolate);
21904
21905     // Should work
21906     v8::Local<v8::Object> obj = v8::Object::New(isolate);
21907
21908     USE(obj);
21909   }
21910 }