deps: backport 1ee712a from V8 upstream
[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/debug.h"
45 #include "src/execution.h"
46 #include "src/objects.h"
47 #include "src/parser.h"
48 #include "src/smart-pointers.h"
49 #include "src/unicode-inl.h"
50 #include "src/utils.h"
51 #include "src/vm-state.h"
52
53 static const bool kLogThreading = false;
54
55 using ::v8::Boolean;
56 using ::v8::BooleanObject;
57 using ::v8::Context;
58 using ::v8::Extension;
59 using ::v8::Function;
60 using ::v8::FunctionTemplate;
61 using ::v8::Handle;
62 using ::v8::HandleScope;
63 using ::v8::Local;
64 using ::v8::Maybe;
65 using ::v8::Message;
66 using ::v8::MessageCallback;
67 using ::v8::Name;
68 using ::v8::None;
69 using ::v8::Object;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::PropertyAttribute;
73 using ::v8::Script;
74 using ::v8::StackTrace;
75 using ::v8::String;
76 using ::v8::Symbol;
77 using ::v8::TryCatch;
78 using ::v8::Undefined;
79 using ::v8::UniqueId;
80 using ::v8::V8;
81 using ::v8::Value;
82
83
84 #define THREADED_PROFILED_TEST(Name)                                 \
85   static void Test##Name();                                          \
86   TEST(Name##WithProfiler) {                                         \
87     RunWithProfiler(&Test##Name);                                    \
88   }                                                                  \
89   THREADED_TEST(Name)
90
91
92 void RunWithProfiler(void (*test)()) {
93   LocalContext env;
94   v8::HandleScope scope(env->GetIsolate());
95   v8::Local<v8::String> profile_name =
96       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
97   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
98
99   cpu_profiler->StartProfiling(profile_name);
100   (*test)();
101   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
102 }
103
104
105 static int signature_callback_count;
106 static Local<Value> signature_expected_receiver;
107 static void IncrementingSignatureCallback(
108     const v8::FunctionCallbackInfo<v8::Value>& args) {
109   ApiTestFuzzer::Fuzz();
110   signature_callback_count++;
111   CHECK(signature_expected_receiver->Equals(args.Holder()));
112   CHECK(signature_expected_receiver->Equals(args.This()));
113   v8::Handle<v8::Array> result =
114       v8::Array::New(args.GetIsolate(), args.Length());
115   for (int i = 0; i < args.Length(); i++)
116     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
117   args.GetReturnValue().Set(result);
118 }
119
120
121 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
122   info.GetReturnValue().Set(42);
123 }
124
125
126 // Tests that call v8::V8::Dispose() cannot be threaded.
127 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
128   CHECK(v8::V8::Initialize());
129   CHECK(v8::V8::Dispose());
130 }
131
132
133 // Tests that call v8::V8::Dispose() cannot be threaded.
134 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
135   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
136   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
137   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
138   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
139   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
140 }
141
142
143 THREADED_TEST(Handles) {
144   v8::HandleScope scope(CcTest::isolate());
145   Local<Context> local_env;
146   {
147     LocalContext env;
148     local_env = env.local();
149   }
150
151   // Local context should still be live.
152   CHECK(!local_env.IsEmpty());
153   local_env->Enter();
154
155   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
156   CHECK(!undef.IsEmpty());
157   CHECK(undef->IsUndefined());
158
159   const char* source = "1 + 2 + 3";
160   Local<Script> script = v8_compile(source);
161   CHECK_EQ(6, script->Run()->Int32Value());
162
163   local_env->Exit();
164 }
165
166
167 THREADED_TEST(IsolateOfContext) {
168   v8::HandleScope scope(CcTest::isolate());
169   v8::Handle<Context> env = Context::New(CcTest::isolate());
170
171   CHECK(!env->GetIsolate()->InContext());
172   CHECK(env->GetIsolate() == CcTest::isolate());
173   env->Enter();
174   CHECK(env->GetIsolate()->InContext());
175   CHECK(env->GetIsolate() == CcTest::isolate());
176   env->Exit();
177   CHECK(!env->GetIsolate()->InContext());
178   CHECK(env->GetIsolate() == CcTest::isolate());
179 }
180
181
182 static void TestSignature(const char* loop_js, Local<Value> receiver,
183                           v8::Isolate* isolate) {
184   i::ScopedVector<char> source(200);
185   i::SNPrintF(source,
186               "for (var i = 0; i < 10; i++) {"
187               "  %s"
188               "}",
189               loop_js);
190   signature_callback_count = 0;
191   signature_expected_receiver = receiver;
192   bool expected_to_throw = receiver.IsEmpty();
193   v8::TryCatch try_catch(isolate);
194   CompileRun(source.start());
195   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
196   if (!expected_to_throw) {
197     CHECK_EQ(10, signature_callback_count);
198   } else {
199     CHECK(v8_str("TypeError: Illegal invocation")
200               ->Equals(try_catch.Exception()->ToString(isolate)));
201   }
202 }
203
204
205 THREADED_TEST(ReceiverSignature) {
206   LocalContext env;
207   v8::Isolate* isolate = env->GetIsolate();
208   v8::HandleScope scope(isolate);
209   // Setup templates.
210   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
211   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
212   v8::Handle<v8::FunctionTemplate> callback_sig =
213       v8::FunctionTemplate::New(
214           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
215   v8::Handle<v8::FunctionTemplate> callback =
216       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
217   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
218   sub_fun->Inherit(fun);
219   v8::Handle<v8::FunctionTemplate> unrel_fun =
220       v8::FunctionTemplate::New(isolate);
221   // Install properties.
222   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
223   fun_proto->Set(v8_str("prop_sig"), callback_sig);
224   fun_proto->Set(v8_str("prop"), callback);
225   fun_proto->SetAccessorProperty(
226       v8_str("accessor_sig"), callback_sig, callback_sig);
227   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
228   // Instantiate templates.
229   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
230   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
231   // Setup global variables.
232   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
233   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
234   env->Global()->Set(v8_str("fun_instance"), fun_instance);
235   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
236   CompileRun(
237       "var accessor_sig_key = 'accessor_sig';"
238       "var accessor_key = 'accessor';"
239       "var prop_sig_key = 'prop_sig';"
240       "var prop_key = 'prop';"
241       ""
242       "function copy_props(obj) {"
243       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
244       "  var source = Fun.prototype;"
245       "  for (var i in keys) {"
246       "    var key = keys[i];"
247       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
248       "    Object.defineProperty(obj, key, desc);"
249       "  }"
250       "}"
251       ""
252       "var obj = {};"
253       "copy_props(obj);"
254       "var unrel = new UnrelFun();"
255       "copy_props(unrel);");
256   // Test with and without ICs
257   const char* test_objects[] = {
258       "fun_instance", "sub_fun_instance", "obj", "unrel" };
259   unsigned bad_signature_start_offset = 2;
260   for (unsigned i = 0; i < arraysize(test_objects); i++) {
261     i::ScopedVector<char> source(200);
262     i::SNPrintF(
263         source, "var test_object = %s; test_object", test_objects[i]);
264     Local<Value> test_object = CompileRun(source.start());
265     TestSignature("test_object.prop();", test_object, isolate);
266     TestSignature("test_object.accessor;", test_object, isolate);
267     TestSignature("test_object[accessor_key];", test_object, isolate);
268     TestSignature("test_object.accessor = 1;", test_object, isolate);
269     TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
270     if (i >= bad_signature_start_offset) test_object = Local<Value>();
271     TestSignature("test_object.prop_sig();", test_object, isolate);
272     TestSignature("test_object.accessor_sig;", test_object, isolate);
273     TestSignature("test_object[accessor_sig_key];", test_object, isolate);
274     TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
275     TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
276   }
277 }
278
279
280 THREADED_TEST(HulIgennem) {
281   LocalContext env;
282   v8::Isolate* isolate = env->GetIsolate();
283   v8::HandleScope scope(isolate);
284   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
285   Local<String> undef_str = undef->ToString(isolate);
286   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
287   undef_str->WriteUtf8(value);
288   CHECK_EQ(0, strcmp(value, "undefined"));
289   i::DeleteArray(value);
290 }
291
292
293 THREADED_TEST(Access) {
294   LocalContext env;
295   v8::Isolate* isolate = env->GetIsolate();
296   v8::HandleScope scope(isolate);
297   Local<v8::Object> obj = v8::Object::New(isolate);
298   Local<Value> foo_before = obj->Get(v8_str("foo"));
299   CHECK(foo_before->IsUndefined());
300   Local<String> bar_str = v8_str("bar");
301   obj->Set(v8_str("foo"), bar_str);
302   Local<Value> foo_after = obj->Get(v8_str("foo"));
303   CHECK(!foo_after->IsUndefined());
304   CHECK(foo_after->IsString());
305   CHECK(bar_str->Equals(foo_after));
306 }
307
308
309 THREADED_TEST(AccessElement) {
310   LocalContext env;
311   v8::HandleScope scope(env->GetIsolate());
312   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
313   Local<Value> before = obj->Get(1);
314   CHECK(before->IsUndefined());
315   Local<String> bar_str = v8_str("bar");
316   obj->Set(1, bar_str);
317   Local<Value> after = obj->Get(1);
318   CHECK(!after->IsUndefined());
319   CHECK(after->IsString());
320   CHECK(bar_str->Equals(after));
321
322   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
323   CHECK(v8_str("a")->Equals(value->Get(0)));
324   CHECK(v8_str("b")->Equals(value->Get(1)));
325 }
326
327
328 THREADED_TEST(Script) {
329   LocalContext env;
330   v8::HandleScope scope(env->GetIsolate());
331   const char* source = "1 + 2 + 3";
332   Local<Script> script = v8_compile(source);
333   CHECK_EQ(6, script->Run()->Int32Value());
334 }
335
336
337 class TestResource: public String::ExternalStringResource {
338  public:
339   explicit TestResource(uint16_t* data, int* counter = NULL,
340                         bool owning_data = true)
341       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
342     while (data[length_]) ++length_;
343   }
344
345   ~TestResource() {
346     if (owning_data_) i::DeleteArray(data_);
347     if (counter_ != NULL) ++*counter_;
348   }
349
350   const uint16_t* data() const {
351     return data_;
352   }
353
354   size_t length() const {
355     return length_;
356   }
357
358  private:
359   uint16_t* data_;
360   size_t length_;
361   int* counter_;
362   bool owning_data_;
363 };
364
365
366 class TestOneByteResource : public String::ExternalOneByteStringResource {
367  public:
368   explicit TestOneByteResource(const char* data, int* counter = NULL,
369                                size_t offset = 0)
370       : orig_data_(data),
371         data_(data + offset),
372         length_(strlen(data) - offset),
373         counter_(counter) {}
374
375   ~TestOneByteResource() {
376     i::DeleteArray(orig_data_);
377     if (counter_ != NULL) ++*counter_;
378   }
379
380   const char* data() const {
381     return data_;
382   }
383
384   size_t length() const {
385     return length_;
386   }
387
388  private:
389   const char* orig_data_;
390   const char* data_;
391   size_t length_;
392   int* counter_;
393 };
394
395
396 THREADED_TEST(ScriptUsingStringResource) {
397   int dispose_count = 0;
398   const char* c_source = "1 + 2 * 3";
399   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
400   {
401     LocalContext env;
402     v8::HandleScope scope(env->GetIsolate());
403     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
404     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
405     Local<Script> script = v8_compile(source);
406     Local<Value> value = script->Run();
407     CHECK(value->IsNumber());
408     CHECK_EQ(7, value->Int32Value());
409     CHECK(source->IsExternal());
410     CHECK_EQ(resource,
411              static_cast<TestResource*>(source->GetExternalStringResource()));
412     String::Encoding encoding = String::UNKNOWN_ENCODING;
413     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
414              source->GetExternalStringResourceBase(&encoding));
415     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
416     CcTest::heap()->CollectAllGarbage();
417     CHECK_EQ(0, dispose_count);
418   }
419   CcTest::i_isolate()->compilation_cache()->Clear();
420   CcTest::heap()->CollectAllAvailableGarbage();
421   CHECK_EQ(1, dispose_count);
422 }
423
424
425 THREADED_TEST(ScriptUsingOneByteStringResource) {
426   int dispose_count = 0;
427   const char* c_source = "1 + 2 * 3";
428   {
429     LocalContext env;
430     v8::HandleScope scope(env->GetIsolate());
431     TestOneByteResource* resource =
432         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
433     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
434     CHECK(source->IsExternalOneByte());
435     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
436              source->GetExternalOneByteStringResource());
437     String::Encoding encoding = String::UNKNOWN_ENCODING;
438     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
439              source->GetExternalStringResourceBase(&encoding));
440     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
441     Local<Script> script = v8_compile(source);
442     Local<Value> value = script->Run();
443     CHECK(value->IsNumber());
444     CHECK_EQ(7, value->Int32Value());
445     CcTest::heap()->CollectAllGarbage();
446     CHECK_EQ(0, dispose_count);
447   }
448   CcTest::i_isolate()->compilation_cache()->Clear();
449   CcTest::heap()->CollectAllAvailableGarbage();
450   CHECK_EQ(1, dispose_count);
451 }
452
453
454 THREADED_TEST(ScriptMakingExternalString) {
455   int dispose_count = 0;
456   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
457   {
458     LocalContext env;
459     v8::HandleScope scope(env->GetIsolate());
460     Local<String> source =
461         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
462     // Trigger GCs so that the newly allocated string moves to old gen.
463     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
464     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
465     CHECK_EQ(source->IsExternal(), false);
466     CHECK_EQ(source->IsExternalOneByte(), false);
467     String::Encoding encoding = String::UNKNOWN_ENCODING;
468     CHECK(!source->GetExternalStringResourceBase(&encoding));
469     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
470     bool success = source->MakeExternal(new TestResource(two_byte_source,
471                                                          &dispose_count));
472     CHECK(success);
473     Local<Script> script = v8_compile(source);
474     Local<Value> value = script->Run();
475     CHECK(value->IsNumber());
476     CHECK_EQ(7, value->Int32Value());
477     CcTest::heap()->CollectAllGarbage();
478     CHECK_EQ(0, dispose_count);
479   }
480   CcTest::i_isolate()->compilation_cache()->Clear();
481   CcTest::heap()->CollectAllGarbage();
482   CHECK_EQ(1, dispose_count);
483 }
484
485
486 THREADED_TEST(ScriptMakingExternalOneByteString) {
487   int dispose_count = 0;
488   const char* c_source = "1 + 2 * 3";
489   {
490     LocalContext env;
491     v8::HandleScope scope(env->GetIsolate());
492     Local<String> source = v8_str(c_source);
493     // Trigger GCs so that the newly allocated string moves to old gen.
494     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
495     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
496     bool success = source->MakeExternal(
497         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
498     CHECK(success);
499     Local<Script> script = v8_compile(source);
500     Local<Value> value = script->Run();
501     CHECK(value->IsNumber());
502     CHECK_EQ(7, value->Int32Value());
503     CcTest::heap()->CollectAllGarbage();
504     CHECK_EQ(0, dispose_count);
505   }
506   CcTest::i_isolate()->compilation_cache()->Clear();
507   CcTest::heap()->CollectAllGarbage();
508   CHECK_EQ(1, dispose_count);
509 }
510
511
512 TEST(MakingExternalStringConditions) {
513   LocalContext env;
514   v8::HandleScope scope(env->GetIsolate());
515
516   // Free some space in the new space so that we can check freshness.
517   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
518   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
519
520   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
521   Local<String> small_string =
522       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
523   i::DeleteArray(two_byte_string);
524
525   // We should refuse to externalize newly created small string.
526   CHECK(!small_string->CanMakeExternal());
527   // Trigger GCs so that the newly allocated string moves to old gen.
528   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
529   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
530   // Old space strings should be accepted.
531   CHECK(small_string->CanMakeExternal());
532
533   two_byte_string = AsciiToTwoByteString("small string 2");
534   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
535   i::DeleteArray(two_byte_string);
536
537   // We should refuse externalizing newly created small string.
538   CHECK(!small_string->CanMakeExternal());
539   for (int i = 0; i < 100; i++) {
540     String::Value value(small_string);
541   }
542   // Frequently used strings should be accepted.
543   CHECK(small_string->CanMakeExternal());
544
545   const int buf_size = 10 * 1024;
546   char* buf = i::NewArray<char>(buf_size);
547   memset(buf, 'a', buf_size);
548   buf[buf_size - 1] = '\0';
549
550   two_byte_string = AsciiToTwoByteString(buf);
551   Local<String> large_string =
552       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
553   i::DeleteArray(buf);
554   i::DeleteArray(two_byte_string);
555   // Large strings should be immediately accepted.
556   CHECK(large_string->CanMakeExternal());
557 }
558
559
560 TEST(MakingExternalOneByteStringConditions) {
561   LocalContext env;
562   v8::HandleScope scope(env->GetIsolate());
563
564   // Free some space in the new space so that we can check freshness.
565   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
566   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
567
568   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
569   // We should refuse to externalize newly created small string.
570   CHECK(!small_string->CanMakeExternal());
571   // Trigger GCs so that the newly allocated string moves to old gen.
572   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
573   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
574   // Old space strings should be accepted.
575   CHECK(small_string->CanMakeExternal());
576
577   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
578   // We should refuse externalizing newly created small string.
579   CHECK(!small_string->CanMakeExternal());
580   for (int i = 0; i < 100; i++) {
581     String::Value value(small_string);
582   }
583   // Frequently used strings should be accepted.
584   CHECK(small_string->CanMakeExternal());
585
586   const int buf_size = 10 * 1024;
587   char* buf = i::NewArray<char>(buf_size);
588   memset(buf, 'a', buf_size);
589   buf[buf_size - 1] = '\0';
590   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
591   i::DeleteArray(buf);
592   // Large strings should be immediately accepted.
593   CHECK(large_string->CanMakeExternal());
594 }
595
596
597 TEST(MakingExternalUnalignedOneByteString) {
598   LocalContext env;
599   v8::HandleScope scope(env->GetIsolate());
600
601   CompileRun("function cons(a, b) { return a + b; }"
602              "function slice(a) { return a.substring(1); }");
603   // Create a cons string that will land in old pointer space.
604   Local<String> cons = Local<String>::Cast(CompileRun(
605       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
606   // Create a sliced string that will land in old pointer space.
607   Local<String> slice = Local<String>::Cast(CompileRun(
608       "slice('abcdefghijklmnopqrstuvwxyz');"));
609
610   // Trigger GCs so that the newly allocated string moves to old gen.
611   SimulateFullSpace(CcTest::heap()->old_space());
612   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
613   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
614
615   // Turn into external string with unaligned resource data.
616   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
617   bool success =
618       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
619   CHECK(success);
620   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
621   success =
622       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
623   CHECK(success);
624
625   // Trigger GCs and force evacuation.
626   CcTest::heap()->CollectAllGarbage();
627   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
628 }
629
630
631 THREADED_TEST(UsingExternalString) {
632   i::Factory* factory = CcTest::i_isolate()->factory();
633   {
634     v8::HandleScope scope(CcTest::isolate());
635     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
636     Local<String> string = String::NewExternal(
637         CcTest::isolate(), new TestResource(two_byte_string));
638     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
639     // Trigger GCs so that the newly allocated string moves to old gen.
640     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
641     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
642     i::Handle<i::String> isymbol =
643         factory->InternalizeString(istring);
644     CHECK(isymbol->IsInternalizedString());
645   }
646   CcTest::heap()->CollectAllGarbage();
647   CcTest::heap()->CollectAllGarbage();
648 }
649
650
651 THREADED_TEST(UsingExternalOneByteString) {
652   i::Factory* factory = CcTest::i_isolate()->factory();
653   {
654     v8::HandleScope scope(CcTest::isolate());
655     const char* one_byte_string = "test string";
656     Local<String> string = String::NewExternal(
657         CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
658     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
659     // Trigger GCs so that the newly allocated string moves to old gen.
660     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
661     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
662     i::Handle<i::String> isymbol =
663         factory->InternalizeString(istring);
664     CHECK(isymbol->IsInternalizedString());
665   }
666   CcTest::heap()->CollectAllGarbage();
667   CcTest::heap()->CollectAllGarbage();
668 }
669
670
671 class RandomLengthResource : public v8::String::ExternalStringResource {
672  public:
673   explicit RandomLengthResource(int length) : length_(length) {}
674   virtual const uint16_t* data() const { return string_; }
675   virtual size_t length() const { return length_; }
676
677  private:
678   uint16_t string_[10];
679   int length_;
680 };
681
682
683 class RandomLengthOneByteResource
684     : public v8::String::ExternalOneByteStringResource {
685  public:
686   explicit RandomLengthOneByteResource(int length) : length_(length) {}
687   virtual const char* data() const { return string_; }
688   virtual size_t length() const { return length_; }
689
690  private:
691   char string_[10];
692   int length_;
693 };
694
695
696 THREADED_TEST(NewExternalForVeryLongString) {
697   auto isolate = CcTest::isolate();
698   {
699     v8::HandleScope scope(isolate);
700     v8::TryCatch try_catch(isolate);
701     RandomLengthOneByteResource r(1 << 30);
702     v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
703     CHECK(str.IsEmpty());
704     CHECK(!try_catch.HasCaught());
705   }
706
707   {
708     v8::HandleScope scope(isolate);
709     v8::TryCatch try_catch(isolate);
710     RandomLengthResource r(1 << 30);
711     v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
712     CHECK(str.IsEmpty());
713     CHECK(!try_catch.HasCaught());
714   }
715 }
716
717
718 THREADED_TEST(ScavengeExternalString) {
719   i::FLAG_stress_compaction = false;
720   i::FLAG_gc_global = false;
721   int dispose_count = 0;
722   bool in_new_space = false;
723   {
724     v8::HandleScope scope(CcTest::isolate());
725     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
726     Local<String> string = String::NewExternal(
727         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
728     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
729     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
730     in_new_space = CcTest::heap()->InNewSpace(*istring);
731     CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
732     CHECK_EQ(0, dispose_count);
733   }
734   CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_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_space()->Contains(*istring));
754     CHECK_EQ(0, dispose_count);
755   }
756   CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
757   CHECK_EQ(1, dispose_count);
758 }
759
760
761 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
762  public:
763   // Only used by non-threaded tests, so it can use static fields.
764   static int dispose_calls;
765   static int dispose_count;
766
767   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
768       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
769
770   void Dispose() {
771     ++dispose_calls;
772     if (dispose_) delete this;
773   }
774  private:
775   bool dispose_;
776 };
777
778
779 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
780 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
781
782
783 TEST(ExternalStringWithDisposeHandling) {
784   const char* c_source = "1 + 2 * 3";
785
786   // Use a stack allocated external string resource allocated object.
787   TestOneByteResourceWithDisposeControl::dispose_count = 0;
788   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
789   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
790   {
791     LocalContext env;
792     v8::HandleScope scope(env->GetIsolate());
793     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
794     Local<Script> script = v8_compile(source);
795     Local<Value> value = script->Run();
796     CHECK(value->IsNumber());
797     CHECK_EQ(7, value->Int32Value());
798     CcTest::heap()->CollectAllAvailableGarbage();
799     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
800   }
801   CcTest::i_isolate()->compilation_cache()->Clear();
802   CcTest::heap()->CollectAllAvailableGarbage();
803   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
804   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
805
806   // Use a heap allocated external string resource allocated object.
807   TestOneByteResourceWithDisposeControl::dispose_count = 0;
808   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
809   TestOneByteResource* res_heap =
810       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
811   {
812     LocalContext env;
813     v8::HandleScope scope(env->GetIsolate());
814     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
815     Local<Script> script = v8_compile(source);
816     Local<Value> value = script->Run();
817     CHECK(value->IsNumber());
818     CHECK_EQ(7, value->Int32Value());
819     CcTest::heap()->CollectAllAvailableGarbage();
820     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
821   }
822   CcTest::i_isolate()->compilation_cache()->Clear();
823   CcTest::heap()->CollectAllAvailableGarbage();
824   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
825   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
826 }
827
828
829 THREADED_TEST(StringConcat) {
830   {
831     LocalContext env;
832     v8::HandleScope scope(env->GetIsolate());
833     const char* one_byte_string_1 = "function a_times_t";
834     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
835     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
836     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
837     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
838     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
839     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
840     Local<String> left = v8_str(one_byte_string_1);
841
842     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
843     Local<String> right =
844         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
845     i::DeleteArray(two_byte_source);
846
847     Local<String> source = String::Concat(left, right);
848     right = String::NewExternal(
849         env->GetIsolate(),
850         new TestOneByteResource(i::StrDup(one_byte_extern_1)));
851     source = String::Concat(source, right);
852     right = String::NewExternal(
853         env->GetIsolate(),
854         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
855     source = String::Concat(source, right);
856     right = v8_str(one_byte_string_2);
857     source = String::Concat(source, right);
858
859     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
860     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
861     i::DeleteArray(two_byte_source);
862
863     source = String::Concat(source, right);
864     right = String::NewExternal(
865         env->GetIsolate(),
866         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
867     source = String::Concat(source, right);
868     Local<Script> script = v8_compile(source);
869     Local<Value> value = script->Run();
870     CHECK(value->IsNumber());
871     CHECK_EQ(68, value->Int32Value());
872   }
873   CcTest::i_isolate()->compilation_cache()->Clear();
874   CcTest::heap()->CollectAllGarbage();
875   CcTest::heap()->CollectAllGarbage();
876 }
877
878
879 THREADED_TEST(GlobalProperties) {
880   LocalContext env;
881   v8::HandleScope scope(env->GetIsolate());
882   v8::Handle<v8::Object> global = env->Global();
883   global->Set(v8_str("pi"), v8_num(3.1415926));
884   Local<Value> pi = global->Get(v8_str("pi"));
885   CHECK_EQ(3.1415926, pi->NumberValue());
886 }
887
888
889 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
890                                  i::Address callback) {
891   ApiTestFuzzer::Fuzz();
892   CheckReturnValue(info, callback);
893   info.GetReturnValue().Set(v8_str("bad value"));
894   info.GetReturnValue().Set(v8_num(102));
895 }
896
897
898 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
899   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
900 }
901
902
903 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
904   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
905 }
906
907 static void construct_callback(
908     const v8::FunctionCallbackInfo<Value>& info) {
909   ApiTestFuzzer::Fuzz();
910   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
911   info.This()->Set(v8_str("x"), v8_num(1));
912   info.This()->Set(v8_str("y"), v8_num(2));
913   info.GetReturnValue().Set(v8_str("bad value"));
914   info.GetReturnValue().Set(info.This());
915 }
916
917
918 static void Return239Callback(
919     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
920   ApiTestFuzzer::Fuzz();
921   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
922   info.GetReturnValue().Set(v8_str("bad value"));
923   info.GetReturnValue().Set(v8_num(239));
924 }
925
926
927 template<typename Handler>
928 static void TestFunctionTemplateInitializer(Handler handler,
929                                             Handler handler_2) {
930   // Test constructor calls.
931   {
932     LocalContext env;
933     v8::Isolate* isolate = env->GetIsolate();
934     v8::HandleScope scope(isolate);
935
936     Local<v8::FunctionTemplate> fun_templ =
937         v8::FunctionTemplate::New(isolate, handler);
938     Local<Function> fun = fun_templ->GetFunction();
939     env->Global()->Set(v8_str("obj"), fun);
940     Local<Script> script = v8_compile("obj()");
941     for (int i = 0; i < 30; i++) {
942       CHECK_EQ(102, script->Run()->Int32Value());
943     }
944   }
945   // Use SetCallHandler to initialize a function template, should work like
946   // the previous one.
947   {
948     LocalContext env;
949     v8::Isolate* isolate = env->GetIsolate();
950     v8::HandleScope scope(isolate);
951
952     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
953     fun_templ->SetCallHandler(handler_2);
954     Local<Function> fun = fun_templ->GetFunction();
955     env->Global()->Set(v8_str("obj"), fun);
956     Local<Script> script = v8_compile("obj()");
957     for (int i = 0; i < 30; i++) {
958       CHECK_EQ(102, script->Run()->Int32Value());
959     }
960   }
961 }
962
963
964 template<typename Constructor, typename Accessor>
965 static void TestFunctionTemplateAccessor(Constructor constructor,
966                                          Accessor accessor) {
967   LocalContext env;
968   v8::HandleScope scope(env->GetIsolate());
969
970   Local<v8::FunctionTemplate> fun_templ =
971       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
972   fun_templ->SetClassName(v8_str("funky"));
973   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
974   Local<Function> fun = fun_templ->GetFunction();
975   env->Global()->Set(v8_str("obj"), fun);
976   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
977   CHECK(v8_str("[object funky]")->Equals(result));
978   CompileRun("var obj_instance = new obj();");
979   Local<Script> script;
980   script = v8_compile("obj_instance.x");
981   for (int i = 0; i < 30; i++) {
982     CHECK_EQ(1, script->Run()->Int32Value());
983   }
984   script = v8_compile("obj_instance.m");
985   for (int i = 0; i < 30; i++) {
986     CHECK_EQ(239, script->Run()->Int32Value());
987   }
988 }
989
990
991 THREADED_PROFILED_TEST(FunctionTemplate) {
992   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
993   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
994 }
995
996
997 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
998   ApiTestFuzzer::Fuzz();
999   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1000   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1001 }
1002
1003
1004 template<typename Callback>
1005 static void TestSimpleCallback(Callback callback) {
1006   LocalContext env;
1007   v8::Isolate* isolate = env->GetIsolate();
1008   v8::HandleScope scope(isolate);
1009
1010   v8::Handle<v8::ObjectTemplate> object_template =
1011       v8::ObjectTemplate::New(isolate);
1012   object_template->Set(isolate, "callback",
1013                        v8::FunctionTemplate::New(isolate, callback));
1014   v8::Local<v8::Object> object = object_template->NewInstance();
1015   (*env)->Global()->Set(v8_str("callback_object"), object);
1016   v8::Handle<v8::Script> script;
1017   script = v8_compile("callback_object.callback(17)");
1018   for (int i = 0; i < 30; i++) {
1019     CHECK_EQ(51424, script->Run()->Int32Value());
1020   }
1021   script = v8_compile("callback_object.callback(17, 24)");
1022   for (int i = 0; i < 30; i++) {
1023     CHECK_EQ(51425, script->Run()->Int32Value());
1024   }
1025 }
1026
1027
1028 THREADED_PROFILED_TEST(SimpleCallback) {
1029   TestSimpleCallback(SimpleCallback);
1030 }
1031
1032
1033 template<typename T>
1034 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1035
1036 // constant return values
1037 static int32_t fast_return_value_int32 = 471;
1038 static uint32_t fast_return_value_uint32 = 571;
1039 static const double kFastReturnValueDouble = 2.7;
1040 // variable return values
1041 static bool fast_return_value_bool = false;
1042 enum ReturnValueOddball {
1043   kNullReturnValue,
1044   kUndefinedReturnValue,
1045   kEmptyStringReturnValue
1046 };
1047 static ReturnValueOddball fast_return_value_void;
1048 static bool fast_return_value_object_is_empty = false;
1049
1050 // Helper function to avoid compiler error: insufficient contextual information
1051 // to determine type when applying FUNCTION_ADDR to a template function.
1052 static i::Address address_of(v8::FunctionCallback callback) {
1053   return FUNCTION_ADDR(callback);
1054 }
1055
1056 template<>
1057 void FastReturnValueCallback<int32_t>(
1058     const v8::FunctionCallbackInfo<v8::Value>& info) {
1059   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1060   info.GetReturnValue().Set(fast_return_value_int32);
1061 }
1062
1063 template<>
1064 void FastReturnValueCallback<uint32_t>(
1065     const v8::FunctionCallbackInfo<v8::Value>& info) {
1066   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1067   info.GetReturnValue().Set(fast_return_value_uint32);
1068 }
1069
1070 template<>
1071 void FastReturnValueCallback<double>(
1072     const v8::FunctionCallbackInfo<v8::Value>& info) {
1073   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1074   info.GetReturnValue().Set(kFastReturnValueDouble);
1075 }
1076
1077 template<>
1078 void FastReturnValueCallback<bool>(
1079     const v8::FunctionCallbackInfo<v8::Value>& info) {
1080   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1081   info.GetReturnValue().Set(fast_return_value_bool);
1082 }
1083
1084 template<>
1085 void FastReturnValueCallback<void>(
1086     const v8::FunctionCallbackInfo<v8::Value>& info) {
1087   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1088   switch (fast_return_value_void) {
1089     case kNullReturnValue:
1090       info.GetReturnValue().SetNull();
1091       break;
1092     case kUndefinedReturnValue:
1093       info.GetReturnValue().SetUndefined();
1094       break;
1095     case kEmptyStringReturnValue:
1096       info.GetReturnValue().SetEmptyString();
1097       break;
1098   }
1099 }
1100
1101 template<>
1102 void FastReturnValueCallback<Object>(
1103     const v8::FunctionCallbackInfo<v8::Value>& info) {
1104   v8::Handle<v8::Object> object;
1105   if (!fast_return_value_object_is_empty) {
1106     object = Object::New(info.GetIsolate());
1107   }
1108   info.GetReturnValue().Set(object);
1109 }
1110
1111 template<typename T>
1112 Handle<Value> TestFastReturnValues() {
1113   LocalContext env;
1114   v8::Isolate* isolate = env->GetIsolate();
1115   v8::EscapableHandleScope scope(isolate);
1116   v8::Handle<v8::ObjectTemplate> object_template =
1117       v8::ObjectTemplate::New(isolate);
1118   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1119   object_template->Set(isolate, "callback",
1120                        v8::FunctionTemplate::New(isolate, callback));
1121   v8::Local<v8::Object> object = object_template->NewInstance();
1122   (*env)->Global()->Set(v8_str("callback_object"), object);
1123   return scope.Escape(CompileRun("callback_object.callback()"));
1124 }
1125
1126
1127 THREADED_PROFILED_TEST(FastReturnValues) {
1128   LocalContext env;
1129   v8::Isolate* isolate = env->GetIsolate();
1130   v8::HandleScope scope(isolate);
1131   v8::Handle<v8::Value> value;
1132   // check int32_t and uint32_t
1133   int32_t int_values[] = {
1134       0, 234, -723,
1135       i::Smi::kMinValue, i::Smi::kMaxValue
1136   };
1137   for (size_t i = 0; i < arraysize(int_values); i++) {
1138     for (int modifier = -1; modifier <= 1; modifier++) {
1139       int int_value = int_values[i] + modifier;
1140       // check int32_t
1141       fast_return_value_int32 = int_value;
1142       value = TestFastReturnValues<int32_t>();
1143       CHECK(value->IsInt32());
1144       CHECK(fast_return_value_int32 == value->Int32Value());
1145       // check uint32_t
1146       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1147       value = TestFastReturnValues<uint32_t>();
1148       CHECK(value->IsUint32());
1149       CHECK(fast_return_value_uint32 == value->Uint32Value());
1150     }
1151   }
1152   // check double
1153   value = TestFastReturnValues<double>();
1154   CHECK(value->IsNumber());
1155   CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1156   // check bool values
1157   for (int i = 0; i < 2; i++) {
1158     fast_return_value_bool = i == 0;
1159     value = TestFastReturnValues<bool>();
1160     CHECK(value->IsBoolean());
1161     CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1162   }
1163   // check oddballs
1164   ReturnValueOddball oddballs[] = {
1165       kNullReturnValue,
1166       kUndefinedReturnValue,
1167       kEmptyStringReturnValue
1168   };
1169   for (size_t i = 0; i < arraysize(oddballs); i++) {
1170     fast_return_value_void = oddballs[i];
1171     value = TestFastReturnValues<void>();
1172     switch (fast_return_value_void) {
1173       case kNullReturnValue:
1174         CHECK(value->IsNull());
1175         break;
1176       case kUndefinedReturnValue:
1177         CHECK(value->IsUndefined());
1178         break;
1179       case kEmptyStringReturnValue:
1180         CHECK(value->IsString());
1181         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1182         break;
1183     }
1184   }
1185   // check handles
1186   fast_return_value_object_is_empty = false;
1187   value = TestFastReturnValues<Object>();
1188   CHECK(value->IsObject());
1189   fast_return_value_object_is_empty = true;
1190   value = TestFastReturnValues<Object>();
1191   CHECK(value->IsUndefined());
1192 }
1193
1194
1195 THREADED_TEST(FunctionTemplateSetLength) {
1196   LocalContext env;
1197   v8::Isolate* isolate = env->GetIsolate();
1198   v8::HandleScope scope(isolate);
1199   {
1200     Local<v8::FunctionTemplate> fun_templ =
1201         v8::FunctionTemplate::New(isolate,
1202                                   handle_callback,
1203                                   Handle<v8::Value>(),
1204                                   Handle<v8::Signature>(),
1205                                   23);
1206     Local<Function> fun = fun_templ->GetFunction();
1207     env->Global()->Set(v8_str("obj"), fun);
1208     Local<Script> script = v8_compile("obj.length");
1209     CHECK_EQ(23, script->Run()->Int32Value());
1210   }
1211   {
1212     Local<v8::FunctionTemplate> fun_templ =
1213         v8::FunctionTemplate::New(isolate, handle_callback);
1214     fun_templ->SetLength(22);
1215     Local<Function> fun = fun_templ->GetFunction();
1216     env->Global()->Set(v8_str("obj"), fun);
1217     Local<Script> script = v8_compile("obj.length");
1218     CHECK_EQ(22, script->Run()->Int32Value());
1219   }
1220   {
1221     // Without setting length it defaults to 0.
1222     Local<v8::FunctionTemplate> fun_templ =
1223         v8::FunctionTemplate::New(isolate, handle_callback);
1224     Local<Function> fun = fun_templ->GetFunction();
1225     env->Global()->Set(v8_str("obj"), fun);
1226     Local<Script> script = v8_compile("obj.length");
1227     CHECK_EQ(0, script->Run()->Int32Value());
1228   }
1229 }
1230
1231
1232 static void* expected_ptr;
1233 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1234   void* ptr = v8::External::Cast(*args.Data())->Value();
1235   CHECK_EQ(expected_ptr, ptr);
1236   args.GetReturnValue().Set(true);
1237 }
1238
1239
1240 static void TestExternalPointerWrapping() {
1241   LocalContext env;
1242   v8::Isolate* isolate = env->GetIsolate();
1243   v8::HandleScope scope(isolate);
1244
1245   v8::Handle<v8::Value> data =
1246       v8::External::New(isolate, expected_ptr);
1247
1248   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1249   obj->Set(v8_str("func"),
1250            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1251   env->Global()->Set(v8_str("obj"), obj);
1252
1253   CHECK(CompileRun(
1254         "function foo() {\n"
1255         "  for (var i = 0; i < 13; i++) obj.func();\n"
1256         "}\n"
1257         "foo(), true")->BooleanValue());
1258 }
1259
1260
1261 THREADED_TEST(ExternalWrap) {
1262   // Check heap allocated object.
1263   int* ptr = new int;
1264   expected_ptr = ptr;
1265   TestExternalPointerWrapping();
1266   delete ptr;
1267
1268   // Check stack allocated object.
1269   int foo;
1270   expected_ptr = &foo;
1271   TestExternalPointerWrapping();
1272
1273   // Check not aligned addresses.
1274   const int n = 100;
1275   char* s = new char[n];
1276   for (int i = 0; i < n; i++) {
1277     expected_ptr = s + i;
1278     TestExternalPointerWrapping();
1279   }
1280
1281   delete[] s;
1282
1283   // Check several invalid addresses.
1284   expected_ptr = reinterpret_cast<void*>(1);
1285   TestExternalPointerWrapping();
1286
1287   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1288   TestExternalPointerWrapping();
1289
1290   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1291   TestExternalPointerWrapping();
1292
1293 #if defined(V8_HOST_ARCH_X64)
1294   // Check a value with a leading 1 bit in x64 Smi encoding.
1295   expected_ptr = reinterpret_cast<void*>(0x400000000);
1296   TestExternalPointerWrapping();
1297
1298   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1299   TestExternalPointerWrapping();
1300
1301   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1302   TestExternalPointerWrapping();
1303 #endif
1304 }
1305
1306
1307 THREADED_TEST(FindInstanceInPrototypeChain) {
1308   LocalContext env;
1309   v8::Isolate* isolate = env->GetIsolate();
1310   v8::HandleScope scope(isolate);
1311
1312   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1313   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1314   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1315   derived->Inherit(base);
1316
1317   Local<v8::Function> base_function = base->GetFunction();
1318   Local<v8::Function> derived_function = derived->GetFunction();
1319   Local<v8::Function> other_function = other->GetFunction();
1320
1321   Local<v8::Object> base_instance = base_function->NewInstance();
1322   Local<v8::Object> derived_instance = derived_function->NewInstance();
1323   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1324   Local<v8::Object> other_instance = other_function->NewInstance();
1325   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1326   other_instance->Set(v8_str("__proto__"), derived_instance2);
1327
1328   // base_instance is only an instance of base.
1329   CHECK(
1330       base_instance->Equals(base_instance->FindInstanceInPrototypeChain(base)));
1331   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1332   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1333
1334   // derived_instance is an instance of base and derived.
1335   CHECK(derived_instance->Equals(
1336       derived_instance->FindInstanceInPrototypeChain(base)));
1337   CHECK(derived_instance->Equals(
1338       derived_instance->FindInstanceInPrototypeChain(derived)));
1339   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1340
1341   // other_instance is an instance of other and its immediate
1342   // prototype derived_instance2 is an instance of base and derived.
1343   // Note, derived_instance is an instance of base and derived too,
1344   // but it comes after derived_instance2 in the prototype chain of
1345   // other_instance.
1346   CHECK(derived_instance2->Equals(
1347       other_instance->FindInstanceInPrototypeChain(base)));
1348   CHECK(derived_instance2->Equals(
1349       other_instance->FindInstanceInPrototypeChain(derived)));
1350   CHECK(other_instance->Equals(
1351       other_instance->FindInstanceInPrototypeChain(other)));
1352 }
1353
1354
1355 THREADED_TEST(TinyInteger) {
1356   LocalContext env;
1357   v8::Isolate* isolate = env->GetIsolate();
1358   v8::HandleScope scope(isolate);
1359
1360   int32_t value = 239;
1361   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1362   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1363
1364   value_obj = v8::Integer::New(isolate, value);
1365   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1366 }
1367
1368
1369 THREADED_TEST(BigSmiInteger) {
1370   LocalContext env;
1371   v8::HandleScope scope(env->GetIsolate());
1372   v8::Isolate* isolate = CcTest::isolate();
1373
1374   int32_t value = i::Smi::kMaxValue;
1375   // We cannot add one to a Smi::kMaxValue without wrapping.
1376   if (i::SmiValuesAre31Bits()) {
1377     CHECK(i::Smi::IsValid(value));
1378     CHECK(!i::Smi::IsValid(value + 1));
1379
1380     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1381     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1382
1383     value_obj = v8::Integer::New(isolate, value);
1384     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1385   }
1386 }
1387
1388
1389 THREADED_TEST(BigInteger) {
1390   LocalContext env;
1391   v8::HandleScope scope(env->GetIsolate());
1392   v8::Isolate* isolate = CcTest::isolate();
1393
1394   // We cannot add one to a Smi::kMaxValue without wrapping.
1395   if (i::SmiValuesAre31Bits()) {
1396     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1397     // The code will not be run in that case, due to the "if" guard.
1398     int32_t value =
1399         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1400     CHECK(value > i::Smi::kMaxValue);
1401     CHECK(!i::Smi::IsValid(value));
1402
1403     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1404     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1405
1406     value_obj = v8::Integer::New(isolate, value);
1407     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1408   }
1409 }
1410
1411
1412 THREADED_TEST(TinyUnsignedInteger) {
1413   LocalContext env;
1414   v8::HandleScope scope(env->GetIsolate());
1415   v8::Isolate* isolate = CcTest::isolate();
1416
1417   uint32_t value = 239;
1418
1419   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1420   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1421
1422   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1423   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1424 }
1425
1426
1427 THREADED_TEST(BigUnsignedSmiInteger) {
1428   LocalContext env;
1429   v8::HandleScope scope(env->GetIsolate());
1430   v8::Isolate* isolate = CcTest::isolate();
1431
1432   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1433   CHECK(i::Smi::IsValid(value));
1434   CHECK(!i::Smi::IsValid(value + 1));
1435
1436   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1437   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1438
1439   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1440   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1441 }
1442
1443
1444 THREADED_TEST(BigUnsignedInteger) {
1445   LocalContext env;
1446   v8::HandleScope scope(env->GetIsolate());
1447   v8::Isolate* isolate = CcTest::isolate();
1448
1449   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1450   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1451   CHECK(!i::Smi::IsValid(value));
1452
1453   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1454   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1455
1456   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1457   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1458 }
1459
1460
1461 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1462   LocalContext env;
1463   v8::HandleScope scope(env->GetIsolate());
1464   v8::Isolate* isolate = CcTest::isolate();
1465
1466   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1467   uint32_t value = INT32_MAX_AS_UINT + 1;
1468   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1469
1470   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1471   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1472
1473   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1474   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1475 }
1476
1477
1478 THREADED_TEST(IsNativeError) {
1479   LocalContext env;
1480   v8::HandleScope scope(env->GetIsolate());
1481   v8::Handle<Value> syntax_error = CompileRun(
1482       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1483   CHECK(syntax_error->IsNativeError());
1484   v8::Handle<Value> not_error = CompileRun("{a:42}");
1485   CHECK(!not_error->IsNativeError());
1486   v8::Handle<Value> not_object = CompileRun("42");
1487   CHECK(!not_object->IsNativeError());
1488 }
1489
1490
1491 THREADED_TEST(IsGeneratorFunctionOrObject) {
1492   LocalContext env;
1493   v8::HandleScope scope(env->GetIsolate());
1494
1495   CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1496   v8::Handle<Value> gen = CompileRun("gen");
1497   v8::Handle<Value> genObj = CompileRun("gen()");
1498   v8::Handle<Value> object = CompileRun("{a:42}");
1499   v8::Handle<Value> func = CompileRun("func");
1500
1501   CHECK(gen->IsGeneratorFunction());
1502   CHECK(gen->IsFunction());
1503   CHECK(!gen->IsGeneratorObject());
1504
1505   CHECK(!genObj->IsGeneratorFunction());
1506   CHECK(!genObj->IsFunction());
1507   CHECK(genObj->IsGeneratorObject());
1508
1509   CHECK(!object->IsGeneratorFunction());
1510   CHECK(!object->IsFunction());
1511   CHECK(!object->IsGeneratorObject());
1512
1513   CHECK(!func->IsGeneratorFunction());
1514   CHECK(func->IsFunction());
1515   CHECK(!func->IsGeneratorObject());
1516 }
1517
1518
1519 THREADED_TEST(ArgumentsObject) {
1520   LocalContext env;
1521   v8::HandleScope scope(env->GetIsolate());
1522   v8::Handle<Value> arguments_object =
1523       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1524   CHECK(arguments_object->IsArgumentsObject());
1525   v8::Handle<Value> array = CompileRun("[1,2,3]");
1526   CHECK(!array->IsArgumentsObject());
1527   v8::Handle<Value> object = CompileRun("{a:42}");
1528   CHECK(!object->IsArgumentsObject());
1529 }
1530
1531
1532 THREADED_TEST(IsMapOrSet) {
1533   LocalContext env;
1534   v8::HandleScope scope(env->GetIsolate());
1535   v8::Handle<Value> map = CompileRun("new Map()");
1536   v8::Handle<Value> set = CompileRun("new Set()");
1537   v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1538   v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1539   CHECK(map->IsMap());
1540   CHECK(set->IsSet());
1541   CHECK(weak_map->IsWeakMap());
1542   CHECK(weak_set->IsWeakSet());
1543
1544   CHECK(!map->IsSet());
1545   CHECK(!map->IsWeakMap());
1546   CHECK(!map->IsWeakSet());
1547
1548   CHECK(!set->IsMap());
1549   CHECK(!set->IsWeakMap());
1550   CHECK(!set->IsWeakSet());
1551
1552   CHECK(!weak_map->IsMap());
1553   CHECK(!weak_map->IsSet());
1554   CHECK(!weak_map->IsWeakSet());
1555
1556   CHECK(!weak_set->IsMap());
1557   CHECK(!weak_set->IsSet());
1558   CHECK(!weak_set->IsWeakMap());
1559
1560   v8::Handle<Value> object = CompileRun("{a:42}");
1561   CHECK(!object->IsMap());
1562   CHECK(!object->IsSet());
1563   CHECK(!object->IsWeakMap());
1564   CHECK(!object->IsWeakSet());
1565 }
1566
1567
1568 THREADED_TEST(StringObject) {
1569   LocalContext env;
1570   v8::HandleScope scope(env->GetIsolate());
1571   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1572   CHECK(boxed_string->IsStringObject());
1573   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1574   CHECK(!unboxed_string->IsStringObject());
1575   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1576   CHECK(!boxed_not_string->IsStringObject());
1577   v8::Handle<Value> not_object = CompileRun("0");
1578   CHECK(!not_object->IsStringObject());
1579   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1580   CHECK(!as_boxed.IsEmpty());
1581   Local<v8::String> the_string = as_boxed->ValueOf();
1582   CHECK(!the_string.IsEmpty());
1583   ExpectObject("\"test\"", the_string);
1584   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1585   CHECK(new_boxed_string->IsStringObject());
1586   as_boxed = new_boxed_string.As<v8::StringObject>();
1587   the_string = as_boxed->ValueOf();
1588   CHECK(!the_string.IsEmpty());
1589   ExpectObject("\"test\"", the_string);
1590 }
1591
1592
1593 TEST(StringObjectDelete) {
1594   LocalContext context;
1595   v8::HandleScope scope(context->GetIsolate());
1596   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1597   CHECK(boxed_string->IsStringObject());
1598   v8::Handle<v8::Object> str_obj = boxed_string.As<v8::Object>();
1599   CHECK(!str_obj->Delete(2));
1600   CHECK(!str_obj->Delete(v8_num(2)));
1601 }
1602
1603
1604 THREADED_TEST(NumberObject) {
1605   LocalContext env;
1606   v8::HandleScope scope(env->GetIsolate());
1607   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1608   CHECK(boxed_number->IsNumberObject());
1609   v8::Handle<Value> unboxed_number = CompileRun("42");
1610   CHECK(!unboxed_number->IsNumberObject());
1611   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1612   CHECK(!boxed_not_number->IsNumberObject());
1613   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1614   CHECK(!as_boxed.IsEmpty());
1615   double the_number = as_boxed->ValueOf();
1616   CHECK_EQ(42.0, the_number);
1617   v8::Handle<v8::Value> new_boxed_number =
1618       v8::NumberObject::New(env->GetIsolate(), 43);
1619   CHECK(new_boxed_number->IsNumberObject());
1620   as_boxed = new_boxed_number.As<v8::NumberObject>();
1621   the_number = as_boxed->ValueOf();
1622   CHECK_EQ(43.0, the_number);
1623 }
1624
1625
1626 THREADED_TEST(BooleanObject) {
1627   LocalContext env;
1628   v8::HandleScope scope(env->GetIsolate());
1629   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1630   CHECK(boxed_boolean->IsBooleanObject());
1631   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1632   CHECK(!unboxed_boolean->IsBooleanObject());
1633   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1634   CHECK(!boxed_not_boolean->IsBooleanObject());
1635   v8::Handle<v8::BooleanObject> as_boxed =
1636       boxed_boolean.As<v8::BooleanObject>();
1637   CHECK(!as_boxed.IsEmpty());
1638   bool the_boolean = as_boxed->ValueOf();
1639   CHECK_EQ(true, the_boolean);
1640   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1641   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1642   CHECK(boxed_true->IsBooleanObject());
1643   CHECK(boxed_false->IsBooleanObject());
1644   as_boxed = boxed_true.As<v8::BooleanObject>();
1645   CHECK_EQ(true, as_boxed->ValueOf());
1646   as_boxed = boxed_false.As<v8::BooleanObject>();
1647   CHECK_EQ(false, as_boxed->ValueOf());
1648 }
1649
1650
1651 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1652   LocalContext env;
1653   v8::HandleScope scope(env->GetIsolate());
1654
1655   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1656   CHECK(primitive_false->IsBoolean());
1657   CHECK(!primitive_false->IsBooleanObject());
1658   CHECK(!primitive_false->BooleanValue());
1659   CHECK(!primitive_false->IsTrue());
1660   CHECK(primitive_false->IsFalse());
1661
1662   Local<Value> false_value = BooleanObject::New(false);
1663   CHECK(!false_value->IsBoolean());
1664   CHECK(false_value->IsBooleanObject());
1665   CHECK(false_value->BooleanValue());
1666   CHECK(!false_value->IsTrue());
1667   CHECK(!false_value->IsFalse());
1668
1669   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1670   CHECK(!false_boolean_object->IsBoolean());
1671   CHECK(false_boolean_object->IsBooleanObject());
1672   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1673   // CHECK(false_boolean_object->BooleanValue());
1674   CHECK(!false_boolean_object->ValueOf());
1675   CHECK(!false_boolean_object->IsTrue());
1676   CHECK(!false_boolean_object->IsFalse());
1677
1678   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1679   CHECK(primitive_true->IsBoolean());
1680   CHECK(!primitive_true->IsBooleanObject());
1681   CHECK(primitive_true->BooleanValue());
1682   CHECK(primitive_true->IsTrue());
1683   CHECK(!primitive_true->IsFalse());
1684
1685   Local<Value> true_value = BooleanObject::New(true);
1686   CHECK(!true_value->IsBoolean());
1687   CHECK(true_value->IsBooleanObject());
1688   CHECK(true_value->BooleanValue());
1689   CHECK(!true_value->IsTrue());
1690   CHECK(!true_value->IsFalse());
1691
1692   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1693   CHECK(!true_boolean_object->IsBoolean());
1694   CHECK(true_boolean_object->IsBooleanObject());
1695   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1696   // CHECK(true_boolean_object->BooleanValue());
1697   CHECK(true_boolean_object->ValueOf());
1698   CHECK(!true_boolean_object->IsTrue());
1699   CHECK(!true_boolean_object->IsFalse());
1700 }
1701
1702
1703 THREADED_TEST(Number) {
1704   LocalContext env;
1705   v8::HandleScope scope(env->GetIsolate());
1706   double PI = 3.1415926;
1707   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1708   CHECK_EQ(PI, pi_obj->NumberValue());
1709 }
1710
1711
1712 THREADED_TEST(ToNumber) {
1713   LocalContext env;
1714   v8::Isolate* isolate = CcTest::isolate();
1715   v8::HandleScope scope(isolate);
1716   Local<String> str = v8_str("3.1415926");
1717   CHECK_EQ(3.1415926, str->NumberValue());
1718   v8::Handle<v8::Boolean> t = v8::True(isolate);
1719   CHECK_EQ(1.0, t->NumberValue());
1720   v8::Handle<v8::Boolean> f = v8::False(isolate);
1721   CHECK_EQ(0.0, f->NumberValue());
1722 }
1723
1724
1725 THREADED_TEST(Date) {
1726   LocalContext env;
1727   v8::HandleScope scope(env->GetIsolate());
1728   double PI = 3.1415926;
1729   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1730   CHECK_EQ(3.0, date->NumberValue());
1731   date.As<v8::Date>()->Set(v8_str("property"),
1732                            v8::Integer::New(env->GetIsolate(), 42));
1733   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1734 }
1735
1736
1737 THREADED_TEST(Boolean) {
1738   LocalContext env;
1739   v8::Isolate* isolate = env->GetIsolate();
1740   v8::HandleScope scope(isolate);
1741   v8::Handle<v8::Boolean> t = v8::True(isolate);
1742   CHECK(t->Value());
1743   v8::Handle<v8::Boolean> f = v8::False(isolate);
1744   CHECK(!f->Value());
1745   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1746   CHECK(!u->BooleanValue());
1747   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1748   CHECK(!n->BooleanValue());
1749   v8::Handle<String> str1 = v8_str("");
1750   CHECK(!str1->BooleanValue());
1751   v8::Handle<String> str2 = v8_str("x");
1752   CHECK(str2->BooleanValue());
1753   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1754   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1755   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1756   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1757   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1758 }
1759
1760
1761 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1762   ApiTestFuzzer::Fuzz();
1763   args.GetReturnValue().Set(v8_num(13.4));
1764 }
1765
1766
1767 static void GetM(Local<String> name,
1768                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1769   ApiTestFuzzer::Fuzz();
1770   info.GetReturnValue().Set(v8_num(876));
1771 }
1772
1773
1774 THREADED_TEST(GlobalPrototype) {
1775   v8::Isolate* isolate = CcTest::isolate();
1776   v8::HandleScope scope(isolate);
1777   v8::Handle<v8::FunctionTemplate> func_templ =
1778       v8::FunctionTemplate::New(isolate);
1779   func_templ->PrototypeTemplate()->Set(
1780       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1781   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1782   templ->Set(isolate, "x", v8_num(200));
1783   templ->SetAccessor(v8_str("m"), GetM);
1784   LocalContext env(0, templ);
1785   v8::Handle<Script> script(v8_compile("dummy()"));
1786   v8::Handle<Value> result(script->Run());
1787   CHECK_EQ(13.4, result->NumberValue());
1788   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1789   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1790 }
1791
1792
1793 THREADED_TEST(ObjectTemplate) {
1794   v8::Isolate* isolate = CcTest::isolate();
1795   v8::HandleScope scope(isolate);
1796   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1797   v8::Local<v8::String> class_name =
1798       v8::String::NewFromUtf8(isolate, "the_class_name");
1799   fun->SetClassName(class_name);
1800   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
1801   templ1->Set(isolate, "x", v8_num(10));
1802   templ1->Set(isolate, "y", v8_num(13));
1803   LocalContext env;
1804   Local<v8::Object> instance1 = templ1->NewInstance();
1805   CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
1806   env->Global()->Set(v8_str("p"), instance1);
1807   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1808   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1809   Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
1810   fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1811   Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
1812   templ2->Set(isolate, "a", v8_num(12));
1813   templ2->Set(isolate, "b", templ1);
1814   Local<v8::Object> instance2 = templ2->NewInstance();
1815   env->Global()->Set(v8_str("q"), instance2);
1816   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1817   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1818   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1819   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1820 }
1821
1822
1823 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1824   ApiTestFuzzer::Fuzz();
1825   args.GetReturnValue().Set(v8_num(17.2));
1826 }
1827
1828
1829 static void GetKnurd(Local<String> property,
1830                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1831   ApiTestFuzzer::Fuzz();
1832   info.GetReturnValue().Set(v8_num(15.2));
1833 }
1834
1835
1836 THREADED_TEST(DescriptorInheritance) {
1837   v8::Isolate* isolate = CcTest::isolate();
1838   v8::HandleScope scope(isolate);
1839   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1840   super->PrototypeTemplate()->Set(isolate, "flabby",
1841                                   v8::FunctionTemplate::New(isolate,
1842                                                             GetFlabby));
1843   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1844
1845   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1846
1847   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1848   base1->Inherit(super);
1849   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1850
1851   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1852   base2->Inherit(super);
1853   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1854
1855   LocalContext env;
1856
1857   env->Global()->Set(v8_str("s"), super->GetFunction());
1858   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1859   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1860
1861   // Checks right __proto__ chain.
1862   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1863   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1864
1865   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1866
1867   // Instance accessor should not be visible on function object or its prototype
1868   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1869   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1870   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1871
1872   env->Global()->Set(v8_str("obj"),
1873                      base1->GetFunction()->NewInstance());
1874   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1875   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1876   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1877   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1878   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1879
1880   env->Global()->Set(v8_str("obj2"),
1881                      base2->GetFunction()->NewInstance());
1882   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1883   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1884   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1885   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1886   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1887
1888   // base1 and base2 cannot cross reference to each's prototype
1889   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1890   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1891 }
1892
1893
1894 // Helper functions for Interceptor/Accessor interaction tests
1895
1896 void SimpleAccessorGetter(Local<String> name,
1897                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1898   Handle<Object> self = Handle<Object>::Cast(info.This());
1899   info.GetReturnValue().Set(
1900       self->Get(String::Concat(v8_str("accessor_"), name)));
1901 }
1902
1903 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1904                           const v8::PropertyCallbackInfo<void>& info) {
1905   Handle<Object> self = Handle<Object>::Cast(info.This());
1906   self->Set(String::Concat(v8_str("accessor_"), name), value);
1907 }
1908
1909 void SymbolAccessorGetter(Local<Name> name,
1910                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1911   CHECK(name->IsSymbol());
1912   Local<Symbol> sym = Local<Symbol>::Cast(name);
1913   if (sym->Name()->IsUndefined())
1914     return;
1915   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
1916 }
1917
1918 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1919                           const v8::PropertyCallbackInfo<void>& info) {
1920   CHECK(name->IsSymbol());
1921   Local<Symbol> sym = Local<Symbol>::Cast(name);
1922   if (sym->Name()->IsUndefined())
1923     return;
1924   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
1925 }
1926
1927 void SymbolAccessorGetterReturnsDefault(
1928     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1929   CHECK(name->IsSymbol());
1930   Local<Symbol> sym = Local<Symbol>::Cast(name);
1931   if (sym->Name()->IsUndefined()) return;
1932   info.GetReturnValue().Set(info.Data());
1933 }
1934
1935 static void ThrowingSymbolAccessorGetter(
1936     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1937   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
1938 }
1939
1940
1941 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1942   v8::Isolate* isolate = CcTest::isolate();
1943   v8::HandleScope scope(isolate);
1944   LocalContext env;
1945   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1946   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1947   CHECK(a->map()->instance_descriptors()->IsFixedArray());
1948   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1949   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1950   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1951   // But we should still have an ExecutableAccessorInfo.
1952   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1953   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
1954   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
1955   CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
1956 }
1957
1958
1959 THREADED_TEST(UndefinedIsNotEnumerable) {
1960   LocalContext env;
1961   v8::HandleScope scope(env->GetIsolate());
1962   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
1963   CHECK(result->IsFalse());
1964 }
1965
1966
1967 v8::Handle<Script> call_recursively_script;
1968 static const int kTargetRecursionDepth = 200;  // near maximum
1969
1970
1971 static void CallScriptRecursivelyCall(
1972     const v8::FunctionCallbackInfo<v8::Value>& args) {
1973   ApiTestFuzzer::Fuzz();
1974   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1975   if (depth == kTargetRecursionDepth) return;
1976   args.This()->Set(v8_str("depth"),
1977                    v8::Integer::New(args.GetIsolate(), depth + 1));
1978   args.GetReturnValue().Set(call_recursively_script->Run());
1979 }
1980
1981
1982 static void CallFunctionRecursivelyCall(
1983     const v8::FunctionCallbackInfo<v8::Value>& args) {
1984   ApiTestFuzzer::Fuzz();
1985   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1986   if (depth == kTargetRecursionDepth) {
1987     printf("[depth = %d]\n", depth);
1988     return;
1989   }
1990   args.This()->Set(v8_str("depth"),
1991                    v8::Integer::New(args.GetIsolate(), depth + 1));
1992   v8::Handle<Value> function =
1993       args.This()->Get(v8_str("callFunctionRecursively"));
1994   args.GetReturnValue().Set(
1995       function.As<Function>()->Call(args.This(), 0, NULL));
1996 }
1997
1998
1999 THREADED_TEST(DeepCrossLanguageRecursion) {
2000   v8::Isolate* isolate = CcTest::isolate();
2001   v8::HandleScope scope(isolate);
2002   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2003   global->Set(v8_str("callScriptRecursively"),
2004               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2005   global->Set(v8_str("callFunctionRecursively"),
2006               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2007   LocalContext env(NULL, global);
2008
2009   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2010   call_recursively_script = v8_compile("callScriptRecursively()");
2011   call_recursively_script->Run();
2012   call_recursively_script = v8::Handle<Script>();
2013
2014   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2015   CompileRun("callFunctionRecursively()");
2016 }
2017
2018
2019 static void ThrowingPropertyHandlerGet(
2020     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2021   // Since this interceptor is used on "with" objects, the runtime will look up
2022   // @@unscopables.  Punt.
2023   if (key->IsSymbol()) return;
2024   ApiTestFuzzer::Fuzz();
2025   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2026 }
2027
2028
2029 static void ThrowingPropertyHandlerSet(
2030     Local<Name> key, Local<Value>,
2031     const v8::PropertyCallbackInfo<v8::Value>& info) {
2032   info.GetIsolate()->ThrowException(key);
2033   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2034 }
2035
2036
2037 THREADED_TEST(CallbackExceptionRegression) {
2038   v8::Isolate* isolate = CcTest::isolate();
2039   v8::HandleScope scope(isolate);
2040   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2041   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2042       ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2043   LocalContext env;
2044   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2045   v8::Handle<Value> otto =
2046       CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2047   CHECK(v8_str("otto")->Equals(otto));
2048   v8::Handle<Value> netto =
2049       CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2050   CHECK(v8_str("netto")->Equals(netto));
2051 }
2052
2053
2054 THREADED_TEST(FunctionPrototype) {
2055   v8::Isolate* isolate = CcTest::isolate();
2056   v8::HandleScope scope(isolate);
2057   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2058   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2059   LocalContext env;
2060   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2061   Local<Script> script = v8_compile("Foo.prototype.plak");
2062   CHECK_EQ(script->Run()->Int32Value(), 321);
2063 }
2064
2065
2066 THREADED_TEST(InternalFields) {
2067   LocalContext env;
2068   v8::Isolate* isolate = env->GetIsolate();
2069   v8::HandleScope scope(isolate);
2070
2071   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2072   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2073   instance_templ->SetInternalFieldCount(1);
2074   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2075   CHECK_EQ(1, obj->InternalFieldCount());
2076   CHECK(obj->GetInternalField(0)->IsUndefined());
2077   obj->SetInternalField(0, v8_num(17));
2078   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2079 }
2080
2081
2082 THREADED_TEST(GlobalObjectInternalFields) {
2083   v8::Isolate* isolate = CcTest::isolate();
2084   v8::HandleScope scope(isolate);
2085   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2086   global_template->SetInternalFieldCount(1);
2087   LocalContext env(NULL, global_template);
2088   v8::Handle<v8::Object> global_proxy = env->Global();
2089   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2090   CHECK_EQ(1, global->InternalFieldCount());
2091   CHECK(global->GetInternalField(0)->IsUndefined());
2092   global->SetInternalField(0, v8_num(17));
2093   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2094 }
2095
2096
2097 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2098   LocalContext env;
2099   v8::HandleScope scope(CcTest::isolate());
2100
2101   v8::Local<v8::Object> global = env->Global();
2102   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2103   CHECK(global->HasRealIndexedProperty(0));
2104 }
2105
2106
2107 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2108                                                void* value) {
2109   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2110   obj->SetAlignedPointerInInternalField(0, value);
2111   CcTest::heap()->CollectAllGarbage();
2112   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2113 }
2114
2115
2116 THREADED_TEST(InternalFieldsAlignedPointers) {
2117   LocalContext env;
2118   v8::Isolate* isolate = env->GetIsolate();
2119   v8::HandleScope scope(isolate);
2120
2121   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2122   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2123   instance_templ->SetInternalFieldCount(1);
2124   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2125   CHECK_EQ(1, obj->InternalFieldCount());
2126
2127   CheckAlignedPointerInInternalField(obj, NULL);
2128
2129   int* heap_allocated = new int[100];
2130   CheckAlignedPointerInInternalField(obj, heap_allocated);
2131   delete[] heap_allocated;
2132
2133   int stack_allocated[100];
2134   CheckAlignedPointerInInternalField(obj, stack_allocated);
2135
2136   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2137   CheckAlignedPointerInInternalField(obj, huge);
2138
2139   v8::Global<v8::Object> persistent(isolate, obj);
2140   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2141   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2142 }
2143
2144
2145 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2146                                               void* value) {
2147   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2148   (*env)->SetAlignedPointerInEmbedderData(index, value);
2149   CcTest::heap()->CollectAllGarbage();
2150   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2151 }
2152
2153
2154 static void* AlignedTestPointer(int i) {
2155   return reinterpret_cast<void*>(i * 1234);
2156 }
2157
2158
2159 THREADED_TEST(EmbedderDataAlignedPointers) {
2160   LocalContext env;
2161   v8::HandleScope scope(env->GetIsolate());
2162
2163   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2164
2165   int* heap_allocated = new int[100];
2166   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2167   delete[] heap_allocated;
2168
2169   int stack_allocated[100];
2170   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2171
2172   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2173   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2174
2175   // Test growing of the embedder data's backing store.
2176   for (int i = 0; i < 100; i++) {
2177     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2178   }
2179   CcTest::heap()->CollectAllGarbage();
2180   for (int i = 0; i < 100; i++) {
2181     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2182   }
2183 }
2184
2185
2186 static void CheckEmbedderData(LocalContext* env, int index,
2187                               v8::Handle<Value> data) {
2188   (*env)->SetEmbedderData(index, data);
2189   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2190 }
2191
2192
2193 THREADED_TEST(EmbedderData) {
2194   LocalContext env;
2195   v8::Isolate* isolate = env->GetIsolate();
2196   v8::HandleScope scope(isolate);
2197
2198   CheckEmbedderData(
2199       &env, 3, v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2200   CheckEmbedderData(&env, 2,
2201                     v8::String::NewFromUtf8(isolate, "over the lazy dog."));
2202   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2203   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2204 }
2205
2206
2207 THREADED_TEST(GetIsolate) {
2208   LocalContext env;
2209   v8::Isolate* isolate = env->GetIsolate();
2210   v8::HandleScope scope(isolate);
2211   Local<v8::Object> obj = v8::Object::New(isolate);
2212   CHECK_EQ(isolate, obj->GetIsolate());
2213   CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2214 }
2215
2216
2217 THREADED_TEST(IdentityHash) {
2218   LocalContext env;
2219   v8::Isolate* isolate = env->GetIsolate();
2220   v8::HandleScope scope(isolate);
2221
2222   // Ensure that the test starts with an fresh heap to test whether the hash
2223   // code is based on the address.
2224   CcTest::heap()->CollectAllGarbage();
2225   Local<v8::Object> obj = v8::Object::New(isolate);
2226   int hash = obj->GetIdentityHash();
2227   int hash1 = obj->GetIdentityHash();
2228   CHECK_EQ(hash, hash1);
2229   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2230   // Since the identity hash is essentially a random number two consecutive
2231   // objects should not be assigned the same hash code. If the test below fails
2232   // the random number generator should be evaluated.
2233   CHECK_NE(hash, hash2);
2234   CcTest::heap()->CollectAllGarbage();
2235   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2236   // Make sure that the identity hash is not based on the initial address of
2237   // the object alone. If the test below fails the random number generator
2238   // should be evaluated.
2239   CHECK_NE(hash, hash3);
2240   int hash4 = obj->GetIdentityHash();
2241   CHECK_EQ(hash, hash4);
2242
2243   // Check identity hashes behaviour in the presence of JS accessors.
2244   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2245   {
2246     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2247     Local<v8::Object> o1 = v8::Object::New(isolate);
2248     Local<v8::Object> o2 = v8::Object::New(isolate);
2249     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2250   }
2251   {
2252     CompileRun(
2253         "function cnst() { return 42; };\n"
2254         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2255     Local<v8::Object> o1 = v8::Object::New(isolate);
2256     Local<v8::Object> o2 = v8::Object::New(isolate);
2257     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2258   }
2259 }
2260
2261
2262 void GlobalProxyIdentityHash(bool set_in_js) {
2263   LocalContext env;
2264   v8::Isolate* isolate = env->GetIsolate();
2265   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2266   v8::HandleScope scope(isolate);
2267   Handle<Object> global_proxy = env->Global();
2268   i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
2269   env->Global()->Set(v8_str("global"), global_proxy);
2270   i::Handle<i::Object> original_hash;
2271   if (set_in_js) {
2272     CompileRun("var m = new Set(); m.add(global);");
2273     original_hash = i::Handle<i::Object>(i_global_proxy->GetHash(), i_isolate);
2274   } else {
2275     original_hash = i::Handle<i::Object>(
2276         i::Object::GetOrCreateHash(i_isolate, i_global_proxy));
2277   }
2278   CHECK(original_hash->IsSmi());
2279   int32_t hash1 = i::Handle<i::Smi>::cast(original_hash)->value();
2280   // Hash should be retained after being detached.
2281   env->DetachGlobal();
2282   int hash2 = global_proxy->GetIdentityHash();
2283   CHECK_EQ(hash1, hash2);
2284   {
2285     // Re-attach global proxy to a new context, hash should stay the same.
2286     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2287     int hash3 = global_proxy->GetIdentityHash();
2288     CHECK_EQ(hash1, hash3);
2289   }
2290 }
2291
2292
2293 THREADED_TEST(GlobalProxyIdentityHash) {
2294   GlobalProxyIdentityHash(true);
2295   GlobalProxyIdentityHash(false);
2296 }
2297
2298
2299 TEST(SymbolIdentityHash) {
2300   LocalContext env;
2301   v8::Isolate* isolate = env->GetIsolate();
2302   v8::HandleScope scope(isolate);
2303
2304   {
2305     Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2306     int hash = symbol->GetIdentityHash();
2307     int hash1 = symbol->GetIdentityHash();
2308     CHECK_EQ(hash, hash1);
2309     CcTest::heap()->CollectAllGarbage();
2310     int hash3 = symbol->GetIdentityHash();
2311     CHECK_EQ(hash, hash3);
2312   }
2313
2314   {
2315     v8::Handle<v8::Symbol> js_symbol =
2316         CompileRun("Symbol('foo')").As<v8::Symbol>();
2317     int hash = js_symbol->GetIdentityHash();
2318     int hash1 = js_symbol->GetIdentityHash();
2319     CHECK_EQ(hash, hash1);
2320     CcTest::heap()->CollectAllGarbage();
2321     int hash3 = js_symbol->GetIdentityHash();
2322     CHECK_EQ(hash, hash3);
2323   }
2324 }
2325
2326
2327 TEST(StringIdentityHash) {
2328   LocalContext env;
2329   v8::Isolate* isolate = env->GetIsolate();
2330   v8::HandleScope scope(isolate);
2331
2332   Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
2333   int hash = str->GetIdentityHash();
2334   int hash1 = str->GetIdentityHash();
2335   CHECK_EQ(hash, hash1);
2336   CcTest::heap()->CollectAllGarbage();
2337   int hash3 = str->GetIdentityHash();
2338   CHECK_EQ(hash, hash3);
2339
2340   Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
2341   int hash4 = str2->GetIdentityHash();
2342   CHECK_EQ(hash, hash4);
2343 }
2344
2345
2346 THREADED_TEST(SymbolProperties) {
2347   LocalContext env;
2348   v8::Isolate* isolate = env->GetIsolate();
2349   v8::HandleScope scope(isolate);
2350
2351   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2352   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2353   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
2354   v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
2355
2356   CcTest::heap()->CollectAllGarbage();
2357
2358   // Check basic symbol functionality.
2359   CHECK(sym1->IsSymbol());
2360   CHECK(sym2->IsSymbol());
2361   CHECK(!obj->IsSymbol());
2362
2363   CHECK(sym1->Equals(sym1));
2364   CHECK(sym2->Equals(sym2));
2365   CHECK(!sym1->Equals(sym2));
2366   CHECK(!sym2->Equals(sym1));
2367   CHECK(sym1->StrictEquals(sym1));
2368   CHECK(sym2->StrictEquals(sym2));
2369   CHECK(!sym1->StrictEquals(sym2));
2370   CHECK(!sym2->StrictEquals(sym1));
2371
2372   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2373
2374   v8::Local<v8::Value> sym_val = sym2;
2375   CHECK(sym_val->IsSymbol());
2376   CHECK(sym_val->Equals(sym2));
2377   CHECK(sym_val->StrictEquals(sym2));
2378   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2379
2380   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2381   CHECK(sym_obj->IsSymbolObject());
2382   CHECK(!sym2->IsSymbolObject());
2383   CHECK(!obj->IsSymbolObject());
2384   CHECK(!sym_obj->Equals(sym2));
2385   CHECK(!sym_obj->StrictEquals(sym2));
2386   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2387   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2388
2389   // Make sure delete of a non-existent symbol property works.
2390   CHECK(obj->Delete(sym1));
2391   CHECK(!obj->Has(sym1));
2392
2393   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2394   CHECK(obj->Has(sym1));
2395   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2396   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2397   CHECK(obj->Has(sym1));
2398   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2399   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2400
2401   CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2402   unsigned num_props = obj->GetPropertyNames()->Length();
2403   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2404                  v8::Integer::New(isolate, 20)));
2405   CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2406   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2407
2408   CcTest::heap()->CollectAllGarbage();
2409
2410   CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2411   CHECK(obj->Get(sym3)->IsUndefined());
2412   CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2413   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2414   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2415             ->Equals(v8::Integer::New(isolate, 42)));
2416
2417   // Add another property and delete it afterwards to force the object in
2418   // slow case.
2419   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2420   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2421   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2422   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2423   CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2424
2425   CHECK(obj->Has(sym1));
2426   CHECK(obj->Has(sym2));
2427   CHECK(obj->Has(sym3));
2428   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2429   CHECK(obj->Delete(sym2));
2430   CHECK(obj->Has(sym1));
2431   CHECK(!obj->Has(sym2));
2432   CHECK(obj->Has(sym3));
2433   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2434   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2435   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2436   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2437             ->Equals(v8::Integer::New(isolate, 42)));
2438   CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2439
2440   // Symbol properties are inherited.
2441   v8::Local<v8::Object> child = v8::Object::New(isolate);
2442   child->SetPrototype(obj);
2443   CHECK(child->Has(sym1));
2444   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2445   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2446   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2447             ->Equals(v8::Integer::New(isolate, 42)));
2448   CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2449 }
2450
2451
2452 THREADED_TEST(SymbolTemplateProperties) {
2453   LocalContext env;
2454   v8::Isolate* isolate = env->GetIsolate();
2455   v8::HandleScope scope(isolate);
2456   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2457   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2458   CHECK(!name.IsEmpty());
2459   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2460   v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2461   CHECK(!new_instance.IsEmpty());
2462   CHECK(new_instance->Has(name));
2463 }
2464
2465
2466 THREADED_TEST(GlobalSymbols) {
2467   LocalContext env;
2468   v8::Isolate* isolate = env->GetIsolate();
2469   v8::HandleScope scope(isolate);
2470
2471   v8::Local<String> name = v8_str("my-symbol");
2472   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2473   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2474   CHECK(glob2->SameValue(glob));
2475
2476   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2477   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2478   CHECK(glob_api2->SameValue(glob_api));
2479   CHECK(!glob_api->SameValue(glob));
2480
2481   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2482   CHECK(!sym->SameValue(glob));
2483
2484   CompileRun("var sym2 = Symbol.for('my-symbol')");
2485   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2486   CHECK(sym2->SameValue(glob));
2487   CHECK(!sym2->SameValue(glob_api));
2488 }
2489
2490
2491 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
2492                                  const char* name) {
2493   LocalContext env;
2494   v8::Isolate* isolate = env->GetIsolate();
2495   v8::HandleScope scope(isolate);
2496
2497   v8::Local<v8::Symbol> symbol = getter(isolate);
2498   std::string script = std::string("var sym = ") + name;
2499   CompileRun(script.c_str());
2500   v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
2501
2502   CHECK(!value.IsEmpty());
2503   CHECK(!symbol.IsEmpty());
2504   CHECK(value->SameValue(symbol));
2505 }
2506
2507
2508 THREADED_TEST(WellKnownSymbols) {
2509   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
2510   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
2511 }
2512
2513
2514 class ScopedArrayBufferContents {
2515  public:
2516   explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
2517       : contents_(contents) {}
2518   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2519   void* Data() const { return contents_.Data(); }
2520   size_t ByteLength() const { return contents_.ByteLength(); }
2521
2522  private:
2523   const v8::ArrayBuffer::Contents contents_;
2524 };
2525
2526 template <typename T>
2527 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2528   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2529   for (int i = 0; i < value->InternalFieldCount(); i++) {
2530     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2531   }
2532 }
2533
2534
2535 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2536   LocalContext env;
2537   v8::Isolate* isolate = env->GetIsolate();
2538   v8::HandleScope handle_scope(isolate);
2539
2540   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2541   CheckInternalFieldsAreZero(ab);
2542   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2543   CHECK(!ab->IsExternal());
2544   CcTest::heap()->CollectAllGarbage();
2545
2546   ScopedArrayBufferContents ab_contents(ab->Externalize());
2547   CHECK(ab->IsExternal());
2548
2549   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2550   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2551   DCHECK(data != NULL);
2552   env->Global()->Set(v8_str("ab"), ab);
2553
2554   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2555   CHECK_EQ(1024, result->Int32Value());
2556
2557   result = CompileRun(
2558       "var u8 = new Uint8Array(ab);"
2559       "u8[0] = 0xFF;"
2560       "u8[1] = 0xAA;"
2561       "u8.length");
2562   CHECK_EQ(1024, result->Int32Value());
2563   CHECK_EQ(0xFF, data[0]);
2564   CHECK_EQ(0xAA, data[1]);
2565   data[0] = 0xCC;
2566   data[1] = 0x11;
2567   result = CompileRun("u8[0] + u8[1]");
2568   CHECK_EQ(0xDD, result->Int32Value());
2569 }
2570
2571
2572 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2573   LocalContext env;
2574   v8::Isolate* isolate = env->GetIsolate();
2575   v8::HandleScope handle_scope(isolate);
2576
2577
2578   v8::Local<v8::Value> result = CompileRun(
2579       "var ab1 = new ArrayBuffer(2);"
2580       "var u8_a = new Uint8Array(ab1);"
2581       "u8_a[0] = 0xAA;"
2582       "u8_a[1] = 0xFF; u8_a.buffer");
2583   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2584   CheckInternalFieldsAreZero(ab1);
2585   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2586   CHECK(!ab1->IsExternal());
2587   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2588   CHECK(ab1->IsExternal());
2589
2590   result = CompileRun("ab1.byteLength");
2591   CHECK_EQ(2, result->Int32Value());
2592   result = CompileRun("u8_a[0]");
2593   CHECK_EQ(0xAA, result->Int32Value());
2594   result = CompileRun("u8_a[1]");
2595   CHECK_EQ(0xFF, result->Int32Value());
2596   result = CompileRun(
2597       "var u8_b = new Uint8Array(ab1);"
2598       "u8_b[0] = 0xBB;"
2599       "u8_a[0]");
2600   CHECK_EQ(0xBB, result->Int32Value());
2601   result = CompileRun("u8_b[1]");
2602   CHECK_EQ(0xFF, result->Int32Value());
2603
2604   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2605   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2606   CHECK_EQ(0xBB, ab1_data[0]);
2607   CHECK_EQ(0xFF, ab1_data[1]);
2608   ab1_data[0] = 0xCC;
2609   ab1_data[1] = 0x11;
2610   result = CompileRun("u8_a[0] + u8_a[1]");
2611   CHECK_EQ(0xDD, result->Int32Value());
2612 }
2613
2614
2615 THREADED_TEST(ArrayBuffer_External) {
2616   LocalContext env;
2617   v8::Isolate* isolate = env->GetIsolate();
2618   v8::HandleScope handle_scope(isolate);
2619
2620   i::ScopedVector<uint8_t> my_data(100);
2621   memset(my_data.start(), 0, 100);
2622   Local<v8::ArrayBuffer> ab3 =
2623       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2624   CheckInternalFieldsAreZero(ab3);
2625   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2626   CHECK(ab3->IsExternal());
2627
2628   env->Global()->Set(v8_str("ab3"), ab3);
2629
2630   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2631   CHECK_EQ(100, result->Int32Value());
2632
2633   result = CompileRun(
2634       "var u8_b = new Uint8Array(ab3);"
2635       "u8_b[0] = 0xBB;"
2636       "u8_b[1] = 0xCC;"
2637       "u8_b.length");
2638   CHECK_EQ(100, result->Int32Value());
2639   CHECK_EQ(0xBB, my_data[0]);
2640   CHECK_EQ(0xCC, my_data[1]);
2641   my_data[0] = 0xCC;
2642   my_data[1] = 0x11;
2643   result = CompileRun("u8_b[0] + u8_b[1]");
2644   CHECK_EQ(0xDD, result->Int32Value());
2645 }
2646
2647
2648 THREADED_TEST(ArrayBuffer_DisableNeuter) {
2649   LocalContext env;
2650   v8::Isolate* isolate = env->GetIsolate();
2651   v8::HandleScope handle_scope(isolate);
2652
2653   i::ScopedVector<uint8_t> my_data(100);
2654   memset(my_data.start(), 0, 100);
2655   Local<v8::ArrayBuffer> ab =
2656       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2657   CHECK(ab->IsNeuterable());
2658
2659   i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
2660   buf->set_is_neuterable(false);
2661
2662   CHECK(!ab->IsNeuterable());
2663 }
2664
2665
2666 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2667   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2668   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2669 }
2670
2671
2672 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2673   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2674   CHECK_EQ(0, static_cast<int>(ta->Length()));
2675   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2676 }
2677
2678
2679 static void CheckIsTypedArrayVarNeutered(const char* name) {
2680   i::ScopedVector<char> source(1024);
2681   i::SNPrintF(source,
2682               "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2683               name, name, name);
2684   CHECK(CompileRun(source.start())->IsTrue());
2685   v8::Handle<v8::TypedArray> ta =
2686       v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2687   CheckIsNeutered(ta);
2688 }
2689
2690
2691 template <typename TypedArray, int kElementSize>
2692 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2693                                          int byteOffset, int length) {
2694   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2695   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2696   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2697   CHECK_EQ(length, static_cast<int>(ta->Length()));
2698   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2699   return ta;
2700 }
2701
2702
2703 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2704   LocalContext env;
2705   v8::Isolate* isolate = env->GetIsolate();
2706   v8::HandleScope handle_scope(isolate);
2707
2708   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
2709
2710   v8::Handle<v8::Uint8Array> u8a =
2711       CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2712   v8::Handle<v8::Uint8ClampedArray> u8c =
2713       CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2714   v8::Handle<v8::Int8Array> i8a =
2715       CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2716
2717   v8::Handle<v8::Uint16Array> u16a =
2718       CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2719   v8::Handle<v8::Int16Array> i16a =
2720       CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2721
2722   v8::Handle<v8::Uint32Array> u32a =
2723       CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2724   v8::Handle<v8::Int32Array> i32a =
2725       CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2726
2727   v8::Handle<v8::Float32Array> f32a =
2728       CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2729   v8::Handle<v8::Float64Array> f64a =
2730       CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2731
2732   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2733   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2734   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2735   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2736
2737   ScopedArrayBufferContents contents(buffer->Externalize());
2738   buffer->Neuter();
2739   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2740   CheckIsNeutered(u8a);
2741   CheckIsNeutered(u8c);
2742   CheckIsNeutered(i8a);
2743   CheckIsNeutered(u16a);
2744   CheckIsNeutered(i16a);
2745   CheckIsNeutered(u32a);
2746   CheckIsNeutered(i32a);
2747   CheckIsNeutered(f32a);
2748   CheckIsNeutered(f64a);
2749   CheckDataViewIsNeutered(dv);
2750 }
2751
2752
2753 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2754   LocalContext env;
2755   v8::Isolate* isolate = env->GetIsolate();
2756   v8::HandleScope handle_scope(isolate);
2757
2758   CompileRun(
2759       "var ab = new ArrayBuffer(1024);"
2760       "var u8a = new Uint8Array(ab, 1, 1023);"
2761       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2762       "var i8a = new Int8Array(ab, 1, 1023);"
2763       "var u16a = new Uint16Array(ab, 2, 511);"
2764       "var i16a = new Int16Array(ab, 2, 511);"
2765       "var u32a = new Uint32Array(ab, 4, 255);"
2766       "var i32a = new Int32Array(ab, 4, 255);"
2767       "var f32a = new Float32Array(ab, 4, 255);"
2768       "var f64a = new Float64Array(ab, 8, 127);"
2769       "var dv = new DataView(ab, 1, 1023);");
2770
2771   v8::Handle<v8::ArrayBuffer> ab =
2772       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2773
2774   v8::Handle<v8::DataView> dv =
2775       v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2776
2777   ScopedArrayBufferContents contents(ab->Externalize());
2778   ab->Neuter();
2779   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2780   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2781
2782   CheckIsTypedArrayVarNeutered("u8a");
2783   CheckIsTypedArrayVarNeutered("u8c");
2784   CheckIsTypedArrayVarNeutered("i8a");
2785   CheckIsTypedArrayVarNeutered("u16a");
2786   CheckIsTypedArrayVarNeutered("i16a");
2787   CheckIsTypedArrayVarNeutered("u32a");
2788   CheckIsTypedArrayVarNeutered("i32a");
2789   CheckIsTypedArrayVarNeutered("f32a");
2790   CheckIsTypedArrayVarNeutered("f64a");
2791
2792   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2793   CheckDataViewIsNeutered(dv);
2794 }
2795
2796
2797 class ScopedSharedArrayBufferContents {
2798  public:
2799   explicit ScopedSharedArrayBufferContents(
2800       const v8::SharedArrayBuffer::Contents& contents)
2801       : contents_(contents) {}
2802   ~ScopedSharedArrayBufferContents() { free(contents_.Data()); }
2803   void* Data() const { return contents_.Data(); }
2804   size_t ByteLength() const { return contents_.ByteLength(); }
2805
2806  private:
2807   const v8::SharedArrayBuffer::Contents contents_;
2808 };
2809
2810
2811 THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
2812   i::FLAG_harmony_sharedarraybuffer = true;
2813   LocalContext env;
2814   v8::Isolate* isolate = env->GetIsolate();
2815   v8::HandleScope handle_scope(isolate);
2816
2817   Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
2818   CheckInternalFieldsAreZero(ab);
2819   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2820   CHECK(!ab->IsExternal());
2821   CcTest::heap()->CollectAllGarbage();
2822
2823   ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
2824   CHECK(ab->IsExternal());
2825
2826   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2827   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2828   DCHECK(data != NULL);
2829   env->Global()->Set(v8_str("ab"), ab);
2830
2831   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2832   CHECK_EQ(1024, result->Int32Value());
2833
2834   result = CompileRun(
2835       "var u8 = new Uint8Array(ab);"
2836       "u8[0] = 0xFF;"
2837       "u8[1] = 0xAA;"
2838       "u8.length");
2839   CHECK_EQ(1024, result->Int32Value());
2840   CHECK_EQ(0xFF, data[0]);
2841   CHECK_EQ(0xAA, data[1]);
2842   data[0] = 0xCC;
2843   data[1] = 0x11;
2844   result = CompileRun("u8[0] + u8[1]");
2845   CHECK_EQ(0xDD, result->Int32Value());
2846 }
2847
2848
2849 THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
2850   i::FLAG_harmony_sharedarraybuffer = true;
2851   LocalContext env;
2852   v8::Isolate* isolate = env->GetIsolate();
2853   v8::HandleScope handle_scope(isolate);
2854
2855
2856   v8::Local<v8::Value> result = CompileRun(
2857       "var ab1 = new SharedArrayBuffer(2);"
2858       "var u8_a = new Uint8Array(ab1);"
2859       "u8_a[0] = 0xAA;"
2860       "u8_a[1] = 0xFF; u8_a.buffer");
2861   Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
2862   CheckInternalFieldsAreZero(ab1);
2863   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2864   CHECK(!ab1->IsExternal());
2865   ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
2866   CHECK(ab1->IsExternal());
2867
2868   result = CompileRun("ab1.byteLength");
2869   CHECK_EQ(2, result->Int32Value());
2870   result = CompileRun("u8_a[0]");
2871   CHECK_EQ(0xAA, result->Int32Value());
2872   result = CompileRun("u8_a[1]");
2873   CHECK_EQ(0xFF, result->Int32Value());
2874   result = CompileRun(
2875       "var u8_b = new Uint8Array(ab1);"
2876       "u8_b[0] = 0xBB;"
2877       "u8_a[0]");
2878   CHECK_EQ(0xBB, result->Int32Value());
2879   result = CompileRun("u8_b[1]");
2880   CHECK_EQ(0xFF, result->Int32Value());
2881
2882   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2883   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2884   CHECK_EQ(0xBB, ab1_data[0]);
2885   CHECK_EQ(0xFF, ab1_data[1]);
2886   ab1_data[0] = 0xCC;
2887   ab1_data[1] = 0x11;
2888   result = CompileRun("u8_a[0] + u8_a[1]");
2889   CHECK_EQ(0xDD, result->Int32Value());
2890 }
2891
2892
2893 THREADED_TEST(SharedArrayBuffer_External) {
2894   i::FLAG_harmony_sharedarraybuffer = true;
2895   LocalContext env;
2896   v8::Isolate* isolate = env->GetIsolate();
2897   v8::HandleScope handle_scope(isolate);
2898
2899   i::ScopedVector<uint8_t> my_data(100);
2900   memset(my_data.start(), 0, 100);
2901   Local<v8::SharedArrayBuffer> ab3 =
2902       v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
2903   CheckInternalFieldsAreZero(ab3);
2904   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2905   CHECK(ab3->IsExternal());
2906
2907   env->Global()->Set(v8_str("ab3"), ab3);
2908
2909   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2910   CHECK_EQ(100, result->Int32Value());
2911
2912   result = CompileRun(
2913       "var u8_b = new Uint8Array(ab3);"
2914       "u8_b[0] = 0xBB;"
2915       "u8_b[1] = 0xCC;"
2916       "u8_b.length");
2917   CHECK_EQ(100, result->Int32Value());
2918   CHECK_EQ(0xBB, my_data[0]);
2919   CHECK_EQ(0xCC, my_data[1]);
2920   my_data[0] = 0xCC;
2921   my_data[1] = 0x11;
2922   result = CompileRun("u8_b[0] + u8_b[1]");
2923   CHECK_EQ(0xDD, result->Int32Value());
2924 }
2925
2926
2927 THREADED_TEST(HiddenProperties) {
2928   LocalContext env;
2929   v8::Isolate* isolate = env->GetIsolate();
2930   v8::HandleScope scope(isolate);
2931
2932   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2933   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2934   v8::Local<v8::String> empty = v8_str("");
2935   v8::Local<v8::String> prop_name = v8_str("prop_name");
2936
2937   CcTest::heap()->CollectAllGarbage();
2938
2939   // Make sure delete of a non-existent hidden value works
2940   CHECK(obj->DeleteHiddenValue(key));
2941
2942   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
2943   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2944   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2945   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2946
2947   CcTest::heap()->CollectAllGarbage();
2948
2949   // Make sure we do not find the hidden property.
2950   CHECK(!obj->Has(empty));
2951   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2952   CHECK(obj->Get(empty)->IsUndefined());
2953   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2954   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
2955   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2956   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2957
2958   CcTest::heap()->CollectAllGarbage();
2959
2960   // Add another property and delete it afterwards to force the object in
2961   // slow case.
2962   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
2963   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2964   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2965   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2966   CHECK(obj->Delete(prop_name));
2967   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2968
2969   CcTest::heap()->CollectAllGarbage();
2970
2971   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2972   CHECK(obj->GetHiddenValue(key).IsEmpty());
2973
2974   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2975   CHECK(obj->DeleteHiddenValue(key));
2976   CHECK(obj->GetHiddenValue(key).IsEmpty());
2977 }
2978
2979
2980 THREADED_TEST(Regress97784) {
2981   // Regression test for crbug.com/97784
2982   // Messing with the Object.prototype should not have effect on
2983   // hidden properties.
2984   LocalContext env;
2985   v8::HandleScope scope(env->GetIsolate());
2986
2987   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2988   v8::Local<v8::String> key = v8_str("hidden");
2989
2990   CompileRun(
2991       "set_called = false;"
2992       "Object.defineProperty("
2993       "    Object.prototype,"
2994       "    'hidden',"
2995       "    {get: function() { return 45; },"
2996       "     set: function() { set_called = true; }})");
2997
2998   CHECK(obj->GetHiddenValue(key).IsEmpty());
2999   // Make sure that the getter and setter from Object.prototype is not invoked.
3000   // If it did we would have full access to the hidden properties in
3001   // the accessor.
3002   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3003   ExpectFalse("set_called");
3004   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3005 }
3006
3007
3008 THREADED_TEST(External) {
3009   v8::HandleScope scope(CcTest::isolate());
3010   int x = 3;
3011   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3012   LocalContext env;
3013   env->Global()->Set(v8_str("ext"), ext);
3014   Local<Value> reext_obj = CompileRun("this.ext");
3015   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3016   int* ptr = static_cast<int*>(reext->Value());
3017   CHECK_EQ(x, 3);
3018   *ptr = 10;
3019   CHECK_EQ(x, 10);
3020
3021   // Make sure unaligned pointers are wrapped properly.
3022   char* data = i::StrDup("0123456789");
3023   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3024   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3025   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3026   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3027
3028   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3029   CHECK_EQ('0', *char_ptr);
3030   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3031   CHECK_EQ('1', *char_ptr);
3032   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3033   CHECK_EQ('2', *char_ptr);
3034   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3035   CHECK_EQ('3', *char_ptr);
3036   i::DeleteArray(data);
3037 }
3038
3039
3040 THREADED_TEST(GlobalHandle) {
3041   v8::Isolate* isolate = CcTest::isolate();
3042   v8::Persistent<String> global;
3043   {
3044     v8::HandleScope scope(isolate);
3045     global.Reset(isolate, v8_str("str"));
3046   }
3047   {
3048     v8::HandleScope scope(isolate);
3049     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3050   }
3051   global.Reset();
3052   {
3053     v8::HandleScope scope(isolate);
3054     global.Reset(isolate, v8_str("str"));
3055   }
3056   {
3057     v8::HandleScope scope(isolate);
3058     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3059   }
3060   global.Reset();
3061 }
3062
3063
3064 THREADED_TEST(ResettingGlobalHandle) {
3065   v8::Isolate* isolate = CcTest::isolate();
3066   v8::Persistent<String> global;
3067   {
3068     v8::HandleScope scope(isolate);
3069     global.Reset(isolate, v8_str("str"));
3070   }
3071   v8::internal::GlobalHandles* global_handles =
3072       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3073   int initial_handle_count = global_handles->global_handles_count();
3074   {
3075     v8::HandleScope scope(isolate);
3076     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3077   }
3078   {
3079     v8::HandleScope scope(isolate);
3080     global.Reset(isolate, v8_str("longer"));
3081   }
3082   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3083   {
3084     v8::HandleScope scope(isolate);
3085     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3086   }
3087   global.Reset();
3088   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3089 }
3090
3091
3092 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3093   v8::Isolate* isolate = CcTest::isolate();
3094   v8::Persistent<String> global;
3095   {
3096     v8::HandleScope scope(isolate);
3097     global.Reset(isolate, v8_str("str"));
3098   }
3099   v8::internal::GlobalHandles* global_handles =
3100       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3101   int initial_handle_count = global_handles->global_handles_count();
3102   {
3103     v8::HandleScope scope(isolate);
3104     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3105   }
3106   {
3107     v8::HandleScope scope(isolate);
3108     Local<String> empty;
3109     global.Reset(isolate, empty);
3110   }
3111   CHECK(global.IsEmpty());
3112   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3113 }
3114
3115
3116 template <class T>
3117 static v8::Global<T> PassUnique(v8::Global<T> unique) {
3118   return unique.Pass();
3119 }
3120
3121
3122 template <class T>
3123 static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
3124                                   const v8::Persistent<T>& global) {
3125   v8::Global<String> unique(isolate, global);
3126   return unique.Pass();
3127 }
3128
3129
3130 THREADED_TEST(Global) {
3131   v8::Isolate* isolate = CcTest::isolate();
3132   v8::Persistent<String> global;
3133   {
3134     v8::HandleScope scope(isolate);
3135     global.Reset(isolate, v8_str("str"));
3136   }
3137   v8::internal::GlobalHandles* global_handles =
3138       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3139   int initial_handle_count = global_handles->global_handles_count();
3140   {
3141     v8::Global<String> unique(isolate, global);
3142     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3143     // Test assignment via Pass
3144     {
3145       v8::Global<String> copy = unique.Pass();
3146       CHECK(unique.IsEmpty());
3147       CHECK(copy == global);
3148       CHECK_EQ(initial_handle_count + 1,
3149                global_handles->global_handles_count());
3150       unique = copy.Pass();
3151     }
3152     // Test ctor via Pass
3153     {
3154       v8::Global<String> copy(unique.Pass());
3155       CHECK(unique.IsEmpty());
3156       CHECK(copy == global);
3157       CHECK_EQ(initial_handle_count + 1,
3158                global_handles->global_handles_count());
3159       unique = copy.Pass();
3160     }
3161     // Test pass through function call
3162     {
3163       v8::Global<String> copy = PassUnique(unique.Pass());
3164       CHECK(unique.IsEmpty());
3165       CHECK(copy == global);
3166       CHECK_EQ(initial_handle_count + 1,
3167                global_handles->global_handles_count());
3168       unique = copy.Pass();
3169     }
3170     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3171   }
3172   // Test pass from function call
3173   {
3174     v8::Global<String> unique = ReturnUnique(isolate, global);
3175     CHECK(unique == global);
3176     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3177   }
3178   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3179   global.Reset();
3180 }
3181
3182
3183 namespace {
3184
3185 class TwoPassCallbackData;
3186 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3187 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3188
3189
3190 class TwoPassCallbackData {
3191  public:
3192   TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
3193       : first_pass_called_(false),
3194         second_pass_called_(false),
3195         trigger_gc_(false),
3196         instance_counter_(instance_counter) {
3197     HandleScope scope(isolate);
3198     i::ScopedVector<char> buffer(40);
3199     i::SNPrintF(buffer, "%p", static_cast<void*>(this));
3200     auto string =
3201         v8::String::NewFromUtf8(isolate, buffer.start(),
3202                                 v8::NewStringType::kNormal).ToLocalChecked();
3203     cell_.Reset(isolate, string);
3204     (*instance_counter_)++;
3205   }
3206
3207   ~TwoPassCallbackData() {
3208     CHECK(first_pass_called_);
3209     CHECK(second_pass_called_);
3210     CHECK(cell_.IsEmpty());
3211     (*instance_counter_)--;
3212   }
3213
3214   void FirstPass() {
3215     CHECK(!first_pass_called_);
3216     CHECK(!second_pass_called_);
3217     CHECK(!cell_.IsEmpty());
3218     cell_.Reset();
3219     first_pass_called_ = true;
3220   }
3221
3222   void SecondPass() {
3223     CHECK(first_pass_called_);
3224     CHECK(!second_pass_called_);
3225     CHECK(cell_.IsEmpty());
3226     second_pass_called_ = true;
3227     delete this;
3228   }
3229
3230   void SetWeak() {
3231     cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
3232   }
3233
3234   void MarkTriggerGc() { trigger_gc_ = true; }
3235   bool trigger_gc() { return trigger_gc_; }
3236
3237   int* instance_counter() { return instance_counter_; }
3238
3239  private:
3240   bool first_pass_called_;
3241   bool second_pass_called_;
3242   bool trigger_gc_;
3243   v8::Global<v8::String> cell_;
3244   int* instance_counter_;
3245 };
3246
3247
3248 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3249   ApiTestFuzzer::Fuzz();
3250   bool trigger_gc = data.GetParameter()->trigger_gc();
3251   int* instance_counter = data.GetParameter()->instance_counter();
3252   data.GetParameter()->SecondPass();
3253   if (!trigger_gc) return;
3254   auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
3255   data_2->SetWeak();
3256   CcTest::heap()->CollectAllGarbage();
3257 }
3258
3259
3260 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3261   data.GetParameter()->FirstPass();
3262   data.SetSecondPassCallback(SecondPassCallback);
3263 }
3264
3265 }  // namespace
3266
3267
3268 TEST(TwoPassPhantomCallbacks) {
3269   auto isolate = CcTest::isolate();
3270   const size_t kLength = 20;
3271   int instance_counter = 0;
3272   for (size_t i = 0; i < kLength; ++i) {
3273     auto data = new TwoPassCallbackData(isolate, &instance_counter);
3274     data->SetWeak();
3275   }
3276   CHECK_EQ(static_cast<int>(kLength), instance_counter);
3277   CcTest::heap()->CollectAllGarbage();
3278   CHECK_EQ(0, instance_counter);
3279 }
3280
3281
3282 TEST(TwoPassPhantomCallbacksNestedGc) {
3283   auto isolate = CcTest::isolate();
3284   const size_t kLength = 20;
3285   TwoPassCallbackData* array[kLength];
3286   int instance_counter = 0;
3287   for (size_t i = 0; i < kLength; ++i) {
3288     array[i] = new TwoPassCallbackData(isolate, &instance_counter);
3289     array[i]->SetWeak();
3290   }
3291   array[5]->MarkTriggerGc();
3292   array[10]->MarkTriggerGc();
3293   array[15]->MarkTriggerGc();
3294   CHECK_EQ(static_cast<int>(kLength), instance_counter);
3295   CcTest::heap()->CollectAllGarbage();
3296   CHECK_EQ(0, instance_counter);
3297 }
3298
3299
3300 namespace {
3301
3302 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
3303
3304
3305 Local<v8::Object> NewObjectForIntKey(
3306     v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
3307     int key) {
3308   auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
3309   auto obj = local->NewInstance();
3310   obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
3311   return obj;
3312 }
3313
3314
3315 template <typename K, typename V>
3316 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
3317  public:
3318   typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
3319   static const v8::PersistentContainerCallbackType kCallbackType =
3320       v8::kWeakWithInternalFields;
3321   struct WeakCallbackDataType {
3322     MapType* map;
3323     K key;
3324   };
3325   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3326                                                      Local<V> value) {
3327     WeakCallbackDataType* data = new WeakCallbackDataType;
3328     data->map = map;
3329     data->key = key;
3330     return data;
3331   }
3332   static MapType* MapFromWeakCallbackInfo(
3333       const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3334     return data.GetParameter()->map;
3335   }
3336   static K KeyFromWeakCallbackInfo(
3337       const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3338     return data.GetParameter()->key;
3339   }
3340   static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3341   static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
3342     CHECK_EQ(IntKeyToVoidPointer(key),
3343              v8::Object::GetAlignedPointerFromInternalField(value, 0));
3344   }
3345   static void DisposeWeak(
3346       const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
3347     K key = KeyFromWeakCallbackInfo(info);
3348     CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
3349     DisposeCallbackData(info.GetParameter());
3350   }
3351 };
3352
3353
3354 template <typename Map>
3355 void TestGlobalValueMap() {
3356   LocalContext env;
3357   v8::Isolate* isolate = env->GetIsolate();
3358   v8::Global<ObjectTemplate> templ;
3359   {
3360     HandleScope scope(isolate);
3361     auto t = ObjectTemplate::New(isolate);
3362     t->SetInternalFieldCount(1);
3363     templ.Reset(isolate, t);
3364   }
3365   Map map(isolate);
3366   v8::internal::GlobalHandles* global_handles =
3367       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3368   int initial_handle_count = global_handles->global_handles_count();
3369   CHECK_EQ(0, static_cast<int>(map.Size()));
3370   {
3371     HandleScope scope(isolate);
3372     Local<v8::Object> obj = map.Get(7);
3373     CHECK(obj.IsEmpty());
3374     Local<v8::Object> expected = v8::Object::New(isolate);
3375     map.Set(7, expected);
3376     CHECK_EQ(1, static_cast<int>(map.Size()));
3377     obj = map.Get(7);
3378     CHECK(expected->Equals(obj));
3379     {
3380       typename Map::PersistentValueReference ref = map.GetReference(7);
3381       CHECK(expected->Equals(ref.NewLocal(isolate)));
3382     }
3383     v8::Global<v8::Object> removed = map.Remove(7);
3384     CHECK_EQ(0, static_cast<int>(map.Size()));
3385     CHECK(expected == removed);
3386     removed = map.Remove(7);
3387     CHECK(removed.IsEmpty());
3388     map.Set(8, expected);
3389     CHECK_EQ(1, static_cast<int>(map.Size()));
3390     map.Set(8, expected);
3391     CHECK_EQ(1, static_cast<int>(map.Size()));
3392     {
3393       typename Map::PersistentValueReference ref;
3394       Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
3395       removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
3396       CHECK_EQ(1, static_cast<int>(map.Size()));
3397       CHECK(expected == removed);
3398       CHECK(expected2->Equals(ref.NewLocal(isolate)));
3399     }
3400   }
3401   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3402   if (map.IsWeak()) {
3403     CcTest::i_isolate()->heap()->CollectAllGarbage(
3404         i::Heap::kAbortIncrementalMarkingMask);
3405   } else {
3406     map.Clear();
3407   }
3408   CHECK_EQ(0, static_cast<int>(map.Size()));
3409   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3410   {
3411     HandleScope scope(isolate);
3412     Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
3413     map.Set(9, value);
3414     map.Clear();
3415   }
3416   CHECK_EQ(0, static_cast<int>(map.Size()));
3417   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3418 }
3419
3420 }  // namespace
3421
3422
3423 TEST(GlobalValueMap) {
3424   // Default case, w/o weak callbacks:
3425   TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
3426
3427   // Custom traits with weak callbacks:
3428   typedef v8::GlobalValueMap<int, v8::Object,
3429                              PhantomStdMapTraits<int, v8::Object>> WeakMap;
3430   TestGlobalValueMap<WeakMap>();
3431 }
3432
3433
3434 TEST(PersistentValueVector) {
3435   LocalContext env;
3436   v8::Isolate* isolate = env->GetIsolate();
3437   v8::internal::GlobalHandles* global_handles =
3438       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3439   int handle_count = global_handles->global_handles_count();
3440   HandleScope scope(isolate);
3441
3442   v8::PersistentValueVector<v8::Object> vector(isolate);
3443
3444   Local<v8::Object> obj1 = v8::Object::New(isolate);
3445   Local<v8::Object> obj2 = v8::Object::New(isolate);
3446   v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
3447
3448   CHECK(vector.IsEmpty());
3449   CHECK_EQ(0, static_cast<int>(vector.Size()));
3450
3451   vector.ReserveCapacity(3);
3452   CHECK(vector.IsEmpty());
3453
3454   vector.Append(obj1);
3455   vector.Append(obj2);
3456   vector.Append(obj1);
3457   vector.Append(obj3.Pass());
3458   vector.Append(obj1);
3459
3460   CHECK(!vector.IsEmpty());
3461   CHECK_EQ(5, static_cast<int>(vector.Size()));
3462   CHECK(obj3.IsEmpty());
3463   CHECK(obj1->Equals(vector.Get(0)));
3464   CHECK(obj1->Equals(vector.Get(2)));
3465   CHECK(obj1->Equals(vector.Get(4)));
3466   CHECK(obj2->Equals(vector.Get(1)));
3467
3468   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3469
3470   vector.Clear();
3471   CHECK(vector.IsEmpty());
3472   CHECK_EQ(0, static_cast<int>(vector.Size()));
3473   CHECK_EQ(handle_count, global_handles->global_handles_count());
3474 }
3475
3476
3477 THREADED_TEST(GlobalHandleUpcast) {
3478   v8::Isolate* isolate = CcTest::isolate();
3479   v8::HandleScope scope(isolate);
3480   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3481   v8::Persistent<String> global_string(isolate, local);
3482   v8::Persistent<Value>& global_value =
3483       v8::Persistent<Value>::Cast(global_string);
3484   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3485   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3486   global_string.Reset();
3487 }
3488
3489
3490 THREADED_TEST(HandleEquality) {
3491   v8::Isolate* isolate = CcTest::isolate();
3492   v8::Persistent<String> global1;
3493   v8::Persistent<String> global2;
3494   {
3495     v8::HandleScope scope(isolate);
3496     global1.Reset(isolate, v8_str("str"));
3497     global2.Reset(isolate, v8_str("str2"));
3498   }
3499   CHECK_EQ(global1 == global1, true);
3500   CHECK_EQ(global1 != global1, false);
3501   {
3502     v8::HandleScope scope(isolate);
3503     Local<String> local1 = Local<String>::New(isolate, global1);
3504     Local<String> local2 = Local<String>::New(isolate, global2);
3505
3506     CHECK_EQ(global1 == local1, true);
3507     CHECK_EQ(global1 != local1, false);
3508     CHECK_EQ(local1 == global1, true);
3509     CHECK_EQ(local1 != global1, false);
3510
3511     CHECK_EQ(global1 == local2, false);
3512     CHECK_EQ(global1 != local2, true);
3513     CHECK_EQ(local2 == global1, false);
3514     CHECK_EQ(local2 != global1, true);
3515
3516     CHECK_EQ(local1 == local2, false);
3517     CHECK_EQ(local1 != local2, true);
3518
3519     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3520     CHECK_EQ(local1 == anotherLocal1, true);
3521     CHECK_EQ(local1 != anotherLocal1, false);
3522   }
3523   global1.Reset();
3524   global2.Reset();
3525 }
3526
3527
3528 THREADED_TEST(LocalHandle) {
3529   v8::HandleScope scope(CcTest::isolate());
3530   v8::Local<String> local =
3531       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3532   CHECK_EQ(local->Length(), 3);
3533 }
3534
3535
3536 class WeakCallCounter {
3537  public:
3538   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
3539   int id() { return id_; }
3540   void increment() { number_of_weak_calls_++; }
3541   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3542
3543  private:
3544   int id_;
3545   int number_of_weak_calls_;
3546 };
3547
3548
3549 template <typename T>
3550 struct WeakCallCounterAndPersistent {
3551   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3552       : counter(counter) {}
3553   WeakCallCounter* counter;
3554   v8::Persistent<T> handle;
3555 };
3556
3557
3558 template <typename T>
3559 static void WeakPointerCallback(
3560     const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
3561   CHECK_EQ(1234, data.GetParameter()->counter->id());
3562   data.GetParameter()->counter->increment();
3563   data.GetParameter()->handle.Reset();
3564 }
3565
3566
3567 template <typename T>
3568 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3569   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3570 }
3571
3572
3573 THREADED_TEST(ApiObjectGroups) {
3574   LocalContext env;
3575   v8::Isolate* iso = env->GetIsolate();
3576   HandleScope scope(iso);
3577
3578   WeakCallCounter counter(1234);
3579
3580   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3581   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3582   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3583   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3584   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3585   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3586
3587   {
3588     HandleScope scope(iso);
3589     g1s1.handle.Reset(iso, Object::New(iso));
3590     g1s2.handle.Reset(iso, Object::New(iso));
3591     g1c1.handle.Reset(iso, Object::New(iso));
3592     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3593                         v8::WeakCallbackType::kParameter);
3594     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3595                         v8::WeakCallbackType::kParameter);
3596     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3597                         v8::WeakCallbackType::kParameter);
3598
3599     g2s1.handle.Reset(iso, Object::New(iso));
3600     g2s2.handle.Reset(iso, Object::New(iso));
3601     g2c1.handle.Reset(iso, Object::New(iso));
3602     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3603                         v8::WeakCallbackType::kParameter);
3604     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3605                         v8::WeakCallbackType::kParameter);
3606     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3607                         v8::WeakCallbackType::kParameter);
3608   }
3609
3610   WeakCallCounterAndPersistent<Value> root(&counter);
3611   root.handle.Reset(iso, g1s1.handle);  // make a root.
3612
3613   // Connect group 1 and 2, make a cycle.
3614   {
3615     HandleScope scope(iso);
3616     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
3617               ->Set(0, Local<Value>::New(iso, g2s2.handle)));
3618     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
3619               ->Set(0, Local<Value>::New(iso, g1s1.handle)));
3620   }
3621
3622   {
3623     UniqueId id1 = MakeUniqueId(g1s1.handle);
3624     UniqueId id2 = MakeUniqueId(g2s2.handle);
3625     iso->SetObjectGroupId(g1s1.handle, id1);
3626     iso->SetObjectGroupId(g1s2.handle, id1);
3627     iso->SetReferenceFromGroup(id1, g1c1.handle);
3628     iso->SetObjectGroupId(g2s1.handle, id2);
3629     iso->SetObjectGroupId(g2s2.handle, id2);
3630     iso->SetReferenceFromGroup(id2, g2c1.handle);
3631   }
3632   // Do a single full GC, ensure incremental marking is stopped.
3633   v8::internal::Heap* heap =
3634       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3635   heap->CollectAllGarbage();
3636
3637   // All object should be alive.
3638   CHECK_EQ(0, counter.NumberOfWeakCalls());
3639
3640   // Weaken the root.
3641   root.handle.SetWeak(&root, &WeakPointerCallback,
3642                       v8::WeakCallbackType::kParameter);
3643   // But make children strong roots---all the objects (except for children)
3644   // should be collectable now.
3645   g1c1.handle.ClearWeak();
3646   g2c1.handle.ClearWeak();
3647
3648   // Groups are deleted, rebuild groups.
3649   {
3650     UniqueId id1 = MakeUniqueId(g1s1.handle);
3651     UniqueId id2 = MakeUniqueId(g2s2.handle);
3652     iso->SetObjectGroupId(g1s1.handle, id1);
3653     iso->SetObjectGroupId(g1s2.handle, id1);
3654     iso->SetReferenceFromGroup(id1, g1c1.handle);
3655     iso->SetObjectGroupId(g2s1.handle, id2);
3656     iso->SetObjectGroupId(g2s2.handle, id2);
3657     iso->SetReferenceFromGroup(id2, g2c1.handle);
3658   }
3659
3660   heap->CollectAllGarbage();
3661
3662   // All objects should be gone. 5 global handles in total.
3663   CHECK_EQ(5, counter.NumberOfWeakCalls());
3664
3665   // And now make children weak again and collect them.
3666   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3667                       v8::WeakCallbackType::kParameter);
3668   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3669                       v8::WeakCallbackType::kParameter);
3670
3671   heap->CollectAllGarbage();
3672   CHECK_EQ(7, counter.NumberOfWeakCalls());
3673 }
3674
3675
3676 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3677   LocalContext env;
3678   v8::Isolate* iso = env->GetIsolate();
3679   HandleScope scope(iso);
3680
3681   WeakCallCounter counter(1234);
3682
3683   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3684   WeakCallCounterAndPersistent<String> g1s2(&counter);
3685   WeakCallCounterAndPersistent<String> g1c1(&counter);
3686   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3687   WeakCallCounterAndPersistent<String> g2s2(&counter);
3688   WeakCallCounterAndPersistent<String> g2c1(&counter);
3689
3690   {
3691     HandleScope scope(iso);
3692     g1s1.handle.Reset(iso, Object::New(iso));
3693     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3694     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3695     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3696                         v8::WeakCallbackType::kParameter);
3697     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3698                         v8::WeakCallbackType::kParameter);
3699     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3700                         v8::WeakCallbackType::kParameter);
3701
3702     g2s1.handle.Reset(iso, Object::New(iso));
3703     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3704     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3705     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3706                         v8::WeakCallbackType::kParameter);
3707     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3708                         v8::WeakCallbackType::kParameter);
3709     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3710                         v8::WeakCallbackType::kParameter);
3711   }
3712
3713   WeakCallCounterAndPersistent<Value> root(&counter);
3714   root.handle.Reset(iso, g1s1.handle);  // make a root.
3715
3716   // Connect group 1 and 2, make a cycle.
3717   {
3718     HandleScope scope(iso);
3719     CHECK(Local<Object>::New(iso, g1s1.handle)
3720               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3721     CHECK(Local<Object>::New(iso, g2s1.handle)
3722               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3723   }
3724
3725   {
3726     UniqueId id1 = MakeUniqueId(g1s1.handle);
3727     UniqueId id2 = MakeUniqueId(g2s2.handle);
3728     iso->SetObjectGroupId(g1s1.handle, id1);
3729     iso->SetObjectGroupId(g1s2.handle, id1);
3730     iso->SetReference(g1s1.handle, g1c1.handle);
3731     iso->SetObjectGroupId(g2s1.handle, id2);
3732     iso->SetObjectGroupId(g2s2.handle, id2);
3733     iso->SetReferenceFromGroup(id2, g2c1.handle);
3734   }
3735   // Do a single full GC, ensure incremental marking is stopped.
3736   v8::internal::Heap* heap =
3737       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3738   heap->CollectAllGarbage();
3739
3740   // All object should be alive.
3741   CHECK_EQ(0, counter.NumberOfWeakCalls());
3742
3743   // Weaken the root.
3744   root.handle.SetWeak(&root, &WeakPointerCallback,
3745                       v8::WeakCallbackType::kParameter);
3746   // But make children strong roots---all the objects (except for children)
3747   // should be collectable now.
3748   g1c1.handle.ClearWeak();
3749   g2c1.handle.ClearWeak();
3750
3751   // Groups are deleted, rebuild groups.
3752   {
3753     UniqueId id1 = MakeUniqueId(g1s1.handle);
3754     UniqueId id2 = MakeUniqueId(g2s2.handle);
3755     iso->SetObjectGroupId(g1s1.handle, id1);
3756     iso->SetObjectGroupId(g1s2.handle, id1);
3757     iso->SetReference(g1s1.handle, g1c1.handle);
3758     iso->SetObjectGroupId(g2s1.handle, id2);
3759     iso->SetObjectGroupId(g2s2.handle, id2);
3760     iso->SetReferenceFromGroup(id2, g2c1.handle);
3761   }
3762
3763   heap->CollectAllGarbage();
3764
3765   // All objects should be gone. 5 global handles in total.
3766   CHECK_EQ(5, counter.NumberOfWeakCalls());
3767
3768   // And now make children weak again and collect them.
3769   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3770                       v8::WeakCallbackType::kParameter);
3771   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3772                       v8::WeakCallbackType::kParameter);
3773
3774   heap->CollectAllGarbage();
3775   CHECK_EQ(7, counter.NumberOfWeakCalls());
3776 }
3777
3778
3779 THREADED_TEST(ApiObjectGroupsCycle) {
3780   LocalContext env;
3781   v8::Isolate* iso = env->GetIsolate();
3782   HandleScope scope(iso);
3783
3784   WeakCallCounter counter(1234);
3785
3786   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3787   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3788   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3789   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3790   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3791   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3792   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3793   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3794
3795   {
3796     HandleScope scope(iso);
3797     g1s1.handle.Reset(iso, Object::New(iso));
3798     g1s2.handle.Reset(iso, Object::New(iso));
3799     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3800                         v8::WeakCallbackType::kParameter);
3801     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3802                         v8::WeakCallbackType::kParameter);
3803     CHECK(g1s1.handle.IsWeak());
3804     CHECK(g1s2.handle.IsWeak());
3805
3806     g2s1.handle.Reset(iso, Object::New(iso));
3807     g2s2.handle.Reset(iso, Object::New(iso));
3808     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3809                         v8::WeakCallbackType::kParameter);
3810     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3811                         v8::WeakCallbackType::kParameter);
3812     CHECK(g2s1.handle.IsWeak());
3813     CHECK(g2s2.handle.IsWeak());
3814
3815     g3s1.handle.Reset(iso, Object::New(iso));
3816     g3s2.handle.Reset(iso, Object::New(iso));
3817     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
3818                         v8::WeakCallbackType::kParameter);
3819     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
3820                         v8::WeakCallbackType::kParameter);
3821     CHECK(g3s1.handle.IsWeak());
3822     CHECK(g3s2.handle.IsWeak());
3823
3824     g4s1.handle.Reset(iso, Object::New(iso));
3825     g4s2.handle.Reset(iso, Object::New(iso));
3826     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback,
3827                         v8::WeakCallbackType::kParameter);
3828     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback,
3829                         v8::WeakCallbackType::kParameter);
3830     CHECK(g4s1.handle.IsWeak());
3831     CHECK(g4s2.handle.IsWeak());
3832   }
3833
3834   WeakCallCounterAndPersistent<Value> root(&counter);
3835   root.handle.Reset(iso, g1s1.handle);  // make a root.
3836
3837   // Connect groups.  We're building the following cycle:
3838   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3839   // groups.
3840   {
3841     UniqueId id1 = MakeUniqueId(g1s1.handle);
3842     UniqueId id2 = MakeUniqueId(g2s1.handle);
3843     UniqueId id3 = MakeUniqueId(g3s1.handle);
3844     UniqueId id4 = MakeUniqueId(g4s1.handle);
3845     iso->SetObjectGroupId(g1s1.handle, id1);
3846     iso->SetObjectGroupId(g1s2.handle, id1);
3847     iso->SetReferenceFromGroup(id1, g2s1.handle);
3848     iso->SetObjectGroupId(g2s1.handle, id2);
3849     iso->SetObjectGroupId(g2s2.handle, id2);
3850     iso->SetReferenceFromGroup(id2, g3s1.handle);
3851     iso->SetObjectGroupId(g3s1.handle, id3);
3852     iso->SetObjectGroupId(g3s2.handle, id3);
3853     iso->SetReferenceFromGroup(id3, g4s1.handle);
3854     iso->SetObjectGroupId(g4s1.handle, id4);
3855     iso->SetObjectGroupId(g4s2.handle, id4);
3856     iso->SetReferenceFromGroup(id4, g1s1.handle);
3857   }
3858   // Do a single full GC
3859   v8::internal::Heap* heap =
3860       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3861   heap->CollectAllGarbage();
3862
3863   // All object should be alive.
3864   CHECK_EQ(0, counter.NumberOfWeakCalls());
3865
3866   // Weaken the root.
3867   root.handle.SetWeak(&root, &WeakPointerCallback,
3868                       v8::WeakCallbackType::kParameter);
3869
3870   // Groups are deleted, rebuild groups.
3871   {
3872     UniqueId id1 = MakeUniqueId(g1s1.handle);
3873     UniqueId id2 = MakeUniqueId(g2s1.handle);
3874     UniqueId id3 = MakeUniqueId(g3s1.handle);
3875     UniqueId id4 = MakeUniqueId(g4s1.handle);
3876     iso->SetObjectGroupId(g1s1.handle, id1);
3877     iso->SetObjectGroupId(g1s2.handle, id1);
3878     iso->SetReferenceFromGroup(id1, g2s1.handle);
3879     iso->SetObjectGroupId(g2s1.handle, id2);
3880     iso->SetObjectGroupId(g2s2.handle, id2);
3881     iso->SetReferenceFromGroup(id2, g3s1.handle);
3882     iso->SetObjectGroupId(g3s1.handle, id3);
3883     iso->SetObjectGroupId(g3s2.handle, id3);
3884     iso->SetReferenceFromGroup(id3, g4s1.handle);
3885     iso->SetObjectGroupId(g4s1.handle, id4);
3886     iso->SetObjectGroupId(g4s2.handle, id4);
3887     iso->SetReferenceFromGroup(id4, g1s1.handle);
3888   }
3889
3890   heap->CollectAllGarbage();
3891
3892   // All objects should be gone. 9 global handles in total.
3893   CHECK_EQ(9, counter.NumberOfWeakCalls());
3894 }
3895
3896
3897 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3898 // on the buildbots, so was made non-threaded for the time being.
3899 TEST(ApiObjectGroupsCycleForScavenger) {
3900   i::FLAG_stress_compaction = false;
3901   i::FLAG_gc_global = false;
3902   LocalContext env;
3903   v8::Isolate* iso = env->GetIsolate();
3904   HandleScope scope(iso);
3905
3906   WeakCallCounter counter(1234);
3907
3908   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3909   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3910   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3911   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3912   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3913   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3914
3915   {
3916     HandleScope scope(iso);
3917     g1s1.handle.Reset(iso, Object::New(iso));
3918     g1s2.handle.Reset(iso, Object::New(iso));
3919     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3920                         v8::WeakCallbackType::kParameter);
3921     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3922                         v8::WeakCallbackType::kParameter);
3923
3924     g2s1.handle.Reset(iso, Object::New(iso));
3925     g2s2.handle.Reset(iso, Object::New(iso));
3926     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3927                         v8::WeakCallbackType::kParameter);
3928     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3929                         v8::WeakCallbackType::kParameter);
3930
3931     g3s1.handle.Reset(iso, Object::New(iso));
3932     g3s2.handle.Reset(iso, Object::New(iso));
3933     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
3934                         v8::WeakCallbackType::kParameter);
3935     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
3936                         v8::WeakCallbackType::kParameter);
3937   }
3938
3939   // Make a root.
3940   WeakCallCounterAndPersistent<Value> root(&counter);
3941   root.handle.Reset(iso, g1s1.handle);
3942   root.handle.MarkPartiallyDependent();
3943
3944   // Connect groups.  We're building the following cycle:
3945   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3946   // groups.
3947   {
3948     HandleScope handle_scope(iso);
3949     g1s1.handle.MarkPartiallyDependent();
3950     g1s2.handle.MarkPartiallyDependent();
3951     g2s1.handle.MarkPartiallyDependent();
3952     g2s2.handle.MarkPartiallyDependent();
3953     g3s1.handle.MarkPartiallyDependent();
3954     g3s2.handle.MarkPartiallyDependent();
3955     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3956     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3957     Local<Object>::New(iso, g1s1.handle.As<Object>())
3958         ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3959     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3960     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3961     Local<Object>::New(iso, g2s1.handle.As<Object>())
3962         ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3963     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3964     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3965     Local<Object>::New(iso, g3s1.handle.As<Object>())
3966         ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3967   }
3968
3969   v8::internal::Heap* heap =
3970       reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3971   heap->CollectAllGarbage();
3972
3973   // All objects should be alive.
3974   CHECK_EQ(0, counter.NumberOfWeakCalls());
3975
3976   // Weaken the root.
3977   root.handle.SetWeak(&root, &WeakPointerCallback,
3978                       v8::WeakCallbackType::kParameter);
3979   root.handle.MarkPartiallyDependent();
3980
3981   // Groups are deleted, rebuild groups.
3982   {
3983     HandleScope handle_scope(iso);
3984     g1s1.handle.MarkPartiallyDependent();
3985     g1s2.handle.MarkPartiallyDependent();
3986     g2s1.handle.MarkPartiallyDependent();
3987     g2s2.handle.MarkPartiallyDependent();
3988     g3s1.handle.MarkPartiallyDependent();
3989     g3s2.handle.MarkPartiallyDependent();
3990     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3991     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3992     Local<Object>::New(iso, g1s1.handle.As<Object>())
3993         ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3994     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3995     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3996     Local<Object>::New(iso, g2s1.handle.As<Object>())
3997         ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3998     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3999     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4000     Local<Object>::New(iso, g3s1.handle.As<Object>())
4001         ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4002   }
4003
4004   heap->CollectAllGarbage();
4005
4006   // All objects should be gone. 7 global handles in total.
4007   CHECK_EQ(7, counter.NumberOfWeakCalls());
4008 }
4009
4010
4011 THREADED_TEST(ScriptException) {
4012   LocalContext env;
4013   v8::HandleScope scope(env->GetIsolate());
4014   Local<Script> script = v8_compile("throw 'panama!';");
4015   v8::TryCatch try_catch(env->GetIsolate());
4016   Local<Value> result = script->Run();
4017   CHECK(result.IsEmpty());
4018   CHECK(try_catch.HasCaught());
4019   String::Utf8Value exception_value(try_catch.Exception());
4020   CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4021 }
4022
4023
4024 TEST(TryCatchCustomException) {
4025   LocalContext env;
4026   v8::Isolate* isolate = env->GetIsolate();
4027   v8::HandleScope scope(isolate);
4028   v8::TryCatch try_catch(isolate);
4029   CompileRun(
4030       "function CustomError() { this.a = 'b'; }"
4031       "(function f() { throw new CustomError(); })();");
4032   CHECK(try_catch.HasCaught());
4033   CHECK(try_catch.Exception()
4034             ->ToObject(isolate)
4035             ->Get(v8_str("a"))
4036             ->Equals(v8_str("b")));
4037 }
4038
4039
4040 bool message_received;
4041
4042
4043 static void check_message_0(v8::Handle<v8::Message> message,
4044                             v8::Handle<Value> data) {
4045   CHECK_EQ(5.76, data->NumberValue());
4046   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4047   CHECK(!message->IsSharedCrossOrigin());
4048   message_received = true;
4049 }
4050
4051
4052 THREADED_TEST(MessageHandler0) {
4053   message_received = false;
4054   v8::HandleScope scope(CcTest::isolate());
4055   CHECK(!message_received);
4056   LocalContext context;
4057   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4058   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4059   script->Run();
4060   CHECK(message_received);
4061   // clear out the message listener
4062   v8::V8::RemoveMessageListeners(check_message_0);
4063 }
4064
4065
4066 static void check_message_1(v8::Handle<v8::Message> message,
4067                             v8::Handle<Value> data) {
4068   CHECK(data->IsNumber());
4069   CHECK_EQ(1337, data->Int32Value());
4070   CHECK(!message->IsSharedCrossOrigin());
4071   message_received = true;
4072 }
4073
4074
4075 TEST(MessageHandler1) {
4076   message_received = false;
4077   v8::HandleScope scope(CcTest::isolate());
4078   CHECK(!message_received);
4079   v8::V8::AddMessageListener(check_message_1);
4080   LocalContext context;
4081   CompileRun("throw 1337;");
4082   CHECK(message_received);
4083   // clear out the message listener
4084   v8::V8::RemoveMessageListeners(check_message_1);
4085 }
4086
4087
4088 static void check_message_2(v8::Handle<v8::Message> message,
4089                             v8::Handle<Value> data) {
4090   LocalContext context;
4091   CHECK(data->IsObject());
4092   v8::Local<v8::Value> hidden_property =
4093       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4094   CHECK(v8_str("hidden value")->Equals(hidden_property));
4095   CHECK(!message->IsSharedCrossOrigin());
4096   message_received = true;
4097 }
4098
4099
4100 TEST(MessageHandler2) {
4101   message_received = false;
4102   v8::HandleScope scope(CcTest::isolate());
4103   CHECK(!message_received);
4104   v8::V8::AddMessageListener(check_message_2);
4105   LocalContext context;
4106   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4107   v8::Object::Cast(*error)
4108       ->SetHiddenValue(v8_str("hidden key"), v8_str("hidden value"));
4109   context->Global()->Set(v8_str("error"), error);
4110   CompileRun("throw error;");
4111   CHECK(message_received);
4112   // clear out the message listener
4113   v8::V8::RemoveMessageListeners(check_message_2);
4114 }
4115
4116
4117 static void check_message_3(v8::Handle<v8::Message> message,
4118                             v8::Handle<Value> data) {
4119   CHECK(message->IsSharedCrossOrigin());
4120   CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4121   CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript());
4122   CHECK(message->GetScriptOrigin().Options().IsOpaque());
4123   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4124   CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue());
4125   message_received = true;
4126 }
4127
4128
4129 TEST(MessageHandler3) {
4130   message_received = false;
4131   v8::Isolate* isolate = CcTest::isolate();
4132   v8::HandleScope scope(isolate);
4133   CHECK(!message_received);
4134   v8::V8::AddMessageListener(check_message_3);
4135   LocalContext context;
4136   v8::ScriptOrigin origin = v8::ScriptOrigin(
4137       v8_str("6.75"), v8::Integer::New(isolate, 1),
4138       v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(),
4139       v8::True(isolate), v8_str("7.40"), v8::True(isolate));
4140   v8::Handle<v8::Script> script =
4141       Script::Compile(v8_str("throw 'error'"), &origin);
4142   script->Run();
4143   CHECK(message_received);
4144   // clear out the message listener
4145   v8::V8::RemoveMessageListeners(check_message_3);
4146 }
4147
4148
4149 static void check_message_4(v8::Handle<v8::Message> message,
4150                             v8::Handle<Value> data) {
4151   CHECK(!message->IsSharedCrossOrigin());
4152   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4153   message_received = true;
4154 }
4155
4156
4157 TEST(MessageHandler4) {
4158   message_received = false;
4159   v8::Isolate* isolate = CcTest::isolate();
4160   v8::HandleScope scope(isolate);
4161   CHECK(!message_received);
4162   v8::V8::AddMessageListener(check_message_4);
4163   LocalContext context;
4164   v8::ScriptOrigin origin =
4165       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4166                        v8::Integer::New(isolate, 2), v8::False(isolate));
4167   v8::Handle<v8::Script> script =
4168       Script::Compile(v8_str("throw 'error'"), &origin);
4169   script->Run();
4170   CHECK(message_received);
4171   // clear out the message listener
4172   v8::V8::RemoveMessageListeners(check_message_4);
4173 }
4174
4175
4176 static void check_message_5a(v8::Handle<v8::Message> message,
4177                              v8::Handle<Value> data) {
4178   CHECK(message->IsSharedCrossOrigin());
4179   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4180   message_received = true;
4181 }
4182
4183
4184 static void check_message_5b(v8::Handle<v8::Message> message,
4185                              v8::Handle<Value> data) {
4186   CHECK(!message->IsSharedCrossOrigin());
4187   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4188   message_received = true;
4189 }
4190
4191
4192 TEST(MessageHandler5) {
4193   message_received = false;
4194   v8::Isolate* isolate = CcTest::isolate();
4195   v8::HandleScope scope(isolate);
4196   CHECK(!message_received);
4197   v8::V8::AddMessageListener(check_message_5a);
4198   LocalContext context;
4199   v8::ScriptOrigin origin1 =
4200       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4201                        v8::Integer::New(isolate, 2), v8::True(isolate));
4202   v8::Handle<v8::Script> script =
4203       Script::Compile(v8_str("throw 'error'"), &origin1);
4204   script->Run();
4205   CHECK(message_received);
4206   // clear out the message listener
4207   v8::V8::RemoveMessageListeners(check_message_5a);
4208
4209   message_received = false;
4210   v8::V8::AddMessageListener(check_message_5b);
4211   v8::ScriptOrigin origin2 =
4212       v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4213                        v8::Integer::New(isolate, 2), v8::False(isolate));
4214   script = Script::Compile(v8_str("throw 'error'"), &origin2);
4215   script->Run();
4216   CHECK(message_received);
4217   // clear out the message listener
4218   v8::V8::RemoveMessageListeners(check_message_5b);
4219 }
4220
4221
4222 TEST(NativeWeakMap) {
4223   v8::Isolate* isolate = CcTest::isolate();
4224   HandleScope scope(isolate);
4225   Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
4226   CHECK(!weak_map.IsEmpty());
4227
4228   LocalContext env;
4229   Local<Object> value = v8::Object::New(isolate);
4230
4231   Local<Object> local1 = v8::Object::New(isolate);
4232   CHECK(!weak_map->Has(local1));
4233   CHECK(weak_map->Get(local1)->IsUndefined());
4234   weak_map->Set(local1, value);
4235   CHECK(weak_map->Has(local1));
4236   CHECK(value->Equals(weak_map->Get(local1)));
4237
4238   WeakCallCounter counter(1234);
4239   WeakCallCounterAndPersistent<Value> o1(&counter);
4240   WeakCallCounterAndPersistent<Value> o2(&counter);
4241   WeakCallCounterAndPersistent<Value> s1(&counter);
4242   {
4243     HandleScope scope(isolate);
4244     Local<v8::Object> obj1 = v8::Object::New(isolate);
4245     Local<v8::Object> obj2 = v8::Object::New(isolate);
4246     Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
4247
4248     weak_map->Set(obj1, value);
4249     weak_map->Set(obj2, value);
4250     weak_map->Set(sym1, value);
4251
4252     o1.handle.Reset(isolate, obj1);
4253     o2.handle.Reset(isolate, obj2);
4254     s1.handle.Reset(isolate, sym1);
4255
4256     CHECK(weak_map->Has(local1));
4257     CHECK(weak_map->Has(obj1));
4258     CHECK(weak_map->Has(obj2));
4259     CHECK(weak_map->Has(sym1));
4260
4261     CHECK(value->Equals(weak_map->Get(local1)));
4262     CHECK(value->Equals(weak_map->Get(obj1)));
4263     CHECK(value->Equals(weak_map->Get(obj2)));
4264     CHECK(value->Equals(weak_map->Get(sym1)));
4265   }
4266   CcTest::heap()->CollectAllGarbage();
4267   {
4268     HandleScope scope(isolate);
4269     CHECK(value->Equals(weak_map->Get(local1)));
4270     CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o1.handle))));
4271     CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o2.handle))));
4272     CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, s1.handle))));
4273   }
4274
4275   o1.handle.SetWeak(&o1, &WeakPointerCallback,
4276                     v8::WeakCallbackType::kParameter);
4277   o2.handle.SetWeak(&o2, &WeakPointerCallback,
4278                     v8::WeakCallbackType::kParameter);
4279   s1.handle.SetWeak(&s1, &WeakPointerCallback,
4280                     v8::WeakCallbackType::kParameter);
4281
4282   CcTest::heap()->CollectAllGarbage();
4283   CHECK_EQ(3, counter.NumberOfWeakCalls());
4284
4285   CHECK(o1.handle.IsEmpty());
4286   CHECK(o2.handle.IsEmpty());
4287   CHECK(s1.handle.IsEmpty());
4288
4289   CHECK(value->Equals(weak_map->Get(local1)));
4290   CHECK(weak_map->Delete(local1));
4291   CHECK(!weak_map->Has(local1));
4292   CHECK(weak_map->Get(local1)->IsUndefined());
4293 }
4294
4295
4296 THREADED_TEST(GetSetProperty) {
4297   LocalContext context;
4298   v8::Isolate* isolate = context->GetIsolate();
4299   v8::HandleScope scope(isolate);
4300   context->Global()->Set(v8_str("foo"), v8_num(14));
4301   context->Global()->Set(v8_str("12"), v8_num(92));
4302   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4303   context->Global()->Set(v8_num(13), v8_num(56));
4304   Local<Value> foo = CompileRun("this.foo");
4305   CHECK_EQ(14, foo->Int32Value());
4306   Local<Value> twelve = CompileRun("this[12]");
4307   CHECK_EQ(92, twelve->Int32Value());
4308   Local<Value> sixteen = CompileRun("this[16]");
4309   CHECK_EQ(32, sixteen->Int32Value());
4310   Local<Value> thirteen = CompileRun("this[13]");
4311   CHECK_EQ(56, thirteen->Int32Value());
4312   CHECK_EQ(92,
4313            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4314   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4315   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4316   CHECK_EQ(32,
4317            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4318   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4319   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4320   CHECK_EQ(56,
4321            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4322   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4323   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4324 }
4325
4326
4327 THREADED_TEST(PropertyAttributes) {
4328   LocalContext context;
4329   v8::HandleScope scope(context->GetIsolate());
4330   // none
4331   Local<String> prop = v8_str("none");
4332   context->Global()->Set(prop, v8_num(7));
4333   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4334   // read-only
4335   prop = v8_str("read_only");
4336   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4337   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4338   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4339   CompileRun("read_only = 9");
4340   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4341   context->Global()->Set(prop, v8_num(10));
4342   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4343   // dont-delete
4344   prop = v8_str("dont_delete");
4345   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4346   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4347   CompileRun("delete dont_delete");
4348   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4349   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4350   // dont-enum
4351   prop = v8_str("dont_enum");
4352   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4353   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4354   // absent
4355   prop = v8_str("absent");
4356   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4357   Local<Value> fake_prop = v8_num(1);
4358   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4359   // exception
4360   TryCatch try_catch(context->GetIsolate());
4361   Local<Value> exception =
4362       CompileRun("({ toString: function() { throw 'exception';} })");
4363   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4364   CHECK(try_catch.HasCaught());
4365   String::Utf8Value exception_value(try_catch.Exception());
4366   CHECK_EQ(0, strcmp("exception", *exception_value));
4367   try_catch.Reset();
4368 }
4369
4370
4371 THREADED_TEST(Array) {
4372   LocalContext context;
4373   v8::HandleScope scope(context->GetIsolate());
4374   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4375   CHECK_EQ(0u, array->Length());
4376   CHECK(array->Get(0)->IsUndefined());
4377   CHECK(!array->Has(0));
4378   CHECK(array->Get(100)->IsUndefined());
4379   CHECK(!array->Has(100));
4380   array->Set(2, v8_num(7));
4381   CHECK_EQ(3u, array->Length());
4382   CHECK(!array->Has(0));
4383   CHECK(!array->Has(1));
4384   CHECK(array->Has(2));
4385   CHECK_EQ(7, array->Get(2)->Int32Value());
4386   Local<Value> obj = CompileRun("[1, 2, 3]");
4387   Local<v8::Array> arr = obj.As<v8::Array>();
4388   CHECK_EQ(3u, arr->Length());
4389   CHECK_EQ(1, arr->Get(0)->Int32Value());
4390   CHECK_EQ(2, arr->Get(1)->Int32Value());
4391   CHECK_EQ(3, arr->Get(2)->Int32Value());
4392   array = v8::Array::New(context->GetIsolate(), 27);
4393   CHECK_EQ(27u, array->Length());
4394   array = v8::Array::New(context->GetIsolate(), -27);
4395   CHECK_EQ(0u, array->Length());
4396 }
4397
4398
4399 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4400   v8::EscapableHandleScope scope(args.GetIsolate());
4401   ApiTestFuzzer::Fuzz();
4402   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4403   for (int i = 0; i < args.Length(); i++) result->Set(i, args[i]);
4404   args.GetReturnValue().Set(scope.Escape(result));
4405 }
4406
4407
4408 THREADED_TEST(Vector) {
4409   v8::Isolate* isolate = CcTest::isolate();
4410   v8::HandleScope scope(isolate);
4411   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4412   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4413   LocalContext context(0, global);
4414
4415   const char* fun = "f()";
4416   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4417   CHECK_EQ(0u, a0->Length());
4418
4419   const char* fun2 = "f(11)";
4420   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4421   CHECK_EQ(1u, a1->Length());
4422   CHECK_EQ(11, a1->Get(0)->Int32Value());
4423
4424   const char* fun3 = "f(12, 13)";
4425   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4426   CHECK_EQ(2u, a2->Length());
4427   CHECK_EQ(12, a2->Get(0)->Int32Value());
4428   CHECK_EQ(13, a2->Get(1)->Int32Value());
4429
4430   const char* fun4 = "f(14, 15, 16)";
4431   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4432   CHECK_EQ(3u, a3->Length());
4433   CHECK_EQ(14, a3->Get(0)->Int32Value());
4434   CHECK_EQ(15, a3->Get(1)->Int32Value());
4435   CHECK_EQ(16, a3->Get(2)->Int32Value());
4436
4437   const char* fun5 = "f(17, 18, 19, 20)";
4438   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4439   CHECK_EQ(4u, a4->Length());
4440   CHECK_EQ(17, a4->Get(0)->Int32Value());
4441   CHECK_EQ(18, a4->Get(1)->Int32Value());
4442   CHECK_EQ(19, a4->Get(2)->Int32Value());
4443   CHECK_EQ(20, a4->Get(3)->Int32Value());
4444 }
4445
4446
4447 THREADED_TEST(FunctionCall) {
4448   LocalContext context;
4449   v8::Isolate* isolate = context->GetIsolate();
4450   v8::HandleScope scope(isolate);
4451   CompileRun(
4452       "function Foo() {"
4453       "  var result = [];"
4454       "  for (var i = 0; i < arguments.length; i++) {"
4455       "    result.push(arguments[i]);"
4456       "  }"
4457       "  return result;"
4458       "}"
4459       "function ReturnThisSloppy() {"
4460       "  return this;"
4461       "}"
4462       "function ReturnThisStrict() {"
4463       "  'use strict';"
4464       "  return this;"
4465       "}");
4466   Local<Function> Foo =
4467       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4468   Local<Function> ReturnThisSloppy =
4469       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4470   Local<Function> ReturnThisStrict =
4471       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4472
4473   v8::Handle<Value>* args0 = NULL;
4474   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4475   CHECK_EQ(0u, a0->Length());
4476
4477   v8::Handle<Value> args1[] = {v8_num(1.1)};
4478   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4479   CHECK_EQ(1u, a1->Length());
4480   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4481
4482   v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4483   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4484   CHECK_EQ(2u, a2->Length());
4485   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4486   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4487
4488   v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4489   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4490   CHECK_EQ(3u, a3->Length());
4491   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4492   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4493   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4494
4495   v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4496                                v8_num(10.11)};
4497   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4498   CHECK_EQ(4u, a4->Length());
4499   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4500   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4501   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4502   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4503
4504   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4505   CHECK(r1->StrictEquals(context->Global()));
4506   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4507   CHECK(r2->StrictEquals(context->Global()));
4508   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4509   CHECK(r3->IsNumberObject());
4510   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4511   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4512   CHECK(r4->IsStringObject());
4513   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4514   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4515   CHECK(r5->IsBooleanObject());
4516   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4517
4518   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4519   CHECK(r6->IsUndefined());
4520   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4521   CHECK(r7->IsNull());
4522   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4523   CHECK(r8->StrictEquals(v8_num(42)));
4524   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4525   CHECK(r9->StrictEquals(v8_str("hello")));
4526   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4527   CHECK(r10->StrictEquals(v8::True(isolate)));
4528 }
4529
4530
4531 THREADED_TEST(ConstructCall) {
4532   LocalContext context;
4533   v8::Isolate* isolate = context->GetIsolate();
4534   v8::HandleScope scope(isolate);
4535   CompileRun(
4536       "function Foo() {"
4537       "  var result = [];"
4538       "  for (var i = 0; i < arguments.length; i++) {"
4539       "    result.push(arguments[i]);"
4540       "  }"
4541       "  return result;"
4542       "}");
4543   Local<Function> Foo =
4544       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4545
4546   v8::Handle<Value>* args0 = NULL;
4547   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4548   CHECK_EQ(0u, a0->Length());
4549
4550   v8::Handle<Value> args1[] = {v8_num(1.1)};
4551   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4552   CHECK_EQ(1u, a1->Length());
4553   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4554
4555   v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4556   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4557   CHECK_EQ(2u, a2->Length());
4558   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4559   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4560
4561   v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4562   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4563   CHECK_EQ(3u, a3->Length());
4564   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4565   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4566   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4567
4568   v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4569                                v8_num(10.11)};
4570   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4571   CHECK_EQ(4u, a4->Length());
4572   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4573   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4574   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4575   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4576 }
4577
4578
4579 static void CheckUncle(v8::TryCatch* try_catch) {
4580   CHECK(try_catch->HasCaught());
4581   String::Utf8Value str_value(try_catch->Exception());
4582   CHECK_EQ(0, strcmp(*str_value, "uncle?"));
4583   try_catch->Reset();
4584 }
4585
4586
4587 THREADED_TEST(ConversionNumber) {
4588   LocalContext env;
4589   v8::Isolate* isolate = env->GetIsolate();
4590   v8::HandleScope scope(isolate);
4591   // Very large number.
4592   CompileRun("var obj = Math.pow(2,32) * 1237;");
4593   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4594   CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
4595   CHECK_EQ(0, obj->ToInt32(isolate)->Value());
4596   CHECK(0u ==
4597         obj->ToUint32(isolate)->Value());  // NOLINT - no CHECK_EQ for unsigned.
4598   // Large number.
4599   CompileRun("var obj = -1234567890123;");
4600   obj = env->Global()->Get(v8_str("obj"));
4601   CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
4602   CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
4603   CHECK(2382691125u == obj->ToUint32(isolate)->Value());  // NOLINT
4604   // Small positive integer.
4605   CompileRun("var obj = 42;");
4606   obj = env->Global()->Get(v8_str("obj"));
4607   CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
4608   CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4609   CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
4610   // Negative integer.
4611   CompileRun("var obj = -37;");
4612   obj = env->Global()->Get(v8_str("obj"));
4613   CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
4614   CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
4615   CHECK(4294967259u == obj->ToUint32(isolate)->Value());  // NOLINT
4616   // Positive non-int32 integer.
4617   CompileRun("var obj = 0x81234567;");
4618   obj = env->Global()->Get(v8_str("obj"));
4619   CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
4620   CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
4621   CHECK(2166572391u == obj->ToUint32(isolate)->Value());  // NOLINT
4622   // Fraction.
4623   CompileRun("var obj = 42.3;");
4624   obj = env->Global()->Get(v8_str("obj"));
4625   CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
4626   CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4627   CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
4628   // Large negative fraction.
4629   CompileRun("var obj = -5726623061.75;");
4630   obj = env->Global()->Get(v8_str("obj"));
4631   CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
4632   CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
4633   CHECK(2863311531u == obj->ToUint32(isolate)->Value());  // NOLINT
4634 }
4635
4636
4637 THREADED_TEST(isNumberType) {
4638   LocalContext env;
4639   v8::HandleScope scope(env->GetIsolate());
4640   // Very large number.
4641   CompileRun("var obj = Math.pow(2,32) * 1237;");
4642   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4643   CHECK(!obj->IsInt32());
4644   CHECK(!obj->IsUint32());
4645   // Large negative number.
4646   CompileRun("var obj = -1234567890123;");
4647   obj = env->Global()->Get(v8_str("obj"));
4648   CHECK(!obj->IsInt32());
4649   CHECK(!obj->IsUint32());
4650   // Small positive integer.
4651   CompileRun("var obj = 42;");
4652   obj = env->Global()->Get(v8_str("obj"));
4653   CHECK(obj->IsInt32());
4654   CHECK(obj->IsUint32());
4655   // Negative integer.
4656   CompileRun("var obj = -37;");
4657   obj = env->Global()->Get(v8_str("obj"));
4658   CHECK(obj->IsInt32());
4659   CHECK(!obj->IsUint32());
4660   // Positive non-int32 integer.
4661   CompileRun("var obj = 0x81234567;");
4662   obj = env->Global()->Get(v8_str("obj"));
4663   CHECK(!obj->IsInt32());
4664   CHECK(obj->IsUint32());
4665   // Fraction.
4666   CompileRun("var obj = 42.3;");
4667   obj = env->Global()->Get(v8_str("obj"));
4668   CHECK(!obj->IsInt32());
4669   CHECK(!obj->IsUint32());
4670   // Large negative fraction.
4671   CompileRun("var obj = -5726623061.75;");
4672   obj = env->Global()->Get(v8_str("obj"));
4673   CHECK(!obj->IsInt32());
4674   CHECK(!obj->IsUint32());
4675   // Positive zero
4676   CompileRun("var obj = 0.0;");
4677   obj = env->Global()->Get(v8_str("obj"));
4678   CHECK(obj->IsInt32());
4679   CHECK(obj->IsUint32());
4680   // Positive zero
4681   CompileRun("var obj = -0.0;");
4682   obj = env->Global()->Get(v8_str("obj"));
4683   CHECK(!obj->IsInt32());
4684   CHECK(!obj->IsUint32());
4685 }
4686
4687
4688 THREADED_TEST(ConversionException) {
4689   LocalContext env;
4690   v8::Isolate* isolate = env->GetIsolate();
4691   v8::HandleScope scope(isolate);
4692   CompileRun(
4693       "function TestClass() { };"
4694       "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4695       "var obj = new TestClass();");
4696   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4697
4698   v8::TryCatch try_catch(isolate);
4699
4700   Local<Value> to_string_result = obj->ToString(isolate);
4701   CHECK(to_string_result.IsEmpty());
4702   CheckUncle(&try_catch);
4703
4704   Local<Value> to_number_result = obj->ToNumber(isolate);
4705   CHECK(to_number_result.IsEmpty());
4706   CheckUncle(&try_catch);
4707
4708   Local<Value> to_integer_result = obj->ToInteger(isolate);
4709   CHECK(to_integer_result.IsEmpty());
4710   CheckUncle(&try_catch);
4711
4712   Local<Value> to_uint32_result = obj->ToUint32(isolate);
4713   CHECK(to_uint32_result.IsEmpty());
4714   CheckUncle(&try_catch);
4715
4716   Local<Value> to_int32_result = obj->ToInt32(isolate);
4717   CHECK(to_int32_result.IsEmpty());
4718   CheckUncle(&try_catch);
4719
4720   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
4721   CHECK(to_object_result.IsEmpty());
4722   CHECK(try_catch.HasCaught());
4723   try_catch.Reset();
4724
4725   int32_t int32_value = obj->Int32Value();
4726   CHECK_EQ(0, int32_value);
4727   CheckUncle(&try_catch);
4728
4729   uint32_t uint32_value = obj->Uint32Value();
4730   CHECK_EQ(0u, uint32_value);
4731   CheckUncle(&try_catch);
4732
4733   double number_value = obj->NumberValue();
4734   CHECK(std::isnan(number_value));
4735   CheckUncle(&try_catch);
4736
4737   int64_t integer_value = obj->IntegerValue();
4738   CHECK_EQ(0, integer_value);
4739   CheckUncle(&try_catch);
4740 }
4741
4742
4743 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4744   ApiTestFuzzer::Fuzz();
4745   args.GetIsolate()->ThrowException(v8_str("konto"));
4746 }
4747
4748
4749 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4750   if (args.Length() < 1) {
4751     args.GetReturnValue().Set(false);
4752     return;
4753   }
4754   v8::HandleScope scope(args.GetIsolate());
4755   v8::TryCatch try_catch(args.GetIsolate());
4756   Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
4757   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4758   args.GetReturnValue().Set(try_catch.HasCaught());
4759 }
4760
4761
4762 THREADED_TEST(APICatch) {
4763   v8::Isolate* isolate = CcTest::isolate();
4764   v8::HandleScope scope(isolate);
4765   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4766   templ->Set(v8_str("ThrowFromC"),
4767              v8::FunctionTemplate::New(isolate, ThrowFromC));
4768   LocalContext context(0, templ);
4769   CompileRun(
4770       "var thrown = false;"
4771       "try {"
4772       "  ThrowFromC();"
4773       "} catch (e) {"
4774       "  thrown = true;"
4775       "}");
4776   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4777   CHECK(thrown->BooleanValue());
4778 }
4779
4780
4781 THREADED_TEST(APIThrowTryCatch) {
4782   v8::Isolate* isolate = CcTest::isolate();
4783   v8::HandleScope scope(isolate);
4784   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4785   templ->Set(v8_str("ThrowFromC"),
4786              v8::FunctionTemplate::New(isolate, ThrowFromC));
4787   LocalContext context(0, templ);
4788   v8::TryCatch try_catch(isolate);
4789   CompileRun("ThrowFromC();");
4790   CHECK(try_catch.HasCaught());
4791 }
4792
4793
4794 // Test that a try-finally block doesn't shadow a try-catch block
4795 // when setting up an external handler.
4796 //
4797 // BUG(271): Some of the exception propagation does not work on the
4798 // ARM simulator because the simulator separates the C++ stack and the
4799 // JS stack.  This test therefore fails on the simulator.  The test is
4800 // not threaded to allow the threading tests to run on the simulator.
4801 TEST(TryCatchInTryFinally) {
4802   v8::Isolate* isolate = CcTest::isolate();
4803   v8::HandleScope scope(isolate);
4804   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4805   templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
4806   LocalContext context(0, templ);
4807   Local<Value> result = CompileRun(
4808       "try {"
4809       "  try {"
4810       "    CCatcher('throw 7;');"
4811       "  } finally {"
4812       "  }"
4813       "} catch (e) {"
4814       "}");
4815   CHECK(result->IsTrue());
4816 }
4817
4818
4819 static void check_reference_error_message(v8::Handle<v8::Message> message,
4820                                           v8::Handle<v8::Value> data) {
4821   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4822   CHECK(message->Get()->Equals(v8_str(reference_error)));
4823 }
4824
4825
4826 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4827   ApiTestFuzzer::Fuzz();
4828   CHECK(false);
4829 }
4830
4831
4832 // Test that overwritten methods are not invoked on uncaught exception
4833 // formatting. However, they are invoked when performing normal error
4834 // string conversions.
4835 TEST(APIThrowMessageOverwrittenToString) {
4836   v8::Isolate* isolate = CcTest::isolate();
4837   v8::HandleScope scope(isolate);
4838   v8::V8::AddMessageListener(check_reference_error_message);
4839   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4840   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4841   LocalContext context(NULL, templ);
4842   CompileRun("asdf;");
4843   CompileRun(
4844       "var limit = {};"
4845       "limit.valueOf = fail;"
4846       "Error.stackTraceLimit = limit;");
4847   CompileRun("asdf");
4848   CompileRun("Array.prototype.pop = fail;");
4849   CompileRun("Object.prototype.hasOwnProperty = fail;");
4850   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4851   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4852   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4853   CompileRun(
4854       "ReferenceError.prototype.toString ="
4855       "  function() { return 'Whoops' }");
4856   CompileRun("asdf;");
4857   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4858   CompileRun("asdf;");
4859   CompileRun("ReferenceError.prototype.constructor = void 0;");
4860   CompileRun("asdf;");
4861   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4862   CompileRun("asdf;");
4863   CompileRun("ReferenceError.prototype = new Object();");
4864   CompileRun("asdf;");
4865   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4866   CHECK(string->Equals(v8_str("Whoops")));
4867   CompileRun(
4868       "ReferenceError.prototype.constructor = new Object();"
4869       "ReferenceError.prototype.constructor.name = 1;"
4870       "Number.prototype.toString = function() { return 'Whoops'; };"
4871       "ReferenceError.prototype.toString = Object.prototype.toString;");
4872   CompileRun("asdf;");
4873   v8::V8::RemoveMessageListeners(check_reference_error_message);
4874 }
4875
4876
4877 static void check_custom_error_tostring(v8::Handle<v8::Message> message,
4878                                         v8::Handle<v8::Value> data) {
4879   const char* uncaught_error = "Uncaught MyError toString";
4880   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4881 }
4882
4883
4884 TEST(CustomErrorToString) {
4885   LocalContext context;
4886   v8::HandleScope scope(context->GetIsolate());
4887   v8::V8::AddMessageListener(check_custom_error_tostring);
4888   CompileRun(
4889       "function MyError(name, message) {                   "
4890       "  this.name = name;                                 "
4891       "  this.message = message;                           "
4892       "}                                                   "
4893       "MyError.prototype = Object.create(Error.prototype); "
4894       "MyError.prototype.toString = function() {           "
4895       "  return 'MyError toString';                        "
4896       "};                                                  "
4897       "throw new MyError('my name', 'my message');         ");
4898   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4899 }
4900
4901
4902 static void check_custom_error_message(v8::Handle<v8::Message> message,
4903                                        v8::Handle<v8::Value> data) {
4904   const char* uncaught_error = "Uncaught MyError: my message";
4905   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4906   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4907 }
4908
4909
4910 TEST(CustomErrorMessage) {
4911   LocalContext context;
4912   v8::HandleScope scope(context->GetIsolate());
4913   v8::V8::AddMessageListener(check_custom_error_message);
4914
4915   // Handlebars.
4916   CompileRun(
4917       "function MyError(msg) {                             "
4918       "  this.name = 'MyError';                            "
4919       "  this.message = msg;                               "
4920       "}                                                   "
4921       "MyError.prototype = new Error();                    "
4922       "throw new MyError('my message');                    ");
4923
4924   // Closure.
4925   CompileRun(
4926       "function MyError(msg) {                             "
4927       "  this.name = 'MyError';                            "
4928       "  this.message = msg;                               "
4929       "}                                                   "
4930       "inherits = function(childCtor, parentCtor) {        "
4931       "    function tempCtor() {};                         "
4932       "    tempCtor.prototype = parentCtor.prototype;      "
4933       "    childCtor.superClass_ = parentCtor.prototype;   "
4934       "    childCtor.prototype = new tempCtor();           "
4935       "    childCtor.prototype.constructor = childCtor;    "
4936       "};                                                  "
4937       "inherits(MyError, Error);                           "
4938       "throw new MyError('my message');                    ");
4939
4940   // Object.create.
4941   CompileRun(
4942       "function MyError(msg) {                             "
4943       "  this.name = 'MyError';                            "
4944       "  this.message = msg;                               "
4945       "}                                                   "
4946       "MyError.prototype = Object.create(Error.prototype); "
4947       "throw new MyError('my message');                    ");
4948
4949   v8::V8::RemoveMessageListeners(check_custom_error_message);
4950 }
4951
4952
4953 static void check_custom_rethrowing_message(v8::Handle<v8::Message> message,
4954                                             v8::Handle<v8::Value> data) {
4955   const char* uncaught_error = "Uncaught exception";
4956   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4957 }
4958
4959
4960 TEST(CustomErrorRethrowsOnToString) {
4961   LocalContext context;
4962   v8::HandleScope scope(context->GetIsolate());
4963   v8::V8::AddMessageListener(check_custom_rethrowing_message);
4964
4965   CompileRun(
4966       "var e = { toString: function() { throw e; } };"
4967       "try { throw e; } finally {}");
4968
4969   v8::V8::RemoveMessageListeners(check_custom_rethrowing_message);
4970 }
4971
4972
4973 static void receive_message(v8::Handle<v8::Message> message,
4974                             v8::Handle<v8::Value> data) {
4975   message->Get();
4976   message_received = true;
4977 }
4978
4979
4980 TEST(APIThrowMessage) {
4981   message_received = false;
4982   v8::Isolate* isolate = CcTest::isolate();
4983   v8::HandleScope scope(isolate);
4984   v8::V8::AddMessageListener(receive_message);
4985   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4986   templ->Set(v8_str("ThrowFromC"),
4987              v8::FunctionTemplate::New(isolate, ThrowFromC));
4988   LocalContext context(0, templ);
4989   CompileRun("ThrowFromC();");
4990   CHECK(message_received);
4991   v8::V8::RemoveMessageListeners(receive_message);
4992 }
4993
4994
4995 TEST(APIThrowMessageAndVerboseTryCatch) {
4996   message_received = false;
4997   v8::Isolate* isolate = CcTest::isolate();
4998   v8::HandleScope scope(isolate);
4999   v8::V8::AddMessageListener(receive_message);
5000   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5001   templ->Set(v8_str("ThrowFromC"),
5002              v8::FunctionTemplate::New(isolate, ThrowFromC));
5003   LocalContext context(0, templ);
5004   v8::TryCatch try_catch(isolate);
5005   try_catch.SetVerbose(true);
5006   Local<Value> result = CompileRun("ThrowFromC();");
5007   CHECK(try_catch.HasCaught());
5008   CHECK(result.IsEmpty());
5009   CHECK(message_received);
5010   v8::V8::RemoveMessageListeners(receive_message);
5011 }
5012
5013
5014 TEST(APIStackOverflowAndVerboseTryCatch) {
5015   message_received = false;
5016   LocalContext context;
5017   v8::HandleScope scope(context->GetIsolate());
5018   v8::V8::AddMessageListener(receive_message);
5019   v8::TryCatch try_catch(context->GetIsolate());
5020   try_catch.SetVerbose(true);
5021   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5022   CHECK(try_catch.HasCaught());
5023   CHECK(result.IsEmpty());
5024   CHECK(message_received);
5025   v8::V8::RemoveMessageListeners(receive_message);
5026 }
5027
5028
5029 THREADED_TEST(ExternalScriptException) {
5030   v8::Isolate* isolate = CcTest::isolate();
5031   v8::HandleScope scope(isolate);
5032   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5033   templ->Set(v8_str("ThrowFromC"),
5034              v8::FunctionTemplate::New(isolate, ThrowFromC));
5035   LocalContext context(0, templ);
5036
5037   v8::TryCatch try_catch(isolate);
5038   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5039   CHECK(result.IsEmpty());
5040   CHECK(try_catch.HasCaught());
5041   String::Utf8Value exception_value(try_catch.Exception());
5042   CHECK_EQ(0, strcmp("konto", *exception_value));
5043 }
5044
5045
5046 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5047   ApiTestFuzzer::Fuzz();
5048   CHECK_EQ(4, args.Length());
5049   int count = args[0]->Int32Value();
5050   int cInterval = args[2]->Int32Value();
5051   if (count == 0) {
5052     args.GetIsolate()->ThrowException(v8_str("FromC"));
5053     return;
5054   } else {
5055     Local<v8::Object> global = args.GetIsolate()->GetCurrentContext()->Global();
5056     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5057     v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
5058     if (count % cInterval == 0) {
5059       v8::TryCatch try_catch(args.GetIsolate());
5060       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5061       int expected = args[3]->Int32Value();
5062       if (try_catch.HasCaught()) {
5063         CHECK_EQ(expected, count);
5064         CHECK(result.IsEmpty());
5065         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5066       } else {
5067         CHECK_NE(expected, count);
5068       }
5069       args.GetReturnValue().Set(result);
5070       return;
5071     } else {
5072       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5073       return;
5074     }
5075   }
5076 }
5077
5078
5079 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5080   ApiTestFuzzer::Fuzz();
5081   CHECK_EQ(3, args.Length());
5082   bool equality = args[0]->BooleanValue();
5083   int count = args[1]->Int32Value();
5084   int expected = args[2]->Int32Value();
5085   if (equality) {
5086     CHECK_EQ(count, expected);
5087   } else {
5088     CHECK_NE(count, expected);
5089   }
5090 }
5091
5092
5093 THREADED_TEST(EvalInTryFinally) {
5094   LocalContext context;
5095   v8::HandleScope scope(context->GetIsolate());
5096   v8::TryCatch try_catch(context->GetIsolate());
5097   CompileRun(
5098       "(function() {"
5099       "  try {"
5100       "    eval('asldkf (*&^&*^');"
5101       "  } finally {"
5102       "    return;"
5103       "  }"
5104       "})()");
5105   CHECK(!try_catch.HasCaught());
5106 }
5107
5108
5109 // This test works by making a stack of alternating JavaScript and C
5110 // activations.  These activations set up exception handlers with regular
5111 // intervals, one interval for C activations and another for JavaScript
5112 // activations.  When enough activations have been created an exception is
5113 // thrown and we check that the right activation catches the exception and that
5114 // no other activations do.  The right activation is always the topmost one with
5115 // a handler, regardless of whether it is in JavaScript or C.
5116 //
5117 // The notation used to describe a test case looks like this:
5118 //
5119 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5120 //
5121 // Each entry is an activation, either JS or C.  The index is the count at that
5122 // level.  Stars identify activations with exception handlers, the @ identifies
5123 // the exception handler that should catch the exception.
5124 //
5125 // BUG(271): Some of the exception propagation does not work on the
5126 // ARM simulator because the simulator separates the C++ stack and the
5127 // JS stack.  This test therefore fails on the simulator.  The test is
5128 // not threaded to allow the threading tests to run on the simulator.
5129 TEST(ExceptionOrder) {
5130   v8::Isolate* isolate = CcTest::isolate();
5131   v8::HandleScope scope(isolate);
5132   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5133   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5134   templ->Set(v8_str("CThrowCountDown"),
5135              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5136   LocalContext context(0, templ);
5137   CompileRun(
5138       "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5139       "  if (count == 0) throw 'FromJS';"
5140       "  if (count % jsInterval == 0) {"
5141       "    try {"
5142       "      var value = CThrowCountDown(count - 1,"
5143       "                                  jsInterval,"
5144       "                                  cInterval,"
5145       "                                  expected);"
5146       "      check(false, count, expected);"
5147       "      return value;"
5148       "    } catch (e) {"
5149       "      check(true, count, expected);"
5150       "    }"
5151       "  } else {"
5152       "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5153       "  }"
5154       "}");
5155   Local<Function> fun =
5156       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5157
5158   const int argc = 4;
5159   //                             count      jsInterval cInterval  expected
5160
5161   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5162   v8::Handle<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
5163   fun->Call(fun, argc, a0);
5164
5165   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5166   v8::Handle<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
5167   fun->Call(fun, argc, a1);
5168
5169   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5170   v8::Handle<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
5171   fun->Call(fun, argc, a2);
5172
5173   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5174   v8::Handle<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
5175   fun->Call(fun, argc, a3);
5176
5177   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5178   v8::Handle<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
5179   fun->Call(fun, argc, a4);
5180
5181   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5182   v8::Handle<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
5183   fun->Call(fun, argc, a5);
5184 }
5185
5186
5187 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5188   ApiTestFuzzer::Fuzz();
5189   CHECK_EQ(1, args.Length());
5190   args.GetIsolate()->ThrowException(args[0]);
5191 }
5192
5193
5194 THREADED_TEST(ThrowValues) {
5195   v8::Isolate* isolate = CcTest::isolate();
5196   v8::HandleScope scope(isolate);
5197   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5198   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5199   LocalContext context(0, templ);
5200   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5201       "function Run(obj) {"
5202       "  try {"
5203       "    Throw(obj);"
5204       "  } catch (e) {"
5205       "    return e;"
5206       "  }"
5207       "  return 'no exception';"
5208       "}"
5209       "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5210   CHECK_EQ(5u, result->Length());
5211   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5212   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5213   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5214   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5215   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5216   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5217   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5218 }
5219
5220
5221 THREADED_TEST(CatchZero) {
5222   LocalContext context;
5223   v8::HandleScope scope(context->GetIsolate());
5224   v8::TryCatch try_catch(context->GetIsolate());
5225   CHECK(!try_catch.HasCaught());
5226   CompileRun("throw 10");
5227   CHECK(try_catch.HasCaught());
5228   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5229   try_catch.Reset();
5230   CHECK(!try_catch.HasCaught());
5231   CompileRun("throw 0");
5232   CHECK(try_catch.HasCaught());
5233   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5234 }
5235
5236
5237 THREADED_TEST(CatchExceptionFromWith) {
5238   LocalContext context;
5239   v8::HandleScope scope(context->GetIsolate());
5240   v8::TryCatch try_catch(context->GetIsolate());
5241   CHECK(!try_catch.HasCaught());
5242   CompileRun("var o = {}; with (o) { throw 42; }");
5243   CHECK(try_catch.HasCaught());
5244 }
5245
5246
5247 THREADED_TEST(TryCatchAndFinallyHidingException) {
5248   LocalContext context;
5249   v8::HandleScope scope(context->GetIsolate());
5250   v8::TryCatch try_catch(context->GetIsolate());
5251   CHECK(!try_catch.HasCaught());
5252   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5253   CompileRun("f({toString: function() { throw 42; }});");
5254   CHECK(!try_catch.HasCaught());
5255 }
5256
5257
5258 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5259   v8::TryCatch try_catch(args.GetIsolate());
5260 }
5261
5262
5263 THREADED_TEST(TryCatchAndFinally) {
5264   LocalContext context;
5265   v8::Isolate* isolate = context->GetIsolate();
5266   v8::HandleScope scope(isolate);
5267   context->Global()->Set(
5268       v8_str("native_with_try_catch"),
5269       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5270   v8::TryCatch try_catch(isolate);
5271   CHECK(!try_catch.HasCaught());
5272   CompileRun(
5273       "try {\n"
5274       "  throw new Error('a');\n"
5275       "} finally {\n"
5276       "  native_with_try_catch();\n"
5277       "}\n");
5278   CHECK(try_catch.HasCaught());
5279 }
5280
5281
5282 static void TryCatchNested1Helper(int depth) {
5283   if (depth > 0) {
5284     v8::TryCatch try_catch(CcTest::isolate());
5285     try_catch.SetVerbose(true);
5286     TryCatchNested1Helper(depth - 1);
5287     CHECK(try_catch.HasCaught());
5288     try_catch.ReThrow();
5289   } else {
5290     CcTest::isolate()->ThrowException(v8_str("E1"));
5291   }
5292 }
5293
5294
5295 static void TryCatchNested2Helper(int depth) {
5296   if (depth > 0) {
5297     v8::TryCatch try_catch(CcTest::isolate());
5298     try_catch.SetVerbose(true);
5299     TryCatchNested2Helper(depth - 1);
5300     CHECK(try_catch.HasCaught());
5301     try_catch.ReThrow();
5302   } else {
5303     CompileRun("throw 'E2';");
5304   }
5305 }
5306
5307
5308 TEST(TryCatchNested) {
5309   v8::V8::Initialize();
5310   LocalContext context;
5311   v8::HandleScope scope(context->GetIsolate());
5312
5313   {
5314     // Test nested try-catch with a native throw in the end.
5315     v8::TryCatch try_catch(context->GetIsolate());
5316     TryCatchNested1Helper(5);
5317     CHECK(try_catch.HasCaught());
5318     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5319   }
5320
5321   {
5322     // Test nested try-catch with a JavaScript throw in the end.
5323     v8::TryCatch try_catch(context->GetIsolate());
5324     TryCatchNested2Helper(5);
5325     CHECK(try_catch.HasCaught());
5326     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5327   }
5328 }
5329
5330
5331 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5332   CHECK(try_catch->HasCaught());
5333   Handle<Message> message = try_catch->Message();
5334   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5335   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5336   CHECK_EQ(0,
5337            strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
5338   CHECK_EQ(1, message->GetLineNumber());
5339   CHECK_EQ(0, message->GetStartColumn());
5340 }
5341
5342
5343 void TryCatchMixedNestingHelper(
5344     const v8::FunctionCallbackInfo<v8::Value>& args) {
5345   ApiTestFuzzer::Fuzz();
5346   v8::TryCatch try_catch(args.GetIsolate());
5347   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5348   CHECK(try_catch.HasCaught());
5349   TryCatchMixedNestingCheck(&try_catch);
5350   try_catch.ReThrow();
5351 }
5352
5353
5354 // This test ensures that an outer TryCatch in the following situation:
5355 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5356 // does not clobber the Message object generated for the inner TryCatch.
5357 // This exercises the ability of TryCatch.ReThrow() to restore the
5358 // inner pending Message before throwing the exception again.
5359 TEST(TryCatchMixedNesting) {
5360   v8::Isolate* isolate = CcTest::isolate();
5361   v8::HandleScope scope(isolate);
5362   v8::V8::Initialize();
5363   v8::TryCatch try_catch(isolate);
5364   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5365   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5366              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5367   LocalContext context(0, templ);
5368   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5369   TryCatchMixedNestingCheck(&try_catch);
5370 }
5371
5372
5373 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5374   ApiTestFuzzer::Fuzz();
5375   v8::TryCatch try_catch(args.GetIsolate());
5376   args.GetIsolate()->ThrowException(v8_str("boom"));
5377   CHECK(try_catch.HasCaught());
5378 }
5379
5380
5381 TEST(TryCatchNative) {
5382   v8::Isolate* isolate = CcTest::isolate();
5383   v8::HandleScope scope(isolate);
5384   v8::V8::Initialize();
5385   v8::TryCatch try_catch(isolate);
5386   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5387   templ->Set(v8_str("TryCatchNativeHelper"),
5388              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5389   LocalContext context(0, templ);
5390   CompileRun("TryCatchNativeHelper();");
5391   CHECK(!try_catch.HasCaught());
5392 }
5393
5394
5395 void TryCatchNativeResetHelper(
5396     const v8::FunctionCallbackInfo<v8::Value>& args) {
5397   ApiTestFuzzer::Fuzz();
5398   v8::TryCatch try_catch(args.GetIsolate());
5399   args.GetIsolate()->ThrowException(v8_str("boom"));
5400   CHECK(try_catch.HasCaught());
5401   try_catch.Reset();
5402   CHECK(!try_catch.HasCaught());
5403 }
5404
5405
5406 TEST(TryCatchNativeReset) {
5407   v8::Isolate* isolate = CcTest::isolate();
5408   v8::HandleScope scope(isolate);
5409   v8::V8::Initialize();
5410   v8::TryCatch try_catch(isolate);
5411   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5412   templ->Set(v8_str("TryCatchNativeResetHelper"),
5413              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5414   LocalContext context(0, templ);
5415   CompileRun("TryCatchNativeResetHelper();");
5416   CHECK(!try_catch.HasCaught());
5417 }
5418
5419
5420 THREADED_TEST(Equality) {
5421   LocalContext context;
5422   v8::Isolate* isolate = context->GetIsolate();
5423   v8::HandleScope scope(context->GetIsolate());
5424   // Check that equality works at all before relying on CHECK_EQ
5425   CHECK(v8_str("a")->Equals(v8_str("a")));
5426   CHECK(!v8_str("a")->Equals(v8_str("b")));
5427
5428   CHECK(v8_str("a")->Equals(v8_str("a")));
5429   CHECK(!v8_str("a")->Equals(v8_str("b")));
5430   CHECK(v8_num(1)->Equals(v8_num(1)));
5431   CHECK(v8_num(1.00)->Equals(v8_num(1)));
5432   CHECK(!v8_num(1)->Equals(v8_num(2)));
5433
5434   // Assume String is not internalized.
5435   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5436   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5437   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5438   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5439   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5440   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5441   Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
5442   CHECK(!not_a_number->StrictEquals(not_a_number));
5443   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5444   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5445
5446   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5447   v8::Persistent<v8::Object> alias(isolate, obj);
5448   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5449   alias.Reset();
5450
5451   CHECK(v8_str("a")->SameValue(v8_str("a")));
5452   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5453   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5454   CHECK(v8_num(1)->SameValue(v8_num(1)));
5455   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5456   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5457   CHECK(not_a_number->SameValue(not_a_number));
5458   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5459   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5460 }
5461
5462
5463 THREADED_TEST(MultiRun) {
5464   LocalContext context;
5465   v8::HandleScope scope(context->GetIsolate());
5466   Local<Script> script = v8_compile("x");
5467   for (int i = 0; i < 10; i++) script->Run();
5468 }
5469
5470
5471 static void GetXValue(Local<String> name,
5472                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5473   ApiTestFuzzer::Fuzz();
5474   CHECK(info.Data()->Equals(v8_str("donut")));
5475   CHECK(name->Equals(v8_str("x")));
5476   info.GetReturnValue().Set(name);
5477 }
5478
5479
5480 THREADED_TEST(SimplePropertyRead) {
5481   LocalContext context;
5482   v8::Isolate* isolate = context->GetIsolate();
5483   v8::HandleScope scope(isolate);
5484   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5485   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5486   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5487   Local<Script> script = v8_compile("obj.x");
5488   for (int i = 0; i < 10; i++) {
5489     Local<Value> result = script->Run();
5490     CHECK(result->Equals(v8_str("x")));
5491   }
5492 }
5493
5494
5495 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5496   LocalContext context;
5497   v8::Isolate* isolate = context->GetIsolate();
5498   v8::HandleScope scope(isolate);
5499   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5500   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5501   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5502
5503   // Uses getOwnPropertyDescriptor to check the configurable status
5504   Local<Script> script_desc = v8_compile(
5505       "var prop = Object.getOwnPropertyDescriptor( "
5506       "obj, 'x');"
5507       "prop.configurable;");
5508   Local<Value> result = script_desc->Run();
5509   CHECK_EQ(result->BooleanValue(), true);
5510
5511   // Redefine get - but still configurable
5512   Local<Script> script_define = v8_compile(
5513       "var desc = { get: function(){return 42; },"
5514       "            configurable: true };"
5515       "Object.defineProperty(obj, 'x', desc);"
5516       "obj.x");
5517   result = script_define->Run();
5518   CHECK(result->Equals(v8_num(42)));
5519
5520   // Check that the accessor is still configurable
5521   result = script_desc->Run();
5522   CHECK_EQ(result->BooleanValue(), true);
5523
5524   // Redefine to a non-configurable
5525   script_define = v8_compile(
5526       "var desc = { get: function(){return 43; },"
5527       "             configurable: false };"
5528       "Object.defineProperty(obj, 'x', desc);"
5529       "obj.x");
5530   result = script_define->Run();
5531   CHECK(result->Equals(v8_num(43)));
5532   result = script_desc->Run();
5533   CHECK_EQ(result->BooleanValue(), false);
5534
5535   // Make sure that it is not possible to redefine again
5536   v8::TryCatch try_catch(isolate);
5537   result = script_define->Run();
5538   CHECK(try_catch.HasCaught());
5539   String::Utf8Value exception_value(try_catch.Exception());
5540   CHECK_EQ(0,
5541            strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5542 }
5543
5544
5545 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5546   v8::Isolate* isolate = CcTest::isolate();
5547   v8::HandleScope scope(isolate);
5548   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5549   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5550   LocalContext context;
5551   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5552
5553   Local<Script> script_desc = v8_compile(
5554       "var prop ="
5555       "Object.getOwnPropertyDescriptor( "
5556       "obj, 'x');"
5557       "prop.configurable;");
5558   Local<Value> result = script_desc->Run();
5559   CHECK_EQ(result->BooleanValue(), true);
5560
5561   Local<Script> script_define = v8_compile(
5562       "var desc = {get: function(){return 42; },"
5563       "            configurable: true };"
5564       "Object.defineProperty(obj, 'x', desc);"
5565       "obj.x");
5566   result = script_define->Run();
5567   CHECK(result->Equals(v8_num(42)));
5568
5569
5570   result = script_desc->Run();
5571   CHECK_EQ(result->BooleanValue(), true);
5572
5573
5574   script_define = v8_compile(
5575       "var desc = {get: function(){return 43; },"
5576       "            configurable: false };"
5577       "Object.defineProperty(obj, 'x', desc);"
5578       "obj.x");
5579   result = script_define->Run();
5580   CHECK(result->Equals(v8_num(43)));
5581   result = script_desc->Run();
5582
5583   CHECK_EQ(result->BooleanValue(), false);
5584
5585   v8::TryCatch try_catch(isolate);
5586   result = script_define->Run();
5587   CHECK(try_catch.HasCaught());
5588   String::Utf8Value exception_value(try_catch.Exception());
5589   CHECK_EQ(0,
5590            strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5591 }
5592
5593
5594 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5595                                                 char const* name) {
5596   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5597 }
5598
5599
5600 THREADED_TEST(DefineAPIAccessorOnObject) {
5601   v8::Isolate* isolate = CcTest::isolate();
5602   v8::HandleScope scope(isolate);
5603   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5604   LocalContext context;
5605
5606   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5607   CompileRun("var obj2 = {};");
5608
5609   CHECK(CompileRun("obj1.x")->IsUndefined());
5610   CHECK(CompileRun("obj2.x")->IsUndefined());
5611
5612   CHECK(GetGlobalProperty(&context, "obj1")
5613             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5614
5615   ExpectString("obj1.x", "x");
5616   CHECK(CompileRun("obj2.x")->IsUndefined());
5617
5618   CHECK(GetGlobalProperty(&context, "obj2")
5619             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5620
5621   ExpectString("obj1.x", "x");
5622   ExpectString("obj2.x", "x");
5623
5624   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5625   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5626
5627   CompileRun(
5628       "Object.defineProperty(obj1, 'x',"
5629       "{ get: function() { return 'y'; }, configurable: true })");
5630
5631   ExpectString("obj1.x", "y");
5632   ExpectString("obj2.x", "x");
5633
5634   CompileRun(
5635       "Object.defineProperty(obj2, 'x',"
5636       "{ get: function() { return 'y'; }, configurable: true })");
5637
5638   ExpectString("obj1.x", "y");
5639   ExpectString("obj2.x", "y");
5640
5641   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5642   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5643
5644   CHECK(GetGlobalProperty(&context, "obj1")
5645             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5646   CHECK(GetGlobalProperty(&context, "obj2")
5647             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5648
5649   ExpectString("obj1.x", "x");
5650   ExpectString("obj2.x", "x");
5651
5652   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5653   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5654
5655   // Define getters/setters, but now make them not configurable.
5656   CompileRun(
5657       "Object.defineProperty(obj1, 'x',"
5658       "{ get: function() { return 'z'; }, configurable: false })");
5659   CompileRun(
5660       "Object.defineProperty(obj2, 'x',"
5661       "{ get: function() { return 'z'; }, configurable: false })");
5662
5663   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5664   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5665
5666   ExpectString("obj1.x", "z");
5667   ExpectString("obj2.x", "z");
5668
5669   CHECK(!GetGlobalProperty(&context, "obj1")
5670              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5671   CHECK(!GetGlobalProperty(&context, "obj2")
5672              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5673
5674   ExpectString("obj1.x", "z");
5675   ExpectString("obj2.x", "z");
5676 }
5677
5678
5679 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5680   v8::Isolate* isolate = CcTest::isolate();
5681   v8::HandleScope scope(isolate);
5682   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5683   LocalContext context;
5684
5685   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5686   CompileRun("var obj2 = {};");
5687
5688   CHECK(GetGlobalProperty(&context, "obj1")
5689             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5690                           v8::DEFAULT, v8::DontDelete));
5691   CHECK(GetGlobalProperty(&context, "obj2")
5692             ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5693                           v8::DEFAULT, v8::DontDelete));
5694
5695   ExpectString("obj1.x", "x");
5696   ExpectString("obj2.x", "x");
5697
5698   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5699   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5700
5701   CHECK(!GetGlobalProperty(&context, "obj1")
5702              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5703   CHECK(!GetGlobalProperty(&context, "obj2")
5704              ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5705
5706   {
5707     v8::TryCatch try_catch(isolate);
5708     CompileRun(
5709         "Object.defineProperty(obj1, 'x',"
5710         "{get: function() { return 'func'; }})");
5711     CHECK(try_catch.HasCaught());
5712     String::Utf8Value exception_value(try_catch.Exception());
5713     CHECK_EQ(
5714         0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5715   }
5716   {
5717     v8::TryCatch try_catch(isolate);
5718     CompileRun(
5719         "Object.defineProperty(obj2, 'x',"
5720         "{get: function() { return 'func'; }})");
5721     CHECK(try_catch.HasCaught());
5722     String::Utf8Value exception_value(try_catch.Exception());
5723     CHECK_EQ(
5724         0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5725   }
5726 }
5727
5728
5729 static void Get239Value(Local<String> name,
5730                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5731   ApiTestFuzzer::Fuzz();
5732   CHECK(info.Data()->Equals(v8_str("donut")));
5733   CHECK(name->Equals(v8_str("239")));
5734   info.GetReturnValue().Set(name);
5735 }
5736
5737
5738 THREADED_TEST(ElementAPIAccessor) {
5739   v8::Isolate* isolate = CcTest::isolate();
5740   v8::HandleScope scope(isolate);
5741   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5742   LocalContext context;
5743
5744   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5745   CompileRun("var obj2 = {};");
5746
5747   CHECK(GetGlobalProperty(&context, "obj1")
5748             ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5749   CHECK(GetGlobalProperty(&context, "obj2")
5750             ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5751
5752   ExpectString("obj1[239]", "239");
5753   ExpectString("obj2[239]", "239");
5754   ExpectString("obj1['239']", "239");
5755   ExpectString("obj2['239']", "239");
5756 }
5757
5758
5759 v8::Persistent<Value> xValue;
5760
5761
5762 static void SetXValue(Local<String> name, Local<Value> value,
5763                       const v8::PropertyCallbackInfo<void>& info) {
5764   CHECK(value->Equals(v8_num(4)));
5765   CHECK(info.Data()->Equals(v8_str("donut")));
5766   CHECK(name->Equals(v8_str("x")));
5767   CHECK(xValue.IsEmpty());
5768   xValue.Reset(info.GetIsolate(), value);
5769 }
5770
5771
5772 THREADED_TEST(SimplePropertyWrite) {
5773   v8::Isolate* isolate = CcTest::isolate();
5774   v8::HandleScope scope(isolate);
5775   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5776   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5777   LocalContext context;
5778   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5779   Local<Script> script = v8_compile("obj.x = 4");
5780   for (int i = 0; i < 10; i++) {
5781     CHECK(xValue.IsEmpty());
5782     script->Run();
5783     CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5784     xValue.Reset();
5785   }
5786 }
5787
5788
5789 THREADED_TEST(SetterOnly) {
5790   v8::Isolate* isolate = CcTest::isolate();
5791   v8::HandleScope scope(isolate);
5792   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5793   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5794   LocalContext context;
5795   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5796   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5797   for (int i = 0; i < 10; i++) {
5798     CHECK(xValue.IsEmpty());
5799     script->Run();
5800     CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5801     xValue.Reset();
5802   }
5803 }
5804
5805
5806 THREADED_TEST(NoAccessors) {
5807   v8::Isolate* isolate = CcTest::isolate();
5808   v8::HandleScope scope(isolate);
5809   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5810   templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL),
5811                      NULL, v8_str("donut"));
5812   LocalContext context;
5813   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5814   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5815   for (int i = 0; i < 10; i++) {
5816     script->Run();
5817   }
5818 }
5819
5820
5821 THREADED_TEST(MultiContexts) {
5822   v8::Isolate* isolate = CcTest::isolate();
5823   v8::HandleScope scope(isolate);
5824   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5825   templ->Set(v8_str("dummy"),
5826              v8::FunctionTemplate::New(isolate, DummyCallHandler));
5827
5828   Local<String> password = v8_str("Password");
5829
5830   // Create an environment
5831   LocalContext context0(0, templ);
5832   context0->SetSecurityToken(password);
5833   v8::Handle<v8::Object> global0 = context0->Global();
5834   global0->Set(v8_str("custom"), v8_num(1234));
5835   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5836
5837   // Create an independent environment
5838   LocalContext context1(0, templ);
5839   context1->SetSecurityToken(password);
5840   v8::Handle<v8::Object> global1 = context1->Global();
5841   global1->Set(v8_str("custom"), v8_num(1234));
5842   CHECK(!global0->Equals(global1));
5843   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5844   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5845
5846   // Now create a new context with the old global
5847   LocalContext context2(0, templ, global1);
5848   context2->SetSecurityToken(password);
5849   v8::Handle<v8::Object> global2 = context2->Global();
5850   CHECK(global1->Equals(global2));
5851   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5852   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5853 }
5854
5855
5856 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5857   // Make sure that functions created by cloning boilerplates cannot
5858   // communicate through their __proto__ field.
5859
5860   v8::HandleScope scope(CcTest::isolate());
5861
5862   LocalContext env0;
5863   v8::Handle<v8::Object> global0 = env0->Global();
5864   v8::Handle<v8::Object> object0 =
5865       global0->Get(v8_str("Object")).As<v8::Object>();
5866   v8::Handle<v8::Object> tostring0 =
5867       object0->Get(v8_str("toString")).As<v8::Object>();
5868   v8::Handle<v8::Object> proto0 =
5869       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5870   proto0->Set(v8_str("custom"), v8_num(1234));
5871
5872   LocalContext env1;
5873   v8::Handle<v8::Object> global1 = env1->Global();
5874   v8::Handle<v8::Object> object1 =
5875       global1->Get(v8_str("Object")).As<v8::Object>();
5876   v8::Handle<v8::Object> tostring1 =
5877       object1->Get(v8_str("toString")).As<v8::Object>();
5878   v8::Handle<v8::Object> proto1 =
5879       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5880   CHECK(!proto1->Has(v8_str("custom")));
5881 }
5882
5883
5884 THREADED_TEST(Regress892105) {
5885   // Make sure that object and array literals created by cloning
5886   // boilerplates cannot communicate through their __proto__
5887   // field. This is rather difficult to check, but we try to add stuff
5888   // to Object.prototype and Array.prototype and create a new
5889   // environment. This should succeed.
5890
5891   v8::HandleScope scope(CcTest::isolate());
5892
5893   Local<String> source = v8_str(
5894       "Object.prototype.obj = 1234;"
5895       "Array.prototype.arr = 4567;"
5896       "8901");
5897
5898   LocalContext env0;
5899   Local<Script> script0 = v8_compile(source);
5900   CHECK_EQ(8901.0, script0->Run()->NumberValue());
5901
5902   LocalContext env1;
5903   Local<Script> script1 = v8_compile(source);
5904   CHECK_EQ(8901.0, script1->Run()->NumberValue());
5905 }
5906
5907
5908 THREADED_TEST(UndetectableObject) {
5909   LocalContext env;
5910   v8::HandleScope scope(env->GetIsolate());
5911
5912   Local<v8::FunctionTemplate> desc =
5913       v8::FunctionTemplate::New(env->GetIsolate());
5914   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5915
5916   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5917   env->Global()->Set(v8_str("undetectable"), obj);
5918
5919   ExpectString("undetectable.toString()", "[object Object]");
5920   ExpectString("typeof undetectable", "undefined");
5921   ExpectString("typeof(undetectable)", "undefined");
5922   ExpectBoolean("typeof undetectable == 'undefined'", true);
5923   ExpectBoolean("typeof undetectable == 'object'", false);
5924   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5925   ExpectBoolean("!undetectable", true);
5926
5927   ExpectObject("true&&undetectable", obj);
5928   ExpectBoolean("false&&undetectable", false);
5929   ExpectBoolean("true||undetectable", true);
5930   ExpectObject("false||undetectable", obj);
5931
5932   ExpectObject("undetectable&&true", obj);
5933   ExpectObject("undetectable&&false", obj);
5934   ExpectBoolean("undetectable||true", true);
5935   ExpectBoolean("undetectable||false", false);
5936
5937   ExpectBoolean("undetectable==null", true);
5938   ExpectBoolean("null==undetectable", true);
5939   ExpectBoolean("undetectable==undefined", true);
5940   ExpectBoolean("undefined==undetectable", true);
5941   ExpectBoolean("undetectable==undetectable", true);
5942
5943
5944   ExpectBoolean("undetectable===null", false);
5945   ExpectBoolean("null===undetectable", false);
5946   ExpectBoolean("undetectable===undefined", false);
5947   ExpectBoolean("undefined===undetectable", false);
5948   ExpectBoolean("undetectable===undetectable", true);
5949 }
5950
5951
5952 THREADED_TEST(VoidLiteral) {
5953   LocalContext env;
5954   v8::Isolate* isolate = env->GetIsolate();
5955   v8::HandleScope scope(isolate);
5956
5957   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5958   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5959
5960   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5961   env->Global()->Set(v8_str("undetectable"), obj);
5962
5963   ExpectBoolean("undefined == void 0", true);
5964   ExpectBoolean("undetectable == void 0", true);
5965   ExpectBoolean("null == void 0", true);
5966   ExpectBoolean("undefined === void 0", true);
5967   ExpectBoolean("undetectable === void 0", false);
5968   ExpectBoolean("null === void 0", false);
5969
5970   ExpectBoolean("void 0 == undefined", true);
5971   ExpectBoolean("void 0 == undetectable", true);
5972   ExpectBoolean("void 0 == null", true);
5973   ExpectBoolean("void 0 === undefined", true);
5974   ExpectBoolean("void 0 === undetectable", false);
5975   ExpectBoolean("void 0 === null", false);
5976
5977   ExpectString(
5978       "(function() {"
5979       "  try {"
5980       "    return x === void 0;"
5981       "  } catch(e) {"
5982       "    return e.toString();"
5983       "  }"
5984       "})()",
5985       "ReferenceError: x is not defined");
5986   ExpectString(
5987       "(function() {"
5988       "  try {"
5989       "    return void 0 === x;"
5990       "  } catch(e) {"
5991       "    return e.toString();"
5992       "  }"
5993       "})()",
5994       "ReferenceError: x is not defined");
5995 }
5996
5997
5998 THREADED_TEST(ExtensibleOnUndetectable) {
5999   LocalContext env;
6000   v8::Isolate* isolate = env->GetIsolate();
6001   v8::HandleScope scope(isolate);
6002
6003   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6004   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6005
6006   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6007   env->Global()->Set(v8_str("undetectable"), obj);
6008
6009   Local<String> source = v8_str(
6010       "undetectable.x = 42;"
6011       "undetectable.x");
6012
6013   Local<Script> script = v8_compile(source);
6014
6015   CHECK(v8::Integer::New(isolate, 42)->Equals(script->Run()));
6016
6017   ExpectBoolean("Object.isExtensible(undetectable)", true);
6018
6019   source = v8_str("Object.preventExtensions(undetectable);");
6020   script = v8_compile(source);
6021   script->Run();
6022   ExpectBoolean("Object.isExtensible(undetectable)", false);
6023
6024   source = v8_str("undetectable.y = 2000;");
6025   script = v8_compile(source);
6026   script->Run();
6027   ExpectBoolean("undetectable.y == undefined", true);
6028 }
6029
6030
6031 // The point of this test is type checking. We run it only so compilers
6032 // don't complain about an unused function.
6033 TEST(PersistentHandles) {
6034   LocalContext env;
6035   v8::Isolate* isolate = CcTest::isolate();
6036   v8::HandleScope scope(isolate);
6037   Local<String> str = v8_str("foo");
6038   v8::Persistent<String> p_str(isolate, str);
6039   p_str.Reset();
6040   Local<Script> scr = v8_compile("");
6041   v8::Persistent<Script> p_scr(isolate, scr);
6042   p_scr.Reset();
6043   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6044   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6045   p_templ.Reset();
6046 }
6047
6048
6049 static void HandleLogDelegator(
6050     const v8::FunctionCallbackInfo<v8::Value>& args) {
6051   ApiTestFuzzer::Fuzz();
6052 }
6053
6054
6055 THREADED_TEST(GlobalObjectTemplate) {
6056   v8::Isolate* isolate = CcTest::isolate();
6057   v8::HandleScope handle_scope(isolate);
6058   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6059   global_template->Set(v8_str("JSNI_Log"),
6060                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6061   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6062   Context::Scope context_scope(context);
6063   CompileRun("JSNI_Log('LOG')");
6064 }
6065
6066
6067 static const char* kSimpleExtensionSource =
6068     "function Foo() {"
6069     "  return 4;"
6070     "}";
6071
6072
6073 TEST(SimpleExtensions) {
6074   v8::HandleScope handle_scope(CcTest::isolate());
6075   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6076   const char* extension_names[] = {"simpletest"};
6077   v8::ExtensionConfiguration extensions(1, extension_names);
6078   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6079   Context::Scope lock(context);
6080   v8::Handle<Value> result = CompileRun("Foo()");
6081   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6082 }
6083
6084
6085 static const char* kStackTraceFromExtensionSource =
6086     "function foo() {"
6087     "  throw new Error();"
6088     "}"
6089     "function bar() {"
6090     "  foo();"
6091     "}";
6092
6093
6094 TEST(StackTraceInExtension) {
6095   v8::HandleScope handle_scope(CcTest::isolate());
6096   v8::RegisterExtension(
6097       new Extension("stacktracetest", kStackTraceFromExtensionSource));
6098   const char* extension_names[] = {"stacktracetest"};
6099   v8::ExtensionConfiguration extensions(1, extension_names);
6100   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6101   Context::Scope lock(context);
6102   CompileRun(
6103       "function user() { bar(); }"
6104       "var error;"
6105       "try{ user(); } catch (e) { error = e; }");
6106   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6107   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6108   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6109 }
6110
6111
6112 TEST(NullExtensions) {
6113   v8::HandleScope handle_scope(CcTest::isolate());
6114   v8::RegisterExtension(new Extension("nulltest", NULL));
6115   const char* extension_names[] = {"nulltest"};
6116   v8::ExtensionConfiguration extensions(1, extension_names);
6117   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6118   Context::Scope lock(context);
6119   v8::Handle<Value> result = CompileRun("1+3");
6120   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6121 }
6122
6123
6124 static const char* kEmbeddedExtensionSource =
6125     "function Ret54321(){return 54321;}~~@@$"
6126     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6127 static const int kEmbeddedExtensionSourceValidLen = 34;
6128
6129
6130 TEST(ExtensionMissingSourceLength) {
6131   v8::HandleScope handle_scope(CcTest::isolate());
6132   v8::RegisterExtension(
6133       new Extension("srclentest_fail", kEmbeddedExtensionSource));
6134   const char* extension_names[] = {"srclentest_fail"};
6135   v8::ExtensionConfiguration extensions(1, extension_names);
6136   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6137   CHECK(0 == *context);
6138 }
6139
6140
6141 TEST(ExtensionWithSourceLength) {
6142   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6143        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6144     v8::HandleScope handle_scope(CcTest::isolate());
6145     i::ScopedVector<char> extension_name(32);
6146     i::SNPrintF(extension_name, "ext #%d", source_len);
6147     v8::RegisterExtension(new Extension(
6148         extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
6149     const char* extension_names[1] = {extension_name.start()};
6150     v8::ExtensionConfiguration extensions(1, extension_names);
6151     v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6152     if (source_len == kEmbeddedExtensionSourceValidLen) {
6153       Context::Scope lock(context);
6154       v8::Handle<Value> result = CompileRun("Ret54321()");
6155       CHECK(v8::Integer::New(CcTest::isolate(), 54321)->Equals(result));
6156     } else {
6157       // Anything but exactly the right length should fail to compile.
6158       CHECK(0 == *context);
6159     }
6160   }
6161 }
6162
6163
6164 static const char* kEvalExtensionSource1 =
6165     "function UseEval1() {"
6166     "  var x = 42;"
6167     "  return eval('x');"
6168     "}";
6169
6170
6171 static const char* kEvalExtensionSource2 =
6172     "(function() {"
6173     "  var x = 42;"
6174     "  function e() {"
6175     "    return eval('x');"
6176     "  }"
6177     "  this.UseEval2 = e;"
6178     "})()";
6179
6180
6181 TEST(UseEvalFromExtension) {
6182   v8::HandleScope handle_scope(CcTest::isolate());
6183   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6184   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6185   const char* extension_names[] = {"evaltest1", "evaltest2"};
6186   v8::ExtensionConfiguration extensions(2, extension_names);
6187   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6188   Context::Scope lock(context);
6189   v8::Handle<Value> result = CompileRun("UseEval1()");
6190   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6191   result = CompileRun("UseEval2()");
6192   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6193 }
6194
6195
6196 static const char* kWithExtensionSource1 =
6197     "function UseWith1() {"
6198     "  var x = 42;"
6199     "  with({x:87}) { return x; }"
6200     "}";
6201
6202
6203 static const char* kWithExtensionSource2 =
6204     "(function() {"
6205     "  var x = 42;"
6206     "  function e() {"
6207     "    with ({x:87}) { return x; }"
6208     "  }"
6209     "  this.UseWith2 = e;"
6210     "})()";
6211
6212
6213 TEST(UseWithFromExtension) {
6214   v8::HandleScope handle_scope(CcTest::isolate());
6215   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6216   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6217   const char* extension_names[] = {"withtest1", "withtest2"};
6218   v8::ExtensionConfiguration extensions(2, extension_names);
6219   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6220   Context::Scope lock(context);
6221   v8::Handle<Value> result = CompileRun("UseWith1()");
6222   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6223   result = CompileRun("UseWith2()");
6224   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6225 }
6226
6227
6228 TEST(AutoExtensions) {
6229   v8::HandleScope handle_scope(CcTest::isolate());
6230   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6231   extension->set_auto_enable(true);
6232   v8::RegisterExtension(extension);
6233   v8::Handle<Context> context = Context::New(CcTest::isolate());
6234   Context::Scope lock(context);
6235   v8::Handle<Value> result = CompileRun("Foo()");
6236   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6237 }
6238
6239
6240 static const char* kSyntaxErrorInExtensionSource = "[";
6241
6242
6243 // Test that a syntax error in an extension does not cause a fatal
6244 // error but results in an empty context.
6245 TEST(SyntaxErrorExtensions) {
6246   v8::HandleScope handle_scope(CcTest::isolate());
6247   v8::RegisterExtension(
6248       new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
6249   const char* extension_names[] = {"syntaxerror"};
6250   v8::ExtensionConfiguration extensions(1, extension_names);
6251   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6252   CHECK(context.IsEmpty());
6253 }
6254
6255
6256 static const char* kExceptionInExtensionSource = "throw 42";
6257
6258
6259 // Test that an exception when installing an extension does not cause
6260 // a fatal error but results in an empty context.
6261 TEST(ExceptionExtensions) {
6262   v8::HandleScope handle_scope(CcTest::isolate());
6263   v8::RegisterExtension(
6264       new Extension("exception", kExceptionInExtensionSource));
6265   const char* extension_names[] = {"exception"};
6266   v8::ExtensionConfiguration extensions(1, extension_names);
6267   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6268   CHECK(context.IsEmpty());
6269 }
6270
6271
6272 static const char* kNativeCallInExtensionSource =
6273     "function call_runtime_last_index_of(x) {"
6274     "  return %StringLastIndexOf(x, 'bob', 10);"
6275     "}";
6276
6277
6278 static const char* kNativeCallTest =
6279     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6280
6281 // Test that a native runtime calls are supported in extensions.
6282 TEST(NativeCallInExtensions) {
6283   v8::HandleScope handle_scope(CcTest::isolate());
6284   v8::RegisterExtension(
6285       new Extension("nativecall", kNativeCallInExtensionSource));
6286   const char* extension_names[] = {"nativecall"};
6287   v8::ExtensionConfiguration extensions(1, extension_names);
6288   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6289   Context::Scope lock(context);
6290   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6291   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 3)));
6292 }
6293
6294
6295 class NativeFunctionExtension : public Extension {
6296  public:
6297   NativeFunctionExtension(const char* name, const char* source,
6298                           v8::FunctionCallback fun = &Echo)
6299       : Extension(name, source), function_(fun) {}
6300
6301   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6302       v8::Isolate* isolate, v8::Handle<v8::String> name) {
6303     return v8::FunctionTemplate::New(isolate, function_);
6304   }
6305
6306   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6307     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6308   }
6309
6310  private:
6311   v8::FunctionCallback function_;
6312 };
6313
6314
6315 TEST(NativeFunctionDeclaration) {
6316   v8::HandleScope handle_scope(CcTest::isolate());
6317   const char* name = "nativedecl";
6318   v8::RegisterExtension(
6319       new NativeFunctionExtension(name, "native function foo();"));
6320   const char* extension_names[] = {name};
6321   v8::ExtensionConfiguration extensions(1, extension_names);
6322   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6323   Context::Scope lock(context);
6324   v8::Handle<Value> result = CompileRun("foo(42);");
6325   CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6326 }
6327
6328
6329 TEST(NativeFunctionDeclarationError) {
6330   v8::HandleScope handle_scope(CcTest::isolate());
6331   const char* name = "nativedeclerr";
6332   // Syntax error in extension code.
6333   v8::RegisterExtension(
6334       new NativeFunctionExtension(name, "native\nfunction foo();"));
6335   const char* extension_names[] = {name};
6336   v8::ExtensionConfiguration extensions(1, extension_names);
6337   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6338   CHECK(context.IsEmpty());
6339 }
6340
6341
6342 TEST(NativeFunctionDeclarationErrorEscape) {
6343   v8::HandleScope handle_scope(CcTest::isolate());
6344   const char* name = "nativedeclerresc";
6345   // Syntax error in extension code - escape code in "native" means that
6346   // it's not treated as a keyword.
6347   v8::RegisterExtension(
6348       new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
6349   const char* extension_names[] = {name};
6350   v8::ExtensionConfiguration extensions(1, extension_names);
6351   v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6352   CHECK(context.IsEmpty());
6353 }
6354
6355
6356 static void CheckDependencies(const char* name, const char* expected) {
6357   v8::HandleScope handle_scope(CcTest::isolate());
6358   v8::ExtensionConfiguration config(1, &name);
6359   LocalContext context(&config);
6360   CHECK(String::NewFromUtf8(CcTest::isolate(), expected)
6361             ->Equals(context->Global()->Get(v8_str("loaded"))));
6362 }
6363
6364
6365 /*
6366  * Configuration:
6367  *
6368  *     /-- B <--\
6369  * A <-          -- D <-- E
6370  *     \-- C <--/
6371  */
6372 THREADED_TEST(ExtensionDependency) {
6373   static const char* kEDeps[] = {"D"};
6374   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6375   static const char* kDDeps[] = {"B", "C"};
6376   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6377   static const char* kBCDeps[] = {"A"};
6378   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6379   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6380   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6381   CheckDependencies("A", "undefinedA");
6382   CheckDependencies("B", "undefinedAB");
6383   CheckDependencies("C", "undefinedAC");
6384   CheckDependencies("D", "undefinedABCD");
6385   CheckDependencies("E", "undefinedABCDE");
6386   v8::HandleScope handle_scope(CcTest::isolate());
6387   static const char* exts[2] = {"C", "E"};
6388   v8::ExtensionConfiguration config(2, exts);
6389   LocalContext context(&config);
6390   CHECK(v8_str("undefinedACBDE")
6391             ->Equals(context->Global()->Get(v8_str("loaded"))));
6392 }
6393
6394
6395 static const char* kExtensionTestScript =
6396     "native function A();"
6397     "native function B();"
6398     "native function C();"
6399     "function Foo(i) {"
6400     "  if (i == 0) return A();"
6401     "  if (i == 1) return B();"
6402     "  if (i == 2) return C();"
6403     "}";
6404
6405
6406 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6407   ApiTestFuzzer::Fuzz();
6408   if (args.IsConstructCall()) {
6409     args.This()->Set(v8_str("data"), args.Data());
6410     args.GetReturnValue().SetNull();
6411     return;
6412   }
6413   args.GetReturnValue().Set(args.Data());
6414 }
6415
6416
6417 class FunctionExtension : public Extension {
6418  public:
6419   FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
6420   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6421       v8::Isolate* isolate, v8::Handle<String> name);
6422 };
6423
6424
6425 static int lookup_count = 0;
6426 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6427     v8::Isolate* isolate, v8::Handle<String> name) {
6428   lookup_count++;
6429   if (name->Equals(v8_str("A"))) {
6430     return v8::FunctionTemplate::New(isolate, CallFun,
6431                                      v8::Integer::New(isolate, 8));
6432   } else if (name->Equals(v8_str("B"))) {
6433     return v8::FunctionTemplate::New(isolate, CallFun,
6434                                      v8::Integer::New(isolate, 7));
6435   } else if (name->Equals(v8_str("C"))) {
6436     return v8::FunctionTemplate::New(isolate, CallFun,
6437                                      v8::Integer::New(isolate, 6));
6438   } else {
6439     return v8::Handle<v8::FunctionTemplate>();
6440   }
6441 }
6442
6443
6444 THREADED_TEST(FunctionLookup) {
6445   v8::RegisterExtension(new FunctionExtension());
6446   v8::HandleScope handle_scope(CcTest::isolate());
6447   static const char* exts[1] = {"functiontest"};
6448   v8::ExtensionConfiguration config(1, exts);
6449   LocalContext context(&config);
6450   CHECK_EQ(3, lookup_count);
6451   CHECK(v8::Integer::New(CcTest::isolate(), 8)->Equals(CompileRun("Foo(0)")));
6452   CHECK(v8::Integer::New(CcTest::isolate(), 7)->Equals(CompileRun("Foo(1)")));
6453   CHECK(v8::Integer::New(CcTest::isolate(), 6)->Equals(CompileRun("Foo(2)")));
6454 }
6455
6456
6457 THREADED_TEST(NativeFunctionConstructCall) {
6458   v8::RegisterExtension(new FunctionExtension());
6459   v8::HandleScope handle_scope(CcTest::isolate());
6460   static const char* exts[1] = {"functiontest"};
6461   v8::ExtensionConfiguration config(1, exts);
6462   LocalContext context(&config);
6463   for (int i = 0; i < 10; i++) {
6464     // Run a few times to ensure that allocation of objects doesn't
6465     // change behavior of a constructor function.
6466     CHECK(v8::Integer::New(CcTest::isolate(), 8)
6467               ->Equals(CompileRun("(new A()).data")));
6468     CHECK(v8::Integer::New(CcTest::isolate(), 7)
6469               ->Equals(CompileRun("(new B()).data")));
6470     CHECK(v8::Integer::New(CcTest::isolate(), 6)
6471               ->Equals(CompileRun("(new C()).data")));
6472   }
6473 }
6474
6475
6476 static const char* last_location;
6477 static const char* last_message;
6478 void StoringErrorCallback(const char* location, const char* message) {
6479   if (last_location == NULL) {
6480     last_location = location;
6481     last_message = message;
6482   }
6483 }
6484
6485
6486 // ErrorReporting creates a circular extensions configuration and
6487 // tests that the fatal error handler gets called.  This renders V8
6488 // unusable and therefore this test cannot be run in parallel.
6489 TEST(ErrorReporting) {
6490   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6491   static const char* aDeps[] = {"B"};
6492   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6493   static const char* bDeps[] = {"A"};
6494   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6495   last_location = NULL;
6496   v8::ExtensionConfiguration config(1, bDeps);
6497   v8::Handle<Context> context = Context::New(CcTest::isolate(), &config);
6498   CHECK(context.IsEmpty());
6499   CHECK(last_location);
6500 }
6501
6502
6503 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6504                                              v8::Handle<Value> data) {
6505   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
6506   CHECK(v8::Undefined(CcTest::isolate())
6507             ->Equals(message->GetScriptOrigin().ResourceName()));
6508   message->GetLineNumber();
6509   message->GetSourceLine();
6510 }
6511
6512
6513 THREADED_TEST(ErrorWithMissingScriptInfo) {
6514   LocalContext context;
6515   v8::HandleScope scope(context->GetIsolate());
6516   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6517   CompileRun("throw Error()");
6518   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6519 }
6520
6521
6522 struct FlagAndPersistent {
6523   bool flag;
6524   v8::Global<v8::Object> handle;
6525 };
6526
6527
6528 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6529   data.GetParameter()->flag = true;
6530   data.GetParameter()->handle.Reset();
6531 }
6532
6533
6534 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
6535   v8::Isolate* iso = CcTest::isolate();
6536   v8::HandleScope scope(iso);
6537   v8::Handle<Context> context = Context::New(iso);
6538   Context::Scope context_scope(context);
6539
6540   FlagAndPersistent object_a, object_b;
6541
6542   intptr_t big_heap_size;
6543
6544   {
6545     v8::HandleScope handle_scope(iso);
6546     Local<Object> a(v8::Object::New(iso));
6547     Local<Object> b(v8::Object::New(iso));
6548     object_a.handle.Reset(iso, a);
6549     object_b.handle.Reset(iso, b);
6550     if (interlinked) {
6551       a->Set(v8_str("x"), b);
6552       b->Set(v8_str("x"), a);
6553     }
6554     if (global_gc) {
6555       CcTest::heap()->CollectAllGarbage();
6556     } else {
6557       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6558     }
6559     // We are relying on this creating a big flag array and reserving the space
6560     // up front.
6561     v8::Handle<Value> big_array = CompileRun("new Array(50000)");
6562     a->Set(v8_str("y"), big_array);
6563     big_heap_size = CcTest::heap()->SizeOfObjects();
6564   }
6565
6566   object_a.flag = false;
6567   object_b.flag = false;
6568   object_a.handle.SetWeak(&object_a, &SetFlag,
6569                           v8::WeakCallbackType::kParameter);
6570   object_b.handle.SetWeak(&object_b, &SetFlag,
6571                           v8::WeakCallbackType::kParameter);
6572   CHECK(!object_b.handle.IsIndependent());
6573   object_a.handle.MarkIndependent();
6574   object_b.handle.MarkIndependent();
6575   CHECK(object_b.handle.IsIndependent());
6576   if (global_gc) {
6577     CcTest::heap()->CollectAllGarbage();
6578   } else {
6579     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6580   }
6581   // A single GC should be enough to reclaim the memory, since we are using
6582   // phantom handles.
6583   CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
6584   CHECK(object_a.flag);
6585   CHECK(object_b.flag);
6586 }
6587
6588
6589 TEST(IndependentWeakHandle) {
6590   IndependentWeakHandle(false, false);
6591   IndependentWeakHandle(false, true);
6592   IndependentWeakHandle(true, false);
6593   IndependentWeakHandle(true, true);
6594 }
6595
6596
6597 class Trivial {
6598  public:
6599   explicit Trivial(int x) : x_(x) {}
6600
6601   int x() { return x_; }
6602   void set_x(int x) { x_ = x; }
6603
6604  private:
6605   int x_;
6606 };
6607
6608
6609 class Trivial2 {
6610  public:
6611   Trivial2(int x, int y) : y_(y), x_(x) {}
6612
6613   int x() { return x_; }
6614   void set_x(int x) { x_ = x; }
6615
6616   int y() { return y_; }
6617   void set_y(int y) { y_ = y; }
6618
6619  private:
6620   int y_;
6621   int x_;
6622 };
6623
6624
6625 void CheckInternalFields(
6626     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
6627   v8::Persistent<v8::Object>* handle = data.GetParameter();
6628   handle->Reset();
6629   Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
6630   Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField2());
6631   CHECK_EQ(42, t1->x());
6632   CHECK_EQ(103, t2->x());
6633   t1->set_x(1729);
6634   t2->set_x(33550336);
6635 }
6636
6637
6638 void InternalFieldCallback(bool global_gc) {
6639   LocalContext env;
6640   v8::Isolate* isolate = env->GetIsolate();
6641   v8::HandleScope scope(isolate);
6642
6643   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
6644   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
6645   Trivial* t1;
6646   Trivial2* t2;
6647   instance_templ->SetInternalFieldCount(2);
6648   {
6649     v8::HandleScope scope(isolate);
6650     Local<v8::Object> obj = templ->GetFunction()->NewInstance();
6651     v8::Persistent<v8::Object> handle(isolate, obj);
6652     CHECK_EQ(2, obj->InternalFieldCount());
6653     CHECK(obj->GetInternalField(0)->IsUndefined());
6654     t1 = new Trivial(42);
6655     t2 = new Trivial2(103, 9);
6656
6657     obj->SetAlignedPointerInInternalField(0, t1);
6658     t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
6659     CHECK_EQ(42, t1->x());
6660
6661     obj->SetAlignedPointerInInternalField(1, t2);
6662     t2 =
6663         reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
6664     CHECK_EQ(103, t2->x());
6665
6666     handle.SetWeak<v8::Persistent<v8::Object>>(
6667         &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
6668     if (!global_gc) {
6669       handle.MarkIndependent();
6670     }
6671   }
6672   if (global_gc) {
6673     CcTest::heap()->CollectAllGarbage();
6674   } else {
6675     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6676   }
6677
6678   CHECK_EQ(1729, t1->x());
6679   CHECK_EQ(33550336, t2->x());
6680
6681   delete t1;
6682   delete t2;
6683 }
6684
6685
6686 THREADED_TEST(InternalFieldCallback) {
6687   InternalFieldCallback(false);
6688   InternalFieldCallback(true);
6689 }
6690
6691
6692 static void ResetUseValueAndSetFlag(
6693     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6694   // Blink will reset the handle, and then use the other handle, so they
6695   // can't use the same backing slot.
6696   data.GetParameter()->handle.Reset();
6697   data.GetParameter()->flag = true;
6698 }
6699
6700
6701 static void ResetWeakHandle(bool global_gc) {
6702   v8::Isolate* iso = CcTest::isolate();
6703   v8::HandleScope scope(iso);
6704   v8::Handle<Context> context = Context::New(iso);
6705   Context::Scope context_scope(context);
6706
6707   FlagAndPersistent object_a, object_b;
6708
6709   {
6710     v8::HandleScope handle_scope(iso);
6711     Local<Object> a(v8::Object::New(iso));
6712     Local<Object> b(v8::Object::New(iso));
6713     object_a.handle.Reset(iso, a);
6714     object_b.handle.Reset(iso, b);
6715     if (global_gc) {
6716       CcTest::heap()->CollectAllGarbage(
6717           TestHeap::Heap::kAbortIncrementalMarkingMask);
6718     } else {
6719       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6720     }
6721   }
6722
6723   object_a.flag = false;
6724   object_b.flag = false;
6725   object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
6726                           v8::WeakCallbackType::kParameter);
6727   object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
6728                           v8::WeakCallbackType::kParameter);
6729   if (!global_gc) {
6730     object_a.handle.MarkIndependent();
6731     object_b.handle.MarkIndependent();
6732     CHECK(object_b.handle.IsIndependent());
6733   }
6734   if (global_gc) {
6735     CcTest::heap()->CollectAllGarbage(
6736         TestHeap::Heap::kAbortIncrementalMarkingMask);
6737   } else {
6738     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6739   }
6740   CHECK(object_a.flag);
6741   CHECK(object_b.flag);
6742 }
6743
6744
6745 THREADED_TEST(ResetWeakHandle) {
6746   ResetWeakHandle(false);
6747   ResetWeakHandle(true);
6748 }
6749
6750
6751 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
6752
6753
6754 static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); }
6755
6756
6757 static void ForceScavenge2(
6758     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6759   data.GetParameter()->flag = true;
6760   InvokeScavenge();
6761 }
6762
6763 static void ForceScavenge1(
6764     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6765   data.GetParameter()->handle.Reset();
6766   data.SetSecondPassCallback(ForceScavenge2);
6767 }
6768
6769
6770 static void ForceMarkSweep2(
6771     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6772   data.GetParameter()->flag = true;
6773   InvokeMarkSweep();
6774 }
6775
6776 static void ForceMarkSweep1(
6777     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6778   data.GetParameter()->handle.Reset();
6779   data.SetSecondPassCallback(ForceMarkSweep2);
6780 }
6781
6782
6783 THREADED_TEST(GCFromWeakCallbacks) {
6784   v8::Isolate* isolate = CcTest::isolate();
6785   v8::HandleScope scope(isolate);
6786   v8::Handle<Context> context = Context::New(isolate);
6787   Context::Scope context_scope(context);
6788
6789   static const int kNumberOfGCTypes = 2;
6790   typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
6791   Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
6792                                                     &ForceMarkSweep1};
6793
6794   typedef void (*GCInvoker)();
6795   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6796
6797   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6798     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6799       FlagAndPersistent object;
6800       {
6801         v8::HandleScope handle_scope(isolate);
6802         object.handle.Reset(isolate, v8::Object::New(isolate));
6803       }
6804       object.flag = false;
6805       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
6806                             v8::WeakCallbackType::kParameter);
6807       object.handle.MarkIndependent();
6808       invoke_gc[outer_gc]();
6809       CHECK(object.flag);
6810     }
6811   }
6812 }
6813
6814
6815 v8::Handle<Function> args_fun;
6816
6817
6818 static void ArgumentsTestCallback(
6819     const v8::FunctionCallbackInfo<v8::Value>& args) {
6820   ApiTestFuzzer::Fuzz();
6821   v8::Isolate* isolate = args.GetIsolate();
6822   CHECK(args_fun->Equals(args.Callee()));
6823   CHECK_EQ(3, args.Length());
6824   CHECK(v8::Integer::New(isolate, 1)->Equals(args[0]));
6825   CHECK(v8::Integer::New(isolate, 2)->Equals(args[1]));
6826   CHECK(v8::Integer::New(isolate, 3)->Equals(args[2]));
6827   CHECK(v8::Undefined(isolate)->Equals(args[3]));
6828   v8::HandleScope scope(args.GetIsolate());
6829   CcTest::heap()->CollectAllGarbage();
6830 }
6831
6832
6833 THREADED_TEST(Arguments) {
6834   v8::Isolate* isolate = CcTest::isolate();
6835   v8::HandleScope scope(isolate);
6836   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
6837   global->Set(v8_str("f"),
6838               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
6839   LocalContext context(NULL, global);
6840   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6841   v8_compile("f(1, 2, 3)")->Run();
6842 }
6843
6844
6845 static int p_getter_count;
6846 static int p_getter_count2;
6847
6848
6849 static void PGetter(Local<String> name,
6850                     const v8::PropertyCallbackInfo<v8::Value>& info) {
6851   ApiTestFuzzer::Fuzz();
6852   p_getter_count++;
6853   v8::Handle<v8::Object> global =
6854       info.GetIsolate()->GetCurrentContext()->Global();
6855   CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6856   if (name->Equals(v8_str("p1"))) {
6857     CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6858   } else if (name->Equals(v8_str("p2"))) {
6859     CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6860   } else if (name->Equals(v8_str("p3"))) {
6861     CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6862   } else if (name->Equals(v8_str("p4"))) {
6863     CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6864   }
6865 }
6866
6867
6868 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6869   ApiTestFuzzer::Fuzz();
6870   LocalContext context;
6871   context->Global()->Set(v8_str("o1"), obj->NewInstance());
6872   CompileRun(
6873     "o1.__proto__ = { };"
6874     "var o2 = { __proto__: o1 };"
6875     "var o3 = { __proto__: o2 };"
6876     "var o4 = { __proto__: o3 };"
6877     "for (var i = 0; i < 10; i++) o4.p4;"
6878     "for (var i = 0; i < 10; i++) o3.p3;"
6879     "for (var i = 0; i < 10; i++) o2.p2;"
6880     "for (var i = 0; i < 10; i++) o1.p1;");
6881 }
6882
6883
6884 static void PGetter2(Local<Name> name,
6885                      const v8::PropertyCallbackInfo<v8::Value>& info) {
6886   ApiTestFuzzer::Fuzz();
6887   p_getter_count2++;
6888   v8::Handle<v8::Object> global =
6889       info.GetIsolate()->GetCurrentContext()->Global();
6890   CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6891   if (name->Equals(v8_str("p1"))) {
6892     CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6893   } else if (name->Equals(v8_str("p2"))) {
6894     CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6895   } else if (name->Equals(v8_str("p3"))) {
6896     CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6897   } else if (name->Equals(v8_str("p4"))) {
6898     CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6899   }
6900 }
6901
6902
6903 THREADED_TEST(GetterHolders) {
6904   v8::Isolate* isolate = CcTest::isolate();
6905   v8::HandleScope scope(isolate);
6906   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6907   obj->SetAccessor(v8_str("p1"), PGetter);
6908   obj->SetAccessor(v8_str("p2"), PGetter);
6909   obj->SetAccessor(v8_str("p3"), PGetter);
6910   obj->SetAccessor(v8_str("p4"), PGetter);
6911   p_getter_count = 0;
6912   RunHolderTest(obj);
6913   CHECK_EQ(40, p_getter_count);
6914 }
6915
6916
6917 THREADED_TEST(PreInterceptorHolders) {
6918   v8::Isolate* isolate = CcTest::isolate();
6919   v8::HandleScope scope(isolate);
6920   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6921   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
6922   p_getter_count2 = 0;
6923   RunHolderTest(obj);
6924   CHECK_EQ(40, p_getter_count2);
6925 }
6926
6927
6928 THREADED_TEST(ObjectInstantiation) {
6929   v8::Isolate* isolate = CcTest::isolate();
6930   v8::HandleScope scope(isolate);
6931   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
6932   templ->SetAccessor(v8_str("t"), PGetter2);
6933   LocalContext context;
6934   context->Global()->Set(v8_str("o"), templ->NewInstance());
6935   for (int i = 0; i < 100; i++) {
6936     v8::HandleScope inner_scope(CcTest::isolate());
6937     v8::Handle<v8::Object> obj = templ->NewInstance();
6938     CHECK(!obj->Equals(context->Global()->Get(v8_str("o"))));
6939     context->Global()->Set(v8_str("o2"), obj);
6940     v8::Handle<Value> value =
6941         CompileRun("o.__proto__ === o2.__proto__");
6942     CHECK(v8::True(isolate)->Equals(value));
6943     context->Global()->Set(v8_str("o"), obj);
6944   }
6945 }
6946
6947
6948 static int StrCmp16(uint16_t* a, uint16_t* b) {
6949   while (true) {
6950     if (*a == 0 && *b == 0) return 0;
6951     if (*a != *b) return 0 + *a - *b;
6952     a++;
6953     b++;
6954   }
6955 }
6956
6957
6958 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6959   while (true) {
6960     if (n-- == 0) return 0;
6961     if (*a == 0 && *b == 0) return 0;
6962     if (*a != *b) return 0 + *a - *b;
6963     a++;
6964     b++;
6965   }
6966 }
6967
6968
6969 int GetUtf8Length(Handle<String> str) {
6970   int len = str->Utf8Length();
6971   if (len < 0) {
6972     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6973     i::String::Flatten(istr);
6974     len = str->Utf8Length();
6975   }
6976   return len;
6977 }
6978
6979
6980 THREADED_TEST(StringWrite) {
6981   LocalContext context;
6982   v8::HandleScope scope(context->GetIsolate());
6983   v8::Handle<String> str = v8_str("abcde");
6984   // abc<Icelandic eth><Unicode snowman>.
6985   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6986   v8::Handle<String> str3 = v8::String::NewFromUtf8(
6987       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
6988   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
6989   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
6990   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
6991       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
6992   // single lead surrogate
6993   uint16_t lead[1] = { 0xd800 };
6994   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
6995       context->GetIsolate(), lead, v8::String::kNormalString, 1);
6996   // single trail surrogate
6997   uint16_t trail[1] = { 0xdc00 };
6998   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
6999       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7000   // surrogate pair
7001   uint16_t pair[2] = { 0xd800,  0xdc00 };
7002   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7003       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7004   const int kStride = 4;  // Must match stride in for loops in JS below.
7005   CompileRun(
7006       "var left = '';"
7007       "for (var i = 0; i < 0xd800; i += 4) {"
7008       "  left = left + String.fromCharCode(i);"
7009       "}");
7010   CompileRun(
7011       "var right = '';"
7012       "for (var i = 0; i < 0xd800; i += 4) {"
7013       "  right = String.fromCharCode(i) + right;"
7014       "}");
7015   v8::Handle<v8::Object> global = context->Global();
7016   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7017   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7018
7019   CHECK_EQ(5, str2->Length());
7020   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7021   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7022
7023   char buf[100];
7024   char utf8buf[0xd800 * 3];
7025   uint16_t wbuf[100];
7026   int len;
7027   int charlen;
7028
7029   memset(utf8buf, 0x1, 1000);
7030   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7031   CHECK_EQ(9, len);
7032   CHECK_EQ(5, charlen);
7033   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7034
7035   memset(utf8buf, 0x1, 1000);
7036   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7037   CHECK_EQ(8, len);
7038   CHECK_EQ(5, charlen);
7039   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7040
7041   memset(utf8buf, 0x1, 1000);
7042   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7043   CHECK_EQ(5, len);
7044   CHECK_EQ(4, charlen);
7045   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7046
7047   memset(utf8buf, 0x1, 1000);
7048   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7049   CHECK_EQ(5, len);
7050   CHECK_EQ(4, charlen);
7051   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7052
7053   memset(utf8buf, 0x1, 1000);
7054   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7055   CHECK_EQ(5, len);
7056   CHECK_EQ(4, charlen);
7057   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7058
7059   memset(utf8buf, 0x1, 1000);
7060   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7061   CHECK_EQ(3, len);
7062   CHECK_EQ(3, charlen);
7063   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7064
7065   memset(utf8buf, 0x1, 1000);
7066   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7067   CHECK_EQ(3, len);
7068   CHECK_EQ(3, charlen);
7069   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7070
7071   memset(utf8buf, 0x1, 1000);
7072   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7073   CHECK_EQ(2, len);
7074   CHECK_EQ(2, charlen);
7075   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7076
7077   // allow orphan surrogates by default
7078   memset(utf8buf, 0x1, 1000);
7079   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7080   CHECK_EQ(13, len);
7081   CHECK_EQ(8, charlen);
7082   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7083
7084   // replace orphan surrogates with unicode replacement character
7085   memset(utf8buf, 0x1, 1000);
7086   len = orphans_str->WriteUtf8(utf8buf,
7087                                sizeof(utf8buf),
7088                                &charlen,
7089                                String::REPLACE_INVALID_UTF8);
7090   CHECK_EQ(13, len);
7091   CHECK_EQ(8, charlen);
7092   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7093
7094   // replace single lead surrogate with unicode replacement character
7095   memset(utf8buf, 0x1, 1000);
7096   len = lead_str->WriteUtf8(utf8buf,
7097                             sizeof(utf8buf),
7098                             &charlen,
7099                             String::REPLACE_INVALID_UTF8);
7100   CHECK_EQ(4, len);
7101   CHECK_EQ(1, charlen);
7102   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7103
7104   // replace single trail surrogate with unicode replacement character
7105   memset(utf8buf, 0x1, 1000);
7106   len = trail_str->WriteUtf8(utf8buf,
7107                              sizeof(utf8buf),
7108                              &charlen,
7109                              String::REPLACE_INVALID_UTF8);
7110   CHECK_EQ(4, len);
7111   CHECK_EQ(1, charlen);
7112   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7113
7114   // do not replace / write anything if surrogate pair does not fit the buffer
7115   // space
7116   memset(utf8buf, 0x1, 1000);
7117   len = pair_str->WriteUtf8(utf8buf,
7118                              3,
7119                              &charlen,
7120                              String::REPLACE_INVALID_UTF8);
7121   CHECK_EQ(0, len);
7122   CHECK_EQ(0, charlen);
7123
7124   memset(utf8buf, 0x1, sizeof(utf8buf));
7125   len = GetUtf8Length(left_tree);
7126   int utf8_expected =
7127       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7128   CHECK_EQ(utf8_expected, len);
7129   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7130   CHECK_EQ(utf8_expected, len);
7131   CHECK_EQ(0xd800 / kStride, charlen);
7132   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7133   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7134   CHECK_EQ(0xc0 - kStride,
7135            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7136   CHECK_EQ(1, utf8buf[utf8_expected]);
7137
7138   memset(utf8buf, 0x1, sizeof(utf8buf));
7139   len = GetUtf8Length(right_tree);
7140   CHECK_EQ(utf8_expected, len);
7141   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7142   CHECK_EQ(utf8_expected, len);
7143   CHECK_EQ(0xd800 / kStride, charlen);
7144   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7145   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7146   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7147   CHECK_EQ(1, utf8buf[utf8_expected]);
7148
7149   memset(buf, 0x1, sizeof(buf));
7150   memset(wbuf, 0x1, sizeof(wbuf));
7151   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7152   CHECK_EQ(5, len);
7153   len = str->Write(wbuf);
7154   CHECK_EQ(5, len);
7155   CHECK_EQ(0, strcmp("abcde", buf));
7156   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7157   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7158
7159   memset(buf, 0x1, sizeof(buf));
7160   memset(wbuf, 0x1, sizeof(wbuf));
7161   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7162   CHECK_EQ(4, len);
7163   len = str->Write(wbuf, 0, 4);
7164   CHECK_EQ(4, len);
7165   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7166   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7167   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7168
7169   memset(buf, 0x1, sizeof(buf));
7170   memset(wbuf, 0x1, sizeof(wbuf));
7171   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7172   CHECK_EQ(5, len);
7173   len = str->Write(wbuf, 0, 5);
7174   CHECK_EQ(5, len);
7175   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7176   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7177   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7178
7179   memset(buf, 0x1, sizeof(buf));
7180   memset(wbuf, 0x1, sizeof(wbuf));
7181   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7182   CHECK_EQ(5, len);
7183   len = str->Write(wbuf, 0, 6);
7184   CHECK_EQ(5, len);
7185   CHECK_EQ(0, strcmp("abcde", buf));
7186   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7187   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7188
7189   memset(buf, 0x1, sizeof(buf));
7190   memset(wbuf, 0x1, sizeof(wbuf));
7191   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7192   CHECK_EQ(1, len);
7193   len = str->Write(wbuf, 4, -1);
7194   CHECK_EQ(1, len);
7195   CHECK_EQ(0, strcmp("e", buf));
7196   uint16_t answer5[] = {'e', '\0'};
7197   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7198
7199   memset(buf, 0x1, sizeof(buf));
7200   memset(wbuf, 0x1, sizeof(wbuf));
7201   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7202   CHECK_EQ(1, len);
7203   len = str->Write(wbuf, 4, 6);
7204   CHECK_EQ(1, len);
7205   CHECK_EQ(0, strcmp("e", buf));
7206   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7207
7208   memset(buf, 0x1, sizeof(buf));
7209   memset(wbuf, 0x1, sizeof(wbuf));
7210   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7211   CHECK_EQ(1, len);
7212   len = str->Write(wbuf, 4, 1);
7213   CHECK_EQ(1, len);
7214   CHECK_EQ(0, strncmp("e\1", buf, 2));
7215   uint16_t answer6[] = {'e', 0x101};
7216   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7217
7218   memset(buf, 0x1, sizeof(buf));
7219   memset(wbuf, 0x1, sizeof(wbuf));
7220   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7221   CHECK_EQ(1, len);
7222   len = str->Write(wbuf, 3, 1);
7223   CHECK_EQ(1, len);
7224   CHECK_EQ(0, strncmp("d\1", buf, 2));
7225   uint16_t answer7[] = {'d', 0x101};
7226   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7227
7228   memset(wbuf, 0x1, sizeof(wbuf));
7229   wbuf[5] = 'X';
7230   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7231   CHECK_EQ(5, len);
7232   CHECK_EQ('X', wbuf[5]);
7233   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7234   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7235   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7236   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7237   wbuf[5] = '\0';
7238   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7239
7240   memset(buf, 0x1, sizeof(buf));
7241   buf[5] = 'X';
7242   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7243                           0,
7244                           6,
7245                           String::NO_NULL_TERMINATION);
7246   CHECK_EQ(5, len);
7247   CHECK_EQ('X', buf[5]);
7248   CHECK_EQ(0, strncmp("abcde", buf, 5));
7249   CHECK_NE(0, strcmp("abcde", buf));
7250   buf[5] = '\0';
7251   CHECK_EQ(0, strcmp("abcde", buf));
7252
7253   memset(utf8buf, 0x1, sizeof(utf8buf));
7254   utf8buf[8] = 'X';
7255   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7256                         String::NO_NULL_TERMINATION);
7257   CHECK_EQ(8, len);
7258   CHECK_EQ('X', utf8buf[8]);
7259   CHECK_EQ(5, charlen);
7260   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7261   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7262   utf8buf[8] = '\0';
7263   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7264
7265   memset(utf8buf, 0x1, sizeof(utf8buf));
7266   utf8buf[5] = 'X';
7267   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7268                         String::NO_NULL_TERMINATION);
7269   CHECK_EQ(5, len);
7270   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7271   CHECK_EQ(5, charlen);
7272   utf8buf[5] = '\0';
7273   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7274
7275   memset(buf, 0x1, sizeof(buf));
7276   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7277   CHECK_EQ(7, len);
7278   CHECK_EQ(0, strcmp("abc", buf));
7279   CHECK_EQ(0, buf[3]);
7280   CHECK_EQ(0, strcmp("def", buf + 4));
7281
7282   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7283   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7284   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7285 }
7286
7287
7288 static void Utf16Helper(
7289     LocalContext& context,  // NOLINT
7290     const char* name,
7291     const char* lengths_name,
7292     int len) {
7293   Local<v8::Array> a =
7294       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7295   Local<v8::Array> alens =
7296       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7297   for (int i = 0; i < len; i++) {
7298     Local<v8::String> string =
7299       Local<v8::String>::Cast(a->Get(i));
7300     Local<v8::Number> expected_len =
7301       Local<v8::Number>::Cast(alens->Get(i));
7302     int length = GetUtf8Length(string);
7303     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7304   }
7305 }
7306
7307
7308 THREADED_TEST(Utf16) {
7309   LocalContext context;
7310   v8::HandleScope scope(context->GetIsolate());
7311   CompileRun(
7312       "var pad = '01234567890123456789';"
7313       "var p = [];"
7314       "var plens = [20, 3, 3];"
7315       "p.push('01234567890123456789');"
7316       "var lead = 0xd800;"
7317       "var trail = 0xdc00;"
7318       "p.push(String.fromCharCode(0xd800));"
7319       "p.push(String.fromCharCode(0xdc00));"
7320       "var a = [];"
7321       "var b = [];"
7322       "var c = [];"
7323       "var alens = [];"
7324       "for (var i = 0; i < 3; i++) {"
7325       "  p[1] = String.fromCharCode(lead++);"
7326       "  for (var j = 0; j < 3; j++) {"
7327       "    p[2] = String.fromCharCode(trail++);"
7328       "    a.push(p[i] + p[j]);"
7329       "    b.push(p[i] + p[j]);"
7330       "    c.push(p[i] + p[j]);"
7331       "    alens.push(plens[i] + plens[j]);"
7332       "  }"
7333       "}"
7334       "alens[5] -= 2;"  // Here the surrogate pairs match up.
7335       "var a2 = [];"
7336       "var b2 = [];"
7337       "var c2 = [];"
7338       "var a2lens = [];"
7339       "for (var m = 0; m < 9; m++) {"
7340       "  for (var n = 0; n < 9; n++) {"
7341       "    a2.push(a[m] + a[n]);"
7342       "    b2.push(b[m] + b[n]);"
7343       "    var newc = 'x' + c[m] + c[n] + 'y';"
7344       "    c2.push(newc.substring(1, newc.length - 1));"
7345       "    var utf = alens[m] + alens[n];"  // And here.
7346            // The 'n's that start with 0xdc.. are 6-8
7347            // The 'm's that end with 0xd8.. are 1, 4 and 7
7348       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
7349       "    a2lens.push(utf);"
7350       "  }"
7351       "}");
7352   Utf16Helper(context, "a", "alens", 9);
7353   Utf16Helper(context, "a2", "a2lens", 81);
7354 }
7355
7356
7357 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7358   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7359   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7360   return *is1 == *is2;
7361 }
7362
7363
7364 THREADED_TEST(Utf16Symbol) {
7365   LocalContext context;
7366   v8::HandleScope scope(context->GetIsolate());
7367
7368   Handle<String> symbol1 = v8::String::NewFromUtf8(
7369       context->GetIsolate(), "abc", v8::String::kInternalizedString);
7370   Handle<String> symbol2 = v8::String::NewFromUtf8(
7371       context->GetIsolate(), "abc", v8::String::kInternalizedString);
7372   CHECK(SameSymbol(symbol1, symbol2));
7373
7374   CompileRun(
7375       "var sym0 = 'benedictus';"
7376       "var sym0b = 'S\303\270ren';"
7377       "var sym1 = '\355\240\201\355\260\207';"
7378       "var sym2 = '\360\220\220\210';"
7379       "var sym3 = 'x\355\240\201\355\260\207';"
7380       "var sym4 = 'x\360\220\220\210';"
7381       "if (sym1.length != 2) throw sym1;"
7382       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7383       "if (sym2.length != 2) throw sym2;"
7384       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7385       "if (sym3.length != 3) throw sym3;"
7386       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7387       "if (sym4.length != 3) throw sym4;"
7388       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7389   Handle<String> sym0 = v8::String::NewFromUtf8(
7390       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
7391   Handle<String> sym0b = v8::String::NewFromUtf8(
7392       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
7393   Handle<String> sym1 =
7394       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
7395                               v8::String::kInternalizedString);
7396   Handle<String> sym2 =
7397       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
7398                               v8::String::kInternalizedString);
7399   Handle<String> sym3 = v8::String::NewFromUtf8(
7400       context->GetIsolate(), "x\355\240\201\355\260\207",
7401       v8::String::kInternalizedString);
7402   Handle<String> sym4 =
7403       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
7404                               v8::String::kInternalizedString);
7405   v8::Local<v8::Object> global = context->Global();
7406   Local<Value> s0 = global->Get(v8_str("sym0"));
7407   Local<Value> s0b = global->Get(v8_str("sym0b"));
7408   Local<Value> s1 = global->Get(v8_str("sym1"));
7409   Local<Value> s2 = global->Get(v8_str("sym2"));
7410   Local<Value> s3 = global->Get(v8_str("sym3"));
7411   Local<Value> s4 = global->Get(v8_str("sym4"));
7412   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7413   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7414   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7415   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7416   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7417   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7418 }
7419
7420
7421 THREADED_TEST(Utf16MissingTrailing) {
7422   LocalContext context;
7423   v8::HandleScope scope(context->GetIsolate());
7424
7425   // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
7426   int size = 1024 * 64;
7427   uint8_t* buffer = new uint8_t[size];
7428   for (int i = 0; i < size; i += 4) {
7429     buffer[i] = 0xf0;
7430     buffer[i + 1] = 0x9d;
7431     buffer[i + 2] = 0x80;
7432     buffer[i + 3] = 0x9e;
7433   }
7434
7435   // Now invoke the decoder without last 3 bytes
7436   v8::Local<v8::String> str =
7437       v8::String::NewFromUtf8(
7438           context->GetIsolate(), reinterpret_cast<char*>(buffer),
7439           v8::NewStringType::kNormal, size - 3).ToLocalChecked();
7440   USE(str);
7441   delete[] buffer;
7442 }
7443
7444
7445 THREADED_TEST(Utf16Trailing3Byte) {
7446   LocalContext context;
7447   v8::HandleScope scope(context->GetIsolate());
7448
7449   // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
7450   int size = 1024 * 63;
7451   uint8_t* buffer = new uint8_t[size];
7452   for (int i = 0; i < size; i += 3) {
7453     buffer[i] = 0xe2;
7454     buffer[i + 1] = 0x80;
7455     buffer[i + 2] = 0xa6;
7456   }
7457
7458   // Now invoke the decoder without last 3 bytes
7459   v8::Local<v8::String> str =
7460       v8::String::NewFromUtf8(
7461           context->GetIsolate(), reinterpret_cast<char*>(buffer),
7462           v8::NewStringType::kNormal, size).ToLocalChecked();
7463
7464   v8::String::Value value(str);
7465   CHECK_EQ(value.length(), size / 3);
7466   CHECK_EQ((*value)[value.length() - 1], 0x2026);
7467
7468   delete[] buffer;
7469 }
7470
7471
7472 THREADED_TEST(ToArrayIndex) {
7473   LocalContext context;
7474   v8::Isolate* isolate = context->GetIsolate();
7475   v8::HandleScope scope(isolate);
7476
7477   v8::Handle<String> str = v8_str("42");
7478   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7479   CHECK(!index.IsEmpty());
7480   CHECK_EQ(42.0, index->Uint32Value());
7481   str = v8_str("42asdf");
7482   index = str->ToArrayIndex();
7483   CHECK(index.IsEmpty());
7484   str = v8_str("-42");
7485   index = str->ToArrayIndex();
7486   CHECK(index.IsEmpty());
7487   str = v8_str("4294967294");
7488   index = str->ToArrayIndex();
7489   CHECK(!index.IsEmpty());
7490   CHECK_EQ(4294967294.0, index->Uint32Value());
7491   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
7492   index = num->ToArrayIndex();
7493   CHECK(!index.IsEmpty());
7494   CHECK_EQ(1.0, index->Uint32Value());
7495   num = v8::Number::New(isolate, -1);
7496   index = num->ToArrayIndex();
7497   CHECK(index.IsEmpty());
7498   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
7499   index = obj->ToArrayIndex();
7500   CHECK(index.IsEmpty());
7501 }
7502
7503
7504 THREADED_TEST(ErrorConstruction) {
7505   LocalContext context;
7506   v8::HandleScope scope(context->GetIsolate());
7507
7508   v8::Handle<String> foo = v8_str("foo");
7509   v8::Handle<String> message = v8_str("message");
7510   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7511   CHECK(range_error->IsObject());
7512   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7513   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7514   CHECK(reference_error->IsObject());
7515   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7516   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7517   CHECK(syntax_error->IsObject());
7518   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7519   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7520   CHECK(type_error->IsObject());
7521   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7522   v8::Handle<Value> error = v8::Exception::Error(foo);
7523   CHECK(error->IsObject());
7524   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7525 }
7526
7527
7528 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
7529   ApiTestFuzzer::Fuzz();
7530   v8::Handle<String> foo = v8_str("foo");
7531   v8::Handle<String> message = v8_str("message");
7532   v8::Handle<Value> error = v8::Exception::Error(foo);
7533   CHECK(error->IsObject());
7534   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7535   info.GetIsolate()->ThrowException(error);
7536   info.GetReturnValue().SetUndefined();
7537 }
7538
7539
7540 THREADED_TEST(ExceptionCreateMessage) {
7541   LocalContext context;
7542   v8::HandleScope scope(context->GetIsolate());
7543   v8::Handle<String> foo_str = v8_str("foo");
7544   v8::Handle<String> message_str = v8_str("message");
7545
7546   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
7547
7548   Local<v8::FunctionTemplate> fun =
7549       v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
7550   v8::Local<v8::Object> global = context->Global();
7551   global->Set(v8_str("throwV8Exception"), fun->GetFunction());
7552
7553   TryCatch try_catch(context->GetIsolate());
7554   CompileRun(
7555       "function f1() {\n"
7556       "  throwV8Exception();\n"
7557       "};\n"
7558       "f1();");
7559   CHECK(try_catch.HasCaught());
7560
7561   v8::Handle<v8::Value> error = try_catch.Exception();
7562   CHECK(error->IsObject());
7563   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7564
7565   v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
7566   CHECK(!message.IsEmpty());
7567   CHECK_EQ(2, message->GetLineNumber());
7568   CHECK_EQ(2, message->GetStartColumn());
7569
7570   v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
7571   CHECK(!stackTrace.IsEmpty());
7572   CHECK_EQ(2, stackTrace->GetFrameCount());
7573
7574   stackTrace = v8::Exception::GetStackTrace(error);
7575   CHECK(!stackTrace.IsEmpty());
7576   CHECK_EQ(2, stackTrace->GetFrameCount());
7577
7578   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
7579
7580   // Now check message location when SetCaptureStackTraceForUncaughtExceptions
7581   // is false.
7582   try_catch.Reset();
7583
7584   CompileRun(
7585       "function f2() {\n"
7586       "  return throwV8Exception();\n"
7587       "};\n"
7588       "f2();");
7589   CHECK(try_catch.HasCaught());
7590
7591   error = try_catch.Exception();
7592   CHECK(error->IsObject());
7593   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7594
7595   message = v8::Exception::CreateMessage(error);
7596   CHECK(!message.IsEmpty());
7597   CHECK_EQ(2, message->GetLineNumber());
7598   CHECK_EQ(9, message->GetStartColumn());
7599
7600   // Should be empty stack trace.
7601   stackTrace = message->GetStackTrace();
7602   CHECK(stackTrace.IsEmpty());
7603   CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
7604 }
7605
7606
7607 THREADED_TEST(ExceptionCreateMessageLength) {
7608   LocalContext context;
7609   v8::HandleScope scope(context->GetIsolate());
7610
7611   // Test that the message is not truncated.
7612   TryCatch try_catch(context->GetIsolate());
7613   CompileRun(
7614       "var message = 'm';"
7615       "while (message.length < 1000) message += message;"
7616       "throw message;");
7617   CHECK(try_catch.HasCaught());
7618
7619   CHECK_LT(1000, try_catch.Message()->Get()->Length());
7620 }
7621
7622
7623 static void YGetter(Local<String> name,
7624                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7625   ApiTestFuzzer::Fuzz();
7626   info.GetReturnValue().Set(v8_num(10));
7627 }
7628
7629
7630 static void YSetter(Local<String> name,
7631                     Local<Value> value,
7632                     const v8::PropertyCallbackInfo<void>& info) {
7633   Local<Object> this_obj = Local<Object>::Cast(info.This());
7634   if (this_obj->Has(name)) this_obj->Delete(name);
7635   this_obj->Set(name, value);
7636 }
7637
7638
7639 THREADED_TEST(DeleteAccessor) {
7640   v8::Isolate* isolate = CcTest::isolate();
7641   v8::HandleScope scope(isolate);
7642   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7643   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7644   LocalContext context;
7645   v8::Handle<v8::Object> holder = obj->NewInstance();
7646   context->Global()->Set(v8_str("holder"), holder);
7647   v8::Handle<Value> result = CompileRun(
7648       "holder.y = 11; holder.y = 12; holder.y");
7649   CHECK_EQ(12u, result->Uint32Value());
7650 }
7651
7652
7653 THREADED_TEST(TypeSwitch) {
7654   v8::Isolate* isolate = CcTest::isolate();
7655   v8::HandleScope scope(isolate);
7656   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
7657   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
7658   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
7659   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7660   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7661   LocalContext context;
7662   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
7663   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7664   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7665   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7666   for (int i = 0; i < 10; i++) {
7667     CHECK_EQ(0, type_switch->match(obj0));
7668     CHECK_EQ(1, type_switch->match(obj1));
7669     CHECK_EQ(2, type_switch->match(obj2));
7670     CHECK_EQ(3, type_switch->match(obj3));
7671     CHECK_EQ(3, type_switch->match(obj3));
7672     CHECK_EQ(2, type_switch->match(obj2));
7673     CHECK_EQ(1, type_switch->match(obj1));
7674     CHECK_EQ(0, type_switch->match(obj0));
7675   }
7676 }
7677
7678
7679 static int trouble_nesting = 0;
7680 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7681   ApiTestFuzzer::Fuzz();
7682   trouble_nesting++;
7683
7684   // Call a JS function that throws an uncaught exception.
7685   Local<v8::Object> arg_this =
7686       args.GetIsolate()->GetCurrentContext()->Global();
7687   Local<Value> trouble_callee = (trouble_nesting == 3) ?
7688     arg_this->Get(v8_str("trouble_callee")) :
7689     arg_this->Get(v8_str("trouble_caller"));
7690   CHECK(trouble_callee->IsFunction());
7691   args.GetReturnValue().Set(
7692       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7693 }
7694
7695
7696 static int report_count = 0;
7697 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7698                                              v8::Handle<Value>) {
7699   report_count++;
7700 }
7701
7702
7703 // Counts uncaught exceptions, but other tests running in parallel
7704 // also have uncaught exceptions.
7705 TEST(ApiUncaughtException) {
7706   report_count = 0;
7707   LocalContext env;
7708   v8::Isolate* isolate = env->GetIsolate();
7709   v8::HandleScope scope(isolate);
7710   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7711
7712   Local<v8::FunctionTemplate> fun =
7713       v8::FunctionTemplate::New(isolate, TroubleCallback);
7714   v8::Local<v8::Object> global = env->Global();
7715   global->Set(v8_str("trouble"), fun->GetFunction());
7716
7717   CompileRun(
7718       "function trouble_callee() {"
7719       "  var x = null;"
7720       "  return x.foo;"
7721       "};"
7722       "function trouble_caller() {"
7723       "  trouble();"
7724       "};");
7725   Local<Value> trouble = global->Get(v8_str("trouble"));
7726   CHECK(trouble->IsFunction());
7727   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7728   CHECK(trouble_callee->IsFunction());
7729   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7730   CHECK(trouble_caller->IsFunction());
7731   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7732   CHECK_EQ(1, report_count);
7733   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7734 }
7735
7736
7737 TEST(ApiUncaughtExceptionInObjectObserve) {
7738   v8::internal::FLAG_stack_size = 150;
7739   report_count = 0;
7740   LocalContext env;
7741   v8::Isolate* isolate = env->GetIsolate();
7742   v8::HandleScope scope(isolate);
7743   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7744   CompileRun(
7745       "var obj = {};"
7746       "var observe_count = 0;"
7747       "function observer1() { ++observe_count; };"
7748       "function observer2() { ++observe_count; };"
7749       "function observer_throws() { throw new Error(); };"
7750       "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
7751       "Object.observe(obj, observer_throws.bind());"
7752       "Object.observe(obj, observer1);"
7753       "Object.observe(obj, stack_overflow);"
7754       "Object.observe(obj, observer2);"
7755       "Object.observe(obj, observer_throws.bind());"
7756       "obj.foo = 'bar';");
7757   CHECK_EQ(3, report_count);
7758   ExpectInt32("observe_count", 2);
7759   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7760 }
7761
7762
7763 static const char* script_resource_name = "ExceptionInNativeScript.js";
7764 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7765                                                 v8::Handle<Value>) {
7766   v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
7767   CHECK(!name_val.IsEmpty() && name_val->IsString());
7768   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
7769   CHECK_EQ(0, strcmp(script_resource_name, *name));
7770   CHECK_EQ(3, message->GetLineNumber());
7771   v8::String::Utf8Value source_line(message->GetSourceLine());
7772   CHECK_EQ(0, strcmp("  new o.foo();", *source_line));
7773 }
7774
7775
7776 TEST(ExceptionInNativeScript) {
7777   LocalContext env;
7778   v8::Isolate* isolate = env->GetIsolate();
7779   v8::HandleScope scope(isolate);
7780   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7781
7782   Local<v8::FunctionTemplate> fun =
7783       v8::FunctionTemplate::New(isolate, TroubleCallback);
7784   v8::Local<v8::Object> global = env->Global();
7785   global->Set(v8_str("trouble"), fun->GetFunction());
7786
7787   CompileRunWithOrigin(
7788       "function trouble() {\n"
7789       "  var o = {};\n"
7790       "  new o.foo();\n"
7791       "};",
7792       script_resource_name);
7793   Local<Value> trouble = global->Get(v8_str("trouble"));
7794   CHECK(trouble->IsFunction());
7795   Function::Cast(*trouble)->Call(global, 0, NULL);
7796   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7797 }
7798
7799
7800 TEST(CompilationErrorUsingTryCatchHandler) {
7801   LocalContext env;
7802   v8::HandleScope scope(env->GetIsolate());
7803   v8::TryCatch try_catch(env->GetIsolate());
7804   v8_compile("This doesn't &*&@#$&*^ compile.");
7805   CHECK(*try_catch.Exception());
7806   CHECK(try_catch.HasCaught());
7807 }
7808
7809
7810 TEST(TryCatchFinallyUsingTryCatchHandler) {
7811   LocalContext env;
7812   v8::HandleScope scope(env->GetIsolate());
7813   v8::TryCatch try_catch(env->GetIsolate());
7814   CompileRun("try { throw ''; } catch (e) {}");
7815   CHECK(!try_catch.HasCaught());
7816   CompileRun("try { throw ''; } finally {}");
7817   CHECK(try_catch.HasCaught());
7818   try_catch.Reset();
7819   CompileRun(
7820       "(function() {"
7821       "try { throw ''; } finally { return; }"
7822       "})()");
7823   CHECK(!try_catch.HasCaught());
7824   CompileRun(
7825       "(function()"
7826       "  { try { throw ''; } finally { throw 0; }"
7827       "})()");
7828   CHECK(try_catch.HasCaught());
7829 }
7830
7831
7832 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
7833   v8::HandleScope scope(args.GetIsolate());
7834   CompileRun(args[0]->ToString(args.GetIsolate()));
7835 }
7836
7837
7838 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
7839   v8::Isolate* isolate = CcTest::isolate();
7840   v8::HandleScope scope(isolate);
7841   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7842   templ->Set(v8_str("CEvaluate"),
7843              v8::FunctionTemplate::New(isolate, CEvaluate));
7844   LocalContext context(0, templ);
7845   v8::TryCatch try_catch(isolate);
7846   CompileRun("try {"
7847              "  CEvaluate('throw 1;');"
7848              "} finally {"
7849              "}");
7850   CHECK(try_catch.HasCaught());
7851   CHECK(!try_catch.Message().IsEmpty());
7852   String::Utf8Value exception_value(try_catch.Exception());
7853   CHECK_EQ(0, strcmp(*exception_value, "1"));
7854   try_catch.Reset();
7855   CompileRun("try {"
7856              "  CEvaluate('throw 1;');"
7857              "} finally {"
7858              "  throw 2;"
7859              "}");
7860   CHECK(try_catch.HasCaught());
7861   CHECK(!try_catch.Message().IsEmpty());
7862   String::Utf8Value finally_exception_value(try_catch.Exception());
7863   CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
7864 }
7865
7866
7867 // For use within the TestSecurityHandler() test.
7868 static bool g_security_callback_result = false;
7869 static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
7870                                  v8::AccessType type, Local<Value> data) {
7871   printf("a\n");
7872   return g_security_callback_result;
7873 }
7874
7875
7876 // SecurityHandler can't be run twice
7877 TEST(SecurityHandler) {
7878   v8::Isolate* isolate = CcTest::isolate();
7879   v8::HandleScope scope0(isolate);
7880   v8::Handle<v8::ObjectTemplate> global_template =
7881       v8::ObjectTemplate::New(isolate);
7882   global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL);
7883   // Create an environment
7884   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
7885   context0->Enter();
7886
7887   v8::Handle<v8::Object> global0 = context0->Global();
7888   v8::Handle<Script> script0 = v8_compile("foo = 111");
7889   script0->Run();
7890   global0->Set(v8_str("0"), v8_num(999));
7891   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7892   CHECK_EQ(111, foo0->Int32Value());
7893   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7894   CHECK_EQ(999, z0->Int32Value());
7895
7896   // Create another environment, should fail security checks.
7897   v8::HandleScope scope1(isolate);
7898
7899   v8::Handle<Context> context1 =
7900     Context::New(isolate, NULL, global_template);
7901   context1->Enter();
7902
7903   v8::Handle<v8::Object> global1 = context1->Global();
7904   global1->Set(v8_str("othercontext"), global0);
7905   // This set will fail the security check.
7906   v8::Handle<Script> script1 =
7907     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7908   script1->Run();
7909   g_security_callback_result = true;
7910   // This read will pass the security check.
7911   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7912   CHECK_EQ(111, foo1->Int32Value());
7913   // This read will pass the security check.
7914   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7915   CHECK_EQ(999, z1->Int32Value());
7916
7917   // Create another environment, should pass security checks.
7918   {
7919     v8::HandleScope scope2(isolate);
7920     LocalContext context2;
7921     v8::Handle<v8::Object> global2 = context2->Global();
7922     global2->Set(v8_str("othercontext"), global0);
7923     v8::Handle<Script> script2 =
7924         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7925     script2->Run();
7926     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7927     CHECK_EQ(333, foo2->Int32Value());
7928     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7929     CHECK_EQ(888, z2->Int32Value());
7930   }
7931
7932   context1->Exit();
7933   context0->Exit();
7934 }
7935
7936
7937 THREADED_TEST(SecurityChecks) {
7938   LocalContext env1;
7939   v8::HandleScope handle_scope(env1->GetIsolate());
7940   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7941
7942   Local<Value> foo = v8_str("foo");
7943   Local<Value> bar = v8_str("bar");
7944
7945   // Set to the same domain.
7946   env1->SetSecurityToken(foo);
7947
7948   // Create a function in env1.
7949   CompileRun("spy=function(){return spy;}");
7950   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7951   CHECK(spy->IsFunction());
7952
7953   // Create another function accessing global objects.
7954   CompileRun("spy2=function(){return new this.Array();}");
7955   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7956   CHECK(spy2->IsFunction());
7957
7958   // Switch to env2 in the same domain and invoke spy on env2.
7959   {
7960     env2->SetSecurityToken(foo);
7961     // Enter env2
7962     Context::Scope scope_env2(env2);
7963     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
7964     CHECK(result->IsFunction());
7965   }
7966
7967   {
7968     env2->SetSecurityToken(bar);
7969     Context::Scope scope_env2(env2);
7970
7971     // Call cross_domain_call, it should throw an exception
7972     v8::TryCatch try_catch(env1->GetIsolate());
7973     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
7974     CHECK(try_catch.HasCaught());
7975   }
7976 }
7977
7978
7979 // Regression test case for issue 1183439.
7980 THREADED_TEST(SecurityChecksForPrototypeChain) {
7981   LocalContext current;
7982   v8::HandleScope scope(current->GetIsolate());
7983   v8::Handle<Context> other = Context::New(current->GetIsolate());
7984
7985   // Change context to be able to get to the Object function in the
7986   // other context without hitting the security checks.
7987   v8::Local<Value> other_object;
7988   { Context::Scope scope(other);
7989     other_object = other->Global()->Get(v8_str("Object"));
7990     other->Global()->Set(v8_num(42), v8_num(87));
7991   }
7992
7993   current->Global()->Set(v8_str("other"), other->Global());
7994   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
7995
7996   // Make sure the security check fails here and we get an undefined
7997   // result instead of getting the Object function. Repeat in a loop
7998   // to make sure to exercise the IC code.
7999   v8::Local<Script> access_other0 = v8_compile("other.Object");
8000   v8::Local<Script> access_other1 = v8_compile("other[42]");
8001   for (int i = 0; i < 5; i++) {
8002     CHECK(access_other0->Run().IsEmpty());
8003     CHECK(access_other1->Run().IsEmpty());
8004   }
8005
8006   // Create an object that has 'other' in its prototype chain and make
8007   // sure we cannot access the Object function indirectly through
8008   // that. Repeat in a loop to make sure to exercise the IC code.
8009   v8_compile("function F() { };"
8010              "F.prototype = other;"
8011              "var f = new F();")->Run();
8012   v8::Local<Script> access_f0 = v8_compile("f.Object");
8013   v8::Local<Script> access_f1 = v8_compile("f[42]");
8014   for (int j = 0; j < 5; j++) {
8015     CHECK(access_f0->Run().IsEmpty());
8016     CHECK(access_f1->Run().IsEmpty());
8017   }
8018
8019   // Now it gets hairy: Set the prototype for the other global object
8020   // to be the current global object. The prototype chain for 'f' now
8021   // goes through 'other' but ends up in the current global object.
8022   { Context::Scope scope(other);
8023     other->Global()->Set(v8_str("__proto__"), current->Global());
8024   }
8025   // Set a named and an index property on the current global
8026   // object. To force the lookup to go through the other global object,
8027   // the properties must not exist in the other global object.
8028   current->Global()->Set(v8_str("foo"), v8_num(100));
8029   current->Global()->Set(v8_num(99), v8_num(101));
8030   // Try to read the properties from f and make sure that the access
8031   // gets stopped by the security checks on the other global object.
8032   Local<Script> access_f2 = v8_compile("f.foo");
8033   Local<Script> access_f3 = v8_compile("f[99]");
8034   for (int k = 0; k < 5; k++) {
8035     CHECK(access_f2->Run().IsEmpty());
8036     CHECK(access_f3->Run().IsEmpty());
8037   }
8038 }
8039
8040
8041 static bool security_check_with_gc_called;
8042
8043 static bool SecurityTestCallbackWithGC(Local<v8::Object> global,
8044                                        Local<v8::Value> name,
8045                                        v8::AccessType type, Local<Value> data) {
8046   CcTest::heap()->CollectAllGarbage();
8047   security_check_with_gc_called = true;
8048   return true;
8049 }
8050
8051
8052 TEST(SecurityTestGCAllowed) {
8053   v8::Isolate* isolate = CcTest::isolate();
8054   v8::HandleScope handle_scope(isolate);
8055   v8::Handle<v8::ObjectTemplate> object_template =
8056       v8::ObjectTemplate::New(isolate);
8057   object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL);
8058
8059   v8::Handle<Context> context = Context::New(isolate);
8060   v8::Context::Scope context_scope(context);
8061
8062   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8063
8064   security_check_with_gc_called = false;
8065   CompileRun("obj[0] = new String(1002);");
8066   CHECK(security_check_with_gc_called);
8067
8068   security_check_with_gc_called = false;
8069   CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
8070   CHECK(security_check_with_gc_called);
8071 }
8072
8073
8074 THREADED_TEST(CrossDomainDelete) {
8075   LocalContext env1;
8076   v8::HandleScope handle_scope(env1->GetIsolate());
8077   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8078
8079   Local<Value> foo = v8_str("foo");
8080   Local<Value> bar = v8_str("bar");
8081
8082   // Set to the same domain.
8083   env1->SetSecurityToken(foo);
8084   env2->SetSecurityToken(foo);
8085
8086   env1->Global()->Set(v8_str("prop"), v8_num(3));
8087   env2->Global()->Set(v8_str("env1"), env1->Global());
8088
8089   // Change env2 to a different domain and delete env1.prop.
8090   env2->SetSecurityToken(bar);
8091   {
8092     Context::Scope scope_env2(env2);
8093     Local<Value> result =
8094         CompileRun("delete env1.prop");
8095     CHECK(result.IsEmpty());
8096   }
8097
8098   // Check that env1.prop still exists.
8099   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8100   CHECK(v->IsNumber());
8101   CHECK_EQ(3, v->Int32Value());
8102 }
8103
8104
8105 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8106   LocalContext env1;
8107   v8::HandleScope handle_scope(env1->GetIsolate());
8108   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8109
8110   Local<Value> foo = v8_str("foo");
8111   Local<Value> bar = v8_str("bar");
8112
8113   // Set to the same domain.
8114   env1->SetSecurityToken(foo);
8115   env2->SetSecurityToken(foo);
8116
8117   env1->Global()->Set(v8_str("prop"), v8_num(3));
8118   env2->Global()->Set(v8_str("env1"), env1->Global());
8119
8120   // env1.prop is enumerable in env2.
8121   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8122   {
8123     Context::Scope scope_env2(env2);
8124     Local<Value> result = CompileRun(test);
8125     CHECK(result->IsTrue());
8126   }
8127
8128   // Change env2 to a different domain and test again.
8129   env2->SetSecurityToken(bar);
8130   {
8131     Context::Scope scope_env2(env2);
8132     Local<Value> result = CompileRun(test);
8133     CHECK(result.IsEmpty());
8134   }
8135 }
8136
8137
8138 THREADED_TEST(CrossDomainForIn) {
8139   LocalContext env1;
8140   v8::HandleScope handle_scope(env1->GetIsolate());
8141   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8142
8143   Local<Value> foo = v8_str("foo");
8144   Local<Value> bar = v8_str("bar");
8145
8146   // Set to the same domain.
8147   env1->SetSecurityToken(foo);
8148   env2->SetSecurityToken(foo);
8149
8150   env1->Global()->Set(v8_str("prop"), v8_num(3));
8151   env2->Global()->Set(v8_str("env1"), env1->Global());
8152
8153   // Change env2 to a different domain and set env1's global object
8154   // as the __proto__ of an object in env2 and enumerate properties
8155   // in for-in. It shouldn't enumerate properties on env1's global
8156   // object.
8157   env2->SetSecurityToken(bar);
8158   {
8159     Context::Scope scope_env2(env2);
8160     Local<Value> result = CompileRun(
8161         "(function() {"
8162         "  var obj = { '__proto__': env1 };"
8163         "  try {"
8164         "    for (var p in obj) {"
8165         "      if (p == 'prop') return false;"
8166         "    }"
8167         "    return false;"
8168         "  } catch (e) {"
8169         "    return true;"
8170         "  }"
8171         "})()");
8172     CHECK(result->IsTrue());
8173   }
8174 }
8175
8176
8177 TEST(ContextDetachGlobal) {
8178   LocalContext env1;
8179   v8::HandleScope handle_scope(env1->GetIsolate());
8180   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8181
8182   Local<v8::Object> global1 = env1->Global();
8183
8184   Local<Value> foo = v8_str("foo");
8185
8186   // Set to the same domain.
8187   env1->SetSecurityToken(foo);
8188   env2->SetSecurityToken(foo);
8189
8190   // Enter env2
8191   env2->Enter();
8192
8193   // Create a function in env2 and add a reference to it in env1.
8194   Local<v8::Object> global2 = env2->Global();
8195   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8196   CompileRun("function getProp() {return prop;}");
8197
8198   env1->Global()->Set(v8_str("getProp"),
8199                       global2->Get(v8_str("getProp")));
8200
8201   // Detach env2's global, and reuse the global object of env2
8202   env2->Exit();
8203   env2->DetachGlobal();
8204
8205   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8206                                           0,
8207                                           v8::Handle<v8::ObjectTemplate>(),
8208                                           global2);
8209   env3->SetSecurityToken(v8_str("bar"));
8210   env3->Enter();
8211
8212   Local<v8::Object> global3 = env3->Global();
8213   CHECK(global2->Equals(global3));
8214   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8215   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8216   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8217   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8218   env3->Exit();
8219
8220   // Call getProp in env1, and it should return the value 1
8221   {
8222     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8223     CHECK(get_prop->IsFunction());
8224     v8::TryCatch try_catch(env1->GetIsolate());
8225     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8226     CHECK(!try_catch.HasCaught());
8227     CHECK_EQ(1, r->Int32Value());
8228   }
8229
8230   // Check that env3 is not accessible from env1
8231   {
8232     Local<Value> r = global3->Get(v8_str("prop2"));
8233     CHECK(r.IsEmpty());
8234   }
8235 }
8236
8237
8238 TEST(DetachGlobal) {
8239   LocalContext env1;
8240   v8::HandleScope scope(env1->GetIsolate());
8241
8242   // Create second environment.
8243   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8244
8245   Local<Value> foo = v8_str("foo");
8246
8247   // Set same security token for env1 and env2.
8248   env1->SetSecurityToken(foo);
8249   env2->SetSecurityToken(foo);
8250
8251   // Create a property on the global object in env2.
8252   {
8253     v8::Context::Scope scope(env2);
8254     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8255   }
8256
8257   // Create a reference to env2 global from env1 global.
8258   env1->Global()->Set(v8_str("other"), env2->Global());
8259
8260   // Check that we have access to other.p in env2 from env1.
8261   Local<Value> result = CompileRun("other.p");
8262   CHECK(result->IsInt32());
8263   CHECK_EQ(42, result->Int32Value());
8264
8265   // Hold on to global from env2 and detach global from env2.
8266   Local<v8::Object> global2 = env2->Global();
8267   env2->DetachGlobal();
8268
8269   // Check that the global has been detached. No other.p property can
8270   // be found.
8271   result = CompileRun("other.p");
8272   CHECK(result.IsEmpty());
8273
8274   // Reuse global2 for env3.
8275   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8276                                           0,
8277                                           v8::Handle<v8::ObjectTemplate>(),
8278                                           global2);
8279   CHECK(global2->Equals(env3->Global()));
8280
8281   // Start by using the same security token for env3 as for env1 and env2.
8282   env3->SetSecurityToken(foo);
8283
8284   // Create a property on the global object in env3.
8285   {
8286     v8::Context::Scope scope(env3);
8287     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8288   }
8289
8290   // Check that other.p is now the property in env3 and that we have access.
8291   result = CompileRun("other.p");
8292   CHECK(result->IsInt32());
8293   CHECK_EQ(24, result->Int32Value());
8294
8295   // Change security token for env3 to something different from env1 and env2.
8296   env3->SetSecurityToken(v8_str("bar"));
8297
8298   // Check that we do not have access to other.p in env1. |other| is now
8299   // the global object for env3 which has a different security token,
8300   // so access should be blocked.
8301   result = CompileRun("other.p");
8302   CHECK(result.IsEmpty());
8303 }
8304
8305
8306 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8307   info.GetReturnValue().Set(
8308       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8309 }
8310
8311
8312 TEST(DetachedAccesses) {
8313   LocalContext env1;
8314   v8::HandleScope scope(env1->GetIsolate());
8315
8316   // Create second environment.
8317   Local<ObjectTemplate> inner_global_template =
8318       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8319   inner_global_template ->SetAccessorProperty(
8320       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8321   v8::Local<Context> env2 =
8322       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8323
8324   Local<Value> foo = v8_str("foo");
8325
8326   // Set same security token for env1 and env2.
8327   env1->SetSecurityToken(foo);
8328   env2->SetSecurityToken(foo);
8329
8330   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8331
8332   {
8333     v8::Context::Scope scope(env2);
8334     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8335     CompileRun(
8336         "function bound_x() { return x; }"
8337         "function get_x()   { return this.x; }"
8338         "function get_x_w() { return (function() {return this.x;})(); }");
8339     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8340     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8341     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8342     env1->Global()->Set(
8343         v8_str("this_x"),
8344         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8345   }
8346
8347   Local<Object> env2_global = env2->Global();
8348   env2->DetachGlobal();
8349
8350   Local<Value> result;
8351   result = CompileRun("bound_x()");
8352   CHECK(v8_str("env2_x")->Equals(result));
8353   result = CompileRun("get_x()");
8354   CHECK(result.IsEmpty());
8355   result = CompileRun("get_x_w()");
8356   CHECK(result.IsEmpty());
8357   result = CompileRun("this_x()");
8358   CHECK(v8_str("env2_x")->Equals(result));
8359
8360   // Reattach env2's proxy
8361   env2 = Context::New(env1->GetIsolate(),
8362                       0,
8363                       v8::Handle<v8::ObjectTemplate>(),
8364                       env2_global);
8365   env2->SetSecurityToken(foo);
8366   {
8367     v8::Context::Scope scope(env2);
8368     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8369     env2->Global()->Set(v8_str("env1"), env1->Global());
8370     result = CompileRun(
8371         "results = [];"
8372         "for (var i = 0; i < 4; i++ ) {"
8373         "  results.push(env1.bound_x());"
8374         "  results.push(env1.get_x());"
8375         "  results.push(env1.get_x_w());"
8376         "  results.push(env1.this_x());"
8377         "}"
8378         "results");
8379     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8380     CHECK_EQ(16u, results->Length());
8381     for (int i = 0; i < 16; i += 4) {
8382       CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8383       CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8384       CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8385       CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8386     }
8387   }
8388
8389   result = CompileRun(
8390       "results = [];"
8391       "for (var i = 0; i < 4; i++ ) {"
8392       "  results.push(bound_x());"
8393       "  results.push(get_x());"
8394       "  results.push(get_x_w());"
8395       "  results.push(this_x());"
8396       "}"
8397       "results");
8398   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8399   CHECK_EQ(16u, results->Length());
8400   for (int i = 0; i < 16; i += 4) {
8401     CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8402     CHECK(v8_str("env3_x")->Equals(results->Get(i + 1)));
8403     CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8404     CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8405   }
8406
8407   result = CompileRun(
8408       "results = [];"
8409       "for (var i = 0; i < 4; i++ ) {"
8410       "  results.push(this.bound_x());"
8411       "  results.push(this.get_x());"
8412       "  results.push(this.get_x_w());"
8413       "  results.push(this.this_x());"
8414       "}"
8415       "results");
8416   results = Local<v8::Array>::Cast(result);
8417   CHECK_EQ(16u, results->Length());
8418   for (int i = 0; i < 16; i += 4) {
8419     CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8420     CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8421     CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8422     CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8423   }
8424 }
8425
8426
8427 static bool allowed_access = false;
8428 static bool AccessBlocker(Local<v8::Object> global, Local<Value> name,
8429                           v8::AccessType type, Local<Value> data) {
8430   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8431          allowed_access;
8432 }
8433
8434
8435 static int g_echo_value = -1;
8436
8437
8438 static void EchoGetter(
8439     Local<String> name,
8440     const v8::PropertyCallbackInfo<v8::Value>& info) {
8441   info.GetReturnValue().Set(v8_num(g_echo_value));
8442 }
8443
8444
8445 static void EchoSetter(Local<String> name,
8446                        Local<Value> value,
8447                        const v8::PropertyCallbackInfo<void>&) {
8448   if (value->IsNumber())
8449     g_echo_value = value->Int32Value();
8450 }
8451
8452
8453 static void UnreachableGetter(
8454     Local<String> name,
8455     const v8::PropertyCallbackInfo<v8::Value>& info) {
8456   CHECK(false);  // This function should not be called..
8457 }
8458
8459
8460 static void UnreachableSetter(Local<String>,
8461                               Local<Value>,
8462                               const v8::PropertyCallbackInfo<void>&) {
8463   CHECK(false);  // This function should nto be called.
8464 }
8465
8466
8467 static void UnreachableFunction(
8468     const v8::FunctionCallbackInfo<v8::Value>& info) {
8469   CHECK(false);  // This function should not be called..
8470 }
8471
8472
8473 TEST(AccessControl) {
8474   v8::Isolate* isolate = CcTest::isolate();
8475   v8::HandleScope handle_scope(isolate);
8476   v8::Handle<v8::ObjectTemplate> global_template =
8477       v8::ObjectTemplate::New(isolate);
8478
8479   global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8480
8481   // Add an accessor accessible by cross-domain JS code.
8482   global_template->SetAccessor(
8483       v8_str("accessible_prop"),
8484       EchoGetter, EchoSetter,
8485       v8::Handle<Value>(),
8486       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8487
8488
8489   // Add an accessor that is not accessible by cross-domain JS code.
8490   global_template->SetAccessor(v8_str("blocked_prop"),
8491                                UnreachableGetter, UnreachableSetter,
8492                                v8::Handle<Value>(),
8493                                v8::DEFAULT);
8494
8495   global_template->SetAccessorProperty(
8496       v8_str("blocked_js_prop"),
8497       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8498       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8499       v8::None,
8500       v8::DEFAULT);
8501
8502   // Create an environment
8503   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8504   context0->Enter();
8505
8506   v8::Handle<v8::Object> global0 = context0->Global();
8507
8508   // Define a property with JS getter and setter.
8509   CompileRun(
8510       "function getter() { return 'getter'; };\n"
8511       "function setter() { return 'setter'; }\n"
8512       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8513
8514   Local<Value> getter = global0->Get(v8_str("getter"));
8515   Local<Value> setter = global0->Get(v8_str("setter"));
8516
8517   // And define normal element.
8518   global0->Set(239, v8_str("239"));
8519
8520   // Define an element with JS getter and setter.
8521   CompileRun(
8522       "function el_getter() { return 'el_getter'; };\n"
8523       "function el_setter() { return 'el_setter'; };\n"
8524       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8525
8526   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8527   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8528
8529   v8::HandleScope scope1(isolate);
8530
8531   v8::Local<Context> context1 = Context::New(isolate);
8532   context1->Enter();
8533
8534   v8::Handle<v8::Object> global1 = context1->Global();
8535   global1->Set(v8_str("other"), global0);
8536
8537   // Access blocked property.
8538   CompileRun("other.blocked_prop = 1");
8539
8540   CHECK(CompileRun("other.blocked_prop").IsEmpty());
8541   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8542             .IsEmpty());
8543   CHECK(
8544       CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
8545
8546   // Access blocked element.
8547   CHECK(CompileRun("other[239] = 1").IsEmpty());
8548
8549   CHECK(CompileRun("other[239]").IsEmpty());
8550   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
8551   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
8552
8553   allowed_access = true;
8554   // Now we can enumerate the property.
8555   ExpectTrue("propertyIsEnumerable.call(other, '239')");
8556   allowed_access = false;
8557
8558   // Access a property with JS accessor.
8559   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
8560
8561   CHECK(CompileRun("other.js_accessor_p").IsEmpty());
8562   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
8563             .IsEmpty());
8564
8565   allowed_access = true;
8566
8567   ExpectString("other.js_accessor_p", "getter");
8568   ExpectObject(
8569       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8570   ExpectObject(
8571       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8572   ExpectUndefined(
8573       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8574
8575   allowed_access = false;
8576
8577   // Access an element with JS accessor.
8578   CHECK(CompileRun("other[42] = 2").IsEmpty());
8579
8580   CHECK(CompileRun("other[42]").IsEmpty());
8581   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
8582
8583   allowed_access = true;
8584
8585   ExpectString("other[42]", "el_getter");
8586   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8587   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8588   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8589
8590   allowed_access = false;
8591
8592   v8::Handle<Value> value;
8593
8594   // Access accessible property
8595   value = CompileRun("other.accessible_prop = 3");
8596   CHECK(value->IsNumber());
8597   CHECK_EQ(3, value->Int32Value());
8598   CHECK_EQ(3, g_echo_value);
8599
8600   value = CompileRun("other.accessible_prop");
8601   CHECK(value->IsNumber());
8602   CHECK_EQ(3, value->Int32Value());
8603
8604   value = CompileRun(
8605       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8606   CHECK(value->IsNumber());
8607   CHECK_EQ(3, value->Int32Value());
8608
8609   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8610   CHECK(value->IsTrue());
8611
8612   // Enumeration doesn't enumerate accessors from inaccessible objects in
8613   // the prototype chain even if the accessors are in themselves accessible.
8614   value = CompileRun(
8615       "(function() {"
8616       "  var obj = { '__proto__': other };"
8617       "  try {"
8618       "    for (var p in obj) {"
8619       "      if (p == 'accessible_prop' ||"
8620       "          p == 'blocked_js_prop' ||"
8621       "          p == 'blocked_js_prop') {"
8622       "        return false;"
8623       "      }"
8624       "    }"
8625       "    return false;"
8626       "  } catch (e) {"
8627       "    return true;"
8628       "  }"
8629       "})()");
8630   CHECK(value->IsTrue());
8631
8632   context1->Exit();
8633   context0->Exit();
8634 }
8635
8636
8637 TEST(AccessControlES5) {
8638   v8::Isolate* isolate = CcTest::isolate();
8639   v8::HandleScope handle_scope(isolate);
8640   v8::Handle<v8::ObjectTemplate> global_template =
8641       v8::ObjectTemplate::New(isolate);
8642
8643   global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8644
8645   // Add accessible accessor.
8646   global_template->SetAccessor(
8647       v8_str("accessible_prop"),
8648       EchoGetter, EchoSetter,
8649       v8::Handle<Value>(),
8650       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8651
8652
8653   // Add an accessor that is not accessible by cross-domain JS code.
8654   global_template->SetAccessor(v8_str("blocked_prop"),
8655                                UnreachableGetter, UnreachableSetter,
8656                                v8::Handle<Value>(),
8657                                v8::DEFAULT);
8658
8659   // Create an environment
8660   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8661   context0->Enter();
8662
8663   v8::Handle<v8::Object> global0 = context0->Global();
8664
8665   v8::Local<Context> context1 = Context::New(isolate);
8666   context1->Enter();
8667   v8::Handle<v8::Object> global1 = context1->Global();
8668   global1->Set(v8_str("other"), global0);
8669
8670   // Regression test for issue 1154.
8671   CHECK(CompileRun("Object.keys(other)").IsEmpty());
8672   CHECK(CompileRun("other.blocked_prop").IsEmpty());
8673
8674   // Regression test for issue 1027.
8675   CompileRun("Object.defineProperty(\n"
8676              "  other, 'blocked_prop', {configurable: false})");
8677   CHECK(CompileRun("other.blocked_prop").IsEmpty());
8678   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8679             .IsEmpty());
8680
8681   // Regression test for issue 1171.
8682   ExpectTrue("Object.isExtensible(other)");
8683   CompileRun("Object.preventExtensions(other)");
8684   ExpectTrue("Object.isExtensible(other)");
8685
8686   // Object.seal and Object.freeze.
8687   CompileRun("Object.freeze(other)");
8688   ExpectTrue("Object.isExtensible(other)");
8689
8690   CompileRun("Object.seal(other)");
8691   ExpectTrue("Object.isExtensible(other)");
8692
8693   // Regression test for issue 1250.
8694   // Make sure that we can set the accessible accessors value using normal
8695   // assignment.
8696   CompileRun("other.accessible_prop = 42");
8697   CHECK_EQ(42, g_echo_value);
8698
8699   v8::Handle<Value> value;
8700   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8701   value = CompileRun("other.accessible_prop == 42");
8702   CHECK(value->IsTrue());
8703 }
8704
8705
8706 static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name,
8707                                 v8::AccessType type, Local<Value> data) {
8708   i::PrintF("Access blocked.\n");
8709   return false;
8710 }
8711
8712
8713 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8714   v8::Isolate* isolate = CcTest::isolate();
8715   v8::HandleScope handle_scope(isolate);
8716   v8::Handle<v8::ObjectTemplate> obj_template =
8717       v8::ObjectTemplate::New(isolate);
8718
8719   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
8720   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8721
8722   // Create an environment
8723   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8724   context0->Enter();
8725
8726   v8::Handle<v8::Object> global0 = context0->Global();
8727
8728   v8::HandleScope scope1(CcTest::isolate());
8729
8730   v8::Local<Context> context1 = Context::New(isolate);
8731   context1->Enter();
8732
8733   v8::Handle<v8::Object> global1 = context1->Global();
8734   global1->Set(v8_str("other"), global0);
8735   global1->Set(v8_str("object"), obj_template->NewInstance());
8736
8737   v8::Handle<Value> value;
8738
8739   // Attempt to get the property names of the other global object and
8740   // of an object that requires access checks.  Accessing the other
8741   // global object should be blocked by access checks on the global
8742   // proxy object.  Accessing the object that requires access checks
8743   // is blocked by the access checks on the object itself.
8744   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8745   CHECK(value.IsEmpty());
8746
8747   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8748   CHECK(value.IsEmpty());
8749
8750   context1->Exit();
8751   context0->Exit();
8752 }
8753
8754
8755 TEST(SuperAccessControl) {
8756   i::FLAG_allow_natives_syntax = true;
8757   v8::Isolate* isolate = CcTest::isolate();
8758   v8::HandleScope handle_scope(isolate);
8759   v8::Handle<v8::ObjectTemplate> obj_template =
8760       v8::ObjectTemplate::New(isolate);
8761   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8762   LocalContext env;
8763   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8764
8765   {
8766     v8::TryCatch try_catch(isolate);
8767     CompileRun(
8768         "var f = { m() { return super.hasOwnProperty; } }.m;"
8769         "var m = %ToMethod(f, prohibited);"
8770         "m();");
8771     CHECK(try_catch.HasCaught());
8772   }
8773
8774   {
8775     v8::TryCatch try_catch(isolate);
8776     CompileRun(
8777         "var f = {m() { return super[42]; } }.m;"
8778         "var m = %ToMethod(f, prohibited);"
8779         "m();");
8780     CHECK(try_catch.HasCaught());
8781   }
8782
8783   {
8784     v8::TryCatch try_catch(isolate);
8785     CompileRun(
8786         "var f = {m() { super.hasOwnProperty = function () {}; } }.m;"
8787         "var m = %ToMethod(f, prohibited);"
8788         "m();");
8789     CHECK(try_catch.HasCaught());
8790   }
8791
8792   {
8793     v8::TryCatch try_catch(isolate);
8794     CompileRun(
8795         "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
8796         "var f = {"
8797         "  m() { "
8798         "    'use strict';"
8799         "    super.x = function () {};"
8800         "  }"
8801         "}.m;"
8802         "var m = %ToMethod(f, prohibited);"
8803         "m();");
8804     CHECK(try_catch.HasCaught());
8805   }
8806 }
8807
8808
8809 TEST(Regress470113) {
8810   v8::Isolate* isolate = CcTest::isolate();
8811   v8::HandleScope handle_scope(isolate);
8812   v8::Handle<v8::ObjectTemplate> obj_template =
8813       v8::ObjectTemplate::New(isolate);
8814   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8815   LocalContext env;
8816   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8817
8818   {
8819     v8::TryCatch try_catch(isolate);
8820     CompileRun(
8821         "'use strict';\n"
8822         "class C extends Object {\n"
8823         "   m() { super.powned = 'Powned!'; }\n"
8824         "}\n"
8825         "let c = new C();\n"
8826         "c.m.call(prohibited)");
8827
8828     CHECK(try_catch.HasCaught());
8829   }
8830 }
8831
8832
8833 static void ConstTenGetter(Local<String> name,
8834                            const v8::PropertyCallbackInfo<v8::Value>& info) {
8835   info.GetReturnValue().Set(v8_num(10));
8836 }
8837
8838
8839 THREADED_TEST(CrossDomainAccessors) {
8840   v8::Isolate* isolate = CcTest::isolate();
8841   v8::HandleScope handle_scope(isolate);
8842
8843   v8::Handle<v8::FunctionTemplate> func_template =
8844       v8::FunctionTemplate::New(isolate);
8845
8846   v8::Handle<v8::ObjectTemplate> global_template =
8847       func_template->InstanceTemplate();
8848
8849   v8::Handle<v8::ObjectTemplate> proto_template =
8850       func_template->PrototypeTemplate();
8851
8852   // Add an accessor to proto that's accessible by cross-domain JS code.
8853   proto_template->SetAccessor(v8_str("accessible"),
8854                               ConstTenGetter, 0,
8855                               v8::Handle<Value>(),
8856                               v8::ALL_CAN_READ);
8857
8858   // Add an accessor that is not accessible by cross-domain JS code.
8859   global_template->SetAccessor(v8_str("unreachable"),
8860                                UnreachableGetter, 0,
8861                                v8::Handle<Value>(),
8862                                v8::DEFAULT);
8863
8864   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8865   context0->Enter();
8866
8867   Local<v8::Object> global = context0->Global();
8868   // Add a normal property that shadows 'accessible'
8869   global->Set(v8_str("accessible"), v8_num(11));
8870
8871   // Enter a new context.
8872   v8::HandleScope scope1(CcTest::isolate());
8873   v8::Local<Context> context1 = Context::New(isolate);
8874   context1->Enter();
8875
8876   v8::Handle<v8::Object> global1 = context1->Global();
8877   global1->Set(v8_str("other"), global);
8878
8879   // Should return 10, instead of 11
8880   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8881   CHECK(value->IsNumber());
8882   CHECK_EQ(10, value->Int32Value());
8883
8884   value = v8_compile("other.unreachable")->Run();
8885   CHECK(value.IsEmpty());
8886
8887   context1->Exit();
8888   context0->Exit();
8889 }
8890
8891
8892 static int access_count = 0;
8893
8894 static bool AccessCounter(Local<v8::Object> global, Local<Value> name,
8895                           v8::AccessType type, Local<Value> data) {
8896   access_count++;
8897   return true;
8898 }
8899
8900
8901 // This one is too easily disturbed by other tests.
8902 TEST(AccessControlIC) {
8903   access_count = 0;
8904
8905   v8::Isolate* isolate = CcTest::isolate();
8906   v8::HandleScope handle_scope(isolate);
8907
8908   // Create an environment.
8909   v8::Local<Context> context0 = Context::New(isolate);
8910   context0->Enter();
8911
8912   // Create an object that requires access-check functions to be
8913   // called for cross-domain access.
8914   v8::Handle<v8::ObjectTemplate> object_template =
8915       v8::ObjectTemplate::New(isolate);
8916   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
8917   Local<v8::Object> object = object_template->NewInstance();
8918
8919   v8::HandleScope scope1(isolate);
8920
8921   // Create another environment.
8922   v8::Local<Context> context1 = Context::New(isolate);
8923   context1->Enter();
8924
8925   // Make easy access to the object from the other environment.
8926   v8::Handle<v8::Object> global1 = context1->Global();
8927   global1->Set(v8_str("obj"), object);
8928
8929   v8::Handle<Value> value;
8930
8931   // Check that the named access-control function is called every time.
8932   CompileRun("function testProp(obj) {"
8933              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
8934              "  for (var j = 0; j < 10; j++) obj.prop;"
8935              "  return obj.prop"
8936              "}");
8937   value = CompileRun("testProp(obj)");
8938   CHECK(value->IsNumber());
8939   CHECK_EQ(1, value->Int32Value());
8940   CHECK_EQ(21, access_count);
8941
8942   // Check that the named access-control function is called every time.
8943   CompileRun("var p = 'prop';"
8944              "function testKeyed(obj) {"
8945              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
8946              "  for (var j = 0; j < 10; j++) obj[p];"
8947              "  return obj[p];"
8948              "}");
8949   // Use obj which requires access checks.  No inline caching is used
8950   // in that case.
8951   value = CompileRun("testKeyed(obj)");
8952   CHECK(value->IsNumber());
8953   CHECK_EQ(1, value->Int32Value());
8954   CHECK_EQ(42, access_count);
8955   // Force the inline caches into generic state and try again.
8956   CompileRun("testKeyed({ a: 0 })");
8957   CompileRun("testKeyed({ b: 0 })");
8958   value = CompileRun("testKeyed(obj)");
8959   CHECK(value->IsNumber());
8960   CHECK_EQ(1, value->Int32Value());
8961   CHECK_EQ(63, access_count);
8962
8963   // Check that the indexed access-control function is called every time.
8964   access_count = 0;
8965
8966   CompileRun("function testIndexed(obj) {"
8967              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
8968              "  for (var j = 0; j < 10; j++) obj[0];"
8969              "  return obj[0]"
8970              "}");
8971   value = CompileRun("testIndexed(obj)");
8972   CHECK(value->IsNumber());
8973   CHECK_EQ(1, value->Int32Value());
8974   CHECK_EQ(21, access_count);
8975   // Force the inline caches into generic state.
8976   CompileRun("testIndexed(new Array(1))");
8977   // Test that the indexed access check is called.
8978   value = CompileRun("testIndexed(obj)");
8979   CHECK(value->IsNumber());
8980   CHECK_EQ(1, value->Int32Value());
8981   CHECK_EQ(42, access_count);
8982
8983   access_count = 0;
8984   // Check that the named access check is called when invoking
8985   // functions on an object that requires access checks.
8986   CompileRun("obj.f = function() {}");
8987   CompileRun("function testCallNormal(obj) {"
8988              "  for (var i = 0; i < 10; i++) obj.f();"
8989              "}");
8990   CompileRun("testCallNormal(obj)");
8991   printf("%i\n", access_count);
8992   CHECK_EQ(11, access_count);
8993
8994   // Force obj into slow case.
8995   value = CompileRun("delete obj.prop");
8996   CHECK(value->BooleanValue());
8997   // Force inline caches into dictionary probing mode.
8998   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
8999   // Test that the named access check is called.
9000   value = CompileRun("testProp(obj);");
9001   CHECK(value->IsNumber());
9002   CHECK_EQ(1, value->Int32Value());
9003   CHECK_EQ(33, access_count);
9004
9005   // Force the call inline cache into dictionary probing mode.
9006   CompileRun("o.f = function() {}; testCallNormal(o)");
9007   // Test that the named access check is still called for each
9008   // invocation of the function.
9009   value = CompileRun("testCallNormal(obj)");
9010   CHECK_EQ(43, access_count);
9011
9012   context1->Exit();
9013   context0->Exit();
9014 }
9015
9016
9017 THREADED_TEST(Version) { v8::V8::GetVersion(); }
9018
9019
9020 static void InstanceFunctionCallback(
9021     const v8::FunctionCallbackInfo<v8::Value>& args) {
9022   ApiTestFuzzer::Fuzz();
9023   args.GetReturnValue().Set(v8_num(12));
9024 }
9025
9026
9027 THREADED_TEST(InstanceProperties) {
9028   LocalContext context;
9029   v8::Isolate* isolate = context->GetIsolate();
9030   v8::HandleScope handle_scope(isolate);
9031
9032   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9033   Local<ObjectTemplate> instance = t->InstanceTemplate();
9034
9035   instance->Set(v8_str("x"), v8_num(42));
9036   instance->Set(v8_str("f"),
9037                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9038
9039   Local<Value> o = t->GetFunction()->NewInstance();
9040
9041   context->Global()->Set(v8_str("i"), o);
9042   Local<Value> value = CompileRun("i.x");
9043   CHECK_EQ(42, value->Int32Value());
9044
9045   value = CompileRun("i.f()");
9046   CHECK_EQ(12, value->Int32Value());
9047 }
9048
9049
9050 static void GlobalObjectInstancePropertiesGet(
9051     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
9052   ApiTestFuzzer::Fuzz();
9053 }
9054
9055
9056 THREADED_TEST(GlobalObjectInstanceProperties) {
9057   v8::Isolate* isolate = CcTest::isolate();
9058   v8::HandleScope handle_scope(isolate);
9059
9060   Local<Value> global_object;
9061
9062   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9063   t->InstanceTemplate()->SetHandler(
9064       v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
9065   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9066   instance_template->Set(v8_str("x"), v8_num(42));
9067   instance_template->Set(v8_str("f"),
9068                          v8::FunctionTemplate::New(isolate,
9069                                                    InstanceFunctionCallback));
9070
9071   // The script to check how Crankshaft compiles missing global function
9072   // invocations.  function g is not defined and should throw on call.
9073   const char* script =
9074       "function wrapper(call) {"
9075       "  var x = 0, y = 1;"
9076       "  for (var i = 0; i < 1000; i++) {"
9077       "    x += i * 100;"
9078       "    y += i * 100;"
9079       "  }"
9080       "  if (call) g();"
9081       "}"
9082       "for (var i = 0; i < 17; i++) wrapper(false);"
9083       "var thrown = 0;"
9084       "try { wrapper(true); } catch (e) { thrown = 1; };"
9085       "thrown";
9086
9087   {
9088     LocalContext env(NULL, instance_template);
9089     // Hold on to the global object so it can be used again in another
9090     // environment initialization.
9091     global_object = env->Global();
9092
9093     Local<Value> value = CompileRun("x");
9094     CHECK_EQ(42, value->Int32Value());
9095     value = CompileRun("f()");
9096     CHECK_EQ(12, value->Int32Value());
9097     value = CompileRun(script);
9098     CHECK_EQ(1, value->Int32Value());
9099   }
9100
9101   {
9102     // Create new environment reusing the global object.
9103     LocalContext env(NULL, instance_template, global_object);
9104     Local<Value> value = CompileRun("x");
9105     CHECK_EQ(42, value->Int32Value());
9106     value = CompileRun("f()");
9107     CHECK_EQ(12, value->Int32Value());
9108     value = CompileRun(script);
9109     CHECK_EQ(1, value->Int32Value());
9110   }
9111 }
9112
9113
9114 THREADED_TEST(CallKnownGlobalReceiver) {
9115   v8::Isolate* isolate = CcTest::isolate();
9116   v8::HandleScope handle_scope(isolate);
9117
9118   Local<Value> global_object;
9119
9120   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9121   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9122
9123   // The script to check that we leave global object not
9124   // global object proxy on stack when we deoptimize from inside
9125   // arguments evaluation.
9126   // To provoke error we need to both force deoptimization
9127   // from arguments evaluation and to force CallIC to take
9128   // CallIC_Miss code path that can't cope with global proxy.
9129   const char* script =
9130       "function bar(x, y) { try { } finally { } }"
9131       "function baz(x) { try { } finally { } }"
9132       "function bom(x) { try { } finally { } }"
9133       "function foo(x) { bar([x], bom(2)); }"
9134       "for (var i = 0; i < 10000; i++) foo(1);"
9135       "foo";
9136
9137   Local<Value> foo;
9138   {
9139     LocalContext env(NULL, instance_template);
9140     // Hold on to the global object so it can be used again in another
9141     // environment initialization.
9142     global_object = env->Global();
9143     foo = CompileRun(script);
9144   }
9145
9146   {
9147     // Create new environment reusing the global object.
9148     LocalContext env(NULL, instance_template, global_object);
9149     env->Global()->Set(v8_str("foo"), foo);
9150     CompileRun("foo()");
9151   }
9152 }
9153
9154
9155 static void ShadowFunctionCallback(
9156     const v8::FunctionCallbackInfo<v8::Value>& args) {
9157   ApiTestFuzzer::Fuzz();
9158   args.GetReturnValue().Set(v8_num(42));
9159 }
9160
9161
9162 static int shadow_y;
9163 static int shadow_y_setter_call_count;
9164 static int shadow_y_getter_call_count;
9165
9166
9167 static void ShadowYSetter(Local<String>,
9168                           Local<Value>,
9169                           const v8::PropertyCallbackInfo<void>&) {
9170   shadow_y_setter_call_count++;
9171   shadow_y = 42;
9172 }
9173
9174
9175 static void ShadowYGetter(Local<String> name,
9176                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9177   ApiTestFuzzer::Fuzz();
9178   shadow_y_getter_call_count++;
9179   info.GetReturnValue().Set(v8_num(shadow_y));
9180 }
9181
9182
9183 static void ShadowIndexedGet(uint32_t index,
9184                              const v8::PropertyCallbackInfo<v8::Value>&) {
9185 }
9186
9187
9188 static void ShadowNamedGet(Local<Name> key,
9189                            const v8::PropertyCallbackInfo<v8::Value>&) {}
9190
9191
9192 THREADED_TEST(ShadowObject) {
9193   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9194   v8::Isolate* isolate = CcTest::isolate();
9195   v8::HandleScope handle_scope(isolate);
9196
9197   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9198   LocalContext context(NULL, global_template);
9199
9200   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9201   t->InstanceTemplate()->SetHandler(
9202       v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
9203   t->InstanceTemplate()->SetHandler(
9204       v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
9205   Local<ObjectTemplate> proto = t->PrototypeTemplate();
9206   Local<ObjectTemplate> instance = t->InstanceTemplate();
9207
9208   proto->Set(v8_str("f"),
9209              v8::FunctionTemplate::New(isolate,
9210                                        ShadowFunctionCallback,
9211                                        Local<Value>()));
9212   proto->Set(v8_str("x"), v8_num(12));
9213
9214   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9215
9216   Local<Value> o = t->GetFunction()->NewInstance();
9217   context->Global()->Set(v8_str("__proto__"), o);
9218
9219   Local<Value> value =
9220       CompileRun("this.propertyIsEnumerable(0)");
9221   CHECK(value->IsBoolean());
9222   CHECK(!value->BooleanValue());
9223
9224   value = CompileRun("x");
9225   CHECK_EQ(12, value->Int32Value());
9226
9227   value = CompileRun("f()");
9228   CHECK_EQ(42, value->Int32Value());
9229
9230   CompileRun("y = 43");
9231   CHECK_EQ(1, shadow_y_setter_call_count);
9232   value = CompileRun("y");
9233   CHECK_EQ(1, shadow_y_getter_call_count);
9234   CHECK_EQ(42, value->Int32Value());
9235 }
9236
9237
9238 THREADED_TEST(HiddenPrototype) {
9239   LocalContext context;
9240   v8::Isolate* isolate = context->GetIsolate();
9241   v8::HandleScope handle_scope(isolate);
9242
9243   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9244   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9245   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9246   t1->SetHiddenPrototype(true);
9247   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9248   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9249   t2->SetHiddenPrototype(true);
9250   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9251   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9252   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9253
9254   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9255   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9256   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9257   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9258
9259   // Setting the prototype on an object skips hidden prototypes.
9260   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9261   o0->Set(v8_str("__proto__"), o1);
9262   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9263   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9264   o0->Set(v8_str("__proto__"), o2);
9265   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9266   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9267   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9268   o0->Set(v8_str("__proto__"), o3);
9269   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9270   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9271   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9272   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9273
9274   // Getting the prototype of o0 should get the first visible one
9275   // which is o3.  Therefore, z should not be defined on the prototype
9276   // object.
9277   Local<Value> proto = o0->Get(v8_str("__proto__"));
9278   CHECK(proto->IsObject());
9279   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9280 }
9281
9282
9283 THREADED_TEST(HiddenPrototypeSet) {
9284   LocalContext context;
9285   v8::Isolate* isolate = context->GetIsolate();
9286   v8::HandleScope handle_scope(isolate);
9287
9288   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
9289   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
9290   ht->SetHiddenPrototype(true);
9291   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
9292   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9293
9294   Local<v8::Object> o = ot->GetFunction()->NewInstance();
9295   Local<v8::Object> h = ht->GetFunction()->NewInstance();
9296   Local<v8::Object> p = pt->GetFunction()->NewInstance();
9297   o->Set(v8_str("__proto__"), h);
9298   h->Set(v8_str("__proto__"), p);
9299
9300   // Setting a property that exists on the hidden prototype goes there.
9301   o->Set(v8_str("x"), v8_num(7));
9302   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9303   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9304   CHECK(p->Get(v8_str("x"))->IsUndefined());
9305
9306   // Setting a new property should not be forwarded to the hidden prototype.
9307   o->Set(v8_str("y"), v8_num(6));
9308   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9309   CHECK(h->Get(v8_str("y"))->IsUndefined());
9310   CHECK(p->Get(v8_str("y"))->IsUndefined());
9311
9312   // Setting a property that only exists on a prototype of the hidden prototype
9313   // is treated normally again.
9314   p->Set(v8_str("z"), v8_num(8));
9315   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9316   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9317   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9318   o->Set(v8_str("z"), v8_num(9));
9319   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9320   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9321   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9322 }
9323
9324
9325 // Regression test for issue 2457.
9326 THREADED_TEST(HiddenPrototypeIdentityHash) {
9327   LocalContext context;
9328   v8::HandleScope handle_scope(context->GetIsolate());
9329
9330   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
9331   t->SetHiddenPrototype(true);
9332   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9333   Handle<Object> p = t->GetFunction()->NewInstance();
9334   Handle<Object> o = Object::New(context->GetIsolate());
9335   o->SetPrototype(p);
9336
9337   int hash = o->GetIdentityHash();
9338   USE(hash);
9339   o->Set(v8_str("foo"), v8_num(42));
9340   DCHECK_EQ(hash, o->GetIdentityHash());
9341 }
9342
9343
9344 THREADED_TEST(SetPrototype) {
9345   LocalContext context;
9346   v8::Isolate* isolate = context->GetIsolate();
9347   v8::HandleScope handle_scope(isolate);
9348
9349   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9350   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9351   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9352   t1->SetHiddenPrototype(true);
9353   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9354   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9355   t2->SetHiddenPrototype(true);
9356   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9357   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9358   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9359
9360   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9361   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9362   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9363   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9364
9365   // Setting the prototype on an object does not skip hidden prototypes.
9366   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9367   CHECK(o0->SetPrototype(o1));
9368   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9369   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9370   CHECK(o1->SetPrototype(o2));
9371   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9372   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9373   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9374   CHECK(o2->SetPrototype(o3));
9375   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9376   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9377   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9378   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9379
9380   // Getting the prototype of o0 should get the first visible one
9381   // which is o3.  Therefore, z should not be defined on the prototype
9382   // object.
9383   Local<Value> proto = o0->Get(v8_str("__proto__"));
9384   CHECK(proto->IsObject());
9385   CHECK(proto.As<v8::Object>()->Equals(o3));
9386
9387   // However, Object::GetPrototype ignores hidden prototype.
9388   Local<Value> proto0 = o0->GetPrototype();
9389   CHECK(proto0->IsObject());
9390   CHECK(proto0.As<v8::Object>()->Equals(o1));
9391
9392   Local<Value> proto1 = o1->GetPrototype();
9393   CHECK(proto1->IsObject());
9394   CHECK(proto1.As<v8::Object>()->Equals(o2));
9395
9396   Local<Value> proto2 = o2->GetPrototype();
9397   CHECK(proto2->IsObject());
9398   CHECK(proto2.As<v8::Object>()->Equals(o3));
9399 }
9400
9401
9402 // Getting property names of an object with a prototype chain that
9403 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
9404 // crash the runtime.
9405 THREADED_TEST(Regress91517) {
9406   i::FLAG_allow_natives_syntax = true;
9407   LocalContext context;
9408   v8::Isolate* isolate = context->GetIsolate();
9409   v8::HandleScope handle_scope(isolate);
9410
9411   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9412   t1->SetHiddenPrototype(true);
9413   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9414   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9415   t2->SetHiddenPrototype(true);
9416   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9417   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
9418   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9419   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9420   t3->SetHiddenPrototype(true);
9421   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9422   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
9423   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9424
9425   // Force dictionary-based properties.
9426   i::ScopedVector<char> name_buf(1024);
9427   for (int i = 1; i <= 1000; i++) {
9428     i::SNPrintF(name_buf, "sdf%d", i);
9429     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9430   }
9431
9432   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9433   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9434   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9435   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9436
9437   // Create prototype chain of hidden prototypes.
9438   CHECK(o4->SetPrototype(o3));
9439   CHECK(o3->SetPrototype(o2));
9440   CHECK(o2->SetPrototype(o1));
9441
9442   // Call the runtime version of GetOwnPropertyNames() on the natively
9443   // created object through JavaScript.
9444   context->Global()->Set(v8_str("obj"), o4);
9445   // PROPERTY_ATTRIBUTES_NONE = 0
9446   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9447
9448   ExpectInt32("names.length", 1006);
9449   ExpectTrue("names.indexOf(\"baz\") >= 0");
9450   ExpectTrue("names.indexOf(\"boo\") >= 0");
9451   ExpectTrue("names.indexOf(\"foo\") >= 0");
9452   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9453   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9454   ExpectFalse("names[1005] == undefined");
9455 }
9456
9457
9458 // Getting property names of an object with a hidden and inherited
9459 // prototype should not duplicate the accessor properties inherited.
9460 THREADED_TEST(Regress269562) {
9461   i::FLAG_allow_natives_syntax = true;
9462   LocalContext context;
9463   v8::HandleScope handle_scope(context->GetIsolate());
9464
9465   Local<v8::FunctionTemplate> t1 =
9466       v8::FunctionTemplate::New(context->GetIsolate());
9467   t1->SetHiddenPrototype(true);
9468
9469   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
9470   i1->SetAccessor(v8_str("foo"),
9471                   SimpleAccessorGetter, SimpleAccessorSetter);
9472   i1->SetAccessor(v8_str("bar"),
9473                   SimpleAccessorGetter, SimpleAccessorSetter);
9474   i1->SetAccessor(v8_str("baz"),
9475                   SimpleAccessorGetter, SimpleAccessorSetter);
9476   i1->Set(v8_str("n1"), v8_num(1));
9477   i1->Set(v8_str("n2"), v8_num(2));
9478
9479   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9480   Local<v8::FunctionTemplate> t2 =
9481       v8::FunctionTemplate::New(context->GetIsolate());
9482   t2->SetHiddenPrototype(true);
9483
9484   // Inherit from t1 and mark prototype as hidden.
9485   t2->Inherit(t1);
9486   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
9487
9488   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9489   CHECK(o2->SetPrototype(o1));
9490
9491   v8::Local<v8::Symbol> sym =
9492       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
9493   o1->Set(sym, v8_num(3));
9494   o1->SetHiddenValue(
9495       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
9496
9497   // Call the runtime version of GetOwnPropertyNames() on
9498   // the natively created object through JavaScript.
9499   context->Global()->Set(v8_str("obj"), o2);
9500   context->Global()->Set(v8_str("sym"), sym);
9501   // PROPERTY_ATTRIBUTES_NONE = 0
9502   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9503
9504   ExpectInt32("names.length", 7);
9505   ExpectTrue("names.indexOf(\"foo\") >= 0");
9506   ExpectTrue("names.indexOf(\"bar\") >= 0");
9507   ExpectTrue("names.indexOf(\"baz\") >= 0");
9508   ExpectTrue("names.indexOf(\"n1\") >= 0");
9509   ExpectTrue("names.indexOf(\"n2\") >= 0");
9510   ExpectTrue("names.indexOf(sym) >= 0");
9511   ExpectTrue("names.indexOf(\"mine\") >= 0");
9512 }
9513
9514
9515 THREADED_TEST(FunctionReadOnlyPrototype) {
9516   LocalContext context;
9517   v8::Isolate* isolate = context->GetIsolate();
9518   v8::HandleScope handle_scope(isolate);
9519
9520   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9521   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9522   t1->ReadOnlyPrototype();
9523   context->Global()->Set(v8_str("func1"), t1->GetFunction());
9524   // Configured value of ReadOnly flag.
9525   CHECK(CompileRun(
9526       "(function() {"
9527       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9528       "  return (descriptor['writable'] == false);"
9529       "})()")->BooleanValue());
9530   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9531   CHECK_EQ(42,
9532            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9533
9534   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9535   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9536   context->Global()->Set(v8_str("func2"), t2->GetFunction());
9537   // Default value of ReadOnly flag.
9538   CHECK(CompileRun(
9539       "(function() {"
9540       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9541       "  return (descriptor['writable'] == true);"
9542       "})()")->BooleanValue());
9543   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9544 }
9545
9546
9547 THREADED_TEST(SetPrototypeThrows) {
9548   LocalContext context;
9549   v8::Isolate* isolate = context->GetIsolate();
9550   v8::HandleScope handle_scope(isolate);
9551
9552   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9553
9554   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9555   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9556
9557   CHECK(o0->SetPrototype(o1));
9558   // If setting the prototype leads to the cycle, SetPrototype should
9559   // return false and keep VM in sane state.
9560   v8::TryCatch try_catch(isolate);
9561   CHECK(!o1->SetPrototype(o0));
9562   CHECK(!try_catch.HasCaught());
9563   DCHECK(!CcTest::i_isolate()->has_pending_exception());
9564
9565   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9566 }
9567
9568
9569 THREADED_TEST(FunctionRemovePrototype) {
9570   LocalContext context;
9571   v8::Isolate* isolate = context->GetIsolate();
9572   v8::HandleScope handle_scope(isolate);
9573
9574   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9575   t1->RemovePrototype();
9576   Local<v8::Function> fun = t1->GetFunction();
9577   context->Global()->Set(v8_str("fun"), fun);
9578   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9579
9580   v8::TryCatch try_catch(isolate);
9581   CompileRun("new fun()");
9582   CHECK(try_catch.HasCaught());
9583
9584   try_catch.Reset();
9585   fun->NewInstance();
9586   CHECK(try_catch.HasCaught());
9587 }
9588
9589
9590 THREADED_TEST(GetterSetterExceptions) {
9591   LocalContext context;
9592   v8::Isolate* isolate = context->GetIsolate();
9593   v8::HandleScope handle_scope(isolate);
9594   CompileRun(
9595       "function Foo() { };"
9596       "function Throw() { throw 5; };"
9597       "var x = { };"
9598       "x.__defineSetter__('set', Throw);"
9599       "x.__defineGetter__('get', Throw);");
9600   Local<v8::Object> x =
9601       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9602   v8::TryCatch try_catch(isolate);
9603   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9604   x->Get(v8_str("get"));
9605   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9606   x->Get(v8_str("get"));
9607   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9608   x->Get(v8_str("get"));
9609   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9610   x->Get(v8_str("get"));
9611 }
9612
9613
9614 THREADED_TEST(Constructor) {
9615   LocalContext context;
9616   v8::Isolate* isolate = context->GetIsolate();
9617   v8::HandleScope handle_scope(isolate);
9618   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9619   templ->SetClassName(v8_str("Fun"));
9620   Local<Function> cons = templ->GetFunction();
9621   context->Global()->Set(v8_str("Fun"), cons);
9622   Local<v8::Object> inst = cons->NewInstance();
9623   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9624   CHECK(obj->IsJSObject());
9625   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9626   CHECK(value->BooleanValue());
9627 }
9628
9629
9630 static void ConstructorCallback(
9631     const v8::FunctionCallbackInfo<v8::Value>& args) {
9632   ApiTestFuzzer::Fuzz();
9633   Local<Object> This;
9634
9635   if (args.IsConstructCall()) {
9636     Local<Object> Holder = args.Holder();
9637     This = Object::New(args.GetIsolate());
9638     Local<Value> proto = Holder->GetPrototype();
9639     if (proto->IsObject()) {
9640       This->SetPrototype(proto);
9641     }
9642   } else {
9643     This = args.This();
9644   }
9645
9646   This->Set(v8_str("a"), args[0]);
9647   args.GetReturnValue().Set(This);
9648 }
9649
9650
9651 static void FakeConstructorCallback(
9652     const v8::FunctionCallbackInfo<v8::Value>& args) {
9653   ApiTestFuzzer::Fuzz();
9654   args.GetReturnValue().Set(args[0]);
9655 }
9656
9657
9658 THREADED_TEST(ConstructorForObject) {
9659   LocalContext context;
9660   v8::Isolate* isolate = context->GetIsolate();
9661   v8::HandleScope handle_scope(isolate);
9662
9663   {
9664     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9665     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9666     Local<Object> instance = instance_template->NewInstance();
9667     context->Global()->Set(v8_str("obj"), instance);
9668     v8::TryCatch try_catch(isolate);
9669     Local<Value> value;
9670     CHECK(!try_catch.HasCaught());
9671
9672     // Call the Object's constructor with a 32-bit signed integer.
9673     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9674     CHECK(!try_catch.HasCaught());
9675     CHECK(value->IsInt32());
9676     CHECK_EQ(28, value->Int32Value());
9677
9678     Local<Value> args1[] = {v8_num(28)};
9679     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9680     CHECK(value_obj1->IsObject());
9681     Local<Object> object1 = Local<Object>::Cast(value_obj1);
9682     value = object1->Get(v8_str("a"));
9683     CHECK(value->IsInt32());
9684     CHECK(!try_catch.HasCaught());
9685     CHECK_EQ(28, value->Int32Value());
9686
9687     // Call the Object's constructor with a String.
9688     value =
9689         CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
9690     CHECK(!try_catch.HasCaught());
9691     CHECK(value->IsString());
9692     String::Utf8Value string_value1(value->ToString(isolate));
9693     CHECK_EQ(0, strcmp("tipli", *string_value1));
9694
9695     Local<Value> args2[] = {v8_str("tipli")};
9696     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9697     CHECK(value_obj2->IsObject());
9698     Local<Object> object2 = Local<Object>::Cast(value_obj2);
9699     value = object2->Get(v8_str("a"));
9700     CHECK(!try_catch.HasCaught());
9701     CHECK(value->IsString());
9702     String::Utf8Value string_value2(value->ToString(isolate));
9703     CHECK_EQ(0, strcmp("tipli", *string_value2));
9704
9705     // Call the Object's constructor with a Boolean.
9706     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9707     CHECK(!try_catch.HasCaught());
9708     CHECK(value->IsBoolean());
9709     CHECK_EQ(true, value->BooleanValue());
9710
9711     Handle<Value> args3[] = {v8::True(isolate)};
9712     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9713     CHECK(value_obj3->IsObject());
9714     Local<Object> object3 = Local<Object>::Cast(value_obj3);
9715     value = object3->Get(v8_str("a"));
9716     CHECK(!try_catch.HasCaught());
9717     CHECK(value->IsBoolean());
9718     CHECK_EQ(true, value->BooleanValue());
9719
9720     // Call the Object's constructor with undefined.
9721     Handle<Value> args4[] = {v8::Undefined(isolate)};
9722     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9723     CHECK(value_obj4->IsObject());
9724     Local<Object> object4 = Local<Object>::Cast(value_obj4);
9725     value = object4->Get(v8_str("a"));
9726     CHECK(!try_catch.HasCaught());
9727     CHECK(value->IsUndefined());
9728
9729     // Call the Object's constructor with null.
9730     Handle<Value> args5[] = {v8::Null(isolate)};
9731     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9732     CHECK(value_obj5->IsObject());
9733     Local<Object> object5 = Local<Object>::Cast(value_obj5);
9734     value = object5->Get(v8_str("a"));
9735     CHECK(!try_catch.HasCaught());
9736     CHECK(value->IsNull());
9737   }
9738
9739   // Check exception handling when there is no constructor set for the Object.
9740   {
9741     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9742     Local<Object> instance = instance_template->NewInstance();
9743     context->Global()->Set(v8_str("obj2"), instance);
9744     v8::TryCatch try_catch(isolate);
9745     Local<Value> value;
9746     CHECK(!try_catch.HasCaught());
9747
9748     value = CompileRun("new obj2(28)");
9749     CHECK(try_catch.HasCaught());
9750     String::Utf8Value exception_value1(try_catch.Exception());
9751     CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
9752     try_catch.Reset();
9753
9754     Local<Value> args[] = {v8_num(29)};
9755     value = instance->CallAsConstructor(1, args);
9756     CHECK(try_catch.HasCaught());
9757     String::Utf8Value exception_value2(try_catch.Exception());
9758     CHECK_EQ(
9759         0, strcmp("TypeError: #<Object> is not a function", *exception_value2));
9760     try_catch.Reset();
9761   }
9762
9763   // Check the case when constructor throws exception.
9764   {
9765     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9766     instance_template->SetCallAsFunctionHandler(ThrowValue);
9767     Local<Object> instance = instance_template->NewInstance();
9768     context->Global()->Set(v8_str("obj3"), instance);
9769     v8::TryCatch try_catch(isolate);
9770     Local<Value> value;
9771     CHECK(!try_catch.HasCaught());
9772
9773     value = CompileRun("new obj3(22)");
9774     CHECK(try_catch.HasCaught());
9775     String::Utf8Value exception_value1(try_catch.Exception());
9776     CHECK_EQ(0, strcmp("22", *exception_value1));
9777     try_catch.Reset();
9778
9779     Local<Value> args[] = {v8_num(23)};
9780     value = instance->CallAsConstructor(1, args);
9781     CHECK(try_catch.HasCaught());
9782     String::Utf8Value exception_value2(try_catch.Exception());
9783     CHECK_EQ(0, strcmp("23", *exception_value2));
9784     try_catch.Reset();
9785   }
9786
9787   // Check whether constructor returns with an object or non-object.
9788   {
9789     Local<FunctionTemplate> function_template =
9790         FunctionTemplate::New(isolate, FakeConstructorCallback);
9791     Local<Function> function = function_template->GetFunction();
9792     Local<Object> instance1 = function;
9793     context->Global()->Set(v8_str("obj4"), instance1);
9794     v8::TryCatch try_catch(isolate);
9795     Local<Value> value;
9796     CHECK(!try_catch.HasCaught());
9797
9798     CHECK(instance1->IsObject());
9799     CHECK(instance1->IsFunction());
9800
9801     value = CompileRun("new obj4(28)");
9802     CHECK(!try_catch.HasCaught());
9803     CHECK(value->IsObject());
9804
9805     Local<Value> args1[] = {v8_num(28)};
9806     value = instance1->CallAsConstructor(1, args1);
9807     CHECK(!try_catch.HasCaught());
9808     CHECK(value->IsObject());
9809
9810     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9811     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9812     Local<Object> instance2 = instance_template->NewInstance();
9813     context->Global()->Set(v8_str("obj5"), instance2);
9814     CHECK(!try_catch.HasCaught());
9815
9816     CHECK(instance2->IsObject());
9817     CHECK(!instance2->IsFunction());
9818
9819     value = CompileRun("new obj5(28)");
9820     CHECK(!try_catch.HasCaught());
9821     CHECK(!value->IsObject());
9822
9823     Local<Value> args2[] = {v8_num(28)};
9824     value = instance2->CallAsConstructor(1, args2);
9825     CHECK(!try_catch.HasCaught());
9826     CHECK(!value->IsObject());
9827   }
9828 }
9829
9830
9831 THREADED_TEST(FunctionDescriptorException) {
9832   LocalContext context;
9833   v8::Isolate* isolate = context->GetIsolate();
9834   v8::HandleScope handle_scope(isolate);
9835   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9836   templ->SetClassName(v8_str("Fun"));
9837   Local<Function> cons = templ->GetFunction();
9838   context->Global()->Set(v8_str("Fun"), cons);
9839   Local<Value> value = CompileRun(
9840       "function test() {"
9841       "  try {"
9842       "    (new Fun()).blah()"
9843       "  } catch (e) {"
9844       "    var str = String(e);"
9845       // "    if (str.indexOf('TypeError') == -1) return 1;"
9846       // "    if (str.indexOf('[object Fun]') != -1) return 2;"
9847       // "    if (str.indexOf('#<Fun>') == -1) return 3;"
9848       "    return 0;"
9849       "  }"
9850       "  return 4;"
9851       "}"
9852       "test();");
9853   CHECK_EQ(0, value->Int32Value());
9854 }
9855
9856
9857 THREADED_TEST(EvalAliasedDynamic) {
9858   LocalContext current;
9859   v8::HandleScope scope(current->GetIsolate());
9860
9861   // Tests where aliased eval can only be resolved dynamically.
9862   Local<Script> script = v8_compile(
9863       "function f(x) { "
9864       "  var foo = 2;"
9865       "  with (x) { return eval('foo'); }"
9866       "}"
9867       "foo = 0;"
9868       "result1 = f(new Object());"
9869       "result2 = f(this);"
9870       "var x = new Object();"
9871       "x.eval = function(x) { return 1; };"
9872       "result3 = f(x);");
9873   script->Run();
9874   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9875   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9876   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9877
9878   v8::TryCatch try_catch(current->GetIsolate());
9879   script = v8_compile(
9880       "function f(x) { "
9881       "  var bar = 2;"
9882       "  with (x) { return eval('bar'); }"
9883       "}"
9884       "result4 = f(this)");
9885   script->Run();
9886   CHECK(!try_catch.HasCaught());
9887   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9888
9889   try_catch.Reset();
9890 }
9891
9892
9893 THREADED_TEST(CrossEval) {
9894   v8::HandleScope scope(CcTest::isolate());
9895   LocalContext other;
9896   LocalContext current;
9897
9898   Local<String> token = v8_str("<security token>");
9899   other->SetSecurityToken(token);
9900   current->SetSecurityToken(token);
9901
9902   // Set up reference from current to other.
9903   current->Global()->Set(v8_str("other"), other->Global());
9904
9905   // Check that new variables are introduced in other context.
9906   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
9907   script->Run();
9908   Local<Value> foo = other->Global()->Get(v8_str("foo"));
9909   CHECK_EQ(1234, foo->Int32Value());
9910   CHECK(!current->Global()->Has(v8_str("foo")));
9911
9912   // Check that writing to non-existing properties introduces them in
9913   // the other context.
9914   script = v8_compile("other.eval('na = 1234')");
9915   script->Run();
9916   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9917   CHECK(!current->Global()->Has(v8_str("na")));
9918
9919   // Check that global variables in current context are not visible in other
9920   // context.
9921   v8::TryCatch try_catch(CcTest::isolate());
9922   script = v8_compile("var bar = 42; other.eval('bar');");
9923   Local<Value> result = script->Run();
9924   CHECK(try_catch.HasCaught());
9925   try_catch.Reset();
9926
9927   // Check that local variables in current context are not visible in other
9928   // context.
9929   script = v8_compile(
9930       "(function() { "
9931       "  var baz = 87;"
9932       "  return other.eval('baz');"
9933       "})();");
9934   result = script->Run();
9935   CHECK(try_catch.HasCaught());
9936   try_catch.Reset();
9937
9938   // Check that global variables in the other environment are visible
9939   // when evaluting code.
9940   other->Global()->Set(v8_str("bis"), v8_num(1234));
9941   script = v8_compile("other.eval('bis')");
9942   CHECK_EQ(1234, script->Run()->Int32Value());
9943   CHECK(!try_catch.HasCaught());
9944
9945   // Check that the 'this' pointer points to the global object evaluating
9946   // code.
9947   other->Global()->Set(v8_str("t"), other->Global());
9948   script = v8_compile("other.eval('this == t')");
9949   result = script->Run();
9950   CHECK(result->IsTrue());
9951   CHECK(!try_catch.HasCaught());
9952
9953   // Check that variables introduced in with-statement are not visible in
9954   // other context.
9955   script = v8_compile("with({x:2}){other.eval('x')}");
9956   result = script->Run();
9957   CHECK(try_catch.HasCaught());
9958   try_catch.Reset();
9959
9960   // Check that you cannot use 'eval.call' with another object than the
9961   // current global object.
9962   script = v8_compile("other.y = 1; eval.call(other, 'y')");
9963   result = script->Run();
9964   CHECK(try_catch.HasCaught());
9965 }
9966
9967
9968 // Test that calling eval in a context which has been detached from
9969 // its global proxy works.
9970 THREADED_TEST(EvalInDetachedGlobal) {
9971   v8::Isolate* isolate = CcTest::isolate();
9972   v8::HandleScope scope(isolate);
9973
9974   v8::Local<Context> context0 = Context::New(isolate);
9975   v8::Local<Context> context1 = Context::New(isolate);
9976
9977   // Set up function in context0 that uses eval from context0.
9978   context0->Enter();
9979   v8::Handle<v8::Value> fun = CompileRun(
9980       "var x = 42;"
9981       "(function() {"
9982       "  var e = eval;"
9983       "  return function(s) { return e(s); }"
9984       "})()");
9985   context0->Exit();
9986
9987   // Put the function into context1 and call it before and after
9988   // detaching the global.  Before detaching, the call succeeds and
9989   // after detaching and exception is thrown.
9990   context1->Enter();
9991   context1->Global()->Set(v8_str("fun"), fun);
9992   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
9993   CHECK_EQ(42, x_value->Int32Value());
9994   context0->DetachGlobal();
9995   v8::TryCatch catcher(isolate);
9996   x_value = CompileRun("fun('x')");
9997   CHECK_EQ(42, x_value->Int32Value());
9998   context1->Exit();
9999 }
10000
10001
10002 THREADED_TEST(CrossLazyLoad) {
10003   v8::HandleScope scope(CcTest::isolate());
10004   LocalContext other;
10005   LocalContext current;
10006
10007   Local<String> token = v8_str("<security token>");
10008   other->SetSecurityToken(token);
10009   current->SetSecurityToken(token);
10010
10011   // Set up reference from current to other.
10012   current->Global()->Set(v8_str("other"), other->Global());
10013
10014   // Trigger lazy loading in other context.
10015   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10016   Local<Value> value = script->Run();
10017   CHECK_EQ(42.0, value->NumberValue());
10018 }
10019
10020
10021 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10022   ApiTestFuzzer::Fuzz();
10023   if (args.IsConstructCall()) {
10024     if (args[0]->IsInt32()) {
10025       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10026       return;
10027     }
10028   }
10029
10030   args.GetReturnValue().Set(args[0]);
10031 }
10032
10033
10034 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10035   args.GetReturnValue().Set(args.This());
10036 }
10037
10038
10039 // Test that a call handler can be set for objects which will allow
10040 // non-function objects created through the API to be called as
10041 // functions.
10042 THREADED_TEST(CallAsFunction) {
10043   LocalContext context;
10044   v8::Isolate* isolate = context->GetIsolate();
10045   v8::HandleScope scope(isolate);
10046
10047   {
10048     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10049     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10050     instance_template->SetCallAsFunctionHandler(call_as_function);
10051     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10052     context->Global()->Set(v8_str("obj"), instance);
10053     v8::TryCatch try_catch(isolate);
10054     Local<Value> value;
10055     CHECK(!try_catch.HasCaught());
10056
10057     value = CompileRun("obj(42)");
10058     CHECK(!try_catch.HasCaught());
10059     CHECK_EQ(42, value->Int32Value());
10060
10061     value = CompileRun("(function(o){return o(49)})(obj)");
10062     CHECK(!try_catch.HasCaught());
10063     CHECK_EQ(49, value->Int32Value());
10064
10065     // test special case of call as function
10066     value = CompileRun("[obj]['0'](45)");
10067     CHECK(!try_catch.HasCaught());
10068     CHECK_EQ(45, value->Int32Value());
10069
10070     value = CompileRun(
10071         "obj.call = Function.prototype.call;"
10072         "obj.call(null, 87)");
10073     CHECK(!try_catch.HasCaught());
10074     CHECK_EQ(87, value->Int32Value());
10075
10076     // Regression tests for bug #1116356: Calling call through call/apply
10077     // must work for non-function receivers.
10078     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10079     value = CompileRun(apply_99);
10080     CHECK(!try_catch.HasCaught());
10081     CHECK_EQ(99, value->Int32Value());
10082
10083     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10084     value = CompileRun(call_17);
10085     CHECK(!try_catch.HasCaught());
10086     CHECK_EQ(17, value->Int32Value());
10087
10088     // Check that the call-as-function handler can be called through
10089     // new.
10090     value = CompileRun("new obj(43)");
10091     CHECK(!try_catch.HasCaught());
10092     CHECK_EQ(-43, value->Int32Value());
10093
10094     // Check that the call-as-function handler can be called through
10095     // the API.
10096     v8::Handle<Value> args[] = {v8_num(28)};
10097     value = instance->CallAsFunction(instance, 1, args);
10098     CHECK(!try_catch.HasCaught());
10099     CHECK_EQ(28, value->Int32Value());
10100   }
10101
10102   {
10103     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10104     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10105     USE(instance_template);
10106     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10107     context->Global()->Set(v8_str("obj2"), instance);
10108     v8::TryCatch try_catch(isolate);
10109     Local<Value> value;
10110     CHECK(!try_catch.HasCaught());
10111
10112     // Call an object without call-as-function handler through the JS
10113     value = CompileRun("obj2(28)");
10114     CHECK(value.IsEmpty());
10115     CHECK(try_catch.HasCaught());
10116     String::Utf8Value exception_value1(try_catch.Exception());
10117     // TODO(verwaest): Better message
10118     CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
10119     try_catch.Reset();
10120
10121     // Call an object without call-as-function handler through the API
10122     value = CompileRun("obj2(28)");
10123     v8::Handle<Value> args[] = {v8_num(28)};
10124     value = instance->CallAsFunction(instance, 1, args);
10125     CHECK(value.IsEmpty());
10126     CHECK(try_catch.HasCaught());
10127     String::Utf8Value exception_value2(try_catch.Exception());
10128     CHECK_EQ(0, strcmp("TypeError: [object Object] is not a function",
10129                        *exception_value2));
10130     try_catch.Reset();
10131   }
10132
10133   {
10134     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10135     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10136     instance_template->SetCallAsFunctionHandler(ThrowValue);
10137     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10138     context->Global()->Set(v8_str("obj3"), instance);
10139     v8::TryCatch try_catch(isolate);
10140     Local<Value> value;
10141     CHECK(!try_catch.HasCaught());
10142
10143     // Catch the exception which is thrown by call-as-function handler
10144     value = CompileRun("obj3(22)");
10145     CHECK(try_catch.HasCaught());
10146     String::Utf8Value exception_value1(try_catch.Exception());
10147     CHECK_EQ(0, strcmp("22", *exception_value1));
10148     try_catch.Reset();
10149
10150     v8::Handle<Value> args[] = {v8_num(23)};
10151     value = instance->CallAsFunction(instance, 1, args);
10152     CHECK(try_catch.HasCaught());
10153     String::Utf8Value exception_value2(try_catch.Exception());
10154     CHECK_EQ(0, strcmp("23", *exception_value2));
10155     try_catch.Reset();
10156   }
10157
10158   {
10159     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10160     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10161     instance_template->SetCallAsFunctionHandler(ReturnThis);
10162     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10163
10164     Local<v8::Value> a1 =
10165         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10166     CHECK(a1->StrictEquals(instance));
10167     Local<v8::Value> a2 = instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10168     CHECK(a2->StrictEquals(instance));
10169     Local<v8::Value> a3 = instance->CallAsFunction(v8_num(42), 0, NULL);
10170     CHECK(a3->StrictEquals(instance));
10171     Local<v8::Value> a4 = instance->CallAsFunction(v8_str("hello"), 0, NULL);
10172     CHECK(a4->StrictEquals(instance));
10173     Local<v8::Value> a5 = instance->CallAsFunction(v8::True(isolate), 0, NULL);
10174     CHECK(a5->StrictEquals(instance));
10175   }
10176
10177   {
10178     CompileRun(
10179         "function ReturnThisSloppy() {"
10180         "  return this;"
10181         "}"
10182         "function ReturnThisStrict() {"
10183         "  'use strict';"
10184         "  return this;"
10185         "}");
10186     Local<Function> ReturnThisSloppy = Local<Function>::Cast(
10187         context->Global()->Get(v8_str("ReturnThisSloppy")));
10188     Local<Function> ReturnThisStrict = Local<Function>::Cast(
10189         context->Global()->Get(v8_str("ReturnThisStrict")));
10190
10191     Local<v8::Value> a1 =
10192         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10193     CHECK(a1->StrictEquals(context->Global()));
10194     Local<v8::Value> a2 =
10195         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10196     CHECK(a2->StrictEquals(context->Global()));
10197     Local<v8::Value> a3 = ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10198     CHECK(a3->IsNumberObject());
10199     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10200     Local<v8::Value> a4 =
10201         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10202     CHECK(a4->IsStringObject());
10203     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10204     Local<v8::Value> a5 =
10205         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10206     CHECK(a5->IsBooleanObject());
10207     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10208
10209     Local<v8::Value> a6 =
10210         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10211     CHECK(a6->IsUndefined());
10212     Local<v8::Value> a7 =
10213         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10214     CHECK(a7->IsNull());
10215     Local<v8::Value> a8 = ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10216     CHECK(a8->StrictEquals(v8_num(42)));
10217     Local<v8::Value> a9 =
10218         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10219     CHECK(a9->StrictEquals(v8_str("hello")));
10220     Local<v8::Value> a10 =
10221         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10222     CHECK(a10->StrictEquals(v8::True(isolate)));
10223   }
10224 }
10225
10226
10227 // Check whether a non-function object is callable.
10228 THREADED_TEST(CallableObject) {
10229   LocalContext context;
10230   v8::Isolate* isolate = context->GetIsolate();
10231   v8::HandleScope scope(isolate);
10232
10233   {
10234     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10235     instance_template->SetCallAsFunctionHandler(call_as_function);
10236     Local<Object> instance = instance_template->NewInstance();
10237     v8::TryCatch try_catch(isolate);
10238
10239     CHECK(instance->IsCallable());
10240     CHECK(!try_catch.HasCaught());
10241   }
10242
10243   {
10244     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10245     Local<Object> instance = instance_template->NewInstance();
10246     v8::TryCatch try_catch(isolate);
10247
10248     CHECK(!instance->IsCallable());
10249     CHECK(!try_catch.HasCaught());
10250   }
10251
10252   {
10253     Local<FunctionTemplate> function_template =
10254         FunctionTemplate::New(isolate, call_as_function);
10255     Local<Function> function = function_template->GetFunction();
10256     Local<Object> instance = function;
10257     v8::TryCatch try_catch(isolate);
10258
10259     CHECK(instance->IsCallable());
10260     CHECK(!try_catch.HasCaught());
10261   }
10262
10263   {
10264     Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10265     Local<Function> function = function_template->GetFunction();
10266     Local<Object> instance = function;
10267     v8::TryCatch try_catch(isolate);
10268
10269     CHECK(instance->IsCallable());
10270     CHECK(!try_catch.HasCaught());
10271   }
10272 }
10273
10274
10275 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
10276   v8::HandleScope scope(isolate);
10277   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
10278   for (int i = 0; i < iterations; i++) {
10279     Local<v8::Number> n(v8::Integer::New(isolate, 42));
10280   }
10281   return Recurse(isolate, depth - 1, iterations);
10282 }
10283
10284
10285 THREADED_TEST(HandleIteration) {
10286   static const int kIterations = 500;
10287   static const int kNesting = 200;
10288   LocalContext context;
10289   v8::Isolate* isolate = context->GetIsolate();
10290   v8::HandleScope scope0(isolate);
10291   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10292   {
10293     v8::HandleScope scope1(isolate);
10294     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10295     for (int i = 0; i < kIterations; i++) {
10296       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10297       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
10298     }
10299
10300     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10301     {
10302       v8::HandleScope scope2(CcTest::isolate());
10303       for (int j = 0; j < kIterations; j++) {
10304         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10305         CHECK_EQ(j + 1 + kIterations,
10306                  v8::HandleScope::NumberOfHandles(isolate));
10307       }
10308     }
10309     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10310   }
10311   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10312   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
10313 }
10314
10315
10316 static void InterceptorCallICFastApi(
10317     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
10318   ApiTestFuzzer::Fuzz();
10319   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10320   int* call_count =
10321       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10322   ++(*call_count);
10323   if ((*call_count) % 20 == 0) {
10324     CcTest::heap()->CollectAllGarbage();
10325   }
10326 }
10327
10328 static void FastApiCallback_TrivialSignature(
10329     const v8::FunctionCallbackInfo<v8::Value>& args) {
10330   ApiTestFuzzer::Fuzz();
10331   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10332   v8::Isolate* isolate = CcTest::isolate();
10333   CHECK_EQ(isolate, args.GetIsolate());
10334   CHECK(args.This()->Equals(args.Holder()));
10335   CHECK(args.Data()->Equals(v8_str("method_data")));
10336   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10337 }
10338
10339 static void FastApiCallback_SimpleSignature(
10340     const v8::FunctionCallbackInfo<v8::Value>& args) {
10341   ApiTestFuzzer::Fuzz();
10342   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10343   v8::Isolate* isolate = CcTest::isolate();
10344   CHECK_EQ(isolate, args.GetIsolate());
10345   CHECK(args.This()->GetPrototype()->Equals(args.Holder()));
10346   CHECK(args.Data()->Equals(v8_str("method_data")));
10347   // Note, we're using HasRealNamedProperty instead of Has to avoid
10348   // invoking the interceptor again.
10349   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10350   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10351 }
10352
10353
10354 // Helper to maximize the odds of object moving.
10355 static void GenerateSomeGarbage() {
10356   CompileRun(
10357       "var garbage;"
10358       "for (var i = 0; i < 1000; i++) {"
10359       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10360       "}"
10361       "garbage = undefined;");
10362 }
10363
10364
10365 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10366   static int count = 0;
10367   if (count++ % 3 == 0) {
10368     CcTest::heap()->CollectAllGarbage();
10369         // This should move the stub
10370     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
10371   }
10372 }
10373
10374
10375 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10376   LocalContext context;
10377   v8::Isolate* isolate = context->GetIsolate();
10378   v8::HandleScope scope(isolate);
10379   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10380       v8::ObjectTemplate::New(isolate);
10381   nativeobject_templ->Set(isolate, "callback",
10382                           v8::FunctionTemplate::New(isolate,
10383                                                     DirectApiCallback));
10384   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10385   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10386   // call the api function multiple times to ensure direct call stub creation.
10387   CompileRun(
10388         "function f() {"
10389         "  for (var i = 1; i <= 30; i++) {"
10390         "    nativeobject.callback();"
10391         "  }"
10392         "}"
10393         "f();");
10394 }
10395
10396
10397 void ThrowingDirectApiCallback(
10398     const v8::FunctionCallbackInfo<v8::Value>& args) {
10399   args.GetIsolate()->ThrowException(v8_str("g"));
10400 }
10401
10402
10403 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10404   LocalContext context;
10405   v8::Isolate* isolate = context->GetIsolate();
10406   v8::HandleScope scope(isolate);
10407   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10408       v8::ObjectTemplate::New(isolate);
10409   nativeobject_templ->Set(isolate, "callback",
10410                           v8::FunctionTemplate::New(isolate,
10411                                                     ThrowingDirectApiCallback));
10412   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10413   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10414   // call the api function multiple times to ensure direct call stub creation.
10415   v8::Handle<Value> result = CompileRun(
10416       "var result = '';"
10417       "function f() {"
10418       "  for (var i = 1; i <= 5; i++) {"
10419       "    try { nativeobject.callback(); } catch (e) { result += e; }"
10420       "  }"
10421       "}"
10422       "f(); result;");
10423   CHECK(v8_str("ggggg")->Equals(result));
10424 }
10425
10426
10427 static int p_getter_count_3;
10428
10429
10430 static Handle<Value> DoDirectGetter() {
10431   if (++p_getter_count_3 % 3 == 0) {
10432     CcTest::heap()->CollectAllGarbage();
10433     GenerateSomeGarbage();
10434   }
10435   return v8_str("Direct Getter Result");
10436 }
10437
10438
10439 static void DirectGetterCallback(
10440     Local<String> name,
10441     const v8::PropertyCallbackInfo<v8::Value>& info) {
10442   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10443   info.GetReturnValue().Set(DoDirectGetter());
10444 }
10445
10446
10447 template<typename Accessor>
10448 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10449   LocalContext context;
10450   v8::Isolate* isolate = context->GetIsolate();
10451   v8::HandleScope scope(isolate);
10452   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10453   obj->SetAccessor(v8_str("p1"), accessor);
10454   context->Global()->Set(v8_str("o1"), obj->NewInstance());
10455   p_getter_count_3 = 0;
10456   v8::Handle<v8::Value> result = CompileRun(
10457       "function f() {"
10458       "  for (var i = 0; i < 30; i++) o1.p1;"
10459       "  return o1.p1"
10460       "}"
10461       "f();");
10462   CHECK(v8_str("Direct Getter Result")->Equals(result));
10463   CHECK_EQ(31, p_getter_count_3);
10464 }
10465
10466
10467 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10468   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10469 }
10470
10471
10472 void ThrowingDirectGetterCallback(
10473     Local<String> name,
10474     const v8::PropertyCallbackInfo<v8::Value>& info) {
10475   info.GetIsolate()->ThrowException(v8_str("g"));
10476 }
10477
10478
10479 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10480   LocalContext context;
10481   v8::Isolate* isolate = context->GetIsolate();
10482   v8::HandleScope scope(isolate);
10483   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10484   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10485   context->Global()->Set(v8_str("o1"), obj->NewInstance());
10486   v8::Handle<Value> result = CompileRun(
10487       "var result = '';"
10488       "for (var i = 0; i < 5; i++) {"
10489       "    try { o1.p1; } catch (e) { result += e; }"
10490       "}"
10491       "result;");
10492   CHECK(v8_str("ggggg")->Equals(result));
10493 }
10494
10495
10496 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10497   int interceptor_call_count = 0;
10498   v8::Isolate* isolate = CcTest::isolate();
10499   v8::HandleScope scope(isolate);
10500   v8::Handle<v8::FunctionTemplate> fun_templ =
10501       v8::FunctionTemplate::New(isolate);
10502   v8::Handle<v8::FunctionTemplate> method_templ =
10503       v8::FunctionTemplate::New(isolate,
10504                                 FastApiCallback_TrivialSignature,
10505                                 v8_str("method_data"),
10506                                 v8::Handle<v8::Signature>());
10507   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10508   proto_templ->Set(v8_str("method"), method_templ);
10509   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10510   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10511       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10512       v8::External::New(isolate, &interceptor_call_count)));
10513   LocalContext context;
10514   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10515   GenerateSomeGarbage();
10516   context->Global()->Set(v8_str("o"), fun->NewInstance());
10517   CompileRun(
10518       "var result = 0;"
10519       "for (var i = 0; i < 100; i++) {"
10520       "  result = o.method(41);"
10521       "}");
10522   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10523   CHECK_EQ(100, interceptor_call_count);
10524 }
10525
10526
10527 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10528   int interceptor_call_count = 0;
10529   v8::Isolate* isolate = CcTest::isolate();
10530   v8::HandleScope scope(isolate);
10531   v8::Handle<v8::FunctionTemplate> fun_templ =
10532       v8::FunctionTemplate::New(isolate);
10533   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10534       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10535       v8::Signature::New(isolate, fun_templ));
10536   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10537   proto_templ->Set(v8_str("method"), method_templ);
10538   fun_templ->SetHiddenPrototype(true);
10539   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10540   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10541       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10542       v8::External::New(isolate, &interceptor_call_count)));
10543   LocalContext context;
10544   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10545   GenerateSomeGarbage();
10546   context->Global()->Set(v8_str("o"), fun->NewInstance());
10547   CompileRun(
10548       "o.foo = 17;"
10549       "var receiver = {};"
10550       "receiver.__proto__ = o;"
10551       "var result = 0;"
10552       "for (var i = 0; i < 100; i++) {"
10553       "  result = receiver.method(41);"
10554       "}");
10555   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10556   CHECK_EQ(100, interceptor_call_count);
10557 }
10558
10559
10560 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10561   int interceptor_call_count = 0;
10562   v8::Isolate* isolate = CcTest::isolate();
10563   v8::HandleScope scope(isolate);
10564   v8::Handle<v8::FunctionTemplate> fun_templ =
10565       v8::FunctionTemplate::New(isolate);
10566   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10567       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10568       v8::Signature::New(isolate, fun_templ));
10569   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10570   proto_templ->Set(v8_str("method"), method_templ);
10571   fun_templ->SetHiddenPrototype(true);
10572   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10573   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10574       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10575       v8::External::New(isolate, &interceptor_call_count)));
10576   LocalContext context;
10577   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10578   GenerateSomeGarbage();
10579   context->Global()->Set(v8_str("o"), fun->NewInstance());
10580   CompileRun(
10581       "o.foo = 17;"
10582       "var receiver = {};"
10583       "receiver.__proto__ = o;"
10584       "var result = 0;"
10585       "var saved_result = 0;"
10586       "for (var i = 0; i < 100; i++) {"
10587       "  result = receiver.method(41);"
10588       "  if (i == 50) {"
10589       "    saved_result = result;"
10590       "    receiver = {method: function(x) { return x - 1 }};"
10591       "  }"
10592       "}");
10593   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10594   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10595   CHECK_GE(interceptor_call_count, 50);
10596 }
10597
10598
10599 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
10600   int interceptor_call_count = 0;
10601   v8::Isolate* isolate = CcTest::isolate();
10602   v8::HandleScope scope(isolate);
10603   v8::Handle<v8::FunctionTemplate> fun_templ =
10604       v8::FunctionTemplate::New(isolate);
10605   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10606       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10607       v8::Signature::New(isolate, fun_templ));
10608   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10609   proto_templ->Set(v8_str("method"), method_templ);
10610   fun_templ->SetHiddenPrototype(true);
10611   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10612   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10613       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10614       v8::External::New(isolate, &interceptor_call_count)));
10615   LocalContext context;
10616   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10617   GenerateSomeGarbage();
10618   context->Global()->Set(v8_str("o"), fun->NewInstance());
10619   CompileRun(
10620       "o.foo = 17;"
10621       "var receiver = {};"
10622       "receiver.__proto__ = o;"
10623       "var result = 0;"
10624       "var saved_result = 0;"
10625       "for (var i = 0; i < 100; i++) {"
10626       "  result = receiver.method(41);"
10627       "  if (i == 50) {"
10628       "    saved_result = result;"
10629       "    o.method = function(x) { return x - 1 };"
10630       "  }"
10631       "}");
10632   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10633   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10634   CHECK_GE(interceptor_call_count, 50);
10635 }
10636
10637
10638 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10639   int interceptor_call_count = 0;
10640   v8::Isolate* isolate = CcTest::isolate();
10641   v8::HandleScope scope(isolate);
10642   v8::Handle<v8::FunctionTemplate> fun_templ =
10643       v8::FunctionTemplate::New(isolate);
10644   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10645       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10646       v8::Signature::New(isolate, fun_templ));
10647   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10648   proto_templ->Set(v8_str("method"), method_templ);
10649   fun_templ->SetHiddenPrototype(true);
10650   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10651   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10652       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10653       v8::External::New(isolate, &interceptor_call_count)));
10654   LocalContext context;
10655   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10656   GenerateSomeGarbage();
10657   context->Global()->Set(v8_str("o"), fun->NewInstance());
10658   v8::TryCatch try_catch(isolate);
10659   CompileRun(
10660       "o.foo = 17;"
10661       "var receiver = {};"
10662       "receiver.__proto__ = o;"
10663       "var result = 0;"
10664       "var saved_result = 0;"
10665       "for (var i = 0; i < 100; i++) {"
10666       "  result = receiver.method(41);"
10667       "  if (i == 50) {"
10668       "    saved_result = result;"
10669       "    receiver = 333;"
10670       "  }"
10671       "}");
10672   CHECK(try_catch.HasCaught());
10673   // TODO(verwaest): Adjust message.
10674   CHECK(v8_str("TypeError: receiver.method is not a function")
10675             ->Equals(try_catch.Exception()->ToString(isolate)));
10676   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10677   CHECK_GE(interceptor_call_count, 50);
10678 }
10679
10680
10681 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10682   int interceptor_call_count = 0;
10683   v8::Isolate* isolate = CcTest::isolate();
10684   v8::HandleScope scope(isolate);
10685   v8::Handle<v8::FunctionTemplate> fun_templ =
10686       v8::FunctionTemplate::New(isolate);
10687   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10688       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10689       v8::Signature::New(isolate, fun_templ));
10690   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10691   proto_templ->Set(v8_str("method"), method_templ);
10692   fun_templ->SetHiddenPrototype(true);
10693   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10694   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10695       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10696       v8::External::New(isolate, &interceptor_call_count)));
10697   LocalContext context;
10698   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10699   GenerateSomeGarbage();
10700   context->Global()->Set(v8_str("o"), fun->NewInstance());
10701   v8::TryCatch try_catch(isolate);
10702   CompileRun(
10703       "o.foo = 17;"
10704       "var receiver = {};"
10705       "receiver.__proto__ = o;"
10706       "var result = 0;"
10707       "var saved_result = 0;"
10708       "for (var i = 0; i < 100; i++) {"
10709       "  result = receiver.method(41);"
10710       "  if (i == 50) {"
10711       "    saved_result = result;"
10712       "    receiver = {method: receiver.method};"
10713       "  }"
10714       "}");
10715   CHECK(try_catch.HasCaught());
10716   CHECK(v8_str("TypeError: Illegal invocation")
10717             ->Equals(try_catch.Exception()->ToString(isolate)));
10718   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10719   CHECK_GE(interceptor_call_count, 50);
10720 }
10721
10722
10723 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
10724   v8::Isolate* isolate = CcTest::isolate();
10725   v8::HandleScope scope(isolate);
10726   v8::Handle<v8::FunctionTemplate> fun_templ =
10727       v8::FunctionTemplate::New(isolate);
10728   v8::Handle<v8::FunctionTemplate> method_templ =
10729       v8::FunctionTemplate::New(isolate,
10730                                 FastApiCallback_TrivialSignature,
10731                                 v8_str("method_data"),
10732                                 v8::Handle<v8::Signature>());
10733   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10734   proto_templ->Set(v8_str("method"), method_templ);
10735   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10736   USE(templ);
10737   LocalContext context;
10738   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10739   GenerateSomeGarbage();
10740   context->Global()->Set(v8_str("o"), fun->NewInstance());
10741   CompileRun(
10742       "var result = 0;"
10743       "for (var i = 0; i < 100; i++) {"
10744       "  result = o.method(41);"
10745       "}");
10746
10747   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10748 }
10749
10750
10751 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
10752   v8::Isolate* isolate = CcTest::isolate();
10753   v8::HandleScope scope(isolate);
10754   v8::Handle<v8::FunctionTemplate> fun_templ =
10755       v8::FunctionTemplate::New(isolate);
10756   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10757       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10758       v8::Signature::New(isolate, fun_templ));
10759   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10760   proto_templ->Set(v8_str("method"), method_templ);
10761   fun_templ->SetHiddenPrototype(true);
10762   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10763   CHECK(!templ.IsEmpty());
10764   LocalContext context;
10765   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10766   GenerateSomeGarbage();
10767   context->Global()->Set(v8_str("o"), fun->NewInstance());
10768   CompileRun(
10769       "o.foo = 17;"
10770       "var receiver = {};"
10771       "receiver.__proto__ = o;"
10772       "var result = 0;"
10773       "for (var i = 0; i < 100; i++) {"
10774       "  result = receiver.method(41);"
10775       "}");
10776
10777   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10778 }
10779
10780
10781 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
10782   v8::Isolate* isolate = CcTest::isolate();
10783   v8::HandleScope scope(isolate);
10784   v8::Handle<v8::FunctionTemplate> fun_templ =
10785       v8::FunctionTemplate::New(isolate);
10786   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10787       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10788       v8::Signature::New(isolate, fun_templ));
10789   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10790   proto_templ->Set(v8_str("method"), method_templ);
10791   fun_templ->SetHiddenPrototype(true);
10792   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10793   CHECK(!templ.IsEmpty());
10794   LocalContext context;
10795   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10796   GenerateSomeGarbage();
10797   context->Global()->Set(v8_str("o"), fun->NewInstance());
10798   CompileRun(
10799       "o.foo = 17;"
10800       "var receiver = {};"
10801       "receiver.__proto__ = o;"
10802       "var result = 0;"
10803       "var saved_result = 0;"
10804       "for (var i = 0; i < 100; i++) {"
10805       "  result = receiver.method(41);"
10806       "  if (i == 50) {"
10807       "    saved_result = result;"
10808       "    receiver = {method: function(x) { return x - 1 }};"
10809       "  }"
10810       "}");
10811   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10812   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10813 }
10814
10815
10816 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10817   v8::Isolate* isolate = CcTest::isolate();
10818   v8::HandleScope scope(isolate);
10819   v8::Handle<v8::FunctionTemplate> fun_templ =
10820       v8::FunctionTemplate::New(isolate);
10821   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10822       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10823       v8::Signature::New(isolate, fun_templ));
10824   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10825   proto_templ->Set(v8_str("method"), method_templ);
10826   fun_templ->SetHiddenPrototype(true);
10827   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10828   CHECK(!templ.IsEmpty());
10829   LocalContext context;
10830   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10831   GenerateSomeGarbage();
10832   context->Global()->Set(v8_str("o"), fun->NewInstance());
10833   v8::TryCatch try_catch(isolate);
10834   CompileRun(
10835       "o.foo = 17;"
10836       "var receiver = {};"
10837       "receiver.__proto__ = o;"
10838       "var result = 0;"
10839       "var saved_result = 0;"
10840       "for (var i = 0; i < 100; i++) {"
10841       "  result = receiver.method(41);"
10842       "  if (i == 50) {"
10843       "    saved_result = result;"
10844       "    receiver = 333;"
10845       "  }"
10846       "}");
10847   CHECK(try_catch.HasCaught());
10848   // TODO(verwaest): Adjust message.
10849   CHECK(v8_str("TypeError: receiver.method is not a function")
10850             ->Equals(try_catch.Exception()->ToString(isolate)));
10851   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10852 }
10853
10854
10855 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
10856   v8::Isolate* isolate = CcTest::isolate();
10857   v8::HandleScope scope(isolate);
10858   v8::Handle<v8::FunctionTemplate> fun_templ =
10859       v8::FunctionTemplate::New(isolate);
10860   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10861       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10862       v8::Signature::New(isolate, fun_templ));
10863   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10864   proto_templ->Set(v8_str("method"), method_templ);
10865   fun_templ->SetHiddenPrototype(true);
10866   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10867   CHECK(!templ.IsEmpty());
10868   LocalContext context;
10869   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10870   GenerateSomeGarbage();
10871   context->Global()->Set(v8_str("o"), fun->NewInstance());
10872   v8::TryCatch try_catch(isolate);
10873   CompileRun(
10874       "o.foo = 17;"
10875       "var receiver = {};"
10876       "receiver.__proto__ = o;"
10877       "var result = 0;"
10878       "var saved_result = 0;"
10879       "for (var i = 0; i < 100; i++) {"
10880       "  result = receiver.method(41);"
10881       "  if (i == 50) {"
10882       "    saved_result = result;"
10883       "    receiver = Object.create(receiver);"
10884       "  }"
10885       "}");
10886   CHECK(try_catch.HasCaught());
10887   CHECK(v8_str("TypeError: Illegal invocation")
10888             ->Equals(try_catch.Exception()->ToString(isolate)));
10889   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10890 }
10891
10892
10893 static void ThrowingGetter(Local<String> name,
10894                            const v8::PropertyCallbackInfo<v8::Value>& info) {
10895   ApiTestFuzzer::Fuzz();
10896   info.GetIsolate()->ThrowException(Handle<Value>());
10897   info.GetReturnValue().SetUndefined();
10898 }
10899
10900
10901 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10902   LocalContext context;
10903   HandleScope scope(context->GetIsolate());
10904
10905   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
10906   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10907   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10908
10909   Local<Object> instance = templ->GetFunction()->NewInstance();
10910
10911   Local<Object> another = Object::New(context->GetIsolate());
10912   another->SetPrototype(instance);
10913
10914   Local<Object> with_js_getter = CompileRun(
10915       "o = {};\n"
10916       "o.__defineGetter__('f', function() { throw undefined; });\n"
10917       "o\n").As<Object>();
10918   CHECK(!with_js_getter.IsEmpty());
10919
10920   TryCatch try_catch(context->GetIsolate());
10921
10922   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10923   CHECK(try_catch.HasCaught());
10924   try_catch.Reset();
10925   CHECK(result.IsEmpty());
10926
10927   Maybe<PropertyAttribute> attr =
10928       instance->GetRealNamedPropertyAttributes(v8_str("f"));
10929   CHECK(!try_catch.HasCaught());
10930   CHECK(Just(None) == attr);
10931
10932   result = another->GetRealNamedProperty(v8_str("f"));
10933   CHECK(try_catch.HasCaught());
10934   try_catch.Reset();
10935   CHECK(result.IsEmpty());
10936
10937   attr = another->GetRealNamedPropertyAttributes(v8_str("f"));
10938   CHECK(!try_catch.HasCaught());
10939   CHECK(Just(None) == attr);
10940
10941   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10942   CHECK(try_catch.HasCaught());
10943   try_catch.Reset();
10944   CHECK(result.IsEmpty());
10945
10946   attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f"));
10947   CHECK(!try_catch.HasCaught());
10948   CHECK(Just(None) == attr);
10949
10950   result = another->Get(v8_str("f"));
10951   CHECK(try_catch.HasCaught());
10952   try_catch.Reset();
10953   CHECK(result.IsEmpty());
10954
10955   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10956   CHECK(try_catch.HasCaught());
10957   try_catch.Reset();
10958   CHECK(result.IsEmpty());
10959
10960   attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f"));
10961   CHECK(!try_catch.HasCaught());
10962   CHECK(Just(None) == attr);
10963
10964   result = with_js_getter->Get(v8_str("f"));
10965   CHECK(try_catch.HasCaught());
10966   try_catch.Reset();
10967   CHECK(result.IsEmpty());
10968 }
10969
10970
10971 static void ThrowingCallbackWithTryCatch(
10972     const v8::FunctionCallbackInfo<v8::Value>& args) {
10973   TryCatch try_catch(args.GetIsolate());
10974   // Verboseness is important: it triggers message delivery which can call into
10975   // external code.
10976   try_catch.SetVerbose(true);
10977   CompileRun("throw 'from JS';");
10978   CHECK(try_catch.HasCaught());
10979   CHECK(!CcTest::i_isolate()->has_pending_exception());
10980   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
10981 }
10982
10983
10984 static int call_depth;
10985
10986
10987 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10988   TryCatch try_catch(CcTest::isolate());
10989 }
10990
10991
10992 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10993   if (--call_depth) CompileRun("throw 'ThrowInJS';");
10994 }
10995
10996
10997 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10998   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
10999 }
11000
11001
11002 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
11003   Handle<String> errorMessageString = message->Get();
11004   CHECK(!errorMessageString.IsEmpty());
11005   message->GetStackTrace();
11006   message->GetScriptOrigin().ResourceName();
11007 }
11008
11009
11010 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
11011   LocalContext context;
11012   v8::Isolate* isolate = context->GetIsolate();
11013   HandleScope scope(isolate);
11014
11015   Local<Function> func =
11016       FunctionTemplate::New(isolate,
11017                             ThrowingCallbackWithTryCatch)->GetFunction();
11018   context->Global()->Set(v8_str("func"), func);
11019
11020   MessageCallback callbacks[] =
11021       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
11022   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
11023     MessageCallback callback = callbacks[i];
11024     if (callback != NULL) {
11025       V8::AddMessageListener(callback);
11026     }
11027     // Some small number to control number of times message handler should
11028     // throw an exception.
11029     call_depth = 5;
11030     ExpectFalse(
11031         "var thrown = false;\n"
11032         "try { func(); } catch(e) { thrown = true; }\n"
11033         "thrown\n");
11034     if (callback != NULL) {
11035       V8::RemoveMessageListeners(callback);
11036     }
11037   }
11038 }
11039
11040
11041 static void ParentGetter(Local<String> name,
11042                          const v8::PropertyCallbackInfo<v8::Value>& info) {
11043   ApiTestFuzzer::Fuzz();
11044   info.GetReturnValue().Set(v8_num(1));
11045 }
11046
11047
11048 static void ChildGetter(Local<String> name,
11049                         const v8::PropertyCallbackInfo<v8::Value>& info) {
11050   ApiTestFuzzer::Fuzz();
11051   info.GetReturnValue().Set(v8_num(42));
11052 }
11053
11054
11055 THREADED_TEST(Overriding) {
11056   LocalContext context;
11057   v8::Isolate* isolate = context->GetIsolate();
11058   v8::HandleScope scope(isolate);
11059
11060   // Parent template.
11061   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
11062   Local<ObjectTemplate> parent_instance_templ =
11063       parent_templ->InstanceTemplate();
11064   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
11065
11066   // Template that inherits from the parent template.
11067   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
11068   Local<ObjectTemplate> child_instance_templ =
11069       child_templ->InstanceTemplate();
11070   child_templ->Inherit(parent_templ);
11071   // Override 'f'.  The child version of 'f' should get called for child
11072   // instances.
11073   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11074   // Add 'g' twice.  The 'g' added last should get called for instances.
11075   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11076   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11077
11078   // Add 'h' as an accessor to the proto template with ReadOnly attributes
11079   // so 'h' can be shadowed on the instance object.
11080   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11081   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11082       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11083
11084   // Add 'i' as an accessor to the instance template with ReadOnly attributes
11085   // but the attribute does not have effect because it is duplicated with
11086   // NULL setter.
11087   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11088       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11089
11090
11091
11092   // Instantiate the child template.
11093   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11094
11095   // Check that the child function overrides the parent one.
11096   context->Global()->Set(v8_str("o"), instance);
11097   Local<Value> value = v8_compile("o.f")->Run();
11098   // Check that the 'g' that was added last is hit.
11099   CHECK_EQ(42, value->Int32Value());
11100   value = v8_compile("o.g")->Run();
11101   CHECK_EQ(42, value->Int32Value());
11102
11103   // Check that 'h' cannot be shadowed.
11104   value = v8_compile("o.h = 3; o.h")->Run();
11105   CHECK_EQ(1, value->Int32Value());
11106
11107   // Check that 'i' cannot be shadowed or changed.
11108   value = v8_compile("o.i = 3; o.i")->Run();
11109   CHECK_EQ(42, value->Int32Value());
11110 }
11111
11112
11113 static void IsConstructHandler(
11114     const v8::FunctionCallbackInfo<v8::Value>& args) {
11115   ApiTestFuzzer::Fuzz();
11116   args.GetReturnValue().Set(args.IsConstructCall());
11117 }
11118
11119
11120 THREADED_TEST(IsConstructCall) {
11121   v8::Isolate* isolate = CcTest::isolate();
11122   v8::HandleScope scope(isolate);
11123
11124   // Function template with call handler.
11125   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11126   templ->SetCallHandler(IsConstructHandler);
11127
11128   LocalContext context;
11129
11130   context->Global()->Set(v8_str("f"), templ->GetFunction());
11131   Local<Value> value = v8_compile("f()")->Run();
11132   CHECK(!value->BooleanValue());
11133   value = v8_compile("new f()")->Run();
11134   CHECK(value->BooleanValue());
11135 }
11136
11137
11138 THREADED_TEST(ObjectProtoToString) {
11139   v8::Isolate* isolate = CcTest::isolate();
11140   v8::HandleScope scope(isolate);
11141   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11142   templ->SetClassName(v8_str("MyClass"));
11143
11144   LocalContext context;
11145
11146   Local<String> customized_tostring = v8_str("customized toString");
11147
11148   // Replace Object.prototype.toString
11149   v8_compile("Object.prototype.toString = function() {"
11150                   "  return 'customized toString';"
11151                   "}")->Run();
11152
11153   // Normal ToString call should call replaced Object.prototype.toString
11154   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11155   Local<String> value = instance->ToString(isolate);
11156   CHECK(value->IsString() && value->Equals(customized_tostring));
11157
11158   // ObjectProtoToString should not call replace toString function.
11159   value = instance->ObjectProtoToString();
11160   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11161
11162   // Check global
11163   value = context->Global()->ObjectProtoToString();
11164   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11165
11166   // Check ordinary object
11167   Local<Value> object = v8_compile("new Object()")->Run();
11168   value = object.As<v8::Object>()->ObjectProtoToString();
11169   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11170 }
11171
11172
11173 TEST(ObjectProtoToStringES6) {
11174   // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
11175   i::FLAG_harmony_tostring = true;
11176   LocalContext context;
11177   v8::Isolate* isolate = CcTest::isolate();
11178   v8::HandleScope scope(isolate);
11179   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11180   templ->SetClassName(v8_str("MyClass"));
11181
11182   Local<String> customized_tostring = v8_str("customized toString");
11183
11184   // Replace Object.prototype.toString
11185   CompileRun(
11186       "Object.prototype.toString = function() {"
11187       "  return 'customized toString';"
11188       "}");
11189
11190   // Normal ToString call should call replaced Object.prototype.toString
11191   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11192   Local<String> value = instance->ToString(isolate);
11193   CHECK(value->IsString() && value->Equals(customized_tostring));
11194
11195   // ObjectProtoToString should not call replace toString function.
11196   value = instance->ObjectProtoToString();
11197   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11198
11199   // Check global
11200   value = context->Global()->ObjectProtoToString();
11201   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11202
11203   // Check ordinary object
11204   Local<Value> object = CompileRun("new Object()");
11205   value = object.As<v8::Object>()->ObjectProtoToString();
11206   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11207
11208   // Check that ES6 semantics using @@toStringTag work
11209   Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
11210
11211 #define TEST_TOSTRINGTAG(type, tag, expected)                \
11212   do {                                                       \
11213     object = CompileRun("new " #type "()");                  \
11214     object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
11215     value = object.As<v8::Object>()->ObjectProtoToString();  \
11216     CHECK(value->IsString() &&                               \
11217           value->Equals(v8_str("[object " #expected "]")));  \
11218   } while (0)
11219
11220   TEST_TOSTRINGTAG(Array, Object, Object);
11221   TEST_TOSTRINGTAG(Object, Arguments, Arguments);
11222   TEST_TOSTRINGTAG(Object, Array, Array);
11223   TEST_TOSTRINGTAG(Object, Boolean, Boolean);
11224   TEST_TOSTRINGTAG(Object, Date, Date);
11225   TEST_TOSTRINGTAG(Object, Error, Error);
11226   TEST_TOSTRINGTAG(Object, Function, Function);
11227   TEST_TOSTRINGTAG(Object, Number, Number);
11228   TEST_TOSTRINGTAG(Object, RegExp, RegExp);
11229   TEST_TOSTRINGTAG(Object, String, String);
11230   TEST_TOSTRINGTAG(Object, Foo, Foo);
11231
11232 #undef TEST_TOSTRINGTAG
11233
11234   Local<v8::RegExp> valueRegExp = v8::RegExp::New(v8_str("^$"),
11235                                                   v8::RegExp::kNone);
11236   Local<Value> valueNumber = v8_num(123);
11237   Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
11238   Local<v8::Function> valueFunction =
11239       CompileRun("(function fn() {})").As<v8::Function>();
11240   Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
11241   Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
11242   Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
11243
11244 #define TEST_TOSTRINGTAG(type, tagValue, expected)          \
11245   do {                                                      \
11246     object = CompileRun("new " #type "()");                 \
11247     object.As<v8::Object>()->Set(toStringTag, tagValue);    \
11248     value = object.As<v8::Object>()->ObjectProtoToString(); \
11249     CHECK(value->IsString() &&                              \
11250           value->Equals(v8_str("[object " #expected "]"))); \
11251   } while (0)
11252
11253 #define TEST_TOSTRINGTAG_TYPES(tagValue)                    \
11254   TEST_TOSTRINGTAG(Array, tagValue, Array);                 \
11255   TEST_TOSTRINGTAG(Object, tagValue, Object);               \
11256   TEST_TOSTRINGTAG(Function, tagValue, Function);           \
11257   TEST_TOSTRINGTAG(Date, tagValue, Date);                   \
11258   TEST_TOSTRINGTAG(RegExp, tagValue, RegExp);               \
11259   TEST_TOSTRINGTAG(Error, tagValue, Error);                 \
11260
11261   // Test non-String-valued @@toStringTag
11262   TEST_TOSTRINGTAG_TYPES(valueRegExp);
11263   TEST_TOSTRINGTAG_TYPES(valueNumber);
11264   TEST_TOSTRINGTAG_TYPES(valueSymbol);
11265   TEST_TOSTRINGTAG_TYPES(valueFunction);
11266   TEST_TOSTRINGTAG_TYPES(valueObject);
11267   TEST_TOSTRINGTAG_TYPES(valueNull);
11268   TEST_TOSTRINGTAG_TYPES(valueUndef);
11269
11270 #undef TEST_TOSTRINGTAG
11271 #undef TEST_TOSTRINGTAG_TYPES
11272
11273   // @@toStringTag getter throws
11274   Local<Value> obj = v8::Object::New(isolate);
11275   obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
11276   {
11277     TryCatch try_catch(isolate);
11278     value = obj.As<v8::Object>()->ObjectProtoToString();
11279     CHECK(value.IsEmpty());
11280     CHECK(try_catch.HasCaught());
11281   }
11282
11283   // @@toStringTag getter does not throw
11284   obj = v8::Object::New(isolate);
11285   obj.As<v8::Object>()->SetAccessor(
11286       toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
11287   {
11288     TryCatch try_catch(isolate);
11289     value = obj.As<v8::Object>()->ObjectProtoToString();
11290     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11291     CHECK(!try_catch.HasCaught());
11292   }
11293
11294   // JS @@toStringTag value
11295   obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
11296   {
11297     TryCatch try_catch(isolate);
11298     value = obj.As<v8::Object>()->ObjectProtoToString();
11299     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11300     CHECK(!try_catch.HasCaught());
11301   }
11302
11303   // JS @@toStringTag getter throws
11304   obj = CompileRun(
11305       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11306       "  get: function() { throw 'Test'; }"
11307       "}); obj");
11308   {
11309     TryCatch try_catch(isolate);
11310     value = obj.As<v8::Object>()->ObjectProtoToString();
11311     CHECK(value.IsEmpty());
11312     CHECK(try_catch.HasCaught());
11313   }
11314
11315   // JS @@toStringTag getter does not throw
11316   obj = CompileRun(
11317       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11318       "  get: function() { return 'Test'; }"
11319       "}); obj");
11320   {
11321     TryCatch try_catch(isolate);
11322     value = obj.As<v8::Object>()->ObjectProtoToString();
11323     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11324     CHECK(!try_catch.HasCaught());
11325   }
11326 }
11327
11328
11329 THREADED_TEST(ObjectGetConstructorName) {
11330   v8::Isolate* isolate = CcTest::isolate();
11331   LocalContext context;
11332   v8::HandleScope scope(isolate);
11333   v8_compile(
11334       "function Parent() {};"
11335       "function Child() {};"
11336       "Child.prototype = new Parent();"
11337       "var outer = { inner: function() { } };"
11338       "var p = new Parent();"
11339       "var c = new Child();"
11340       "var x = new outer.inner();"
11341       "var proto = Child.prototype;")->Run();
11342
11343   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11344   CHECK(p->IsObject() &&
11345         p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
11346
11347   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11348   CHECK(c->IsObject() &&
11349         c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
11350
11351   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11352   CHECK(x->IsObject() &&
11353         x->ToObject(isolate)->GetConstructorName()->Equals(
11354             v8_str("outer.inner")));
11355
11356   Local<v8::Value> child_prototype = context->Global()->Get(v8_str("proto"));
11357   CHECK(child_prototype->IsObject() &&
11358         child_prototype->ToObject(isolate)->GetConstructorName()->Equals(
11359             v8_str("Parent")));
11360 }
11361
11362
11363 bool ApiTestFuzzer::fuzzing_ = false;
11364 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
11365 int ApiTestFuzzer::active_tests_;
11366 int ApiTestFuzzer::tests_being_run_;
11367 int ApiTestFuzzer::current_;
11368
11369
11370 // We are in a callback and want to switch to another thread (if we
11371 // are currently running the thread fuzzing test).
11372 void ApiTestFuzzer::Fuzz() {
11373   if (!fuzzing_) return;
11374   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11375   test->ContextSwitch();
11376 }
11377
11378
11379 // Let the next thread go.  Since it is also waiting on the V8 lock it may
11380 // not start immediately.
11381 bool ApiTestFuzzer::NextThread() {
11382   int test_position = GetNextTestNumber();
11383   const char* test_name = RegisterThreadedTest::nth(current_)->name();
11384   if (test_position == current_) {
11385     if (kLogThreading)
11386       printf("Stay with %s\n", test_name);
11387     return false;
11388   }
11389   if (kLogThreading) {
11390     printf("Switch from %s to %s\n",
11391            test_name,
11392            RegisterThreadedTest::nth(test_position)->name());
11393   }
11394   current_ = test_position;
11395   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
11396   return true;
11397 }
11398
11399
11400 void ApiTestFuzzer::Run() {
11401   // When it is our turn...
11402   gate_.Wait();
11403   {
11404     // ... get the V8 lock and start running the test.
11405     v8::Locker locker(CcTest::isolate());
11406     CallTest();
11407   }
11408   // This test finished.
11409   active_ = false;
11410   active_tests_--;
11411   // If it was the last then signal that fact.
11412   if (active_tests_ == 0) {
11413     all_tests_done_.Signal();
11414   } else {
11415     // Otherwise select a new test and start that.
11416     NextThread();
11417   }
11418 }
11419
11420
11421 static unsigned linear_congruential_generator;
11422
11423
11424 void ApiTestFuzzer::SetUp(PartOfTest part) {
11425   linear_congruential_generator = i::FLAG_testing_prng_seed;
11426   fuzzing_ = true;
11427   int count = RegisterThreadedTest::count();
11428   int start =  count * part / (LAST_PART + 1);
11429   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11430   active_tests_ = tests_being_run_ = end - start + 1;
11431   for (int i = 0; i < tests_being_run_; i++) {
11432     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
11433   }
11434   for (int i = 0; i < active_tests_; i++) {
11435     RegisterThreadedTest::nth(i)->fuzzer_->Start();
11436   }
11437 }
11438
11439
11440 static void CallTestNumber(int test_number) {
11441   (RegisterThreadedTest::nth(test_number)->callback())();
11442 }
11443
11444
11445 void ApiTestFuzzer::RunAllTests() {
11446   // Set off the first test.
11447   current_ = -1;
11448   NextThread();
11449   // Wait till they are all done.
11450   all_tests_done_.Wait();
11451 }
11452
11453
11454 int ApiTestFuzzer::GetNextTestNumber() {
11455   int next_test;
11456   do {
11457     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11458     linear_congruential_generator *= 1664525u;
11459     linear_congruential_generator += 1013904223u;
11460   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11461   return next_test;
11462 }
11463
11464
11465 void ApiTestFuzzer::ContextSwitch() {
11466   // If the new thread is the same as the current thread there is nothing to do.
11467   if (NextThread()) {
11468     // Now it can start.
11469     v8::Unlocker unlocker(CcTest::isolate());
11470     // Wait till someone starts us again.
11471     gate_.Wait();
11472     // And we're off.
11473   }
11474 }
11475
11476
11477 void ApiTestFuzzer::TearDown() {
11478   fuzzing_ = false;
11479   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11480     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11481     if (fuzzer != NULL) fuzzer->Join();
11482   }
11483 }
11484
11485
11486 // Lets not be needlessly self-referential.
11487 TEST(Threading1) {
11488   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
11489   ApiTestFuzzer::RunAllTests();
11490   ApiTestFuzzer::TearDown();
11491 }
11492
11493
11494 TEST(Threading2) {
11495   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
11496   ApiTestFuzzer::RunAllTests();
11497   ApiTestFuzzer::TearDown();
11498 }
11499
11500
11501 TEST(Threading3) {
11502   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
11503   ApiTestFuzzer::RunAllTests();
11504   ApiTestFuzzer::TearDown();
11505 }
11506
11507
11508 TEST(Threading4) {
11509   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
11510   ApiTestFuzzer::RunAllTests();
11511   ApiTestFuzzer::TearDown();
11512 }
11513
11514
11515 void ApiTestFuzzer::CallTest() {
11516   v8::Isolate::Scope scope(CcTest::isolate());
11517   if (kLogThreading)
11518     printf("Start test %d\n", test_number_);
11519   CallTestNumber(test_number_);
11520   if (kLogThreading)
11521     printf("End test %d\n", test_number_);
11522 }
11523
11524
11525 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
11526   v8::Isolate* isolate = args.GetIsolate();
11527   CHECK(v8::Locker::IsLocked(isolate));
11528   ApiTestFuzzer::Fuzz();
11529   v8::Unlocker unlocker(isolate);
11530   const char* code = "throw 7;";
11531   {
11532     v8::Locker nested_locker(isolate);
11533     v8::HandleScope scope(isolate);
11534     v8::Handle<Value> exception;
11535     {
11536       v8::TryCatch try_catch(isolate);
11537       v8::Handle<Value> value = CompileRun(code);
11538       CHECK(value.IsEmpty());
11539       CHECK(try_catch.HasCaught());
11540       // Make sure to wrap the exception in a new handle because
11541       // the handle returned from the TryCatch is destroyed
11542       // when the TryCatch is destroyed.
11543       exception = Local<Value>::New(isolate, try_catch.Exception());
11544     }
11545     args.GetIsolate()->ThrowException(exception);
11546   }
11547 }
11548
11549
11550 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
11551   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11552   ApiTestFuzzer::Fuzz();
11553   v8::Unlocker unlocker(CcTest::isolate());
11554   const char* code = "throw 7;";
11555   {
11556     v8::Locker nested_locker(CcTest::isolate());
11557     v8::HandleScope scope(args.GetIsolate());
11558     v8::Handle<Value> value = CompileRun(code);
11559     CHECK(value.IsEmpty());
11560     args.GetReturnValue().Set(v8_str("foo"));
11561   }
11562 }
11563
11564
11565 // These are locking tests that don't need to be run again
11566 // as part of the locking aggregation tests.
11567 TEST(NestedLockers) {
11568   v8::Isolate* isolate = CcTest::isolate();
11569   v8::Locker locker(isolate);
11570   CHECK(v8::Locker::IsLocked(isolate));
11571   LocalContext env;
11572   v8::HandleScope scope(env->GetIsolate());
11573   Local<v8::FunctionTemplate> fun_templ =
11574       v8::FunctionTemplate::New(isolate, ThrowInJS);
11575   Local<Function> fun = fun_templ->GetFunction();
11576   env->Global()->Set(v8_str("throw_in_js"), fun);
11577   Local<Script> script = v8_compile("(function () {"
11578                                     "  try {"
11579                                     "    throw_in_js();"
11580                                     "    return 42;"
11581                                     "  } catch (e) {"
11582                                     "    return e * 13;"
11583                                     "  }"
11584                                     "})();");
11585   CHECK_EQ(91, script->Run()->Int32Value());
11586 }
11587
11588
11589 // These are locking tests that don't need to be run again
11590 // as part of the locking aggregation tests.
11591 TEST(NestedLockersNoTryCatch) {
11592   v8::Locker locker(CcTest::isolate());
11593   LocalContext env;
11594   v8::HandleScope scope(env->GetIsolate());
11595   Local<v8::FunctionTemplate> fun_templ =
11596       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
11597   Local<Function> fun = fun_templ->GetFunction();
11598   env->Global()->Set(v8_str("throw_in_js"), fun);
11599   Local<Script> script = v8_compile("(function () {"
11600                                     "  try {"
11601                                     "    throw_in_js();"
11602                                     "    return 42;"
11603                                     "  } catch (e) {"
11604                                     "    return e * 13;"
11605                                     "  }"
11606                                     "})();");
11607   CHECK_EQ(91, script->Run()->Int32Value());
11608 }
11609
11610
11611 THREADED_TEST(RecursiveLocking) {
11612   v8::Locker locker(CcTest::isolate());
11613   {
11614     v8::Locker locker2(CcTest::isolate());
11615     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11616   }
11617 }
11618
11619
11620 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
11621   ApiTestFuzzer::Fuzz();
11622   v8::Unlocker unlocker(CcTest::isolate());
11623 }
11624
11625
11626 THREADED_TEST(LockUnlockLock) {
11627   {
11628     v8::Locker locker(CcTest::isolate());
11629     v8::HandleScope scope(CcTest::isolate());
11630     LocalContext env;
11631     Local<v8::FunctionTemplate> fun_templ =
11632         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11633     Local<Function> fun = fun_templ->GetFunction();
11634     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11635     Local<Script> script = v8_compile("(function () {"
11636                                       "  unlock_for_a_moment();"
11637                                       "  return 42;"
11638                                       "})();");
11639     CHECK_EQ(42, script->Run()->Int32Value());
11640   }
11641   {
11642     v8::Locker locker(CcTest::isolate());
11643     v8::HandleScope scope(CcTest::isolate());
11644     LocalContext env;
11645     Local<v8::FunctionTemplate> fun_templ =
11646         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11647     Local<Function> fun = fun_templ->GetFunction();
11648     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11649     Local<Script> script = v8_compile("(function () {"
11650                                       "  unlock_for_a_moment();"
11651                                       "  return 42;"
11652                                       "})();");
11653     CHECK_EQ(42, script->Run()->Int32Value());
11654   }
11655 }
11656
11657
11658 static int GetGlobalObjectsCount() {
11659   int count = 0;
11660   i::HeapIterator it(CcTest::heap());
11661   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11662     if (object->IsJSGlobalObject()) count++;
11663   return count;
11664 }
11665
11666
11667 static void CheckSurvivingGlobalObjectsCount(int expected) {
11668   // We need to collect all garbage twice to be sure that everything
11669   // has been collected.  This is because inline caches are cleared in
11670   // the first garbage collection but some of the maps have already
11671   // been marked at that point.  Therefore some of the maps are not
11672   // collected until the second garbage collection.
11673   CcTest::heap()->CollectAllGarbage();
11674   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
11675   int count = GetGlobalObjectsCount();
11676 #ifdef DEBUG
11677   if (count != expected) CcTest::heap()->TracePathToGlobal();
11678 #endif
11679   CHECK_EQ(expected, count);
11680 }
11681
11682
11683 TEST(DontLeakGlobalObjects) {
11684   // Regression test for issues 1139850 and 1174891.
11685
11686   i::FLAG_expose_gc = true;
11687   v8::V8::Initialize();
11688
11689   for (int i = 0; i < 5; i++) {
11690     { v8::HandleScope scope(CcTest::isolate());
11691       LocalContext context;
11692     }
11693     CcTest::isolate()->ContextDisposedNotification();
11694     CheckSurvivingGlobalObjectsCount(0);
11695
11696     { v8::HandleScope scope(CcTest::isolate());
11697       LocalContext context;
11698       v8_compile("Date")->Run();
11699     }
11700     CcTest::isolate()->ContextDisposedNotification();
11701     CheckSurvivingGlobalObjectsCount(0);
11702
11703     { v8::HandleScope scope(CcTest::isolate());
11704       LocalContext context;
11705       v8_compile("/aaa/")->Run();
11706     }
11707     CcTest::isolate()->ContextDisposedNotification();
11708     CheckSurvivingGlobalObjectsCount(0);
11709
11710     { v8::HandleScope scope(CcTest::isolate());
11711       const char* extension_list[] = { "v8/gc" };
11712       v8::ExtensionConfiguration extensions(1, extension_list);
11713       LocalContext context(&extensions);
11714       v8_compile("gc();")->Run();
11715     }
11716     CcTest::isolate()->ContextDisposedNotification();
11717     CheckSurvivingGlobalObjectsCount(0);
11718   }
11719 }
11720
11721
11722 TEST(CopyablePersistent) {
11723   LocalContext context;
11724   v8::Isolate* isolate = context->GetIsolate();
11725   i::GlobalHandles* globals =
11726       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11727   int initial_handles = globals->global_handles_count();
11728   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
11729       CopyableObject;
11730   {
11731     CopyableObject handle1;
11732     {
11733       v8::HandleScope scope(isolate);
11734       handle1.Reset(isolate, v8::Object::New(isolate));
11735     }
11736     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
11737     CopyableObject  handle2;
11738     handle2 = handle1;
11739     CHECK(handle1 == handle2);
11740     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
11741     CopyableObject handle3(handle2);
11742     CHECK(handle1 == handle3);
11743     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
11744   }
11745   // Verify autodispose
11746   CHECK_EQ(initial_handles, globals->global_handles_count());
11747 }
11748
11749
11750 static void WeakApiCallback(
11751     const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
11752   data.GetParameter()->Reset();
11753   delete data.GetParameter();
11754 }
11755
11756
11757 TEST(WeakCallbackApi) {
11758   LocalContext context;
11759   v8::Isolate* isolate = context->GetIsolate();
11760   i::GlobalHandles* globals =
11761       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11762   int initial_handles = globals->global_handles_count();
11763   {
11764     v8::HandleScope scope(isolate);
11765     v8::Local<v8::Object> obj = v8::Object::New(isolate);
11766     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
11767     v8::Persistent<v8::Object>* handle =
11768         new v8::Persistent<v8::Object>(isolate, obj);
11769     handle->SetWeak<v8::Persistent<v8::Object>>(
11770         handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
11771   }
11772   reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
11773       i::Heap::kAbortIncrementalMarkingMask);
11774   // Verify disposed.
11775   CHECK_EQ(initial_handles, globals->global_handles_count());
11776 }
11777
11778
11779 v8::Persistent<v8::Object> some_object;
11780 v8::Persistent<v8::Object> bad_handle;
11781
11782
11783 void NewPersistentHandleCallback2(
11784     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11785   v8::HandleScope scope(data.GetIsolate());
11786   bad_handle.Reset(data.GetIsolate(), some_object);
11787 }
11788
11789
11790 void NewPersistentHandleCallback1(
11791     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11792   data.GetParameter()->Reset();
11793   data.SetSecondPassCallback(NewPersistentHandleCallback2);
11794 }
11795
11796
11797 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11798   LocalContext context;
11799   v8::Isolate* isolate = context->GetIsolate();
11800
11801   v8::Persistent<v8::Object> handle1, handle2;
11802   {
11803     v8::HandleScope scope(isolate);
11804     some_object.Reset(isolate, v8::Object::New(isolate));
11805     handle1.Reset(isolate, v8::Object::New(isolate));
11806     handle2.Reset(isolate, v8::Object::New(isolate));
11807   }
11808   // Note: order is implementation dependent alas: currently
11809   // global handle nodes are processed by PostGarbageCollectionProcessing
11810   // in reverse allocation order, so if second allocated handle is deleted,
11811   // weak callback of the first handle would be able to 'reallocate' it.
11812   handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
11813                   v8::WeakCallbackType::kParameter);
11814   handle2.Reset();
11815   CcTest::heap()->CollectAllGarbage();
11816 }
11817
11818
11819 v8::Persistent<v8::Object> to_be_disposed;
11820
11821
11822 void DisposeAndForceGcCallback2(
11823     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11824   to_be_disposed.Reset();
11825   CcTest::heap()->CollectAllGarbage();
11826 }
11827
11828
11829 void DisposeAndForceGcCallback1(
11830     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11831   data.GetParameter()->Reset();
11832   data.SetSecondPassCallback(DisposeAndForceGcCallback2);
11833 }
11834
11835
11836 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11837   LocalContext context;
11838   v8::Isolate* isolate = context->GetIsolate();
11839
11840   v8::Persistent<v8::Object> handle1, handle2;
11841   {
11842     v8::HandleScope scope(isolate);
11843     handle1.Reset(isolate, v8::Object::New(isolate));
11844     handle2.Reset(isolate, v8::Object::New(isolate));
11845   }
11846   handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
11847                   v8::WeakCallbackType::kParameter);
11848   to_be_disposed.Reset(isolate, handle2);
11849   CcTest::heap()->CollectAllGarbage();
11850 }
11851
11852 void DisposingCallback(
11853     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11854   data.GetParameter()->Reset();
11855 }
11856
11857 void HandleCreatingCallback2(
11858     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11859   v8::HandleScope scope(data.GetIsolate());
11860   v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
11861 }
11862
11863
11864 void HandleCreatingCallback1(
11865     const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11866   data.GetParameter()->Reset();
11867   data.SetSecondPassCallback(HandleCreatingCallback2);
11868 }
11869
11870
11871 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11872   LocalContext context;
11873   v8::Isolate* isolate = context->GetIsolate();
11874
11875   v8::Persistent<v8::Object> handle1, handle2, handle3;
11876   {
11877     v8::HandleScope scope(isolate);
11878     handle3.Reset(isolate, v8::Object::New(isolate));
11879     handle2.Reset(isolate, v8::Object::New(isolate));
11880     handle1.Reset(isolate, v8::Object::New(isolate));
11881   }
11882   handle2.SetWeak(&handle2, DisposingCallback,
11883                   v8::WeakCallbackType::kParameter);
11884   handle3.SetWeak(&handle3, HandleCreatingCallback1,
11885                   v8::WeakCallbackType::kParameter);
11886   CcTest::heap()->CollectAllGarbage();
11887 }
11888
11889
11890 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11891   v8::V8::Initialize();
11892
11893   const int nof = 2;
11894   const char* sources[nof] = {
11895     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11896     "Object()"
11897   };
11898
11899   for (int i = 0; i < nof; i++) {
11900     const char* source = sources[i];
11901     { v8::HandleScope scope(CcTest::isolate());
11902       LocalContext context;
11903       CompileRun(source);
11904     }
11905     { v8::HandleScope scope(CcTest::isolate());
11906       LocalContext context;
11907       CompileRun(source);
11908     }
11909   }
11910 }
11911
11912
11913 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
11914   v8::EscapableHandleScope inner(env->GetIsolate());
11915   env->Enter();
11916   v8::Local<Value> three = v8_num(3);
11917   v8::Local<Value> value = inner.Escape(three);
11918   env->Exit();
11919   return value;
11920 }
11921
11922
11923 THREADED_TEST(NestedHandleScopeAndContexts) {
11924   v8::Isolate* isolate = CcTest::isolate();
11925   v8::HandleScope outer(isolate);
11926   v8::Local<Context> env = Context::New(isolate);
11927   env->Enter();
11928   v8::Handle<Value> value = NestedScope(env);
11929   v8::Handle<String> str(value->ToString(isolate));
11930   CHECK(!str.IsEmpty());
11931   env->Exit();
11932 }
11933
11934
11935 static bool MatchPointers(void* key1, void* key2) {
11936   return key1 == key2;
11937 }
11938
11939
11940 struct SymbolInfo {
11941   size_t id;
11942   size_t size;
11943   std::string name;
11944 };
11945
11946
11947 class SetFunctionEntryHookTest {
11948  public:
11949   SetFunctionEntryHookTest() {
11950     CHECK(instance_ == NULL);
11951     instance_ = this;
11952   }
11953   ~SetFunctionEntryHookTest() {
11954     CHECK(instance_ == this);
11955     instance_ = NULL;
11956   }
11957   void Reset() {
11958     symbols_.clear();
11959     symbol_locations_.clear();
11960     invocations_.clear();
11961   }
11962   void RunTest();
11963   void OnJitEvent(const v8::JitCodeEvent* event);
11964   static void JitEvent(const v8::JitCodeEvent* event) {
11965     CHECK(instance_ != NULL);
11966     instance_->OnJitEvent(event);
11967   }
11968
11969   void OnEntryHook(uintptr_t function,
11970                    uintptr_t return_addr_location);
11971   static void EntryHook(uintptr_t function,
11972                         uintptr_t return_addr_location) {
11973     CHECK(instance_ != NULL);
11974     instance_->OnEntryHook(function, return_addr_location);
11975   }
11976
11977   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11978     CHECK(instance_ != NULL);
11979     args.GetReturnValue().Set(v8_num(42));
11980   }
11981   void RunLoopInNewEnv(v8::Isolate* isolate);
11982
11983   // Records addr as location of symbol.
11984   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
11985
11986   // Finds the symbol containing addr
11987   SymbolInfo* FindSymbolForAddr(i::Address addr);
11988   // Returns the number of invocations where the caller name contains
11989   // \p caller_name and the function name contains \p function_name.
11990   int CountInvocations(const char* caller_name,
11991                        const char* function_name);
11992
11993   i::Handle<i::JSFunction> foo_func_;
11994   i::Handle<i::JSFunction> bar_func_;
11995
11996   typedef std::map<size_t, SymbolInfo> SymbolMap;
11997   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
11998   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
11999   SymbolMap symbols_;
12000   SymbolLocationMap symbol_locations_;
12001   InvocationMap invocations_;
12002
12003   static SetFunctionEntryHookTest* instance_;
12004 };
12005 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12006
12007
12008 // Returns true if addr is in the range [start, start+len).
12009 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12010   if (start <= addr && start + len > addr)
12011     return true;
12012
12013   return false;
12014 }
12015
12016 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12017                                               SymbolInfo* symbol) {
12018   // Insert the symbol at the new location.
12019   SymbolLocationMap::iterator it =
12020       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12021   // Now erase symbols to the left and right that overlap this one.
12022   while (it != symbol_locations_.begin()) {
12023     SymbolLocationMap::iterator left = it;
12024     --left;
12025     if (!Overlaps(left->first, left->second->size, addr))
12026       break;
12027     symbol_locations_.erase(left);
12028   }
12029
12030   // Now erase symbols to the left and right that overlap this one.
12031   while (true) {
12032     SymbolLocationMap::iterator right = it;
12033     ++right;
12034     if (right == symbol_locations_.end())
12035         break;
12036     if (!Overlaps(addr, symbol->size, right->first))
12037       break;
12038     symbol_locations_.erase(right);
12039   }
12040 }
12041
12042
12043 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12044   switch (event->type) {
12045     case v8::JitCodeEvent::CODE_ADDED: {
12046         CHECK(event->code_start != NULL);
12047         CHECK_NE(0, static_cast<int>(event->code_len));
12048         CHECK(event->name.str != NULL);
12049         size_t symbol_id = symbols_.size();
12050
12051         // Record the new symbol.
12052         SymbolInfo& info = symbols_[symbol_id];
12053         info.id = symbol_id;
12054         info.size = event->code_len;
12055         info.name.assign(event->name.str, event->name.str + event->name.len);
12056
12057         // And record it's location.
12058         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
12059       }
12060       break;
12061
12062     case v8::JitCodeEvent::CODE_MOVED: {
12063         // We would like to never see code move that we haven't seen before,
12064         // but the code creation event does not happen until the line endings
12065         // have been calculated (this is so that we can report the line in the
12066         // script at which the function source is found, see
12067         // Compiler::RecordFunctionCompilation) and the line endings
12068         // calculations can cause a GC, which can move the newly created code
12069         // before its existence can be logged.
12070         SymbolLocationMap::iterator it(
12071             symbol_locations_.find(
12072                 reinterpret_cast<i::Address>(event->code_start)));
12073         if (it != symbol_locations_.end()) {
12074           // Found a symbol at this location, move it.
12075           SymbolInfo* info = it->second;
12076           symbol_locations_.erase(it);
12077           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
12078                          info);
12079         }
12080       }
12081     default:
12082       break;
12083   }
12084 }
12085
12086 void SetFunctionEntryHookTest::OnEntryHook(
12087     uintptr_t function, uintptr_t return_addr_location) {
12088   // Get the function's code object.
12089   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
12090       reinterpret_cast<i::Address>(function));
12091   CHECK(function_code != NULL);
12092
12093   // Then try and look up the caller's code object.
12094   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
12095
12096   // Count the invocation.
12097   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
12098   SymbolInfo* function_symbol =
12099       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
12100   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12101
12102   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12103     // Check that we have a symbol for the "bar" function at the right location.
12104     SymbolLocationMap::iterator it(
12105         symbol_locations_.find(function_code->instruction_start()));
12106     CHECK(it != symbol_locations_.end());
12107   }
12108
12109   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12110     // Check that we have a symbol for "foo" at the right location.
12111     SymbolLocationMap::iterator it(
12112         symbol_locations_.find(function_code->instruction_start()));
12113     CHECK(it != symbol_locations_.end());
12114   }
12115 }
12116
12117
12118 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12119   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12120   // Do we have a direct hit on a symbol?
12121   if (it != symbol_locations_.end()) {
12122     if (it->first == addr)
12123       return it->second;
12124   }
12125
12126   // If not a direct hit, it'll have to be the previous symbol.
12127   if (it == symbol_locations_.begin())
12128     return NULL;
12129
12130   --it;
12131   size_t offs = addr - it->first;
12132   if (offs < it->second->size)
12133     return it->second;
12134
12135   return NULL;
12136 }
12137
12138
12139 int SetFunctionEntryHookTest::CountInvocations(
12140     const char* caller_name, const char* function_name) {
12141   InvocationMap::iterator it(invocations_.begin());
12142   int invocations = 0;
12143   for (; it != invocations_.end(); ++it) {
12144     SymbolInfo* caller = it->first.first;
12145     SymbolInfo* function = it->first.second;
12146
12147     // Filter out non-matching functions.
12148     if (function_name != NULL) {
12149       if (function->name.find(function_name) == std::string::npos)
12150         continue;
12151     }
12152
12153     // Filter out non-matching callers.
12154     if (caller_name != NULL) {
12155       if (caller == NULL)
12156         continue;
12157       if (caller->name.find(caller_name) == std::string::npos)
12158         continue;
12159     }
12160
12161     // It matches add the invocation count to the tally.
12162     invocations += it->second;
12163   }
12164
12165   return invocations;
12166 }
12167
12168
12169 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12170   v8::HandleScope outer(isolate);
12171   v8::Local<Context> env = Context::New(isolate);
12172   env->Enter();
12173
12174   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12175   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
12176   env->Global()->Set(v8_str("obj"), t->NewInstance());
12177
12178   const char* script =
12179       "function bar() {\n"
12180       "  var sum = 0;\n"
12181       "  for (i = 0; i < 100; ++i)\n"
12182       "    sum = foo(i);\n"
12183       "  return sum;\n"
12184       "}\n"
12185       "function foo(i) { return i * i; }\n"
12186       "// Invoke on the runtime function.\n"
12187       "obj.asdf()";
12188   CompileRun(script);
12189   bar_func_ = i::Handle<i::JSFunction>::cast(
12190           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12191   DCHECK(!bar_func_.is_null());
12192
12193   foo_func_ =
12194       i::Handle<i::JSFunction>::cast(
12195            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12196   DCHECK(!foo_func_.is_null());
12197
12198   v8::Handle<v8::Value> value = CompileRun("bar();");
12199   CHECK(value->IsNumber());
12200   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12201
12202   // Test the optimized codegen path.
12203   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12204                      "bar();");
12205   CHECK(value->IsNumber());
12206   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12207
12208   env->Exit();
12209 }
12210
12211
12212 void SetFunctionEntryHookTest::RunTest() {
12213   // Work in a new isolate throughout.
12214   v8::Isolate::CreateParams create_params;
12215   create_params.entry_hook = EntryHook;
12216   create_params.code_event_handler = JitEvent;
12217   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
12218   v8::Isolate* isolate = v8::Isolate::New(create_params);
12219
12220   {
12221     v8::Isolate::Scope scope(isolate);
12222
12223     RunLoopInNewEnv(isolate);
12224
12225     // Check the exepected invocation counts.
12226     CHECK_EQ(2, CountInvocations(NULL, "bar"));
12227     CHECK_EQ(200, CountInvocations("bar", "foo"));
12228     CHECK_EQ(200, CountInvocations(NULL, "foo"));
12229
12230     // Verify that we have an entry hook on some specific stubs.
12231     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12232     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12233     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12234   }
12235   isolate->Dispose();
12236
12237   Reset();
12238
12239   // Make sure a second isolate is unaffected by the previous entry hook.
12240   create_params = v8::Isolate::CreateParams();
12241   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
12242   isolate = v8::Isolate::New(create_params);
12243   {
12244     v8::Isolate::Scope scope(isolate);
12245
12246     // Reset the entry count to zero and set the entry hook.
12247     RunLoopInNewEnv(isolate);
12248
12249     // We should record no invocations in this isolate.
12250     CHECK_EQ(0, static_cast<int>(invocations_.size()));
12251   }
12252
12253   isolate->Dispose();
12254 }
12255
12256
12257 TEST(SetFunctionEntryHook) {
12258   // FunctionEntryHook does not work well with experimental natives.
12259   // Experimental natives are compiled during snapshot deserialization.
12260   // This test breaks because InstallGetter (function from snapshot that
12261   // only gets called from experimental natives) is compiled with entry hooks.
12262   i::FLAG_allow_natives_syntax = true;
12263   i::FLAG_use_inlining = false;
12264
12265   SetFunctionEntryHookTest test;
12266   test.RunTest();
12267 }
12268
12269
12270 static i::HashMap* code_map = NULL;
12271 static i::HashMap* jitcode_line_info = NULL;
12272 static int saw_bar = 0;
12273 static int move_events = 0;
12274
12275
12276 static bool FunctionNameIs(const char* expected,
12277                            const v8::JitCodeEvent* event) {
12278   // Log lines for functions are of the general form:
12279   // "LazyCompile:<type><function_name>", where the type is one of
12280   // "*", "~" or "".
12281   static const char kPreamble[] = "LazyCompile:";
12282   static size_t kPreambleLen = sizeof(kPreamble) - 1;
12283
12284   if (event->name.len < sizeof(kPreamble) - 1 ||
12285       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12286     return false;
12287   }
12288
12289   const char* tail = event->name.str + kPreambleLen;
12290   size_t tail_len = event->name.len - kPreambleLen;
12291   size_t expected_len = strlen(expected);
12292   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12293     --tail_len;
12294     ++tail;
12295   }
12296
12297   // Check for tails like 'bar :1'.
12298   if (tail_len > expected_len + 2 &&
12299       tail[expected_len] == ' ' &&
12300       tail[expected_len + 1] == ':' &&
12301       tail[expected_len + 2] &&
12302       !strncmp(tail, expected, expected_len)) {
12303     return true;
12304   }
12305
12306   if (tail_len != expected_len)
12307     return false;
12308
12309   return strncmp(tail, expected, expected_len) == 0;
12310 }
12311
12312
12313 static void event_handler(const v8::JitCodeEvent* event) {
12314   CHECK(event != NULL);
12315   CHECK(code_map != NULL);
12316   CHECK(jitcode_line_info != NULL);
12317
12318   class DummyJitCodeLineInfo {
12319   };
12320
12321   switch (event->type) {
12322     case v8::JitCodeEvent::CODE_ADDED: {
12323         CHECK(event->code_start != NULL);
12324         CHECK_NE(0, static_cast<int>(event->code_len));
12325         CHECK(event->name.str != NULL);
12326         i::HashMap::Entry* entry = code_map->LookupOrInsert(
12327             event->code_start, i::ComputePointerHash(event->code_start));
12328         entry->value = reinterpret_cast<void*>(event->code_len);
12329
12330         if (FunctionNameIs("bar", event)) {
12331           ++saw_bar;
12332         }
12333       }
12334       break;
12335
12336     case v8::JitCodeEvent::CODE_MOVED: {
12337         uint32_t hash = i::ComputePointerHash(event->code_start);
12338         // We would like to never see code move that we haven't seen before,
12339         // but the code creation event does not happen until the line endings
12340         // have been calculated (this is so that we can report the line in the
12341         // script at which the function source is found, see
12342         // Compiler::RecordFunctionCompilation) and the line endings
12343         // calculations can cause a GC, which can move the newly created code
12344         // before its existence can be logged.
12345         i::HashMap::Entry* entry = code_map->Lookup(event->code_start, hash);
12346         if (entry != NULL) {
12347           ++move_events;
12348
12349           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12350           code_map->Remove(event->code_start, hash);
12351
12352           entry = code_map->LookupOrInsert(
12353               event->new_code_start,
12354               i::ComputePointerHash(event->new_code_start));
12355           entry->value = reinterpret_cast<void*>(event->code_len);
12356         }
12357       }
12358       break;
12359
12360     case v8::JitCodeEvent::CODE_REMOVED:
12361       // Object/code removal events are currently not dispatched from the GC.
12362       CHECK(false);
12363       break;
12364
12365     // For CODE_START_LINE_INFO_RECORDING event, we will create one
12366     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12367     // record it in jitcode_line_info.
12368     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12369         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12370         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12371         temp_event->user_data = line_info;
12372         i::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
12373             line_info, i::ComputePointerHash(line_info));
12374         entry->value = reinterpret_cast<void*>(line_info);
12375       }
12376       break;
12377     // For these two events, we will check whether the event->user_data
12378     // data structure is created before during CODE_START_LINE_INFO_RECORDING
12379     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12380     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12381         CHECK(event->user_data != NULL);
12382         uint32_t hash = i::ComputePointerHash(event->user_data);
12383         i::HashMap::Entry* entry =
12384             jitcode_line_info->Lookup(event->user_data, hash);
12385         CHECK(entry != NULL);
12386         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12387       }
12388       break;
12389
12390     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12391         CHECK(event->user_data != NULL);
12392         uint32_t hash = i::ComputePointerHash(event->user_data);
12393         i::HashMap::Entry* entry =
12394             jitcode_line_info->Lookup(event->user_data, hash);
12395         CHECK(entry != NULL);
12396       }
12397       break;
12398
12399     default:
12400       // Impossible event.
12401       CHECK(false);
12402       break;
12403   }
12404 }
12405
12406
12407 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
12408   i::FLAG_stress_compaction = true;
12409   i::FLAG_incremental_marking = false;
12410   if (i::FLAG_never_compact) return;
12411   const char* script =
12412       "function bar() {"
12413       "  var sum = 0;"
12414       "  for (i = 0; i < 10; ++i)"
12415       "    sum = foo(i);"
12416       "  return sum;"
12417       "}"
12418       "function foo(i) { return i; };"
12419       "bar();";
12420
12421   // Run this test in a new isolate to make sure we don't
12422   // have remnants of state from other code.
12423   v8::Isolate::CreateParams create_params;
12424   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
12425   v8::Isolate* isolate = v8::Isolate::New(create_params);
12426   isolate->Enter();
12427   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
12428   i::Heap* heap = i_isolate->heap();
12429
12430   // Start with a clean slate.
12431   heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare");
12432
12433   {
12434     v8::HandleScope scope(isolate);
12435     i::HashMap code(MatchPointers);
12436     code_map = &code;
12437
12438     i::HashMap lineinfo(MatchPointers);
12439     jitcode_line_info = &lineinfo;
12440
12441     saw_bar = 0;
12442     move_events = 0;
12443
12444     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12445
12446     // Generate new code objects sparsely distributed across several
12447     // different fragmented code-space pages.
12448     const int kIterations = 10;
12449     for (int i = 0; i < kIterations; ++i) {
12450       LocalContext env(isolate);
12451       i::AlwaysAllocateScope always_allocate(i_isolate);
12452       SimulateFullSpace(heap->code_space());
12453       CompileRun(script);
12454
12455       // Keep a strong reference to the code object in the handle scope.
12456       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12457           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12458       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12459           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
12460
12461       // Clear the compilation cache to get more wastage.
12462       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
12463     }
12464
12465     // Force code movement.
12466     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move");
12467
12468     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12469
12470     CHECK_LE(kIterations, saw_bar);
12471     CHECK_LT(0, move_events);
12472
12473     code_map = NULL;
12474     jitcode_line_info = NULL;
12475   }
12476
12477   isolate->Exit();
12478   isolate->Dispose();
12479
12480   // Do this in a new isolate.
12481   isolate = v8::Isolate::New(create_params);
12482   isolate->Enter();
12483
12484   // Verify that we get callbacks for existing code objects when we
12485   // request enumeration of existing code.
12486   {
12487     v8::HandleScope scope(isolate);
12488     LocalContext env(isolate);
12489     CompileRun(script);
12490
12491     // Now get code through initial iteration.
12492     i::HashMap code(MatchPointers);
12493     code_map = &code;
12494
12495     i::HashMap lineinfo(MatchPointers);
12496     jitcode_line_info = &lineinfo;
12497
12498     isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
12499                                     event_handler);
12500     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12501
12502     jitcode_line_info = NULL;
12503     // We expect that we got some events. Note that if we could get code removal
12504     // notifications, we could compare two collections, one created by listening
12505     // from the time of creation of an isolate, and the other by subscribing
12506     // with EnumExisting.
12507     CHECK_LT(0u, code.occupancy());
12508
12509     code_map = NULL;
12510   }
12511
12512   isolate->Exit();
12513   isolate->Dispose();
12514 }
12515
12516
12517 THREADED_TEST(ExternalAllocatedMemory) {
12518   v8::Isolate* isolate = CcTest::isolate();
12519   v8::HandleScope outer(isolate);
12520   v8::Local<Context> env(Context::New(isolate));
12521   CHECK(!env.IsEmpty());
12522   const int64_t kSize = 1024*1024;
12523   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
12524   CHECK_EQ(baseline + kSize,
12525            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
12526   CHECK_EQ(baseline,
12527            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
12528   const int64_t kTriggerGCSize =
12529       v8::internal::Internals::kExternalAllocationLimit + 1;
12530   CHECK_EQ(baseline + kTriggerGCSize,
12531            isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
12532   CHECK_EQ(baseline,
12533            isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
12534 }
12535
12536
12537 // Regression test for issue 54, object templates with internal fields
12538 // but no accessors or interceptors did not get their internal field
12539 // count set on instances.
12540 THREADED_TEST(Regress54) {
12541   LocalContext context;
12542   v8::Isolate* isolate = context->GetIsolate();
12543   v8::HandleScope outer(isolate);
12544   static v8::Persistent<v8::ObjectTemplate> templ;
12545   if (templ.IsEmpty()) {
12546     v8::EscapableHandleScope inner(isolate);
12547     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
12548     local->SetInternalFieldCount(1);
12549     templ.Reset(isolate, inner.Escape(local));
12550   }
12551   v8::Handle<v8::Object> result =
12552       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
12553   CHECK_EQ(1, result->InternalFieldCount());
12554 }
12555
12556
12557 // If part of the threaded tests, this test makes ThreadingTest fail
12558 // on mac.
12559 TEST(CatchStackOverflow) {
12560   LocalContext context;
12561   v8::HandleScope scope(context->GetIsolate());
12562   v8::TryCatch try_catch(context->GetIsolate());
12563   v8::Handle<v8::Value> result = CompileRun(
12564     "function f() {"
12565     "  return f();"
12566     "}"
12567     ""
12568     "f();");
12569   CHECK(result.IsEmpty());
12570 }
12571
12572
12573 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
12574                                     const char* resource_name,
12575                                     int line_offset) {
12576   v8::HandleScope scope(CcTest::isolate());
12577   v8::TryCatch try_catch(CcTest::isolate());
12578   v8::Handle<v8::Value> result = script->Run();
12579   CHECK(result.IsEmpty());
12580   CHECK(try_catch.HasCaught());
12581   v8::Handle<v8::Message> message = try_catch.Message();
12582   CHECK(!message.IsEmpty());
12583   CHECK_EQ(10 + line_offset, message->GetLineNumber());
12584   CHECK_EQ(91, message->GetStartPosition());
12585   CHECK_EQ(92, message->GetEndPosition());
12586   CHECK_EQ(2, message->GetStartColumn());
12587   CHECK_EQ(3, message->GetEndColumn());
12588   v8::String::Utf8Value line(message->GetSourceLine());
12589   CHECK_EQ(0, strcmp("  throw 'nirk';", *line));
12590   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
12591   CHECK_EQ(0, strcmp(resource_name, *name));
12592 }
12593
12594
12595 THREADED_TEST(TryCatchSourceInfo) {
12596   LocalContext context;
12597   v8::HandleScope scope(context->GetIsolate());
12598   v8::Local<v8::String> source = v8_str(
12599       "function Foo() {\n"
12600       "  return Bar();\n"
12601       "}\n"
12602       "\n"
12603       "function Bar() {\n"
12604       "  return Baz();\n"
12605       "}\n"
12606       "\n"
12607       "function Baz() {\n"
12608       "  throw 'nirk';\n"
12609       "}\n"
12610       "\n"
12611       "Foo();\n");
12612
12613   const char* resource_name;
12614   v8::Handle<v8::Script> script;
12615   resource_name = "test.js";
12616   script = CompileWithOrigin(source, resource_name);
12617   CheckTryCatchSourceInfo(script, resource_name, 0);
12618
12619   resource_name = "test1.js";
12620   v8::ScriptOrigin origin1(
12621       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
12622   script = v8::Script::Compile(source, &origin1);
12623   CheckTryCatchSourceInfo(script, resource_name, 0);
12624
12625   resource_name = "test2.js";
12626   v8::ScriptOrigin origin2(
12627       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
12628       v8::Integer::New(context->GetIsolate(), 7));
12629   script = v8::Script::Compile(source, &origin2);
12630   CheckTryCatchSourceInfo(script, resource_name, 7);
12631 }
12632
12633
12634 THREADED_TEST(TryCatchSourceInfoForEOSError) {
12635   LocalContext context;
12636   v8::HandleScope scope(context->GetIsolate());
12637   v8::TryCatch try_catch(context->GetIsolate());
12638   v8::Script::Compile(v8_str("!\n"));
12639   CHECK(try_catch.HasCaught());
12640   v8::Handle<v8::Message> message = try_catch.Message();
12641   CHECK_EQ(1, message->GetLineNumber());
12642   CHECK_EQ(0, message->GetStartColumn());
12643 }
12644
12645
12646 THREADED_TEST(CompilationCache) {
12647   LocalContext context;
12648   v8::HandleScope scope(context->GetIsolate());
12649   v8::Handle<v8::String> source0 =
12650       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12651   v8::Handle<v8::String> source1 =
12652       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12653   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
12654   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
12655   v8::Handle<v8::Script> script2 =
12656       v8::Script::Compile(source0);  // different origin
12657   CHECK_EQ(1234, script0->Run()->Int32Value());
12658   CHECK_EQ(1234, script1->Run()->Int32Value());
12659   CHECK_EQ(1234, script2->Run()->Int32Value());
12660 }
12661
12662
12663 static void FunctionNameCallback(
12664     const v8::FunctionCallbackInfo<v8::Value>& args) {
12665   ApiTestFuzzer::Fuzz();
12666   args.GetReturnValue().Set(v8_num(42));
12667 }
12668
12669
12670 THREADED_TEST(CallbackFunctionName) {
12671   LocalContext context;
12672   v8::Isolate* isolate = context->GetIsolate();
12673   v8::HandleScope scope(isolate);
12674   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12675   t->Set(v8_str("asdf"),
12676          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
12677   context->Global()->Set(v8_str("obj"), t->NewInstance());
12678   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
12679   CHECK(value->IsString());
12680   v8::String::Utf8Value name(value);
12681   CHECK_EQ(0, strcmp("asdf", *name));
12682 }
12683
12684
12685 THREADED_TEST(DateAccess) {
12686   LocalContext context;
12687   v8::HandleScope scope(context->GetIsolate());
12688   v8::Handle<v8::Value> date =
12689       v8::Date::New(context->GetIsolate(), 1224744689038.0);
12690   CHECK(date->IsDate());
12691   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
12692 }
12693
12694
12695 void CheckProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12696                      unsigned elmc, const char* elmv[]) {
12697   v8::Handle<v8::Object> obj = val.As<v8::Object>();
12698   v8::Handle<v8::Array> props = obj->GetPropertyNames();
12699   CHECK_EQ(elmc, props->Length());
12700   for (unsigned i = 0; i < elmc; i++) {
12701     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12702     CHECK_EQ(0, strcmp(elmv[i], *elm));
12703   }
12704 }
12705
12706
12707 void CheckOwnProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12708                         unsigned elmc, const char* elmv[]) {
12709   v8::Handle<v8::Object> obj = val.As<v8::Object>();
12710   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
12711   CHECK_EQ(elmc, props->Length());
12712   for (unsigned i = 0; i < elmc; i++) {
12713     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12714     CHECK_EQ(0, strcmp(elmv[i], *elm));
12715   }
12716 }
12717
12718
12719 THREADED_TEST(PropertyEnumeration) {
12720   LocalContext context;
12721   v8::Isolate* isolate = context->GetIsolate();
12722   v8::HandleScope scope(isolate);
12723   v8::Handle<v8::Value> obj = CompileRun(
12724       "var result = [];"
12725       "result[0] = {};"
12726       "result[1] = {a: 1, b: 2};"
12727       "result[2] = [1, 2, 3];"
12728       "var proto = {x: 1, y: 2, z: 3};"
12729       "var x = { __proto__: proto, w: 0, z: 1 };"
12730       "result[3] = x;"
12731       "result;");
12732   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12733   CHECK_EQ(4u, elms->Length());
12734   int elmc0 = 0;
12735   const char** elmv0 = NULL;
12736   CheckProperties(
12737       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12738   CheckOwnProperties(
12739       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12740   int elmc1 = 2;
12741   const char* elmv1[] = {"a", "b"};
12742   CheckProperties(
12743       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12744   CheckOwnProperties(
12745       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12746   int elmc2 = 3;
12747   const char* elmv2[] = {"0", "1", "2"};
12748   CheckProperties(
12749       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12750   CheckOwnProperties(
12751       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12752   int elmc3 = 4;
12753   const char* elmv3[] = {"w", "z", "x", "y"};
12754   CheckProperties(
12755       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
12756   int elmc4 = 2;
12757   const char* elmv4[] = {"w", "z"};
12758   CheckOwnProperties(
12759       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
12760 }
12761
12762
12763 THREADED_TEST(PropertyEnumeration2) {
12764   LocalContext context;
12765   v8::Isolate* isolate = context->GetIsolate();
12766   v8::HandleScope scope(isolate);
12767   v8::Handle<v8::Value> obj = CompileRun(
12768       "var result = [];"
12769       "result[0] = {};"
12770       "result[1] = {a: 1, b: 2};"
12771       "result[2] = [1, 2, 3];"
12772       "var proto = {x: 1, y: 2, z: 3};"
12773       "var x = { __proto__: proto, w: 0, z: 1 };"
12774       "result[3] = x;"
12775       "result;");
12776   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12777   CHECK_EQ(4u, elms->Length());
12778   int elmc0 = 0;
12779   const char** elmv0 = NULL;
12780   CheckProperties(isolate,
12781                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12782
12783   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
12784   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
12785   CHECK_EQ(0u, props->Length());
12786   for (uint32_t i = 0; i < props->Length(); i++) {
12787     printf("p[%u]\n", i);
12788   }
12789 }
12790
12791
12792 THREADED_TEST(AccessChecksReenabledCorrectly) {
12793   LocalContext context;
12794   v8::Isolate* isolate = context->GetIsolate();
12795   v8::HandleScope scope(isolate);
12796   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12797   templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
12798   templ->Set(v8_str("a"), v8_str("a"));
12799   // Add more than 8 (see kMaxFastProperties) properties
12800   // so that the constructor will force copying map.
12801   // Cannot sprintf, gcc complains unsafety.
12802   char buf[4];
12803   for (char i = '0'; i <= '9' ; i++) {
12804     buf[0] = i;
12805     for (char j = '0'; j <= '9'; j++) {
12806       buf[1] = j;
12807       for (char k = '0'; k <= '9'; k++) {
12808         buf[2] = k;
12809         buf[3] = 0;
12810         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
12811       }
12812     }
12813   }
12814
12815   Local<v8::Object> instance_1 = templ->NewInstance();
12816   context->Global()->Set(v8_str("obj_1"), instance_1);
12817
12818   Local<Value> value_1 = CompileRun("obj_1.a");
12819   CHECK(value_1.IsEmpty());
12820
12821   Local<v8::Object> instance_2 = templ->NewInstance();
12822   context->Global()->Set(v8_str("obj_2"), instance_2);
12823
12824   Local<Value> value_2 = CompileRun("obj_2.a");
12825   CHECK(value_2.IsEmpty());
12826 }
12827
12828
12829 // Tests that ScriptData can be serialized and deserialized.
12830 TEST(PreCompileSerialization) {
12831   v8::V8::Initialize();
12832   LocalContext env;
12833   v8::Isolate* isolate = env->GetIsolate();
12834   HandleScope handle_scope(isolate);
12835
12836   i::FLAG_min_preparse_length = 0;
12837   const char* script = "function foo(a) { return a+1; }";
12838   v8::ScriptCompiler::Source source(v8_str(script));
12839   v8::ScriptCompiler::Compile(isolate, &source,
12840                               v8::ScriptCompiler::kProduceParserCache);
12841   // Serialize.
12842   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
12843   i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
12844   i::MemCopy(serialized_data, cd->data, cd->length);
12845
12846   // Deserialize.
12847   i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
12848
12849   // Verify that the original is the same as the deserialized.
12850   CHECK_EQ(cd->length, deserialized->length());
12851   CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
12852
12853   delete deserialized;
12854   i::DeleteArray(serialized_data);
12855 }
12856
12857
12858 // This tests that we do not allow dictionary load/call inline caches
12859 // to use functions that have not yet been compiled.  The potential
12860 // problem of loading a function that has not yet been compiled can
12861 // arise because we share code between contexts via the compilation
12862 // cache.
12863 THREADED_TEST(DictionaryICLoadedFunction) {
12864   v8::HandleScope scope(CcTest::isolate());
12865   // Test LoadIC.
12866   for (int i = 0; i < 2; i++) {
12867     LocalContext context;
12868     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12869     context->Global()->Delete(v8_str("tmp"));
12870     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12871   }
12872   // Test CallIC.
12873   for (int i = 0; i < 2; i++) {
12874     LocalContext context;
12875     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12876     context->Global()->Delete(v8_str("tmp"));
12877     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12878   }
12879 }
12880
12881
12882 // Test that cross-context new calls use the context of the callee to
12883 // create the new JavaScript object.
12884 THREADED_TEST(CrossContextNew) {
12885   v8::Isolate* isolate = CcTest::isolate();
12886   v8::HandleScope scope(isolate);
12887   v8::Local<Context> context0 = Context::New(isolate);
12888   v8::Local<Context> context1 = Context::New(isolate);
12889
12890   // Allow cross-domain access.
12891   Local<String> token = v8_str("<security token>");
12892   context0->SetSecurityToken(token);
12893   context1->SetSecurityToken(token);
12894
12895   // Set an 'x' property on the Object prototype and define a
12896   // constructor function in context0.
12897   context0->Enter();
12898   CompileRun("Object.prototype.x = 42; function C() {};");
12899   context0->Exit();
12900
12901   // Call the constructor function from context0 and check that the
12902   // result has the 'x' property.
12903   context1->Enter();
12904   context1->Global()->Set(v8_str("other"), context0->Global());
12905   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12906   CHECK(value->IsInt32());
12907   CHECK_EQ(42, value->Int32Value());
12908   context1->Exit();
12909 }
12910
12911
12912 // Verify that we can clone an object
12913 TEST(ObjectClone) {
12914   LocalContext env;
12915   v8::Isolate* isolate = env->GetIsolate();
12916   v8::HandleScope scope(isolate);
12917
12918   const char* sample =
12919     "var rv = {};"      \
12920     "rv.alpha = 'hello';" \
12921     "rv.beta = 123;"     \
12922     "rv;";
12923
12924   // Create an object, verify basics.
12925   Local<Value> val = CompileRun(sample);
12926   CHECK(val->IsObject());
12927   Local<v8::Object> obj = val.As<v8::Object>();
12928   obj->Set(v8_str("gamma"), v8_str("cloneme"));
12929
12930   CHECK(v8_str("hello")->Equals(obj->Get(v8_str("alpha"))));
12931   CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
12932   CHECK(v8_str("cloneme")->Equals(obj->Get(v8_str("gamma"))));
12933
12934   // Clone it.
12935   Local<v8::Object> clone = obj->Clone();
12936   CHECK(v8_str("hello")->Equals(clone->Get(v8_str("alpha"))));
12937   CHECK(v8::Integer::New(isolate, 123)->Equals(clone->Get(v8_str("beta"))));
12938   CHECK(v8_str("cloneme")->Equals(clone->Get(v8_str("gamma"))));
12939
12940   // Set a property on the clone, verify each object.
12941   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
12942   CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
12943   CHECK(v8::Integer::New(isolate, 456)->Equals(clone->Get(v8_str("beta"))));
12944 }
12945
12946
12947 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
12948  public:
12949   explicit OneByteVectorResource(i::Vector<const char> vector)
12950       : data_(vector) {}
12951   virtual ~OneByteVectorResource() {}
12952   virtual size_t length() const { return data_.length(); }
12953   virtual const char* data() const { return data_.start(); }
12954  private:
12955   i::Vector<const char> data_;
12956 };
12957
12958
12959 class UC16VectorResource : public v8::String::ExternalStringResource {
12960  public:
12961   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12962       : data_(vector) {}
12963   virtual ~UC16VectorResource() {}
12964   virtual size_t length() const { return data_.length(); }
12965   virtual const i::uc16* data() const { return data_.start(); }
12966  private:
12967   i::Vector<const i::uc16> data_;
12968 };
12969
12970
12971 static void MorphAString(i::String* string,
12972                          OneByteVectorResource* one_byte_resource,
12973                          UC16VectorResource* uc16_resource) {
12974   CHECK(i::StringShape(string).IsExternal());
12975   if (string->IsOneByteRepresentation()) {
12976     // Check old map is not internalized or long.
12977     CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
12978     // Morph external string to be TwoByte string.
12979     string->set_map(CcTest::heap()->external_string_map());
12980     i::ExternalTwoByteString* morphed =
12981          i::ExternalTwoByteString::cast(string);
12982     morphed->set_resource(uc16_resource);
12983   } else {
12984     // Check old map is not internalized or long.
12985     CHECK(string->map() == CcTest::heap()->external_string_map());
12986     // Morph external string to be one-byte string.
12987     string->set_map(CcTest::heap()->external_one_byte_string_map());
12988     i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
12989     morphed->set_resource(one_byte_resource);
12990   }
12991 }
12992
12993
12994 // Test that we can still flatten a string if the components it is built up
12995 // from have been turned into 16 bit strings in the mean time.
12996 THREADED_TEST(MorphCompositeStringTest) {
12997   char utf_buffer[129];
12998   const char* c_string = "Now is the time for all good men"
12999                          " to come to the aid of the party";
13000   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
13001   {
13002     LocalContext env;
13003     i::Factory* factory = CcTest::i_isolate()->factory();
13004     v8::HandleScope scope(env->GetIsolate());
13005     OneByteVectorResource one_byte_resource(
13006         i::Vector<const char>(c_string, i::StrLength(c_string)));
13007     UC16VectorResource uc16_resource(
13008         i::Vector<const uint16_t>(two_byte_string,
13009                                   i::StrLength(c_string)));
13010
13011     Local<String> lhs(
13012         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13013                                         &one_byte_resource).ToHandleChecked()));
13014     Local<String> rhs(
13015         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13016                                         &one_byte_resource).ToHandleChecked()));
13017
13018     env->Global()->Set(v8_str("lhs"), lhs);
13019     env->Global()->Set(v8_str("rhs"), rhs);
13020
13021     CompileRun(
13022         "var cons = lhs + rhs;"
13023         "var slice = lhs.substring(1, lhs.length - 1);"
13024         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
13025
13026     CHECK(lhs->IsOneByte());
13027     CHECK(rhs->IsOneByte());
13028
13029     MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
13030                  &uc16_resource);
13031     MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
13032                  &uc16_resource);
13033
13034     // This should UTF-8 without flattening, since everything is ASCII.
13035     Handle<String> cons = v8_compile("cons")->Run().As<String>();
13036     CHECK_EQ(128, cons->Utf8Length());
13037     int nchars = -1;
13038     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
13039     CHECK_EQ(128, nchars);
13040     CHECK_EQ(0, strcmp(
13041         utf_buffer,
13042         "Now is the time for all good men to come to the aid of the party"
13043         "Now is the time for all good men to come to the aid of the party"));
13044
13045     // Now do some stuff to make sure the strings are flattened, etc.
13046     CompileRun(
13047         "/[^a-z]/.test(cons);"
13048         "/[^a-z]/.test(slice);"
13049         "/[^a-z]/.test(slice_on_cons);");
13050     const char* expected_cons =
13051         "Now is the time for all good men to come to the aid of the party"
13052         "Now is the time for all good men to come to the aid of the party";
13053     const char* expected_slice =
13054         "ow is the time for all good men to come to the aid of the part";
13055     const char* expected_slice_on_cons =
13056         "ow is the time for all good men to come to the aid of the party"
13057         "Now is the time for all good men to come to the aid of the part";
13058     CHECK(String::NewFromUtf8(env->GetIsolate(), expected_cons)
13059               ->Equals(env->Global()->Get(v8_str("cons"))));
13060     CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice)
13061               ->Equals(env->Global()->Get(v8_str("slice"))));
13062     CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons)
13063               ->Equals(env->Global()->Get(v8_str("slice_on_cons"))));
13064   }
13065   i::DeleteArray(two_byte_string);
13066 }
13067
13068
13069 TEST(CompileExternalTwoByteSource) {
13070   LocalContext context;
13071   v8::HandleScope scope(context->GetIsolate());
13072
13073   // This is a very short list of sources, which currently is to check for a
13074   // regression caused by r2703.
13075   const char* one_byte_sources[] = {
13076       "0.5",
13077       "-0.5",   // This mainly testes PushBack in the Scanner.
13078       "--0.5",  // This mainly testes PushBack in the Scanner.
13079       NULL};
13080
13081   // Compile the sources as external two byte strings.
13082   for (int i = 0; one_byte_sources[i] != NULL; i++) {
13083     uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
13084     TestResource* uc16_resource = new TestResource(two_byte_string);
13085     v8::Local<v8::String> source =
13086         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
13087     v8::Script::Compile(source);
13088   }
13089 }
13090
13091
13092 #ifndef V8_INTERPRETED_REGEXP
13093
13094 struct RegExpInterruptionData {
13095   v8::base::Atomic32 loop_count;
13096   UC16VectorResource* string_resource;
13097   v8::Persistent<v8::String> string;
13098 } regexp_interruption_data;
13099
13100
13101 class RegExpInterruptionThread : public v8::base::Thread {
13102  public:
13103   explicit RegExpInterruptionThread(v8::Isolate* isolate)
13104       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
13105
13106   virtual void Run() {
13107     for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
13108          v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
13109          v8::base::NoBarrier_AtomicIncrement(
13110              &regexp_interruption_data.loop_count, 1)) {
13111       // Wait a bit before requesting GC.
13112       v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
13113       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
13114     }
13115     // Wait a bit before terminating.
13116     v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
13117     v8::V8::TerminateExecution(isolate_);
13118   }
13119
13120  private:
13121   v8::Isolate* isolate_;
13122 };
13123
13124
13125 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
13126   if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
13127     return;
13128   }
13129   v8::HandleScope scope(CcTest::isolate());
13130   v8::Local<v8::String> string = v8::Local<v8::String>::New(
13131       CcTest::isolate(), regexp_interruption_data.string);
13132   string->MakeExternal(regexp_interruption_data.string_resource);
13133 }
13134
13135
13136 // Test that RegExp execution can be interrupted.  Specifically, we test
13137 // * interrupting with GC
13138 // * turn the subject string from one-byte internal to two-byte external string
13139 // * force termination
13140 TEST(RegExpInterruption) {
13141   v8::HandleScope scope(CcTest::isolate());
13142   LocalContext env;
13143
13144   RegExpInterruptionThread timeout_thread(CcTest::isolate());
13145
13146   v8::V8::AddGCPrologueCallback(RunBeforeGC);
13147   static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
13148   i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
13149   v8::Local<v8::String> string = v8_str(one_byte_content);
13150
13151   CcTest::global()->Set(v8_str("a"), string);
13152   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
13153   regexp_interruption_data.string_resource = new UC16VectorResource(
13154       i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
13155
13156   v8::TryCatch try_catch(CcTest::isolate());
13157   timeout_thread.Start();
13158
13159   CompileRun("/((a*)*)*b/.exec(a)");
13160   CHECK(try_catch.HasTerminated());
13161
13162   timeout_thread.Join();
13163
13164   regexp_interruption_data.string.Reset();
13165   i::DeleteArray(uc16_content);
13166 }
13167
13168 #endif  // V8_INTERPRETED_REGEXP
13169
13170
13171 // Test that we cannot set a property on the global object if there
13172 // is a read-only property in the prototype chain.
13173 TEST(ReadOnlyPropertyInGlobalProto) {
13174   v8::Isolate* isolate = CcTest::isolate();
13175   v8::HandleScope scope(isolate);
13176   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13177   LocalContext context(0, templ);
13178   v8::Handle<v8::Object> global = context->Global();
13179   v8::Handle<v8::Object> global_proto =
13180       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13181   global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
13182                          v8::ReadOnly);
13183   global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
13184                          v8::ReadOnly);
13185   // Check without 'eval' or 'with'.
13186   v8::Handle<v8::Value> res =
13187       CompileRun("function f() { x = 42; return x; }; f()");
13188   CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13189   // Check with 'eval'.
13190   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13191   CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13192   // Check with 'with'.
13193   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13194   CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13195 }
13196
13197 static int force_set_set_count = 0;
13198 static int force_set_get_count = 0;
13199 bool pass_on_get = false;
13200
13201 static void ForceSetGetter(v8::Local<v8::String> name,
13202                            const v8::PropertyCallbackInfo<v8::Value>& info) {
13203   force_set_get_count++;
13204   if (pass_on_get) {
13205     return;
13206   }
13207   info.GetReturnValue().Set(3);
13208 }
13209
13210 static void ForceSetSetter(v8::Local<v8::String> name,
13211                            v8::Local<v8::Value> value,
13212                            const v8::PropertyCallbackInfo<void>& info) {
13213   force_set_set_count++;
13214 }
13215
13216 static void ForceSetInterceptGetter(
13217     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13218   CHECK(name->IsString());
13219   ForceSetGetter(Local<String>::Cast(name), info);
13220 }
13221
13222 static void ForceSetInterceptSetter(
13223     v8::Local<v8::Name> name, v8::Local<v8::Value> value,
13224     const v8::PropertyCallbackInfo<v8::Value>& info) {
13225   force_set_set_count++;
13226   info.GetReturnValue().SetUndefined();
13227 }
13228
13229
13230 TEST(ForceSet) {
13231   force_set_get_count = 0;
13232   force_set_set_count = 0;
13233   pass_on_get = false;
13234
13235   v8::Isolate* isolate = CcTest::isolate();
13236   v8::HandleScope scope(isolate);
13237   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13238   v8::Handle<v8::String> access_property =
13239       v8::String::NewFromUtf8(isolate, "a");
13240   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13241   LocalContext context(NULL, templ);
13242   v8::Handle<v8::Object> global = context->Global();
13243
13244   // Ordinary properties
13245   v8::Handle<v8::String> simple_property =
13246       v8::String::NewFromUtf8(isolate, "p");
13247   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
13248   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13249   // This should fail because the property is read-only
13250   global->Set(simple_property, v8::Int32::New(isolate, 5));
13251   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13252   // This should succeed even though the property is read-only
13253   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
13254   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13255
13256   // Accessors
13257   CHECK_EQ(0, force_set_set_count);
13258   CHECK_EQ(0, force_set_get_count);
13259   CHECK_EQ(3, global->Get(access_property)->Int32Value());
13260   // CHECK_EQ the property shouldn't override it, just call the setter
13261   // which in this case does nothing.
13262   global->Set(access_property, v8::Int32::New(isolate, 7));
13263   CHECK_EQ(3, global->Get(access_property)->Int32Value());
13264   CHECK_EQ(1, force_set_set_count);
13265   CHECK_EQ(2, force_set_get_count);
13266   // ForceSet doesn't call the accessors for now.
13267   // TODO(verwaest): Update once blink doesn't rely on ForceSet to delete api
13268   // accessors.
13269   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
13270   CHECK_EQ(8, global->Get(access_property)->Int32Value());
13271   CHECK_EQ(1, force_set_set_count);
13272   CHECK_EQ(2, force_set_get_count);
13273 }
13274
13275
13276 TEST(ForceSetWithInterceptor) {
13277   v8::Isolate* isolate = CcTest::isolate();
13278   v8::HandleScope scope(isolate);
13279   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13280   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13281       ForceSetInterceptGetter, ForceSetInterceptSetter));
13282   pass_on_get = true;
13283   LocalContext context(NULL, templ);
13284   v8::Handle<v8::Object> global = context->Global();
13285
13286   force_set_get_count = 0;
13287   force_set_set_count = 0;
13288   pass_on_get = false;
13289
13290   v8::Handle<v8::String> some_property =
13291       v8::String::NewFromUtf8(isolate, "a");
13292   CHECK_EQ(0, force_set_set_count);
13293   CHECK_EQ(0, force_set_get_count);
13294   CHECK_EQ(3, global->Get(some_property)->Int32Value());
13295   // Setting the property shouldn't override it, just call the setter
13296   // which in this case does nothing.
13297   global->Set(some_property, v8::Int32::New(isolate, 7));
13298   CHECK_EQ(3, global->Get(some_property)->Int32Value());
13299   CHECK_EQ(1, force_set_set_count);
13300   CHECK_EQ(2, force_set_get_count);
13301   // Getting the property when the interceptor returns an empty handle
13302   // should yield undefined, since the property isn't present on the
13303   // object itself yet.
13304   pass_on_get = true;
13305   CHECK(global->Get(some_property)->IsUndefined());
13306   CHECK_EQ(1, force_set_set_count);
13307   CHECK_EQ(3, force_set_get_count);
13308   // Forcing the property to be set should cause the value to be
13309   // set locally without calling the interceptor.
13310   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
13311   CHECK_EQ(8, global->Get(some_property)->Int32Value());
13312   CHECK_EQ(1, force_set_set_count);
13313   CHECK_EQ(4, force_set_get_count);
13314   // Reenabling the interceptor should cause it to take precedence over
13315   // the property
13316   pass_on_get = false;
13317   CHECK_EQ(3, global->Get(some_property)->Int32Value());
13318   CHECK_EQ(1, force_set_set_count);
13319   CHECK_EQ(5, force_set_get_count);
13320   // The interceptor should also work for other properties
13321   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
13322                   ->Int32Value());
13323   CHECK_EQ(1, force_set_set_count);
13324   CHECK_EQ(6, force_set_get_count);
13325 }
13326
13327
13328 TEST(CreateDataProperty) {
13329   LocalContext env;
13330   v8::Isolate* isolate = env->GetIsolate();
13331   v8::HandleScope handle_scope(isolate);
13332
13333   CompileRun(
13334       "var a = {};"
13335       "var b = [];"
13336       "Object.defineProperty(a, 'foo', {value: 23});"
13337       "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
13338
13339   v8::Local<v8::Object> obj =
13340       v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
13341   v8::Local<v8::Array> arr =
13342       v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b")));
13343   {
13344     // Can't change a non-configurable properties.
13345     v8::TryCatch try_catch(isolate);
13346     CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
13347                                    v8::Integer::New(isolate, 42)).FromJust());
13348     CHECK(!try_catch.HasCaught());
13349     CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
13350                                   v8::Integer::New(isolate, 42)).FromJust());
13351     CHECK(!try_catch.HasCaught());
13352     v8::Local<v8::Value> val =
13353         obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
13354     CHECK(val->IsNumber());
13355     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13356   }
13357
13358   {
13359     // Set a regular property.
13360     v8::TryCatch try_catch(isolate);
13361     CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
13362                                   v8::Integer::New(isolate, 42)).FromJust());
13363     CHECK(!try_catch.HasCaught());
13364     v8::Local<v8::Value> val =
13365         obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
13366     CHECK(val->IsNumber());
13367     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13368   }
13369
13370   {
13371     // Set an indexed property.
13372     v8::TryCatch try_catch(isolate);
13373     CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
13374                                   v8::Integer::New(isolate, 42)).FromJust());
13375     CHECK(!try_catch.HasCaught());
13376     v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
13377     CHECK(val->IsNumber());
13378     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13379   }
13380
13381   {
13382     // Special cases for arrays.
13383     v8::TryCatch try_catch(isolate);
13384     CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
13385                                    v8::Integer::New(isolate, 1)).FromJust());
13386     CHECK(!try_catch.HasCaught());
13387   }
13388   {
13389     // Special cases for arrays: index exceeds the array's length
13390     v8::TryCatch try_catch(isolate);
13391     CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
13392               .FromJust());
13393     CHECK(!try_catch.HasCaught());
13394     CHECK_EQ(2U, arr->Length());
13395     v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
13396     CHECK(val->IsNumber());
13397     CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
13398
13399     // Set an existing entry.
13400     CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
13401               .FromJust());
13402     CHECK(!try_catch.HasCaught());
13403     val = arr->Get(env.local(), 0).ToLocalChecked();
13404     CHECK(val->IsNumber());
13405     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13406   }
13407
13408   CompileRun("Object.freeze(a);");
13409   {
13410     // Can't change non-extensible objects.
13411     v8::TryCatch try_catch(isolate);
13412     CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
13413                                    v8::Integer::New(isolate, 42)).FromJust());
13414     CHECK(!try_catch.HasCaught());
13415   }
13416
13417   v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13418   templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
13419   v8::Local<v8::Object> access_checked =
13420       templ->NewInstance(env.local()).ToLocalChecked();
13421   {
13422     v8::TryCatch try_catch(isolate);
13423     CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
13424                                              v8::Integer::New(isolate, 42))
13425               .IsNothing());
13426     CHECK(try_catch.HasCaught());
13427   }
13428 }
13429
13430
13431 TEST(DefineOwnProperty) {
13432   LocalContext env;
13433   v8::Isolate* isolate = env->GetIsolate();
13434   v8::HandleScope handle_scope(isolate);
13435
13436   CompileRun(
13437       "var a = {};"
13438       "var b = [];"
13439       "Object.defineProperty(a, 'foo', {value: 23});"
13440       "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
13441
13442   v8::Local<v8::Object> obj =
13443       v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
13444   v8::Local<v8::Array> arr =
13445       v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b")));
13446   {
13447     // Can't change a non-configurable properties.
13448     v8::TryCatch try_catch(isolate);
13449     CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
13450                                   v8::Integer::New(isolate, 42)).FromJust());
13451     CHECK(!try_catch.HasCaught());
13452     CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
13453                                  v8::Integer::New(isolate, 42)).FromJust());
13454     CHECK(!try_catch.HasCaught());
13455     v8::Local<v8::Value> val =
13456         obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
13457     CHECK(val->IsNumber());
13458     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13459   }
13460
13461   {
13462     // Set a regular property.
13463     v8::TryCatch try_catch(isolate);
13464     CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
13465                                  v8::Integer::New(isolate, 42)).FromJust());
13466     CHECK(!try_catch.HasCaught());
13467     v8::Local<v8::Value> val =
13468         obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
13469     CHECK(val->IsNumber());
13470     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13471   }
13472
13473   {
13474     // Set an indexed property.
13475     v8::TryCatch try_catch(isolate);
13476     CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
13477                                  v8::Integer::New(isolate, 42)).FromJust());
13478     CHECK(!try_catch.HasCaught());
13479     v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
13480     CHECK(val->IsNumber());
13481     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13482   }
13483
13484   {
13485     // Special cases for arrays.
13486     v8::TryCatch try_catch(isolate);
13487     CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
13488                                   v8::Integer::New(isolate, 1)).FromJust());
13489     CHECK(!try_catch.HasCaught());
13490   }
13491   {
13492     // Special cases for arrays: index exceeds the array's length
13493     v8::TryCatch try_catch(isolate);
13494     CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
13495                                  v8::Integer::New(isolate, 23)).FromJust());
13496     CHECK(!try_catch.HasCaught());
13497     CHECK_EQ(2U, arr->Length());
13498     v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
13499     CHECK(val->IsNumber());
13500     CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
13501
13502     // Set an existing entry.
13503     CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
13504                                  v8::Integer::New(isolate, 42)).FromJust());
13505     CHECK(!try_catch.HasCaught());
13506     val = arr->Get(env.local(), 0).ToLocalChecked();
13507     CHECK(val->IsNumber());
13508     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13509   }
13510
13511   {
13512     // Set a non-writable property.
13513     v8::TryCatch try_catch(isolate);
13514     CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
13515                                  v8::Integer::New(isolate, 42),
13516                                  v8::ReadOnly).FromJust());
13517     CHECK(!try_catch.HasCaught());
13518     v8::Local<v8::Value> val =
13519         obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
13520     CHECK(val->IsNumber());
13521     CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13522     CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
13523                                     env.local(), v8_str("lala")).FromJust());
13524     CHECK(!try_catch.HasCaught());
13525   }
13526
13527   CompileRun("Object.freeze(a);");
13528   {
13529     // Can't change non-extensible objects.
13530     v8::TryCatch try_catch(isolate);
13531     CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
13532                                   v8::Integer::New(isolate, 42)).FromJust());
13533     CHECK(!try_catch.HasCaught());
13534   }
13535
13536   v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13537   templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
13538   v8::Local<v8::Object> access_checked =
13539       templ->NewInstance(env.local()).ToLocalChecked();
13540   {
13541     v8::TryCatch try_catch(isolate);
13542     CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
13543                                             v8::Integer::New(isolate, 42))
13544               .IsNothing());
13545     CHECK(try_catch.HasCaught());
13546   }
13547 }
13548
13549
13550 static v8::Local<Context> calling_context0;
13551 static v8::Local<Context> calling_context1;
13552 static v8::Local<Context> calling_context2;
13553
13554
13555 // Check that the call to the callback is initiated in
13556 // calling_context2, the directly calling context is calling_context1
13557 // and the callback itself is in calling_context0.
13558 static void GetCallingContextCallback(
13559     const v8::FunctionCallbackInfo<v8::Value>& args) {
13560   ApiTestFuzzer::Fuzz();
13561   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
13562   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
13563   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
13564   args.GetReturnValue().Set(42);
13565 }
13566
13567
13568 THREADED_TEST(GetCurrentContextWhenNotInContext) {
13569   i::Isolate* isolate = CcTest::i_isolate();
13570   CHECK(isolate != NULL);
13571   CHECK(isolate->context() == NULL);
13572   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
13573   v8::HandleScope scope(v8_isolate);
13574   // The following should not crash, but return an empty handle.
13575   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
13576   CHECK(current.IsEmpty());
13577 }
13578
13579
13580 THREADED_TEST(GetCallingContext) {
13581   v8::Isolate* isolate = CcTest::isolate();
13582   v8::HandleScope scope(isolate);
13583
13584   Local<Context> calling_context0(Context::New(isolate));
13585   Local<Context> calling_context1(Context::New(isolate));
13586   Local<Context> calling_context2(Context::New(isolate));
13587   ::calling_context0 = calling_context0;
13588   ::calling_context1 = calling_context1;
13589   ::calling_context2 = calling_context2;
13590
13591   // Allow cross-domain access.
13592   Local<String> token = v8_str("<security token>");
13593   calling_context0->SetSecurityToken(token);
13594   calling_context1->SetSecurityToken(token);
13595   calling_context2->SetSecurityToken(token);
13596
13597   // Create an object with a C++ callback in context0.
13598   calling_context0->Enter();
13599   Local<v8::FunctionTemplate> callback_templ =
13600       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
13601   calling_context0->Global()->Set(v8_str("callback"),
13602                                   callback_templ->GetFunction());
13603   calling_context0->Exit();
13604
13605   // Expose context0 in context1 and set up a function that calls the
13606   // callback function.
13607   calling_context1->Enter();
13608   calling_context1->Global()->Set(v8_str("context0"),
13609                                   calling_context0->Global());
13610   CompileRun("function f() { context0.callback() }");
13611   calling_context1->Exit();
13612
13613   // Expose context1 in context2 and call the callback function in
13614   // context0 indirectly through f in context1.
13615   calling_context2->Enter();
13616   calling_context2->Global()->Set(v8_str("context1"),
13617                                   calling_context1->Global());
13618   CompileRun("context1.f()");
13619   calling_context2->Exit();
13620   ::calling_context0.Clear();
13621   ::calling_context1.Clear();
13622   ::calling_context2.Clear();
13623 }
13624
13625
13626 // Check that a variable declaration with no explicit initialization
13627 // value does shadow an existing property in the prototype chain.
13628 THREADED_TEST(InitGlobalVarInProtoChain) {
13629   LocalContext context;
13630   v8::HandleScope scope(context->GetIsolate());
13631   // Introduce a variable in the prototype chain.
13632   CompileRun("__proto__.x = 42");
13633   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13634   CHECK(!result->IsUndefined());
13635   CHECK_EQ(43, result->Int32Value());
13636 }
13637
13638
13639 // Regression test for issue 398.
13640 // If a function is added to an object, creating a constant function
13641 // field, and the result is cloned, replacing the constant function on the
13642 // original should not affect the clone.
13643 // See http://code.google.com/p/v8/issues/detail?id=398
13644 THREADED_TEST(ReplaceConstantFunction) {
13645   LocalContext context;
13646   v8::Isolate* isolate = context->GetIsolate();
13647   v8::HandleScope scope(isolate);
13648   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
13649   v8::Handle<v8::FunctionTemplate> func_templ =
13650       v8::FunctionTemplate::New(isolate);
13651   v8::Handle<v8::String> foo_string =
13652       v8::String::NewFromUtf8(isolate, "foo");
13653   obj->Set(foo_string, func_templ->GetFunction());
13654   v8::Handle<v8::Object> obj_clone = obj->Clone();
13655   obj_clone->Set(foo_string,
13656                  v8::String::NewFromUtf8(isolate, "Hello"));
13657   CHECK(!obj->Get(foo_string)->IsUndefined());
13658 }
13659
13660
13661 static void CheckElementValue(i::Isolate* isolate,
13662                               int expected,
13663                               i::Handle<i::Object> obj,
13664                               int offset) {
13665   i::Object* element =
13666       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
13667   CHECK_EQ(expected, i::Smi::cast(element)->value());
13668 }
13669
13670
13671 template <class ExternalArrayClass, class ElementType>
13672 static void ObjectWithExternalArrayTestHelper(Handle<Context> context,
13673                                               v8::Handle<Object> obj,
13674                                               int element_count,
13675                                               i::ExternalArrayType array_type,
13676                                               int64_t low, int64_t high) {
13677   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13678   i::Isolate* isolate = jsobj->GetIsolate();
13679   obj->Set(v8_str("field"),
13680            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
13681   context->Global()->Set(v8_str("ext_array"), obj);
13682   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13683   CHECK_EQ(1503, result->Int32Value());
13684   result = CompileRun("ext_array[1]");
13685   CHECK_EQ(1, result->Int32Value());
13686
13687   // Check assigned smis
13688   result = CompileRun("for (var i = 0; i < 8; i++) {"
13689                       "  ext_array[i] = i;"
13690                       "}"
13691                       "var sum = 0;"
13692                       "for (var i = 0; i < 8; i++) {"
13693                       "  sum += ext_array[i];"
13694                       "}"
13695                       "sum;");
13696
13697   CHECK_EQ(28, result->Int32Value());
13698   // Check pass through of assigned smis
13699   result = CompileRun("var sum = 0;"
13700                       "for (var i = 0; i < 8; i++) {"
13701                       "  sum += ext_array[i] = ext_array[i] = -i;"
13702                       "}"
13703                       "sum;");
13704   CHECK_EQ(-28, result->Int32Value());
13705
13706
13707   // Check assigned smis in reverse order
13708   result = CompileRun("for (var i = 8; --i >= 0; ) {"
13709                       "  ext_array[i] = i;"
13710                       "}"
13711                       "var sum = 0;"
13712                       "for (var i = 0; i < 8; i++) {"
13713                       "  sum += ext_array[i];"
13714                       "}"
13715                       "sum;");
13716   CHECK_EQ(28, result->Int32Value());
13717
13718   // Check pass through of assigned HeapNumbers
13719   result = CompileRun("var sum = 0;"
13720                       "for (var i = 0; i < 16; i+=2) {"
13721                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13722                       "}"
13723                       "sum;");
13724   CHECK_EQ(-28, result->Int32Value());
13725
13726   // Check assigned HeapNumbers
13727   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13728                       "  ext_array[i] = (i * 0.5);"
13729                       "}"
13730                       "var sum = 0;"
13731                       "for (var i = 0; i < 16; i+=2) {"
13732                       "  sum += ext_array[i];"
13733                       "}"
13734                       "sum;");
13735   CHECK_EQ(28, result->Int32Value());
13736
13737   // Check assigned HeapNumbers in reverse order
13738   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13739                       "  ext_array[i] = (i * 0.5);"
13740                       "}"
13741                       "var sum = 0;"
13742                       "for (var i = 0; i < 16; i+=2) {"
13743                       "  sum += ext_array[i];"
13744                       "}"
13745                       "sum;");
13746   CHECK_EQ(28, result->Int32Value());
13747
13748   i::ScopedVector<char> test_buf(1024);
13749
13750   // Check legal boundary conditions.
13751   // The repeated loads and stores ensure the ICs are exercised.
13752   const char* boundary_program =
13753       "var res = 0;"
13754       "for (var i = 0; i < 16; i++) {"
13755       "  ext_array[i] = %lld;"
13756       "  if (i > 8) {"
13757       "    res = ext_array[i];"
13758       "  }"
13759       "}"
13760       "res;";
13761   i::SNPrintF(test_buf,
13762               boundary_program,
13763               low);
13764   result = CompileRun(test_buf.start());
13765   CHECK_EQ(low, result->IntegerValue());
13766
13767   i::SNPrintF(test_buf,
13768               boundary_program,
13769               high);
13770   result = CompileRun(test_buf.start());
13771   CHECK_EQ(high, result->IntegerValue());
13772
13773   // Check misprediction of type in IC.
13774   result = CompileRun("var tmp_array = ext_array;"
13775                       "var sum = 0;"
13776                       "for (var i = 0; i < 8; i++) {"
13777                       "  tmp_array[i] = i;"
13778                       "  sum += tmp_array[i];"
13779                       "  if (i == 4) {"
13780                       "    tmp_array = {};"
13781                       "  }"
13782                       "}"
13783                       "sum;");
13784   // Force GC to trigger verification.
13785   CcTest::heap()->CollectAllGarbage();
13786   CHECK_EQ(28, result->Int32Value());
13787
13788   // Make sure out-of-range loads do not throw.
13789   i::SNPrintF(test_buf,
13790               "var caught_exception = false;"
13791               "try {"
13792               "  ext_array[%d];"
13793               "} catch (e) {"
13794               "  caught_exception = true;"
13795               "}"
13796               "caught_exception;",
13797               element_count);
13798   result = CompileRun(test_buf.start());
13799   CHECK_EQ(false, result->BooleanValue());
13800
13801   // Make sure out-of-range stores do not throw.
13802   i::SNPrintF(test_buf,
13803               "var caught_exception = false;"
13804               "try {"
13805               "  ext_array[%d] = 1;"
13806               "} catch (e) {"
13807               "  caught_exception = true;"
13808               "}"
13809               "caught_exception;",
13810               element_count);
13811   result = CompileRun(test_buf.start());
13812   CHECK_EQ(false, result->BooleanValue());
13813
13814   // Check other boundary conditions, values and operations.
13815   result = CompileRun("for (var i = 0; i < 8; i++) {"
13816                       "  ext_array[7] = undefined;"
13817                       "}"
13818                       "ext_array[7];");
13819   CHECK_EQ(0, result->Int32Value());
13820   if (array_type == i::kExternalFloat64Array ||
13821       array_type == i::kExternalFloat32Array) {
13822     CHECK(std::isnan(
13823         i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
13824   } else {
13825     CheckElementValue(isolate, 0, jsobj, 7);
13826   }
13827
13828   result = CompileRun("for (var i = 0; i < 8; i++) {"
13829                       "  ext_array[6] = '2.3';"
13830                       "}"
13831                       "ext_array[6];");
13832   CHECK_EQ(2, result->Int32Value());
13833   CHECK_EQ(2,
13834            static_cast<int>(
13835                i::Object::GetElement(
13836                    isolate, jsobj, 6).ToHandleChecked()->Number()));
13837
13838   if (array_type != i::kExternalFloat32Array &&
13839       array_type != i::kExternalFloat64Array) {
13840     // Though the specification doesn't state it, be explicit about
13841     // converting NaNs and +/-Infinity to zero.
13842     result = CompileRun("for (var i = 0; i < 8; i++) {"
13843                         "  ext_array[i] = 5;"
13844                         "}"
13845                         "for (var i = 0; i < 8; i++) {"
13846                         "  ext_array[i] = NaN;"
13847                         "}"
13848                         "ext_array[5];");
13849     CHECK_EQ(0, result->Int32Value());
13850     CheckElementValue(isolate, 0, jsobj, 5);
13851
13852     result = CompileRun("for (var i = 0; i < 8; i++) {"
13853                         "  ext_array[i] = 5;"
13854                         "}"
13855                         "for (var i = 0; i < 8; i++) {"
13856                         "  ext_array[i] = Infinity;"
13857                         "}"
13858                         "ext_array[5];");
13859     int expected_value =
13860         (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
13861     CHECK_EQ(expected_value, result->Int32Value());
13862     CheckElementValue(isolate, expected_value, jsobj, 5);
13863
13864     result = CompileRun("for (var i = 0; i < 8; i++) {"
13865                         "  ext_array[i] = 5;"
13866                         "}"
13867                         "for (var i = 0; i < 8; i++) {"
13868                         "  ext_array[i] = -Infinity;"
13869                         "}"
13870                         "ext_array[5];");
13871     CHECK_EQ(0, result->Int32Value());
13872     CheckElementValue(isolate, 0, jsobj, 5);
13873
13874     // Check truncation behavior of integral arrays.
13875     const char* unsigned_data =
13876         "var source_data = [0.6, 10.6];"
13877         "var expected_results = [0, 10];";
13878     const char* signed_data =
13879         "var source_data = [0.6, 10.6, -0.6, -10.6];"
13880         "var expected_results = [0, 10, 0, -10];";
13881     const char* pixel_data =
13882         "var source_data = [0.6, 10.6];"
13883         "var expected_results = [1, 11];";
13884     bool is_unsigned = (array_type == i::kExternalUint8Array ||
13885                         array_type == i::kExternalUint16Array ||
13886                         array_type == i::kExternalUint32Array);
13887     bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
13888
13889     i::SNPrintF(test_buf,
13890                 "%s"
13891                 "var all_passed = true;"
13892                 "for (var i = 0; i < source_data.length; i++) {"
13893                 "  for (var j = 0; j < 8; j++) {"
13894                 "    ext_array[j] = source_data[i];"
13895                 "  }"
13896                 "  all_passed = all_passed &&"
13897                 "               (ext_array[5] == expected_results[i]);"
13898                 "}"
13899                 "all_passed;",
13900                 (is_unsigned ?
13901                      unsigned_data :
13902                      (is_pixel_data ? pixel_data : signed_data)));
13903     result = CompileRun(test_buf.start());
13904     CHECK_EQ(true, result->BooleanValue());
13905   }
13906
13907   i::Handle<ExternalArrayClass> array(
13908       ExternalArrayClass::cast(jsobj->elements()));
13909   for (int i = 0; i < element_count; i++) {
13910     array->set(i, static_cast<ElementType>(i));
13911   }
13912
13913   // Test complex assignments
13914   result = CompileRun("function ee_op_test_complex_func(sum) {"
13915                       " for (var i = 0; i < 40; ++i) {"
13916                       "   sum += (ext_array[i] += 1);"
13917                       "   sum += (ext_array[i] -= 1);"
13918                       " } "
13919                       " return sum;"
13920                       "}"
13921                       "sum=0;"
13922                       "for (var i=0;i<10000;++i) {"
13923                       "  sum=ee_op_test_complex_func(sum);"
13924                       "}"
13925                       "sum;");
13926   CHECK_EQ(16000000, result->Int32Value());
13927
13928   // Test count operations
13929   result = CompileRun("function ee_op_test_count_func(sum) {"
13930                       " for (var i = 0; i < 40; ++i) {"
13931                       "   sum += (++ext_array[i]);"
13932                       "   sum += (--ext_array[i]);"
13933                       " } "
13934                       " return sum;"
13935                       "}"
13936                       "sum=0;"
13937                       "for (var i=0;i<10000;++i) {"
13938                       "  sum=ee_op_test_count_func(sum);"
13939                       "}"
13940                       "sum;");
13941   CHECK_EQ(16000000, result->Int32Value());
13942
13943   result = CompileRun("ext_array[3] = 33;"
13944                       "delete ext_array[3];"
13945                       "ext_array[3];");
13946   CHECK_EQ(33, result->Int32Value());
13947
13948   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13949                       "ext_array[2] = 12; ext_array[3] = 13;"
13950                       "ext_array.__defineGetter__('2',"
13951                       "function() { return 120; });"
13952                       "ext_array[2];");
13953   CHECK_EQ(12, result->Int32Value());
13954
13955   result = CompileRun("var js_array = new Array(40);"
13956                       "js_array[0] = 77;"
13957                       "js_array;");
13958   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13959
13960   result = CompileRun("ext_array[1] = 23;"
13961                       "ext_array.__proto__ = [];"
13962                       "js_array.__proto__ = ext_array;"
13963                       "js_array.concat(ext_array);");
13964   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13965   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13966
13967   result = CompileRun("ext_array[1] = 23;");
13968   CHECK_EQ(23, result->Int32Value());
13969 }
13970
13971
13972 template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
13973           class ElementType>
13974 static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
13975                                       ElementType low, ElementType high) {
13976   i::FLAG_allow_natives_syntax = true;
13977   LocalContext context;
13978   i::Isolate* isolate = CcTest::i_isolate();
13979   i::Factory* factory = isolate->factory();
13980   v8::HandleScope scope(context->GetIsolate());
13981   const int kElementCount = 260;
13982   i::Handle<i::JSTypedArray> jsobj =
13983       factory->NewJSTypedArray(elements_kind, kElementCount);
13984   i::Handle<FixedTypedArrayClass> fixed_array(
13985       FixedTypedArrayClass::cast(jsobj->elements()));
13986   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
13987            fixed_array->map()->instance_type());
13988   CHECK_EQ(kElementCount, fixed_array->length());
13989   CcTest::heap()->CollectAllGarbage();
13990   for (int i = 0; i < kElementCount; i++) {
13991     fixed_array->set(i, static_cast<ElementType>(i));
13992   }
13993   // Force GC to trigger verification.
13994   CcTest::heap()->CollectAllGarbage();
13995   for (int i = 0; i < kElementCount; i++) {
13996     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
13997              static_cast<int64_t>(fixed_array->get_scalar(i)));
13998   }
13999   v8::Handle<v8::Object> obj = v8::Utils::ToLocal(jsobj);
14000
14001   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
14002       context.local(), obj, kElementCount, array_type,
14003       static_cast<int64_t>(low),
14004       static_cast<int64_t>(high));
14005 }
14006
14007
14008 THREADED_TEST(FixedUint8Array) {
14009   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
14010       i::kExternalUint8Array, 0x0, 0xFF);
14011 }
14012
14013
14014 THREADED_TEST(FixedUint8ClampedArray) {
14015   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
14016                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
14017       i::kExternalUint8ClampedArray, 0x0, 0xFF);
14018 }
14019
14020
14021 THREADED_TEST(FixedInt8Array) {
14022   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
14023       i::kExternalInt8Array, -0x80, 0x7F);
14024 }
14025
14026
14027 THREADED_TEST(FixedUint16Array) {
14028   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
14029       i::kExternalUint16Array, 0x0, 0xFFFF);
14030 }
14031
14032
14033 THREADED_TEST(FixedInt16Array) {
14034   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
14035       i::kExternalInt16Array, -0x8000, 0x7FFF);
14036 }
14037
14038
14039 THREADED_TEST(FixedUint32Array) {
14040   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
14041       i::kExternalUint32Array, 0x0, UINT_MAX);
14042 }
14043
14044
14045 THREADED_TEST(FixedInt32Array) {
14046   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
14047       i::kExternalInt32Array, INT_MIN, INT_MAX);
14048 }
14049
14050
14051 THREADED_TEST(FixedFloat32Array) {
14052   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
14053       i::kExternalFloat32Array, -500, 500);
14054 }
14055
14056
14057 THREADED_TEST(FixedFloat64Array) {
14058   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
14059       i::kExternalFloat64Array, -500, 500);
14060 }
14061
14062
14063 template <typename ElementType, typename TypedArray, class ExternalArrayClass,
14064           class ArrayBufferType>
14065 void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
14066                           int64_t high) {
14067   const int kElementCount = 50;
14068
14069   i::ScopedVector<ElementType> backing_store(kElementCount+2);
14070
14071   LocalContext env;
14072   v8::Isolate* isolate = env->GetIsolate();
14073   v8::HandleScope handle_scope(isolate);
14074
14075   Local<ArrayBufferType> ab =
14076       ArrayBufferType::New(isolate, backing_store.start(),
14077                            (kElementCount + 2) * sizeof(ElementType));
14078   Local<TypedArray> ta =
14079       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
14080   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
14081   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
14082   CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
14083   CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
14084   CHECK(ab->Equals(ta->Buffer()));
14085
14086   ElementType* data = backing_store.start() + 2;
14087   for (int i = 0; i < kElementCount; i++) {
14088     data[i] = static_cast<ElementType>(i);
14089   }
14090
14091   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14092       env.local(), ta, kElementCount, array_type, low, high);
14093 }
14094
14095
14096 THREADED_TEST(Uint8Array) {
14097   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
14098                        v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
14099 }
14100
14101
14102 THREADED_TEST(Int8Array) {
14103   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
14104                        v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
14105 }
14106
14107
14108 THREADED_TEST(Uint16Array) {
14109   TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
14110                        v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
14111 }
14112
14113
14114 THREADED_TEST(Int16Array) {
14115   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
14116                        v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
14117                                         0x7FFF);
14118 }
14119
14120
14121 THREADED_TEST(Uint32Array) {
14122   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
14123                        v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
14124 }
14125
14126
14127 THREADED_TEST(Int32Array) {
14128   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
14129                        v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
14130                                         INT_MAX);
14131 }
14132
14133
14134 THREADED_TEST(Float32Array) {
14135   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
14136                        v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
14137 }
14138
14139
14140 THREADED_TEST(Float64Array) {
14141   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
14142                        v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
14143 }
14144
14145
14146 THREADED_TEST(Uint8ClampedArray) {
14147   TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
14148                        i::ExternalUint8ClampedArray, v8::ArrayBuffer>(
14149       i::kExternalUint8ClampedArray, 0, 0xFF);
14150 }
14151
14152
14153 THREADED_TEST(DataView) {
14154   const int kSize = 50;
14155
14156   i::ScopedVector<uint8_t> backing_store(kSize+2);
14157
14158   LocalContext env;
14159   v8::Isolate* isolate = env->GetIsolate();
14160   v8::HandleScope handle_scope(isolate);
14161
14162   Local<v8::ArrayBuffer> ab =
14163       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14164   Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
14165   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14166   CHECK_EQ(2u, dv->ByteOffset());
14167   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14168   CHECK(ab->Equals(dv->Buffer()));
14169 }
14170
14171
14172 THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
14173   LocalContext env;
14174   v8::Isolate* isolate = env->GetIsolate();
14175   v8::HandleScope handle_scope(isolate);
14176
14177   // Make sure the pointer looks like a heap object
14178   uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
14179
14180   // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
14181   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
14182
14183   // Should not crash
14184   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
14185   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
14186   CcTest::heap()->CollectAllGarbage();
14187   CcTest::heap()->CollectAllGarbage();
14188
14189   // Should not move the pointer
14190   CHECK_EQ(ab->GetContents().Data(), store_ptr);
14191 }
14192
14193
14194 THREADED_TEST(SharedUint8Array) {
14195   i::FLAG_harmony_sharedarraybuffer = true;
14196   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
14197                        v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
14198 }
14199
14200
14201 THREADED_TEST(SharedInt8Array) {
14202   i::FLAG_harmony_sharedarraybuffer = true;
14203   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
14204                        v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
14205                                               0x7F);
14206 }
14207
14208
14209 THREADED_TEST(SharedUint16Array) {
14210   i::FLAG_harmony_sharedarraybuffer = true;
14211   TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
14212                        v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
14213                                               0xFFFF);
14214 }
14215
14216
14217 THREADED_TEST(SharedInt16Array) {
14218   i::FLAG_harmony_sharedarraybuffer = true;
14219   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
14220                        v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
14221                                               0x7FFF);
14222 }
14223
14224
14225 THREADED_TEST(SharedUint32Array) {
14226   i::FLAG_harmony_sharedarraybuffer = true;
14227   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
14228                        v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
14229                                               UINT_MAX);
14230 }
14231
14232
14233 THREADED_TEST(SharedInt32Array) {
14234   i::FLAG_harmony_sharedarraybuffer = true;
14235   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
14236                        v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
14237                                               INT_MAX);
14238 }
14239
14240
14241 THREADED_TEST(SharedFloat32Array) {
14242   i::FLAG_harmony_sharedarraybuffer = true;
14243   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
14244                        v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
14245                                               500);
14246 }
14247
14248
14249 THREADED_TEST(SharedFloat64Array) {
14250   i::FLAG_harmony_sharedarraybuffer = true;
14251   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
14252                        v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
14253                                               500);
14254 }
14255
14256
14257 THREADED_TEST(SharedUint8ClampedArray) {
14258   i::FLAG_harmony_sharedarraybuffer = true;
14259   TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
14260                        i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>(
14261       i::kExternalUint8ClampedArray, 0, 0xFF);
14262 }
14263
14264
14265 THREADED_TEST(SharedDataView) {
14266   i::FLAG_harmony_sharedarraybuffer = true;
14267   const int kSize = 50;
14268
14269   i::ScopedVector<uint8_t> backing_store(kSize + 2);
14270
14271   LocalContext env;
14272   v8::Isolate* isolate = env->GetIsolate();
14273   v8::HandleScope handle_scope(isolate);
14274
14275   Local<v8::SharedArrayBuffer> ab =
14276       v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14277   Local<v8::DataView> dv =
14278       v8::DataView::New(ab, 2, kSize);
14279   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14280   CHECK_EQ(2u, dv->ByteOffset());
14281   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14282   CHECK(ab->Equals(dv->Buffer()));
14283 }
14284
14285
14286 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
14287   THREADED_TEST(Is##View) {                                                   \
14288     LocalContext env;                                                         \
14289     v8::Isolate* isolate = env->GetIsolate();                                 \
14290     v8::HandleScope handle_scope(isolate);                                    \
14291                                                                               \
14292     Handle<Value> result = CompileRun(                                        \
14293         "var ab = new ArrayBuffer(128);"                                      \
14294         "new " #View "(ab)");                                                 \
14295     CHECK(result->IsArrayBufferView());                                       \
14296     CHECK(result->Is##View());                                                \
14297     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
14298   }
14299
14300 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
14301 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
14302 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
14303 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
14304 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
14305 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
14306 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
14307 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
14308 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
14309 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
14310
14311 #undef IS_ARRAY_BUFFER_VIEW_TEST
14312
14313
14314
14315 THREADED_TEST(ScriptContextDependence) {
14316   LocalContext c1;
14317   v8::HandleScope scope(c1->GetIsolate());
14318   const char *source = "foo";
14319   v8::Handle<v8::Script> dep = v8_compile(source);
14320   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
14321       c1->GetIsolate(), source));
14322   v8::Handle<v8::UnboundScript> indep =
14323       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
14324   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
14325                     v8::Integer::New(c1->GetIsolate(), 100));
14326   CHECK_EQ(dep->Run()->Int32Value(), 100);
14327   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
14328   LocalContext c2;
14329   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
14330                     v8::Integer::New(c2->GetIsolate(), 101));
14331   CHECK_EQ(dep->Run()->Int32Value(), 100);
14332   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
14333 }
14334
14335
14336 THREADED_TEST(StackTrace) {
14337   LocalContext context;
14338   v8::HandleScope scope(context->GetIsolate());
14339   v8::TryCatch try_catch(context->GetIsolate());
14340   const char *source = "function foo() { FAIL.FAIL; }; foo();";
14341   v8::Handle<v8::String> src =
14342       v8::String::NewFromUtf8(context->GetIsolate(), source);
14343   v8::Handle<v8::String> origin =
14344       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
14345   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
14346   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
14347       ->BindToCurrentContext()
14348       ->Run();
14349   CHECK(try_catch.HasCaught());
14350   v8::String::Utf8Value stack(try_catch.StackTrace());
14351   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14352 }
14353
14354
14355 // Checks that a StackFrame has certain expected values.
14356 void checkStackFrame(const char* expected_script_name,
14357     const char* expected_func_name, int expected_line_number,
14358     int expected_column, bool is_eval, bool is_constructor,
14359     v8::Handle<v8::StackFrame> frame) {
14360   v8::HandleScope scope(CcTest::isolate());
14361   v8::String::Utf8Value func_name(frame->GetFunctionName());
14362   v8::String::Utf8Value script_name(frame->GetScriptName());
14363   if (*script_name == NULL) {
14364     // The situation where there is no associated script, like for evals.
14365     CHECK(expected_script_name == NULL);
14366   } else {
14367     CHECK(strstr(*script_name, expected_script_name) != NULL);
14368   }
14369   CHECK(strstr(*func_name, expected_func_name) != NULL);
14370   CHECK_EQ(expected_line_number, frame->GetLineNumber());
14371   CHECK_EQ(expected_column, frame->GetColumn());
14372   CHECK_EQ(is_eval, frame->IsEval());
14373   CHECK_EQ(is_constructor, frame->IsConstructor());
14374 }
14375
14376
14377 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
14378   v8::HandleScope scope(args.GetIsolate());
14379   const char* origin = "capture-stack-trace-test";
14380   const int kOverviewTest = 1;
14381   const int kDetailedTest = 2;
14382
14383   DCHECK(args.Length() == 1);
14384
14385   int testGroup = args[0]->Int32Value();
14386   if (testGroup == kOverviewTest) {
14387     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14388         args.GetIsolate(), 10, v8::StackTrace::kOverview);
14389     CHECK_EQ(4, stackTrace->GetFrameCount());
14390     checkStackFrame(origin, "bar", 2, 10, false, false,
14391                     stackTrace->GetFrame(0));
14392     checkStackFrame(origin, "foo", 6, 3, false, false,
14393                     stackTrace->GetFrame(1));
14394     // This is the source string inside the eval which has the call to foo.
14395     checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2));
14396     // The last frame is an anonymous function which has the initial eval call.
14397     checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3));
14398
14399     CHECK(stackTrace->AsArray()->IsArray());
14400   } else if (testGroup == kDetailedTest) {
14401     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14402         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
14403     CHECK_EQ(4, stackTrace->GetFrameCount());
14404     checkStackFrame(origin, "bat", 4, 22, false, false,
14405                     stackTrace->GetFrame(0));
14406     checkStackFrame(origin, "baz", 8, 3, false, true,
14407                     stackTrace->GetFrame(1));
14408     bool is_eval = true;
14409     // This is the source string inside the eval which has the call to baz.
14410     checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2));
14411     // The last frame is an anonymous function which has the initial eval call.
14412     checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3));
14413
14414     CHECK(stackTrace->AsArray()->IsArray());
14415   }
14416 }
14417
14418
14419 // Tests the C++ StackTrace API.
14420 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14421 // THREADED_TEST(CaptureStackTrace) {
14422 TEST(CaptureStackTrace) {
14423   v8::Isolate* isolate = CcTest::isolate();
14424   v8::HandleScope scope(isolate);
14425   v8::Handle<v8::String> origin =
14426       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
14427   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14428   templ->Set(v8_str("AnalyzeStackInNativeCode"),
14429              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
14430   LocalContext context(0, templ);
14431
14432   // Test getting OVERVIEW information. Should ignore information that is not
14433   // script name, function name, line number, and column offset.
14434   const char *overview_source =
14435     "function bar() {\n"
14436     "  var y; AnalyzeStackInNativeCode(1);\n"
14437     "}\n"
14438     "function foo() {\n"
14439     "\n"
14440     "  bar();\n"
14441     "}\n"
14442     "var x;eval('new foo();');";
14443   v8::Handle<v8::String> overview_src =
14444       v8::String::NewFromUtf8(isolate, overview_source);
14445   v8::ScriptCompiler::Source script_source(overview_src,
14446                                            v8::ScriptOrigin(origin));
14447   v8::Handle<Value> overview_result(
14448       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
14449           ->BindToCurrentContext()
14450           ->Run());
14451   CHECK(!overview_result.IsEmpty());
14452   CHECK(overview_result->IsObject());
14453
14454   // Test getting DETAILED information.
14455   const char *detailed_source =
14456     "function bat() {AnalyzeStackInNativeCode(2);\n"
14457     "}\n"
14458     "\n"
14459     "function baz() {\n"
14460     "  bat();\n"
14461     "}\n"
14462     "eval('new baz();');";
14463   v8::Handle<v8::String> detailed_src =
14464       v8::String::NewFromUtf8(isolate, detailed_source);
14465   // Make the script using a non-zero line and column offset.
14466   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
14467   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
14468   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14469   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
14470   v8::Handle<v8::UnboundScript> detailed_script(
14471       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
14472   v8::Handle<Value> detailed_result(
14473       detailed_script->BindToCurrentContext()->Run());
14474   CHECK(!detailed_result.IsEmpty());
14475   CHECK(detailed_result->IsObject());
14476 }
14477
14478
14479 static void StackTraceForUncaughtExceptionListener(
14480     v8::Handle<v8::Message> message,
14481     v8::Handle<Value>) {
14482   report_count++;
14483   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14484   CHECK_EQ(2, stack_trace->GetFrameCount());
14485   checkStackFrame("origin", "foo", 2, 3, false, false,
14486                   stack_trace->GetFrame(0));
14487   checkStackFrame("origin", "bar", 5, 3, false, false,
14488                   stack_trace->GetFrame(1));
14489 }
14490
14491
14492 TEST(CaptureStackTraceForUncaughtException) {
14493   report_count = 0;
14494   LocalContext env;
14495   v8::HandleScope scope(env->GetIsolate());
14496   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14497   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14498
14499   CompileRunWithOrigin(
14500       "function foo() {\n"
14501       "  throw 1;\n"
14502       "};\n"
14503       "function bar() {\n"
14504       "  foo();\n"
14505       "};",
14506       "origin");
14507   v8::Local<v8::Object> global = env->Global();
14508   Local<Value> trouble = global->Get(v8_str("bar"));
14509   CHECK(trouble->IsFunction());
14510   Function::Cast(*trouble)->Call(global, 0, NULL);
14511   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14512   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14513   CHECK_EQ(1, report_count);
14514 }
14515
14516
14517 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
14518   report_count = 0;
14519   LocalContext env;
14520   v8::HandleScope scope(env->GetIsolate());
14521
14522   // Create an Error object first.
14523   CompileRunWithOrigin(
14524       "function foo() {\n"
14525       "e=new Error('err');\n"
14526       "};\n"
14527       "function bar() {\n"
14528       "  foo();\n"
14529       "};\n"
14530       "var e;",
14531       "origin");
14532   v8::Local<v8::Object> global = env->Global();
14533   Local<Value> trouble = global->Get(v8_str("bar"));
14534   CHECK(trouble->IsFunction());
14535   Function::Cast(*trouble)->Call(global, 0, NULL);
14536
14537   // Enable capturing detailed stack trace late, and throw the exception.
14538   // The detailed stack trace should be extracted from the simple stack.
14539   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14540   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14541   CompileRunWithOrigin("throw e", "origin");
14542   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14543   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14544   CHECK_EQ(1, report_count);
14545 }
14546
14547
14548 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14549   LocalContext env;
14550   v8::HandleScope scope(env->GetIsolate());
14551   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14552                                                     1024,
14553                                                     v8::StackTrace::kDetailed);
14554
14555   CompileRun(
14556       "var setters = ['column', 'lineNumber', 'scriptName',\n"
14557       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14558       "    'isConstructor'];\n"
14559       "for (var i = 0; i < setters.length; i++) {\n"
14560       "  var prop = setters[i];\n"
14561       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14562       "}\n");
14563   CompileRun("throw 'exception';");
14564   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14565 }
14566
14567
14568 static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
14569                                            v8::Handle<Value>) {
14570   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14571   CHECK_EQ(5, stack_trace->GetFrameCount());
14572   checkStackFrame("origin", "foo:0", 4, 7, false, false,
14573                   stack_trace->GetFrame(0));
14574   checkStackFrame("origin", "foo:1", 5, 27, false, false,
14575                   stack_trace->GetFrame(1));
14576   checkStackFrame("origin", "foo", 5, 27, false, false,
14577                   stack_trace->GetFrame(2));
14578   checkStackFrame("origin", "foo", 5, 27, false, false,
14579                   stack_trace->GetFrame(3));
14580   checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
14581 }
14582
14583
14584 TEST(GetStackTraceContainsFunctionsWithFunctionName) {
14585   LocalContext env;
14586   v8::HandleScope scope(env->GetIsolate());
14587
14588   CompileRunWithOrigin(
14589       "function gen(name, counter) {\n"
14590       "  var f = function foo() {\n"
14591       "    if (counter === 0)\n"
14592       "      throw 1;\n"
14593       "    gen(name, counter - 1)();\n"
14594       "  };\n"
14595       "  if (counter == 3) {\n"
14596       "    Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
14597       "  } else {\n"
14598       "    Object.defineProperty(f, 'name', {writable:true});\n"
14599       "    if (counter == 2)\n"
14600       "      f.name = 42;\n"
14601       "    else\n"
14602       "      f.name = name + ':' + counter;\n"
14603       "  }\n"
14604       "  return f;\n"
14605       "};",
14606       "origin");
14607
14608   v8::V8::AddMessageListener(StackTraceFunctionNameListener);
14609   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14610   CompileRunWithOrigin("gen('foo', 3)();", "origin");
14611   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14612   v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
14613 }
14614
14615
14616 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14617                                      v8::Handle<v8::Value> data) {
14618   // Use the frame where JavaScript is called from.
14619   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14620   CHECK(!stack_trace.IsEmpty());
14621   int frame_count = stack_trace->GetFrameCount();
14622   CHECK_EQ(3, frame_count);
14623   int line_number[] = {1, 2, 5};
14624   for (int i = 0; i < frame_count; i++) {
14625     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14626   }
14627 }
14628
14629
14630 // Test that we only return the stack trace at the site where the exception
14631 // is first thrown (not where it is rethrown).
14632 TEST(RethrowStackTrace) {
14633   LocalContext env;
14634   v8::HandleScope scope(env->GetIsolate());
14635   // We make sure that
14636   // - the stack trace of the ReferenceError in g() is reported.
14637   // - the stack trace is not overwritten when e1 is rethrown by t().
14638   // - the stack trace of e2 does not overwrite that of e1.
14639   const char* source =
14640       "function g() { error; }          \n"
14641       "function f() { g(); }            \n"
14642       "function t(e) { throw e; }       \n"
14643       "try {                            \n"
14644       "  f();                           \n"
14645       "} catch (e1) {                   \n"
14646       "  try {                          \n"
14647       "    error;                       \n"
14648       "  } catch (e2) {                 \n"
14649       "    t(e1);                       \n"
14650       "  }                              \n"
14651       "}                                \n";
14652   v8::V8::AddMessageListener(RethrowStackTraceHandler);
14653   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14654   CompileRun(source);
14655   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14656   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14657 }
14658
14659
14660 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14661                                               v8::Handle<v8::Value> data) {
14662   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14663   CHECK(!stack_trace.IsEmpty());
14664   int frame_count = stack_trace->GetFrameCount();
14665   CHECK_EQ(2, frame_count);
14666   int line_number[] = {3, 7};
14667   for (int i = 0; i < frame_count; i++) {
14668     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14669   }
14670 }
14671
14672
14673 // Test that we do not recognize identity for primitive exceptions.
14674 TEST(RethrowPrimitiveStackTrace) {
14675   LocalContext env;
14676   v8::HandleScope scope(env->GetIsolate());
14677   // We do not capture stack trace for non Error objects on creation time.
14678   // Instead, we capture the stack trace on last throw.
14679   const char* source =
14680       "function g() { throw 404; }      \n"
14681       "function f() { g(); }            \n"
14682       "function t(e) { throw e; }       \n"
14683       "try {                            \n"
14684       "  f();                           \n"
14685       "} catch (e1) {                   \n"
14686       "  t(e1)                          \n"
14687       "}                                \n";
14688   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14689   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14690   CompileRun(source);
14691   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14692   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14693 }
14694
14695
14696 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14697                                               v8::Handle<v8::Value> data) {
14698   // Use the frame where JavaScript is called from.
14699   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14700   CHECK(!stack_trace.IsEmpty());
14701   CHECK_EQ(1, stack_trace->GetFrameCount());
14702   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14703 }
14704
14705
14706 // Test that the stack trace is captured when the error object is created and
14707 // not where it is thrown.
14708 TEST(RethrowExistingStackTrace) {
14709   LocalContext env;
14710   v8::HandleScope scope(env->GetIsolate());
14711   const char* source =
14712       "var e = new Error();           \n"
14713       "throw e;                       \n";
14714   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14715   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14716   CompileRun(source);
14717   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14718   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14719 }
14720
14721
14722 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14723                                                v8::Handle<v8::Value> data) {
14724   // Use the frame where JavaScript is called from.
14725   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14726   CHECK(!stack_trace.IsEmpty());
14727   CHECK_EQ(1, stack_trace->GetFrameCount());
14728   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14729 }
14730
14731
14732 // Test that the stack trace is captured where the bogus Error object is thrown.
14733 TEST(RethrowBogusErrorStackTrace) {
14734   LocalContext env;
14735   v8::HandleScope scope(env->GetIsolate());
14736   const char* source =
14737       "var e = {__proto__: new Error()} \n"
14738       "throw e;                         \n";
14739   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14740   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14741   CompileRun(source);
14742   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14743   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14744 }
14745
14746
14747 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
14748 int promise_reject_counter = 0;
14749 int promise_revoke_counter = 0;
14750 int promise_reject_msg_line_number = -1;
14751 int promise_reject_msg_column_number = -1;
14752 int promise_reject_line_number = -1;
14753 int promise_reject_column_number = -1;
14754 int promise_reject_frame_count = -1;
14755
14756 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
14757   if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
14758     promise_reject_counter++;
14759     CcTest::global()->Set(v8_str("rejected"), reject_message.GetPromise());
14760     CcTest::global()->Set(v8_str("value"), reject_message.GetValue());
14761     v8::Handle<v8::Message> message =
14762         v8::Exception::CreateMessage(reject_message.GetValue());
14763     v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14764
14765     promise_reject_msg_line_number = message->GetLineNumber();
14766     promise_reject_msg_column_number = message->GetStartColumn() + 1;
14767
14768     if (!stack_trace.IsEmpty()) {
14769       promise_reject_frame_count = stack_trace->GetFrameCount();
14770       if (promise_reject_frame_count > 0) {
14771         CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
14772         promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
14773         promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
14774       } else {
14775         promise_reject_line_number = -1;
14776         promise_reject_column_number = -1;
14777       }
14778     }
14779   } else {
14780     promise_revoke_counter++;
14781     CcTest::global()->Set(v8_str("revoked"), reject_message.GetPromise());
14782     CHECK(reject_message.GetValue().IsEmpty());
14783   }
14784 }
14785
14786
14787 v8::Handle<v8::Promise> GetPromise(const char* name) {
14788   return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
14789 }
14790
14791
14792 v8::Handle<v8::Value> RejectValue() {
14793   return CcTest::global()->Get(v8_str("value"));
14794 }
14795
14796
14797 void ResetPromiseStates() {
14798   promise_reject_counter = 0;
14799   promise_revoke_counter = 0;
14800   promise_reject_msg_line_number = -1;
14801   promise_reject_msg_column_number = -1;
14802   promise_reject_line_number = -1;
14803   promise_reject_column_number = -1;
14804   promise_reject_frame_count = -1;
14805   CcTest::global()->Set(v8_str("rejected"), v8_str(""));
14806   CcTest::global()->Set(v8_str("value"), v8_str(""));
14807   CcTest::global()->Set(v8_str("revoked"), v8_str(""));
14808 }
14809
14810
14811 TEST(PromiseRejectCallback) {
14812   LocalContext env;
14813   v8::Isolate* isolate = env->GetIsolate();
14814   v8::HandleScope scope(isolate);
14815
14816   isolate->SetPromiseRejectCallback(PromiseRejectCallback);
14817
14818   ResetPromiseStates();
14819
14820   // Create promise p0.
14821   CompileRun(
14822       "var reject;            \n"
14823       "var p0 = new Promise(  \n"
14824       "  function(res, rej) { \n"
14825       "    reject = rej;      \n"
14826       "  }                    \n"
14827       ");                     \n");
14828   CHECK(!GetPromise("p0")->HasHandler());
14829   CHECK_EQ(0, promise_reject_counter);
14830   CHECK_EQ(0, promise_revoke_counter);
14831
14832   // Add resolve handler (and default reject handler) to p0.
14833   CompileRun("var p1 = p0.then(function(){});");
14834   CHECK(GetPromise("p0")->HasHandler());
14835   CHECK(!GetPromise("p1")->HasHandler());
14836   CHECK_EQ(0, promise_reject_counter);
14837   CHECK_EQ(0, promise_revoke_counter);
14838
14839   // Reject p0.
14840   CompileRun("reject('ppp');");
14841   CHECK(GetPromise("p0")->HasHandler());
14842   CHECK(!GetPromise("p1")->HasHandler());
14843   CHECK_EQ(1, promise_reject_counter);
14844   CHECK_EQ(0, promise_revoke_counter);
14845   CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
14846   CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
14847   CHECK(RejectValue()->Equals(v8_str("ppp")));
14848
14849   // Reject p0 again. Callback is not triggered again.
14850   CompileRun("reject();");
14851   CHECK(GetPromise("p0")->HasHandler());
14852   CHECK(!GetPromise("p1")->HasHandler());
14853   CHECK_EQ(1, promise_reject_counter);
14854   CHECK_EQ(0, promise_revoke_counter);
14855
14856   // Add resolve handler to p1.
14857   CompileRun("var p2 = p1.then(function(){});");
14858   CHECK(GetPromise("p0")->HasHandler());
14859   CHECK(GetPromise("p1")->HasHandler());
14860   CHECK(!GetPromise("p2")->HasHandler());
14861   CHECK_EQ(2, promise_reject_counter);
14862   CHECK_EQ(1, promise_revoke_counter);
14863   CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
14864   CHECK(RejectValue()->Equals(v8_str("ppp")));
14865   CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
14866
14867   ResetPromiseStates();
14868
14869   // Create promise q0.
14870   CompileRun(
14871       "var q0 = new Promise(  \n"
14872       "  function(res, rej) { \n"
14873       "    reject = rej;      \n"
14874       "  }                    \n"
14875       ");                     \n");
14876   CHECK(!GetPromise("q0")->HasHandler());
14877   CHECK_EQ(0, promise_reject_counter);
14878   CHECK_EQ(0, promise_revoke_counter);
14879
14880   // Add reject handler to q0.
14881   CompileRun("var q1 = q0.catch(function() {});");
14882   CHECK(GetPromise("q0")->HasHandler());
14883   CHECK(!GetPromise("q1")->HasHandler());
14884   CHECK_EQ(0, promise_reject_counter);
14885   CHECK_EQ(0, promise_revoke_counter);
14886
14887   // Reject q0.
14888   CompileRun("reject('qq')");
14889   CHECK(GetPromise("q0")->HasHandler());
14890   CHECK(!GetPromise("q1")->HasHandler());
14891   CHECK_EQ(0, promise_reject_counter);
14892   CHECK_EQ(0, promise_revoke_counter);
14893
14894   // Add a new reject handler, which rejects by returning Promise.reject().
14895   // The returned promise q_ triggers a reject callback at first, only to
14896   // revoke it when returning it causes q2 to be rejected.
14897   CompileRun(
14898       "var q_;"
14899       "var q2 = q0.catch(               \n"
14900       "   function() {                  \n"
14901       "     q_ = Promise.reject('qqq'); \n"
14902       "     return q_;                  \n"
14903       "   }                             \n"
14904       ");                               \n");
14905   CHECK(GetPromise("q0")->HasHandler());
14906   CHECK(!GetPromise("q1")->HasHandler());
14907   CHECK(!GetPromise("q2")->HasHandler());
14908   CHECK(GetPromise("q_")->HasHandler());
14909   CHECK_EQ(2, promise_reject_counter);
14910   CHECK_EQ(1, promise_revoke_counter);
14911   CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
14912   CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
14913   CHECK(RejectValue()->Equals(v8_str("qqq")));
14914
14915   // Add a reject handler to the resolved q1, which rejects by throwing.
14916   CompileRun(
14917       "var q3 = q1.then(  \n"
14918       "   function() {    \n"
14919       "     throw 'qqqq'; \n"
14920       "   }               \n"
14921       ");                 \n");
14922   CHECK(GetPromise("q0")->HasHandler());
14923   CHECK(GetPromise("q1")->HasHandler());
14924   CHECK(!GetPromise("q2")->HasHandler());
14925   CHECK(!GetPromise("q3")->HasHandler());
14926   CHECK_EQ(3, promise_reject_counter);
14927   CHECK_EQ(1, promise_revoke_counter);
14928   CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
14929   CHECK(RejectValue()->Equals(v8_str("qqqq")));
14930
14931   ResetPromiseStates();
14932
14933   // Create promise r0, which has three handlers, two of which handle rejects.
14934   CompileRun(
14935       "var r0 = new Promise(             \n"
14936       "  function(res, rej) {            \n"
14937       "    reject = rej;                 \n"
14938       "  }                               \n"
14939       ");                                \n"
14940       "var r1 = r0.catch(function() {}); \n"
14941       "var r2 = r0.then(function() {});  \n"
14942       "var r3 = r0.then(function() {},   \n"
14943       "                 function() {});  \n");
14944   CHECK(GetPromise("r0")->HasHandler());
14945   CHECK(!GetPromise("r1")->HasHandler());
14946   CHECK(!GetPromise("r2")->HasHandler());
14947   CHECK(!GetPromise("r3")->HasHandler());
14948   CHECK_EQ(0, promise_reject_counter);
14949   CHECK_EQ(0, promise_revoke_counter);
14950
14951   // Reject r0.
14952   CompileRun("reject('rrr')");
14953   CHECK(GetPromise("r0")->HasHandler());
14954   CHECK(!GetPromise("r1")->HasHandler());
14955   CHECK(!GetPromise("r2")->HasHandler());
14956   CHECK(!GetPromise("r3")->HasHandler());
14957   CHECK_EQ(1, promise_reject_counter);
14958   CHECK_EQ(0, promise_revoke_counter);
14959   CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
14960   CHECK(RejectValue()->Equals(v8_str("rrr")));
14961
14962   // Add reject handler to r2.
14963   CompileRun("var r4 = r2.catch(function() {});");
14964   CHECK(GetPromise("r0")->HasHandler());
14965   CHECK(!GetPromise("r1")->HasHandler());
14966   CHECK(GetPromise("r2")->HasHandler());
14967   CHECK(!GetPromise("r3")->HasHandler());
14968   CHECK(!GetPromise("r4")->HasHandler());
14969   CHECK_EQ(1, promise_reject_counter);
14970   CHECK_EQ(1, promise_revoke_counter);
14971   CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
14972   CHECK(RejectValue()->Equals(v8_str("rrr")));
14973
14974   // Add reject handlers to r4.
14975   CompileRun("var r5 = r4.then(function() {}, function() {});");
14976   CHECK(GetPromise("r0")->HasHandler());
14977   CHECK(!GetPromise("r1")->HasHandler());
14978   CHECK(GetPromise("r2")->HasHandler());
14979   CHECK(!GetPromise("r3")->HasHandler());
14980   CHECK(GetPromise("r4")->HasHandler());
14981   CHECK(!GetPromise("r5")->HasHandler());
14982   CHECK_EQ(1, promise_reject_counter);
14983   CHECK_EQ(1, promise_revoke_counter);
14984
14985   ResetPromiseStates();
14986
14987   // Create promise s0, which has three handlers, none of which handle rejects.
14988   CompileRun(
14989       "var s0 = new Promise(            \n"
14990       "  function(res, rej) {           \n"
14991       "    reject = rej;                \n"
14992       "  }                              \n"
14993       ");                               \n"
14994       "var s1 = s0.then(function() {}); \n"
14995       "var s2 = s0.then(function() {}); \n"
14996       "var s3 = s0.then(function() {}); \n");
14997   CHECK(GetPromise("s0")->HasHandler());
14998   CHECK(!GetPromise("s1")->HasHandler());
14999   CHECK(!GetPromise("s2")->HasHandler());
15000   CHECK(!GetPromise("s3")->HasHandler());
15001   CHECK_EQ(0, promise_reject_counter);
15002   CHECK_EQ(0, promise_revoke_counter);
15003
15004   // Reject s0.
15005   CompileRun("reject('sss')");
15006   CHECK(GetPromise("s0")->HasHandler());
15007   CHECK(!GetPromise("s1")->HasHandler());
15008   CHECK(!GetPromise("s2")->HasHandler());
15009   CHECK(!GetPromise("s3")->HasHandler());
15010   CHECK_EQ(3, promise_reject_counter);
15011   CHECK_EQ(0, promise_revoke_counter);
15012   CHECK(RejectValue()->Equals(v8_str("sss")));
15013
15014   // Test stack frames.
15015   V8::SetCaptureStackTraceForUncaughtExceptions(true);
15016
15017   ResetPromiseStates();
15018
15019   // Create promise t0, which is rejected in the constructor with an error.
15020   CompileRunWithOrigin(
15021       "var t0 = new Promise(  \n"
15022       "  function(res, rej) { \n"
15023       "    reference_error;   \n"
15024       "  }                    \n"
15025       ");                     \n",
15026       "pro", 0, 0);
15027   CHECK(!GetPromise("t0")->HasHandler());
15028   CHECK_EQ(1, promise_reject_counter);
15029   CHECK_EQ(0, promise_revoke_counter);
15030   CHECK_EQ(2, promise_reject_frame_count);
15031   CHECK_EQ(3, promise_reject_line_number);
15032   CHECK_EQ(5, promise_reject_column_number);
15033   CHECK_EQ(3, promise_reject_msg_line_number);
15034   CHECK_EQ(5, promise_reject_msg_column_number);
15035
15036   ResetPromiseStates();
15037
15038   // Create promise u0 and chain u1 to it, which is rejected via throw.
15039   CompileRunWithOrigin(
15040       "var u0 = Promise.resolve();        \n"
15041       "var u1 = u0.then(                  \n"
15042       "           function() {            \n"
15043       "             (function() {         \n"
15044       "                throw new Error(); \n"
15045       "              })();                \n"
15046       "           }                       \n"
15047       "         );                        \n",
15048       "pro", 0, 0);
15049   CHECK(GetPromise("u0")->HasHandler());
15050   CHECK(!GetPromise("u1")->HasHandler());
15051   CHECK_EQ(1, promise_reject_counter);
15052   CHECK_EQ(0, promise_revoke_counter);
15053   CHECK_EQ(2, promise_reject_frame_count);
15054   CHECK_EQ(5, promise_reject_line_number);
15055   CHECK_EQ(23, promise_reject_column_number);
15056   CHECK_EQ(5, promise_reject_msg_line_number);
15057   CHECK_EQ(23, promise_reject_msg_column_number);
15058
15059   // Throw in u3, which handles u1's rejection.
15060   CompileRunWithOrigin(
15061       "function f() {                \n"
15062       "  return (function() {        \n"
15063       "    return new Error();       \n"
15064       "  })();                       \n"
15065       "}                             \n"
15066       "var u2 = Promise.reject(f()); \n"
15067       "var u3 = u1.catch(            \n"
15068       "           function() {       \n"
15069       "             return u2;       \n"
15070       "           }                  \n"
15071       "         );                   \n",
15072       "pro", 0, 0);
15073   CHECK(GetPromise("u0")->HasHandler());
15074   CHECK(GetPromise("u1")->HasHandler());
15075   CHECK(GetPromise("u2")->HasHandler());
15076   CHECK(!GetPromise("u3")->HasHandler());
15077   CHECK_EQ(3, promise_reject_counter);
15078   CHECK_EQ(2, promise_revoke_counter);
15079   CHECK_EQ(3, promise_reject_frame_count);
15080   CHECK_EQ(3, promise_reject_line_number);
15081   CHECK_EQ(12, promise_reject_column_number);
15082   CHECK_EQ(3, promise_reject_msg_line_number);
15083   CHECK_EQ(12, promise_reject_msg_column_number);
15084
15085   ResetPromiseStates();
15086
15087   // Create promise rejected promise v0, which is incorrectly handled by v1
15088   // via chaining cycle.
15089   CompileRunWithOrigin(
15090       "var v0 = Promise.reject(); \n"
15091       "var v1 = v0.catch(         \n"
15092       "           function() {    \n"
15093       "             return v1;    \n"
15094       "           }               \n"
15095       "         );                \n",
15096       "pro", 0, 0);
15097   CHECK(GetPromise("v0")->HasHandler());
15098   CHECK(!GetPromise("v1")->HasHandler());
15099   CHECK_EQ(2, promise_reject_counter);
15100   CHECK_EQ(1, promise_revoke_counter);
15101   CHECK_EQ(0, promise_reject_frame_count);
15102   CHECK_EQ(-1, promise_reject_line_number);
15103   CHECK_EQ(-1, promise_reject_column_number);
15104
15105   ResetPromiseStates();
15106
15107   // Create promise t1, which rejects by throwing syntax error from eval.
15108   CompileRunWithOrigin(
15109       "var t1 = new Promise(   \n"
15110       "  function(res, rej) {  \n"
15111       "    var content = '\\n\\\n"
15112       "      }';               \n"
15113       "    eval(content);      \n"
15114       "  }                     \n"
15115       ");                      \n",
15116       "pro", 0, 0);
15117   CHECK(!GetPromise("t1")->HasHandler());
15118   CHECK_EQ(1, promise_reject_counter);
15119   CHECK_EQ(0, promise_revoke_counter);
15120   CHECK_EQ(2, promise_reject_frame_count);
15121   CHECK_EQ(5, promise_reject_line_number);
15122   CHECK_EQ(10, promise_reject_column_number);
15123   CHECK_EQ(2, promise_reject_msg_line_number);
15124   CHECK_EQ(7, promise_reject_msg_column_number);
15125 }
15126
15127
15128 void AnalyzeStackOfEvalWithSourceURL(
15129     const v8::FunctionCallbackInfo<v8::Value>& args) {
15130   v8::HandleScope scope(args.GetIsolate());
15131   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15132       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15133   CHECK_EQ(5, stackTrace->GetFrameCount());
15134   v8::Handle<v8::String> url = v8_str("eval_url");
15135   for (int i = 0; i < 3; i++) {
15136     v8::Handle<v8::String> name =
15137         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15138     CHECK(!name.IsEmpty());
15139     CHECK(url->Equals(name));
15140   }
15141 }
15142
15143
15144 TEST(SourceURLInStackTrace) {
15145   v8::Isolate* isolate = CcTest::isolate();
15146   v8::HandleScope scope(isolate);
15147   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15148   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
15149              v8::FunctionTemplate::New(isolate,
15150                                        AnalyzeStackOfEvalWithSourceURL));
15151   LocalContext context(0, templ);
15152
15153   const char *source =
15154     "function outer() {\n"
15155     "function bar() {\n"
15156     "  AnalyzeStackOfEvalWithSourceURL();\n"
15157     "}\n"
15158     "function foo() {\n"
15159     "\n"
15160     "  bar();\n"
15161     "}\n"
15162     "foo();\n"
15163     "}\n"
15164     "eval('(' + outer +')()%s');";
15165
15166   i::ScopedVector<char> code(1024);
15167   i::SNPrintF(code, source, "//# sourceURL=eval_url");
15168   CHECK(CompileRun(code.start())->IsUndefined());
15169   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
15170   CHECK(CompileRun(code.start())->IsUndefined());
15171 }
15172
15173
15174 static int scriptIdInStack[2];
15175
15176 void AnalyzeScriptIdInStack(
15177     const v8::FunctionCallbackInfo<v8::Value>& args) {
15178   v8::HandleScope scope(args.GetIsolate());
15179   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15180       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
15181   CHECK_EQ(2, stackTrace->GetFrameCount());
15182   for (int i = 0; i < 2; i++) {
15183     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
15184   }
15185 }
15186
15187
15188 TEST(ScriptIdInStackTrace) {
15189   v8::Isolate* isolate = CcTest::isolate();
15190   v8::HandleScope scope(isolate);
15191   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15192   templ->Set(v8_str("AnalyzeScriptIdInStack"),
15193              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
15194   LocalContext context(0, templ);
15195
15196   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
15197     isolate,
15198     "function foo() {\n"
15199     "  AnalyzeScriptIdInStack();"
15200     "}\n"
15201     "foo();\n");
15202   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
15203   script->Run();
15204   for (int i = 0; i < 2; i++) {
15205     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
15206     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
15207   }
15208 }
15209
15210
15211 void AnalyzeStackOfInlineScriptWithSourceURL(
15212     const v8::FunctionCallbackInfo<v8::Value>& args) {
15213   v8::HandleScope scope(args.GetIsolate());
15214   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15215       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15216   CHECK_EQ(4, stackTrace->GetFrameCount());
15217   v8::Handle<v8::String> url = v8_str("source_url");
15218   for (int i = 0; i < 3; i++) {
15219     v8::Handle<v8::String> name =
15220         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15221     CHECK(!name.IsEmpty());
15222     CHECK(url->Equals(name));
15223   }
15224 }
15225
15226
15227 TEST(InlineScriptWithSourceURLInStackTrace) {
15228   v8::Isolate* isolate = CcTest::isolate();
15229   v8::HandleScope scope(isolate);
15230   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15231   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15232              v8::FunctionTemplate::New(
15233                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
15234   LocalContext context(0, templ);
15235
15236   const char *source =
15237     "function outer() {\n"
15238     "function bar() {\n"
15239     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
15240     "}\n"
15241     "function foo() {\n"
15242     "\n"
15243     "  bar();\n"
15244     "}\n"
15245     "foo();\n"
15246     "}\n"
15247     "outer()\n%s";
15248
15249   i::ScopedVector<char> code(1024);
15250   i::SNPrintF(code, source, "//# sourceURL=source_url");
15251   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15252   i::SNPrintF(code, source, "//@ sourceURL=source_url");
15253   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15254 }
15255
15256
15257 void AnalyzeStackOfDynamicScriptWithSourceURL(
15258     const v8::FunctionCallbackInfo<v8::Value>& args) {
15259   v8::HandleScope scope(args.GetIsolate());
15260   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15261       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15262   CHECK_EQ(4, stackTrace->GetFrameCount());
15263   v8::Handle<v8::String> url = v8_str("source_url");
15264   for (int i = 0; i < 3; i++) {
15265     v8::Handle<v8::String> name =
15266         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15267     CHECK(!name.IsEmpty());
15268     CHECK(url->Equals(name));
15269   }
15270 }
15271
15272
15273 TEST(DynamicWithSourceURLInStackTrace) {
15274   v8::Isolate* isolate = CcTest::isolate();
15275   v8::HandleScope scope(isolate);
15276   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15277   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15278              v8::FunctionTemplate::New(
15279                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
15280   LocalContext context(0, templ);
15281
15282   const char *source =
15283     "function outer() {\n"
15284     "function bar() {\n"
15285     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15286     "}\n"
15287     "function foo() {\n"
15288     "\n"
15289     "  bar();\n"
15290     "}\n"
15291     "foo();\n"
15292     "}\n"
15293     "outer()\n%s";
15294
15295   i::ScopedVector<char> code(1024);
15296   i::SNPrintF(code, source, "//# sourceURL=source_url");
15297   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15298   i::SNPrintF(code, source, "//@ sourceURL=source_url");
15299   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15300 }
15301
15302
15303 TEST(DynamicWithSourceURLInStackTraceString) {
15304   LocalContext context;
15305   v8::HandleScope scope(context->GetIsolate());
15306
15307   const char *source =
15308     "function outer() {\n"
15309     "  function foo() {\n"
15310     "    FAIL.FAIL;\n"
15311     "  }\n"
15312     "  foo();\n"
15313     "}\n"
15314     "outer()\n%s";
15315
15316   i::ScopedVector<char> code(1024);
15317   i::SNPrintF(code, source, "//# sourceURL=source_url");
15318   v8::TryCatch try_catch(context->GetIsolate());
15319   CompileRunWithOrigin(code.start(), "", 0, 0);
15320   CHECK(try_catch.HasCaught());
15321   v8::String::Utf8Value stack(try_catch.StackTrace());
15322   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
15323 }
15324
15325
15326 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15327   LocalContext context;
15328   v8::HandleScope scope(context->GetIsolate());
15329
15330   const char *source =
15331     "function outer() {\n"
15332     "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
15333     "  //# sourceURL=source_url\";\n"
15334     "  eval(scriptContents);\n"
15335     "  foo(); }\n"
15336     "outer();\n"
15337     "//# sourceURL=outer_url";
15338
15339   v8::TryCatch try_catch(context->GetIsolate());
15340   CompileRun(source);
15341   CHECK(try_catch.HasCaught());
15342
15343   Local<v8::Message> message = try_catch.Message();
15344   Handle<Value> sourceURL =
15345     message->GetScriptOrigin().ResourceName();
15346   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15347 }
15348
15349
15350 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15351   LocalContext context;
15352   v8::HandleScope scope(context->GetIsolate());
15353
15354   const char *source =
15355     "function outer() {\n"
15356     "  var scriptContents = \"function boo(){ boo(); }\\\n"
15357     "  //# sourceURL=source_url\";\n"
15358     "  eval(scriptContents);\n"
15359     "  boo(); }\n"
15360     "outer();\n"
15361     "//# sourceURL=outer_url";
15362
15363   v8::TryCatch try_catch(context->GetIsolate());
15364   CompileRun(source);
15365   CHECK(try_catch.HasCaught());
15366
15367   Local<v8::Message> message = try_catch.Message();
15368   Handle<Value> sourceURL =
15369     message->GetScriptOrigin().ResourceName();
15370   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15371 }
15372
15373
15374 static void CreateGarbageInOldSpace() {
15375   i::Factory* factory = CcTest::i_isolate()->factory();
15376   v8::HandleScope scope(CcTest::isolate());
15377   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
15378   for (int i = 0; i < 1000; i++) {
15379     factory->NewFixedArray(1000, i::TENURED);
15380   }
15381 }
15382
15383
15384 // Test that idle notification can be handled and eventually collects garbage.
15385 TEST(TestIdleNotification) {
15386   if (!i::FLAG_incremental_marking) return;
15387   const intptr_t MB = 1024 * 1024;
15388   const double IdlePauseInSeconds = 1.0;
15389   LocalContext env;
15390   v8::HandleScope scope(env->GetIsolate());
15391   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
15392   CreateGarbageInOldSpace();
15393   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
15394   CHECK_GT(size_with_garbage, initial_size + MB);
15395   bool finished = false;
15396   for (int i = 0; i < 200 && !finished; i++) {
15397     if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
15398       CcTest::heap()->StartIdleIncrementalMarking();
15399     }
15400     finished = env->GetIsolate()->IdleNotificationDeadline(
15401         (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
15402          static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
15403         IdlePauseInSeconds);
15404     if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
15405       CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
15406     }
15407   }
15408   intptr_t final_size = CcTest::heap()->SizeOfObjects();
15409   CHECK(finished);
15410   CHECK_LT(final_size, initial_size + 1);
15411 }
15412
15413
15414 TEST(Regress2333) {
15415   LocalContext env;
15416   for (int i = 0; i < 3; i++) {
15417     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
15418   }
15419 }
15420
15421 static uint32_t* stack_limit;
15422
15423 static void GetStackLimitCallback(
15424     const v8::FunctionCallbackInfo<v8::Value>& args) {
15425   stack_limit = reinterpret_cast<uint32_t*>(
15426       CcTest::i_isolate()->stack_guard()->real_climit());
15427 }
15428
15429
15430 // Uses the address of a local variable to determine the stack top now.
15431 // Given a size, returns an address that is that far from the current
15432 // top of stack.
15433 static uint32_t* ComputeStackLimit(uint32_t size) {
15434   uint32_t* answer = &size - (size / sizeof(size));
15435   // If the size is very large and the stack is very near the bottom of
15436   // memory then the calculation above may wrap around and give an address
15437   // that is above the (downwards-growing) stack.  In that case we return
15438   // a very low address.
15439   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
15440   return answer;
15441 }
15442
15443
15444 // We need at least 165kB for an x64 debug build with clang and ASAN.
15445 static const int stack_breathing_room = 256 * i::KB;
15446
15447
15448 TEST(SetStackLimit) {
15449   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
15450
15451   // Set stack limit.
15452   CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
15453
15454   // Execute a script.
15455   LocalContext env;
15456   v8::HandleScope scope(env->GetIsolate());
15457   Local<v8::FunctionTemplate> fun_templ =
15458       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
15459   Local<Function> fun = fun_templ->GetFunction();
15460   env->Global()->Set(v8_str("get_stack_limit"), fun);
15461   CompileRun("get_stack_limit();");
15462
15463   CHECK(stack_limit == set_limit);
15464 }
15465
15466
15467 TEST(SetStackLimitInThread) {
15468   uint32_t* set_limit;
15469   {
15470     v8::Locker locker(CcTest::isolate());
15471     set_limit = ComputeStackLimit(stack_breathing_room);
15472
15473     // Set stack limit.
15474     CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
15475
15476     // Execute a script.
15477     v8::HandleScope scope(CcTest::isolate());
15478     LocalContext env;
15479     Local<v8::FunctionTemplate> fun_templ =
15480         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
15481     Local<Function> fun = fun_templ->GetFunction();
15482     env->Global()->Set(v8_str("get_stack_limit"), fun);
15483     CompileRun("get_stack_limit();");
15484
15485     CHECK(stack_limit == set_limit);
15486   }
15487   {
15488     v8::Locker locker(CcTest::isolate());
15489     CHECK(stack_limit == set_limit);
15490   }
15491 }
15492
15493
15494 THREADED_TEST(GetHeapStatistics) {
15495   LocalContext c1;
15496   v8::HandleScope scope(c1->GetIsolate());
15497   v8::HeapStatistics heap_statistics;
15498   CHECK_EQ(0u, heap_statistics.total_heap_size());
15499   CHECK_EQ(0u, heap_statistics.used_heap_size());
15500   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
15501   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15502   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
15503 }
15504
15505
15506 class VisitorImpl : public v8::ExternalResourceVisitor {
15507  public:
15508   explicit VisitorImpl(TestResource** resource) {
15509     for (int i = 0; i < 4; i++) {
15510       resource_[i] = resource[i];
15511       found_resource_[i] = false;
15512     }
15513   }
15514   virtual ~VisitorImpl() {}
15515   virtual void VisitExternalString(v8::Handle<v8::String> string) {
15516     if (!string->IsExternal()) {
15517       CHECK(string->IsExternalOneByte());
15518       return;
15519     }
15520     v8::String::ExternalStringResource* resource =
15521         string->GetExternalStringResource();
15522     CHECK(resource);
15523     for (int i = 0; i < 4; i++) {
15524       if (resource_[i] == resource) {
15525         CHECK(!found_resource_[i]);
15526         found_resource_[i] = true;
15527       }
15528     }
15529   }
15530   void CheckVisitedResources() {
15531     for (int i = 0; i < 4; i++) {
15532       CHECK(found_resource_[i]);
15533     }
15534   }
15535
15536  private:
15537   v8::String::ExternalStringResource* resource_[4];
15538   bool found_resource_[4];
15539 };
15540
15541
15542 TEST(ExternalizeOldSpaceTwoByteCons) {
15543   v8::Isolate* isolate = CcTest::isolate();
15544   LocalContext env;
15545   v8::HandleScope scope(isolate);
15546   v8::Local<v8::String> cons =
15547       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
15548   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
15549   CcTest::heap()->CollectAllAvailableGarbage();
15550   CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
15551
15552   TestResource* resource = new TestResource(
15553       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
15554   cons->MakeExternal(resource);
15555
15556   CHECK(cons->IsExternal());
15557   CHECK_EQ(resource, cons->GetExternalStringResource());
15558   String::Encoding encoding;
15559   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
15560   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
15561 }
15562
15563
15564 TEST(ExternalizeOldSpaceOneByteCons) {
15565   v8::Isolate* isolate = CcTest::isolate();
15566   LocalContext env;
15567   v8::HandleScope scope(isolate);
15568   v8::Local<v8::String> cons =
15569       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
15570   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
15571   CcTest::heap()->CollectAllAvailableGarbage();
15572   CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
15573
15574   TestOneByteResource* resource =
15575       new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
15576   cons->MakeExternal(resource);
15577
15578   CHECK(cons->IsExternalOneByte());
15579   CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
15580   String::Encoding encoding;
15581   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
15582   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
15583 }
15584
15585
15586 TEST(VisitExternalStrings) {
15587   v8::Isolate* isolate = CcTest::isolate();
15588   LocalContext env;
15589   v8::HandleScope scope(isolate);
15590   const char* string = "Some string";
15591   uint16_t* two_byte_string = AsciiToTwoByteString(string);
15592   TestResource* resource[4];
15593   resource[0] = new TestResource(two_byte_string);
15594   v8::Local<v8::String> string0 =
15595       v8::String::NewExternal(env->GetIsolate(), resource[0]);
15596   resource[1] = new TestResource(two_byte_string, NULL, false);
15597   v8::Local<v8::String> string1 =
15598       v8::String::NewExternal(env->GetIsolate(), resource[1]);
15599
15600   // Externalized symbol.
15601   resource[2] = new TestResource(two_byte_string, NULL, false);
15602   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
15603       env->GetIsolate(), string, v8::String::kInternalizedString);
15604   CHECK(string2->MakeExternal(resource[2]));
15605
15606   // Symbolized External.
15607   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15608   v8::Local<v8::String> string3 =
15609       v8::String::NewExternal(env->GetIsolate(), resource[3]);
15610   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
15611   // Turn into a symbol.
15612   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
15613   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
15614       string3_i).is_null());
15615   CHECK(string3_i->IsInternalizedString());
15616
15617   // We need to add usages for string* to avoid warnings in GCC 4.7
15618   CHECK(string0->IsExternal());
15619   CHECK(string1->IsExternal());
15620   CHECK(string2->IsExternal());
15621   CHECK(string3->IsExternal());
15622
15623   VisitorImpl visitor(resource);
15624   v8::V8::VisitExternalResources(&visitor);
15625   visitor.CheckVisitedResources();
15626 }
15627
15628
15629 TEST(ExternalStringCollectedAtTearDown) {
15630   int destroyed = 0;
15631   v8::Isolate::CreateParams create_params;
15632   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
15633   v8::Isolate* isolate = v8::Isolate::New(create_params);
15634   { v8::Isolate::Scope isolate_scope(isolate);
15635     v8::HandleScope handle_scope(isolate);
15636     const char* s = "One string to test them all, one string to find them.";
15637     TestOneByteResource* inscription =
15638         new TestOneByteResource(i::StrDup(s), &destroyed);
15639     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
15640     // Ring is still alive.  Orcs are roaming freely across our lands.
15641     CHECK_EQ(0, destroyed);
15642     USE(ring);
15643   }
15644
15645   isolate->Dispose();
15646   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
15647   CHECK_EQ(1, destroyed);
15648 }
15649
15650
15651 TEST(ExternalInternalizedStringCollectedAtTearDown) {
15652   int destroyed = 0;
15653   v8::Isolate::CreateParams create_params;
15654   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
15655   v8::Isolate* isolate = v8::Isolate::New(create_params);
15656   { v8::Isolate::Scope isolate_scope(isolate);
15657     LocalContext env(isolate);
15658     v8::HandleScope handle_scope(isolate);
15659     CompileRun("var ring = 'One string to test them all';");
15660     const char* s = "One string to test them all";
15661     TestOneByteResource* inscription =
15662         new TestOneByteResource(i::StrDup(s), &destroyed);
15663     v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
15664     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
15665     ring->MakeExternal(inscription);
15666     // Ring is still alive.  Orcs are roaming freely across our lands.
15667     CHECK_EQ(0, destroyed);
15668     USE(ring);
15669   }
15670
15671   isolate->Dispose();
15672   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
15673   CHECK_EQ(1, destroyed);
15674 }
15675
15676
15677 TEST(ExternalInternalizedStringCollectedAtGC) {
15678   int destroyed = 0;
15679   { LocalContext env;
15680     v8::HandleScope handle_scope(env->GetIsolate());
15681     CompileRun("var ring = 'One string to test them all';");
15682     const char* s = "One string to test them all";
15683     TestOneByteResource* inscription =
15684         new TestOneByteResource(i::StrDup(s), &destroyed);
15685     v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
15686     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
15687     ring->MakeExternal(inscription);
15688     // Ring is still alive.  Orcs are roaming freely across our lands.
15689     CHECK_EQ(0, destroyed);
15690     USE(ring);
15691   }
15692
15693   // Garbage collector deals swift blows to evil.
15694   CcTest::i_isolate()->compilation_cache()->Clear();
15695   CcTest::heap()->CollectAllAvailableGarbage();
15696
15697   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
15698   CHECK_EQ(1, destroyed);
15699 }
15700
15701
15702 static double DoubleFromBits(uint64_t value) {
15703   double target;
15704   i::MemCopy(&target, &value, sizeof(target));
15705   return target;
15706 }
15707
15708
15709 static uint64_t DoubleToBits(double value) {
15710   uint64_t target;
15711   i::MemCopy(&target, &value, sizeof(target));
15712   return target;
15713 }
15714
15715
15716 static double DoubleToDateTime(double input) {
15717   double date_limit = 864e13;
15718   if (std::isnan(input) || input < -date_limit || input > date_limit) {
15719     return std::numeric_limits<double>::quiet_NaN();
15720   }
15721   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
15722 }
15723
15724
15725 // We don't have a consistent way to write 64-bit constants syntactically, so we
15726 // split them into two 32-bit constants and combine them programmatically.
15727 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15728   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15729 }
15730
15731
15732 THREADED_TEST(QuietSignalingNaNs) {
15733   LocalContext context;
15734   v8::Isolate* isolate = context->GetIsolate();
15735   v8::HandleScope scope(isolate);
15736   v8::TryCatch try_catch(isolate);
15737
15738   // Special double values.
15739   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15740   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15741   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15742   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15743   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15744   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15745   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15746
15747   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15748   // on either side of the epoch.
15749   double date_limit = 864e13;
15750
15751   double test_values[] = {
15752       snan,
15753       qnan,
15754       infinity,
15755       max_normal,
15756       date_limit + 1,
15757       date_limit,
15758       min_normal,
15759       max_denormal,
15760       min_denormal,
15761       0,
15762       -0,
15763       -min_denormal,
15764       -max_denormal,
15765       -min_normal,
15766       -date_limit,
15767       -date_limit - 1,
15768       -max_normal,
15769       -infinity,
15770       -qnan,
15771       -snan
15772   };
15773   int num_test_values = 20;
15774
15775   for (int i = 0; i < num_test_values; i++) {
15776     double test_value = test_values[i];
15777
15778     // Check that Number::New preserves non-NaNs and quiets SNaNs.
15779     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
15780     double stored_number = number->NumberValue();
15781     if (!std::isnan(test_value)) {
15782       CHECK_EQ(test_value, stored_number);
15783     } else {
15784       uint64_t stored_bits = DoubleToBits(stored_number);
15785       // Check if quiet nan (bits 51..62 all set).
15786 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
15787     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
15788       // Most significant fraction bit for quiet nan is set to 0
15789       // on MIPS architecture. Allowed by IEEE-754.
15790       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15791 #else
15792       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
15793 #endif
15794     }
15795
15796     // Check that Date::New preserves non-NaNs in the date range and
15797     // quiets SNaNs.
15798     v8::Handle<v8::Value> date =
15799         v8::Date::New(isolate, test_value);
15800     double expected_stored_date = DoubleToDateTime(test_value);
15801     double stored_date = date->NumberValue();
15802     if (!std::isnan(expected_stored_date)) {
15803       CHECK_EQ(expected_stored_date, stored_date);
15804     } else {
15805       uint64_t stored_bits = DoubleToBits(stored_date);
15806       // Check if quiet nan (bits 51..62 all set).
15807 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
15808     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
15809       // Most significant fraction bit for quiet nan is set to 0
15810       // on MIPS architecture. Allowed by IEEE-754.
15811       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15812 #else
15813       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
15814 #endif
15815     }
15816   }
15817 }
15818
15819
15820 static void SpaghettiIncident(
15821     const v8::FunctionCallbackInfo<v8::Value>& args) {
15822   v8::HandleScope scope(args.GetIsolate());
15823   v8::TryCatch tc(args.GetIsolate());
15824   v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
15825   USE(str);
15826   if (tc.HasCaught())
15827     tc.ReThrow();
15828 }
15829
15830
15831 // Test that an exception can be propagated down through a spaghetti
15832 // stack using ReThrow.
15833 THREADED_TEST(SpaghettiStackReThrow) {
15834   v8::Isolate* isolate = CcTest::isolate();
15835   v8::HandleScope scope(isolate);
15836   LocalContext context;
15837   context->Global()->Set(
15838       v8::String::NewFromUtf8(isolate, "s"),
15839       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
15840   v8::TryCatch try_catch(isolate);
15841   CompileRun(
15842       "var i = 0;"
15843       "var o = {"
15844       "  toString: function () {"
15845       "    if (i == 10) {"
15846       "      throw 'Hey!';"
15847       "    } else {"
15848       "      i++;"
15849       "      return s(o);"
15850       "    }"
15851       "  }"
15852       "};"
15853       "s(o);");
15854   CHECK(try_catch.HasCaught());
15855   v8::String::Utf8Value value(try_catch.Exception());
15856   CHECK_EQ(0, strcmp(*value, "Hey!"));
15857 }
15858
15859
15860 TEST(Regress528) {
15861   v8::V8::Initialize();
15862   v8::Isolate* isolate = CcTest::isolate();
15863   i::FLAG_retain_maps_for_n_gc = 0;
15864   v8::HandleScope scope(isolate);
15865   v8::Local<Context> other_context;
15866   int gc_count;
15867
15868   // Create a context used to keep the code from aging in the compilation
15869   // cache.
15870   other_context = Context::New(isolate);
15871
15872   // Context-dependent context data creates reference from the compilation
15873   // cache to the global object.
15874   const char* source_simple = "1";
15875   {
15876     v8::HandleScope scope(isolate);
15877     v8::Local<Context> context = Context::New(isolate);
15878
15879     context->Enter();
15880     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
15881     context->SetEmbedderData(0, obj);
15882     CompileRun(source_simple);
15883     context->Exit();
15884   }
15885   isolate->ContextDisposedNotification();
15886   for (gc_count = 1; gc_count < 10; gc_count++) {
15887     other_context->Enter();
15888     CompileRun(source_simple);
15889     other_context->Exit();
15890     CcTest::heap()->CollectAllGarbage();
15891     if (GetGlobalObjectsCount() == 1) break;
15892   }
15893   CHECK_GE(2, gc_count);
15894   CHECK_EQ(1, GetGlobalObjectsCount());
15895
15896   // Eval in a function creates reference from the compilation cache to the
15897   // global object.
15898   const char* source_eval = "function f(){eval('1')}; f()";
15899   {
15900     v8::HandleScope scope(isolate);
15901     v8::Local<Context> context = Context::New(isolate);
15902
15903     context->Enter();
15904     CompileRun(source_eval);
15905     context->Exit();
15906   }
15907   isolate->ContextDisposedNotification();
15908   for (gc_count = 1; gc_count < 10; gc_count++) {
15909     other_context->Enter();
15910     CompileRun(source_eval);
15911     other_context->Exit();
15912     CcTest::heap()->CollectAllGarbage();
15913     if (GetGlobalObjectsCount() == 1) break;
15914   }
15915   CHECK_GE(2, gc_count);
15916   CHECK_EQ(1, GetGlobalObjectsCount());
15917
15918   // Looking up the line number for an exception creates reference from the
15919   // compilation cache to the global object.
15920   const char* source_exception = "function f(){throw 1;} f()";
15921   {
15922     v8::HandleScope scope(isolate);
15923     v8::Local<Context> context = Context::New(isolate);
15924
15925     context->Enter();
15926     v8::TryCatch try_catch(isolate);
15927     CompileRun(source_exception);
15928     CHECK(try_catch.HasCaught());
15929     v8::Handle<v8::Message> message = try_catch.Message();
15930     CHECK(!message.IsEmpty());
15931     CHECK_EQ(1, message->GetLineNumber());
15932     context->Exit();
15933   }
15934   isolate->ContextDisposedNotification();
15935   for (gc_count = 1; gc_count < 10; gc_count++) {
15936     other_context->Enter();
15937     CompileRun(source_exception);
15938     other_context->Exit();
15939     CcTest::heap()->CollectAllGarbage();
15940     if (GetGlobalObjectsCount() == 1) break;
15941   }
15942   CHECK_GE(2, gc_count);
15943   CHECK_EQ(1, GetGlobalObjectsCount());
15944
15945   isolate->ContextDisposedNotification();
15946 }
15947
15948
15949 THREADED_TEST(ScriptOrigin) {
15950   LocalContext env;
15951   v8::HandleScope scope(env->GetIsolate());
15952   v8::ScriptOrigin origin = v8::ScriptOrigin(
15953       v8::String::NewFromUtf8(env->GetIsolate(), "test"),
15954       v8::Integer::New(env->GetIsolate(), 1),
15955       v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
15956       v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
15957       v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"),
15958       v8::True(env->GetIsolate()));
15959   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
15960       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
15961   v8::Script::Compile(script, &origin)->Run();
15962   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15963       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
15964   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15965       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
15966
15967   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15968   CHECK_EQ(0, strcmp("test",
15969                      *v8::String::Utf8Value(script_origin_f.ResourceName())));
15970   CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
15971   CHECK(script_origin_f.Options().IsSharedCrossOrigin());
15972   CHECK(script_origin_f.Options().IsEmbedderDebugScript());
15973   CHECK(script_origin_f.Options().IsOpaque());
15974   printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
15975
15976   CHECK_EQ(0, strcmp("http://sourceMapUrl",
15977                      *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
15978
15979   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15980   CHECK_EQ(0, strcmp("test",
15981                      *v8::String::Utf8Value(script_origin_g.ResourceName())));
15982   CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
15983   CHECK(script_origin_g.Options().IsSharedCrossOrigin());
15984   CHECK(script_origin_g.Options().IsEmbedderDebugScript());
15985   CHECK(script_origin_g.Options().IsOpaque());
15986   CHECK_EQ(0, strcmp("http://sourceMapUrl",
15987                      *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
15988 }
15989
15990
15991 THREADED_TEST(FunctionGetInferredName) {
15992   LocalContext env;
15993   v8::HandleScope scope(env->GetIsolate());
15994   v8::ScriptOrigin origin =
15995       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
15996   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
15997       env->GetIsolate(),
15998       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15999   v8::Script::Compile(script, &origin)->Run();
16000   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16001       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16002   CHECK_EQ(0,
16003            strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
16004 }
16005
16006
16007 THREADED_TEST(FunctionGetDisplayName) {
16008   LocalContext env;
16009   v8::HandleScope scope(env->GetIsolate());
16010   const char* code = "var error = false;"
16011                      "function a() { this.x = 1; };"
16012                      "a.displayName = 'display_a';"
16013                      "var b = (function() {"
16014                      "  var f = function() { this.x = 2; };"
16015                      "  f.displayName = 'display_b';"
16016                      "  return f;"
16017                      "})();"
16018                      "var c = function() {};"
16019                      "c.__defineGetter__('displayName', function() {"
16020                      "  error = true;"
16021                      "  throw new Error();"
16022                      "});"
16023                      "function d() {};"
16024                      "d.__defineGetter__('displayName', function() {"
16025                      "  error = true;"
16026                      "  return 'wrong_display_name';"
16027                      "});"
16028                      "function e() {};"
16029                      "e.displayName = 'wrong_display_name';"
16030                      "e.__defineSetter__('displayName', function() {"
16031                      "  error = true;"
16032                      "  throw new Error();"
16033                      "});"
16034                      "function f() {};"
16035                      "f.displayName = { 'foo': 6, toString: function() {"
16036                      "  error = true;"
16037                      "  return 'wrong_display_name';"
16038                      "}};"
16039                      "var g = function() {"
16040                      "  arguments.callee.displayName = 'set_in_runtime';"
16041                      "}; g();"
16042                      ;
16043   v8::ScriptOrigin origin =
16044       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16045   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
16046       ->Run();
16047   v8::Local<v8::Value> error =
16048       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
16049   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
16050       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
16051   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
16052       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
16053   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
16054       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
16055   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
16056       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
16057   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
16058       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
16059   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16060       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16061   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16062       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16063   CHECK_EQ(false, error->BooleanValue());
16064   CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
16065   CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
16066   CHECK(c->GetDisplayName()->IsUndefined());
16067   CHECK(d->GetDisplayName()->IsUndefined());
16068   CHECK(e->GetDisplayName()->IsUndefined());
16069   CHECK(f->GetDisplayName()->IsUndefined());
16070   CHECK_EQ(
16071       0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
16072 }
16073
16074
16075 THREADED_TEST(ScriptLineNumber) {
16076   LocalContext env;
16077   v8::HandleScope scope(env->GetIsolate());
16078   v8::ScriptOrigin origin =
16079       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16080   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16081       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16082   v8::Script::Compile(script, &origin)->Run();
16083   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16084       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16085   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16086       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16087   CHECK_EQ(0, f->GetScriptLineNumber());
16088   CHECK_EQ(2, g->GetScriptLineNumber());
16089 }
16090
16091
16092 THREADED_TEST(ScriptColumnNumber) {
16093   LocalContext env;
16094   v8::Isolate* isolate = env->GetIsolate();
16095   v8::HandleScope scope(isolate);
16096   v8::ScriptOrigin origin =
16097       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16098                        v8::Integer::New(isolate, 3),
16099                        v8::Integer::New(isolate, 2));
16100   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16101       isolate, "function foo() {}\n\n     function bar() {}");
16102   v8::Script::Compile(script, &origin)->Run();
16103   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16104       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16105   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16106       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16107   CHECK_EQ(14, foo->GetScriptColumnNumber());
16108   CHECK_EQ(17, bar->GetScriptColumnNumber());
16109 }
16110
16111
16112 THREADED_TEST(FunctionIsBuiltin) {
16113   LocalContext env;
16114   v8::Isolate* isolate = env->GetIsolate();
16115   v8::HandleScope scope(isolate);
16116   v8::Local<v8::Function> f;
16117   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
16118   CHECK(f->IsBuiltin());
16119   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
16120   CHECK(f->IsBuiltin());
16121   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
16122   CHECK(f->IsBuiltin());
16123   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
16124   CHECK(f->IsBuiltin());
16125   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
16126   CHECK(!f->IsBuiltin());
16127 }
16128
16129
16130 THREADED_TEST(FunctionGetScriptId) {
16131   LocalContext env;
16132   v8::Isolate* isolate = env->GetIsolate();
16133   v8::HandleScope scope(isolate);
16134   v8::ScriptOrigin origin =
16135       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16136                        v8::Integer::New(isolate, 3),
16137                        v8::Integer::New(isolate, 2));
16138   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
16139       isolate, "function foo() {}\n\n     function bar() {}");
16140   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16141   script->Run();
16142   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16143       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16144   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16145       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16146   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
16147   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
16148 }
16149
16150
16151 THREADED_TEST(FunctionGetBoundFunction) {
16152   LocalContext env;
16153   v8::HandleScope scope(env->GetIsolate());
16154   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
16155       env->GetIsolate(), "test"));
16156   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16157       env->GetIsolate(),
16158       "var a = new Object();\n"
16159       "a.x = 1;\n"
16160       "function f () { return this.x };\n"
16161       "var g = f.bind(a);\n"
16162       "var b = g();");
16163   v8::Script::Compile(script, &origin)->Run();
16164   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16165       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16166   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16167       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16168   CHECK(g->GetBoundFunction()->IsFunction());
16169   Local<v8::Function> original_function = Local<v8::Function>::Cast(
16170       g->GetBoundFunction());
16171   CHECK(f->GetName()->Equals(original_function->GetName()));
16172   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
16173   CHECK_EQ(f->GetScriptColumnNumber(),
16174            original_function->GetScriptColumnNumber());
16175 }
16176
16177
16178 static void GetterWhichReturns42(
16179     Local<String> name,
16180     const v8::PropertyCallbackInfo<v8::Value>& info) {
16181   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16182   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16183   info.GetReturnValue().Set(v8_num(42));
16184 }
16185
16186
16187 static void SetterWhichSetsYOnThisTo23(
16188     Local<String> name,
16189     Local<Value> value,
16190     const v8::PropertyCallbackInfo<void>& info) {
16191   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16192   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16193   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16194 }
16195
16196
16197 void FooGetInterceptor(Local<Name> name,
16198                        const v8::PropertyCallbackInfo<v8::Value>& info) {
16199   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16200   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16201   if (!name->Equals(v8_str("foo"))) return;
16202   info.GetReturnValue().Set(v8_num(42));
16203 }
16204
16205
16206 void FooSetInterceptor(Local<Name> name, Local<Value> value,
16207                        const v8::PropertyCallbackInfo<v8::Value>& info) {
16208   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16209   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16210   if (!name->Equals(v8_str("foo"))) return;
16211   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16212   info.GetReturnValue().Set(v8_num(23));
16213 }
16214
16215
16216 TEST(SetterOnConstructorPrototype) {
16217   v8::Isolate* isolate = CcTest::isolate();
16218   v8::HandleScope scope(isolate);
16219   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16220   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16221                      SetterWhichSetsYOnThisTo23);
16222   LocalContext context;
16223   context->Global()->Set(v8_str("P"), templ->NewInstance());
16224   CompileRun("function C1() {"
16225              "  this.x = 23;"
16226              "};"
16227              "C1.prototype = P;"
16228              "function C2() {"
16229              "  this.x = 23"
16230              "};"
16231              "C2.prototype = { };"
16232              "C2.prototype.__proto__ = P;");
16233
16234   v8::Local<v8::Script> script;
16235   script = v8_compile("new C1();");
16236   for (int i = 0; i < 10; i++) {
16237     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16238     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16239     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16240   }
16241
16242 script = v8_compile("new C2();");
16243   for (int i = 0; i < 10; i++) {
16244     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16245     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
16246     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
16247   }
16248 }
16249
16250
16251 static void NamedPropertyGetterWhichReturns42(
16252     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16253   info.GetReturnValue().Set(v8_num(42));
16254 }
16255
16256
16257 static void NamedPropertySetterWhichSetsYOnThisTo23(
16258     Local<Name> name, Local<Value> value,
16259     const v8::PropertyCallbackInfo<v8::Value>& info) {
16260   if (name->Equals(v8_str("x"))) {
16261     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16262   }
16263 }
16264
16265
16266 THREADED_TEST(InterceptorOnConstructorPrototype) {
16267   v8::Isolate* isolate = CcTest::isolate();
16268   v8::HandleScope scope(isolate);
16269   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16270   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16271       NamedPropertyGetterWhichReturns42,
16272       NamedPropertySetterWhichSetsYOnThisTo23));
16273   LocalContext context;
16274   context->Global()->Set(v8_str("P"), templ->NewInstance());
16275   CompileRun("function C1() {"
16276              "  this.x = 23;"
16277              "};"
16278              "C1.prototype = P;"
16279              "function C2() {"
16280              "  this.x = 23"
16281              "};"
16282              "C2.prototype = { };"
16283              "C2.prototype.__proto__ = P;");
16284
16285   v8::Local<v8::Script> script;
16286   script = v8_compile("new C1();");
16287   for (int i = 0; i < 10; i++) {
16288     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16289     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16290     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16291   }
16292
16293   script = v8_compile("new C2();");
16294   for (int i = 0; i < 10; i++) {
16295     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16296     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
16297     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
16298   }
16299 }
16300
16301
16302 TEST(Regress618) {
16303   const char* source = "function C1() {"
16304                        "  this.x = 23;"
16305                        "};"
16306                        "C1.prototype = P;";
16307
16308   LocalContext context;
16309   v8::Isolate* isolate = context->GetIsolate();
16310   v8::HandleScope scope(isolate);
16311   v8::Local<v8::Script> script;
16312
16313   // Use a simple object as prototype.
16314   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
16315   prototype->Set(v8_str("y"), v8_num(42));
16316   context->Global()->Set(v8_str("P"), prototype);
16317
16318   // This compile will add the code to the compilation cache.
16319   CompileRun(source);
16320
16321   script = v8_compile("new C1();");
16322   // Allow enough iterations for the inobject slack tracking logic
16323   // to finalize instance size and install the fast construct stub.
16324   for (int i = 0; i < 256; i++) {
16325     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16326     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16327     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16328   }
16329
16330   // Use an API object with accessors as prototype.
16331   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16332   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16333                      SetterWhichSetsYOnThisTo23);
16334   context->Global()->Set(v8_str("P"), templ->NewInstance());
16335
16336   // This compile will get the code from the compilation cache.
16337   CompileRun(source);
16338
16339   script = v8_compile("new C1();");
16340   for (int i = 0; i < 10; i++) {
16341     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16342     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16343     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16344   }
16345 }
16346
16347 v8::Isolate* gc_callbacks_isolate = NULL;
16348 int prologue_call_count = 0;
16349 int epilogue_call_count = 0;
16350 int prologue_call_count_second = 0;
16351 int epilogue_call_count_second = 0;
16352 int prologue_call_count_alloc = 0;
16353 int epilogue_call_count_alloc = 0;
16354
16355 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16356   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16357   ++prologue_call_count;
16358 }
16359
16360
16361 void PrologueCallback(v8::Isolate* isolate,
16362                       v8::GCType,
16363                       v8::GCCallbackFlags flags) {
16364   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16365   CHECK_EQ(gc_callbacks_isolate, isolate);
16366   ++prologue_call_count;
16367 }
16368
16369
16370 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16371   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16372   ++epilogue_call_count;
16373 }
16374
16375
16376 void EpilogueCallback(v8::Isolate* isolate,
16377                       v8::GCType,
16378                       v8::GCCallbackFlags flags) {
16379   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16380   CHECK_EQ(gc_callbacks_isolate, isolate);
16381   ++epilogue_call_count;
16382 }
16383
16384
16385 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16386   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16387   ++prologue_call_count_second;
16388 }
16389
16390
16391 void PrologueCallbackSecond(v8::Isolate* isolate,
16392                             v8::GCType,
16393                             v8::GCCallbackFlags flags) {
16394   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16395   CHECK_EQ(gc_callbacks_isolate, isolate);
16396   ++prologue_call_count_second;
16397 }
16398
16399
16400 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16401   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16402   ++epilogue_call_count_second;
16403 }
16404
16405
16406 void EpilogueCallbackSecond(v8::Isolate* isolate,
16407                             v8::GCType,
16408                             v8::GCCallbackFlags flags) {
16409   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16410   CHECK_EQ(gc_callbacks_isolate, isolate);
16411   ++epilogue_call_count_second;
16412 }
16413
16414
16415 void PrologueCallbackAlloc(v8::Isolate* isolate,
16416                            v8::GCType,
16417                            v8::GCCallbackFlags flags) {
16418   v8::HandleScope scope(isolate);
16419
16420   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16421   CHECK_EQ(gc_callbacks_isolate, isolate);
16422   ++prologue_call_count_alloc;
16423
16424   // Simulate full heap to see if we will reenter this callback
16425   SimulateFullSpace(CcTest::heap()->new_space());
16426
16427   Local<Object> obj = Object::New(isolate);
16428   CHECK(!obj.IsEmpty());
16429
16430   CcTest::heap()->CollectAllGarbage(
16431       i::Heap::kAbortIncrementalMarkingMask);
16432 }
16433
16434
16435 void EpilogueCallbackAlloc(v8::Isolate* isolate,
16436                            v8::GCType,
16437                            v8::GCCallbackFlags flags) {
16438   v8::HandleScope scope(isolate);
16439
16440   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16441   CHECK_EQ(gc_callbacks_isolate, isolate);
16442   ++epilogue_call_count_alloc;
16443
16444   // Simulate full heap to see if we will reenter this callback
16445   SimulateFullSpace(CcTest::heap()->new_space());
16446
16447   Local<Object> obj = Object::New(isolate);
16448   CHECK(!obj.IsEmpty());
16449
16450   CcTest::heap()->CollectAllGarbage(
16451       i::Heap::kAbortIncrementalMarkingMask);
16452 }
16453
16454
16455 TEST(GCCallbacksOld) {
16456   LocalContext context;
16457
16458   v8::V8::AddGCPrologueCallback(PrologueCallback);
16459   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
16460   CHECK_EQ(0, prologue_call_count);
16461   CHECK_EQ(0, epilogue_call_count);
16462   CcTest::heap()->CollectAllGarbage();
16463   CHECK_EQ(1, prologue_call_count);
16464   CHECK_EQ(1, epilogue_call_count);
16465   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
16466   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
16467   CcTest::heap()->CollectAllGarbage();
16468   CHECK_EQ(2, prologue_call_count);
16469   CHECK_EQ(2, epilogue_call_count);
16470   CHECK_EQ(1, prologue_call_count_second);
16471   CHECK_EQ(1, epilogue_call_count_second);
16472   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
16473   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
16474   CcTest::heap()->CollectAllGarbage();
16475   CHECK_EQ(2, prologue_call_count);
16476   CHECK_EQ(2, epilogue_call_count);
16477   CHECK_EQ(2, prologue_call_count_second);
16478   CHECK_EQ(2, epilogue_call_count_second);
16479   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
16480   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
16481   CcTest::heap()->CollectAllGarbage();
16482   CHECK_EQ(2, prologue_call_count);
16483   CHECK_EQ(2, epilogue_call_count);
16484   CHECK_EQ(2, prologue_call_count_second);
16485   CHECK_EQ(2, epilogue_call_count_second);
16486 }
16487
16488
16489 TEST(GCCallbacks) {
16490   LocalContext context;
16491   v8::Isolate* isolate = context->GetIsolate();
16492   gc_callbacks_isolate = isolate;
16493   isolate->AddGCPrologueCallback(PrologueCallback);
16494   isolate->AddGCEpilogueCallback(EpilogueCallback);
16495   CHECK_EQ(0, prologue_call_count);
16496   CHECK_EQ(0, epilogue_call_count);
16497   CcTest::heap()->CollectAllGarbage();
16498   CHECK_EQ(1, prologue_call_count);
16499   CHECK_EQ(1, epilogue_call_count);
16500   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
16501   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
16502   CcTest::heap()->CollectAllGarbage();
16503   CHECK_EQ(2, prologue_call_count);
16504   CHECK_EQ(2, epilogue_call_count);
16505   CHECK_EQ(1, prologue_call_count_second);
16506   CHECK_EQ(1, epilogue_call_count_second);
16507   isolate->RemoveGCPrologueCallback(PrologueCallback);
16508   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
16509   CcTest::heap()->CollectAllGarbage();
16510   CHECK_EQ(2, prologue_call_count);
16511   CHECK_EQ(2, epilogue_call_count);
16512   CHECK_EQ(2, prologue_call_count_second);
16513   CHECK_EQ(2, epilogue_call_count_second);
16514   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
16515   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
16516   CcTest::heap()->CollectAllGarbage();
16517   CHECK_EQ(2, prologue_call_count);
16518   CHECK_EQ(2, epilogue_call_count);
16519   CHECK_EQ(2, prologue_call_count_second);
16520   CHECK_EQ(2, epilogue_call_count_second);
16521
16522   CHECK_EQ(0, prologue_call_count_alloc);
16523   CHECK_EQ(0, epilogue_call_count_alloc);
16524   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
16525   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
16526   CcTest::heap()->CollectAllGarbage(
16527       i::Heap::kAbortIncrementalMarkingMask);
16528   CHECK_EQ(1, prologue_call_count_alloc);
16529   CHECK_EQ(1, epilogue_call_count_alloc);
16530   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
16531   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
16532 }
16533
16534
16535 THREADED_TEST(AddToJSFunctionResultCache) {
16536   i::FLAG_stress_compaction = false;
16537   i::FLAG_allow_natives_syntax = true;
16538   v8::HandleScope scope(CcTest::isolate());
16539
16540   LocalContext context;
16541
16542   const char* code =
16543       "(function() {"
16544       "  var key0 = 'a';"
16545       "  var key1 = 'b';"
16546       "  var r0 = %_GetFromCache(0, key0);"
16547       "  var r1 = %_GetFromCache(0, key1);"
16548       "  var r0_ = %_GetFromCache(0, key0);"
16549       "  if (r0 !== r0_)"
16550       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
16551       "  var r1_ = %_GetFromCache(0, key1);"
16552       "  if (r1 !== r1_)"
16553       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
16554       "  return 'PASSED';"
16555       "})()";
16556   CcTest::heap()->ClearJSFunctionResultCaches();
16557   ExpectString(code, "PASSED");
16558 }
16559
16560
16561 THREADED_TEST(FillJSFunctionResultCache) {
16562   i::FLAG_allow_natives_syntax = true;
16563   LocalContext context;
16564   v8::HandleScope scope(context->GetIsolate());
16565
16566   const char* code =
16567       "(function() {"
16568       "  var k = 'a';"
16569       "  var r = %_GetFromCache(0, k);"
16570       "  for (var i = 0; i < 16; i++) {"
16571       "    %_GetFromCache(0, 'a' + i);"
16572       "  };"
16573       "  if (r === %_GetFromCache(0, k))"
16574       "    return 'FAILED: k0CacheSize is too small';"
16575       "  return 'PASSED';"
16576       "})()";
16577   CcTest::heap()->ClearJSFunctionResultCaches();
16578   ExpectString(code, "PASSED");
16579 }
16580
16581
16582 THREADED_TEST(RoundRobinGetFromCache) {
16583   i::FLAG_allow_natives_syntax = true;
16584   LocalContext context;
16585   v8::HandleScope scope(context->GetIsolate());
16586
16587   const char* code =
16588       "(function() {"
16589       "  var keys = [];"
16590       "  for (var i = 0; i < 16; i++) keys.push(i);"
16591       "  var values = [];"
16592       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
16593       "  for (var i = 0; i < 16; i++) {"
16594       "    var v = %_GetFromCache(0, keys[i]);"
16595       "    if (v.toString() !== values[i].toString())"
16596       "      return 'Wrong value for ' + "
16597       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
16598       "  };"
16599       "  return 'PASSED';"
16600       "})()";
16601   CcTest::heap()->ClearJSFunctionResultCaches();
16602   ExpectString(code, "PASSED");
16603 }
16604
16605
16606 THREADED_TEST(ReverseGetFromCache) {
16607   i::FLAG_allow_natives_syntax = true;
16608   LocalContext context;
16609   v8::HandleScope scope(context->GetIsolate());
16610
16611   const char* code =
16612       "(function() {"
16613       "  var keys = [];"
16614       "  for (var i = 0; i < 16; i++) keys.push(i);"
16615       "  var values = [];"
16616       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
16617       "  for (var i = 15; i >= 16; i--) {"
16618       "    var v = %_GetFromCache(0, keys[i]);"
16619       "    if (v !== values[i])"
16620       "      return 'Wrong value for ' + "
16621       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
16622       "  };"
16623       "  return 'PASSED';"
16624       "})()";
16625   CcTest::heap()->ClearJSFunctionResultCaches();
16626   ExpectString(code, "PASSED");
16627 }
16628
16629
16630 THREADED_TEST(TestEviction) {
16631   i::FLAG_allow_natives_syntax = true;
16632   LocalContext context;
16633   v8::HandleScope scope(context->GetIsolate());
16634
16635   const char* code =
16636       "(function() {"
16637       "  for (var i = 0; i < 2*16; i++) {"
16638       "    %_GetFromCache(0, 'a' + i);"
16639       "  };"
16640       "  return 'PASSED';"
16641       "})()";
16642   CcTest::heap()->ClearJSFunctionResultCaches();
16643   ExpectString(code, "PASSED");
16644 }
16645
16646
16647 THREADED_TEST(TwoByteStringInOneByteCons) {
16648   // See Chromium issue 47824.
16649   LocalContext context;
16650   v8::HandleScope scope(context->GetIsolate());
16651
16652   const char* init_code =
16653       "var str1 = 'abelspendabel';"
16654       "var str2 = str1 + str1 + str1;"
16655       "str2;";
16656   Local<Value> result = CompileRun(init_code);
16657
16658   Local<Value> indexof = CompileRun("str2.indexOf('els')");
16659   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
16660
16661   CHECK(result->IsString());
16662   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
16663   int length = string->length();
16664   CHECK(string->IsOneByteRepresentation());
16665
16666   i::Handle<i::String> flat_string = i::String::Flatten(string);
16667
16668   CHECK(string->IsOneByteRepresentation());
16669   CHECK(flat_string->IsOneByteRepresentation());
16670
16671   // Create external resource.
16672   uint16_t* uc16_buffer = new uint16_t[length + 1];
16673
16674   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
16675   uc16_buffer[length] = 0;
16676
16677   TestResource resource(uc16_buffer);
16678
16679   flat_string->MakeExternal(&resource);
16680
16681   CHECK(flat_string->IsTwoByteRepresentation());
16682
16683   // If the cons string has been short-circuited, skip the following checks.
16684   if (!string.is_identical_to(flat_string)) {
16685     // At this point, we should have a Cons string which is flat and one-byte,
16686     // with a first half that is a two-byte string (although it only contains
16687     // one-byte characters). This is a valid sequence of steps, and it can
16688     // happen in real pages.
16689     CHECK(string->IsOneByteRepresentation());
16690     i::ConsString* cons = i::ConsString::cast(*string);
16691     CHECK_EQ(0, cons->second()->length());
16692     CHECK(cons->first()->IsTwoByteRepresentation());
16693   }
16694
16695   // Check that some string operations work.
16696
16697   // Atom RegExp.
16698   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
16699   CHECK_EQ(6, reresult->Int32Value());
16700
16701   // Nonatom RegExp.
16702   reresult = CompileRun("str2.match(/abe./g).length;");
16703   CHECK_EQ(6, reresult->Int32Value());
16704
16705   reresult = CompileRun("str2.search(/bel/g);");
16706   CHECK_EQ(1, reresult->Int32Value());
16707
16708   reresult = CompileRun("str2.search(/be./g);");
16709   CHECK_EQ(1, reresult->Int32Value());
16710
16711   ExpectTrue("/bel/g.test(str2);");
16712
16713   ExpectTrue("/be./g.test(str2);");
16714
16715   reresult = CompileRun("/bel/g.exec(str2);");
16716   CHECK(!reresult->IsNull());
16717
16718   reresult = CompileRun("/be./g.exec(str2);");
16719   CHECK(!reresult->IsNull());
16720
16721   ExpectString("str2.substring(2, 10);", "elspenda");
16722
16723   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
16724
16725   ExpectString("str2.charAt(2);", "e");
16726
16727   ExpectObject("str2.indexOf('els');", indexof);
16728
16729   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
16730
16731   reresult = CompileRun("str2.charCodeAt(2);");
16732   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
16733 }
16734
16735
16736 TEST(ContainsOnlyOneByte) {
16737   v8::V8::Initialize();
16738   v8::Isolate* isolate = CcTest::isolate();
16739   v8::HandleScope scope(isolate);
16740   // Make a buffer long enough that it won't automatically be converted.
16741   const int length = 512;
16742   // Ensure word aligned assignment.
16743   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
16744   i::SmartArrayPointer<uintptr_t>
16745   aligned_contents(new uintptr_t[aligned_length]);
16746   uint16_t* string_contents =
16747       reinterpret_cast<uint16_t*>(aligned_contents.get());
16748   // Set to contain only one byte.
16749   for (int i = 0; i < length-1; i++) {
16750     string_contents[i] = 0x41;
16751   }
16752   string_contents[length-1] = 0;
16753   // Simple case.
16754   Handle<String> string =
16755       String::NewExternal(isolate,
16756                           new TestResource(string_contents, NULL, false));
16757   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16758   // Counter example.
16759   string = String::NewFromTwoByte(isolate, string_contents);
16760   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
16761   // Test left right and balanced cons strings.
16762   Handle<String> base = String::NewFromUtf8(isolate, "a");
16763   Handle<String> left = base;
16764   Handle<String> right = base;
16765   for (int i = 0; i < 1000; i++) {
16766     left = String::Concat(base, left);
16767     right = String::Concat(right, base);
16768   }
16769   Handle<String> balanced = String::Concat(left, base);
16770   balanced = String::Concat(balanced, right);
16771   Handle<String> cons_strings[] = {left, balanced, right};
16772   Handle<String> two_byte =
16773       String::NewExternal(isolate,
16774                           new TestResource(string_contents, NULL, false));
16775   USE(two_byte); USE(cons_strings);
16776   for (size_t i = 0; i < arraysize(cons_strings); i++) {
16777     // Base assumptions.
16778     string = cons_strings[i];
16779     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
16780     // Test left and right concatentation.
16781     string = String::Concat(two_byte, cons_strings[i]);
16782     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16783     string = String::Concat(cons_strings[i], two_byte);
16784     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16785   }
16786   // Set bits in different positions
16787   // for strings of different lengths and alignments.
16788   for (int alignment = 0; alignment < 7; alignment++) {
16789     for (int size = 2; alignment + size < length; size *= 2) {
16790       int zero_offset = size + alignment;
16791       string_contents[zero_offset] = 0;
16792       for (int i = 0; i < size; i++) {
16793         int shift = 8 + (i % 7);
16794         string_contents[alignment + i] = 1 << shift;
16795         string = String::NewExternal(
16796             isolate,
16797             new TestResource(string_contents + alignment, NULL, false));
16798         CHECK_EQ(size, string->Length());
16799         CHECK(!string->ContainsOnlyOneByte());
16800         string_contents[alignment + i] = 0x41;
16801       }
16802       string_contents[zero_offset] = 0x41;
16803     }
16804   }
16805 }
16806
16807
16808 // Failed access check callback that performs a GC on each invocation.
16809 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
16810                                  v8::AccessType type,
16811                                  Local<v8::Value> data) {
16812   CcTest::heap()->CollectAllGarbage();
16813   CcTest::isolate()->ThrowException(
16814       v8::Exception::Error(v8_str("cross context")));
16815 }
16816
16817
16818 TEST(GCInFailedAccessCheckCallback) {
16819   // Install a failed access check callback that performs a GC on each
16820   // invocation. Then force the callback to be called from va
16821
16822   v8::V8::Initialize();
16823   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
16824
16825   v8::Isolate* isolate = CcTest::isolate();
16826   v8::HandleScope scope(isolate);
16827
16828   // Create an ObjectTemplate for global objects and install access
16829   // check callbacks that will block access.
16830   v8::Handle<v8::ObjectTemplate> global_template =
16831       v8::ObjectTemplate::New(isolate);
16832   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
16833                                            v8::Handle<v8::Value>());
16834
16835   // Create a context and set an x property on it's global object.
16836   LocalContext context0(NULL, global_template);
16837   context0->Global()->Set(v8_str("x"), v8_num(42));
16838   v8::Handle<v8::Object> global0 = context0->Global();
16839
16840   // Create a context with a different security token so that the
16841   // failed access check callback will be called on each access.
16842   LocalContext context1(NULL, global_template);
16843   context1->Global()->Set(v8_str("other"), global0);
16844
16845   v8::TryCatch try_catch(isolate);
16846
16847   // Get property with failed access check.
16848   CHECK(CompileRun("other.x").IsEmpty());
16849   CHECK(try_catch.HasCaught());
16850   try_catch.Reset();
16851
16852   // Get element with failed access check.
16853   CHECK(CompileRun("other[0]").IsEmpty());
16854   CHECK(try_catch.HasCaught());
16855   try_catch.Reset();
16856
16857   // Set property with failed access check.
16858   CHECK(CompileRun("other.x = new Object()").IsEmpty());
16859   CHECK(try_catch.HasCaught());
16860   try_catch.Reset();
16861
16862   // Set element with failed access check.
16863   CHECK(CompileRun("other[0] = new Object()").IsEmpty());
16864   CHECK(try_catch.HasCaught());
16865   try_catch.Reset();
16866
16867   // Get property attribute with failed access check.
16868   CHECK(CompileRun("\'x\' in other").IsEmpty());
16869   CHECK(try_catch.HasCaught());
16870   try_catch.Reset();
16871
16872   // Get property attribute for element with failed access check.
16873   CHECK(CompileRun("0 in other").IsEmpty());
16874   CHECK(try_catch.HasCaught());
16875   try_catch.Reset();
16876
16877   // Delete property.
16878   CHECK(CompileRun("delete other.x").IsEmpty());
16879   CHECK(try_catch.HasCaught());
16880   try_catch.Reset();
16881
16882   // Delete element.
16883   CHECK_EQ(false, global0->Delete(0));
16884
16885   // DefineAccessor.
16886   CHECK_EQ(false,
16887            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
16888
16889   // Define JavaScript accessor.
16890   CHECK(CompileRun(
16891             "Object.prototype.__defineGetter__.call("
16892             "    other, \'x\', function() { return 42; })").IsEmpty());
16893   CHECK(try_catch.HasCaught());
16894   try_catch.Reset();
16895
16896   // LookupAccessor.
16897   CHECK(CompileRun(
16898             "Object.prototype.__lookupGetter__.call("
16899             "    other, \'x\')").IsEmpty());
16900   CHECK(try_catch.HasCaught());
16901   try_catch.Reset();
16902
16903   // HasOwnElement.
16904   CHECK(CompileRun(
16905             "Object.prototype.hasOwnProperty.call("
16906             "other, \'0\')").IsEmpty());
16907   CHECK(try_catch.HasCaught());
16908   try_catch.Reset();
16909
16910   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
16911   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
16912   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
16913
16914   // Reset the failed access check callback so it does not influence
16915   // the other tests.
16916   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
16917 }
16918
16919
16920 TEST(IsolateNewDispose) {
16921   v8::Isolate* current_isolate = CcTest::isolate();
16922   v8::Isolate::CreateParams create_params;
16923   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16924   v8::Isolate* isolate = v8::Isolate::New(create_params);
16925   CHECK(isolate != NULL);
16926   CHECK(current_isolate != isolate);
16927   CHECK(current_isolate == CcTest::isolate());
16928
16929   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16930   last_location = last_message = NULL;
16931   isolate->Dispose();
16932   CHECK(!last_location);
16933   CHECK(!last_message);
16934 }
16935
16936
16937 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
16938   v8::Isolate::CreateParams create_params;
16939   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16940   v8::Isolate* isolate = v8::Isolate::New(create_params);
16941   {
16942     v8::Isolate::Scope i_scope(isolate);
16943     v8::HandleScope scope(isolate);
16944     LocalContext context(isolate);
16945     // Run something in this isolate.
16946     ExpectTrue("true");
16947     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16948     last_location = last_message = NULL;
16949     // Still entered, should fail.
16950     isolate->Dispose();
16951     CHECK(last_location);
16952     CHECK(last_message);
16953   }
16954   isolate->Dispose();
16955 }
16956
16957
16958 static void BreakArrayGuarantees(const char* script) {
16959   v8::Isolate::CreateParams create_params;
16960   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16961   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
16962   isolate1->Enter();
16963   v8::Persistent<v8::Context> context1;
16964   {
16965     v8::HandleScope scope(isolate1);
16966     context1.Reset(isolate1, Context::New(isolate1));
16967   }
16968
16969   {
16970     v8::HandleScope scope(isolate1);
16971     v8::Local<v8::Context> context =
16972         v8::Local<v8::Context>::New(isolate1, context1);
16973     v8::Context::Scope context_scope(context);
16974     v8::internal::Isolate* i_isolate =
16975         reinterpret_cast<v8::internal::Isolate*>(isolate1);
16976     CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
16977     // Run something in new isolate.
16978     CompileRun(script);
16979     CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
16980   }
16981   isolate1->Exit();
16982   isolate1->Dispose();
16983 }
16984
16985
16986 TEST(VerifyArrayPrototypeGuarantees) {
16987   // Break fast array hole handling by element changes.
16988   BreakArrayGuarantees("[].__proto__[1] = 3;");
16989   BreakArrayGuarantees("Object.prototype[3] = 'three';");
16990   BreakArrayGuarantees("Array.prototype.push(1);");
16991   BreakArrayGuarantees("Array.prototype.unshift(1);");
16992   // Break fast array hole handling by changing length.
16993   BreakArrayGuarantees("Array.prototype.length = 30;");
16994   // Break fast array hole handling by prototype structure changes.
16995   BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
16996   // By sending elements to dictionary mode.
16997   BreakArrayGuarantees("Object.freeze(Array.prototype);");
16998   BreakArrayGuarantees("Object.freeze(Object.prototype);");
16999   BreakArrayGuarantees(
17000       "Object.defineProperty(Array.prototype, 0, {"
17001       "  get: function() { return 3; }});");
17002   BreakArrayGuarantees(
17003       "Object.defineProperty(Object.prototype, 0, {"
17004       "  get: function() { return 3; }});");
17005 }
17006
17007
17008 TEST(RunTwoIsolatesOnSingleThread) {
17009   // Run isolate 1.
17010   v8::Isolate::CreateParams create_params;
17011   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17012   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
17013   isolate1->Enter();
17014   v8::Persistent<v8::Context> context1;
17015   {
17016     v8::HandleScope scope(isolate1);
17017     context1.Reset(isolate1, Context::New(isolate1));
17018   }
17019
17020   {
17021     v8::HandleScope scope(isolate1);
17022     v8::Local<v8::Context> context =
17023         v8::Local<v8::Context>::New(isolate1, context1);
17024     v8::Context::Scope context_scope(context);
17025     // Run something in new isolate.
17026     CompileRun("var foo = 'isolate 1';");
17027     ExpectString("function f() { return foo; }; f()", "isolate 1");
17028   }
17029
17030   // Run isolate 2.
17031   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
17032   v8::Persistent<v8::Context> context2;
17033
17034   {
17035     v8::Isolate::Scope iscope(isolate2);
17036     v8::HandleScope scope(isolate2);
17037     context2.Reset(isolate2, Context::New(isolate2));
17038     v8::Local<v8::Context> context =
17039         v8::Local<v8::Context>::New(isolate2, context2);
17040     v8::Context::Scope context_scope(context);
17041
17042     // Run something in new isolate.
17043     CompileRun("var foo = 'isolate 2';");
17044     ExpectString("function f() { return foo; }; f()", "isolate 2");
17045   }
17046
17047   {
17048     v8::HandleScope scope(isolate1);
17049     v8::Local<v8::Context> context =
17050         v8::Local<v8::Context>::New(isolate1, context1);
17051     v8::Context::Scope context_scope(context);
17052     // Now again in isolate 1
17053     ExpectString("function f() { return foo; }; f()", "isolate 1");
17054   }
17055
17056   isolate1->Exit();
17057
17058   // Run some stuff in default isolate.
17059   v8::Persistent<v8::Context> context_default;
17060   {
17061     v8::Isolate* isolate = CcTest::isolate();
17062     v8::Isolate::Scope iscope(isolate);
17063     v8::HandleScope scope(isolate);
17064     context_default.Reset(isolate, Context::New(isolate));
17065   }
17066
17067   {
17068     v8::HandleScope scope(CcTest::isolate());
17069     v8::Local<v8::Context> context =
17070         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17071     v8::Context::Scope context_scope(context);
17072     // Variables in other isolates should be not available, verify there
17073     // is an exception.
17074     ExpectTrue("function f() {"
17075                "  try {"
17076                "    foo;"
17077                "    return false;"
17078                "  } catch(e) {"
17079                "    return true;"
17080                "  }"
17081                "};"
17082                "var isDefaultIsolate = true;"
17083                "f()");
17084   }
17085
17086   isolate1->Enter();
17087
17088   {
17089     v8::Isolate::Scope iscope(isolate2);
17090     v8::HandleScope scope(isolate2);
17091     v8::Local<v8::Context> context =
17092         v8::Local<v8::Context>::New(isolate2, context2);
17093     v8::Context::Scope context_scope(context);
17094     ExpectString("function f() { return foo; }; f()", "isolate 2");
17095   }
17096
17097   {
17098     v8::HandleScope scope(v8::Isolate::GetCurrent());
17099     v8::Local<v8::Context> context =
17100         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17101     v8::Context::Scope context_scope(context);
17102     ExpectString("function f() { return foo; }; f()", "isolate 1");
17103   }
17104
17105   {
17106     v8::Isolate::Scope iscope(isolate2);
17107     context2.Reset();
17108   }
17109
17110   context1.Reset();
17111   isolate1->Exit();
17112
17113   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17114   last_location = last_message = NULL;
17115
17116   isolate1->Dispose();
17117   CHECK(!last_location);
17118   CHECK(!last_message);
17119
17120   isolate2->Dispose();
17121   CHECK(!last_location);
17122   CHECK(!last_message);
17123
17124   // Check that default isolate still runs.
17125   {
17126     v8::HandleScope scope(CcTest::isolate());
17127     v8::Local<v8::Context> context =
17128         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17129     v8::Context::Scope context_scope(context);
17130     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17131   }
17132 }
17133
17134
17135 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17136   v8::Isolate::Scope isolate_scope(isolate);
17137   v8::HandleScope scope(isolate);
17138   LocalContext context(isolate);
17139   i::ScopedVector<char> code(1024);
17140   i::SNPrintF(code, "function fib(n) {"
17141                     "  if (n <= 2) return 1;"
17142                     "  return fib(n-1) + fib(n-2);"
17143                     "}"
17144                     "fib(%d)", limit);
17145   Local<Value> value = CompileRun(code.start());
17146   CHECK(value->IsNumber());
17147   return static_cast<int>(value->NumberValue());
17148 }
17149
17150 class IsolateThread : public v8::base::Thread {
17151  public:
17152   explicit IsolateThread(int fib_limit)
17153       : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
17154
17155   void Run() {
17156     v8::Isolate::CreateParams create_params;
17157     create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17158     v8::Isolate* isolate = v8::Isolate::New(create_params);
17159     result_ = CalcFibonacci(isolate, fib_limit_);
17160     isolate->Dispose();
17161   }
17162
17163   int result() { return result_; }
17164
17165  private:
17166   int fib_limit_;
17167   int result_;
17168 };
17169
17170
17171 TEST(MultipleIsolatesOnIndividualThreads) {
17172   IsolateThread thread1(21);
17173   IsolateThread thread2(12);
17174
17175   // Compute some fibonacci numbers on 3 threads in 3 isolates.
17176   thread1.Start();
17177   thread2.Start();
17178
17179   int result1 = CalcFibonacci(CcTest::isolate(), 21);
17180   int result2 = CalcFibonacci(CcTest::isolate(), 12);
17181
17182   thread1.Join();
17183   thread2.Join();
17184
17185   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17186   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17187   CHECK_EQ(result1, 10946);
17188   CHECK_EQ(result2, 144);
17189   CHECK_EQ(result1, thread1.result());
17190   CHECK_EQ(result2, thread2.result());
17191 }
17192
17193
17194 TEST(IsolateDifferentContexts) {
17195   v8::Isolate::CreateParams create_params;
17196   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17197   v8::Isolate* isolate = v8::Isolate::New(create_params);
17198   Local<v8::Context> context;
17199   {
17200     v8::Isolate::Scope isolate_scope(isolate);
17201     v8::HandleScope handle_scope(isolate);
17202     context = v8::Context::New(isolate);
17203     v8::Context::Scope context_scope(context);
17204     Local<Value> v = CompileRun("2");
17205     CHECK(v->IsNumber());
17206     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
17207   }
17208   {
17209     v8::Isolate::Scope isolate_scope(isolate);
17210     v8::HandleScope handle_scope(isolate);
17211     context = v8::Context::New(isolate);
17212     v8::Context::Scope context_scope(context);
17213     Local<Value> v = CompileRun("22");
17214     CHECK(v->IsNumber());
17215     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
17216   }
17217   isolate->Dispose();
17218 }
17219
17220 class InitDefaultIsolateThread : public v8::base::Thread {
17221  public:
17222   enum TestCase {
17223     SetResourceConstraints,
17224     SetFatalHandler,
17225     SetCounterFunction,
17226     SetCreateHistogramFunction,
17227     SetAddHistogramSampleFunction
17228   };
17229
17230   explicit InitDefaultIsolateThread(TestCase testCase)
17231       : Thread(Options("InitDefaultIsolateThread")),
17232         testCase_(testCase),
17233         result_(false) {}
17234
17235   void Run() {
17236     v8::Isolate::CreateParams create_params;
17237     create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17238     switch (testCase_) {
17239       case SetResourceConstraints: {
17240         create_params.constraints.set_max_semi_space_size(1);
17241         create_params.constraints.set_max_old_space_size(4);
17242         break;
17243       }
17244       default:
17245         break;
17246     }
17247     v8::Isolate* isolate = v8::Isolate::New(create_params);
17248     isolate->Enter();
17249     switch (testCase_) {
17250       case SetResourceConstraints:
17251         // Already handled in pre-Isolate-creation block.
17252         break;
17253
17254       case SetFatalHandler:
17255         v8::V8::SetFatalErrorHandler(NULL);
17256         break;
17257
17258       case SetCounterFunction:
17259         CcTest::isolate()->SetCounterFunction(NULL);
17260         break;
17261
17262       case SetCreateHistogramFunction:
17263         CcTest::isolate()->SetCreateHistogramFunction(NULL);
17264         break;
17265
17266       case SetAddHistogramSampleFunction:
17267         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
17268         break;
17269     }
17270     isolate->Exit();
17271     isolate->Dispose();
17272     result_ = true;
17273   }
17274
17275   bool result() { return result_; }
17276
17277  private:
17278   TestCase testCase_;
17279   bool result_;
17280 };
17281
17282
17283 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
17284   InitDefaultIsolateThread thread(testCase);
17285   thread.Start();
17286   thread.Join();
17287   CHECK_EQ(thread.result(), true);
17288 }
17289
17290
17291 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
17292   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
17293 }
17294
17295
17296 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
17297   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
17298 }
17299
17300
17301 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
17302   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
17303 }
17304
17305
17306 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
17307   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
17308 }
17309
17310
17311 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
17312   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
17313 }
17314
17315
17316 TEST(StringCheckMultipleContexts) {
17317   const char* code =
17318       "(function() { return \"a\".charAt(0); })()";
17319
17320   {
17321     // Run the code twice in the first context to initialize the call IC.
17322     LocalContext context1;
17323     v8::HandleScope scope(context1->GetIsolate());
17324     ExpectString(code, "a");
17325     ExpectString(code, "a");
17326   }
17327
17328   {
17329     // Change the String.prototype in the second context and check
17330     // that the right function gets called.
17331     LocalContext context2;
17332     v8::HandleScope scope(context2->GetIsolate());
17333     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
17334     ExpectString(code, "not a");
17335   }
17336 }
17337
17338
17339 TEST(NumberCheckMultipleContexts) {
17340   const char* code =
17341       "(function() { return (42).toString(); })()";
17342
17343   {
17344     // Run the code twice in the first context to initialize the call IC.
17345     LocalContext context1;
17346     v8::HandleScope scope(context1->GetIsolate());
17347     ExpectString(code, "42");
17348     ExpectString(code, "42");
17349   }
17350
17351   {
17352     // Change the Number.prototype in the second context and check
17353     // that the right function gets called.
17354     LocalContext context2;
17355     v8::HandleScope scope(context2->GetIsolate());
17356     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
17357     ExpectString(code, "not 42");
17358   }
17359 }
17360
17361
17362 TEST(BooleanCheckMultipleContexts) {
17363   const char* code =
17364       "(function() { return true.toString(); })()";
17365
17366   {
17367     // Run the code twice in the first context to initialize the call IC.
17368     LocalContext context1;
17369     v8::HandleScope scope(context1->GetIsolate());
17370     ExpectString(code, "true");
17371     ExpectString(code, "true");
17372   }
17373
17374   {
17375     // Change the Boolean.prototype in the second context and check
17376     // that the right function gets called.
17377     LocalContext context2;
17378     v8::HandleScope scope(context2->GetIsolate());
17379     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
17380     ExpectString(code, "");
17381   }
17382 }
17383
17384
17385 TEST(DontDeleteCellLoadIC) {
17386   const char* function_code =
17387       "function readCell() { while (true) { return cell; } }";
17388
17389   {
17390     // Run the code twice in the first context to initialize the load
17391     // IC for a don't delete cell.
17392     LocalContext context1;
17393     v8::HandleScope scope(context1->GetIsolate());
17394     CompileRun("var cell = \"first\";");
17395     ExpectBoolean("delete cell", false);
17396     CompileRun(function_code);
17397     ExpectString("readCell()", "first");
17398     ExpectString("readCell()", "first");
17399   }
17400
17401   {
17402     // Use a deletable cell in the second context.
17403     LocalContext context2;
17404     v8::HandleScope scope(context2->GetIsolate());
17405     CompileRun("cell = \"second\";");
17406     CompileRun(function_code);
17407     ExpectString("readCell()", "second");
17408     ExpectBoolean("delete cell", true);
17409     ExpectString("(function() {"
17410                  "  try {"
17411                  "    return readCell();"
17412                  "  } catch(e) {"
17413                  "    return e.toString();"
17414                  "  }"
17415                  "})()",
17416                  "ReferenceError: cell is not defined");
17417     CompileRun("cell = \"new_second\";");
17418     CcTest::heap()->CollectAllGarbage();
17419     ExpectString("readCell()", "new_second");
17420     ExpectString("readCell()", "new_second");
17421   }
17422 }
17423
17424
17425 class Visitor42 : public v8::PersistentHandleVisitor {
17426  public:
17427   explicit Visitor42(v8::Persistent<v8::Object>* object)
17428       : counter_(0), object_(object) { }
17429
17430   virtual void VisitPersistentHandle(Persistent<Value>* value,
17431                                      uint16_t class_id) {
17432     if (class_id != 42) return;
17433     CHECK_EQ(42, value->WrapperClassId());
17434     v8::Isolate* isolate = CcTest::isolate();
17435     v8::HandleScope handle_scope(isolate);
17436     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
17437     v8::Handle<v8::Value> object =
17438         v8::Local<v8::Object>::New(isolate, *object_);
17439     CHECK(handle->IsObject());
17440     CHECK(Handle<Object>::Cast(handle)->Equals(object));
17441     ++counter_;
17442   }
17443
17444   int counter_;
17445   v8::Persistent<v8::Object>* object_;
17446 };
17447
17448
17449 TEST(PersistentHandleVisitor) {
17450   LocalContext context;
17451   v8::Isolate* isolate = context->GetIsolate();
17452   v8::HandleScope scope(isolate);
17453   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17454   CHECK_EQ(0, object.WrapperClassId());
17455   object.SetWrapperClassId(42);
17456   CHECK_EQ(42, object.WrapperClassId());
17457
17458   Visitor42 visitor(&object);
17459   v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
17460   CHECK_EQ(1, visitor.counter_);
17461
17462   object.Reset();
17463 }
17464
17465
17466 TEST(WrapperClassId) {
17467   LocalContext context;
17468   v8::Isolate* isolate = context->GetIsolate();
17469   v8::HandleScope scope(isolate);
17470   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17471   CHECK_EQ(0, object.WrapperClassId());
17472   object.SetWrapperClassId(65535);
17473   CHECK_EQ(65535, object.WrapperClassId());
17474   object.Reset();
17475 }
17476
17477
17478 TEST(PersistentHandleInNewSpaceVisitor) {
17479   LocalContext context;
17480   v8::Isolate* isolate = context->GetIsolate();
17481   v8::HandleScope scope(isolate);
17482   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
17483   CHECK_EQ(0, object1.WrapperClassId());
17484   object1.SetWrapperClassId(42);
17485   CHECK_EQ(42, object1.WrapperClassId());
17486
17487   CcTest::heap()->CollectAllGarbage();
17488   CcTest::heap()->CollectAllGarbage();
17489
17490   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
17491   CHECK_EQ(0, object2.WrapperClassId());
17492   object2.SetWrapperClassId(42);
17493   CHECK_EQ(42, object2.WrapperClassId());
17494
17495   Visitor42 visitor(&object2);
17496   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
17497   CHECK_EQ(1, visitor.counter_);
17498
17499   object1.Reset();
17500   object2.Reset();
17501 }
17502
17503
17504 TEST(RegExp) {
17505   LocalContext context;
17506   v8::HandleScope scope(context->GetIsolate());
17507
17508   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
17509   CHECK(re->IsRegExp());
17510   CHECK(re->GetSource()->Equals(v8_str("foo")));
17511   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17512
17513   re = v8::RegExp::New(v8_str("bar"),
17514                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17515                                                       v8::RegExp::kGlobal));
17516   CHECK(re->IsRegExp());
17517   CHECK(re->GetSource()->Equals(v8_str("bar")));
17518   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
17519            static_cast<int>(re->GetFlags()));
17520
17521   re = v8::RegExp::New(v8_str("baz"),
17522                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17523                                                       v8::RegExp::kMultiline));
17524   CHECK(re->IsRegExp());
17525   CHECK(re->GetSource()->Equals(v8_str("baz")));
17526   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
17527            static_cast<int>(re->GetFlags()));
17528
17529   re = CompileRun("/quux/").As<v8::RegExp>();
17530   CHECK(re->IsRegExp());
17531   CHECK(re->GetSource()->Equals(v8_str("quux")));
17532   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17533
17534   re = CompileRun("/quux/gm").As<v8::RegExp>();
17535   CHECK(re->IsRegExp());
17536   CHECK(re->GetSource()->Equals(v8_str("quux")));
17537   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
17538            static_cast<int>(re->GetFlags()));
17539
17540   // Override the RegExp constructor and check the API constructor
17541   // still works.
17542   CompileRun("RegExp = function() {}");
17543
17544   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
17545   CHECK(re->IsRegExp());
17546   CHECK(re->GetSource()->Equals(v8_str("foobar")));
17547   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17548
17549   re = v8::RegExp::New(v8_str("foobarbaz"),
17550                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17551                                                       v8::RegExp::kMultiline));
17552   CHECK(re->IsRegExp());
17553   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
17554   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
17555            static_cast<int>(re->GetFlags()));
17556
17557   context->Global()->Set(v8_str("re"), re);
17558   ExpectTrue("re.test('FoobarbaZ')");
17559
17560   // RegExps are objects on which you can set properties.
17561   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
17562   v8::Handle<v8::Value> value(CompileRun("re.property"));
17563   CHECK_EQ(32, value->Int32Value());
17564
17565   v8::TryCatch try_catch(context->GetIsolate());
17566   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
17567   CHECK(re.IsEmpty());
17568   CHECK(try_catch.HasCaught());
17569   context->Global()->Set(v8_str("ex"), try_catch.Exception());
17570   ExpectTrue("ex instanceof SyntaxError");
17571 }
17572
17573
17574 THREADED_TEST(Equals) {
17575   LocalContext localContext;
17576   v8::HandleScope handleScope(localContext->GetIsolate());
17577
17578   v8::Handle<v8::Object> globalProxy = localContext->Global();
17579   v8::Handle<Value> global = globalProxy->GetPrototype();
17580
17581   CHECK(global->StrictEquals(global));
17582   CHECK(!global->StrictEquals(globalProxy));
17583   CHECK(!globalProxy->StrictEquals(global));
17584   CHECK(globalProxy->StrictEquals(globalProxy));
17585
17586   CHECK(global->Equals(global));
17587   CHECK(!global->Equals(globalProxy));
17588   CHECK(!globalProxy->Equals(global));
17589   CHECK(globalProxy->Equals(globalProxy));
17590 }
17591
17592
17593 static void Getter(v8::Local<v8::Name> property,
17594                    const v8::PropertyCallbackInfo<v8::Value>& info) {
17595   info.GetReturnValue().Set(v8_str("42!"));
17596 }
17597
17598
17599 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
17600   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
17601   result->Set(0, v8_str("universalAnswer"));
17602   info.GetReturnValue().Set(result);
17603 }
17604
17605
17606 TEST(NamedEnumeratorAndForIn) {
17607   LocalContext context;
17608   v8::Isolate* isolate = context->GetIsolate();
17609   v8::HandleScope handle_scope(isolate);
17610   v8::Context::Scope context_scope(context.local());
17611
17612   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
17613   tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
17614                                                          NULL, Enumerator));
17615   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
17616   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
17617         "var result = []; for (var k in o) result.push(k); result"));
17618   CHECK_EQ(1u, result->Length());
17619   CHECK(v8_str("universalAnswer")->Equals(result->Get(0)));
17620 }
17621
17622
17623 TEST(DefinePropertyPostDetach) {
17624   LocalContext context;
17625   v8::HandleScope scope(context->GetIsolate());
17626   v8::Handle<v8::Object> proxy = context->Global();
17627   v8::Handle<v8::Function> define_property =
17628       CompileRun("(function() {"
17629                  "  Object.defineProperty("
17630                  "    this,"
17631                  "    1,"
17632                  "    { configurable: true, enumerable: true, value: 3 });"
17633                  "})").As<Function>();
17634   context->DetachGlobal();
17635   define_property->Call(proxy, 0, NULL);
17636 }
17637
17638
17639 static void InstallContextId(v8::Handle<Context> context, int id) {
17640   Context::Scope scope(context);
17641   CompileRun("Object.prototype").As<Object>()->
17642       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
17643 }
17644
17645
17646 static void CheckContextId(v8::Handle<Object> object, int expected) {
17647   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
17648 }
17649
17650
17651 THREADED_TEST(CreationContext) {
17652   v8::Isolate* isolate = CcTest::isolate();
17653   HandleScope handle_scope(isolate);
17654   Handle<Context> context1 = Context::New(isolate);
17655   InstallContextId(context1, 1);
17656   Handle<Context> context2 = Context::New(isolate);
17657   InstallContextId(context2, 2);
17658   Handle<Context> context3 = Context::New(isolate);
17659   InstallContextId(context3, 3);
17660
17661   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
17662
17663   Local<Object> object1;
17664   Local<Function> func1;
17665   {
17666     Context::Scope scope(context1);
17667     object1 = Object::New(isolate);
17668     func1 = tmpl->GetFunction();
17669   }
17670
17671   Local<Object> object2;
17672   Local<Function> func2;
17673   {
17674     Context::Scope scope(context2);
17675     object2 = Object::New(isolate);
17676     func2 = tmpl->GetFunction();
17677   }
17678
17679   Local<Object> instance1;
17680   Local<Object> instance2;
17681
17682   {
17683     Context::Scope scope(context3);
17684     instance1 = func1->NewInstance();
17685     instance2 = func2->NewInstance();
17686   }
17687
17688   {
17689     Handle<Context> other_context = Context::New(isolate);
17690     Context::Scope scope(other_context);
17691     CHECK(object1->CreationContext() == context1);
17692     CheckContextId(object1, 1);
17693     CHECK(func1->CreationContext() == context1);
17694     CheckContextId(func1, 1);
17695     CHECK(instance1->CreationContext() == context1);
17696     CheckContextId(instance1, 1);
17697     CHECK(object2->CreationContext() == context2);
17698     CheckContextId(object2, 2);
17699     CHECK(func2->CreationContext() == context2);
17700     CheckContextId(func2, 2);
17701     CHECK(instance2->CreationContext() == context2);
17702     CheckContextId(instance2, 2);
17703   }
17704
17705   {
17706     Context::Scope scope(context1);
17707     CHECK(object1->CreationContext() == context1);
17708     CheckContextId(object1, 1);
17709     CHECK(func1->CreationContext() == context1);
17710     CheckContextId(func1, 1);
17711     CHECK(instance1->CreationContext() == context1);
17712     CheckContextId(instance1, 1);
17713     CHECK(object2->CreationContext() == context2);
17714     CheckContextId(object2, 2);
17715     CHECK(func2->CreationContext() == context2);
17716     CheckContextId(func2, 2);
17717     CHECK(instance2->CreationContext() == context2);
17718     CheckContextId(instance2, 2);
17719   }
17720
17721   {
17722     Context::Scope scope(context2);
17723     CHECK(object1->CreationContext() == context1);
17724     CheckContextId(object1, 1);
17725     CHECK(func1->CreationContext() == context1);
17726     CheckContextId(func1, 1);
17727     CHECK(instance1->CreationContext() == context1);
17728     CheckContextId(instance1, 1);
17729     CHECK(object2->CreationContext() == context2);
17730     CheckContextId(object2, 2);
17731     CHECK(func2->CreationContext() == context2);
17732     CheckContextId(func2, 2);
17733     CHECK(instance2->CreationContext() == context2);
17734     CheckContextId(instance2, 2);
17735   }
17736 }
17737
17738
17739 THREADED_TEST(CreationContextOfJsFunction) {
17740   HandleScope handle_scope(CcTest::isolate());
17741   Handle<Context> context = Context::New(CcTest::isolate());
17742   InstallContextId(context, 1);
17743
17744   Local<Object> function;
17745   {
17746     Context::Scope scope(context);
17747     function = CompileRun("function foo() {}; foo").As<Object>();
17748   }
17749
17750   Handle<Context> other_context = Context::New(CcTest::isolate());
17751   Context::Scope scope(other_context);
17752   CHECK(function->CreationContext() == context);
17753   CheckContextId(function, 1);
17754 }
17755
17756
17757 void HasOwnPropertyIndexedPropertyGetter(
17758     uint32_t index,
17759     const v8::PropertyCallbackInfo<v8::Value>& info) {
17760   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
17761 }
17762
17763
17764 void HasOwnPropertyNamedPropertyGetter(
17765     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
17766   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
17767 }
17768
17769
17770 void HasOwnPropertyIndexedPropertyQuery(
17771     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17772   if (index == 42) info.GetReturnValue().Set(1);
17773 }
17774
17775
17776 void HasOwnPropertyNamedPropertyQuery(
17777     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17778   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
17779 }
17780
17781
17782 void HasOwnPropertyNamedPropertyQuery2(
17783     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17784   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
17785 }
17786
17787
17788 void HasOwnPropertyAccessorGetter(
17789     Local<String> property,
17790     const v8::PropertyCallbackInfo<v8::Value>& info) {
17791   info.GetReturnValue().Set(v8_str("yes"));
17792 }
17793
17794
17795 TEST(HasOwnProperty) {
17796   LocalContext env;
17797   v8::Isolate* isolate = env->GetIsolate();
17798   v8::HandleScope scope(isolate);
17799   { // Check normal properties and defined getters.
17800     Handle<Value> value = CompileRun(
17801         "function Foo() {"
17802         "    this.foo = 11;"
17803         "    this.__defineGetter__('baz', function() { return 1; });"
17804         "};"
17805         "function Bar() { "
17806         "    this.bar = 13;"
17807         "    this.__defineGetter__('bla', function() { return 2; });"
17808         "};"
17809         "Bar.prototype = new Foo();"
17810         "new Bar();");
17811     CHECK(value->IsObject());
17812     Handle<Object> object = value->ToObject(isolate);
17813     CHECK(object->Has(v8_str("foo")));
17814     CHECK(!object->HasOwnProperty(v8_str("foo")));
17815     CHECK(object->HasOwnProperty(v8_str("bar")));
17816     CHECK(object->Has(v8_str("baz")));
17817     CHECK(!object->HasOwnProperty(v8_str("baz")));
17818     CHECK(object->HasOwnProperty(v8_str("bla")));
17819   }
17820   { // Check named getter interceptors.
17821     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17822     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17823         HasOwnPropertyNamedPropertyGetter));
17824     Handle<Object> instance = templ->NewInstance();
17825     CHECK(!instance->HasOwnProperty(v8_str("42")));
17826     CHECK(instance->HasOwnProperty(v8_str("foo")));
17827     CHECK(!instance->HasOwnProperty(v8_str("bar")));
17828   }
17829   { // Check indexed getter interceptors.
17830     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17831     templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17832         HasOwnPropertyIndexedPropertyGetter));
17833     Handle<Object> instance = templ->NewInstance();
17834     CHECK(instance->HasOwnProperty(v8_str("42")));
17835     CHECK(!instance->HasOwnProperty(v8_str("43")));
17836     CHECK(!instance->HasOwnProperty(v8_str("foo")));
17837   }
17838   { // Check named query interceptors.
17839     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17840     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17841         0, 0, HasOwnPropertyNamedPropertyQuery));
17842     Handle<Object> instance = templ->NewInstance();
17843     CHECK(instance->HasOwnProperty(v8_str("foo")));
17844     CHECK(!instance->HasOwnProperty(v8_str("bar")));
17845   }
17846   { // Check indexed query interceptors.
17847     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17848     templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17849         0, 0, HasOwnPropertyIndexedPropertyQuery));
17850     Handle<Object> instance = templ->NewInstance();
17851     CHECK(instance->HasOwnProperty(v8_str("42")));
17852     CHECK(!instance->HasOwnProperty(v8_str("41")));
17853   }
17854   { // Check callbacks.
17855     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17856     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
17857     Handle<Object> instance = templ->NewInstance();
17858     CHECK(instance->HasOwnProperty(v8_str("foo")));
17859     CHECK(!instance->HasOwnProperty(v8_str("bar")));
17860   }
17861   { // Check that query wins on disagreement.
17862     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17863     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17864         HasOwnPropertyNamedPropertyGetter, 0,
17865         HasOwnPropertyNamedPropertyQuery2));
17866     Handle<Object> instance = templ->NewInstance();
17867     CHECK(!instance->HasOwnProperty(v8_str("foo")));
17868     CHECK(instance->HasOwnProperty(v8_str("bar")));
17869   }
17870 }
17871
17872
17873 TEST(IndexedInterceptorWithStringProto) {
17874   v8::Isolate* isolate = CcTest::isolate();
17875   v8::HandleScope scope(isolate);
17876   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17877   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17878       NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
17879   LocalContext context;
17880   context->Global()->Set(v8_str("obj"), templ->NewInstance());
17881   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
17882   // These should be intercepted.
17883   CHECK(CompileRun("42 in obj")->BooleanValue());
17884   CHECK(CompileRun("'42' in obj")->BooleanValue());
17885   // These should fall through to the String prototype.
17886   CHECK(CompileRun("0 in obj")->BooleanValue());
17887   CHECK(CompileRun("'0' in obj")->BooleanValue());
17888   // And these should both fail.
17889   CHECK(!CompileRun("32 in obj")->BooleanValue());
17890   CHECK(!CompileRun("'32' in obj")->BooleanValue());
17891 }
17892
17893
17894 void CheckCodeGenerationAllowed() {
17895   Handle<Value> result = CompileRun("eval('42')");
17896   CHECK_EQ(42, result->Int32Value());
17897   result = CompileRun("(function(e) { return e('42'); })(eval)");
17898   CHECK_EQ(42, result->Int32Value());
17899   result = CompileRun("var f = new Function('return 42'); f()");
17900   CHECK_EQ(42, result->Int32Value());
17901 }
17902
17903
17904 void CheckCodeGenerationDisallowed() {
17905   TryCatch try_catch(CcTest::isolate());
17906
17907   Handle<Value> result = CompileRun("eval('42')");
17908   CHECK(result.IsEmpty());
17909   CHECK(try_catch.HasCaught());
17910   try_catch.Reset();
17911
17912   result = CompileRun("(function(e) { return e('42'); })(eval)");
17913   CHECK(result.IsEmpty());
17914   CHECK(try_catch.HasCaught());
17915   try_catch.Reset();
17916
17917   result = CompileRun("var f = new Function('return 42'); f()");
17918   CHECK(result.IsEmpty());
17919   CHECK(try_catch.HasCaught());
17920 }
17921
17922
17923 bool CodeGenerationAllowed(Local<Context> context) {
17924   ApiTestFuzzer::Fuzz();
17925   return true;
17926 }
17927
17928
17929 bool CodeGenerationDisallowed(Local<Context> context) {
17930   ApiTestFuzzer::Fuzz();
17931   return false;
17932 }
17933
17934
17935 THREADED_TEST(AllowCodeGenFromStrings) {
17936   LocalContext context;
17937   v8::HandleScope scope(context->GetIsolate());
17938
17939   // eval and the Function constructor allowed by default.
17940   CHECK(context->IsCodeGenerationFromStringsAllowed());
17941   CheckCodeGenerationAllowed();
17942
17943   // Disallow eval and the Function constructor.
17944   context->AllowCodeGenerationFromStrings(false);
17945   CHECK(!context->IsCodeGenerationFromStringsAllowed());
17946   CheckCodeGenerationDisallowed();
17947
17948   // Allow again.
17949   context->AllowCodeGenerationFromStrings(true);
17950   CheckCodeGenerationAllowed();
17951
17952   // Disallow but setting a global callback that will allow the calls.
17953   context->AllowCodeGenerationFromStrings(false);
17954   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
17955   CHECK(!context->IsCodeGenerationFromStringsAllowed());
17956   CheckCodeGenerationAllowed();
17957
17958   // Set a callback that disallows the code generation.
17959   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17960   CHECK(!context->IsCodeGenerationFromStringsAllowed());
17961   CheckCodeGenerationDisallowed();
17962 }
17963
17964
17965 TEST(SetErrorMessageForCodeGenFromStrings) {
17966   LocalContext context;
17967   v8::HandleScope scope(context->GetIsolate());
17968   TryCatch try_catch(context->GetIsolate());
17969
17970   Handle<String> message = v8_str("Message") ;
17971   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
17972   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17973   context->AllowCodeGenerationFromStrings(false);
17974   context->SetErrorMessageForCodeGenerationFromStrings(message);
17975   Handle<Value> result = CompileRun("eval('42')");
17976   CHECK(result.IsEmpty());
17977   CHECK(try_catch.HasCaught());
17978   Handle<String> actual_message = try_catch.Message()->Get();
17979   CHECK(expected_message->Equals(actual_message));
17980 }
17981
17982
17983 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
17984 }
17985
17986
17987 THREADED_TEST(CallAPIFunctionOnNonObject) {
17988   LocalContext context;
17989   v8::Isolate* isolate = context->GetIsolate();
17990   v8::HandleScope scope(isolate);
17991   Handle<FunctionTemplate> templ =
17992       v8::FunctionTemplate::New(isolate, NonObjectThis);
17993   Handle<Function> function = templ->GetFunction();
17994   context->Global()->Set(v8_str("f"), function);
17995   TryCatch try_catch(isolate);
17996   CompileRun("f.call(2)");
17997 }
17998
17999
18000 // Regression test for issue 1470.
18001 THREADED_TEST(ReadOnlyIndexedProperties) {
18002   v8::Isolate* isolate = CcTest::isolate();
18003   v8::HandleScope scope(isolate);
18004   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18005
18006   LocalContext context;
18007   Local<v8::Object> obj = templ->NewInstance();
18008   context->Global()->Set(v8_str("obj"), obj);
18009   obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18010   obj->Set(v8_str("1"), v8_str("foobar"));
18011   CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("1"))));
18012   obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18013   obj->Set(v8_num(2), v8_str("foobar"));
18014   CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_num(2))));
18015
18016   // Test non-smi case.
18017   obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18018   obj->Set(v8_str("2000000000"), v8_str("foobar"));
18019   CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("2000000000"))));
18020 }
18021
18022
18023 static int CountLiveMapsInMapCache(i::Context* context) {
18024   i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
18025   int length = map_cache->length();
18026   int count = 0;
18027   for (int i = 0; i < length; i++) {
18028     i::Object* value = map_cache->get(i);
18029     if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
18030   }
18031   return count;
18032 }
18033
18034
18035 THREADED_TEST(Regress1516) {
18036   LocalContext context;
18037   v8::HandleScope scope(context->GetIsolate());
18038
18039   // Object with 20 properties is not a common case, so it should be removed
18040   // from the cache after GC.
18041   { v8::HandleScope temp_scope(context->GetIsolate());
18042     CompileRun(
18043         "({"
18044         "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
18045         "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
18046         "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
18047         "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
18048         "})");
18049   }
18050
18051   int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
18052   CHECK_LE(1, elements);
18053
18054   CcTest::heap()->CollectAllGarbage();
18055
18056   CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
18057 }
18058
18059
18060 THREADED_TEST(Regress93759) {
18061   v8::Isolate* isolate = CcTest::isolate();
18062   HandleScope scope(isolate);
18063
18064   // Template for object with security check.
18065   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
18066   no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
18067
18068   // Templates for objects with hidden prototypes and possibly security check.
18069   Local<FunctionTemplate> hidden_proto_template =
18070       v8::FunctionTemplate::New(isolate);
18071   hidden_proto_template->SetHiddenPrototype(true);
18072
18073   Local<FunctionTemplate> protected_hidden_proto_template =
18074       v8::FunctionTemplate::New(isolate);
18075   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18076       AccessAlwaysBlocked, NULL);
18077   protected_hidden_proto_template->SetHiddenPrototype(true);
18078
18079   // Context for "foreign" objects used in test.
18080   Local<Context> context = v8::Context::New(isolate);
18081   context->Enter();
18082
18083   // Plain object, no security check.
18084   Local<Object> simple_object = Object::New(isolate);
18085
18086   // Object with explicit security check.
18087   Local<Object> protected_object = no_proto_template->NewInstance();
18088
18089   // JSGlobalProxy object, always have security check.
18090   Local<Object> proxy_object = context->Global();
18091
18092   // Global object, the  prototype of proxy_object. No security checks.
18093   Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
18094
18095   // Hidden prototype without security check.
18096   Local<Object> hidden_prototype =
18097       hidden_proto_template->GetFunction()->NewInstance();
18098   Local<Object> object_with_hidden =
18099     Object::New(isolate);
18100   object_with_hidden->SetPrototype(hidden_prototype);
18101
18102   // Hidden prototype with security check on the hidden prototype.
18103   Local<Object> protected_hidden_prototype =
18104       protected_hidden_proto_template->GetFunction()->NewInstance();
18105   Local<Object> object_with_protected_hidden =
18106     Object::New(isolate);
18107   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18108
18109   context->Exit();
18110
18111   // Template for object for second context. Values to test are put on it as
18112   // properties.
18113   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
18114   global_template->Set(v8_str("simple"), simple_object);
18115   global_template->Set(v8_str("protected"), protected_object);
18116   global_template->Set(v8_str("global"), global_object);
18117   global_template->Set(v8_str("proxy"), proxy_object);
18118   global_template->Set(v8_str("hidden"), object_with_hidden);
18119   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18120
18121   LocalContext context2(NULL, global_template);
18122
18123   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18124   CHECK(result1->Equals(simple_object->GetPrototype()));
18125
18126   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18127   CHECK(result2.IsEmpty());
18128
18129   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18130   CHECK(result3->Equals(global_object->GetPrototype()));
18131
18132   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18133   CHECK(result4.IsEmpty());
18134
18135   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18136   CHECK(result5->Equals(
18137       object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
18138
18139   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18140   CHECK(result6.IsEmpty());
18141 }
18142
18143
18144 static void TestReceiver(Local<Value> expected_result,
18145                          Local<Value> expected_receiver,
18146                          const char* code) {
18147   Local<Value> result = CompileRun(code);
18148   CHECK(result->IsObject());
18149   CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
18150   CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
18151 }
18152
18153
18154 THREADED_TEST(ForeignFunctionReceiver) {
18155   v8::Isolate* isolate = CcTest::isolate();
18156   HandleScope scope(isolate);
18157
18158   // Create two contexts with different "id" properties ('i' and 'o').
18159   // Call a function both from its own context and from a the foreign
18160   // context, and see what "this" is bound to (returning both "this"
18161   // and "this.id" for comparison).
18162
18163   Local<Context> foreign_context = v8::Context::New(isolate);
18164   foreign_context->Enter();
18165   Local<Value> foreign_function =
18166     CompileRun("function func() { return { 0: this.id, "
18167                "                           1: this, "
18168                "                           toString: function() { "
18169                "                               return this[0];"
18170                "                           }"
18171                "                         };"
18172                "}"
18173                "var id = 'i';"
18174                "func;");
18175   CHECK(foreign_function->IsFunction());
18176   foreign_context->Exit();
18177
18178   LocalContext context;
18179
18180   Local<String> password = v8_str("Password");
18181   // Don't get hit by security checks when accessing foreign_context's
18182   // global receiver (aka. global proxy).
18183   context->SetSecurityToken(password);
18184   foreign_context->SetSecurityToken(password);
18185
18186   Local<String> i = v8_str("i");
18187   Local<String> o = v8_str("o");
18188   Local<String> id = v8_str("id");
18189
18190   CompileRun("function ownfunc() { return { 0: this.id, "
18191              "                              1: this, "
18192              "                              toString: function() { "
18193              "                                  return this[0];"
18194              "                              }"
18195              "                             };"
18196              "}"
18197              "var id = 'o';"
18198              "ownfunc");
18199   context->Global()->Set(v8_str("func"), foreign_function);
18200
18201   // Sanity check the contexts.
18202   CHECK(i->Equals(foreign_context->Global()->Get(id)));
18203   CHECK(o->Equals(context->Global()->Get(id)));
18204
18205   // Checking local function's receiver.
18206   // Calling function using its call/apply methods.
18207   TestReceiver(o, context->Global(), "ownfunc.call()");
18208   TestReceiver(o, context->Global(), "ownfunc.apply()");
18209   // Making calls through built-in functions.
18210   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
18211   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
18212   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
18213   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
18214   // Calling with environment record as base.
18215   TestReceiver(o, context->Global(), "ownfunc()");
18216   // Calling with no base.
18217   TestReceiver(o, context->Global(), "(1,ownfunc)()");
18218
18219   // Checking foreign function return value.
18220   // Calling function using its call/apply methods.
18221   TestReceiver(i, foreign_context->Global(), "func.call()");
18222   TestReceiver(i, foreign_context->Global(), "func.apply()");
18223   // Calling function using another context's call/apply methods.
18224   TestReceiver(i, foreign_context->Global(),
18225                "Function.prototype.call.call(func)");
18226   TestReceiver(i, foreign_context->Global(),
18227                "Function.prototype.call.apply(func)");
18228   TestReceiver(i, foreign_context->Global(),
18229                "Function.prototype.apply.call(func)");
18230   TestReceiver(i, foreign_context->Global(),
18231                "Function.prototype.apply.apply(func)");
18232   // Making calls through built-in functions.
18233   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
18234   // ToString(func()) is func()[0], i.e., the returned this.id.
18235   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
18236   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
18237   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
18238
18239   // Calling with environment record as base.
18240   TestReceiver(i, foreign_context->Global(), "func()");
18241   // Calling with no base.
18242   TestReceiver(i, foreign_context->Global(), "(1,func)()");
18243 }
18244
18245
18246 uint8_t callback_fired = 0;
18247
18248
18249 void CallCompletedCallback1() {
18250   v8::base::OS::Print("Firing callback 1.\n");
18251   callback_fired ^= 1;  // Toggle first bit.
18252 }
18253
18254
18255 void CallCompletedCallback2() {
18256   v8::base::OS::Print("Firing callback 2.\n");
18257   callback_fired ^= 2;  // Toggle second bit.
18258 }
18259
18260
18261 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
18262   int32_t level = args[0]->Int32Value();
18263   if (level < 3) {
18264     level++;
18265     v8::base::OS::Print("Entering recursion level %d.\n", level);
18266     char script[64];
18267     i::Vector<char> script_vector(script, sizeof(script));
18268     i::SNPrintF(script_vector, "recursion(%d)", level);
18269     CompileRun(script_vector.start());
18270     v8::base::OS::Print("Leaving recursion level %d.\n", level);
18271     CHECK_EQ(0, callback_fired);
18272   } else {
18273     v8::base::OS::Print("Recursion ends.\n");
18274     CHECK_EQ(0, callback_fired);
18275   }
18276 }
18277
18278
18279 TEST(CallCompletedCallback) {
18280   LocalContext env;
18281   v8::HandleScope scope(env->GetIsolate());
18282   v8::Handle<v8::FunctionTemplate> recursive_runtime =
18283       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
18284   env->Global()->Set(v8_str("recursion"),
18285                      recursive_runtime->GetFunction());
18286   // Adding the same callback a second time has no effect.
18287   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18288   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18289   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
18290   v8::base::OS::Print("--- Script (1) ---\n");
18291   Local<Script> script = v8::Script::Compile(
18292       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
18293   script->Run();
18294   CHECK_EQ(3, callback_fired);
18295
18296   v8::base::OS::Print("\n--- Script (2) ---\n");
18297   callback_fired = 0;
18298   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
18299   script->Run();
18300   CHECK_EQ(2, callback_fired);
18301
18302   v8::base::OS::Print("\n--- Function ---\n");
18303   callback_fired = 0;
18304   Local<Function> recursive_function =
18305       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
18306   v8::Handle<Value> args[] = { v8_num(0) };
18307   recursive_function->Call(env->Global(), 1, args);
18308   CHECK_EQ(2, callback_fired);
18309 }
18310
18311
18312 void CallCompletedCallbackNoException() {
18313   v8::HandleScope scope(CcTest::isolate());
18314   CompileRun("1+1;");
18315 }
18316
18317
18318 void CallCompletedCallbackException() {
18319   v8::HandleScope scope(CcTest::isolate());
18320   CompileRun("throw 'second exception';");
18321 }
18322
18323
18324 TEST(CallCompletedCallbackOneException) {
18325   LocalContext env;
18326   v8::HandleScope scope(env->GetIsolate());
18327   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
18328   CompileRun("throw 'exception';");
18329 }
18330
18331
18332 TEST(CallCompletedCallbackTwoExceptions) {
18333   LocalContext env;
18334   v8::HandleScope scope(env->GetIsolate());
18335   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
18336   CompileRun("throw 'first exception';");
18337 }
18338
18339
18340 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
18341   v8::HandleScope scope(info.GetIsolate());
18342   CompileRun("ext1Calls++;");
18343 }
18344
18345
18346 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
18347   v8::HandleScope scope(info.GetIsolate());
18348   CompileRun("ext2Calls++;");
18349 }
18350
18351
18352 void* g_passed_to_three = NULL;
18353
18354
18355 static void MicrotaskThree(void* data) {
18356   g_passed_to_three = data;
18357 }
18358
18359
18360 TEST(EnqueueMicrotask) {
18361   LocalContext env;
18362   v8::HandleScope scope(env->GetIsolate());
18363   CompileRun(
18364       "var ext1Calls = 0;"
18365       "var ext2Calls = 0;");
18366   CompileRun("1+1;");
18367   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18368   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18369
18370   env->GetIsolate()->EnqueueMicrotask(
18371       Function::New(env->GetIsolate(), MicrotaskOne));
18372   CompileRun("1+1;");
18373   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18374   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18375
18376   env->GetIsolate()->EnqueueMicrotask(
18377       Function::New(env->GetIsolate(), MicrotaskOne));
18378   env->GetIsolate()->EnqueueMicrotask(
18379       Function::New(env->GetIsolate(), MicrotaskTwo));
18380   CompileRun("1+1;");
18381   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18382   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18383
18384   env->GetIsolate()->EnqueueMicrotask(
18385       Function::New(env->GetIsolate(), MicrotaskTwo));
18386   CompileRun("1+1;");
18387   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18388   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18389
18390   CompileRun("1+1;");
18391   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18392   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18393
18394   g_passed_to_three = NULL;
18395   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
18396   CompileRun("1+1;");
18397   CHECK(!g_passed_to_three);
18398   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18399   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18400
18401   int dummy;
18402   env->GetIsolate()->EnqueueMicrotask(
18403       Function::New(env->GetIsolate(), MicrotaskOne));
18404   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
18405   env->GetIsolate()->EnqueueMicrotask(
18406       Function::New(env->GetIsolate(), MicrotaskTwo));
18407   CompileRun("1+1;");
18408   CHECK_EQ(&dummy, g_passed_to_three);
18409   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
18410   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18411   g_passed_to_three = NULL;
18412 }
18413
18414
18415 static void MicrotaskExceptionOne(
18416     const v8::FunctionCallbackInfo<Value>& info) {
18417   v8::HandleScope scope(info.GetIsolate());
18418   CompileRun("exception1Calls++;");
18419   info.GetIsolate()->ThrowException(
18420       v8::Exception::Error(v8_str("first")));
18421 }
18422
18423
18424 static void MicrotaskExceptionTwo(
18425     const v8::FunctionCallbackInfo<Value>& info) {
18426   v8::HandleScope scope(info.GetIsolate());
18427   CompileRun("exception2Calls++;");
18428   info.GetIsolate()->ThrowException(
18429       v8::Exception::Error(v8_str("second")));
18430 }
18431
18432
18433 TEST(RunMicrotasksIgnoresThrownExceptions) {
18434   LocalContext env;
18435   v8::Isolate* isolate = env->GetIsolate();
18436   v8::HandleScope scope(isolate);
18437   CompileRun(
18438       "var exception1Calls = 0;"
18439       "var exception2Calls = 0;");
18440   isolate->EnqueueMicrotask(
18441       Function::New(isolate, MicrotaskExceptionOne));
18442   isolate->EnqueueMicrotask(
18443       Function::New(isolate, MicrotaskExceptionTwo));
18444   TryCatch try_catch(isolate);
18445   CompileRun("1+1;");
18446   CHECK(!try_catch.HasCaught());
18447   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
18448   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
18449 }
18450
18451
18452 TEST(SetAutorunMicrotasks) {
18453   LocalContext env;
18454   v8::HandleScope scope(env->GetIsolate());
18455   CompileRun(
18456       "var ext1Calls = 0;"
18457       "var ext2Calls = 0;");
18458   CompileRun("1+1;");
18459   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18460   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18461
18462   env->GetIsolate()->EnqueueMicrotask(
18463       Function::New(env->GetIsolate(), MicrotaskOne));
18464   CompileRun("1+1;");
18465   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18466   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18467
18468   env->GetIsolate()->SetAutorunMicrotasks(false);
18469   env->GetIsolate()->EnqueueMicrotask(
18470       Function::New(env->GetIsolate(), MicrotaskOne));
18471   env->GetIsolate()->EnqueueMicrotask(
18472       Function::New(env->GetIsolate(), MicrotaskTwo));
18473   CompileRun("1+1;");
18474   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18475   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18476
18477   env->GetIsolate()->RunMicrotasks();
18478   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18479   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18480
18481   env->GetIsolate()->EnqueueMicrotask(
18482       Function::New(env->GetIsolate(), MicrotaskTwo));
18483   CompileRun("1+1;");
18484   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18485   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18486
18487   env->GetIsolate()->RunMicrotasks();
18488   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18489   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18490
18491   env->GetIsolate()->SetAutorunMicrotasks(true);
18492   env->GetIsolate()->EnqueueMicrotask(
18493       Function::New(env->GetIsolate(), MicrotaskTwo));
18494   CompileRun("1+1;");
18495   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18496   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18497
18498   env->GetIsolate()->EnqueueMicrotask(
18499       Function::New(env->GetIsolate(), MicrotaskTwo));
18500   {
18501     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
18502     CompileRun("1+1;");
18503     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18504     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18505   }
18506
18507   CompileRun("1+1;");
18508   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18509   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
18510 }
18511
18512
18513 TEST(RunMicrotasksWithoutEnteringContext) {
18514   v8::Isolate* isolate = CcTest::isolate();
18515   HandleScope handle_scope(isolate);
18516   isolate->SetAutorunMicrotasks(false);
18517   Handle<Context> context = Context::New(isolate);
18518   {
18519     Context::Scope context_scope(context);
18520     CompileRun("var ext1Calls = 0;");
18521     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
18522   }
18523   isolate->RunMicrotasks();
18524   {
18525     Context::Scope context_scope(context);
18526     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18527   }
18528   isolate->SetAutorunMicrotasks(true);
18529 }
18530
18531
18532 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
18533   v8::DebugEvent event = event_details.GetEvent();
18534   if (event != v8::Break) return;
18535   Handle<Object> exec_state = event_details.GetExecutionState();
18536   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
18537   CompileRun("function f(id) { new FrameDetails(id, 0); }");
18538   Handle<Function> fun =
18539       Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
18540   fun->Call(CcTest::global(), 1, &break_id);
18541 }
18542
18543
18544 TEST(Regress385349) {
18545   i::FLAG_allow_natives_syntax = true;
18546   v8::Isolate* isolate = CcTest::isolate();
18547   HandleScope handle_scope(isolate);
18548   isolate->SetAutorunMicrotasks(false);
18549   Handle<Context> context = Context::New(isolate);
18550   v8::Debug::SetDebugEventListener(DebugEventInObserver);
18551   {
18552     Context::Scope context_scope(context);
18553     CompileRun("var obj = {};"
18554                "Object.observe(obj, function(changes) { debugger; });"
18555                "obj.a = 0;");
18556   }
18557   isolate->RunMicrotasks();
18558   isolate->SetAutorunMicrotasks(true);
18559   v8::Debug::SetDebugEventListener(NULL);
18560 }
18561
18562
18563 #ifdef ENABLE_DISASSEMBLER
18564 static int probes_counter = 0;
18565 static int misses_counter = 0;
18566 static int updates_counter = 0;
18567
18568
18569 static int* LookupCounter(const char* name) {
18570   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
18571     return &probes_counter;
18572   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
18573     return &misses_counter;
18574   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
18575     return &updates_counter;
18576   }
18577   return NULL;
18578 }
18579
18580
18581 static const char* kMegamorphicTestProgram =
18582     "function ClassA() { };"
18583     "function ClassB() { };"
18584     "ClassA.prototype.foo = function() { };"
18585     "ClassB.prototype.foo = function() { };"
18586     "function fooify(obj) { obj.foo(); };"
18587     "var a = new ClassA();"
18588     "var b = new ClassB();"
18589     "for (var i = 0; i < 10000; i++) {"
18590     "  fooify(a);"
18591     "  fooify(b);"
18592     "}";
18593 #endif
18594
18595
18596 static void StubCacheHelper(bool primary) {
18597 #ifdef ENABLE_DISASSEMBLER
18598   i::FLAG_native_code_counters = true;
18599   if (primary) {
18600     i::FLAG_test_primary_stub_cache = true;
18601   } else {
18602     i::FLAG_test_secondary_stub_cache = true;
18603   }
18604   i::FLAG_crankshaft = false;
18605   LocalContext env;
18606   env->GetIsolate()->SetCounterFunction(LookupCounter);
18607   v8::HandleScope scope(env->GetIsolate());
18608   int initial_probes = probes_counter;
18609   int initial_misses = misses_counter;
18610   int initial_updates = updates_counter;
18611   CompileRun(kMegamorphicTestProgram);
18612   int probes = probes_counter - initial_probes;
18613   int misses = misses_counter - initial_misses;
18614   int updates = updates_counter - initial_updates;
18615   CHECK_LT(updates, 10);
18616   CHECK_LT(misses, 10);
18617   // TODO(verwaest): Update this test to overflow the degree of polymorphism
18618   // before megamorphism. The number of probes will only work once we teach the
18619   // serializer to embed references to counters in the stubs, given that the
18620   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
18621   CHECK_GE(probes, 0);
18622 #endif
18623 }
18624
18625
18626 TEST(SecondaryStubCache) {
18627   StubCacheHelper(true);
18628 }
18629
18630
18631 TEST(PrimaryStubCache) {
18632   StubCacheHelper(false);
18633 }
18634
18635
18636 #ifdef DEBUG
18637 static int cow_arrays_created_runtime = 0;
18638
18639
18640 static int* LookupCounterCOWArrays(const char* name) {
18641   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
18642     return &cow_arrays_created_runtime;
18643   }
18644   return NULL;
18645 }
18646 #endif
18647
18648
18649 TEST(CheckCOWArraysCreatedRuntimeCounter) {
18650 #ifdef DEBUG
18651   i::FLAG_native_code_counters = true;
18652   LocalContext env;
18653   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
18654   v8::HandleScope scope(env->GetIsolate());
18655   int initial_cow_arrays = cow_arrays_created_runtime;
18656   CompileRun("var o = [1, 2, 3];");
18657   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
18658   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
18659   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
18660   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
18661   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
18662 #endif
18663 }
18664
18665
18666 TEST(StaticGetters) {
18667   LocalContext context;
18668   i::Factory* factory = CcTest::i_isolate()->factory();
18669   v8::Isolate* isolate = CcTest::isolate();
18670   v8::HandleScope scope(isolate);
18671   i::Handle<i::Object> undefined_value = factory->undefined_value();
18672   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
18673   i::Handle<i::Object> null_value = factory->null_value();
18674   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
18675   i::Handle<i::Object> true_value = factory->true_value();
18676   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
18677   i::Handle<i::Object> false_value = factory->false_value();
18678   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
18679 }
18680
18681
18682 UNINITIALIZED_TEST(IsolateEmbedderData) {
18683   CcTest::DisableAutomaticDispose();
18684   v8::Isolate::CreateParams create_params;
18685   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18686   v8::Isolate* isolate = v8::Isolate::New(create_params);
18687   isolate->Enter();
18688   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
18689   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18690     CHECK(!isolate->GetData(slot));
18691     CHECK(!i_isolate->GetData(slot));
18692   }
18693   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18694     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
18695     isolate->SetData(slot, data);
18696   }
18697   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18698     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
18699     CHECK_EQ(data, isolate->GetData(slot));
18700     CHECK_EQ(data, i_isolate->GetData(slot));
18701   }
18702   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18703     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
18704     isolate->SetData(slot, data);
18705   }
18706   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18707     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
18708     CHECK_EQ(data, isolate->GetData(slot));
18709     CHECK_EQ(data, i_isolate->GetData(slot));
18710   }
18711   isolate->Exit();
18712   isolate->Dispose();
18713 }
18714
18715
18716 TEST(StringEmpty) {
18717   LocalContext context;
18718   i::Factory* factory = CcTest::i_isolate()->factory();
18719   v8::Isolate* isolate = CcTest::isolate();
18720   v8::HandleScope scope(isolate);
18721   i::Handle<i::Object> empty_string = factory->empty_string();
18722   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
18723 }
18724
18725
18726 static int instance_checked_getter_count = 0;
18727 static void InstanceCheckedGetter(
18728     Local<String> name,
18729     const v8::PropertyCallbackInfo<v8::Value>& info) {
18730   CHECK(name->Equals(v8_str("foo")));
18731   instance_checked_getter_count++;
18732   info.GetReturnValue().Set(v8_num(11));
18733 }
18734
18735
18736 static int instance_checked_setter_count = 0;
18737 static void InstanceCheckedSetter(Local<String> name,
18738                       Local<Value> value,
18739                       const v8::PropertyCallbackInfo<void>& info) {
18740   CHECK(name->Equals(v8_str("foo")));
18741   CHECK(value->Equals(v8_num(23)));
18742   instance_checked_setter_count++;
18743 }
18744
18745
18746 static void CheckInstanceCheckedResult(int getters, int setters,
18747                                        bool expects_callbacks,
18748                                        TryCatch* try_catch) {
18749   if (expects_callbacks) {
18750     CHECK(!try_catch->HasCaught());
18751     CHECK_EQ(getters, instance_checked_getter_count);
18752     CHECK_EQ(setters, instance_checked_setter_count);
18753   } else {
18754     CHECK(try_catch->HasCaught());
18755     CHECK_EQ(0, instance_checked_getter_count);
18756     CHECK_EQ(0, instance_checked_setter_count);
18757   }
18758   try_catch->Reset();
18759 }
18760
18761
18762 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
18763   instance_checked_getter_count = 0;
18764   instance_checked_setter_count = 0;
18765   TryCatch try_catch(CcTest::isolate());
18766
18767   // Test path through generic runtime code.
18768   CompileRun("obj.foo");
18769   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
18770   CompileRun("obj.foo = 23");
18771   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
18772
18773   // Test path through generated LoadIC and StoredIC.
18774   CompileRun("function test_get(o) { o.foo; }"
18775              "test_get(obj);");
18776   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
18777   CompileRun("test_get(obj);");
18778   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
18779   CompileRun("test_get(obj);");
18780   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
18781   CompileRun("function test_set(o) { o.foo = 23; }"
18782              "test_set(obj);");
18783   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
18784   CompileRun("test_set(obj);");
18785   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
18786   CompileRun("test_set(obj);");
18787   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
18788
18789   // Test path through optimized code.
18790   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
18791              "test_get(obj);");
18792   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
18793   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
18794              "test_set(obj);");
18795   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
18796
18797   // Cleanup so that closures start out fresh in next check.
18798   CompileRun("%DeoptimizeFunction(test_get);"
18799              "%ClearFunctionTypeFeedback(test_get);"
18800              "%DeoptimizeFunction(test_set);"
18801              "%ClearFunctionTypeFeedback(test_set);");
18802 }
18803
18804
18805 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
18806   v8::internal::FLAG_allow_natives_syntax = true;
18807   LocalContext context;
18808   v8::HandleScope scope(context->GetIsolate());
18809
18810   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18811   Local<ObjectTemplate> inst = templ->InstanceTemplate();
18812   inst->SetAccessor(v8_str("foo"),
18813                     InstanceCheckedGetter, InstanceCheckedSetter,
18814                     Handle<Value>(),
18815                     v8::DEFAULT,
18816                     v8::None,
18817                     v8::AccessorSignature::New(context->GetIsolate(), templ));
18818   context->Global()->Set(v8_str("f"), templ->GetFunction());
18819
18820   printf("Testing positive ...\n");
18821   CompileRun("var obj = new f();");
18822   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18823   CheckInstanceCheckedAccessors(true);
18824
18825   printf("Testing negative ...\n");
18826   CompileRun("var obj = {};"
18827              "obj.__proto__ = new f();");
18828   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18829   CheckInstanceCheckedAccessors(false);
18830 }
18831
18832
18833 static void EmptyInterceptorGetter(
18834     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
18835
18836
18837 static void EmptyInterceptorSetter(
18838     Local<String> name, Local<Value> value,
18839     const v8::PropertyCallbackInfo<v8::Value>& info) {}
18840
18841
18842 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
18843   v8::internal::FLAG_allow_natives_syntax = true;
18844   LocalContext context;
18845   v8::HandleScope scope(context->GetIsolate());
18846
18847   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18848   Local<ObjectTemplate> inst = templ->InstanceTemplate();
18849   templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
18850                                                      EmptyInterceptorSetter);
18851   inst->SetAccessor(v8_str("foo"),
18852                     InstanceCheckedGetter, InstanceCheckedSetter,
18853                     Handle<Value>(),
18854                     v8::DEFAULT,
18855                     v8::None,
18856                     v8::AccessorSignature::New(context->GetIsolate(), templ));
18857   context->Global()->Set(v8_str("f"), templ->GetFunction());
18858
18859   printf("Testing positive ...\n");
18860   CompileRun("var obj = new f();");
18861   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18862   CheckInstanceCheckedAccessors(true);
18863
18864   printf("Testing negative ...\n");
18865   CompileRun("var obj = {};"
18866              "obj.__proto__ = new f();");
18867   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18868   CheckInstanceCheckedAccessors(false);
18869 }
18870
18871
18872 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
18873   v8::internal::FLAG_allow_natives_syntax = true;
18874   LocalContext context;
18875   v8::HandleScope scope(context->GetIsolate());
18876
18877   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18878   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
18879   proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
18880                      InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
18881                      v8::None,
18882                      v8::AccessorSignature::New(context->GetIsolate(), templ));
18883   context->Global()->Set(v8_str("f"), templ->GetFunction());
18884
18885   printf("Testing positive ...\n");
18886   CompileRun("var obj = new f();");
18887   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18888   CheckInstanceCheckedAccessors(true);
18889
18890   printf("Testing negative ...\n");
18891   CompileRun("var obj = {};"
18892              "obj.__proto__ = new f();");
18893   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18894   CheckInstanceCheckedAccessors(false);
18895
18896   printf("Testing positive with modified prototype chain ...\n");
18897   CompileRun("var obj = new f();"
18898              "var pro = {};"
18899              "pro.__proto__ = obj.__proto__;"
18900              "obj.__proto__ = pro;");
18901   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18902   CheckInstanceCheckedAccessors(true);
18903 }
18904
18905
18906 TEST(TryFinallyMessage) {
18907   LocalContext context;
18908   v8::HandleScope scope(context->GetIsolate());
18909   {
18910     // Test that the original error message is not lost if there is a
18911     // recursive call into Javascript is done in the finally block, e.g. to
18912     // initialize an IC. (crbug.com/129171)
18913     TryCatch try_catch(context->GetIsolate());
18914     const char* trigger_ic =
18915         "try {                      \n"
18916         "  throw new Error('test'); \n"
18917         "} finally {                \n"
18918         "  var x = 0;               \n"
18919         "  x++;                     \n"  // Trigger an IC initialization here.
18920         "}                          \n";
18921     CompileRun(trigger_ic);
18922     CHECK(try_catch.HasCaught());
18923     Local<Message> message = try_catch.Message();
18924     CHECK(!message.IsEmpty());
18925     CHECK_EQ(2, message->GetLineNumber());
18926   }
18927
18928   {
18929     // Test that the original exception message is indeed overwritten if
18930     // a new error is thrown in the finally block.
18931     TryCatch try_catch(context->GetIsolate());
18932     const char* throw_again =
18933         "try {                       \n"
18934         "  throw new Error('test');  \n"
18935         "} finally {                 \n"
18936         "  var x = 0;                \n"
18937         "  x++;                      \n"
18938         "  throw new Error('again'); \n"  // This is the new uncaught error.
18939         "}                           \n";
18940     CompileRun(throw_again);
18941     CHECK(try_catch.HasCaught());
18942     Local<Message> message = try_catch.Message();
18943     CHECK(!message.IsEmpty());
18944     CHECK_EQ(6, message->GetLineNumber());
18945   }
18946 }
18947
18948
18949 static void Helper137002(bool do_store,
18950                          bool polymorphic,
18951                          bool remove_accessor,
18952                          bool interceptor) {
18953   LocalContext context;
18954   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
18955   if (interceptor) {
18956     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
18957                                                             FooSetInterceptor));
18958   } else {
18959     templ->SetAccessor(v8_str("foo"),
18960                        GetterWhichReturns42,
18961                        SetterWhichSetsYOnThisTo23);
18962   }
18963   context->Global()->Set(v8_str("obj"), templ->NewInstance());
18964
18965   // Turn monomorphic on slow object with native accessor, then turn
18966   // polymorphic, finally optimize to create negative lookup and fail.
18967   CompileRun(do_store ?
18968              "function f(x) { x.foo = void 0; }" :
18969              "function f(x) { return x.foo; }");
18970   CompileRun("obj.y = void 0;");
18971   if (!interceptor) {
18972     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
18973   }
18974   CompileRun("obj.__proto__ = null;"
18975              "f(obj); f(obj); f(obj);");
18976   if (polymorphic) {
18977     CompileRun("f({});");
18978   }
18979   CompileRun("obj.y = void 0;"
18980              "%OptimizeFunctionOnNextCall(f);");
18981   if (remove_accessor) {
18982     CompileRun("delete obj.foo;");
18983   }
18984   CompileRun("var result = f(obj);");
18985   if (do_store) {
18986     CompileRun("result = obj.y;");
18987   }
18988   if (remove_accessor && !interceptor) {
18989     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
18990   } else {
18991     CHECK_EQ(do_store ? 23 : 42,
18992              context->Global()->Get(v8_str("result"))->Int32Value());
18993   }
18994 }
18995
18996
18997 THREADED_TEST(Regress137002a) {
18998   i::FLAG_allow_natives_syntax = true;
18999   i::FLAG_compilation_cache = false;
19000   v8::HandleScope scope(CcTest::isolate());
19001   for (int i = 0; i < 16; i++) {
19002     Helper137002(i & 8, i & 4, i & 2, i & 1);
19003   }
19004 }
19005
19006
19007 THREADED_TEST(Regress137002b) {
19008   i::FLAG_allow_natives_syntax = true;
19009   LocalContext context;
19010   v8::Isolate* isolate = context->GetIsolate();
19011   v8::HandleScope scope(isolate);
19012   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19013   templ->SetAccessor(v8_str("foo"),
19014                      GetterWhichReturns42,
19015                      SetterWhichSetsYOnThisTo23);
19016   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19017
19018   // Turn monomorphic on slow object with native accessor, then just
19019   // delete the property and fail.
19020   CompileRun("function load(x) { return x.foo; }"
19021              "function store(x) { x.foo = void 0; }"
19022              "function keyed_load(x, key) { return x[key]; }"
19023              // Second version of function has a different source (add void 0)
19024              // so that it does not share code with the first version.  This
19025              // ensures that the ICs are monomorphic.
19026              "function load2(x) { void 0; return x.foo; }"
19027              "function store2(x) { void 0; x.foo = void 0; }"
19028              "function keyed_load2(x, key) { void 0; return x[key]; }"
19029
19030              "obj.y = void 0;"
19031              "obj.__proto__ = null;"
19032              "var subobj = {};"
19033              "subobj.y = void 0;"
19034              "subobj.__proto__ = obj;"
19035              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19036
19037              // Make the ICs monomorphic.
19038              "load(obj); load(obj);"
19039              "load2(subobj); load2(subobj);"
19040              "store(obj); store(obj);"
19041              "store2(subobj); store2(subobj);"
19042              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19043              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19044
19045              // Actually test the shiny new ICs and better not crash. This
19046              // serves as a regression test for issue 142088 as well.
19047              "load(obj);"
19048              "load2(subobj);"
19049              "store(obj);"
19050              "store2(subobj);"
19051              "keyed_load(obj, 'foo');"
19052              "keyed_load2(subobj, 'foo');"
19053
19054              // Delete the accessor.  It better not be called any more now.
19055              "delete obj.foo;"
19056              "obj.y = void 0;"
19057              "subobj.y = void 0;"
19058
19059              "var load_result = load(obj);"
19060              "var load_result2 = load2(subobj);"
19061              "var keyed_load_result = keyed_load(obj, 'foo');"
19062              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19063              "store(obj);"
19064              "store2(subobj);"
19065              "var y_from_obj = obj.y;"
19066              "var y_from_subobj = subobj.y;");
19067   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19068   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19069   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19070   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19071   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19072   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19073 }
19074
19075
19076 THREADED_TEST(Regress142088) {
19077   i::FLAG_allow_natives_syntax = true;
19078   LocalContext context;
19079   v8::Isolate* isolate = context->GetIsolate();
19080   v8::HandleScope scope(isolate);
19081   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19082   templ->SetAccessor(v8_str("foo"),
19083                      GetterWhichReturns42,
19084                      SetterWhichSetsYOnThisTo23);
19085   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19086
19087   CompileRun("function load(x) { return x.foo; }"
19088              "var o = Object.create(obj);"
19089              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19090              "load(o); load(o); load(o); load(o);");
19091 }
19092
19093
19094 THREADED_TEST(Regress137496) {
19095   i::FLAG_expose_gc = true;
19096   LocalContext context;
19097   v8::HandleScope scope(context->GetIsolate());
19098
19099   // Compile a try-finally clause where the finally block causes a GC
19100   // while there still is a message pending for external reporting.
19101   TryCatch try_catch(context->GetIsolate());
19102   try_catch.SetVerbose(true);
19103   CompileRun("try { throw new Error(); } finally { gc(); }");
19104   CHECK(try_catch.HasCaught());
19105 }
19106
19107
19108 THREADED_TEST(Regress157124) {
19109   LocalContext context;
19110   v8::Isolate* isolate = context->GetIsolate();
19111   v8::HandleScope scope(isolate);
19112   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19113   Local<Object> obj = templ->NewInstance();
19114   obj->GetIdentityHash();
19115   obj->DeleteHiddenValue(v8_str("Bug"));
19116 }
19117
19118
19119 THREADED_TEST(Regress2535) {
19120   LocalContext context;
19121   v8::HandleScope scope(context->GetIsolate());
19122   Local<Value> set_value = CompileRun("new Set();");
19123   Local<Object> set_object(Local<Object>::Cast(set_value));
19124   CHECK_EQ(0, set_object->InternalFieldCount());
19125   Local<Value> map_value = CompileRun("new Map();");
19126   Local<Object> map_object(Local<Object>::Cast(map_value));
19127   CHECK_EQ(0, map_object->InternalFieldCount());
19128 }
19129
19130
19131 THREADED_TEST(Regress2746) {
19132   LocalContext context;
19133   v8::Isolate* isolate = context->GetIsolate();
19134   v8::HandleScope scope(isolate);
19135   Local<Object> obj = Object::New(isolate);
19136   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
19137   obj->SetHiddenValue(key, v8::Undefined(isolate));
19138   Local<Value> value = obj->GetHiddenValue(key);
19139   CHECK(!value.IsEmpty());
19140   CHECK(value->IsUndefined());
19141 }
19142
19143
19144 THREADED_TEST(Regress260106) {
19145   LocalContext context;
19146   v8::Isolate* isolate = context->GetIsolate();
19147   v8::HandleScope scope(isolate);
19148   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
19149                                                         DummyCallHandler);
19150   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19151   Local<Function> function = templ->GetFunction();
19152   CHECK(!function.IsEmpty());
19153   CHECK(function->IsFunction());
19154 }
19155
19156
19157 THREADED_TEST(JSONParseObject) {
19158   LocalContext context;
19159   HandleScope scope(context->GetIsolate());
19160   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
19161   Handle<Object> global = context->Global();
19162   global->Set(v8_str("obj"), obj);
19163   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
19164 }
19165
19166
19167 THREADED_TEST(JSONParseNumber) {
19168   LocalContext context;
19169   HandleScope scope(context->GetIsolate());
19170   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
19171   Handle<Object> global = context->Global();
19172   global->Set(v8_str("obj"), obj);
19173   ExpectString("JSON.stringify(obj)", "42");
19174 }
19175
19176
19177 #if V8_OS_POSIX && !V8_OS_NACL
19178 class ThreadInterruptTest {
19179  public:
19180   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
19181   ~ThreadInterruptTest() {}
19182
19183   void RunTest() {
19184     InterruptThread i_thread(this);
19185     i_thread.Start();
19186
19187     sem_.Wait();
19188     CHECK_EQ(kExpectedValue, sem_value_);
19189   }
19190
19191  private:
19192   static const int kExpectedValue = 1;
19193
19194   class InterruptThread : public v8::base::Thread {
19195    public:
19196     explicit InterruptThread(ThreadInterruptTest* test)
19197         : Thread(Options("InterruptThread")), test_(test) {}
19198
19199     virtual void Run() {
19200       struct sigaction action;
19201
19202       // Ensure that we'll enter waiting condition
19203       v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
19204
19205       // Setup signal handler
19206       memset(&action, 0, sizeof(action));
19207       action.sa_handler = SignalHandler;
19208       sigaction(SIGCHLD, &action, NULL);
19209
19210       // Send signal
19211       kill(getpid(), SIGCHLD);
19212
19213       // Ensure that if wait has returned because of error
19214       v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
19215
19216       // Set value and signal semaphore
19217       test_->sem_value_ = 1;
19218       test_->sem_.Signal();
19219     }
19220
19221     static void SignalHandler(int signal) {
19222     }
19223
19224    private:
19225      ThreadInterruptTest* test_;
19226   };
19227
19228   v8::base::Semaphore sem_;
19229   volatile int sem_value_;
19230 };
19231
19232
19233 THREADED_TEST(SemaphoreInterruption) {
19234   ThreadInterruptTest().RunTest();
19235 }
19236
19237
19238 #endif  // V8_OS_POSIX
19239
19240
19241 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19242   CHECK(false);
19243 }
19244
19245
19246 TEST(JSONStringifyAccessCheck) {
19247   v8::V8::Initialize();
19248   v8::Isolate* isolate = CcTest::isolate();
19249   v8::HandleScope scope(isolate);
19250
19251   // Create an ObjectTemplate for global objects and install access
19252   // check callbacks that will block access.
19253   v8::Handle<v8::ObjectTemplate> global_template =
19254       v8::ObjectTemplate::New(isolate);
19255   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19256
19257   // Create a context and set an x property on it's global object.
19258   LocalContext context0(NULL, global_template);
19259   v8::Handle<v8::Object> global0 = context0->Global();
19260   global0->Set(v8_str("x"), v8_num(42));
19261   ExpectString("JSON.stringify(this)", "{\"x\":42}");
19262
19263   for (int i = 0; i < 2; i++) {
19264     if (i == 1) {
19265       // Install a toJSON function on the second run.
19266       v8::Handle<v8::FunctionTemplate> toJSON =
19267           v8::FunctionTemplate::New(isolate, UnreachableCallback);
19268
19269       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19270     }
19271     // Create a context with a different security token so that the
19272     // failed access check callback will be called on each access.
19273     LocalContext context1(NULL, global_template);
19274     context1->Global()->Set(v8_str("other"), global0);
19275
19276     CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
19277     CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
19278     CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
19279   }
19280 }
19281
19282
19283 bool access_check_fail_thrown = false;
19284 bool catch_callback_called = false;
19285
19286
19287 // Failed access check callback that performs a GC on each invocation.
19288 void FailedAccessCheckThrows(Local<v8::Object> target,
19289                              v8::AccessType type,
19290                              Local<v8::Value> data) {
19291   access_check_fail_thrown = true;
19292   i::PrintF("Access check failed. Error thrown.\n");
19293   CcTest::isolate()->ThrowException(
19294       v8::Exception::Error(v8_str("cross context")));
19295 }
19296
19297
19298 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19299   for (int i = 0; i < args.Length(); i++) {
19300     i::PrintF("%s\n", *String::Utf8Value(args[i]));
19301   }
19302   catch_callback_called = true;
19303 }
19304
19305
19306 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19307   args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
19308       args[1]->ToString(args.GetIsolate()));
19309 }
19310
19311
19312 void CheckCorrectThrow(const char* script) {
19313   // Test that the script, when wrapped into a try-catch, triggers the catch
19314   // clause due to failed access check throwing an exception.
19315   // The subsequent try-catch should run without any exception.
19316   access_check_fail_thrown = false;
19317   catch_callback_called = false;
19318   i::ScopedVector<char> source(1024);
19319   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19320   CompileRun(source.start());
19321   CHECK(access_check_fail_thrown);
19322   CHECK(catch_callback_called);
19323
19324   access_check_fail_thrown = false;
19325   catch_callback_called = false;
19326   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19327   CHECK(!access_check_fail_thrown);
19328   CHECK(!catch_callback_called);
19329 }
19330
19331
19332 TEST(AccessCheckThrows) {
19333   i::FLAG_allow_natives_syntax = true;
19334   i::FLAG_turbo_try_catch = true;
19335   v8::V8::Initialize();
19336   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19337   v8::Isolate* isolate = CcTest::isolate();
19338   v8::HandleScope scope(isolate);
19339
19340   // Create an ObjectTemplate for global objects and install access
19341   // check callbacks that will block access.
19342   v8::Handle<v8::ObjectTemplate> global_template =
19343       v8::ObjectTemplate::New(isolate);
19344   global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19345
19346   // Create a context and set an x property on it's global object.
19347   LocalContext context0(NULL, global_template);
19348   v8::Handle<v8::Object> global0 = context0->Global();
19349
19350   // Create a context with a different security token so that the
19351   // failed access check callback will be called on each access.
19352   LocalContext context1(NULL, global_template);
19353   context1->Global()->Set(v8_str("other"), global0);
19354
19355   v8::Handle<v8::FunctionTemplate> catcher_fun =
19356       v8::FunctionTemplate::New(isolate, CatcherCallback);
19357   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19358
19359   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19360       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
19361   context1->Global()->Set(v8_str("has_own_property"),
19362                           has_own_property_fun->GetFunction());
19363
19364   {
19365     v8::TryCatch try_catch(isolate);
19366     access_check_fail_thrown = false;
19367     CompileRun("other.x;");
19368     CHECK(access_check_fail_thrown);
19369     CHECK(try_catch.HasCaught());
19370   }
19371
19372   CheckCorrectThrow("other.x");
19373   CheckCorrectThrow("other[1]");
19374   CheckCorrectThrow("JSON.stringify(other)");
19375   CheckCorrectThrow("has_own_property(other, 'x')");
19376   CheckCorrectThrow("%GetProperty(other, 'x')");
19377   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
19378   CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
19379   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19380   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19381   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
19382   CheckCorrectThrow("%HasProperty(other, 'x')");
19383   CheckCorrectThrow("%HasElement(other, 1)");
19384   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19385   CheckCorrectThrow("%GetPropertyNames(other)");
19386   // PROPERTY_ATTRIBUTES_NONE = 0
19387   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
19388   CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
19389                         "other, 'x', null, null, 1)");
19390
19391   // Reset the failed access check callback so it does not influence
19392   // the other tests.
19393   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19394 }
19395
19396
19397 class RequestInterruptTestBase {
19398  public:
19399   RequestInterruptTestBase()
19400       : env_(),
19401         isolate_(env_->GetIsolate()),
19402         sem_(0),
19403         warmup_(20000),
19404         should_continue_(true) {
19405   }
19406
19407   virtual ~RequestInterruptTestBase() { }
19408
19409   virtual void StartInterruptThread() = 0;
19410
19411   virtual void TestBody() = 0;
19412
19413   void RunTest() {
19414     StartInterruptThread();
19415
19416     v8::HandleScope handle_scope(isolate_);
19417
19418     TestBody();
19419
19420     // Verify we arrived here because interruptor was called
19421     // not due to a bug causing us to exit the loop too early.
19422     CHECK(!should_continue());
19423   }
19424
19425   void WakeUpInterruptor() {
19426     sem_.Signal();
19427   }
19428
19429   bool should_continue() const { return should_continue_; }
19430
19431   bool ShouldContinue() {
19432     if (warmup_ > 0) {
19433       if (--warmup_ == 0) {
19434         WakeUpInterruptor();
19435       }
19436     }
19437
19438     return should_continue_;
19439   }
19440
19441   static void ShouldContinueCallback(
19442       const v8::FunctionCallbackInfo<Value>& info) {
19443     RequestInterruptTestBase* test =
19444         reinterpret_cast<RequestInterruptTestBase*>(
19445             info.Data().As<v8::External>()->Value());
19446     info.GetReturnValue().Set(test->ShouldContinue());
19447   }
19448
19449   LocalContext env_;
19450   v8::Isolate* isolate_;
19451   v8::base::Semaphore sem_;
19452   int warmup_;
19453   bool should_continue_;
19454 };
19455
19456
19457 class RequestInterruptTestBaseWithSimpleInterrupt
19458     : public RequestInterruptTestBase {
19459  public:
19460   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
19461
19462   virtual void StartInterruptThread() {
19463     i_thread.Start();
19464   }
19465
19466  private:
19467   class InterruptThread : public v8::base::Thread {
19468    public:
19469     explicit InterruptThread(RequestInterruptTestBase* test)
19470         : Thread(Options("RequestInterruptTest")), test_(test) {}
19471
19472     virtual void Run() {
19473       test_->sem_.Wait();
19474       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
19475     }
19476
19477     static void OnInterrupt(v8::Isolate* isolate, void* data) {
19478       reinterpret_cast<RequestInterruptTestBase*>(data)->
19479           should_continue_ = false;
19480     }
19481
19482    private:
19483      RequestInterruptTestBase* test_;
19484   };
19485
19486   InterruptThread i_thread;
19487 };
19488
19489
19490 class RequestInterruptTestWithFunctionCall
19491     : public RequestInterruptTestBaseWithSimpleInterrupt {
19492  public:
19493   virtual void TestBody() {
19494     Local<Function> func = Function::New(
19495         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
19496     env_->Global()->Set(v8_str("ShouldContinue"), func);
19497
19498     CompileRun("while (ShouldContinue()) { }");
19499   }
19500 };
19501
19502
19503 class RequestInterruptTestWithMethodCall
19504     : public RequestInterruptTestBaseWithSimpleInterrupt {
19505  public:
19506   virtual void TestBody() {
19507     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19508     v8::Local<v8::Template> proto = t->PrototypeTemplate();
19509     proto->Set(v8_str("shouldContinue"), Function::New(
19510         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19511     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19512
19513     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
19514   }
19515 };
19516
19517
19518 class RequestInterruptTestWithAccessor
19519     : public RequestInterruptTestBaseWithSimpleInterrupt {
19520  public:
19521   virtual void TestBody() {
19522     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19523     v8::Local<v8::Template> proto = t->PrototypeTemplate();
19524     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
19525         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19526     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19527
19528     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
19529   }
19530 };
19531
19532
19533 class RequestInterruptTestWithNativeAccessor
19534     : public RequestInterruptTestBaseWithSimpleInterrupt {
19535  public:
19536   virtual void TestBody() {
19537     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19538     t->InstanceTemplate()->SetNativeDataProperty(
19539         v8_str("shouldContinue"),
19540         &ShouldContinueNativeGetter,
19541         NULL,
19542         v8::External::New(isolate_, this));
19543     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19544
19545     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
19546   }
19547
19548  private:
19549   static void ShouldContinueNativeGetter(
19550       Local<String> property,
19551       const v8::PropertyCallbackInfo<v8::Value>& info) {
19552     RequestInterruptTestBase* test =
19553         reinterpret_cast<RequestInterruptTestBase*>(
19554             info.Data().As<v8::External>()->Value());
19555     info.GetReturnValue().Set(test->ShouldContinue());
19556   }
19557 };
19558
19559
19560 class RequestInterruptTestWithMethodCallAndInterceptor
19561     : public RequestInterruptTestBaseWithSimpleInterrupt {
19562  public:
19563   virtual void TestBody() {
19564     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19565     v8::Local<v8::Template> proto = t->PrototypeTemplate();
19566     proto->Set(v8_str("shouldContinue"), Function::New(
19567         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19568     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
19569     instance_template->SetHandler(
19570         v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
19571
19572     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19573
19574     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
19575   }
19576
19577  private:
19578   static void EmptyInterceptor(
19579       Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
19580 };
19581
19582
19583 class RequestInterruptTestWithMathAbs
19584     : public RequestInterruptTestBaseWithSimpleInterrupt {
19585  public:
19586   virtual void TestBody() {
19587     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
19588         isolate_,
19589         WakeUpInterruptorCallback,
19590         v8::External::New(isolate_, this)));
19591
19592     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
19593         isolate_,
19594         ShouldContinueCallback,
19595         v8::External::New(isolate_, this)));
19596
19597     i::FLAG_allow_natives_syntax = true;
19598     CompileRun("function loopish(o) {"
19599                "  var pre = 10;"
19600                "  while (o.abs(1) > 0) {"
19601                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
19602                "    if (pre > 0) {"
19603                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
19604                "    }"
19605                "  }"
19606                "}"
19607                "var i = 50;"
19608                "var obj = {abs: function () { return i-- }, x: null};"
19609                "delete obj.x;"
19610                "loopish(obj);"
19611                "%OptimizeFunctionOnNextCall(loopish);"
19612                "loopish(Math);");
19613
19614     i::FLAG_allow_natives_syntax = false;
19615   }
19616
19617  private:
19618   static void WakeUpInterruptorCallback(
19619       const v8::FunctionCallbackInfo<Value>& info) {
19620     if (!info[0]->BooleanValue()) return;
19621
19622     RequestInterruptTestBase* test =
19623         reinterpret_cast<RequestInterruptTestBase*>(
19624             info.Data().As<v8::External>()->Value());
19625     test->WakeUpInterruptor();
19626   }
19627
19628   static void ShouldContinueCallback(
19629       const v8::FunctionCallbackInfo<Value>& info) {
19630     RequestInterruptTestBase* test =
19631         reinterpret_cast<RequestInterruptTestBase*>(
19632             info.Data().As<v8::External>()->Value());
19633     info.GetReturnValue().Set(test->should_continue());
19634   }
19635 };
19636
19637
19638 TEST(RequestInterruptTestWithFunctionCall) {
19639   RequestInterruptTestWithFunctionCall().RunTest();
19640 }
19641
19642
19643 TEST(RequestInterruptTestWithMethodCall) {
19644   RequestInterruptTestWithMethodCall().RunTest();
19645 }
19646
19647
19648 TEST(RequestInterruptTestWithAccessor) {
19649   RequestInterruptTestWithAccessor().RunTest();
19650 }
19651
19652
19653 TEST(RequestInterruptTestWithNativeAccessor) {
19654   RequestInterruptTestWithNativeAccessor().RunTest();
19655 }
19656
19657
19658 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
19659   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
19660 }
19661
19662
19663 TEST(RequestInterruptTestWithMathAbs) {
19664   RequestInterruptTestWithMathAbs().RunTest();
19665 }
19666
19667
19668 class RequestMultipleInterrupts : public RequestInterruptTestBase {
19669  public:
19670   RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
19671
19672   virtual void StartInterruptThread() {
19673     i_thread.Start();
19674   }
19675
19676   virtual void TestBody() {
19677     Local<Function> func = Function::New(
19678         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
19679     env_->Global()->Set(v8_str("ShouldContinue"), func);
19680
19681     CompileRun("while (ShouldContinue()) { }");
19682   }
19683
19684  private:
19685   class InterruptThread : public v8::base::Thread {
19686    public:
19687     enum { NUM_INTERRUPTS = 10 };
19688     explicit InterruptThread(RequestMultipleInterrupts* test)
19689         : Thread(Options("RequestInterruptTest")), test_(test) {}
19690
19691     virtual void Run() {
19692       test_->sem_.Wait();
19693       for (int i = 0; i < NUM_INTERRUPTS; i++) {
19694         test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
19695       }
19696     }
19697
19698     static void OnInterrupt(v8::Isolate* isolate, void* data) {
19699       RequestMultipleInterrupts* test =
19700           reinterpret_cast<RequestMultipleInterrupts*>(data);
19701       test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
19702     }
19703
19704    private:
19705     RequestMultipleInterrupts* test_;
19706   };
19707
19708   InterruptThread i_thread;
19709   int counter_;
19710 };
19711
19712
19713 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
19714
19715
19716 static bool interrupt_was_called = false;
19717
19718
19719 void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
19720   interrupt_was_called = true;
19721 }
19722
19723
19724 TEST(RequestInterruptSmallScripts) {
19725   LocalContext env;
19726   v8::Isolate* isolate = CcTest::isolate();
19727   v8::HandleScope scope(isolate);
19728
19729   interrupt_was_called = false;
19730   isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL);
19731   CompileRun("(function(x){return x;})(1);");
19732   CHECK(interrupt_was_called);
19733 }
19734
19735
19736 static Local<Value> function_new_expected_env;
19737 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
19738   CHECK(function_new_expected_env->Equals(info.Data()));
19739   info.GetReturnValue().Set(17);
19740 }
19741
19742
19743 THREADED_TEST(FunctionNew) {
19744   LocalContext env;
19745   v8::Isolate* isolate = env->GetIsolate();
19746   v8::HandleScope scope(isolate);
19747   Local<Object> data = v8::Object::New(isolate);
19748   function_new_expected_env = data;
19749   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
19750   env->Global()->Set(v8_str("func"), func);
19751   Local<Value> result = CompileRun("func();");
19752   CHECK(v8::Integer::New(isolate, 17)->Equals(result));
19753   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19754   // Verify function not cached
19755   auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
19756                                                ->shared()
19757                                                ->get_api_func_data()
19758                                                ->serial_number()),
19759                               i_isolate);
19760   auto cache = i_isolate->function_cache();
19761   CHECK(cache->Lookup(serial_number)->IsTheHole());
19762   // Verify that each Function::New creates a new function instance
19763   Local<Object> data2 = v8::Object::New(isolate);
19764   function_new_expected_env = data2;
19765   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
19766   CHECK(!func2->IsNull());
19767   CHECK(!func->Equals(func2));
19768   env->Global()->Set(v8_str("func2"), func2);
19769   Local<Value> result2 = CompileRun("func2();");
19770   CHECK(v8::Integer::New(isolate, 17)->Equals(result2));
19771 }
19772
19773
19774 TEST(EscapeableHandleScope) {
19775   HandleScope outer_scope(CcTest::isolate());
19776   LocalContext context;
19777   const int runs = 10;
19778   Local<String> values[runs];
19779   for (int i = 0; i < runs; i++) {
19780     v8::EscapableHandleScope inner_scope(CcTest::isolate());
19781     Local<String> value;
19782     if (i != 0) value = v8_str("escape value");
19783     values[i] = inner_scope.Escape(value);
19784   }
19785   for (int i = 0; i < runs; i++) {
19786     Local<String> expected;
19787     if (i != 0) {
19788       CHECK(v8_str("escape value")->Equals(values[i]));
19789     } else {
19790       CHECK(values[i].IsEmpty());
19791     }
19792   }
19793 }
19794
19795
19796 static void SetterWhichExpectsThisAndHolderToDiffer(
19797     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
19798   CHECK(info.Holder() != info.This());
19799 }
19800
19801
19802 TEST(Regress239669) {
19803   LocalContext context;
19804   v8::Isolate* isolate = context->GetIsolate();
19805   v8::HandleScope scope(isolate);
19806   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19807   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
19808   context->Global()->Set(v8_str("P"), templ->NewInstance());
19809   CompileRun(
19810       "function C1() {"
19811       "  this.x = 23;"
19812       "};"
19813       "C1.prototype = P;"
19814       "for (var i = 0; i < 4; i++ ) {"
19815       "  new C1();"
19816       "}");
19817 }
19818
19819
19820 class ApiCallOptimizationChecker {
19821  private:
19822   static Local<Object> data;
19823   static Local<Object> receiver;
19824   static Local<Object> holder;
19825   static Local<Object> callee;
19826   static int count;
19827
19828   static void OptimizationCallback(
19829       const v8::FunctionCallbackInfo<v8::Value>& info) {
19830     CHECK(callee == info.Callee());
19831     CHECK(data == info.Data());
19832     CHECK(receiver == info.This());
19833     if (info.Length() == 1) {
19834       CHECK(v8_num(1)->Equals(info[0]));
19835     }
19836     CHECK(holder == info.Holder());
19837     count++;
19838     info.GetReturnValue().Set(v8_str("returned"));
19839   }
19840
19841  public:
19842   enum SignatureType {
19843     kNoSignature,
19844     kSignatureOnReceiver,
19845     kSignatureOnPrototype
19846   };
19847
19848   void RunAll() {
19849     SignatureType signature_types[] =
19850       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
19851     for (unsigned i = 0; i < arraysize(signature_types); i++) {
19852       SignatureType signature_type = signature_types[i];
19853       for (int j = 0; j < 2; j++) {
19854         bool global = j == 0;
19855         int key = signature_type +
19856             arraysize(signature_types) * (global ? 1 : 0);
19857         Run(signature_type, global, key);
19858       }
19859     }
19860   }
19861
19862   void Run(SignatureType signature_type, bool global, int key) {
19863     v8::Isolate* isolate = CcTest::isolate();
19864     v8::HandleScope scope(isolate);
19865     // Build a template for signature checks.
19866     Local<v8::ObjectTemplate> signature_template;
19867     Local<v8::Signature> signature;
19868     {
19869       Local<v8::FunctionTemplate> parent_template =
19870         FunctionTemplate::New(isolate);
19871       parent_template->SetHiddenPrototype(true);
19872       Local<v8::FunctionTemplate> function_template
19873           = FunctionTemplate::New(isolate);
19874       function_template->Inherit(parent_template);
19875       switch (signature_type) {
19876         case kNoSignature:
19877           break;
19878         case kSignatureOnReceiver:
19879           signature = v8::Signature::New(isolate, function_template);
19880           break;
19881         case kSignatureOnPrototype:
19882           signature = v8::Signature::New(isolate, parent_template);
19883           break;
19884       }
19885       signature_template = function_template->InstanceTemplate();
19886     }
19887     // Global object must pass checks.
19888     Local<v8::Context> context =
19889         v8::Context::New(isolate, NULL, signature_template);
19890     v8::Context::Scope context_scope(context);
19891     // Install regular object that can pass signature checks.
19892     Local<Object> function_receiver = signature_template->NewInstance();
19893     context->Global()->Set(v8_str("function_receiver"), function_receiver);
19894     // Get the holder objects.
19895     Local<Object> inner_global =
19896         Local<Object>::Cast(context->Global()->GetPrototype());
19897     // Install functions on hidden prototype object if there is one.
19898     data = Object::New(isolate);
19899     Local<FunctionTemplate> function_template = FunctionTemplate::New(
19900         isolate, OptimizationCallback, data, signature);
19901     Local<Function> function = function_template->GetFunction();
19902     Local<Object> global_holder = inner_global;
19903     Local<Object> function_holder = function_receiver;
19904     if (signature_type == kSignatureOnPrototype) {
19905       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
19906       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
19907     }
19908     global_holder->Set(v8_str("g_f"), function);
19909     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
19910     function_holder->Set(v8_str("f"), function);
19911     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
19912     // Initialize expected values.
19913     callee = function;
19914     count = 0;
19915     if (global) {
19916       receiver = context->Global();
19917       holder = inner_global;
19918     } else {
19919       holder = function_receiver;
19920       // If not using a signature, add something else to the prototype chain
19921       // to test the case that holder != receiver
19922       if (signature_type == kNoSignature) {
19923         receiver = Local<Object>::Cast(CompileRun(
19924             "var receiver_subclass = {};\n"
19925             "receiver_subclass.__proto__ = function_receiver;\n"
19926             "receiver_subclass"));
19927       } else {
19928         receiver = Local<Object>::Cast(CompileRun(
19929           "var receiver_subclass = function_receiver;\n"
19930           "receiver_subclass"));
19931       }
19932     }
19933     // With no signature, the holder is not set.
19934     if (signature_type == kNoSignature) holder = receiver;
19935     // build wrap_function
19936     i::ScopedVector<char> wrap_function(200);
19937     if (global) {
19938       i::SNPrintF(
19939           wrap_function,
19940           "function wrap_f_%d() { var f = g_f; return f(); }\n"
19941           "function wrap_get_%d() { return this.g_acc; }\n"
19942           "function wrap_set_%d() { return this.g_acc = 1; }\n",
19943           key, key, key);
19944     } else {
19945       i::SNPrintF(
19946           wrap_function,
19947           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
19948           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
19949           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
19950           key, key, key);
19951     }
19952     // build source string
19953     i::ScopedVector<char> source(1000);
19954     i::SNPrintF(
19955         source,
19956         "%s\n"  // wrap functions
19957         "function wrap_f() { return wrap_f_%d(); }\n"
19958         "function wrap_get() { return wrap_get_%d(); }\n"
19959         "function wrap_set() { return wrap_set_%d(); }\n"
19960         "check = function(returned) {\n"
19961         "  if (returned !== 'returned') { throw returned; }\n"
19962         "}\n"
19963         "\n"
19964         "check(wrap_f());\n"
19965         "check(wrap_f());\n"
19966         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
19967         "check(wrap_f());\n"
19968         "\n"
19969         "check(wrap_get());\n"
19970         "check(wrap_get());\n"
19971         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
19972         "check(wrap_get());\n"
19973         "\n"
19974         "check = function(returned) {\n"
19975         "  if (returned !== 1) { throw returned; }\n"
19976         "}\n"
19977         "check(wrap_set());\n"
19978         "check(wrap_set());\n"
19979         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
19980         "check(wrap_set());\n",
19981         wrap_function.start(), key, key, key, key, key, key);
19982     v8::TryCatch try_catch(isolate);
19983     CompileRun(source.start());
19984     DCHECK(!try_catch.HasCaught());
19985     CHECK_EQ(9, count);
19986   }
19987 };
19988
19989
19990 Local<Object> ApiCallOptimizationChecker::data;
19991 Local<Object> ApiCallOptimizationChecker::receiver;
19992 Local<Object> ApiCallOptimizationChecker::holder;
19993 Local<Object> ApiCallOptimizationChecker::callee;
19994 int ApiCallOptimizationChecker::count = 0;
19995
19996
19997 TEST(FunctionCallOptimization) {
19998   i::FLAG_allow_natives_syntax = true;
19999   ApiCallOptimizationChecker checker;
20000   checker.RunAll();
20001 }
20002
20003
20004 TEST(FunctionCallOptimizationMultipleArgs) {
20005   i::FLAG_allow_natives_syntax = true;
20006   LocalContext context;
20007   v8::Isolate* isolate = context->GetIsolate();
20008   v8::HandleScope scope(isolate);
20009   Handle<Object> global = context->Global();
20010   Local<v8::Function> function = Function::New(isolate, Returns42);
20011   global->Set(v8_str("x"), function);
20012   CompileRun(
20013       "function x_wrap() {\n"
20014       "  for (var i = 0; i < 5; i++) {\n"
20015       "    x(1,2,3);\n"
20016       "  }\n"
20017       "}\n"
20018       "x_wrap();\n"
20019       "%OptimizeFunctionOnNextCall(x_wrap);"
20020       "x_wrap();\n");
20021 }
20022
20023
20024 static void ReturnsSymbolCallback(
20025     const v8::FunctionCallbackInfo<v8::Value>& info) {
20026   info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
20027 }
20028
20029
20030 TEST(ApiCallbackCanReturnSymbols) {
20031   i::FLAG_allow_natives_syntax = true;
20032   LocalContext context;
20033   v8::Isolate* isolate = context->GetIsolate();
20034   v8::HandleScope scope(isolate);
20035   Handle<Object> global = context->Global();
20036   Local<v8::Function> function = Function::New(isolate, ReturnsSymbolCallback);
20037   global->Set(v8_str("x"), function);
20038   CompileRun(
20039       "function x_wrap() {\n"
20040       "  for (var i = 0; i < 5; i++) {\n"
20041       "    x();\n"
20042       "  }\n"
20043       "}\n"
20044       "x_wrap();\n"
20045       "%OptimizeFunctionOnNextCall(x_wrap);"
20046       "x_wrap();\n");
20047 }
20048
20049
20050 TEST(EmptyApiCallback) {
20051   LocalContext context;
20052   auto isolate = context->GetIsolate();
20053   v8::HandleScope scope(isolate);
20054   auto global = context->Global();
20055   auto function = FunctionTemplate::New(isolate)->GetFunction();
20056   global->Set(v8_str("x"), function);
20057
20058   auto result = CompileRun("x()");
20059   CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20060
20061   result = CompileRun("x(1,2,3)");
20062   CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20063
20064   result = CompileRun("7 + x.call(3) + 11");
20065   CHECK(result->IsInt32());
20066   CHECK_EQ(21, result->Int32Value());
20067
20068   result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
20069   CHECK(result->IsInt32());
20070   CHECK_EQ(21, result->Int32Value());
20071
20072   result = CompileRun("var y = []; x.call(y)");
20073   CHECK(result->IsArray());
20074
20075   result = CompileRun("x.call(y, 1, 2, 3, 4)");
20076   CHECK(result->IsArray());
20077 }
20078
20079
20080 TEST(SimpleSignatureCheck) {
20081   LocalContext context;
20082   auto isolate = context->GetIsolate();
20083   v8::HandleScope scope(isolate);
20084   auto global = context->Global();
20085   auto sig_obj = FunctionTemplate::New(isolate);
20086   auto sig = v8::Signature::New(isolate, sig_obj);
20087   auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20088   global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20089   global->Set(v8_str("x"), x->GetFunction());
20090   CompileRun("var s = new sig_obj();");
20091   {
20092     TryCatch try_catch(isolate);
20093     CompileRun("x()");
20094     CHECK(try_catch.HasCaught());
20095   }
20096   {
20097     TryCatch try_catch(isolate);
20098     CompileRun("x.call(1)");
20099     CHECK(try_catch.HasCaught());
20100   }
20101   {
20102     TryCatch try_catch(isolate);
20103     auto result = CompileRun("s.x = x; s.x()");
20104     CHECK(!try_catch.HasCaught());
20105     CHECK_EQ(42, result->Int32Value());
20106   }
20107   {
20108     TryCatch try_catch(isolate);
20109     auto result = CompileRun("x.call(s)");
20110     CHECK(!try_catch.HasCaught());
20111     CHECK_EQ(42, result->Int32Value());
20112   }
20113 }
20114
20115
20116 TEST(ChainSignatureCheck) {
20117   LocalContext context;
20118   auto isolate = context->GetIsolate();
20119   v8::HandleScope scope(isolate);
20120   auto global = context->Global();
20121   auto sig_obj = FunctionTemplate::New(isolate);
20122   auto sig = v8::Signature::New(isolate, sig_obj);
20123   for (int i = 0; i < 4; ++i) {
20124     auto temp = FunctionTemplate::New(isolate);
20125     temp->Inherit(sig_obj);
20126     sig_obj = temp;
20127   }
20128   auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20129   global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20130   global->Set(v8_str("x"), x->GetFunction());
20131   CompileRun("var s = new sig_obj();");
20132   {
20133     TryCatch try_catch(isolate);
20134     CompileRun("x()");
20135     CHECK(try_catch.HasCaught());
20136   }
20137   {
20138     TryCatch try_catch(isolate);
20139     CompileRun("x.call(1)");
20140     CHECK(try_catch.HasCaught());
20141   }
20142   {
20143     TryCatch try_catch(isolate);
20144     auto result = CompileRun("s.x = x; s.x()");
20145     CHECK(!try_catch.HasCaught());
20146     CHECK_EQ(42, result->Int32Value());
20147   }
20148   {
20149     TryCatch try_catch(isolate);
20150     auto result = CompileRun("x.call(s)");
20151     CHECK(!try_catch.HasCaught());
20152     CHECK_EQ(42, result->Int32Value());
20153   }
20154 }
20155
20156
20157 TEST(PrototypeSignatureCheck) {
20158   LocalContext context;
20159   auto isolate = context->GetIsolate();
20160   v8::HandleScope scope(isolate);
20161   auto global = context->Global();
20162   auto sig_obj = FunctionTemplate::New(isolate);
20163   sig_obj->SetHiddenPrototype(true);
20164   auto sig = v8::Signature::New(isolate, sig_obj);
20165   auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20166   global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20167   global->Set(v8_str("x"), x->GetFunction());
20168   CompileRun("s = {}; s.__proto__ = new sig_obj();");
20169   {
20170     TryCatch try_catch(isolate);
20171     CompileRun("x()");
20172     CHECK(try_catch.HasCaught());
20173   }
20174   {
20175     TryCatch try_catch(isolate);
20176     CompileRun("x.call(1)");
20177     CHECK(try_catch.HasCaught());
20178   }
20179   {
20180     TryCatch try_catch(isolate);
20181     auto result = CompileRun("s.x = x; s.x()");
20182     CHECK(!try_catch.HasCaught());
20183     CHECK_EQ(42, result->Int32Value());
20184   }
20185   {
20186     TryCatch try_catch(isolate);
20187     auto result = CompileRun("x.call(s)");
20188     CHECK(!try_catch.HasCaught());
20189     CHECK_EQ(42, result->Int32Value());
20190   }
20191 }
20192
20193
20194 static const char* last_event_message;
20195 static int last_event_status;
20196 void StoringEventLoggerCallback(const char* message, int status) {
20197     last_event_message = message;
20198     last_event_status = status;
20199 }
20200
20201
20202 TEST(EventLogging) {
20203   v8::Isolate* isolate = CcTest::isolate();
20204   isolate->SetEventLogger(StoringEventLoggerCallback);
20205   v8::internal::HistogramTimer histogramTimer(
20206       "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
20207       reinterpret_cast<v8::internal::Isolate*>(isolate));
20208   histogramTimer.Start();
20209   CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20210   CHECK_EQ(0, last_event_status);
20211   histogramTimer.Stop();
20212   CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20213   CHECK_EQ(1, last_event_status);
20214 }
20215
20216
20217 TEST(Promises) {
20218   LocalContext context;
20219   v8::Isolate* isolate = context->GetIsolate();
20220   v8::HandleScope scope(isolate);
20221   Handle<Object> global = context->Global();
20222
20223   // Creation.
20224   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20225   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
20226   Handle<v8::Promise> p = pr->GetPromise();
20227   Handle<v8::Promise> r = rr->GetPromise();
20228   CHECK_EQ(isolate, p->GetIsolate());
20229
20230   // IsPromise predicate.
20231   CHECK(p->IsPromise());
20232   CHECK(r->IsPromise());
20233   Handle<Value> o = v8::Object::New(isolate);
20234   CHECK(!o->IsPromise());
20235
20236   // Resolution and rejection.
20237   pr->Resolve(v8::Integer::New(isolate, 1));
20238   CHECK(p->IsPromise());
20239   rr->Reject(v8::Integer::New(isolate, 2));
20240   CHECK(r->IsPromise());
20241
20242   // Chaining non-pending promises.
20243   CompileRun(
20244       "var x1 = 0;\n"
20245       "var x2 = 0;\n"
20246       "function f1(x) { x1 = x; return x+1 };\n"
20247       "function f2(x) { x2 = x; return x+1 };\n");
20248   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20249   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20250
20251   p->Chain(f1);
20252   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20253   isolate->RunMicrotasks();
20254   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20255
20256   p->Catch(f2);
20257   isolate->RunMicrotasks();
20258   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20259
20260   r->Catch(f2);
20261   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20262   isolate->RunMicrotasks();
20263   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20264
20265   r->Chain(f1);
20266   isolate->RunMicrotasks();
20267   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20268
20269   // Chaining pending promises.
20270   CompileRun("x1 = x2 = 0;");
20271   pr = v8::Promise::Resolver::New(isolate);
20272   rr = v8::Promise::Resolver::New(isolate);
20273
20274   pr->GetPromise()->Chain(f1);
20275   rr->GetPromise()->Catch(f2);
20276   isolate->RunMicrotasks();
20277   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20278   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20279
20280   pr->Resolve(v8::Integer::New(isolate, 1));
20281   rr->Reject(v8::Integer::New(isolate, 2));
20282   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20283   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20284
20285   isolate->RunMicrotasks();
20286   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20287   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20288
20289   // Multi-chaining.
20290   CompileRun("x1 = x2 = 0;");
20291   pr = v8::Promise::Resolver::New(isolate);
20292   pr->GetPromise()->Chain(f1)->Chain(f2);
20293   pr->Resolve(v8::Integer::New(isolate, 3));
20294   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20295   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20296   isolate->RunMicrotasks();
20297   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20298   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20299
20300   CompileRun("x1 = x2 = 0;");
20301   rr = v8::Promise::Resolver::New(isolate);
20302   rr->GetPromise()->Catch(f1)->Chain(f2);
20303   rr->Reject(v8::Integer::New(isolate, 3));
20304   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20305   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20306   isolate->RunMicrotasks();
20307   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20308   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20309 }
20310
20311
20312 TEST(PromiseThen) {
20313   LocalContext context;
20314   v8::Isolate* isolate = context->GetIsolate();
20315   v8::HandleScope scope(isolate);
20316   Handle<Object> global = context->Global();
20317
20318   // Creation.
20319   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20320   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
20321   Handle<v8::Promise> p = pr->GetPromise();
20322   Handle<v8::Promise> q = qr->GetPromise();
20323
20324   CHECK(p->IsPromise());
20325   CHECK(q->IsPromise());
20326
20327   pr->Resolve(v8::Integer::New(isolate, 1));
20328   qr->Resolve(p);
20329
20330   // Chaining non-pending promises.
20331   CompileRun(
20332       "var x1 = 0;\n"
20333       "var x2 = 0;\n"
20334       "function f1(x) { x1 = x; return x+1 };\n"
20335       "function f2(x) { x2 = x; return x+1 };\n");
20336   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20337   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20338
20339   // Chain
20340   q->Chain(f1);
20341   CHECK(global->Get(v8_str("x1"))->IsNumber());
20342   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20343   isolate->RunMicrotasks();
20344   CHECK(!global->Get(v8_str("x1"))->IsNumber());
20345   CHECK(p->Equals(global->Get(v8_str("x1"))));
20346
20347   // Then
20348   CompileRun("x1 = x2 = 0;");
20349   q->Then(f1);
20350   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20351   isolate->RunMicrotasks();
20352   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20353
20354   // Then
20355   CompileRun("x1 = x2 = 0;");
20356   pr = v8::Promise::Resolver::New(isolate);
20357   qr = v8::Promise::Resolver::New(isolate);
20358
20359   qr->Resolve(pr);
20360   qr->GetPromise()->Then(f1)->Then(f2);
20361
20362   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20363   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20364   isolate->RunMicrotasks();
20365   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20366   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20367
20368   pr->Resolve(v8::Integer::New(isolate, 3));
20369
20370   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20371   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20372   isolate->RunMicrotasks();
20373   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20374   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20375 }
20376
20377
20378 TEST(DisallowJavascriptExecutionScope) {
20379   LocalContext context;
20380   v8::Isolate* isolate = context->GetIsolate();
20381   v8::HandleScope scope(isolate);
20382   v8::Isolate::DisallowJavascriptExecutionScope no_js(
20383       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20384   CompileRun("2+2");
20385 }
20386
20387
20388 TEST(AllowJavascriptExecutionScope) {
20389   LocalContext context;
20390   v8::Isolate* isolate = context->GetIsolate();
20391   v8::HandleScope scope(isolate);
20392   v8::Isolate::DisallowJavascriptExecutionScope no_js(
20393       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20394   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20395       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20396   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
20397     CompileRun("1+1");
20398   }
20399 }
20400
20401
20402 TEST(ThrowOnJavascriptExecution) {
20403   LocalContext context;
20404   v8::Isolate* isolate = context->GetIsolate();
20405   v8::HandleScope scope(isolate);
20406   v8::TryCatch try_catch(isolate);
20407   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20408       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20409   CompileRun("1+1");
20410   CHECK(try_catch.HasCaught());
20411 }
20412
20413
20414 TEST(Regress354123) {
20415   LocalContext current;
20416   v8::Isolate* isolate = current->GetIsolate();
20417   v8::HandleScope scope(isolate);
20418
20419   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
20420   templ->SetAccessCheckCallbacks(AccessCounter, NULL);
20421   current->Global()->Set(v8_str("friend"), templ->NewInstance());
20422
20423   // Test access using __proto__ from the prototype chain.
20424   access_count = 0;
20425   CompileRun("friend.__proto__ = {};");
20426   CHECK_EQ(2, access_count);
20427   CompileRun("friend.__proto__;");
20428   CHECK_EQ(4, access_count);
20429
20430   // Test access using __proto__ as a hijacked function (A).
20431   access_count = 0;
20432   CompileRun("var p = Object.prototype;"
20433              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
20434              "f.call(friend, {});");
20435   CHECK_EQ(1, access_count);
20436   CompileRun("var p = Object.prototype;"
20437              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
20438              "f.call(friend);");
20439   CHECK_EQ(2, access_count);
20440
20441   // Test access using __proto__ as a hijacked function (B).
20442   access_count = 0;
20443   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
20444              "f.call(friend, {});");
20445   CHECK_EQ(1, access_count);
20446   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
20447              "f.call(friend);");
20448   CHECK_EQ(2, access_count);
20449
20450   // Test access using Object.setPrototypeOf reflective method.
20451   access_count = 0;
20452   CompileRun("Object.setPrototypeOf(friend, {});");
20453   CHECK_EQ(1, access_count);
20454   CompileRun("Object.getPrototypeOf(friend);");
20455   CHECK_EQ(2, access_count);
20456 }
20457
20458
20459 TEST(CaptureStackTraceForStackOverflow) {
20460   v8::internal::FLAG_stack_size = 150;
20461   LocalContext current;
20462   v8::Isolate* isolate = current->GetIsolate();
20463   v8::HandleScope scope(isolate);
20464   V8::SetCaptureStackTraceForUncaughtExceptions(
20465       true, 10, v8::StackTrace::kDetailed);
20466   v8::TryCatch try_catch(isolate);
20467   CompileRun("(function f(x) { f(x+1); })(0)");
20468   CHECK(try_catch.HasCaught());
20469 }
20470
20471
20472 TEST(ScriptNameAndLineNumber) {
20473   LocalContext env;
20474   v8::Isolate* isolate = env->GetIsolate();
20475   v8::HandleScope scope(isolate);
20476   const char* url = "http://www.foo.com/foo.js";
20477   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
20478   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
20479   Local<Script> script = v8::ScriptCompiler::Compile(
20480       isolate, &script_source);
20481   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
20482   CHECK(!script_name.IsEmpty());
20483   CHECK(script_name->IsString());
20484   String::Utf8Value utf8_name(script_name);
20485   CHECK_EQ(0, strcmp(url, *utf8_name));
20486   int line_number = script->GetUnboundScript()->GetLineNumber(0);
20487   CHECK_EQ(13, line_number);
20488 }
20489
20490 void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
20491                         const char* expected_source_mapping_url) {
20492   if (expected_source_url != NULL) {
20493     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
20494     CHECK_EQ(0, strcmp(expected_source_url, *url));
20495   } else {
20496     CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
20497   }
20498   if (expected_source_mapping_url != NULL) {
20499     v8::String::Utf8Value url(
20500         script->GetUnboundScript()->GetSourceMappingURL());
20501     CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
20502   } else {
20503     CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
20504   }
20505 }
20506
20507 void SourceURLHelper(const char* source, const char* expected_source_url,
20508                      const char* expected_source_mapping_url) {
20509   Local<Script> script = v8_compile(source);
20510   CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
20511 }
20512
20513
20514 TEST(ScriptSourceURLAndSourceMappingURL) {
20515   LocalContext env;
20516   v8::Isolate* isolate = env->GetIsolate();
20517   v8::HandleScope scope(isolate);
20518   SourceURLHelper("function foo() {}\n"
20519                   "//# sourceURL=bar1.js\n", "bar1.js", NULL);
20520   SourceURLHelper("function foo() {}\n"
20521                   "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
20522
20523   // Both sourceURL and sourceMappingURL.
20524   SourceURLHelper("function foo() {}\n"
20525                   "//# sourceURL=bar3.js\n"
20526                   "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
20527
20528   // Two source URLs; the first one is ignored.
20529   SourceURLHelper("function foo() {}\n"
20530                   "//# sourceURL=ignoreme.js\n"
20531                   "//# sourceURL=bar5.js\n", "bar5.js", NULL);
20532   SourceURLHelper("function foo() {}\n"
20533                   "//# sourceMappingURL=ignoreme.js\n"
20534                   "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
20535
20536   // SourceURL or sourceMappingURL in the middle of the script.
20537   SourceURLHelper("function foo() {}\n"
20538                   "//# sourceURL=bar7.js\n"
20539                   "function baz() {}\n", "bar7.js", NULL);
20540   SourceURLHelper("function foo() {}\n"
20541                   "//# sourceMappingURL=bar8.js\n"
20542                   "function baz() {}\n", NULL, "bar8.js");
20543
20544   // Too much whitespace.
20545   SourceURLHelper("function foo() {}\n"
20546                   "//#  sourceURL=bar9.js\n"
20547                   "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
20548   SourceURLHelper("function foo() {}\n"
20549                   "//# sourceURL =bar11.js\n"
20550                   "//# sourceMappingURL =bar12.js\n", NULL, NULL);
20551
20552   // Disallowed characters in value.
20553   SourceURLHelper("function foo() {}\n"
20554                   "//# sourceURL=bar13 .js   \n"
20555                   "//# sourceMappingURL=bar14 .js \n",
20556                   NULL, NULL);
20557   SourceURLHelper("function foo() {}\n"
20558                   "//# sourceURL=bar15\t.js   \n"
20559                   "//# sourceMappingURL=bar16\t.js \n",
20560                   NULL, NULL);
20561   SourceURLHelper("function foo() {}\n"
20562                   "//# sourceURL=bar17'.js   \n"
20563                   "//# sourceMappingURL=bar18'.js \n",
20564                   NULL, NULL);
20565   SourceURLHelper("function foo() {}\n"
20566                   "//# sourceURL=bar19\".js   \n"
20567                   "//# sourceMappingURL=bar20\".js \n",
20568                   NULL, NULL);
20569
20570   // Not too much whitespace.
20571   SourceURLHelper("function foo() {}\n"
20572                   "//# sourceURL=  bar21.js   \n"
20573                   "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
20574 }
20575
20576
20577 TEST(GetOwnPropertyDescriptor) {
20578   LocalContext env;
20579   v8::Isolate* isolate = env->GetIsolate();
20580   v8::HandleScope scope(isolate);
20581   CompileRun(
20582     "var x = { value : 13};"
20583     "Object.defineProperty(x, 'p0', {value : 12});"
20584     "Object.defineProperty(x, 'p1', {"
20585     "  set : function(value) { this.value = value; },"
20586     "  get : function() { return this.value; },"
20587     "});");
20588   Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
20589   Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
20590   CHECK(desc->IsUndefined());
20591   desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
20592   CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
20593   desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
20594   Local<Function> set =
20595     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
20596   Local<Function> get =
20597     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
20598   CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
20599   Handle<Value> args[] = { v8_num(14) };
20600   set->Call(x, 1, args);
20601   CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
20602 }
20603
20604
20605 TEST(Regress411877) {
20606   v8::Isolate* isolate = CcTest::isolate();
20607   v8::HandleScope handle_scope(isolate);
20608   v8::Handle<v8::ObjectTemplate> object_template =
20609       v8::ObjectTemplate::New(isolate);
20610   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20611
20612   v8::Handle<Context> context = Context::New(isolate);
20613   v8::Context::Scope context_scope(context);
20614
20615   context->Global()->Set(v8_str("o"), object_template->NewInstance());
20616   CompileRun("Object.getOwnPropertyNames(o)");
20617 }
20618
20619
20620 TEST(GetHiddenPropertyTableAfterAccessCheck) {
20621   v8::Isolate* isolate = CcTest::isolate();
20622   v8::HandleScope handle_scope(isolate);
20623   v8::Handle<v8::ObjectTemplate> object_template =
20624       v8::ObjectTemplate::New(isolate);
20625   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20626
20627   v8::Handle<Context> context = Context::New(isolate);
20628   v8::Context::Scope context_scope(context);
20629
20630   v8::Handle<v8::Object> obj = object_template->NewInstance();
20631   obj->Set(v8_str("key"), v8_str("value"));
20632   obj->Delete(v8_str("key"));
20633
20634   obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
20635 }
20636
20637
20638 TEST(Regress411793) {
20639   v8::Isolate* isolate = CcTest::isolate();
20640   v8::HandleScope handle_scope(isolate);
20641   v8::Handle<v8::ObjectTemplate> object_template =
20642       v8::ObjectTemplate::New(isolate);
20643   object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20644
20645   v8::Handle<Context> context = Context::New(isolate);
20646   v8::Context::Scope context_scope(context);
20647
20648   context->Global()->Set(v8_str("o"), object_template->NewInstance());
20649   CompileRun(
20650       "Object.defineProperty(o, 'key', "
20651       "    { get: function() {}, set: function() {} });");
20652 }
20653
20654 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
20655  public:
20656   explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
20657
20658   virtual size_t GetMoreData(const uint8_t** src) {
20659     // Unlike in real use cases, this function will never block.
20660     if (chunks_[index_] == NULL) {
20661       return 0;
20662     }
20663     // Copy the data, since the caller takes ownership of it.
20664     size_t len = strlen(chunks_[index_]);
20665     // We don't need to zero-terminate since we return the length.
20666     uint8_t* copy = new uint8_t[len];
20667     memcpy(copy, chunks_[index_], len);
20668     *src = copy;
20669     ++index_;
20670     return len;
20671   }
20672
20673   // Helper for constructing a string from chunks (the compilation needs it
20674   // too).
20675   static char* FullSourceString(const char** chunks) {
20676     size_t total_len = 0;
20677     for (size_t i = 0; chunks[i] != NULL; ++i) {
20678       total_len += strlen(chunks[i]);
20679     }
20680     char* full_string = new char[total_len + 1];
20681     size_t offset = 0;
20682     for (size_t i = 0; chunks[i] != NULL; ++i) {
20683       size_t len = strlen(chunks[i]);
20684       memcpy(full_string + offset, chunks[i], len);
20685       offset += len;
20686     }
20687     full_string[total_len] = 0;
20688     return full_string;
20689   }
20690
20691  private:
20692   const char** chunks_;
20693   unsigned index_;
20694 };
20695
20696
20697 // Helper function for running streaming tests.
20698 void RunStreamingTest(const char** chunks,
20699                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
20700                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
20701                       bool expected_success = true,
20702                       const char* expected_source_url = NULL,
20703                       const char* expected_source_mapping_url = NULL) {
20704   LocalContext env;
20705   v8::Isolate* isolate = env->GetIsolate();
20706   v8::HandleScope scope(isolate);
20707   v8::TryCatch try_catch(isolate);
20708
20709   v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
20710                                             encoding);
20711   v8::ScriptCompiler::ScriptStreamingTask* task =
20712       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
20713
20714   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20715   // task here in the main thread.
20716   task->Run();
20717   delete task;
20718
20719   // Possible errors are only produced while compiling.
20720   CHECK_EQ(false, try_catch.HasCaught());
20721
20722   v8::ScriptOrigin origin(v8_str("http://foo.com"));
20723   char* full_source = TestSourceStream::FullSourceString(chunks);
20724   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
20725       isolate, &source, v8_str(full_source), origin);
20726   if (expected_success) {
20727     CHECK(!script.IsEmpty());
20728     v8::Handle<Value> result(script->Run());
20729     // All scripts are supposed to return the fixed value 13 when ran.
20730     CHECK_EQ(13, result->Int32Value());
20731     CheckMagicComments(script, expected_source_url,
20732                        expected_source_mapping_url);
20733   } else {
20734     CHECK(script.IsEmpty());
20735     CHECK(try_catch.HasCaught());
20736   }
20737   delete[] full_source;
20738 }
20739
20740
20741 TEST(StreamingSimpleScript) {
20742   // This script is unrealistically small, since no one chunk is enough to fill
20743   // the backing buffer of Scanner, let alone overflow it.
20744   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20745                           NULL};
20746   RunStreamingTest(chunks);
20747 }
20748
20749
20750 TEST(StreamingBiggerScript) {
20751   const char* chunk1 =
20752       "function foo() {\n"
20753       "  // Make this chunk sufficiently long so that it will overflow the\n"
20754       "  // backing buffer of the Scanner.\n"
20755       "  var i = 0;\n"
20756       "  var result = 0;\n"
20757       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20758       "  result = 0;\n"
20759       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20760       "  result = 0;\n"
20761       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20762       "  result = 0;\n"
20763       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20764       "  return result;\n"
20765       "}\n";
20766   const char* chunks[] = {chunk1, "foo(); ", NULL};
20767   RunStreamingTest(chunks);
20768 }
20769
20770
20771 TEST(StreamingScriptWithParseError) {
20772   // Test that parse errors from streamed scripts are propagated correctly.
20773   {
20774     char chunk1[] =
20775         "  // This will result in a parse error.\n"
20776         "  var if else then foo";
20777     char chunk2[] = "  13\n";
20778     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20779
20780     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
20781                      false);
20782   }
20783   // Test that the next script succeeds normally.
20784   {
20785     char chunk1[] =
20786         "  // This will be parsed successfully.\n"
20787         "  function foo() { return ";
20788     char chunk2[] = "  13; }\n";
20789     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20790
20791     RunStreamingTest(chunks);
20792   }
20793 }
20794
20795
20796 TEST(StreamingUtf8Script) {
20797   // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
20798   // don't like it.
20799   const char* chunk1 =
20800       "function foo() {\n"
20801       "  // This function will contain an UTF-8 character which is not in\n"
20802       "  // ASCII.\n"
20803       "  var foob\xec\x92\x81r = 13;\n"
20804       "  return foob\xec\x92\x81r;\n"
20805       "}\n";
20806   const char* chunks[] = {chunk1, "foo(); ", NULL};
20807   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20808 }
20809
20810
20811 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
20812   // A sanity check to prove that the approach of splitting UTF-8
20813   // characters is correct. Here is an UTF-8 character which will take three
20814   // bytes.
20815   const char* reference = "\xec\x92\x81";
20816   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
20817
20818   char chunk1[] =
20819       "function foo() {\n"
20820       "  // This function will contain an UTF-8 character which is not in\n"
20821       "  // ASCII.\n"
20822       "  var foob";
20823   char chunk2[] =
20824       "XXXr = 13;\n"
20825       "  return foob\xec\x92\x81r;\n"
20826       "}\n";
20827   for (int i = 0; i < 3; ++i) {
20828     chunk2[i] = reference[i];
20829   }
20830   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20831   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20832 }
20833
20834
20835 TEST(StreamingUtf8ScriptWithSplitCharacters) {
20836   // Stream data where a multi-byte UTF-8 character is split between two data
20837   // chunks.
20838   const char* reference = "\xec\x92\x81";
20839   char chunk1[] =
20840       "function foo() {\n"
20841       "  // This function will contain an UTF-8 character which is not in\n"
20842       "  // ASCII.\n"
20843       "  var foobX";
20844   char chunk2[] =
20845       "XXr = 13;\n"
20846       "  return foob\xec\x92\x81r;\n"
20847       "}\n";
20848   chunk1[strlen(chunk1) - 1] = reference[0];
20849   chunk2[0] = reference[1];
20850   chunk2[1] = reference[2];
20851   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20852   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20853 }
20854
20855
20856 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
20857   // Tests edge cases which should still be decoded correctly.
20858
20859   // Case 1: a chunk contains only bytes for a split character (and no other
20860   // data). This kind of a chunk would be exceptionally small, but we should
20861   // still decode it correctly.
20862   const char* reference = "\xec\x92\x81";
20863   // The small chunk is at the beginning of the split character
20864   {
20865     char chunk1[] =
20866         "function foo() {\n"
20867         "  // This function will contain an UTF-8 character which is not in\n"
20868         "  // ASCII.\n"
20869         "  var foob";
20870     char chunk2[] = "XX";
20871     char chunk3[] =
20872         "Xr = 13;\n"
20873         "  return foob\xec\x92\x81r;\n"
20874         "}\n";
20875     chunk2[0] = reference[0];
20876     chunk2[1] = reference[1];
20877     chunk3[0] = reference[2];
20878     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20879     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20880   }
20881   // The small chunk is at the end of a character
20882   {
20883     char chunk1[] =
20884         "function foo() {\n"
20885         "  // This function will contain an UTF-8 character which is not in\n"
20886         "  // ASCII.\n"
20887         "  var foobX";
20888     char chunk2[] = "XX";
20889     char chunk3[] =
20890         "r = 13;\n"
20891         "  return foob\xec\x92\x81r;\n"
20892         "}\n";
20893     chunk1[strlen(chunk1) - 1] = reference[0];
20894     chunk2[0] = reference[1];
20895     chunk2[1] = reference[2];
20896     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20897     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20898   }
20899   // Case 2: the script ends with a multi-byte character. Make sure that it's
20900   // decoded correctly and not just ignored.
20901   {
20902     char chunk1[] =
20903         "var foob\xec\x92\x81 = 13;\n"
20904         "foob\xec\x92\x81";
20905     const char* chunks[] = {chunk1, NULL};
20906     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20907   }
20908 }
20909
20910
20911 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
20912   // Test cases where a UTF-8 character is split over several chunks. Those
20913   // cases are not supported (the embedder should give the data in big enough
20914   // chunks), but we shouldn't crash, just produce a parse error.
20915   const char* reference = "\xec\x92\x81";
20916   char chunk1[] =
20917       "function foo() {\n"
20918       "  // This function will contain an UTF-8 character which is not in\n"
20919       "  // ASCII.\n"
20920       "  var foobX";
20921   char chunk2[] = "X";
20922   char chunk3[] =
20923       "Xr = 13;\n"
20924       "  return foob\xec\x92\x81r;\n"
20925       "}\n";
20926   chunk1[strlen(chunk1) - 1] = reference[0];
20927   chunk2[0] = reference[1];
20928   chunk3[0] = reference[2];
20929   const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20930
20931   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
20932 }
20933
20934
20935 TEST(StreamingProducesParserCache) {
20936   i::FLAG_min_preparse_length = 0;
20937   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20938                           NULL};
20939
20940   LocalContext env;
20941   v8::Isolate* isolate = env->GetIsolate();
20942   v8::HandleScope scope(isolate);
20943
20944   v8::ScriptCompiler::StreamedSource source(
20945       new TestSourceStream(chunks),
20946       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
20947   v8::ScriptCompiler::ScriptStreamingTask* task =
20948       v8::ScriptCompiler::StartStreamingScript(
20949           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
20950
20951   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20952   // task here in the main thread.
20953   task->Run();
20954   delete task;
20955
20956   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
20957   CHECK(cached_data != NULL);
20958   CHECK(cached_data->data != NULL);
20959   CHECK(!cached_data->rejected);
20960   CHECK_GT(cached_data->length, 0);
20961 }
20962
20963
20964 TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
20965   // If the debugger is active, we should just not produce parser cache at
20966   // all. This is a regeression test: We used to produce a parser cache without
20967   // any data in it (just headers).
20968   i::FLAG_min_preparse_length = 0;
20969   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20970                           NULL};
20971
20972   LocalContext env;
20973   v8::Isolate* isolate = env->GetIsolate();
20974   v8::HandleScope scope(isolate);
20975
20976   // Make the debugger active by setting a breakpoint.
20977   CompileRun("function break_here() { }");
20978   i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
20979       v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
20980   EnableDebugger();
20981   v8::internal::Debug* debug = CcTest::i_isolate()->debug();
20982   int position = 0;
20983   debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
20984                                                   CcTest::i_isolate()),
20985                        &position);
20986
20987   v8::ScriptCompiler::StreamedSource source(
20988       new TestSourceStream(chunks),
20989       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
20990   v8::ScriptCompiler::ScriptStreamingTask* task =
20991       v8::ScriptCompiler::StartStreamingScript(
20992           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
20993
20994   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20995   // task here in the main thread.
20996   task->Run();
20997   delete task;
20998
20999   // Check that we got no cached data.
21000   CHECK(source.GetCachedData() == NULL);
21001   DisableDebugger();
21002 }
21003
21004
21005 TEST(StreamingScriptWithInvalidUtf8) {
21006   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
21007   // chunk don't produce a crash.
21008   const char* reference = "\xec\x92\x81\x80\x80";
21009   char chunk1[] =
21010       "function foo() {\n"
21011       "  // This function will contain an UTF-8 character which is not in\n"
21012       "  // ASCII.\n"
21013       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
21014   char chunk2[] =
21015       "r = 13;\n"
21016       "  return foob\xec\x92\x81\x80\x80r;\n"
21017       "}\n";
21018   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
21019
21020   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21021   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21022 }
21023
21024
21025 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
21026   // Regression test: Stream data where there are several multi-byte UTF-8
21027   // characters in a sequence and one of them is split between two data chunks.
21028   const char* reference = "\xec\x92\x81";
21029   char chunk1[] =
21030       "function foo() {\n"
21031       "  // This function will contain an UTF-8 character which is not in\n"
21032       "  // ASCII.\n"
21033       "  var foob\xec\x92\x81X";
21034   char chunk2[] =
21035       "XXr = 13;\n"
21036       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
21037       "}\n";
21038   chunk1[strlen(chunk1) - 1] = reference[0];
21039   chunk2[0] = reference[1];
21040   chunk2[1] = reference[2];
21041   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21042   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21043 }
21044
21045
21046 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
21047   // Another regression test, similar to the previous one. The difference is
21048   // that the split character is not the last one in the sequence.
21049   const char* reference = "\xec\x92\x81";
21050   char chunk1[] =
21051       "function foo() {\n"
21052       "  // This function will contain an UTF-8 character which is not in\n"
21053       "  // ASCII.\n"
21054       "  var foobX";
21055   char chunk2[] =
21056       "XX\xec\x92\x81r = 13;\n"
21057       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
21058       "}\n";
21059   chunk1[strlen(chunk1) - 1] = reference[0];
21060   chunk2[0] = reference[1];
21061   chunk2[1] = reference[2];
21062   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21063   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21064 }
21065
21066
21067 TEST(StreamingWithHarmonyScopes) {
21068   // Don't use RunStreamingTest here so that both scripts get to use the same
21069   // LocalContext and HandleScope.
21070   LocalContext env;
21071   v8::Isolate* isolate = env->GetIsolate();
21072   v8::HandleScope scope(isolate);
21073
21074   // First, run a script with a let variable.
21075   CompileRun("\"use strict\"; let x = 1;");
21076
21077   // Then stream a script which (erroneously) tries to introduce the same
21078   // variable again.
21079   const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
21080
21081   v8::TryCatch try_catch(isolate);
21082   v8::ScriptCompiler::StreamedSource source(
21083       new TestSourceStream(chunks),
21084       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21085   v8::ScriptCompiler::ScriptStreamingTask* task =
21086       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21087   task->Run();
21088   delete task;
21089
21090   // Parsing should succeed (the script will be parsed and compiled in a context
21091   // independent way, so the error is not detected).
21092   CHECK_EQ(false, try_catch.HasCaught());
21093
21094   v8::ScriptOrigin origin(v8_str("http://foo.com"));
21095   char* full_source = TestSourceStream::FullSourceString(chunks);
21096   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21097       isolate, &source, v8_str(full_source), origin);
21098   CHECK(!script.IsEmpty());
21099   CHECK_EQ(false, try_catch.HasCaught());
21100
21101   // Running the script exposes the error.
21102   v8::Handle<Value> result(script->Run());
21103   CHECK(result.IsEmpty());
21104   CHECK(try_catch.HasCaught());
21105   delete[] full_source;
21106 }
21107
21108
21109 TEST(CodeCache) {
21110   v8::Isolate::CreateParams create_params;
21111   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21112
21113   const char* source = "Math.sqrt(4)";
21114   const char* origin = "code cache test";
21115   v8::ScriptCompiler::CachedData* cache;
21116
21117   v8::Isolate* isolate1 = v8::Isolate::New(create_params);
21118   {
21119     v8::Isolate::Scope iscope(isolate1);
21120     v8::HandleScope scope(isolate1);
21121     v8::Local<v8::Context> context = v8::Context::New(isolate1);
21122     v8::Context::Scope cscope(context);
21123     v8::Local<v8::String> source_string = v8_str(source);
21124     v8::ScriptOrigin script_origin(v8_str(origin));
21125     v8::ScriptCompiler::Source source(source_string, script_origin);
21126     v8::ScriptCompiler::CompileOptions option =
21127         v8::ScriptCompiler::kProduceCodeCache;
21128     v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
21129     int length = source.GetCachedData()->length;
21130     uint8_t* cache_data = new uint8_t[length];
21131     memcpy(cache_data, source.GetCachedData()->data, length);
21132     cache = new v8::ScriptCompiler::CachedData(
21133         cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
21134   }
21135   isolate1->Dispose();
21136
21137   v8::Isolate* isolate2 = v8::Isolate::New(create_params);
21138   {
21139     v8::Isolate::Scope iscope(isolate2);
21140     v8::HandleScope scope(isolate2);
21141     v8::Local<v8::Context> context = v8::Context::New(isolate2);
21142     v8::Context::Scope cscope(context);
21143     v8::Local<v8::String> source_string = v8_str(source);
21144     v8::ScriptOrigin script_origin(v8_str(origin));
21145     v8::ScriptCompiler::Source source(source_string, script_origin, cache);
21146     v8::ScriptCompiler::CompileOptions option =
21147         v8::ScriptCompiler::kConsumeCodeCache;
21148     v8::Local<v8::Script> script;
21149     {
21150       i::DisallowCompilation no_compile(
21151           reinterpret_cast<i::Isolate*>(isolate2));
21152       script = v8::ScriptCompiler::Compile(context, &source, option)
21153                    .ToLocalChecked();
21154     }
21155     CHECK_EQ(2, script->Run()->ToInt32(isolate2)->Int32Value());
21156   }
21157   isolate2->Dispose();
21158 }
21159
21160
21161 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
21162   const char* garbage = "garbage garbage garbage garbage garbage garbage";
21163   const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
21164   int length = 16;
21165   v8::ScriptCompiler::CachedData* cached_data =
21166       new v8::ScriptCompiler::CachedData(data, length);
21167   DCHECK(!cached_data->rejected);
21168   v8::ScriptOrigin origin(v8_str("origin"));
21169   v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
21170   v8::Handle<v8::Script> script =
21171       v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
21172   CHECK(cached_data->rejected);
21173   CHECK_EQ(42, script->Run()->Int32Value());
21174 }
21175
21176
21177 TEST(InvalidCacheData) {
21178   v8::V8::Initialize();
21179   v8::HandleScope scope(CcTest::isolate());
21180   LocalContext context;
21181   TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
21182   TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
21183 }
21184
21185
21186 TEST(ParserCacheRejectedGracefully) {
21187   i::FLAG_min_preparse_length = 0;
21188   v8::V8::Initialize();
21189   v8::HandleScope scope(CcTest::isolate());
21190   LocalContext context;
21191   // Produce valid cached data.
21192   v8::ScriptOrigin origin(v8_str("origin"));
21193   v8::Local<v8::String> source_str = v8_str("function foo() {}");
21194   v8::ScriptCompiler::Source source(source_str, origin);
21195   v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
21196       CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
21197   CHECK(!script.IsEmpty());
21198   const v8::ScriptCompiler::CachedData* original_cached_data =
21199       source.GetCachedData();
21200   CHECK(original_cached_data != NULL);
21201   CHECK(original_cached_data->data != NULL);
21202   CHECK(!original_cached_data->rejected);
21203   CHECK_GT(original_cached_data->length, 0);
21204   // Recompiling the same script with it won't reject the data.
21205   {
21206     v8::ScriptCompiler::Source source_with_cached_data(
21207         source_str, origin,
21208         new v8::ScriptCompiler::CachedData(original_cached_data->data,
21209                                            original_cached_data->length));
21210     v8::Handle<v8::Script> script =
21211         v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21212                                     v8::ScriptCompiler::kConsumeParserCache);
21213     CHECK(!script.IsEmpty());
21214     const v8::ScriptCompiler::CachedData* new_cached_data =
21215         source_with_cached_data.GetCachedData();
21216     CHECK(new_cached_data != NULL);
21217     CHECK(!new_cached_data->rejected);
21218   }
21219   // Compile an incompatible script with the cached data. The new script doesn't
21220   // have the same starting position for the function as the old one, so the old
21221   // cached data will be incompatible with it and will be rejected.
21222   {
21223     v8::Local<v8::String> incompatible_source_str =
21224         v8_str("   function foo() {}");
21225     v8::ScriptCompiler::Source source_with_cached_data(
21226         incompatible_source_str, origin,
21227         new v8::ScriptCompiler::CachedData(original_cached_data->data,
21228                                            original_cached_data->length));
21229     v8::Handle<v8::Script> script =
21230         v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21231                                     v8::ScriptCompiler::kConsumeParserCache);
21232     CHECK(!script.IsEmpty());
21233     const v8::ScriptCompiler::CachedData* new_cached_data =
21234         source_with_cached_data.GetCachedData();
21235     CHECK(new_cached_data != NULL);
21236     CHECK(new_cached_data->rejected);
21237   }
21238 }
21239
21240
21241 TEST(StringConcatOverflow) {
21242   v8::V8::Initialize();
21243   v8::HandleScope scope(CcTest::isolate());
21244   RandomLengthOneByteResource* r =
21245       new RandomLengthOneByteResource(i::String::kMaxLength);
21246   v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
21247   CHECK(!str.IsEmpty());
21248   v8::TryCatch try_catch(CcTest::isolate());
21249   v8::Local<v8::String> result = v8::String::Concat(str, str);
21250   CHECK(result.IsEmpty());
21251   CHECK(!try_catch.HasCaught());
21252 }
21253
21254
21255 TEST(TurboAsmDisablesNeuter) {
21256   v8::V8::Initialize();
21257   v8::HandleScope scope(CcTest::isolate());
21258   LocalContext context;
21259 #if V8_TURBOFAN_TARGET
21260   bool should_be_neuterable = !i::FLAG_turbo_asm;
21261 #else
21262   bool should_be_neuterable = true;
21263 #endif
21264   const char* load =
21265       "function Module(stdlib, foreign, heap) {"
21266       "  'use asm';"
21267       "  var MEM32 = new stdlib.Int32Array(heap);"
21268       "  function load() { return MEM32[0]; }"
21269       "  return { load: load };"
21270       "}"
21271       "var buffer = new ArrayBuffer(4);"
21272       "Module(this, {}, buffer).load();"
21273       "buffer";
21274
21275   i::FLAG_turbo_osr = false;  // TODO(titzer): test requires eager TF.
21276   v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
21277   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21278
21279   const char* store =
21280       "function Module(stdlib, foreign, heap) {"
21281       "  'use asm';"
21282       "  var MEM32 = new stdlib.Int32Array(heap);"
21283       "  function store() { MEM32[0] = 0; }"
21284       "  return { store: store };"
21285       "}"
21286       "var buffer = new ArrayBuffer(4);"
21287       "Module(this, {}, buffer).store();"
21288       "buffer";
21289
21290   i::FLAG_turbo_osr = false;  // TODO(titzer): test requires eager TF.
21291   result = CompileRun(store).As<v8::ArrayBuffer>();
21292   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21293 }
21294
21295
21296 TEST(GetPrototypeAccessControl) {
21297   i::FLAG_allow_natives_syntax = true;
21298   v8::Isolate* isolate = CcTest::isolate();
21299   v8::HandleScope handle_scope(isolate);
21300   LocalContext env;
21301
21302   v8::Handle<v8::ObjectTemplate> obj_template =
21303       v8::ObjectTemplate::New(isolate);
21304   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
21305
21306   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
21307
21308   {
21309     v8::TryCatch try_catch(isolate);
21310     CompileRun(
21311         "function f() { %_GetPrototype(prohibited); }"
21312         "%OptimizeFunctionOnNextCall(f);"
21313         "f();");
21314     CHECK(try_catch.HasCaught());
21315   }
21316 }
21317
21318
21319 TEST(GetPrototypeHidden) {
21320   i::FLAG_allow_natives_syntax = true;
21321   v8::Isolate* isolate = CcTest::isolate();
21322   v8::HandleScope handle_scope(isolate);
21323   LocalContext env;
21324
21325   Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
21326   t->SetHiddenPrototype(true);
21327   Handle<Object> proto = t->GetFunction()->NewInstance();
21328   Handle<Object> object = Object::New(isolate);
21329   Handle<Object> proto2 = Object::New(isolate);
21330   object->SetPrototype(proto);
21331   proto->SetPrototype(proto2);
21332
21333   env->Global()->Set(v8_str("object"), object);
21334   env->Global()->Set(v8_str("proto"), proto);
21335   env->Global()->Set(v8_str("proto2"), proto2);
21336
21337   v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
21338   CHECK(result->Equals(proto2));
21339
21340   result = CompileRun(
21341       "function f() { return %_GetPrototype(object); }"
21342       "%OptimizeFunctionOnNextCall(f);"
21343       "f()");
21344   CHECK(result->Equals(proto2));
21345 }
21346
21347
21348 TEST(ClassPrototypeCreationContext) {
21349   v8::Isolate* isolate = CcTest::isolate();
21350   v8::HandleScope handle_scope(isolate);
21351   LocalContext env;
21352
21353   Handle<Object> result = Handle<Object>::Cast(
21354       CompileRun("'use strict'; class Example { }; Example.prototype"));
21355   CHECK(env.local() == result->CreationContext());
21356 }
21357
21358
21359 TEST(SimpleStreamingScriptWithSourceURL) {
21360   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
21361                           "//# sourceURL=bar2.js\n", NULL};
21362   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21363                    "bar2.js");
21364 }
21365
21366
21367 TEST(StreamingScriptWithSplitSourceURL) {
21368   const char* chunks[] = {"function foo() { ret", "urn 13; } f",
21369                           "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
21370   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21371                    "bar2.js");
21372 }
21373
21374
21375 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
21376   const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
21377                           " sourceMappingURL=bar2.js\n", "foo();", NULL};
21378   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
21379                    "bar2.js");
21380 }
21381
21382
21383 TEST(NewStringRangeError) {
21384   v8::Isolate* isolate = CcTest::isolate();
21385   v8::HandleScope handle_scope(isolate);
21386   const int length = i::String::kMaxLength + 1;
21387   const int buffer_size = length * sizeof(uint16_t);
21388   void* buffer = malloc(buffer_size);
21389   if (buffer == NULL) return;
21390   memset(buffer, 'A', buffer_size);
21391   {
21392     v8::TryCatch try_catch(isolate);
21393     char* data = reinterpret_cast<char*>(buffer);
21394     CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
21395                                   length).IsEmpty());
21396     CHECK(!try_catch.HasCaught());
21397   }
21398   {
21399     v8::TryCatch try_catch(isolate);
21400     uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
21401     CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
21402                                      length).IsEmpty());
21403     CHECK(!try_catch.HasCaught());
21404   }
21405   {
21406     v8::TryCatch try_catch(isolate);
21407     uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
21408     CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
21409                                      length).IsEmpty());
21410     CHECK(!try_catch.HasCaught());
21411   }
21412   free(buffer);
21413 }
21414
21415
21416 TEST(SealHandleScope) {
21417   v8::Isolate* isolate = CcTest::isolate();
21418   v8::HandleScope handle_scope(isolate);
21419   LocalContext env;
21420
21421   v8::SealHandleScope seal(isolate);
21422
21423   // Should fail
21424   v8::Local<v8::Object> obj = v8::Object::New(isolate);
21425
21426   USE(obj);
21427 }
21428
21429
21430 TEST(SealHandleScopeNested) {
21431   v8::Isolate* isolate = CcTest::isolate();
21432   v8::HandleScope handle_scope(isolate);
21433   LocalContext env;
21434
21435   v8::SealHandleScope seal(isolate);
21436
21437   {
21438     v8::HandleScope handle_scope(isolate);
21439
21440     // Should work
21441     v8::Local<v8::Object> obj = v8::Object::New(isolate);
21442
21443     USE(obj);
21444   }
21445 }
21446
21447
21448 static bool access_was_called = false;
21449
21450
21451 static bool AccessAlwaysAllowedWithFlag(Local<v8::Object> global,
21452                                         Local<Value> name, v8::AccessType type,
21453                                         Local<Value> data) {
21454   access_was_called = true;
21455   return true;
21456 }
21457
21458
21459 static bool AccessAlwaysBlockedWithFlag(Local<v8::Object> global,
21460                                         Local<Value> name, v8::AccessType type,
21461                                         Local<Value> data) {
21462   access_was_called = true;
21463   return false;
21464 }
21465
21466
21467 TEST(StrongModeAccessCheckAllowed) {
21468   i::FLAG_strong_mode = true;
21469   v8::Isolate* isolate = CcTest::isolate();
21470   v8::HandleScope handle_scope(isolate);
21471   v8::Handle<Value> value;
21472   access_was_called = false;
21473
21474   v8::Handle<v8::ObjectTemplate> obj_template =
21475       v8::ObjectTemplate::New(isolate);
21476
21477   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
21478   obj_template->SetAccessCheckCallbacks(AccessAlwaysAllowedWithFlag, NULL);
21479
21480   // Create an environment
21481   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
21482   context0->Enter();
21483   v8::Handle<v8::Object> global0 = context0->Global();
21484   global0->Set(v8_str("object"), obj_template->NewInstance());
21485   {
21486     v8::TryCatch try_catch(isolate);
21487     value = CompileRun("'use strong'; object.x");
21488     CHECK(!try_catch.HasCaught());
21489     CHECK(!access_was_called);
21490     CHECK_EQ(42, value->Int32Value());
21491   }
21492   {
21493     v8::TryCatch try_catch(isolate);
21494     value = CompileRun("'use strong'; object.foo");
21495     CHECK(try_catch.HasCaught());
21496     CHECK(!access_was_called);
21497   }
21498   {
21499     v8::TryCatch try_catch(isolate);
21500     value = CompileRun("'use strong'; object[10]");
21501     CHECK(try_catch.HasCaught());
21502     CHECK(!access_was_called);
21503   }
21504
21505   // Create an environment
21506   v8::Local<Context> context1 = Context::New(isolate);
21507   context1->Enter();
21508   v8::Handle<v8::Object> global1 = context1->Global();
21509   global1->Set(v8_str("object"), obj_template->NewInstance());
21510   {
21511     v8::TryCatch try_catch(isolate);
21512     value = CompileRun("'use strong'; object.x");
21513     CHECK(!try_catch.HasCaught());
21514     CHECK(access_was_called);
21515     CHECK_EQ(42, value->Int32Value());
21516   }
21517   access_was_called = false;
21518   {
21519     v8::TryCatch try_catch(isolate);
21520     value = CompileRun("'use strong'; object.foo");
21521     CHECK(try_catch.HasCaught());
21522     CHECK(access_was_called);
21523   }
21524   access_was_called = false;
21525   {
21526     v8::TryCatch try_catch(isolate);
21527     value = CompileRun("'use strong'; object[10]");
21528     CHECK(try_catch.HasCaught());
21529     CHECK(access_was_called);
21530   }
21531
21532   context1->Exit();
21533   context0->Exit();
21534 }
21535
21536
21537 TEST(StrongModeAccessCheckBlocked) {
21538   i::FLAG_strong_mode = true;
21539   v8::Isolate* isolate = CcTest::isolate();
21540   v8::HandleScope handle_scope(isolate);
21541   v8::Handle<Value> value;
21542   access_was_called = false;
21543
21544   v8::Handle<v8::ObjectTemplate> obj_template =
21545       v8::ObjectTemplate::New(isolate);
21546
21547   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
21548   obj_template->SetAccessCheckCallbacks(AccessAlwaysBlockedWithFlag, NULL);
21549
21550   // Create an environment
21551   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
21552   context0->Enter();
21553   v8::Handle<v8::Object> global0 = context0->Global();
21554   global0->Set(v8_str("object"), obj_template->NewInstance());
21555   {
21556     v8::TryCatch try_catch(isolate);
21557     value = CompileRun("'use strong'; object.x");
21558     CHECK(!try_catch.HasCaught());
21559     CHECK(!access_was_called);
21560     CHECK_EQ(42, value->Int32Value());
21561   }
21562   {
21563     v8::TryCatch try_catch(isolate);
21564     value = CompileRun("'use strong'; object.foo");
21565     CHECK(try_catch.HasCaught());
21566     CHECK(!access_was_called);
21567   }
21568   {
21569     v8::TryCatch try_catch(isolate);
21570     value = CompileRun("'use strong'; object[10]");
21571     CHECK(try_catch.HasCaught());
21572     CHECK(!access_was_called);
21573   }
21574
21575   // Create an environment
21576   v8::Local<Context> context1 = Context::New(isolate);
21577   context1->Enter();
21578   v8::Handle<v8::Object> global1 = context1->Global();
21579   global1->Set(v8_str("object"), obj_template->NewInstance());
21580   {
21581     v8::TryCatch try_catch(isolate);
21582     value = CompileRun("'use strong'; object.x");
21583     CHECK(try_catch.HasCaught());
21584     CHECK(access_was_called);
21585   }
21586   access_was_called = false;
21587   {
21588     v8::TryCatch try_catch(isolate);
21589     value = CompileRun("'use strong'; object.foo");
21590     CHECK(try_catch.HasCaught());
21591     CHECK(access_was_called);
21592   }
21593   access_was_called = false;
21594   {
21595     v8::TryCatch try_catch(isolate);
21596     value = CompileRun("'use strong'; object[10]");
21597     CHECK(try_catch.HasCaught());
21598     CHECK(access_was_called);
21599   }
21600
21601   context1->Exit();
21602   context0->Exit();
21603 }
21604
21605
21606 TEST(StrongModeArityCallFromApi) {
21607   i::FLAG_strong_mode = true;
21608   LocalContext env;
21609   v8::Isolate* isolate = env->GetIsolate();
21610   v8::HandleScope scope(isolate);
21611   Local<Function> fun;
21612   {
21613     v8::TryCatch try_catch(isolate);
21614     fun = Local<Function>::Cast(CompileRun(
21615         "function f(x) { 'use strong'; }"
21616         "f"));
21617
21618     CHECK(!try_catch.HasCaught());
21619   }
21620
21621   {
21622     v8::TryCatch try_catch(isolate);
21623     fun->Call(v8::Undefined(isolate), 0, nullptr);
21624     CHECK(try_catch.HasCaught());
21625   }
21626
21627   {
21628     v8::TryCatch try_catch(isolate);
21629     v8::Handle<Value> args[] = {v8_num(42)};
21630     fun->Call(v8::Undefined(isolate), arraysize(args), args);
21631     CHECK(!try_catch.HasCaught());
21632   }
21633
21634   {
21635     v8::TryCatch try_catch(isolate);
21636     v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
21637     fun->Call(v8::Undefined(isolate), arraysize(args), args);
21638     CHECK(!try_catch.HasCaught());
21639   }
21640 }
21641
21642
21643 TEST(StrongModeArityCallFromApi2) {
21644   i::FLAG_strong_mode = true;
21645   LocalContext env;
21646   v8::Isolate* isolate = env->GetIsolate();
21647   v8::HandleScope scope(isolate);
21648   Local<Function> fun;
21649   {
21650     v8::TryCatch try_catch(isolate);
21651     fun = Local<Function>::Cast(CompileRun(
21652         "'use strong';"
21653         "function f(x) {}"
21654         "f"));
21655
21656     CHECK(!try_catch.HasCaught());
21657   }
21658
21659   {
21660     v8::TryCatch try_catch(isolate);
21661     fun->Call(v8::Undefined(isolate), 0, nullptr);
21662     CHECK(try_catch.HasCaught());
21663   }
21664
21665   {
21666     v8::TryCatch try_catch(isolate);
21667     v8::Handle<Value> args[] = {v8_num(42)};
21668     fun->Call(v8::Undefined(isolate), arraysize(args), args);
21669     CHECK(!try_catch.HasCaught());
21670   }
21671
21672   {
21673     v8::TryCatch try_catch(isolate);
21674     v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
21675     fun->Call(v8::Undefined(isolate), arraysize(args), args);
21676     CHECK(!try_catch.HasCaught());
21677   }
21678 }
21679
21680
21681 TEST(StrongObjectDelete) {
21682   i::FLAG_strong_mode = true;
21683   LocalContext env;
21684   v8::Isolate* isolate = env->GetIsolate();
21685   v8::HandleScope scope(isolate);
21686   Local<Object> obj;
21687   {
21688     v8::TryCatch try_catch;
21689     obj = Local<Object>::Cast(CompileRun(
21690         "'use strong';"
21691         "({});"));
21692     CHECK(!try_catch.HasCaught());
21693   }
21694   obj->ForceSet(v8_str("foo"), v8_num(1), v8::None);
21695   obj->ForceSet(v8_str("2"), v8_num(1), v8::None);
21696   CHECK(obj->HasOwnProperty(v8_str("foo")));
21697   CHECK(obj->HasOwnProperty(v8_str("2")));
21698   CHECK(!obj->Delete(v8_str("foo")));
21699   CHECK(!obj->Delete(2));
21700 }
21701
21702
21703 static void ExtrasExportsTestRuntimeFunction(
21704     const v8::FunctionCallbackInfo<v8::Value>& args) {
21705   CHECK_EQ(3, args[0]->Int32Value());
21706   args.GetReturnValue().Set(v8_num(7));
21707 }
21708
21709
21710 TEST(ExtrasExportsObject) {
21711   v8::Isolate* isolate = CcTest::isolate();
21712   v8::HandleScope handle_scope(isolate);
21713   LocalContext env;
21714
21715   // standalone.gypi ensures we include the test-extra.js file, which should
21716   // export the tested functions.
21717   v8::Local<v8::Object> exports = env->GetExtrasExportsObject();
21718
21719   auto func =
21720       exports->Get(v8_str("testExtraShouldReturnFive")).As<v8::Function>();
21721   auto undefined = v8::Undefined(isolate);
21722   auto result = func->Call(undefined, 0, {}).As<v8::Number>();
21723   CHECK_EQ(5, result->Int32Value());
21724
21725   v8::Handle<v8::FunctionTemplate> runtimeFunction =
21726       v8::FunctionTemplate::New(isolate, ExtrasExportsTestRuntimeFunction);
21727   exports->Set(v8_str("runtime"), runtimeFunction->GetFunction());
21728   func =
21729       exports->Get(v8_str("testExtraShouldCallToRuntime")).As<v8::Function>();
21730   result = func->Call(undefined, 0, {}).As<v8::Number>();
21731   CHECK_EQ(7, result->Int32Value());
21732 }
21733
21734
21735 TEST(Map) {
21736   v8::Isolate* isolate = CcTest::isolate();
21737   v8::HandleScope handle_scope(isolate);
21738   LocalContext env;
21739
21740   v8::Local<v8::Map> map = v8::Map::New(isolate);
21741   CHECK(map->IsObject());
21742   CHECK(map->IsMap());
21743   CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
21744   CHECK_EQ(0U, map->Size());
21745
21746   v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
21747   CHECK(val->IsMap());
21748   map = v8::Local<v8::Map>::Cast(val);
21749   CHECK_EQ(2U, map->Size());
21750
21751   v8::Local<v8::Array> contents = map->AsArray();
21752   CHECK_EQ(4U, contents->Length());
21753   CHECK_EQ(1, contents->Get(0).As<v8::Int32>()->Value());
21754   CHECK_EQ(2, contents->Get(1).As<v8::Int32>()->Value());
21755   CHECK_EQ(3, contents->Get(2).As<v8::Int32>()->Value());
21756   CHECK_EQ(4, contents->Get(3).As<v8::Int32>()->Value());
21757
21758   map = v8::Map::FromArray(env.local(), contents).ToLocalChecked();
21759   CHECK_EQ(2U, map->Size());
21760
21761   CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
21762   CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
21763
21764   CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
21765   CHECK(!map->Has(env.local(), map).FromJust());
21766
21767   CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
21768                   .ToLocalChecked()
21769                   ->Int32Value());
21770   CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
21771                   .ToLocalChecked()
21772                   ->Int32Value());
21773
21774   CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
21775             .ToLocalChecked()
21776             ->IsUndefined());
21777
21778   CHECK(!map->Set(env.local(), map, map).IsEmpty());
21779   CHECK_EQ(3U, map->Size());
21780   CHECK(map->Has(env.local(), map).FromJust());
21781
21782   CHECK(map->Delete(env.local(), map).FromJust());
21783   CHECK_EQ(2U, map->Size());
21784   CHECK(!map->Has(env.local(), map).FromJust());
21785   CHECK(!map->Delete(env.local(), map).FromJust());
21786
21787   map->Clear();
21788   CHECK_EQ(0U, map->Size());
21789 }
21790
21791
21792 TEST(MapFromArrayOddLength) {
21793   v8::Isolate* isolate = CcTest::isolate();
21794   v8::HandleScope handle_scope(isolate);
21795   LocalContext env;
21796   // Odd lengths result in a null MaybeLocal.
21797   Local<v8::Array> contents = v8::Array::New(isolate, 41);
21798   CHECK(v8::Map::FromArray(env.local(), contents).IsEmpty());
21799 }
21800
21801
21802 TEST(Set) {
21803   v8::Isolate* isolate = CcTest::isolate();
21804   v8::HandleScope handle_scope(isolate);
21805   LocalContext env;
21806
21807   v8::Local<v8::Set> set = v8::Set::New(isolate);
21808   CHECK(set->IsObject());
21809   CHECK(set->IsSet());
21810   CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
21811   CHECK_EQ(0U, set->Size());
21812
21813   v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
21814   CHECK(val->IsSet());
21815   set = v8::Local<v8::Set>::Cast(val);
21816   CHECK_EQ(2U, set->Size());
21817
21818   v8::Local<v8::Array> keys = set->AsArray();
21819   CHECK_EQ(2U, keys->Length());
21820   CHECK_EQ(1, keys->Get(0).As<v8::Int32>()->Value());
21821   CHECK_EQ(2, keys->Get(1).As<v8::Int32>()->Value());
21822
21823   set = v8::Set::FromArray(env.local(), keys).ToLocalChecked();
21824   CHECK_EQ(2U, set->Size());
21825
21826   CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
21827   CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
21828
21829   CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
21830   CHECK(!set->Has(env.local(), set).FromJust());
21831
21832   CHECK(!set->Add(env.local(), set).IsEmpty());
21833   CHECK_EQ(3U, set->Size());
21834   CHECK(set->Has(env.local(), set).FromJust());
21835
21836   CHECK(set->Delete(env.local(), set).FromJust());
21837   CHECK_EQ(2U, set->Size());
21838   CHECK(!set->Has(env.local(), set).FromJust());
21839   CHECK(!set->Delete(env.local(), set).FromJust());
21840
21841   set->Clear();
21842   CHECK_EQ(0U, set->Size());
21843 }
21844
21845
21846 TEST(CompatibleReceiverCheckOnCachedICHandler) {
21847   v8::Isolate* isolate = CcTest::isolate();
21848   v8::HandleScope scope(isolate);
21849   v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
21850   v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
21851   auto returns_42 =
21852       v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
21853   parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
21854   v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
21855   child->Inherit(parent);
21856   LocalContext env;
21857   env->Global()->Set(v8_str("Child"), child->GetFunction());
21858
21859   // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
21860   CompileRun(
21861       "var real = new Child();\n"
21862       "for (var i = 0; i < 3; ++i) {\n"
21863       "  real.age;\n"
21864       "}\n");
21865
21866   // Check that the cached stub is never used.
21867   ExpectInt32(
21868       "var fake = Object.create(Child.prototype);\n"
21869       "var result = 0;\n"
21870       "function test(d) {\n"
21871       "  if (d == 3) return;\n"
21872       "  try {\n"
21873       "    fake.age;\n"
21874       "    result = 1;\n"
21875       "  } catch (e) {\n"
21876       "  }\n"
21877       "  test(d+1);\n"
21878       "}\n"
21879       "test(0);\n"
21880       "result;\n",
21881       0);
21882 }
21883
21884
21885 static int nb_uncaught_exception_callback_calls = 0;
21886
21887
21888 bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
21889   ++nb_uncaught_exception_callback_calls;
21890   return false;
21891 }
21892
21893
21894 TEST(AbortOnUncaughtExceptionNoAbort) {
21895   v8::Isolate* isolate = CcTest::isolate();
21896   v8::HandleScope handle_scope(isolate);
21897   v8::Handle<v8::ObjectTemplate> global_template =
21898       v8::ObjectTemplate::New(isolate);
21899   LocalContext env(NULL, global_template);
21900
21901   i::FLAG_abort_on_uncaught_exception = true;
21902   isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
21903
21904   CompileRun("function boom() { throw new Error(\"boom\") }");
21905
21906   v8::Local<v8::Object> global_object = env->Global();
21907   v8::Local<v8::Function> foo =
21908       v8::Local<v8::Function>::Cast(global_object->Get(v8_str("boom")));
21909
21910   foo->Call(global_object, 0, NULL);
21911
21912   CHECK_EQ(1, nb_uncaught_exception_callback_calls);
21913 }