Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / 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 <string>
31 #include <map>
32
33 #include "src/v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "include/v8-util.h"
40 #include "src/api.h"
41 #include "src/arguments.h"
42 #include "src/compilation-cache.h"
43 #include "src/cpu-profiler.h"
44 #include "src/execution.h"
45 #include "src/isolate.h"
46 #include "src/objects.h"
47 #include "src/parser.h"
48 #include "src/platform.h"
49 #include "src/snapshot.h"
50 #include "src/unicode-inl.h"
51 #include "src/utils.h"
52 #include "src/vm-state.h"
53 #include "test/cctest/cctest.h"
54
55 static const bool kLogThreading = false;
56
57 using ::v8::Boolean;
58 using ::v8::BooleanObject;
59 using ::v8::Context;
60 using ::v8::Extension;
61 using ::v8::Function;
62 using ::v8::FunctionTemplate;
63 using ::v8::Handle;
64 using ::v8::HandleScope;
65 using ::v8::Local;
66 using ::v8::Message;
67 using ::v8::MessageCallback;
68 using ::v8::Object;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
71 using ::v8::Script;
72 using ::v8::StackTrace;
73 using ::v8::String;
74 using ::v8::TryCatch;
75 using ::v8::Undefined;
76 using ::v8::UniqueId;
77 using ::v8::V8;
78 using ::v8::Value;
79
80
81 #define THREADED_PROFILED_TEST(Name)                                 \
82   static void Test##Name();                                          \
83   TEST(Name##WithProfiler) {                                         \
84     RunWithProfiler(&Test##Name);                                    \
85   }                                                                  \
86   THREADED_TEST(Name)
87
88
89 void RunWithProfiler(void (*test)()) {
90   LocalContext env;
91   v8::HandleScope scope(env->GetIsolate());
92   v8::Local<v8::String> profile_name =
93       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
95
96   cpu_profiler->StartProfiling(profile_name);
97   (*test)();
98   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
99 }
100
101
102 static int signature_callback_count;
103 static Local<Value> signature_expected_receiver;
104 static void IncrementingSignatureCallback(
105     const v8::FunctionCallbackInfo<v8::Value>& args) {
106   ApiTestFuzzer::Fuzz();
107   signature_callback_count++;
108   CHECK_EQ(signature_expected_receiver, args.Holder());
109   CHECK_EQ(signature_expected_receiver, args.This());
110   v8::Handle<v8::Array> result =
111       v8::Array::New(args.GetIsolate(), args.Length());
112   for (int i = 0; i < args.Length(); i++)
113     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
114   args.GetReturnValue().Set(result);
115 }
116
117
118 static void SignatureCallback(
119     const v8::FunctionCallbackInfo<v8::Value>& args) {
120   ApiTestFuzzer::Fuzz();
121   v8::Handle<v8::Array> result =
122       v8::Array::New(args.GetIsolate(), args.Length());
123   for (int i = 0; i < args.Length(); i++) {
124     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
125   }
126   args.GetReturnValue().Set(result);
127 }
128
129
130 // Tests that call v8::V8::Dispose() cannot be threaded.
131 TEST(InitializeAndDisposeOnce) {
132   CHECK(v8::V8::Initialize());
133   CHECK(v8::V8::Dispose());
134 }
135
136
137 // Tests that call v8::V8::Dispose() cannot be threaded.
138 TEST(InitializeAndDisposeMultiple) {
139   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
140   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142   // TODO(mstarzinger): This should fail gracefully instead of asserting.
143   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
145 }
146
147
148 THREADED_TEST(Handles) {
149   v8::HandleScope scope(CcTest::isolate());
150   Local<Context> local_env;
151   {
152     LocalContext env;
153     local_env = env.local();
154   }
155
156   // Local context should still be live.
157   CHECK(!local_env.IsEmpty());
158   local_env->Enter();
159
160   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
161   CHECK(!undef.IsEmpty());
162   CHECK(undef->IsUndefined());
163
164   const char* source = "1 + 2 + 3";
165   Local<Script> script = v8_compile(source);
166   CHECK_EQ(6, script->Run()->Int32Value());
167
168   local_env->Exit();
169 }
170
171
172 THREADED_TEST(IsolateOfContext) {
173   v8::HandleScope scope(CcTest::isolate());
174   v8::Handle<Context> env = Context::New(CcTest::isolate());
175
176   CHECK(!env->GetIsolate()->InContext());
177   CHECK(env->GetIsolate() == CcTest::isolate());
178   env->Enter();
179   CHECK(env->GetIsolate()->InContext());
180   CHECK(env->GetIsolate() == CcTest::isolate());
181   env->Exit();
182   CHECK(!env->GetIsolate()->InContext());
183   CHECK(env->GetIsolate() == CcTest::isolate());
184 }
185
186
187 static void TestSignature(const char* loop_js, Local<Value> receiver) {
188   i::ScopedVector<char> source(200);
189   i::SNPrintF(source,
190               "for (var i = 0; i < 10; i++) {"
191               "  %s"
192               "}",
193               loop_js);
194   signature_callback_count = 0;
195   signature_expected_receiver = receiver;
196   bool expected_to_throw = receiver.IsEmpty();
197   v8::TryCatch try_catch;
198   CompileRun(source.start());
199   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
200   if (!expected_to_throw) {
201     CHECK_EQ(10, signature_callback_count);
202   } else {
203     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
204              try_catch.Exception()->ToString());
205   }
206 }
207
208
209 THREADED_TEST(ReceiverSignature) {
210   LocalContext env;
211   v8::Isolate* isolate = env->GetIsolate();
212   v8::HandleScope scope(isolate);
213   // Setup templates.
214   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
215   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
216   v8::Handle<v8::FunctionTemplate> callback_sig =
217       v8::FunctionTemplate::New(
218           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
219   v8::Handle<v8::FunctionTemplate> callback =
220       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
221   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
222   sub_fun->Inherit(fun);
223   v8::Handle<v8::FunctionTemplate> unrel_fun =
224       v8::FunctionTemplate::New(isolate);
225   // Install properties.
226   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
227   fun_proto->Set(v8_str("prop_sig"), callback_sig);
228   fun_proto->Set(v8_str("prop"), callback);
229   fun_proto->SetAccessorProperty(
230       v8_str("accessor_sig"), callback_sig, callback_sig);
231   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
232   // Instantiate templates.
233   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
234   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
235   // Setup global variables.
236   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
237   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
238   env->Global()->Set(v8_str("fun_instance"), fun_instance);
239   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
240   CompileRun(
241       "var accessor_sig_key = 'accessor_sig';"
242       "var accessor_key = 'accessor';"
243       "var prop_sig_key = 'prop_sig';"
244       "var prop_key = 'prop';"
245       ""
246       "function copy_props(obj) {"
247       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
248       "  var source = Fun.prototype;"
249       "  for (var i in keys) {"
250       "    var key = keys[i];"
251       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
252       "    Object.defineProperty(obj, key, desc);"
253       "  }"
254       "}"
255       ""
256       "var obj = {};"
257       "copy_props(obj);"
258       "var unrel = new UnrelFun();"
259       "copy_props(unrel);");
260   // Test with and without ICs
261   const char* test_objects[] = {
262       "fun_instance", "sub_fun_instance", "obj", "unrel" };
263   unsigned bad_signature_start_offset = 2;
264   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
265     i::ScopedVector<char> source(200);
266     i::SNPrintF(
267         source, "var test_object = %s; test_object", test_objects[i]);
268     Local<Value> test_object = CompileRun(source.start());
269     TestSignature("test_object.prop();", test_object);
270     TestSignature("test_object.accessor;", test_object);
271     TestSignature("test_object[accessor_key];", test_object);
272     TestSignature("test_object.accessor = 1;", test_object);
273     TestSignature("test_object[accessor_key] = 1;", test_object);
274     if (i >= bad_signature_start_offset) test_object = Local<Value>();
275     TestSignature("test_object.prop_sig();", test_object);
276     TestSignature("test_object.accessor_sig;", test_object);
277     TestSignature("test_object[accessor_sig_key];", test_object);
278     TestSignature("test_object.accessor_sig = 1;", test_object);
279     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
280   }
281 }
282
283
284 THREADED_TEST(ArgumentSignature) {
285   LocalContext env;
286   v8::Isolate* isolate = env->GetIsolate();
287   v8::HandleScope scope(isolate);
288   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
289   cons->SetClassName(v8_str("Cons"));
290   v8::Handle<v8::Signature> sig = v8::Signature::New(
291       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
292   v8::Handle<v8::FunctionTemplate> fun =
293       v8::FunctionTemplate::New(isolate,
294                                 SignatureCallback,
295                                 v8::Handle<Value>(),
296                                 sig);
297   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
298   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
299
300   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
301   CHECK(value1->IsTrue());
302
303   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
304   CHECK(value2->IsTrue());
305
306   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
307   CHECK(value3->IsTrue());
308
309   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
310   cons1->SetClassName(v8_str("Cons1"));
311   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
312   cons2->SetClassName(v8_str("Cons2"));
313   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
314   cons3->SetClassName(v8_str("Cons3"));
315
316   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
317   v8::Handle<v8::Signature> wsig = v8::Signature::New(
318       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
319   v8::Handle<v8::FunctionTemplate> fun2 =
320       v8::FunctionTemplate::New(isolate,
321                                 SignatureCallback,
322                                 v8::Handle<Value>(),
323                                 wsig);
324
325   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
326   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
327   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
328   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
329   v8::Handle<Value> value4 = CompileRun(
330       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
331       "'[object Cons1],[object Cons2],[object Cons3]'");
332   CHECK(value4->IsTrue());
333
334   v8::Handle<Value> value5 = CompileRun(
335       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
336   CHECK(value5->IsTrue());
337
338   v8::Handle<Value> value6 = CompileRun(
339       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
340   CHECK(value6->IsTrue());
341
342   v8::Handle<Value> value7 = CompileRun(
343       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
344       "'[object Cons1],[object Cons2],[object Cons3],d';");
345   CHECK(value7->IsTrue());
346
347   v8::Handle<Value> value8 = CompileRun(
348       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
349   CHECK(value8->IsTrue());
350 }
351
352
353 THREADED_TEST(HulIgennem) {
354   LocalContext env;
355   v8::Isolate* isolate = env->GetIsolate();
356   v8::HandleScope scope(isolate);
357   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
358   Local<String> undef_str = undef->ToString();
359   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
360   undef_str->WriteUtf8(value);
361   CHECK_EQ(0, strcmp(value, "undefined"));
362   i::DeleteArray(value);
363 }
364
365
366 THREADED_TEST(Access) {
367   LocalContext env;
368   v8::Isolate* isolate = env->GetIsolate();
369   v8::HandleScope scope(isolate);
370   Local<v8::Object> obj = v8::Object::New(isolate);
371   Local<Value> foo_before = obj->Get(v8_str("foo"));
372   CHECK(foo_before->IsUndefined());
373   Local<String> bar_str = v8_str("bar");
374   obj->Set(v8_str("foo"), bar_str);
375   Local<Value> foo_after = obj->Get(v8_str("foo"));
376   CHECK(!foo_after->IsUndefined());
377   CHECK(foo_after->IsString());
378   CHECK_EQ(bar_str, foo_after);
379 }
380
381
382 THREADED_TEST(AccessElement) {
383   LocalContext env;
384   v8::HandleScope scope(env->GetIsolate());
385   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
386   Local<Value> before = obj->Get(1);
387   CHECK(before->IsUndefined());
388   Local<String> bar_str = v8_str("bar");
389   obj->Set(1, bar_str);
390   Local<Value> after = obj->Get(1);
391   CHECK(!after->IsUndefined());
392   CHECK(after->IsString());
393   CHECK_EQ(bar_str, after);
394
395   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
396   CHECK_EQ(v8_str("a"), value->Get(0));
397   CHECK_EQ(v8_str("b"), value->Get(1));
398 }
399
400
401 THREADED_TEST(Script) {
402   LocalContext env;
403   v8::HandleScope scope(env->GetIsolate());
404   const char* source = "1 + 2 + 3";
405   Local<Script> script = v8_compile(source);
406   CHECK_EQ(6, script->Run()->Int32Value());
407 }
408
409
410 class TestResource: public String::ExternalStringResource {
411  public:
412   TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
413       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
414     while (data[length_]) ++length_;
415   }
416
417   ~TestResource() {
418     if (owning_data_) i::DeleteArray(data_);
419     if (counter_ != NULL) ++*counter_;
420   }
421
422   const uint16_t* data() const {
423     return data_;
424   }
425
426   size_t length() const {
427     return length_;
428   }
429
430  private:
431   uint16_t* data_;
432   size_t length_;
433   int* counter_;
434   bool owning_data_;
435 };
436
437
438 class TestAsciiResource: public String::ExternalAsciiStringResource {
439  public:
440   TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
441       : orig_data_(data),
442         data_(data + offset),
443         length_(strlen(data) - offset),
444         counter_(counter) { }
445
446   ~TestAsciiResource() {
447     i::DeleteArray(orig_data_);
448     if (counter_ != NULL) ++*counter_;
449   }
450
451   const char* data() const {
452     return data_;
453   }
454
455   size_t length() const {
456     return length_;
457   }
458
459  private:
460   const char* orig_data_;
461   const char* data_;
462   size_t length_;
463   int* counter_;
464 };
465
466
467 THREADED_TEST(ScriptUsingStringResource) {
468   int dispose_count = 0;
469   const char* c_source = "1 + 2 * 3";
470   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
471   {
472     LocalContext env;
473     v8::HandleScope scope(env->GetIsolate());
474     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
475     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
476     Local<Script> script = v8_compile(source);
477     Local<Value> value = script->Run();
478     CHECK(value->IsNumber());
479     CHECK_EQ(7, value->Int32Value());
480     CHECK(source->IsExternal());
481     CHECK_EQ(resource,
482              static_cast<TestResource*>(source->GetExternalStringResource()));
483     String::Encoding encoding = String::UNKNOWN_ENCODING;
484     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
485              source->GetExternalStringResourceBase(&encoding));
486     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
487     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
488     CHECK_EQ(0, dispose_count);
489   }
490   CcTest::i_isolate()->compilation_cache()->Clear();
491   CcTest::heap()->CollectAllAvailableGarbage();
492   CHECK_EQ(1, dispose_count);
493 }
494
495
496 THREADED_TEST(ScriptUsingAsciiStringResource) {
497   int dispose_count = 0;
498   const char* c_source = "1 + 2 * 3";
499   {
500     LocalContext env;
501     v8::HandleScope scope(env->GetIsolate());
502     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
503                                                         &dispose_count);
504     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
505     CHECK(source->IsExternalAscii());
506     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
507              source->GetExternalAsciiStringResource());
508     String::Encoding encoding = String::UNKNOWN_ENCODING;
509     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510              source->GetExternalStringResourceBase(&encoding));
511     CHECK_EQ(String::ASCII_ENCODING, encoding);
512     Local<Script> script = v8_compile(source);
513     Local<Value> value = script->Run();
514     CHECK(value->IsNumber());
515     CHECK_EQ(7, value->Int32Value());
516     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
517     CHECK_EQ(0, dispose_count);
518   }
519   CcTest::i_isolate()->compilation_cache()->Clear();
520   CcTest::heap()->CollectAllAvailableGarbage();
521   CHECK_EQ(1, dispose_count);
522 }
523
524
525 THREADED_TEST(ScriptMakingExternalString) {
526   int dispose_count = 0;
527   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
528   {
529     LocalContext env;
530     v8::HandleScope scope(env->GetIsolate());
531     Local<String> source =
532         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
533     // Trigger GCs so that the newly allocated string moves to old gen.
534     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
535     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
536     CHECK_EQ(source->IsExternal(), false);
537     CHECK_EQ(source->IsExternalAscii(), false);
538     String::Encoding encoding = String::UNKNOWN_ENCODING;
539     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
540     CHECK_EQ(String::ASCII_ENCODING, encoding);
541     bool success = source->MakeExternal(new TestResource(two_byte_source,
542                                                          &dispose_count));
543     CHECK(success);
544     Local<Script> script = v8_compile(source);
545     Local<Value> value = script->Run();
546     CHECK(value->IsNumber());
547     CHECK_EQ(7, value->Int32Value());
548     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
549     CHECK_EQ(0, dispose_count);
550   }
551   CcTest::i_isolate()->compilation_cache()->Clear();
552   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
553   CHECK_EQ(1, dispose_count);
554 }
555
556
557 THREADED_TEST(ScriptMakingExternalAsciiString) {
558   int dispose_count = 0;
559   const char* c_source = "1 + 2 * 3";
560   {
561     LocalContext env;
562     v8::HandleScope scope(env->GetIsolate());
563     Local<String> source = v8_str(c_source);
564     // Trigger GCs so that the newly allocated string moves to old gen.
565     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
566     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
567     bool success = source->MakeExternal(
568         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
569     CHECK(success);
570     Local<Script> script = v8_compile(source);
571     Local<Value> value = script->Run();
572     CHECK(value->IsNumber());
573     CHECK_EQ(7, value->Int32Value());
574     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
575     CHECK_EQ(0, dispose_count);
576   }
577   CcTest::i_isolate()->compilation_cache()->Clear();
578   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
579   CHECK_EQ(1, dispose_count);
580 }
581
582
583 TEST(MakingExternalStringConditions) {
584   LocalContext env;
585   v8::HandleScope scope(env->GetIsolate());
586
587   // Free some space in the new space so that we can check freshness.
588   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
589   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
590
591   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
592   Local<String> small_string =
593       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
594   i::DeleteArray(two_byte_string);
595
596   // We should refuse to externalize newly created small string.
597   CHECK(!small_string->CanMakeExternal());
598   // Trigger GCs so that the newly allocated string moves to old gen.
599   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
600   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
601   // Old space strings should be accepted.
602   CHECK(small_string->CanMakeExternal());
603
604   two_byte_string = AsciiToTwoByteString("small string 2");
605   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
606   i::DeleteArray(two_byte_string);
607
608   // We should refuse externalizing newly created small string.
609   CHECK(!small_string->CanMakeExternal());
610   for (int i = 0; i < 100; i++) {
611     String::Value value(small_string);
612   }
613   // Frequently used strings should be accepted.
614   CHECK(small_string->CanMakeExternal());
615
616   const int buf_size = 10 * 1024;
617   char* buf = i::NewArray<char>(buf_size);
618   memset(buf, 'a', buf_size);
619   buf[buf_size - 1] = '\0';
620
621   two_byte_string = AsciiToTwoByteString(buf);
622   Local<String> large_string =
623       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
624   i::DeleteArray(buf);
625   i::DeleteArray(two_byte_string);
626   // Large strings should be immediately accepted.
627   CHECK(large_string->CanMakeExternal());
628 }
629
630
631 TEST(MakingExternalAsciiStringConditions) {
632   LocalContext env;
633   v8::HandleScope scope(env->GetIsolate());
634
635   // Free some space in the new space so that we can check freshness.
636   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
637   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
638
639   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
640   // We should refuse to externalize newly created small string.
641   CHECK(!small_string->CanMakeExternal());
642   // Trigger GCs so that the newly allocated string moves to old gen.
643   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
644   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
645   // Old space strings should be accepted.
646   CHECK(small_string->CanMakeExternal());
647
648   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
649   // We should refuse externalizing newly created small string.
650   CHECK(!small_string->CanMakeExternal());
651   for (int i = 0; i < 100; i++) {
652     String::Value value(small_string);
653   }
654   // Frequently used strings should be accepted.
655   CHECK(small_string->CanMakeExternal());
656
657   const int buf_size = 10 * 1024;
658   char* buf = i::NewArray<char>(buf_size);
659   memset(buf, 'a', buf_size);
660   buf[buf_size - 1] = '\0';
661   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
662   i::DeleteArray(buf);
663   // Large strings should be immediately accepted.
664   CHECK(large_string->CanMakeExternal());
665 }
666
667
668 TEST(MakingExternalUnalignedAsciiString) {
669   LocalContext env;
670   v8::HandleScope scope(env->GetIsolate());
671
672   CompileRun("function cons(a, b) { return a + b; }"
673              "function slice(a) { return a.substring(1); }");
674   // Create a cons string that will land in old pointer space.
675   Local<String> cons = Local<String>::Cast(CompileRun(
676       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
677   // Create a sliced string that will land in old pointer space.
678   Local<String> slice = Local<String>::Cast(CompileRun(
679       "slice('abcdefghijklmnopqrstuvwxyz');"));
680
681   // Trigger GCs so that the newly allocated string moves to old gen.
682   SimulateFullSpace(CcTest::heap()->old_pointer_space());
683   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
684   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
685
686   // Turn into external string with unaligned resource data.
687   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
688   bool success = cons->MakeExternal(
689       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
690   CHECK(success);
691   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
692   success = slice->MakeExternal(
693       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
694   CHECK(success);
695
696   // Trigger GCs and force evacuation.
697   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
698   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
699 }
700
701
702 THREADED_TEST(UsingExternalString) {
703   i::Factory* factory = CcTest::i_isolate()->factory();
704   {
705     v8::HandleScope scope(CcTest::isolate());
706     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
707     Local<String> string = String::NewExternal(
708         CcTest::isolate(), new TestResource(two_byte_string));
709     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
710     // Trigger GCs so that the newly allocated string moves to old gen.
711     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
712     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
713     i::Handle<i::String> isymbol =
714         factory->InternalizeString(istring);
715     CHECK(isymbol->IsInternalizedString());
716   }
717   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
718   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
719 }
720
721
722 THREADED_TEST(UsingExternalAsciiString) {
723   i::Factory* factory = CcTest::i_isolate()->factory();
724   {
725     v8::HandleScope scope(CcTest::isolate());
726     const char* one_byte_string = "test string";
727     Local<String> string = String::NewExternal(
728         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
729     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
730     // Trigger GCs so that the newly allocated string moves to old gen.
731     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
732     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
733     i::Handle<i::String> isymbol =
734         factory->InternalizeString(istring);
735     CHECK(isymbol->IsInternalizedString());
736   }
737   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
738   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
739 }
740
741
742 THREADED_TEST(ScavengeExternalString) {
743   i::FLAG_stress_compaction = false;
744   i::FLAG_gc_global = false;
745   int dispose_count = 0;
746   bool in_new_space = false;
747   {
748     v8::HandleScope scope(CcTest::isolate());
749     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
750     Local<String> string = String::NewExternal(
751         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
752     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
753     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
754     in_new_space = CcTest::heap()->InNewSpace(*istring);
755     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
756     CHECK_EQ(0, dispose_count);
757   }
758   CcTest::heap()->CollectGarbage(
759       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
760   CHECK_EQ(1, dispose_count);
761 }
762
763
764 THREADED_TEST(ScavengeExternalAsciiString) {
765   i::FLAG_stress_compaction = false;
766   i::FLAG_gc_global = false;
767   int dispose_count = 0;
768   bool in_new_space = false;
769   {
770     v8::HandleScope scope(CcTest::isolate());
771     const char* one_byte_string = "test string";
772     Local<String> string = String::NewExternal(
773         CcTest::isolate(),
774         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
775     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
776     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
777     in_new_space = CcTest::heap()->InNewSpace(*istring);
778     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
779     CHECK_EQ(0, dispose_count);
780   }
781   CcTest::heap()->CollectGarbage(
782       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
783   CHECK_EQ(1, dispose_count);
784 }
785
786
787 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
788  public:
789   // Only used by non-threaded tests, so it can use static fields.
790   static int dispose_calls;
791   static int dispose_count;
792
793   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
794       : TestAsciiResource(data, &dispose_count),
795         dispose_(dispose) { }
796
797   void Dispose() {
798     ++dispose_calls;
799     if (dispose_) delete this;
800   }
801  private:
802   bool dispose_;
803 };
804
805
806 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
807 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
808
809
810 TEST(ExternalStringWithDisposeHandling) {
811   const char* c_source = "1 + 2 * 3";
812
813   // Use a stack allocated external string resource allocated object.
814   TestAsciiResourceWithDisposeControl::dispose_count = 0;
815   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
816   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
817   {
818     LocalContext env;
819     v8::HandleScope scope(env->GetIsolate());
820     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
821     Local<Script> script = v8_compile(source);
822     Local<Value> value = script->Run();
823     CHECK(value->IsNumber());
824     CHECK_EQ(7, value->Int32Value());
825     CcTest::heap()->CollectAllAvailableGarbage();
826     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
827   }
828   CcTest::i_isolate()->compilation_cache()->Clear();
829   CcTest::heap()->CollectAllAvailableGarbage();
830   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
831   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
832
833   // Use a heap allocated external string resource allocated object.
834   TestAsciiResourceWithDisposeControl::dispose_count = 0;
835   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
836   TestAsciiResource* res_heap =
837       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
838   {
839     LocalContext env;
840     v8::HandleScope scope(env->GetIsolate());
841     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
842     Local<Script> script = v8_compile(source);
843     Local<Value> value = script->Run();
844     CHECK(value->IsNumber());
845     CHECK_EQ(7, value->Int32Value());
846     CcTest::heap()->CollectAllAvailableGarbage();
847     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
848   }
849   CcTest::i_isolate()->compilation_cache()->Clear();
850   CcTest::heap()->CollectAllAvailableGarbage();
851   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
852   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
853 }
854
855
856 THREADED_TEST(StringConcat) {
857   {
858     LocalContext env;
859     v8::HandleScope scope(env->GetIsolate());
860     const char* one_byte_string_1 = "function a_times_t";
861     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
862     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
863     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
864     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
865     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
866     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
867     Local<String> left = v8_str(one_byte_string_1);
868
869     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
870     Local<String> right =
871         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
872     i::DeleteArray(two_byte_source);
873
874     Local<String> source = String::Concat(left, right);
875     right = String::NewExternal(
876         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
877     source = String::Concat(source, right);
878     right = String::NewExternal(
879         env->GetIsolate(),
880         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
881     source = String::Concat(source, right);
882     right = v8_str(one_byte_string_2);
883     source = String::Concat(source, right);
884
885     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
886     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
887     i::DeleteArray(two_byte_source);
888
889     source = String::Concat(source, right);
890     right = String::NewExternal(
891         env->GetIsolate(),
892         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
893     source = String::Concat(source, right);
894     Local<Script> script = v8_compile(source);
895     Local<Value> value = script->Run();
896     CHECK(value->IsNumber());
897     CHECK_EQ(68, value->Int32Value());
898   }
899   CcTest::i_isolate()->compilation_cache()->Clear();
900   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
901   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
902 }
903
904
905 THREADED_TEST(GlobalProperties) {
906   LocalContext env;
907   v8::HandleScope scope(env->GetIsolate());
908   v8::Handle<v8::Object> global = env->Global();
909   global->Set(v8_str("pi"), v8_num(3.1415926));
910   Local<Value> pi = global->Get(v8_str("pi"));
911   CHECK_EQ(3.1415926, pi->NumberValue());
912 }
913
914
915 template<typename T>
916 static void CheckReturnValue(const T& t, i::Address callback) {
917   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
918   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
919   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
920   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
921   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
922   // Verify reset
923   bool is_runtime = (*o)->IsTheHole();
924   rv.Set(true);
925   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
926   rv.Set(v8::Handle<v8::Object>());
927   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
928   CHECK_EQ(is_runtime, (*o)->IsTheHole());
929
930   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
931   // If CPU profiler is active check that when API callback is invoked
932   // VMState is set to EXTERNAL.
933   if (isolate->cpu_profiler()->is_profiling()) {
934     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
935     CHECK(isolate->external_callback_scope());
936     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
937   }
938 }
939
940
941 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
942                                  i::Address callback) {
943   ApiTestFuzzer::Fuzz();
944   CheckReturnValue(info, callback);
945   info.GetReturnValue().Set(v8_str("bad value"));
946   info.GetReturnValue().Set(v8_num(102));
947 }
948
949
950 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
951   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
952 }
953
954
955 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
956   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
957 }
958
959 static void construct_callback(
960     const v8::FunctionCallbackInfo<Value>& info) {
961   ApiTestFuzzer::Fuzz();
962   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
963   info.This()->Set(v8_str("x"), v8_num(1));
964   info.This()->Set(v8_str("y"), v8_num(2));
965   info.GetReturnValue().Set(v8_str("bad value"));
966   info.GetReturnValue().Set(info.This());
967 }
968
969
970 static void Return239Callback(
971     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
972   ApiTestFuzzer::Fuzz();
973   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
974   info.GetReturnValue().Set(v8_str("bad value"));
975   info.GetReturnValue().Set(v8_num(239));
976 }
977
978
979 template<typename Handler>
980 static void TestFunctionTemplateInitializer(Handler handler,
981                                             Handler handler_2) {
982   // Test constructor calls.
983   {
984     LocalContext env;
985     v8::Isolate* isolate = env->GetIsolate();
986     v8::HandleScope scope(isolate);
987
988     Local<v8::FunctionTemplate> fun_templ =
989         v8::FunctionTemplate::New(isolate, handler);
990     Local<Function> fun = fun_templ->GetFunction();
991     env->Global()->Set(v8_str("obj"), fun);
992     Local<Script> script = v8_compile("obj()");
993     for (int i = 0; i < 30; i++) {
994       CHECK_EQ(102, script->Run()->Int32Value());
995     }
996   }
997   // Use SetCallHandler to initialize a function template, should work like
998   // the previous one.
999   {
1000     LocalContext env;
1001     v8::Isolate* isolate = env->GetIsolate();
1002     v8::HandleScope scope(isolate);
1003
1004     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1005     fun_templ->SetCallHandler(handler_2);
1006     Local<Function> fun = fun_templ->GetFunction();
1007     env->Global()->Set(v8_str("obj"), fun);
1008     Local<Script> script = v8_compile("obj()");
1009     for (int i = 0; i < 30; i++) {
1010       CHECK_EQ(102, script->Run()->Int32Value());
1011     }
1012   }
1013 }
1014
1015
1016 template<typename Constructor, typename Accessor>
1017 static void TestFunctionTemplateAccessor(Constructor constructor,
1018                                          Accessor accessor) {
1019   LocalContext env;
1020   v8::HandleScope scope(env->GetIsolate());
1021
1022   Local<v8::FunctionTemplate> fun_templ =
1023       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1024   fun_templ->SetClassName(v8_str("funky"));
1025   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1026   Local<Function> fun = fun_templ->GetFunction();
1027   env->Global()->Set(v8_str("obj"), fun);
1028   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1029   CHECK_EQ(v8_str("[object funky]"), result);
1030   CompileRun("var obj_instance = new obj();");
1031   Local<Script> script;
1032   script = v8_compile("obj_instance.x");
1033   for (int i = 0; i < 30; i++) {
1034     CHECK_EQ(1, script->Run()->Int32Value());
1035   }
1036   script = v8_compile("obj_instance.m");
1037   for (int i = 0; i < 30; i++) {
1038     CHECK_EQ(239, script->Run()->Int32Value());
1039   }
1040 }
1041
1042
1043 THREADED_PROFILED_TEST(FunctionTemplate) {
1044   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1045   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1046 }
1047
1048
1049 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1050   ApiTestFuzzer::Fuzz();
1051   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1052   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1053 }
1054
1055
1056 template<typename Callback>
1057 static void TestSimpleCallback(Callback callback) {
1058   LocalContext env;
1059   v8::Isolate* isolate = env->GetIsolate();
1060   v8::HandleScope scope(isolate);
1061
1062   v8::Handle<v8::ObjectTemplate> object_template =
1063       v8::ObjectTemplate::New(isolate);
1064   object_template->Set(isolate, "callback",
1065                        v8::FunctionTemplate::New(isolate, callback));
1066   v8::Local<v8::Object> object = object_template->NewInstance();
1067   (*env)->Global()->Set(v8_str("callback_object"), object);
1068   v8::Handle<v8::Script> script;
1069   script = v8_compile("callback_object.callback(17)");
1070   for (int i = 0; i < 30; i++) {
1071     CHECK_EQ(51424, script->Run()->Int32Value());
1072   }
1073   script = v8_compile("callback_object.callback(17, 24)");
1074   for (int i = 0; i < 30; i++) {
1075     CHECK_EQ(51425, script->Run()->Int32Value());
1076   }
1077 }
1078
1079
1080 THREADED_PROFILED_TEST(SimpleCallback) {
1081   TestSimpleCallback(SimpleCallback);
1082 }
1083
1084
1085 template<typename T>
1086 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1087
1088 // constant return values
1089 static int32_t fast_return_value_int32 = 471;
1090 static uint32_t fast_return_value_uint32 = 571;
1091 static const double kFastReturnValueDouble = 2.7;
1092 // variable return values
1093 static bool fast_return_value_bool = false;
1094 enum ReturnValueOddball {
1095   kNullReturnValue,
1096   kUndefinedReturnValue,
1097   kEmptyStringReturnValue
1098 };
1099 static ReturnValueOddball fast_return_value_void;
1100 static bool fast_return_value_object_is_empty = false;
1101
1102 // Helper function to avoid compiler error: insufficient contextual information
1103 // to determine type when applying FUNCTION_ADDR to a template function.
1104 static i::Address address_of(v8::FunctionCallback callback) {
1105   return FUNCTION_ADDR(callback);
1106 }
1107
1108 template<>
1109 void FastReturnValueCallback<int32_t>(
1110     const v8::FunctionCallbackInfo<v8::Value>& info) {
1111   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1112   info.GetReturnValue().Set(fast_return_value_int32);
1113 }
1114
1115 template<>
1116 void FastReturnValueCallback<uint32_t>(
1117     const v8::FunctionCallbackInfo<v8::Value>& info) {
1118   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1119   info.GetReturnValue().Set(fast_return_value_uint32);
1120 }
1121
1122 template<>
1123 void FastReturnValueCallback<double>(
1124     const v8::FunctionCallbackInfo<v8::Value>& info) {
1125   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1126   info.GetReturnValue().Set(kFastReturnValueDouble);
1127 }
1128
1129 template<>
1130 void FastReturnValueCallback<bool>(
1131     const v8::FunctionCallbackInfo<v8::Value>& info) {
1132   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1133   info.GetReturnValue().Set(fast_return_value_bool);
1134 }
1135
1136 template<>
1137 void FastReturnValueCallback<void>(
1138     const v8::FunctionCallbackInfo<v8::Value>& info) {
1139   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1140   switch (fast_return_value_void) {
1141     case kNullReturnValue:
1142       info.GetReturnValue().SetNull();
1143       break;
1144     case kUndefinedReturnValue:
1145       info.GetReturnValue().SetUndefined();
1146       break;
1147     case kEmptyStringReturnValue:
1148       info.GetReturnValue().SetEmptyString();
1149       break;
1150   }
1151 }
1152
1153 template<>
1154 void FastReturnValueCallback<Object>(
1155     const v8::FunctionCallbackInfo<v8::Value>& info) {
1156   v8::Handle<v8::Object> object;
1157   if (!fast_return_value_object_is_empty) {
1158     object = Object::New(info.GetIsolate());
1159   }
1160   info.GetReturnValue().Set(object);
1161 }
1162
1163 template<typename T>
1164 Handle<Value> TestFastReturnValues() {
1165   LocalContext env;
1166   v8::Isolate* isolate = env->GetIsolate();
1167   v8::EscapableHandleScope scope(isolate);
1168   v8::Handle<v8::ObjectTemplate> object_template =
1169       v8::ObjectTemplate::New(isolate);
1170   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1171   object_template->Set(isolate, "callback",
1172                        v8::FunctionTemplate::New(isolate, callback));
1173   v8::Local<v8::Object> object = object_template->NewInstance();
1174   (*env)->Global()->Set(v8_str("callback_object"), object);
1175   return scope.Escape(CompileRun("callback_object.callback()"));
1176 }
1177
1178
1179 THREADED_PROFILED_TEST(FastReturnValues) {
1180   LocalContext env;
1181   v8::HandleScope scope(CcTest::isolate());
1182   v8::Handle<v8::Value> value;
1183   // check int32_t and uint32_t
1184   int32_t int_values[] = {
1185       0, 234, -723,
1186       i::Smi::kMinValue, i::Smi::kMaxValue
1187   };
1188   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1189     for (int modifier = -1; modifier <= 1; modifier++) {
1190       int int_value = int_values[i] + modifier;
1191       // check int32_t
1192       fast_return_value_int32 = int_value;
1193       value = TestFastReturnValues<int32_t>();
1194       CHECK(value->IsInt32());
1195       CHECK(fast_return_value_int32 == value->Int32Value());
1196       // check uint32_t
1197       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1198       value = TestFastReturnValues<uint32_t>();
1199       CHECK(value->IsUint32());
1200       CHECK(fast_return_value_uint32 == value->Uint32Value());
1201     }
1202   }
1203   // check double
1204   value = TestFastReturnValues<double>();
1205   CHECK(value->IsNumber());
1206   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1207   // check bool values
1208   for (int i = 0; i < 2; i++) {
1209     fast_return_value_bool = i == 0;
1210     value = TestFastReturnValues<bool>();
1211     CHECK(value->IsBoolean());
1212     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1213   }
1214   // check oddballs
1215   ReturnValueOddball oddballs[] = {
1216       kNullReturnValue,
1217       kUndefinedReturnValue,
1218       kEmptyStringReturnValue
1219   };
1220   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1221     fast_return_value_void = oddballs[i];
1222     value = TestFastReturnValues<void>();
1223     switch (fast_return_value_void) {
1224       case kNullReturnValue:
1225         CHECK(value->IsNull());
1226         break;
1227       case kUndefinedReturnValue:
1228         CHECK(value->IsUndefined());
1229         break;
1230       case kEmptyStringReturnValue:
1231         CHECK(value->IsString());
1232         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1233         break;
1234     }
1235   }
1236   // check handles
1237   fast_return_value_object_is_empty = false;
1238   value = TestFastReturnValues<Object>();
1239   CHECK(value->IsObject());
1240   fast_return_value_object_is_empty = true;
1241   value = TestFastReturnValues<Object>();
1242   CHECK(value->IsUndefined());
1243 }
1244
1245
1246 THREADED_TEST(FunctionTemplateSetLength) {
1247   LocalContext env;
1248   v8::Isolate* isolate = env->GetIsolate();
1249   v8::HandleScope scope(isolate);
1250   {
1251     Local<v8::FunctionTemplate> fun_templ =
1252         v8::FunctionTemplate::New(isolate,
1253                                   handle_callback,
1254                                   Handle<v8::Value>(),
1255                                   Handle<v8::Signature>(),
1256                                   23);
1257     Local<Function> fun = fun_templ->GetFunction();
1258     env->Global()->Set(v8_str("obj"), fun);
1259     Local<Script> script = v8_compile("obj.length");
1260     CHECK_EQ(23, script->Run()->Int32Value());
1261   }
1262   {
1263     Local<v8::FunctionTemplate> fun_templ =
1264         v8::FunctionTemplate::New(isolate, handle_callback);
1265     fun_templ->SetLength(22);
1266     Local<Function> fun = fun_templ->GetFunction();
1267     env->Global()->Set(v8_str("obj"), fun);
1268     Local<Script> script = v8_compile("obj.length");
1269     CHECK_EQ(22, script->Run()->Int32Value());
1270   }
1271   {
1272     // Without setting length it defaults to 0.
1273     Local<v8::FunctionTemplate> fun_templ =
1274         v8::FunctionTemplate::New(isolate, handle_callback);
1275     Local<Function> fun = fun_templ->GetFunction();
1276     env->Global()->Set(v8_str("obj"), fun);
1277     Local<Script> script = v8_compile("obj.length");
1278     CHECK_EQ(0, script->Run()->Int32Value());
1279   }
1280 }
1281
1282
1283 static void* expected_ptr;
1284 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1285   void* ptr = v8::External::Cast(*args.Data())->Value();
1286   CHECK_EQ(expected_ptr, ptr);
1287   args.GetReturnValue().Set(true);
1288 }
1289
1290
1291 static void TestExternalPointerWrapping() {
1292   LocalContext env;
1293   v8::Isolate* isolate = env->GetIsolate();
1294   v8::HandleScope scope(isolate);
1295
1296   v8::Handle<v8::Value> data =
1297       v8::External::New(isolate, expected_ptr);
1298
1299   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1300   obj->Set(v8_str("func"),
1301            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1302   env->Global()->Set(v8_str("obj"), obj);
1303
1304   CHECK(CompileRun(
1305         "function foo() {\n"
1306         "  for (var i = 0; i < 13; i++) obj.func();\n"
1307         "}\n"
1308         "foo(), true")->BooleanValue());
1309 }
1310
1311
1312 THREADED_TEST(ExternalWrap) {
1313   // Check heap allocated object.
1314   int* ptr = new int;
1315   expected_ptr = ptr;
1316   TestExternalPointerWrapping();
1317   delete ptr;
1318
1319   // Check stack allocated object.
1320   int foo;
1321   expected_ptr = &foo;
1322   TestExternalPointerWrapping();
1323
1324   // Check not aligned addresses.
1325   const int n = 100;
1326   char* s = new char[n];
1327   for (int i = 0; i < n; i++) {
1328     expected_ptr = s + i;
1329     TestExternalPointerWrapping();
1330   }
1331
1332   delete[] s;
1333
1334   // Check several invalid addresses.
1335   expected_ptr = reinterpret_cast<void*>(1);
1336   TestExternalPointerWrapping();
1337
1338   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1339   TestExternalPointerWrapping();
1340
1341   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1342   TestExternalPointerWrapping();
1343
1344 #if defined(V8_HOST_ARCH_X64)
1345   // Check a value with a leading 1 bit in x64 Smi encoding.
1346   expected_ptr = reinterpret_cast<void*>(0x400000000);
1347   TestExternalPointerWrapping();
1348
1349   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1350   TestExternalPointerWrapping();
1351
1352   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1353   TestExternalPointerWrapping();
1354 #endif
1355 }
1356
1357
1358 THREADED_TEST(FindInstanceInPrototypeChain) {
1359   LocalContext env;
1360   v8::Isolate* isolate = env->GetIsolate();
1361   v8::HandleScope scope(isolate);
1362
1363   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1364   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1365   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1366   derived->Inherit(base);
1367
1368   Local<v8::Function> base_function = base->GetFunction();
1369   Local<v8::Function> derived_function = derived->GetFunction();
1370   Local<v8::Function> other_function = other->GetFunction();
1371
1372   Local<v8::Object> base_instance = base_function->NewInstance();
1373   Local<v8::Object> derived_instance = derived_function->NewInstance();
1374   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1375   Local<v8::Object> other_instance = other_function->NewInstance();
1376   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1377   other_instance->Set(v8_str("__proto__"), derived_instance2);
1378
1379   // base_instance is only an instance of base.
1380   CHECK_EQ(base_instance,
1381            base_instance->FindInstanceInPrototypeChain(base));
1382   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1383   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1384
1385   // derived_instance is an instance of base and derived.
1386   CHECK_EQ(derived_instance,
1387            derived_instance->FindInstanceInPrototypeChain(base));
1388   CHECK_EQ(derived_instance,
1389            derived_instance->FindInstanceInPrototypeChain(derived));
1390   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1391
1392   // other_instance is an instance of other and its immediate
1393   // prototype derived_instance2 is an instance of base and derived.
1394   // Note, derived_instance is an instance of base and derived too,
1395   // but it comes after derived_instance2 in the prototype chain of
1396   // other_instance.
1397   CHECK_EQ(derived_instance2,
1398            other_instance->FindInstanceInPrototypeChain(base));
1399   CHECK_EQ(derived_instance2,
1400            other_instance->FindInstanceInPrototypeChain(derived));
1401   CHECK_EQ(other_instance,
1402            other_instance->FindInstanceInPrototypeChain(other));
1403 }
1404
1405
1406 THREADED_TEST(TinyInteger) {
1407   LocalContext env;
1408   v8::Isolate* isolate = env->GetIsolate();
1409   v8::HandleScope scope(isolate);
1410
1411   int32_t value = 239;
1412   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1413   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1414
1415   value_obj = v8::Integer::New(isolate, value);
1416   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1417 }
1418
1419
1420 THREADED_TEST(BigSmiInteger) {
1421   LocalContext env;
1422   v8::HandleScope scope(env->GetIsolate());
1423   v8::Isolate* isolate = CcTest::isolate();
1424
1425   int32_t value = i::Smi::kMaxValue;
1426   // We cannot add one to a Smi::kMaxValue without wrapping.
1427   if (i::SmiValuesAre31Bits()) {
1428     CHECK(i::Smi::IsValid(value));
1429     CHECK(!i::Smi::IsValid(value + 1));
1430
1431     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1432     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1433
1434     value_obj = v8::Integer::New(isolate, value);
1435     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1436   }
1437 }
1438
1439
1440 THREADED_TEST(BigInteger) {
1441   LocalContext env;
1442   v8::HandleScope scope(env->GetIsolate());
1443   v8::Isolate* isolate = CcTest::isolate();
1444
1445   // We cannot add one to a Smi::kMaxValue without wrapping.
1446   if (i::SmiValuesAre31Bits()) {
1447     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1448     // The code will not be run in that case, due to the "if" guard.
1449     int32_t value =
1450         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1451     CHECK(value > i::Smi::kMaxValue);
1452     CHECK(!i::Smi::IsValid(value));
1453
1454     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1455     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1456
1457     value_obj = v8::Integer::New(isolate, value);
1458     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1459   }
1460 }
1461
1462
1463 THREADED_TEST(TinyUnsignedInteger) {
1464   LocalContext env;
1465   v8::HandleScope scope(env->GetIsolate());
1466   v8::Isolate* isolate = CcTest::isolate();
1467
1468   uint32_t value = 239;
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(BigUnsignedSmiInteger) {
1479   LocalContext env;
1480   v8::HandleScope scope(env->GetIsolate());
1481   v8::Isolate* isolate = CcTest::isolate();
1482
1483   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1484   CHECK(i::Smi::IsValid(value));
1485   CHECK(!i::Smi::IsValid(value + 1));
1486
1487   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1488   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1489
1490   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1491   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1492 }
1493
1494
1495 THREADED_TEST(BigUnsignedInteger) {
1496   LocalContext env;
1497   v8::HandleScope scope(env->GetIsolate());
1498   v8::Isolate* isolate = CcTest::isolate();
1499
1500   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1501   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1502   CHECK(!i::Smi::IsValid(value));
1503
1504   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1505   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1506
1507   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1508   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509 }
1510
1511
1512 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1513   LocalContext env;
1514   v8::HandleScope scope(env->GetIsolate());
1515   v8::Isolate* isolate = CcTest::isolate();
1516
1517   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1518   uint32_t value = INT32_MAX_AS_UINT + 1;
1519   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1520
1521   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1522   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1523
1524   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1525   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1526 }
1527
1528
1529 THREADED_TEST(IsNativeError) {
1530   LocalContext env;
1531   v8::HandleScope scope(env->GetIsolate());
1532   v8::Handle<Value> syntax_error = CompileRun(
1533       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1534   CHECK(syntax_error->IsNativeError());
1535   v8::Handle<Value> not_error = CompileRun("{a:42}");
1536   CHECK(!not_error->IsNativeError());
1537   v8::Handle<Value> not_object = CompileRun("42");
1538   CHECK(!not_object->IsNativeError());
1539 }
1540
1541
1542 THREADED_TEST(StringObject) {
1543   LocalContext env;
1544   v8::HandleScope scope(env->GetIsolate());
1545   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1546   CHECK(boxed_string->IsStringObject());
1547   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1548   CHECK(!unboxed_string->IsStringObject());
1549   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1550   CHECK(!boxed_not_string->IsStringObject());
1551   v8::Handle<Value> not_object = CompileRun("0");
1552   CHECK(!not_object->IsStringObject());
1553   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1554   CHECK(!as_boxed.IsEmpty());
1555   Local<v8::String> the_string = as_boxed->ValueOf();
1556   CHECK(!the_string.IsEmpty());
1557   ExpectObject("\"test\"", the_string);
1558   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1559   CHECK(new_boxed_string->IsStringObject());
1560   as_boxed = new_boxed_string.As<v8::StringObject>();
1561   the_string = as_boxed->ValueOf();
1562   CHECK(!the_string.IsEmpty());
1563   ExpectObject("\"test\"", the_string);
1564 }
1565
1566
1567 THREADED_TEST(NumberObject) {
1568   LocalContext env;
1569   v8::HandleScope scope(env->GetIsolate());
1570   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1571   CHECK(boxed_number->IsNumberObject());
1572   v8::Handle<Value> unboxed_number = CompileRun("42");
1573   CHECK(!unboxed_number->IsNumberObject());
1574   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1575   CHECK(!boxed_not_number->IsNumberObject());
1576   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1577   CHECK(!as_boxed.IsEmpty());
1578   double the_number = as_boxed->ValueOf();
1579   CHECK_EQ(42.0, the_number);
1580   v8::Handle<v8::Value> new_boxed_number =
1581       v8::NumberObject::New(env->GetIsolate(), 43);
1582   CHECK(new_boxed_number->IsNumberObject());
1583   as_boxed = new_boxed_number.As<v8::NumberObject>();
1584   the_number = as_boxed->ValueOf();
1585   CHECK_EQ(43.0, the_number);
1586 }
1587
1588
1589 THREADED_TEST(BooleanObject) {
1590   LocalContext env;
1591   v8::HandleScope scope(env->GetIsolate());
1592   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1593   CHECK(boxed_boolean->IsBooleanObject());
1594   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1595   CHECK(!unboxed_boolean->IsBooleanObject());
1596   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1597   CHECK(!boxed_not_boolean->IsBooleanObject());
1598   v8::Handle<v8::BooleanObject> as_boxed =
1599       boxed_boolean.As<v8::BooleanObject>();
1600   CHECK(!as_boxed.IsEmpty());
1601   bool the_boolean = as_boxed->ValueOf();
1602   CHECK_EQ(true, the_boolean);
1603   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1604   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1605   CHECK(boxed_true->IsBooleanObject());
1606   CHECK(boxed_false->IsBooleanObject());
1607   as_boxed = boxed_true.As<v8::BooleanObject>();
1608   CHECK_EQ(true, as_boxed->ValueOf());
1609   as_boxed = boxed_false.As<v8::BooleanObject>();
1610   CHECK_EQ(false, as_boxed->ValueOf());
1611 }
1612
1613
1614 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1615   LocalContext env;
1616   v8::HandleScope scope(env->GetIsolate());
1617
1618   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1619   CHECK(primitive_false->IsBoolean());
1620   CHECK(!primitive_false->IsBooleanObject());
1621   CHECK(!primitive_false->BooleanValue());
1622   CHECK(!primitive_false->IsTrue());
1623   CHECK(primitive_false->IsFalse());
1624
1625   Local<Value> false_value = BooleanObject::New(false);
1626   CHECK(!false_value->IsBoolean());
1627   CHECK(false_value->IsBooleanObject());
1628   CHECK(false_value->BooleanValue());
1629   CHECK(!false_value->IsTrue());
1630   CHECK(!false_value->IsFalse());
1631
1632   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1633   CHECK(!false_boolean_object->IsBoolean());
1634   CHECK(false_boolean_object->IsBooleanObject());
1635   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1636   // CHECK(false_boolean_object->BooleanValue());
1637   CHECK(!false_boolean_object->ValueOf());
1638   CHECK(!false_boolean_object->IsTrue());
1639   CHECK(!false_boolean_object->IsFalse());
1640
1641   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1642   CHECK(primitive_true->IsBoolean());
1643   CHECK(!primitive_true->IsBooleanObject());
1644   CHECK(primitive_true->BooleanValue());
1645   CHECK(primitive_true->IsTrue());
1646   CHECK(!primitive_true->IsFalse());
1647
1648   Local<Value> true_value = BooleanObject::New(true);
1649   CHECK(!true_value->IsBoolean());
1650   CHECK(true_value->IsBooleanObject());
1651   CHECK(true_value->BooleanValue());
1652   CHECK(!true_value->IsTrue());
1653   CHECK(!true_value->IsFalse());
1654
1655   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1656   CHECK(!true_boolean_object->IsBoolean());
1657   CHECK(true_boolean_object->IsBooleanObject());
1658   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1659   // CHECK(true_boolean_object->BooleanValue());
1660   CHECK(true_boolean_object->ValueOf());
1661   CHECK(!true_boolean_object->IsTrue());
1662   CHECK(!true_boolean_object->IsFalse());
1663 }
1664
1665
1666 THREADED_TEST(Number) {
1667   LocalContext env;
1668   v8::HandleScope scope(env->GetIsolate());
1669   double PI = 3.1415926;
1670   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1671   CHECK_EQ(PI, pi_obj->NumberValue());
1672 }
1673
1674
1675 THREADED_TEST(ToNumber) {
1676   LocalContext env;
1677   v8::Isolate* isolate = CcTest::isolate();
1678   v8::HandleScope scope(isolate);
1679   Local<String> str = v8_str("3.1415926");
1680   CHECK_EQ(3.1415926, str->NumberValue());
1681   v8::Handle<v8::Boolean> t = v8::True(isolate);
1682   CHECK_EQ(1.0, t->NumberValue());
1683   v8::Handle<v8::Boolean> f = v8::False(isolate);
1684   CHECK_EQ(0.0, f->NumberValue());
1685 }
1686
1687
1688 THREADED_TEST(Date) {
1689   LocalContext env;
1690   v8::HandleScope scope(env->GetIsolate());
1691   double PI = 3.1415926;
1692   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1693   CHECK_EQ(3.0, date->NumberValue());
1694   date.As<v8::Date>()->Set(v8_str("property"),
1695                            v8::Integer::New(env->GetIsolate(), 42));
1696   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1697 }
1698
1699
1700 THREADED_TEST(Boolean) {
1701   LocalContext env;
1702   v8::Isolate* isolate = env->GetIsolate();
1703   v8::HandleScope scope(isolate);
1704   v8::Handle<v8::Boolean> t = v8::True(isolate);
1705   CHECK(t->Value());
1706   v8::Handle<v8::Boolean> f = v8::False(isolate);
1707   CHECK(!f->Value());
1708   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1709   CHECK(!u->BooleanValue());
1710   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1711   CHECK(!n->BooleanValue());
1712   v8::Handle<String> str1 = v8_str("");
1713   CHECK(!str1->BooleanValue());
1714   v8::Handle<String> str2 = v8_str("x");
1715   CHECK(str2->BooleanValue());
1716   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1717   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1718   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1719   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1720   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1721 }
1722
1723
1724 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1725   ApiTestFuzzer::Fuzz();
1726   args.GetReturnValue().Set(v8_num(13.4));
1727 }
1728
1729
1730 static void GetM(Local<String> name,
1731                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1732   ApiTestFuzzer::Fuzz();
1733   info.GetReturnValue().Set(v8_num(876));
1734 }
1735
1736
1737 THREADED_TEST(GlobalPrototype) {
1738   v8::Isolate* isolate = CcTest::isolate();
1739   v8::HandleScope scope(isolate);
1740   v8::Handle<v8::FunctionTemplate> func_templ =
1741       v8::FunctionTemplate::New(isolate);
1742   func_templ->PrototypeTemplate()->Set(
1743       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1744   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1745   templ->Set(isolate, "x", v8_num(200));
1746   templ->SetAccessor(v8_str("m"), GetM);
1747   LocalContext env(0, templ);
1748   v8::Handle<Script> script(v8_compile("dummy()"));
1749   v8::Handle<Value> result(script->Run());
1750   CHECK_EQ(13.4, result->NumberValue());
1751   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1752   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1753 }
1754
1755
1756 THREADED_TEST(ObjectTemplate) {
1757   v8::Isolate* isolate = CcTest::isolate();
1758   v8::HandleScope scope(isolate);
1759   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1760   templ1->Set(isolate, "x", v8_num(10));
1761   templ1->Set(isolate, "y", v8_num(13));
1762   LocalContext env;
1763   Local<v8::Object> instance1 = templ1->NewInstance();
1764   env->Global()->Set(v8_str("p"), instance1);
1765   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1766   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1767   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1768   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1769   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1770   templ2->Set(isolate, "a", v8_num(12));
1771   templ2->Set(isolate, "b", templ1);
1772   Local<v8::Object> instance2 = templ2->NewInstance();
1773   env->Global()->Set(v8_str("q"), instance2);
1774   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1775   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1776   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1777   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1778 }
1779
1780
1781 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1782   ApiTestFuzzer::Fuzz();
1783   args.GetReturnValue().Set(v8_num(17.2));
1784 }
1785
1786
1787 static void GetKnurd(Local<String> property,
1788                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1789   ApiTestFuzzer::Fuzz();
1790   info.GetReturnValue().Set(v8_num(15.2));
1791 }
1792
1793
1794 THREADED_TEST(DescriptorInheritance) {
1795   v8::Isolate* isolate = CcTest::isolate();
1796   v8::HandleScope scope(isolate);
1797   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1798   super->PrototypeTemplate()->Set(isolate, "flabby",
1799                                   v8::FunctionTemplate::New(isolate,
1800                                                             GetFlabby));
1801   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1802
1803   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1804
1805   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1806   base1->Inherit(super);
1807   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1808
1809   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1810   base2->Inherit(super);
1811   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1812
1813   LocalContext env;
1814
1815   env->Global()->Set(v8_str("s"), super->GetFunction());
1816   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1817   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1818
1819   // Checks right __proto__ chain.
1820   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1821   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1822
1823   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1824
1825   // Instance accessor should not be visible on function object or its prototype
1826   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1827   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1828   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1829
1830   env->Global()->Set(v8_str("obj"),
1831                      base1->GetFunction()->NewInstance());
1832   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1833   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1834   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1835   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1836   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1837
1838   env->Global()->Set(v8_str("obj2"),
1839                      base2->GetFunction()->NewInstance());
1840   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1841   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1842   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1843   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1844   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1845
1846   // base1 and base2 cannot cross reference to each's prototype
1847   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1848   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1849 }
1850
1851
1852 int echo_named_call_count;
1853
1854
1855 static void EchoNamedProperty(Local<String> name,
1856                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1857   ApiTestFuzzer::Fuzz();
1858   CHECK_EQ(v8_str("data"), info.Data());
1859   echo_named_call_count++;
1860   info.GetReturnValue().Set(name);
1861 }
1862
1863
1864 // Helper functions for Interceptor/Accessor interaction tests
1865
1866 void SimpleAccessorGetter(Local<String> name,
1867                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1868   Handle<Object> self = Handle<Object>::Cast(info.This());
1869   info.GetReturnValue().Set(
1870       self->Get(String::Concat(v8_str("accessor_"), name)));
1871 }
1872
1873 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1874                           const v8::PropertyCallbackInfo<void>& info) {
1875   Handle<Object> self = Handle<Object>::Cast(info.This());
1876   self->Set(String::Concat(v8_str("accessor_"), name), value);
1877 }
1878
1879 void EmptyInterceptorGetter(Local<String> name,
1880                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1881 }
1882
1883 void EmptyInterceptorSetter(Local<String> name,
1884                             Local<Value> value,
1885                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1886 }
1887
1888 void InterceptorGetter(Local<String> name,
1889                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1890   // Intercept names that start with 'interceptor_'.
1891   String::Utf8Value utf8(name);
1892   char* name_str = *utf8;
1893   char prefix[] = "interceptor_";
1894   int i;
1895   for (i = 0; name_str[i] && prefix[i]; ++i) {
1896     if (name_str[i] != prefix[i]) return;
1897   }
1898   Handle<Object> self = Handle<Object>::Cast(info.This());
1899   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1900 }
1901
1902 void InterceptorSetter(Local<String> name,
1903                        Local<Value> value,
1904                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1905   // Intercept accesses that set certain integer values, for which the name does
1906   // not start with 'accessor_'.
1907   String::Utf8Value utf8(name);
1908   char* name_str = *utf8;
1909   char prefix[] = "accessor_";
1910   int i;
1911   for (i = 0; name_str[i] && prefix[i]; ++i) {
1912     if (name_str[i] != prefix[i]) break;
1913   }
1914   if (!prefix[i]) return;
1915
1916   if (value->IsInt32() && value->Int32Value() < 10000) {
1917     Handle<Object> self = Handle<Object>::Cast(info.This());
1918     self->SetHiddenValue(name, value);
1919     info.GetReturnValue().Set(value);
1920   }
1921 }
1922
1923 void AddAccessor(Handle<FunctionTemplate> templ,
1924                  Handle<String> name,
1925                  v8::AccessorGetterCallback getter,
1926                  v8::AccessorSetterCallback setter) {
1927   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1928 }
1929
1930 void AddInterceptor(Handle<FunctionTemplate> templ,
1931                     v8::NamedPropertyGetterCallback getter,
1932                     v8::NamedPropertySetterCallback setter) {
1933   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1934 }
1935
1936
1937 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1938   v8::HandleScope scope(CcTest::isolate());
1939   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1940   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1941   child->Inherit(parent);
1942   AddAccessor(parent, v8_str("age"),
1943               SimpleAccessorGetter, SimpleAccessorSetter);
1944   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1945   LocalContext env;
1946   env->Global()->Set(v8_str("Child"), child->GetFunction());
1947   CompileRun("var child = new Child;"
1948              "child.age = 10;");
1949   ExpectBoolean("child.hasOwnProperty('age')", false);
1950   ExpectInt32("child.age", 10);
1951   ExpectInt32("child.accessor_age", 10);
1952 }
1953
1954
1955 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1956   v8::Isolate* isolate = CcTest::isolate();
1957   v8::HandleScope scope(isolate);
1958   LocalContext env;
1959   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1960   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1961   CHECK(a->map()->instance_descriptors()->IsFixedArray());
1962   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1963   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1964   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1965   // But we should still have an ExecutableAccessorInfo.
1966   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1967   i::LookupResult lookup(i_isolate);
1968   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1969   a->LookupOwnRealNamedProperty(name, &lookup);
1970   CHECK(lookup.IsPropertyCallbacks());
1971   i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate);
1972   CHECK(callback->IsExecutableAccessorInfo());
1973 }
1974
1975
1976 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1977   v8::HandleScope scope(CcTest::isolate());
1978   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1979   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1980   LocalContext env;
1981   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1982   CompileRun("var o1 = new Constructor;"
1983              "o1.a = 1;"  // Ensure a and x share the descriptor array.
1984              "Object.defineProperty(o1, 'x', {value: 10});");
1985   CompileRun("var o2 = new Constructor;"
1986              "o2.a = 1;"
1987              "Object.defineProperty(o2, 'x', {value: 10});");
1988 }
1989
1990
1991 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1992   v8::Isolate* isolate = CcTest::isolate();
1993   v8::HandleScope scope(isolate);
1994   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1995   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1996   child->Inherit(parent);
1997   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1998   LocalContext env;
1999   env->Global()->Set(v8_str("Child"), child->GetFunction());
2000   CompileRun("var child = new Child;"
2001              "var parent = child.__proto__;"
2002              "Object.defineProperty(parent, 'age', "
2003              "  {get: function(){ return this.accessor_age; }, "
2004              "   set: function(v){ this.accessor_age = v; }, "
2005              "   enumerable: true, configurable: true});"
2006              "child.age = 10;");
2007   ExpectBoolean("child.hasOwnProperty('age')", false);
2008   ExpectInt32("child.age", 10);
2009   ExpectInt32("child.accessor_age", 10);
2010 }
2011
2012
2013 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2014   v8::Isolate* isolate = CcTest::isolate();
2015   v8::HandleScope scope(isolate);
2016   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2017   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2018   child->Inherit(parent);
2019   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2020   LocalContext env;
2021   env->Global()->Set(v8_str("Child"), child->GetFunction());
2022   CompileRun("var child = new Child;"
2023              "var parent = child.__proto__;"
2024              "parent.name = 'Alice';");
2025   ExpectBoolean("child.hasOwnProperty('name')", false);
2026   ExpectString("child.name", "Alice");
2027   CompileRun("child.name = 'Bob';");
2028   ExpectString("child.name", "Bob");
2029   ExpectBoolean("child.hasOwnProperty('name')", true);
2030   ExpectString("parent.name", "Alice");
2031 }
2032
2033
2034 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2035   v8::HandleScope scope(CcTest::isolate());
2036   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2037   AddAccessor(templ, v8_str("age"),
2038               SimpleAccessorGetter, SimpleAccessorSetter);
2039   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2040   LocalContext env;
2041   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2042   CompileRun("var obj = new Obj;"
2043              "function setAge(i){ obj.age = i; };"
2044              "for(var i = 0; i <= 10000; i++) setAge(i);");
2045   // All i < 10000 go to the interceptor.
2046   ExpectInt32("obj.interceptor_age", 9999);
2047   // The last i goes to the accessor.
2048   ExpectInt32("obj.accessor_age", 10000);
2049 }
2050
2051
2052 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2053   v8::HandleScope scope(CcTest::isolate());
2054   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2055   AddAccessor(templ, v8_str("age"),
2056               SimpleAccessorGetter, SimpleAccessorSetter);
2057   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2058   LocalContext env;
2059   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2060   CompileRun("var obj = new Obj;"
2061              "function setAge(i){ obj.age = i; };"
2062              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2063   // All i >= 10000 go to the accessor.
2064   ExpectInt32("obj.accessor_age", 10000);
2065   // The last i goes to the interceptor.
2066   ExpectInt32("obj.interceptor_age", 9999);
2067 }
2068
2069
2070 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2071   v8::HandleScope scope(CcTest::isolate());
2072   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2073   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2074   child->Inherit(parent);
2075   AddAccessor(parent, v8_str("age"),
2076               SimpleAccessorGetter, SimpleAccessorSetter);
2077   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2078   LocalContext env;
2079   env->Global()->Set(v8_str("Child"), child->GetFunction());
2080   CompileRun("var child = new Child;"
2081              "function setAge(i){ child.age = i; };"
2082              "for(var i = 0; i <= 10000; i++) setAge(i);");
2083   // All i < 10000 go to the interceptor.
2084   ExpectInt32("child.interceptor_age", 9999);
2085   // The last i goes to the accessor.
2086   ExpectInt32("child.accessor_age", 10000);
2087 }
2088
2089
2090 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2091   v8::HandleScope scope(CcTest::isolate());
2092   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2093   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2094   child->Inherit(parent);
2095   AddAccessor(parent, v8_str("age"),
2096               SimpleAccessorGetter, SimpleAccessorSetter);
2097   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2098   LocalContext env;
2099   env->Global()->Set(v8_str("Child"), child->GetFunction());
2100   CompileRun("var child = new Child;"
2101              "function setAge(i){ child.age = i; };"
2102              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2103   // All i >= 10000 go to the accessor.
2104   ExpectInt32("child.accessor_age", 10000);
2105   // The last i goes to the interceptor.
2106   ExpectInt32("child.interceptor_age", 9999);
2107 }
2108
2109
2110 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2111   v8::HandleScope scope(CcTest::isolate());
2112   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2113   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2114   LocalContext env;
2115   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2116   CompileRun("var obj = new Obj;"
2117              "function setter(i) { this.accessor_age = i; };"
2118              "function getter() { return this.accessor_age; };"
2119              "function setAge(i) { obj.age = i; };"
2120              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2121              "for(var i = 0; i <= 10000; i++) setAge(i);");
2122   // All i < 10000 go to the interceptor.
2123   ExpectInt32("obj.interceptor_age", 9999);
2124   // The last i goes to the JavaScript accessor.
2125   ExpectInt32("obj.accessor_age", 10000);
2126   // The installed JavaScript getter is still intact.
2127   // This last part is a regression test for issue 1651 and relies on the fact
2128   // that both interceptor and accessor are being installed on the same object.
2129   ExpectInt32("obj.age", 10000);
2130   ExpectBoolean("obj.hasOwnProperty('age')", true);
2131   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2132 }
2133
2134
2135 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2136   v8::HandleScope scope(CcTest::isolate());
2137   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2138   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2139   LocalContext env;
2140   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2141   CompileRun("var obj = new Obj;"
2142              "function setter(i) { this.accessor_age = i; };"
2143              "function getter() { return this.accessor_age; };"
2144              "function setAge(i) { obj.age = i; };"
2145              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2146              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2147   // All i >= 10000 go to the accessor.
2148   ExpectInt32("obj.accessor_age", 10000);
2149   // The last i goes to the interceptor.
2150   ExpectInt32("obj.interceptor_age", 9999);
2151   // The installed JavaScript getter is still intact.
2152   // This last part is a regression test for issue 1651 and relies on the fact
2153   // that both interceptor and accessor are being installed on the same object.
2154   ExpectInt32("obj.age", 10000);
2155   ExpectBoolean("obj.hasOwnProperty('age')", true);
2156   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2157 }
2158
2159
2160 THREADED_TEST(SwitchFromInterceptorToProperty) {
2161   v8::HandleScope scope(CcTest::isolate());
2162   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2163   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2164   child->Inherit(parent);
2165   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2166   LocalContext env;
2167   env->Global()->Set(v8_str("Child"), child->GetFunction());
2168   CompileRun("var child = new Child;"
2169              "function setAge(i){ child.age = i; };"
2170              "for(var i = 0; i <= 10000; i++) setAge(i);");
2171   // All i < 10000 go to the interceptor.
2172   ExpectInt32("child.interceptor_age", 9999);
2173   // The last i goes to child's own property.
2174   ExpectInt32("child.age", 10000);
2175 }
2176
2177
2178 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2179   v8::HandleScope scope(CcTest::isolate());
2180   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2181   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2182   child->Inherit(parent);
2183   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2184   LocalContext env;
2185   env->Global()->Set(v8_str("Child"), child->GetFunction());
2186   CompileRun("var child = new Child;"
2187              "function setAge(i){ child.age = i; };"
2188              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2189   // All i >= 10000 go to child's own property.
2190   ExpectInt32("child.age", 10000);
2191   // The last i goes to the interceptor.
2192   ExpectInt32("child.interceptor_age", 9999);
2193 }
2194
2195
2196 THREADED_TEST(NamedPropertyHandlerGetter) {
2197   echo_named_call_count = 0;
2198   v8::HandleScope scope(CcTest::isolate());
2199   v8::Handle<v8::FunctionTemplate> templ =
2200       v8::FunctionTemplate::New(CcTest::isolate());
2201   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2202                                                      0, 0, 0, 0,
2203                                                      v8_str("data"));
2204   LocalContext env;
2205   env->Global()->Set(v8_str("obj"),
2206                      templ->GetFunction()->NewInstance());
2207   CHECK_EQ(echo_named_call_count, 0);
2208   v8_compile("obj.x")->Run();
2209   CHECK_EQ(echo_named_call_count, 1);
2210   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2211   v8::Handle<Value> str = CompileRun(code);
2212   String::Utf8Value value(str);
2213   CHECK_EQ(*value, "oddlepoddle");
2214   // Check default behavior
2215   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2216   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2217   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2218 }
2219
2220
2221 int echo_indexed_call_count = 0;
2222
2223
2224 static void EchoIndexedProperty(
2225     uint32_t index,
2226     const v8::PropertyCallbackInfo<v8::Value>& info) {
2227   ApiTestFuzzer::Fuzz();
2228   CHECK_EQ(v8_num(637), info.Data());
2229   echo_indexed_call_count++;
2230   info.GetReturnValue().Set(v8_num(index));
2231 }
2232
2233
2234 THREADED_TEST(IndexedPropertyHandlerGetter) {
2235   v8::Isolate* isolate = CcTest::isolate();
2236   v8::HandleScope scope(isolate);
2237   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2238   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2239                                                        0, 0, 0, 0,
2240                                                        v8_num(637));
2241   LocalContext env;
2242   env->Global()->Set(v8_str("obj"),
2243                      templ->GetFunction()->NewInstance());
2244   Local<Script> script = v8_compile("obj[900]");
2245   CHECK_EQ(script->Run()->Int32Value(), 900);
2246 }
2247
2248
2249 v8::Handle<v8::Object> bottom;
2250
2251 static void CheckThisIndexedPropertyHandler(
2252     uint32_t index,
2253     const v8::PropertyCallbackInfo<v8::Value>& info) {
2254   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2255   ApiTestFuzzer::Fuzz();
2256   CHECK(info.This()->Equals(bottom));
2257 }
2258
2259 static void CheckThisNamedPropertyHandler(
2260     Local<String> name,
2261     const v8::PropertyCallbackInfo<v8::Value>& info) {
2262   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2263   ApiTestFuzzer::Fuzz();
2264   CHECK(info.This()->Equals(bottom));
2265 }
2266
2267 void CheckThisIndexedPropertySetter(
2268     uint32_t index,
2269     Local<Value> value,
2270     const v8::PropertyCallbackInfo<v8::Value>& info) {
2271   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2272   ApiTestFuzzer::Fuzz();
2273   CHECK(info.This()->Equals(bottom));
2274 }
2275
2276
2277 void CheckThisNamedPropertySetter(
2278     Local<String> property,
2279     Local<Value> value,
2280     const v8::PropertyCallbackInfo<v8::Value>& info) {
2281   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2282   ApiTestFuzzer::Fuzz();
2283   CHECK(info.This()->Equals(bottom));
2284 }
2285
2286 void CheckThisIndexedPropertyQuery(
2287     uint32_t index,
2288     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2289   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2290   ApiTestFuzzer::Fuzz();
2291   CHECK(info.This()->Equals(bottom));
2292 }
2293
2294
2295 void CheckThisNamedPropertyQuery(
2296     Local<String> property,
2297     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2298   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2299   ApiTestFuzzer::Fuzz();
2300   CHECK(info.This()->Equals(bottom));
2301 }
2302
2303
2304 void CheckThisIndexedPropertyDeleter(
2305     uint32_t index,
2306     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2307   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2308   ApiTestFuzzer::Fuzz();
2309   CHECK(info.This()->Equals(bottom));
2310 }
2311
2312
2313 void CheckThisNamedPropertyDeleter(
2314     Local<String> property,
2315     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2316   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2317   ApiTestFuzzer::Fuzz();
2318   CHECK(info.This()->Equals(bottom));
2319 }
2320
2321
2322 void CheckThisIndexedPropertyEnumerator(
2323     const v8::PropertyCallbackInfo<v8::Array>& info) {
2324   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2325   ApiTestFuzzer::Fuzz();
2326   CHECK(info.This()->Equals(bottom));
2327 }
2328
2329
2330 void CheckThisNamedPropertyEnumerator(
2331     const v8::PropertyCallbackInfo<v8::Array>& info) {
2332   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2333   ApiTestFuzzer::Fuzz();
2334   CHECK(info.This()->Equals(bottom));
2335 }
2336
2337
2338 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2339   LocalContext env;
2340   v8::Isolate* isolate = env->GetIsolate();
2341   v8::HandleScope scope(isolate);
2342
2343   // Set up a prototype chain with three interceptors.
2344   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2345   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2346       CheckThisIndexedPropertyHandler,
2347       CheckThisIndexedPropertySetter,
2348       CheckThisIndexedPropertyQuery,
2349       CheckThisIndexedPropertyDeleter,
2350       CheckThisIndexedPropertyEnumerator);
2351
2352   templ->InstanceTemplate()->SetNamedPropertyHandler(
2353       CheckThisNamedPropertyHandler,
2354       CheckThisNamedPropertySetter,
2355       CheckThisNamedPropertyQuery,
2356       CheckThisNamedPropertyDeleter,
2357       CheckThisNamedPropertyEnumerator);
2358
2359   bottom = templ->GetFunction()->NewInstance();
2360   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2361   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2362
2363   bottom->SetPrototype(middle);
2364   middle->SetPrototype(top);
2365   env->Global()->Set(v8_str("obj"), bottom);
2366
2367   // Indexed and named get.
2368   CompileRun("obj[0]");
2369   CompileRun("obj.x");
2370
2371   // Indexed and named set.
2372   CompileRun("obj[1] = 42");
2373   CompileRun("obj.y = 42");
2374
2375   // Indexed and named query.
2376   CompileRun("0 in obj");
2377   CompileRun("'x' in obj");
2378
2379   // Indexed and named deleter.
2380   CompileRun("delete obj[0]");
2381   CompileRun("delete obj.x");
2382
2383   // Enumerators.
2384   CompileRun("for (var p in obj) ;");
2385 }
2386
2387
2388 static void PrePropertyHandlerGet(
2389     Local<String> key,
2390     const v8::PropertyCallbackInfo<v8::Value>& info) {
2391   ApiTestFuzzer::Fuzz();
2392   if (v8_str("pre")->Equals(key)) {
2393     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2394   }
2395 }
2396
2397
2398 static void PrePropertyHandlerQuery(
2399     Local<String> key,
2400     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2401   if (v8_str("pre")->Equals(key)) {
2402     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2403   }
2404 }
2405
2406
2407 THREADED_TEST(PrePropertyHandler) {
2408   v8::Isolate* isolate = CcTest::isolate();
2409   v8::HandleScope scope(isolate);
2410   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2411   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2412                                                     0,
2413                                                     PrePropertyHandlerQuery);
2414   LocalContext env(NULL, desc->InstanceTemplate());
2415   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2416   v8::Handle<Value> result_pre = CompileRun("pre");
2417   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2418   v8::Handle<Value> result_on = CompileRun("on");
2419   CHECK_EQ(v8_str("Object: on"), result_on);
2420   v8::Handle<Value> result_post = CompileRun("post");
2421   CHECK(result_post.IsEmpty());
2422 }
2423
2424
2425 THREADED_TEST(UndefinedIsNotEnumerable) {
2426   LocalContext env;
2427   v8::HandleScope scope(env->GetIsolate());
2428   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2429   CHECK(result->IsFalse());
2430 }
2431
2432
2433 v8::Handle<Script> call_recursively_script;
2434 static const int kTargetRecursionDepth = 200;  // near maximum
2435
2436
2437 static void CallScriptRecursivelyCall(
2438     const v8::FunctionCallbackInfo<v8::Value>& args) {
2439   ApiTestFuzzer::Fuzz();
2440   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2441   if (depth == kTargetRecursionDepth) return;
2442   args.This()->Set(v8_str("depth"),
2443                    v8::Integer::New(args.GetIsolate(), depth + 1));
2444   args.GetReturnValue().Set(call_recursively_script->Run());
2445 }
2446
2447
2448 static void CallFunctionRecursivelyCall(
2449     const v8::FunctionCallbackInfo<v8::Value>& args) {
2450   ApiTestFuzzer::Fuzz();
2451   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2452   if (depth == kTargetRecursionDepth) {
2453     printf("[depth = %d]\n", depth);
2454     return;
2455   }
2456   args.This()->Set(v8_str("depth"),
2457                    v8::Integer::New(args.GetIsolate(), depth + 1));
2458   v8::Handle<Value> function =
2459       args.This()->Get(v8_str("callFunctionRecursively"));
2460   args.GetReturnValue().Set(
2461       function.As<Function>()->Call(args.This(), 0, NULL));
2462 }
2463
2464
2465 THREADED_TEST(DeepCrossLanguageRecursion) {
2466   v8::Isolate* isolate = CcTest::isolate();
2467   v8::HandleScope scope(isolate);
2468   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2469   global->Set(v8_str("callScriptRecursively"),
2470               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2471   global->Set(v8_str("callFunctionRecursively"),
2472               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2473   LocalContext env(NULL, global);
2474
2475   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2476   call_recursively_script = v8_compile("callScriptRecursively()");
2477   call_recursively_script->Run();
2478   call_recursively_script = v8::Handle<Script>();
2479
2480   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2481   CompileRun("callFunctionRecursively()");
2482 }
2483
2484
2485 static void ThrowingPropertyHandlerGet(
2486     Local<String> key,
2487     const v8::PropertyCallbackInfo<v8::Value>& info) {
2488   ApiTestFuzzer::Fuzz();
2489   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2490 }
2491
2492
2493 static void ThrowingPropertyHandlerSet(
2494     Local<String> key,
2495     Local<Value>,
2496     const v8::PropertyCallbackInfo<v8::Value>& info) {
2497   info.GetIsolate()->ThrowException(key);
2498   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2499 }
2500
2501
2502 THREADED_TEST(CallbackExceptionRegression) {
2503   v8::Isolate* isolate = CcTest::isolate();
2504   v8::HandleScope scope(isolate);
2505   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2506   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2507                                ThrowingPropertyHandlerSet);
2508   LocalContext env;
2509   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2510   v8::Handle<Value> otto = CompileRun(
2511       "try { with (obj) { otto; } } catch (e) { e; }");
2512   CHECK_EQ(v8_str("otto"), otto);
2513   v8::Handle<Value> netto = CompileRun(
2514       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2515   CHECK_EQ(v8_str("netto"), netto);
2516 }
2517
2518
2519 THREADED_TEST(FunctionPrototype) {
2520   v8::Isolate* isolate = CcTest::isolate();
2521   v8::HandleScope scope(isolate);
2522   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2523   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2524   LocalContext env;
2525   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2526   Local<Script> script = v8_compile("Foo.prototype.plak");
2527   CHECK_EQ(script->Run()->Int32Value(), 321);
2528 }
2529
2530
2531 THREADED_TEST(InternalFields) {
2532   LocalContext env;
2533   v8::Isolate* isolate = env->GetIsolate();
2534   v8::HandleScope scope(isolate);
2535
2536   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2537   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2538   instance_templ->SetInternalFieldCount(1);
2539   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2540   CHECK_EQ(1, obj->InternalFieldCount());
2541   CHECK(obj->GetInternalField(0)->IsUndefined());
2542   obj->SetInternalField(0, v8_num(17));
2543   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2544 }
2545
2546
2547 THREADED_TEST(GlobalObjectInternalFields) {
2548   v8::Isolate* isolate = CcTest::isolate();
2549   v8::HandleScope scope(isolate);
2550   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2551   global_template->SetInternalFieldCount(1);
2552   LocalContext env(NULL, global_template);
2553   v8::Handle<v8::Object> global_proxy = env->Global();
2554   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2555   CHECK_EQ(1, global->InternalFieldCount());
2556   CHECK(global->GetInternalField(0)->IsUndefined());
2557   global->SetInternalField(0, v8_num(17));
2558   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2559 }
2560
2561
2562 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2563   LocalContext env;
2564   v8::HandleScope scope(CcTest::isolate());
2565
2566   v8::Local<v8::Object> global = env->Global();
2567   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2568   CHECK(global->HasRealIndexedProperty(0));
2569 }
2570
2571
2572 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2573                                                void* value) {
2574   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2575   obj->SetAlignedPointerInInternalField(0, value);
2576   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2577   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2578 }
2579
2580
2581 THREADED_TEST(InternalFieldsAlignedPointers) {
2582   LocalContext env;
2583   v8::Isolate* isolate = env->GetIsolate();
2584   v8::HandleScope scope(isolate);
2585
2586   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2587   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2588   instance_templ->SetInternalFieldCount(1);
2589   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2590   CHECK_EQ(1, obj->InternalFieldCount());
2591
2592   CheckAlignedPointerInInternalField(obj, NULL);
2593
2594   int* heap_allocated = new int[100];
2595   CheckAlignedPointerInInternalField(obj, heap_allocated);
2596   delete[] heap_allocated;
2597
2598   int stack_allocated[100];
2599   CheckAlignedPointerInInternalField(obj, stack_allocated);
2600
2601   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2602   CheckAlignedPointerInInternalField(obj, huge);
2603
2604   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2605   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2606   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2607 }
2608
2609
2610 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2611                                               int index,
2612                                               void* value) {
2613   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2614   (*env)->SetAlignedPointerInEmbedderData(index, value);
2615   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2616   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2617 }
2618
2619
2620 static void* AlignedTestPointer(int i) {
2621   return reinterpret_cast<void*>(i * 1234);
2622 }
2623
2624
2625 THREADED_TEST(EmbedderDataAlignedPointers) {
2626   LocalContext env;
2627   v8::HandleScope scope(env->GetIsolate());
2628
2629   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2630
2631   int* heap_allocated = new int[100];
2632   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2633   delete[] heap_allocated;
2634
2635   int stack_allocated[100];
2636   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2637
2638   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2639   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2640
2641   // Test growing of the embedder data's backing store.
2642   for (int i = 0; i < 100; i++) {
2643     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2644   }
2645   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2646   for (int i = 0; i < 100; i++) {
2647     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2648   }
2649 }
2650
2651
2652 static void CheckEmbedderData(LocalContext* env,
2653                               int index,
2654                               v8::Handle<Value> data) {
2655   (*env)->SetEmbedderData(index, data);
2656   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2657 }
2658
2659
2660 THREADED_TEST(EmbedderData) {
2661   LocalContext env;
2662   v8::Isolate* isolate = env->GetIsolate();
2663   v8::HandleScope scope(isolate);
2664
2665   CheckEmbedderData(
2666       &env, 3,
2667       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2668   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2669                                                      "over the lazy dog."));
2670   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2671   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2672 }
2673
2674
2675 THREADED_TEST(IdentityHash) {
2676   LocalContext env;
2677   v8::Isolate* isolate = env->GetIsolate();
2678   v8::HandleScope scope(isolate);
2679
2680   // Ensure that the test starts with an fresh heap to test whether the hash
2681   // code is based on the address.
2682   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2683   Local<v8::Object> obj = v8::Object::New(isolate);
2684   int hash = obj->GetIdentityHash();
2685   int hash1 = obj->GetIdentityHash();
2686   CHECK_EQ(hash, hash1);
2687   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2688   // Since the identity hash is essentially a random number two consecutive
2689   // objects should not be assigned the same hash code. If the test below fails
2690   // the random number generator should be evaluated.
2691   CHECK_NE(hash, hash2);
2692   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2693   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2694   // Make sure that the identity hash is not based on the initial address of
2695   // the object alone. If the test below fails the random number generator
2696   // should be evaluated.
2697   CHECK_NE(hash, hash3);
2698   int hash4 = obj->GetIdentityHash();
2699   CHECK_EQ(hash, hash4);
2700
2701   // Check identity hashes behaviour in the presence of JS accessors.
2702   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2703   {
2704     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2705     Local<v8::Object> o1 = v8::Object::New(isolate);
2706     Local<v8::Object> o2 = v8::Object::New(isolate);
2707     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2708   }
2709   {
2710     CompileRun(
2711         "function cnst() { return 42; };\n"
2712         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2713     Local<v8::Object> o1 = v8::Object::New(isolate);
2714     Local<v8::Object> o2 = v8::Object::New(isolate);
2715     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2716   }
2717 }
2718
2719
2720 THREADED_TEST(GlobalProxyIdentityHash) {
2721   LocalContext env;
2722   v8::Isolate* isolate = env->GetIsolate();
2723   v8::HandleScope scope(isolate);
2724   Handle<Object> global_proxy = env->Global();
2725   int hash1 = global_proxy->GetIdentityHash();
2726   // Hash should be retained after being detached.
2727   env->DetachGlobal();
2728   int hash2 = global_proxy->GetIdentityHash();
2729   CHECK_EQ(hash1, hash2);
2730   {
2731     // Re-attach global proxy to a new context, hash should stay the same.
2732     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2733     int hash3 = global_proxy->GetIdentityHash();
2734     CHECK_EQ(hash1, hash3);
2735   }
2736 }
2737
2738
2739 THREADED_TEST(SymbolProperties) {
2740   i::FLAG_harmony_symbols = true;
2741
2742   LocalContext env;
2743   v8::Isolate* isolate = env->GetIsolate();
2744   v8::HandleScope scope(isolate);
2745
2746   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2747   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2748   v8::Local<v8::Symbol> sym2 =
2749       v8::Symbol::New(isolate, v8_str("my-symbol"));
2750
2751   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2752
2753   // Check basic symbol functionality.
2754   CHECK(sym1->IsSymbol());
2755   CHECK(sym2->IsSymbol());
2756   CHECK(!obj->IsSymbol());
2757
2758   CHECK(sym1->Equals(sym1));
2759   CHECK(sym2->Equals(sym2));
2760   CHECK(!sym1->Equals(sym2));
2761   CHECK(!sym2->Equals(sym1));
2762   CHECK(sym1->StrictEquals(sym1));
2763   CHECK(sym2->StrictEquals(sym2));
2764   CHECK(!sym1->StrictEquals(sym2));
2765   CHECK(!sym2->StrictEquals(sym1));
2766
2767   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2768
2769   v8::Local<v8::Value> sym_val = sym2;
2770   CHECK(sym_val->IsSymbol());
2771   CHECK(sym_val->Equals(sym2));
2772   CHECK(sym_val->StrictEquals(sym2));
2773   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2774
2775   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2776   CHECK(sym_obj->IsSymbolObject());
2777   CHECK(!sym2->IsSymbolObject());
2778   CHECK(!obj->IsSymbolObject());
2779   CHECK(!sym_obj->Equals(sym2));
2780   CHECK(!sym_obj->StrictEquals(sym2));
2781   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2782   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2783
2784   // Make sure delete of a non-existent symbol property works.
2785   CHECK(obj->Delete(sym1));
2786   CHECK(!obj->Has(sym1));
2787
2788   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2789   CHECK(obj->Has(sym1));
2790   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2791   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2792   CHECK(obj->Has(sym1));
2793   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2794   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2795
2796   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2797   int num_props = obj->GetPropertyNames()->Length();
2798   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2799                  v8::Integer::New(isolate, 20)));
2800   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2801   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2802
2803   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2804
2805   // Add another property and delete it afterwards to force the object in
2806   // slow case.
2807   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2808   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2809   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2810   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2811   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2812
2813   CHECK(obj->Has(sym1));
2814   CHECK(obj->Has(sym2));
2815   CHECK(obj->Delete(sym2));
2816   CHECK(obj->Has(sym1));
2817   CHECK(!obj->Has(sym2));
2818   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2819   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2820
2821   // Symbol properties are inherited.
2822   v8::Local<v8::Object> child = v8::Object::New(isolate);
2823   child->SetPrototype(obj);
2824   CHECK(child->Has(sym1));
2825   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2826   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2827 }
2828
2829
2830 THREADED_TEST(PrivateProperties) {
2831   LocalContext env;
2832   v8::Isolate* isolate = env->GetIsolate();
2833   v8::HandleScope scope(isolate);
2834
2835   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2836   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2837   v8::Local<v8::Private> priv2 =
2838       v8::Private::New(isolate, v8_str("my-private"));
2839
2840   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2841
2842   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2843
2844   // Make sure delete of a non-existent private symbol property works.
2845   CHECK(obj->DeletePrivate(priv1));
2846   CHECK(!obj->HasPrivate(priv1));
2847
2848   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2849   CHECK(obj->HasPrivate(priv1));
2850   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2851   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2852   CHECK(obj->HasPrivate(priv1));
2853   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2854
2855   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2856   int num_props = obj->GetPropertyNames()->Length();
2857   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2858                  v8::Integer::New(isolate, 20)));
2859   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2860   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2861
2862   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2863
2864   // Add another property and delete it afterwards to force the object in
2865   // slow case.
2866   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2867   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2868   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2869   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2870   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2871
2872   CHECK(obj->HasPrivate(priv1));
2873   CHECK(obj->HasPrivate(priv2));
2874   CHECK(obj->DeletePrivate(priv2));
2875   CHECK(obj->HasPrivate(priv1));
2876   CHECK(!obj->HasPrivate(priv2));
2877   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2878   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2879
2880   // Private properties are inherited (for the time being).
2881   v8::Local<v8::Object> child = v8::Object::New(isolate);
2882   child->SetPrototype(obj);
2883   CHECK(child->HasPrivate(priv1));
2884   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2885   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2886 }
2887
2888
2889 THREADED_TEST(GlobalSymbols) {
2890   i::FLAG_harmony_symbols = true;
2891
2892   LocalContext env;
2893   v8::Isolate* isolate = env->GetIsolate();
2894   v8::HandleScope scope(isolate);
2895
2896   v8::Local<String> name = v8_str("my-symbol");
2897   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2898   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2899   CHECK(glob2->SameValue(glob));
2900
2901   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2902   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2903   CHECK(glob_api2->SameValue(glob_api));
2904   CHECK(!glob_api->SameValue(glob));
2905
2906   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2907   CHECK(!sym->SameValue(glob));
2908
2909   CompileRun("var sym2 = Symbol.for('my-symbol')");
2910   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2911   CHECK(sym2->SameValue(glob));
2912   CHECK(!sym2->SameValue(glob_api));
2913 }
2914
2915
2916 THREADED_TEST(GlobalPrivates) {
2917   LocalContext env;
2918   v8::Isolate* isolate = env->GetIsolate();
2919   v8::HandleScope scope(isolate);
2920
2921   v8::Local<String> name = v8_str("my-private");
2922   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2923   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2924   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2925
2926   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2927   CHECK(obj->HasPrivate(glob2));
2928
2929   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2930   CHECK(!obj->HasPrivate(priv));
2931
2932   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2933   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2934   CHECK(!obj->Has(intern));
2935 }
2936
2937
2938 class ScopedArrayBufferContents {
2939  public:
2940   explicit ScopedArrayBufferContents(
2941       const v8::ArrayBuffer::Contents& contents)
2942     : contents_(contents) {}
2943   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2944   void* Data() const { return contents_.Data(); }
2945   size_t ByteLength() const { return contents_.ByteLength(); }
2946  private:
2947   const v8::ArrayBuffer::Contents contents_;
2948 };
2949
2950 template <typename T>
2951 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2952   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2953   for (int i = 0; i < value->InternalFieldCount(); i++) {
2954     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2955   }
2956 }
2957
2958
2959 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2960   LocalContext env;
2961   v8::Isolate* isolate = env->GetIsolate();
2962   v8::HandleScope handle_scope(isolate);
2963
2964   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2965   CheckInternalFieldsAreZero(ab);
2966   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2967   CHECK(!ab->IsExternal());
2968   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2969
2970   ScopedArrayBufferContents ab_contents(ab->Externalize());
2971   CHECK(ab->IsExternal());
2972
2973   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2974   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2975   ASSERT(data != NULL);
2976   env->Global()->Set(v8_str("ab"), ab);
2977
2978   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2979   CHECK_EQ(1024, result->Int32Value());
2980
2981   result = CompileRun("var u8 = new Uint8Array(ab);"
2982                       "u8[0] = 0xFF;"
2983                       "u8[1] = 0xAA;"
2984                       "u8.length");
2985   CHECK_EQ(1024, result->Int32Value());
2986   CHECK_EQ(0xFF, data[0]);
2987   CHECK_EQ(0xAA, data[1]);
2988   data[0] = 0xCC;
2989   data[1] = 0x11;
2990   result = CompileRun("u8[0] + u8[1]");
2991   CHECK_EQ(0xDD, result->Int32Value());
2992 }
2993
2994
2995 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2996   LocalContext env;
2997   v8::Isolate* isolate = env->GetIsolate();
2998   v8::HandleScope handle_scope(isolate);
2999
3000
3001   v8::Local<v8::Value> result =
3002       CompileRun("var ab1 = new ArrayBuffer(2);"
3003                  "var u8_a = new Uint8Array(ab1);"
3004                  "u8_a[0] = 0xAA;"
3005                  "u8_a[1] = 0xFF; u8_a.buffer");
3006   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3007   CheckInternalFieldsAreZero(ab1);
3008   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3009   CHECK(!ab1->IsExternal());
3010   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3011   CHECK(ab1->IsExternal());
3012
3013   result = CompileRun("ab1.byteLength");
3014   CHECK_EQ(2, result->Int32Value());
3015   result = CompileRun("u8_a[0]");
3016   CHECK_EQ(0xAA, result->Int32Value());
3017   result = CompileRun("u8_a[1]");
3018   CHECK_EQ(0xFF, result->Int32Value());
3019   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3020                       "u8_b[0] = 0xBB;"
3021                       "u8_a[0]");
3022   CHECK_EQ(0xBB, result->Int32Value());
3023   result = CompileRun("u8_b[1]");
3024   CHECK_EQ(0xFF, result->Int32Value());
3025
3026   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3027   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3028   CHECK_EQ(0xBB, ab1_data[0]);
3029   CHECK_EQ(0xFF, ab1_data[1]);
3030   ab1_data[0] = 0xCC;
3031   ab1_data[1] = 0x11;
3032   result = CompileRun("u8_a[0] + u8_a[1]");
3033   CHECK_EQ(0xDD, result->Int32Value());
3034 }
3035
3036
3037 THREADED_TEST(ArrayBuffer_External) {
3038   LocalContext env;
3039   v8::Isolate* isolate = env->GetIsolate();
3040   v8::HandleScope handle_scope(isolate);
3041
3042   i::ScopedVector<uint8_t> my_data(100);
3043   memset(my_data.start(), 0, 100);
3044   Local<v8::ArrayBuffer> ab3 =
3045       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3046   CheckInternalFieldsAreZero(ab3);
3047   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3048   CHECK(ab3->IsExternal());
3049
3050   env->Global()->Set(v8_str("ab3"), ab3);
3051
3052   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3053   CHECK_EQ(100, result->Int32Value());
3054
3055   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3056                       "u8_b[0] = 0xBB;"
3057                       "u8_b[1] = 0xCC;"
3058                       "u8_b.length");
3059   CHECK_EQ(100, result->Int32Value());
3060   CHECK_EQ(0xBB, my_data[0]);
3061   CHECK_EQ(0xCC, my_data[1]);
3062   my_data[0] = 0xCC;
3063   my_data[1] = 0x11;
3064   result = CompileRun("u8_b[0] + u8_b[1]");
3065   CHECK_EQ(0xDD, result->Int32Value());
3066 }
3067
3068
3069 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3070   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3071   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3072 }
3073
3074
3075 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3076   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3077   CHECK_EQ(0, static_cast<int>(ta->Length()));
3078   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3079 }
3080
3081
3082 static void CheckIsTypedArrayVarNeutered(const char* name) {
3083   i::ScopedVector<char> source(1024);
3084   i::SNPrintF(source,
3085       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3086       name, name, name);
3087   CHECK(CompileRun(source.start())->IsTrue());
3088   v8::Handle<v8::TypedArray> ta =
3089     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3090   CheckIsNeutered(ta);
3091 }
3092
3093
3094 template <typename TypedArray, int kElementSize>
3095 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3096                                          int byteOffset,
3097                                          int length) {
3098   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3099   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3100   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3101   CHECK_EQ(length, static_cast<int>(ta->Length()));
3102   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3103   return ta;
3104 }
3105
3106
3107 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3108   LocalContext env;
3109   v8::Isolate* isolate = env->GetIsolate();
3110   v8::HandleScope handle_scope(isolate);
3111
3112   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3113
3114   v8::Handle<v8::Uint8Array> u8a =
3115     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3116   v8::Handle<v8::Uint8ClampedArray> u8c =
3117     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3118   v8::Handle<v8::Int8Array> i8a =
3119     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3120
3121   v8::Handle<v8::Uint16Array> u16a =
3122     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3123   v8::Handle<v8::Int16Array> i16a =
3124     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3125
3126   v8::Handle<v8::Uint32Array> u32a =
3127     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3128   v8::Handle<v8::Int32Array> i32a =
3129     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3130
3131   v8::Handle<v8::Float32Array> f32a =
3132     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3133   v8::Handle<v8::Float64Array> f64a =
3134     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3135
3136   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3137   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3138   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3139   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3140
3141   ScopedArrayBufferContents contents(buffer->Externalize());
3142   buffer->Neuter();
3143   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3144   CheckIsNeutered(u8a);
3145   CheckIsNeutered(u8c);
3146   CheckIsNeutered(i8a);
3147   CheckIsNeutered(u16a);
3148   CheckIsNeutered(i16a);
3149   CheckIsNeutered(u32a);
3150   CheckIsNeutered(i32a);
3151   CheckIsNeutered(f32a);
3152   CheckIsNeutered(f64a);
3153   CheckDataViewIsNeutered(dv);
3154 }
3155
3156
3157 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3158   LocalContext env;
3159   v8::Isolate* isolate = env->GetIsolate();
3160   v8::HandleScope handle_scope(isolate);
3161
3162   CompileRun(
3163       "var ab = new ArrayBuffer(1024);"
3164       "var u8a = new Uint8Array(ab, 1, 1023);"
3165       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3166       "var i8a = new Int8Array(ab, 1, 1023);"
3167       "var u16a = new Uint16Array(ab, 2, 511);"
3168       "var i16a = new Int16Array(ab, 2, 511);"
3169       "var u32a = new Uint32Array(ab, 4, 255);"
3170       "var i32a = new Int32Array(ab, 4, 255);"
3171       "var f32a = new Float32Array(ab, 4, 255);"
3172       "var f64a = new Float64Array(ab, 8, 127);"
3173       "var dv = new DataView(ab, 1, 1023);");
3174
3175   v8::Handle<v8::ArrayBuffer> ab =
3176       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3177
3178   v8::Handle<v8::DataView> dv =
3179     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3180
3181   ScopedArrayBufferContents contents(ab->Externalize());
3182   ab->Neuter();
3183   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3184   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3185
3186   CheckIsTypedArrayVarNeutered("u8a");
3187   CheckIsTypedArrayVarNeutered("u8c");
3188   CheckIsTypedArrayVarNeutered("i8a");
3189   CheckIsTypedArrayVarNeutered("u16a");
3190   CheckIsTypedArrayVarNeutered("i16a");
3191   CheckIsTypedArrayVarNeutered("u32a");
3192   CheckIsTypedArrayVarNeutered("i32a");
3193   CheckIsTypedArrayVarNeutered("f32a");
3194   CheckIsTypedArrayVarNeutered("f64a");
3195
3196   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3197   CheckDataViewIsNeutered(dv);
3198 }
3199
3200
3201
3202 THREADED_TEST(HiddenProperties) {
3203   LocalContext env;
3204   v8::Isolate* isolate = env->GetIsolate();
3205   v8::HandleScope scope(isolate);
3206
3207   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3208   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3209   v8::Local<v8::String> empty = v8_str("");
3210   v8::Local<v8::String> prop_name = v8_str("prop_name");
3211
3212   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3213
3214   // Make sure delete of a non-existent hidden value works
3215   CHECK(obj->DeleteHiddenValue(key));
3216
3217   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3218   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3219   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3220   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3221
3222   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3223
3224   // Make sure we do not find the hidden property.
3225   CHECK(!obj->Has(empty));
3226   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3227   CHECK(obj->Get(empty)->IsUndefined());
3228   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3229   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3230   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3231   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3232
3233   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3234
3235   // Add another property and delete it afterwards to force the object in
3236   // slow case.
3237   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3238   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3240   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3241   CHECK(obj->Delete(prop_name));
3242   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3243
3244   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3245
3246   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3247   CHECK(obj->GetHiddenValue(key).IsEmpty());
3248
3249   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3250   CHECK(obj->DeleteHiddenValue(key));
3251   CHECK(obj->GetHiddenValue(key).IsEmpty());
3252 }
3253
3254
3255 THREADED_TEST(Regress97784) {
3256   // Regression test for crbug.com/97784
3257   // Messing with the Object.prototype should not have effect on
3258   // hidden properties.
3259   LocalContext env;
3260   v8::HandleScope scope(env->GetIsolate());
3261
3262   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3263   v8::Local<v8::String> key = v8_str("hidden");
3264
3265   CompileRun(
3266       "set_called = false;"
3267       "Object.defineProperty("
3268       "    Object.prototype,"
3269       "    'hidden',"
3270       "    {get: function() { return 45; },"
3271       "     set: function() { set_called = true; }})");
3272
3273   CHECK(obj->GetHiddenValue(key).IsEmpty());
3274   // Make sure that the getter and setter from Object.prototype is not invoked.
3275   // If it did we would have full access to the hidden properties in
3276   // the accessor.
3277   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3278   ExpectFalse("set_called");
3279   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3280 }
3281
3282
3283 static bool interceptor_for_hidden_properties_called;
3284 static void InterceptorForHiddenProperties(
3285     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3286   interceptor_for_hidden_properties_called = true;
3287 }
3288
3289
3290 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3291   LocalContext context;
3292   v8::Isolate* isolate = context->GetIsolate();
3293   v8::HandleScope scope(isolate);
3294
3295   interceptor_for_hidden_properties_called = false;
3296
3297   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3298
3299   // Associate an interceptor with an object and start setting hidden values.
3300   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3301   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3302   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3303   Local<v8::Function> function = fun_templ->GetFunction();
3304   Local<v8::Object> obj = function->NewInstance();
3305   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3306   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3307   CHECK(!interceptor_for_hidden_properties_called);
3308 }
3309
3310
3311 THREADED_TEST(External) {
3312   v8::HandleScope scope(CcTest::isolate());
3313   int x = 3;
3314   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3315   LocalContext env;
3316   env->Global()->Set(v8_str("ext"), ext);
3317   Local<Value> reext_obj = CompileRun("this.ext");
3318   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3319   int* ptr = static_cast<int*>(reext->Value());
3320   CHECK_EQ(x, 3);
3321   *ptr = 10;
3322   CHECK_EQ(x, 10);
3323
3324   // Make sure unaligned pointers are wrapped properly.
3325   char* data = i::StrDup("0123456789");
3326   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3327   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3328   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3329   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3330
3331   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3332   CHECK_EQ('0', *char_ptr);
3333   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3334   CHECK_EQ('1', *char_ptr);
3335   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3336   CHECK_EQ('2', *char_ptr);
3337   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3338   CHECK_EQ('3', *char_ptr);
3339   i::DeleteArray(data);
3340 }
3341
3342
3343 THREADED_TEST(GlobalHandle) {
3344   v8::Isolate* isolate = CcTest::isolate();
3345   v8::Persistent<String> global;
3346   {
3347     v8::HandleScope scope(isolate);
3348     global.Reset(isolate, v8_str("str"));
3349   }
3350   {
3351     v8::HandleScope scope(isolate);
3352     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3353   }
3354   global.Reset();
3355   {
3356     v8::HandleScope scope(isolate);
3357     global.Reset(isolate, v8_str("str"));
3358   }
3359   {
3360     v8::HandleScope scope(isolate);
3361     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3362   }
3363   global.Reset();
3364 }
3365
3366
3367 THREADED_TEST(ResettingGlobalHandle) {
3368   v8::Isolate* isolate = CcTest::isolate();
3369   v8::Persistent<String> global;
3370   {
3371     v8::HandleScope scope(isolate);
3372     global.Reset(isolate, v8_str("str"));
3373   }
3374   v8::internal::GlobalHandles* global_handles =
3375       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3376   int initial_handle_count = global_handles->global_handles_count();
3377   {
3378     v8::HandleScope scope(isolate);
3379     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3380   }
3381   {
3382     v8::HandleScope scope(isolate);
3383     global.Reset(isolate, v8_str("longer"));
3384   }
3385   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3386   {
3387     v8::HandleScope scope(isolate);
3388     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3389   }
3390   global.Reset();
3391   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3392 }
3393
3394
3395 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3396   v8::Isolate* isolate = CcTest::isolate();
3397   v8::Persistent<String> global;
3398   {
3399     v8::HandleScope scope(isolate);
3400     global.Reset(isolate, v8_str("str"));
3401   }
3402   v8::internal::GlobalHandles* global_handles =
3403       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3404   int initial_handle_count = global_handles->global_handles_count();
3405   {
3406     v8::HandleScope scope(isolate);
3407     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3408   }
3409   {
3410     v8::HandleScope scope(isolate);
3411     Local<String> empty;
3412     global.Reset(isolate, empty);
3413   }
3414   CHECK(global.IsEmpty());
3415   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3416 }
3417
3418
3419 template<class T>
3420 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3421   return unique.Pass();
3422 }
3423
3424
3425 template<class T>
3426 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3427                                             const v8::Persistent<T> & global) {
3428   v8::UniquePersistent<String> unique(isolate, global);
3429   return unique.Pass();
3430 }
3431
3432
3433 THREADED_TEST(UniquePersistent) {
3434   v8::Isolate* isolate = CcTest::isolate();
3435   v8::Persistent<String> global;
3436   {
3437     v8::HandleScope scope(isolate);
3438     global.Reset(isolate, v8_str("str"));
3439   }
3440   v8::internal::GlobalHandles* global_handles =
3441       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3442   int initial_handle_count = global_handles->global_handles_count();
3443   {
3444     v8::UniquePersistent<String> unique(isolate, global);
3445     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3446     // Test assignment via Pass
3447     {
3448       v8::UniquePersistent<String> copy = unique.Pass();
3449       CHECK(unique.IsEmpty());
3450       CHECK(copy == global);
3451       CHECK_EQ(initial_handle_count + 1,
3452                global_handles->global_handles_count());
3453       unique = copy.Pass();
3454     }
3455     // Test ctor via Pass
3456     {
3457       v8::UniquePersistent<String> copy(unique.Pass());
3458       CHECK(unique.IsEmpty());
3459       CHECK(copy == global);
3460       CHECK_EQ(initial_handle_count + 1,
3461                global_handles->global_handles_count());
3462       unique = copy.Pass();
3463     }
3464     // Test pass through function call
3465     {
3466       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3467       CHECK(unique.IsEmpty());
3468       CHECK(copy == global);
3469       CHECK_EQ(initial_handle_count + 1,
3470                global_handles->global_handles_count());
3471       unique = copy.Pass();
3472     }
3473     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3474   }
3475   // Test pass from function call
3476   {
3477     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3478     CHECK(unique == global);
3479     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3480   }
3481   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3482   global.Reset();
3483 }
3484
3485
3486 template<typename K, typename V>
3487 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3488  public:
3489   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3490       MapType;
3491   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3492   struct WeakCallbackDataType {
3493     MapType* map;
3494     K key;
3495   };
3496   static WeakCallbackDataType* WeakCallbackParameter(
3497       MapType* map, const K& key, Local<V> value) {
3498     WeakCallbackDataType* data = new WeakCallbackDataType;
3499     data->map = map;
3500     data->key = key;
3501     return data;
3502   }
3503   static MapType* MapFromWeakCallbackData(
3504       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3505     return data.GetParameter()->map;
3506   }
3507   static K KeyFromWeakCallbackData(
3508       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3509     return data.GetParameter()->key;
3510   }
3511   static void DisposeCallbackData(WeakCallbackDataType* data) {
3512     delete data;
3513   }
3514   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3515       K key) { }
3516 };
3517
3518
3519 template<typename Map>
3520 static void TestPersistentValueMap() {
3521   LocalContext env;
3522   v8::Isolate* isolate = env->GetIsolate();
3523   Map map(isolate);
3524   v8::internal::GlobalHandles* global_handles =
3525       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3526   int initial_handle_count = global_handles->global_handles_count();
3527   CHECK_EQ(0, static_cast<int>(map.Size()));
3528   {
3529     HandleScope scope(isolate);
3530     Local<v8::Object> obj = map.Get(7);
3531     CHECK(obj.IsEmpty());
3532     Local<v8::Object> expected = v8::Object::New(isolate);
3533     map.Set(7, expected);
3534     CHECK_EQ(1, static_cast<int>(map.Size()));
3535     obj = map.Get(7);
3536     CHECK_EQ(expected, obj);
3537     {
3538       typename Map::PersistentValueReference ref = map.GetReference(7);
3539       CHECK_EQ(expected, ref.NewLocal(isolate));
3540     }
3541     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3542     CHECK_EQ(0, static_cast<int>(map.Size()));
3543     CHECK(expected == removed);
3544     removed = map.Remove(7);
3545     CHECK(removed.IsEmpty());
3546     map.Set(8, expected);
3547     CHECK_EQ(1, static_cast<int>(map.Size()));
3548     map.Set(8, expected);
3549     CHECK_EQ(1, static_cast<int>(map.Size()));
3550     {
3551       typename Map::PersistentValueReference ref;
3552       Local<v8::Object> expected2 = v8::Object::New(isolate);
3553       removed = map.Set(8,
3554           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3555       CHECK_EQ(1, static_cast<int>(map.Size()));
3556       CHECK(expected == removed);
3557       CHECK_EQ(expected2, ref.NewLocal(isolate));
3558     }
3559   }
3560   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3561   if (map.IsWeak()) {
3562     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3563         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3564   } else {
3565     map.Clear();
3566   }
3567   CHECK_EQ(0, static_cast<int>(map.Size()));
3568   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3569 }
3570
3571
3572 TEST(PersistentValueMap) {
3573   // Default case, w/o weak callbacks:
3574   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3575
3576   // Custom traits with weak callbacks:
3577   typedef v8::PersistentValueMap<int, v8::Object,
3578       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3579   TestPersistentValueMap<WeakPersistentValueMap>();
3580 }
3581
3582
3583 TEST(PersistentValueVector) {
3584   LocalContext env;
3585   v8::Isolate* isolate = env->GetIsolate();
3586   v8::internal::GlobalHandles* global_handles =
3587       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3588   int handle_count = global_handles->global_handles_count();
3589   HandleScope scope(isolate);
3590
3591   v8::PersistentValueVector<v8::Object> vector(isolate);
3592
3593   Local<v8::Object> obj1 = v8::Object::New(isolate);
3594   Local<v8::Object> obj2 = v8::Object::New(isolate);
3595   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3596
3597   CHECK(vector.IsEmpty());
3598   CHECK_EQ(0, static_cast<int>(vector.Size()));
3599
3600   vector.ReserveCapacity(3);
3601   CHECK(vector.IsEmpty());
3602
3603   vector.Append(obj1);
3604   vector.Append(obj2);
3605   vector.Append(obj1);
3606   vector.Append(obj3.Pass());
3607   vector.Append(obj1);
3608
3609   CHECK(!vector.IsEmpty());
3610   CHECK_EQ(5, static_cast<int>(vector.Size()));
3611   CHECK(obj3.IsEmpty());
3612   CHECK_EQ(obj1, vector.Get(0));
3613   CHECK_EQ(obj1, vector.Get(2));
3614   CHECK_EQ(obj1, vector.Get(4));
3615   CHECK_EQ(obj2, vector.Get(1));
3616
3617   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3618
3619   vector.Clear();
3620   CHECK(vector.IsEmpty());
3621   CHECK_EQ(0, static_cast<int>(vector.Size()));
3622   CHECK_EQ(handle_count, global_handles->global_handles_count());
3623 }
3624
3625
3626 THREADED_TEST(GlobalHandleUpcast) {
3627   v8::Isolate* isolate = CcTest::isolate();
3628   v8::HandleScope scope(isolate);
3629   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3630   v8::Persistent<String> global_string(isolate, local);
3631   v8::Persistent<Value>& global_value =
3632       v8::Persistent<Value>::Cast(global_string);
3633   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3634   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3635   global_string.Reset();
3636 }
3637
3638
3639 THREADED_TEST(HandleEquality) {
3640   v8::Isolate* isolate = CcTest::isolate();
3641   v8::Persistent<String> global1;
3642   v8::Persistent<String> global2;
3643   {
3644     v8::HandleScope scope(isolate);
3645     global1.Reset(isolate, v8_str("str"));
3646     global2.Reset(isolate, v8_str("str2"));
3647   }
3648   CHECK_EQ(global1 == global1, true);
3649   CHECK_EQ(global1 != global1, false);
3650   {
3651     v8::HandleScope scope(isolate);
3652     Local<String> local1 = Local<String>::New(isolate, global1);
3653     Local<String> local2 = Local<String>::New(isolate, global2);
3654
3655     CHECK_EQ(global1 == local1, true);
3656     CHECK_EQ(global1 != local1, false);
3657     CHECK_EQ(local1 == global1, true);
3658     CHECK_EQ(local1 != global1, false);
3659
3660     CHECK_EQ(global1 == local2, false);
3661     CHECK_EQ(global1 != local2, true);
3662     CHECK_EQ(local2 == global1, false);
3663     CHECK_EQ(local2 != global1, true);
3664
3665     CHECK_EQ(local1 == local2, false);
3666     CHECK_EQ(local1 != local2, true);
3667
3668     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3669     CHECK_EQ(local1 == anotherLocal1, true);
3670     CHECK_EQ(local1 != anotherLocal1, false);
3671   }
3672   global1.Reset();
3673   global2.Reset();
3674 }
3675
3676
3677 THREADED_TEST(LocalHandle) {
3678   v8::HandleScope scope(CcTest::isolate());
3679   v8::Local<String> local =
3680       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3681   CHECK_EQ(local->Length(), 3);
3682 }
3683
3684
3685 class WeakCallCounter {
3686  public:
3687   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3688   int id() { return id_; }
3689   void increment() { number_of_weak_calls_++; }
3690   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3691  private:
3692   int id_;
3693   int number_of_weak_calls_;
3694 };
3695
3696
3697 template<typename T>
3698 struct WeakCallCounterAndPersistent {
3699   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3700       : counter(counter) {}
3701   WeakCallCounter* counter;
3702   v8::Persistent<T> handle;
3703 };
3704
3705
3706 template <typename T>
3707 static void WeakPointerCallback(
3708     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3709   CHECK_EQ(1234, data.GetParameter()->counter->id());
3710   data.GetParameter()->counter->increment();
3711   data.GetParameter()->handle.Reset();
3712 }
3713
3714
3715 template<typename T>
3716 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3717   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3718 }
3719
3720
3721 THREADED_TEST(ApiObjectGroups) {
3722   LocalContext env;
3723   v8::Isolate* iso = env->GetIsolate();
3724   HandleScope scope(iso);
3725
3726   WeakCallCounter counter(1234);
3727
3728   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3729   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3730   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3731   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3732   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3733   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3734
3735   {
3736     HandleScope scope(iso);
3737     g1s1.handle.Reset(iso, Object::New(iso));
3738     g1s2.handle.Reset(iso, Object::New(iso));
3739     g1c1.handle.Reset(iso, Object::New(iso));
3740     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3741     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3742     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3743
3744     g2s1.handle.Reset(iso, Object::New(iso));
3745     g2s2.handle.Reset(iso, Object::New(iso));
3746     g2c1.handle.Reset(iso, Object::New(iso));
3747     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3748     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3749     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3750   }
3751
3752   WeakCallCounterAndPersistent<Value> root(&counter);
3753   root.handle.Reset(iso, g1s1.handle);  // make a root.
3754
3755   // Connect group 1 and 2, make a cycle.
3756   {
3757     HandleScope scope(iso);
3758     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3759             Set(0, Local<Value>::New(iso, g2s2.handle)));
3760     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3761             Set(0, Local<Value>::New(iso, g1s1.handle)));
3762   }
3763
3764   {
3765     UniqueId id1 = MakeUniqueId(g1s1.handle);
3766     UniqueId id2 = MakeUniqueId(g2s2.handle);
3767     iso->SetObjectGroupId(g1s1.handle, id1);
3768     iso->SetObjectGroupId(g1s2.handle, id1);
3769     iso->SetReferenceFromGroup(id1, g1c1.handle);
3770     iso->SetObjectGroupId(g2s1.handle, id2);
3771     iso->SetObjectGroupId(g2s2.handle, id2);
3772     iso->SetReferenceFromGroup(id2, g2c1.handle);
3773   }
3774   // Do a single full GC, ensure incremental marking is stopped.
3775   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3776       iso)->heap();
3777   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3778
3779   // All object should be alive.
3780   CHECK_EQ(0, counter.NumberOfWeakCalls());
3781
3782   // Weaken the root.
3783   root.handle.SetWeak(&root, &WeakPointerCallback);
3784   // But make children strong roots---all the objects (except for children)
3785   // should be collectable now.
3786   g1c1.handle.ClearWeak();
3787   g2c1.handle.ClearWeak();
3788
3789   // Groups are deleted, rebuild groups.
3790   {
3791     UniqueId id1 = MakeUniqueId(g1s1.handle);
3792     UniqueId id2 = MakeUniqueId(g2s2.handle);
3793     iso->SetObjectGroupId(g1s1.handle, id1);
3794     iso->SetObjectGroupId(g1s2.handle, id1);
3795     iso->SetReferenceFromGroup(id1, g1c1.handle);
3796     iso->SetObjectGroupId(g2s1.handle, id2);
3797     iso->SetObjectGroupId(g2s2.handle, id2);
3798     iso->SetReferenceFromGroup(id2, g2c1.handle);
3799   }
3800
3801   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3802
3803   // All objects should be gone. 5 global handles in total.
3804   CHECK_EQ(5, counter.NumberOfWeakCalls());
3805
3806   // And now make children weak again and collect them.
3807   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3808   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3809
3810   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3811   CHECK_EQ(7, counter.NumberOfWeakCalls());
3812 }
3813
3814
3815 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3816   LocalContext env;
3817   v8::Isolate* iso = env->GetIsolate();
3818   HandleScope scope(iso);
3819
3820   WeakCallCounter counter(1234);
3821
3822   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3823   WeakCallCounterAndPersistent<String> g1s2(&counter);
3824   WeakCallCounterAndPersistent<String> g1c1(&counter);
3825   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3826   WeakCallCounterAndPersistent<String> g2s2(&counter);
3827   WeakCallCounterAndPersistent<String> g2c1(&counter);
3828
3829   {
3830     HandleScope scope(iso);
3831     g1s1.handle.Reset(iso, Object::New(iso));
3832     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3833     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3834     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3835     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3836     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3837
3838     g2s1.handle.Reset(iso, Object::New(iso));
3839     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3840     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3841     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3842     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3843     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3844   }
3845
3846   WeakCallCounterAndPersistent<Value> root(&counter);
3847   root.handle.Reset(iso, g1s1.handle);  // make a root.
3848
3849   // Connect group 1 and 2, make a cycle.
3850   {
3851     HandleScope scope(iso);
3852     CHECK(Local<Object>::New(iso, g1s1.handle)
3853               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3854     CHECK(Local<Object>::New(iso, g2s1.handle)
3855               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3856   }
3857
3858   {
3859     UniqueId id1 = MakeUniqueId(g1s1.handle);
3860     UniqueId id2 = MakeUniqueId(g2s2.handle);
3861     iso->SetObjectGroupId(g1s1.handle, id1);
3862     iso->SetObjectGroupId(g1s2.handle, id1);
3863     iso->SetReference(g1s1.handle, g1c1.handle);
3864     iso->SetObjectGroupId(g2s1.handle, id2);
3865     iso->SetObjectGroupId(g2s2.handle, id2);
3866     iso->SetReferenceFromGroup(id2, g2c1.handle);
3867   }
3868   // Do a single full GC, ensure incremental marking is stopped.
3869   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3870       iso)->heap();
3871   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3872
3873   // All object should be alive.
3874   CHECK_EQ(0, counter.NumberOfWeakCalls());
3875
3876   // Weaken the root.
3877   root.handle.SetWeak(&root, &WeakPointerCallback);
3878   // But make children strong roots---all the objects (except for children)
3879   // should be collectable now.
3880   g1c1.handle.ClearWeak();
3881   g2c1.handle.ClearWeak();
3882
3883   // Groups are deleted, rebuild groups.
3884   {
3885     UniqueId id1 = MakeUniqueId(g1s1.handle);
3886     UniqueId id2 = MakeUniqueId(g2s2.handle);
3887     iso->SetObjectGroupId(g1s1.handle, id1);
3888     iso->SetObjectGroupId(g1s2.handle, id1);
3889     iso->SetReference(g1s1.handle, g1c1.handle);
3890     iso->SetObjectGroupId(g2s1.handle, id2);
3891     iso->SetObjectGroupId(g2s2.handle, id2);
3892     iso->SetReferenceFromGroup(id2, g2c1.handle);
3893   }
3894
3895   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3896
3897   // All objects should be gone. 5 global handles in total.
3898   CHECK_EQ(5, counter.NumberOfWeakCalls());
3899
3900   // And now make children weak again and collect them.
3901   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3902   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3903
3904   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3905   CHECK_EQ(7, counter.NumberOfWeakCalls());
3906 }
3907
3908
3909 THREADED_TEST(ApiObjectGroupsCycle) {
3910   LocalContext env;
3911   v8::Isolate* iso = env->GetIsolate();
3912   HandleScope scope(iso);
3913
3914   WeakCallCounter counter(1234);
3915
3916   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3917   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3918   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3919   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3920   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3921   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3922   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3923   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3924
3925   {
3926     HandleScope scope(iso);
3927     g1s1.handle.Reset(iso, Object::New(iso));
3928     g1s2.handle.Reset(iso, Object::New(iso));
3929     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3930     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3931     CHECK(g1s1.handle.IsWeak());
3932     CHECK(g1s2.handle.IsWeak());
3933
3934     g2s1.handle.Reset(iso, Object::New(iso));
3935     g2s2.handle.Reset(iso, Object::New(iso));
3936     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3937     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3938     CHECK(g2s1.handle.IsWeak());
3939     CHECK(g2s2.handle.IsWeak());
3940
3941     g3s1.handle.Reset(iso, Object::New(iso));
3942     g3s2.handle.Reset(iso, Object::New(iso));
3943     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3944     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3945     CHECK(g3s1.handle.IsWeak());
3946     CHECK(g3s2.handle.IsWeak());
3947
3948     g4s1.handle.Reset(iso, Object::New(iso));
3949     g4s2.handle.Reset(iso, Object::New(iso));
3950     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3951     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3952     CHECK(g4s1.handle.IsWeak());
3953     CHECK(g4s2.handle.IsWeak());
3954   }
3955
3956   WeakCallCounterAndPersistent<Value> root(&counter);
3957   root.handle.Reset(iso, g1s1.handle);  // make a root.
3958
3959   // Connect groups.  We're building the following cycle:
3960   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3961   // groups.
3962   {
3963     UniqueId id1 = MakeUniqueId(g1s1.handle);
3964     UniqueId id2 = MakeUniqueId(g2s1.handle);
3965     UniqueId id3 = MakeUniqueId(g3s1.handle);
3966     UniqueId id4 = MakeUniqueId(g4s1.handle);
3967     iso->SetObjectGroupId(g1s1.handle, id1);
3968     iso->SetObjectGroupId(g1s2.handle, id1);
3969     iso->SetReferenceFromGroup(id1, g2s1.handle);
3970     iso->SetObjectGroupId(g2s1.handle, id2);
3971     iso->SetObjectGroupId(g2s2.handle, id2);
3972     iso->SetReferenceFromGroup(id2, g3s1.handle);
3973     iso->SetObjectGroupId(g3s1.handle, id3);
3974     iso->SetObjectGroupId(g3s2.handle, id3);
3975     iso->SetReferenceFromGroup(id3, g4s1.handle);
3976     iso->SetObjectGroupId(g4s1.handle, id4);
3977     iso->SetObjectGroupId(g4s2.handle, id4);
3978     iso->SetReferenceFromGroup(id4, g1s1.handle);
3979   }
3980   // Do a single full GC
3981   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3982       iso)->heap();
3983   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3984
3985   // All object should be alive.
3986   CHECK_EQ(0, counter.NumberOfWeakCalls());
3987
3988   // Weaken the root.
3989   root.handle.SetWeak(&root, &WeakPointerCallback);
3990
3991   // Groups are deleted, rebuild groups.
3992   {
3993     UniqueId id1 = MakeUniqueId(g1s1.handle);
3994     UniqueId id2 = MakeUniqueId(g2s1.handle);
3995     UniqueId id3 = MakeUniqueId(g3s1.handle);
3996     UniqueId id4 = MakeUniqueId(g4s1.handle);
3997     iso->SetObjectGroupId(g1s1.handle, id1);
3998     iso->SetObjectGroupId(g1s2.handle, id1);
3999     iso->SetReferenceFromGroup(id1, g2s1.handle);
4000     iso->SetObjectGroupId(g2s1.handle, id2);
4001     iso->SetObjectGroupId(g2s2.handle, id2);
4002     iso->SetReferenceFromGroup(id2, g3s1.handle);
4003     iso->SetObjectGroupId(g3s1.handle, id3);
4004     iso->SetObjectGroupId(g3s2.handle, id3);
4005     iso->SetReferenceFromGroup(id3, g4s1.handle);
4006     iso->SetObjectGroupId(g4s1.handle, id4);
4007     iso->SetObjectGroupId(g4s2.handle, id4);
4008     iso->SetReferenceFromGroup(id4, g1s1.handle);
4009   }
4010
4011   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4012
4013   // All objects should be gone. 9 global handles in total.
4014   CHECK_EQ(9, counter.NumberOfWeakCalls());
4015 }
4016
4017
4018 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4019 // on the buildbots, so was made non-threaded for the time being.
4020 TEST(ApiObjectGroupsCycleForScavenger) {
4021   i::FLAG_stress_compaction = false;
4022   i::FLAG_gc_global = false;
4023   LocalContext env;
4024   v8::Isolate* iso = env->GetIsolate();
4025   HandleScope scope(iso);
4026
4027   WeakCallCounter counter(1234);
4028
4029   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4030   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4031   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4032   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4033   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4034   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4035
4036   {
4037     HandleScope scope(iso);
4038     g1s1.handle.Reset(iso, Object::New(iso));
4039     g1s2.handle.Reset(iso, Object::New(iso));
4040     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4041     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4042
4043     g2s1.handle.Reset(iso, Object::New(iso));
4044     g2s2.handle.Reset(iso, Object::New(iso));
4045     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4046     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4047
4048     g3s1.handle.Reset(iso, Object::New(iso));
4049     g3s2.handle.Reset(iso, Object::New(iso));
4050     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4051     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4052   }
4053
4054   // Make a root.
4055   WeakCallCounterAndPersistent<Value> root(&counter);
4056   root.handle.Reset(iso, g1s1.handle);
4057   root.handle.MarkPartiallyDependent();
4058
4059   // Connect groups.  We're building the following cycle:
4060   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4061   // groups.
4062   {
4063     HandleScope handle_scope(iso);
4064     g1s1.handle.MarkPartiallyDependent();
4065     g1s2.handle.MarkPartiallyDependent();
4066     g2s1.handle.MarkPartiallyDependent();
4067     g2s2.handle.MarkPartiallyDependent();
4068     g3s1.handle.MarkPartiallyDependent();
4069     g3s2.handle.MarkPartiallyDependent();
4070     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4071     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4072     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4073         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4074     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4075     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4076     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4077         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4078     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4079     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4080     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4081         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4082   }
4083
4084   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4085       iso)->heap();
4086   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4087
4088   // All objects should be alive.
4089   CHECK_EQ(0, counter.NumberOfWeakCalls());
4090
4091   // Weaken the root.
4092   root.handle.SetWeak(&root, &WeakPointerCallback);
4093   root.handle.MarkPartiallyDependent();
4094
4095   // Groups are deleted, rebuild groups.
4096   {
4097     HandleScope handle_scope(iso);
4098     g1s1.handle.MarkPartiallyDependent();
4099     g1s2.handle.MarkPartiallyDependent();
4100     g2s1.handle.MarkPartiallyDependent();
4101     g2s2.handle.MarkPartiallyDependent();
4102     g3s1.handle.MarkPartiallyDependent();
4103     g3s2.handle.MarkPartiallyDependent();
4104     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4105     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4106     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4107         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4108     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4109     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4110     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4111         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4112     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4113     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4114     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4115         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4116   }
4117
4118   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4119
4120   // All objects should be gone. 7 global handles in total.
4121   CHECK_EQ(7, counter.NumberOfWeakCalls());
4122 }
4123
4124
4125 THREADED_TEST(ScriptException) {
4126   LocalContext env;
4127   v8::HandleScope scope(env->GetIsolate());
4128   Local<Script> script = v8_compile("throw 'panama!';");
4129   v8::TryCatch try_catch;
4130   Local<Value> result = script->Run();
4131   CHECK(result.IsEmpty());
4132   CHECK(try_catch.HasCaught());
4133   String::Utf8Value exception_value(try_catch.Exception());
4134   CHECK_EQ(*exception_value, "panama!");
4135 }
4136
4137
4138 TEST(TryCatchCustomException) {
4139   LocalContext env;
4140   v8::HandleScope scope(env->GetIsolate());
4141   v8::TryCatch try_catch;
4142   CompileRun("function CustomError() { this.a = 'b'; }"
4143              "(function f() { throw new CustomError(); })();");
4144   CHECK(try_catch.HasCaught());
4145   CHECK(try_catch.Exception()->ToObject()->
4146             Get(v8_str("a"))->Equals(v8_str("b")));
4147 }
4148
4149
4150 bool message_received;
4151
4152
4153 static void check_message_0(v8::Handle<v8::Message> message,
4154                             v8::Handle<Value> data) {
4155   CHECK_EQ(5.76, data->NumberValue());
4156   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4157   CHECK(!message->IsSharedCrossOrigin());
4158   message_received = true;
4159 }
4160
4161
4162 THREADED_TEST(MessageHandler0) {
4163   message_received = false;
4164   v8::HandleScope scope(CcTest::isolate());
4165   CHECK(!message_received);
4166   LocalContext context;
4167   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4168   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4169   script->Run();
4170   CHECK(message_received);
4171   // clear out the message listener
4172   v8::V8::RemoveMessageListeners(check_message_0);
4173 }
4174
4175
4176 static void check_message_1(v8::Handle<v8::Message> message,
4177                             v8::Handle<Value> data) {
4178   CHECK(data->IsNumber());
4179   CHECK_EQ(1337, data->Int32Value());
4180   CHECK(!message->IsSharedCrossOrigin());
4181   message_received = true;
4182 }
4183
4184
4185 TEST(MessageHandler1) {
4186   message_received = false;
4187   v8::HandleScope scope(CcTest::isolate());
4188   CHECK(!message_received);
4189   v8::V8::AddMessageListener(check_message_1);
4190   LocalContext context;
4191   CompileRun("throw 1337;");
4192   CHECK(message_received);
4193   // clear out the message listener
4194   v8::V8::RemoveMessageListeners(check_message_1);
4195 }
4196
4197
4198 static void check_message_2(v8::Handle<v8::Message> message,
4199                             v8::Handle<Value> data) {
4200   LocalContext context;
4201   CHECK(data->IsObject());
4202   v8::Local<v8::Value> hidden_property =
4203       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4204   CHECK(v8_str("hidden value")->Equals(hidden_property));
4205   CHECK(!message->IsSharedCrossOrigin());
4206   message_received = true;
4207 }
4208
4209
4210 TEST(MessageHandler2) {
4211   message_received = false;
4212   v8::HandleScope scope(CcTest::isolate());
4213   CHECK(!message_received);
4214   v8::V8::AddMessageListener(check_message_2);
4215   LocalContext context;
4216   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4217   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4218                                            v8_str("hidden value"));
4219   context->Global()->Set(v8_str("error"), error);
4220   CompileRun("throw error;");
4221   CHECK(message_received);
4222   // clear out the message listener
4223   v8::V8::RemoveMessageListeners(check_message_2);
4224 }
4225
4226
4227 static void check_message_3(v8::Handle<v8::Message> message,
4228                             v8::Handle<Value> data) {
4229   CHECK(message->IsSharedCrossOrigin());
4230   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4231   message_received = true;
4232 }
4233
4234
4235 TEST(MessageHandler3) {
4236   message_received = false;
4237   v8::Isolate* isolate = CcTest::isolate();
4238   v8::HandleScope scope(isolate);
4239   CHECK(!message_received);
4240   v8::V8::AddMessageListener(check_message_3);
4241   LocalContext context;
4242   v8::ScriptOrigin origin =
4243       v8::ScriptOrigin(v8_str("6.75"),
4244                        v8::Integer::New(isolate, 1),
4245                        v8::Integer::New(isolate, 2),
4246                        v8::True(isolate));
4247   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4248                                                   &origin);
4249   script->Run();
4250   CHECK(message_received);
4251   // clear out the message listener
4252   v8::V8::RemoveMessageListeners(check_message_3);
4253 }
4254
4255
4256 static void check_message_4(v8::Handle<v8::Message> message,
4257                             v8::Handle<Value> data) {
4258   CHECK(!message->IsSharedCrossOrigin());
4259   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4260   message_received = true;
4261 }
4262
4263
4264 TEST(MessageHandler4) {
4265   message_received = false;
4266   v8::Isolate* isolate = CcTest::isolate();
4267   v8::HandleScope scope(isolate);
4268   CHECK(!message_received);
4269   v8::V8::AddMessageListener(check_message_4);
4270   LocalContext context;
4271   v8::ScriptOrigin origin =
4272       v8::ScriptOrigin(v8_str("6.75"),
4273                        v8::Integer::New(isolate, 1),
4274                        v8::Integer::New(isolate, 2),
4275                        v8::False(isolate));
4276   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4277                                                   &origin);
4278   script->Run();
4279   CHECK(message_received);
4280   // clear out the message listener
4281   v8::V8::RemoveMessageListeners(check_message_4);
4282 }
4283
4284
4285 static void check_message_5a(v8::Handle<v8::Message> message,
4286                             v8::Handle<Value> data) {
4287   CHECK(message->IsSharedCrossOrigin());
4288   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4289   message_received = true;
4290 }
4291
4292
4293 static void check_message_5b(v8::Handle<v8::Message> message,
4294                             v8::Handle<Value> data) {
4295   CHECK(!message->IsSharedCrossOrigin());
4296   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4297   message_received = true;
4298 }
4299
4300
4301 TEST(MessageHandler5) {
4302   message_received = false;
4303   v8::Isolate* isolate = CcTest::isolate();
4304   v8::HandleScope scope(isolate);
4305   CHECK(!message_received);
4306   v8::V8::AddMessageListener(check_message_5a);
4307   LocalContext context;
4308   v8::ScriptOrigin origin =
4309       v8::ScriptOrigin(v8_str("6.75"),
4310                        v8::Integer::New(isolate, 1),
4311                        v8::Integer::New(isolate, 2),
4312                        v8::True(isolate));
4313   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4314                                                   &origin);
4315   script->Run();
4316   CHECK(message_received);
4317   // clear out the message listener
4318   v8::V8::RemoveMessageListeners(check_message_5a);
4319
4320   message_received = false;
4321   v8::V8::AddMessageListener(check_message_5b);
4322   origin =
4323       v8::ScriptOrigin(v8_str("6.75"),
4324                        v8::Integer::New(isolate, 1),
4325                        v8::Integer::New(isolate, 2),
4326                        v8::False(isolate));
4327   script = Script::Compile(v8_str("throw 'error'"),
4328                            &origin);
4329   script->Run();
4330   CHECK(message_received);
4331   // clear out the message listener
4332   v8::V8::RemoveMessageListeners(check_message_5b);
4333 }
4334
4335
4336 THREADED_TEST(GetSetProperty) {
4337   LocalContext context;
4338   v8::Isolate* isolate = context->GetIsolate();
4339   v8::HandleScope scope(isolate);
4340   context->Global()->Set(v8_str("foo"), v8_num(14));
4341   context->Global()->Set(v8_str("12"), v8_num(92));
4342   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4343   context->Global()->Set(v8_num(13), v8_num(56));
4344   Local<Value> foo = CompileRun("this.foo");
4345   CHECK_EQ(14, foo->Int32Value());
4346   Local<Value> twelve = CompileRun("this[12]");
4347   CHECK_EQ(92, twelve->Int32Value());
4348   Local<Value> sixteen = CompileRun("this[16]");
4349   CHECK_EQ(32, sixteen->Int32Value());
4350   Local<Value> thirteen = CompileRun("this[13]");
4351   CHECK_EQ(56, thirteen->Int32Value());
4352   CHECK_EQ(92,
4353            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4354   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4355   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4356   CHECK_EQ(32,
4357            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4358   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4359   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4360   CHECK_EQ(56,
4361            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4362   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4363   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4364 }
4365
4366
4367 THREADED_TEST(PropertyAttributes) {
4368   LocalContext context;
4369   v8::HandleScope scope(context->GetIsolate());
4370   // none
4371   Local<String> prop = v8_str("none");
4372   context->Global()->Set(prop, v8_num(7));
4373   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4374   // read-only
4375   prop = v8_str("read_only");
4376   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4377   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4378   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4379   CompileRun("read_only = 9");
4380   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4381   context->Global()->Set(prop, v8_num(10));
4382   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4383   // dont-delete
4384   prop = v8_str("dont_delete");
4385   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4386   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4387   CompileRun("delete dont_delete");
4388   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4389   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4390   // dont-enum
4391   prop = v8_str("dont_enum");
4392   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4393   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4394   // absent
4395   prop = v8_str("absent");
4396   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4397   Local<Value> fake_prop = v8_num(1);
4398   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4399   // exception
4400   TryCatch try_catch;
4401   Local<Value> exception =
4402       CompileRun("({ toString: function() { throw 'exception';} })");
4403   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4404   CHECK(try_catch.HasCaught());
4405   String::Utf8Value exception_value(try_catch.Exception());
4406   CHECK_EQ("exception", *exception_value);
4407   try_catch.Reset();
4408 }
4409
4410
4411 THREADED_TEST(Array) {
4412   LocalContext context;
4413   v8::HandleScope scope(context->GetIsolate());
4414   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4415   CHECK_EQ(0, array->Length());
4416   CHECK(array->Get(0)->IsUndefined());
4417   CHECK(!array->Has(0));
4418   CHECK(array->Get(100)->IsUndefined());
4419   CHECK(!array->Has(100));
4420   array->Set(2, v8_num(7));
4421   CHECK_EQ(3, array->Length());
4422   CHECK(!array->Has(0));
4423   CHECK(!array->Has(1));
4424   CHECK(array->Has(2));
4425   CHECK_EQ(7, array->Get(2)->Int32Value());
4426   Local<Value> obj = CompileRun("[1, 2, 3]");
4427   Local<v8::Array> arr = obj.As<v8::Array>();
4428   CHECK_EQ(3, arr->Length());
4429   CHECK_EQ(1, arr->Get(0)->Int32Value());
4430   CHECK_EQ(2, arr->Get(1)->Int32Value());
4431   CHECK_EQ(3, arr->Get(2)->Int32Value());
4432   array = v8::Array::New(context->GetIsolate(), 27);
4433   CHECK_EQ(27, array->Length());
4434   array = v8::Array::New(context->GetIsolate(), -27);
4435   CHECK_EQ(0, array->Length());
4436 }
4437
4438
4439 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4440   v8::EscapableHandleScope scope(args.GetIsolate());
4441   ApiTestFuzzer::Fuzz();
4442   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4443   for (int i = 0; i < args.Length(); i++)
4444     result->Set(i, args[i]);
4445   args.GetReturnValue().Set(scope.Escape(result));
4446 }
4447
4448
4449 THREADED_TEST(Vector) {
4450   v8::Isolate* isolate = CcTest::isolate();
4451   v8::HandleScope scope(isolate);
4452   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4453   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4454   LocalContext context(0, global);
4455
4456   const char* fun = "f()";
4457   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4458   CHECK_EQ(0, a0->Length());
4459
4460   const char* fun2 = "f(11)";
4461   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4462   CHECK_EQ(1, a1->Length());
4463   CHECK_EQ(11, a1->Get(0)->Int32Value());
4464
4465   const char* fun3 = "f(12, 13)";
4466   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4467   CHECK_EQ(2, a2->Length());
4468   CHECK_EQ(12, a2->Get(0)->Int32Value());
4469   CHECK_EQ(13, a2->Get(1)->Int32Value());
4470
4471   const char* fun4 = "f(14, 15, 16)";
4472   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4473   CHECK_EQ(3, a3->Length());
4474   CHECK_EQ(14, a3->Get(0)->Int32Value());
4475   CHECK_EQ(15, a3->Get(1)->Int32Value());
4476   CHECK_EQ(16, a3->Get(2)->Int32Value());
4477
4478   const char* fun5 = "f(17, 18, 19, 20)";
4479   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4480   CHECK_EQ(4, a4->Length());
4481   CHECK_EQ(17, a4->Get(0)->Int32Value());
4482   CHECK_EQ(18, a4->Get(1)->Int32Value());
4483   CHECK_EQ(19, a4->Get(2)->Int32Value());
4484   CHECK_EQ(20, a4->Get(3)->Int32Value());
4485 }
4486
4487
4488 THREADED_TEST(FunctionCall) {
4489   LocalContext context;
4490   v8::Isolate* isolate = context->GetIsolate();
4491   v8::HandleScope scope(isolate);
4492   CompileRun(
4493     "function Foo() {"
4494     "  var result = [];"
4495     "  for (var i = 0; i < arguments.length; i++) {"
4496     "    result.push(arguments[i]);"
4497     "  }"
4498     "  return result;"
4499     "}"
4500     "function ReturnThisSloppy() {"
4501     "  return this;"
4502     "}"
4503     "function ReturnThisStrict() {"
4504     "  'use strict';"
4505     "  return this;"
4506     "}");
4507   Local<Function> Foo =
4508       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4509   Local<Function> ReturnThisSloppy =
4510       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4511   Local<Function> ReturnThisStrict =
4512       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4513
4514   v8::Handle<Value>* args0 = NULL;
4515   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4516   CHECK_EQ(0, a0->Length());
4517
4518   v8::Handle<Value> args1[] = { v8_num(1.1) };
4519   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4520   CHECK_EQ(1, a1->Length());
4521   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4522
4523   v8::Handle<Value> args2[] = { v8_num(2.2),
4524                                 v8_num(3.3) };
4525   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4526   CHECK_EQ(2, a2->Length());
4527   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4528   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4529
4530   v8::Handle<Value> args3[] = { v8_num(4.4),
4531                                 v8_num(5.5),
4532                                 v8_num(6.6) };
4533   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4534   CHECK_EQ(3, a3->Length());
4535   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4536   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4537   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4538
4539   v8::Handle<Value> args4[] = { v8_num(7.7),
4540                                 v8_num(8.8),
4541                                 v8_num(9.9),
4542                                 v8_num(10.11) };
4543   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4544   CHECK_EQ(4, a4->Length());
4545   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4546   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4547   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4548   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4549
4550   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4551   CHECK(r1->StrictEquals(context->Global()));
4552   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4553   CHECK(r2->StrictEquals(context->Global()));
4554   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4555   CHECK(r3->IsNumberObject());
4556   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4557   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4558   CHECK(r4->IsStringObject());
4559   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4560   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4561   CHECK(r5->IsBooleanObject());
4562   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4563
4564   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4565   CHECK(r6->IsUndefined());
4566   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4567   CHECK(r7->IsNull());
4568   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4569   CHECK(r8->StrictEquals(v8_num(42)));
4570   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4571   CHECK(r9->StrictEquals(v8_str("hello")));
4572   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4573   CHECK(r10->StrictEquals(v8::True(isolate)));
4574 }
4575
4576
4577 THREADED_TEST(ConstructCall) {
4578   LocalContext context;
4579   v8::Isolate* isolate = context->GetIsolate();
4580   v8::HandleScope scope(isolate);
4581   CompileRun(
4582     "function Foo() {"
4583     "  var result = [];"
4584     "  for (var i = 0; i < arguments.length; i++) {"
4585     "    result.push(arguments[i]);"
4586     "  }"
4587     "  return result;"
4588     "}");
4589   Local<Function> Foo =
4590       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4591
4592   v8::Handle<Value>* args0 = NULL;
4593   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4594   CHECK_EQ(0, a0->Length());
4595
4596   v8::Handle<Value> args1[] = { v8_num(1.1) };
4597   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4598   CHECK_EQ(1, a1->Length());
4599   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4600
4601   v8::Handle<Value> args2[] = { v8_num(2.2),
4602                                 v8_num(3.3) };
4603   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4604   CHECK_EQ(2, a2->Length());
4605   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4606   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4607
4608   v8::Handle<Value> args3[] = { v8_num(4.4),
4609                                 v8_num(5.5),
4610                                 v8_num(6.6) };
4611   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4612   CHECK_EQ(3, a3->Length());
4613   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4614   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4615   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4616
4617   v8::Handle<Value> args4[] = { v8_num(7.7),
4618                                 v8_num(8.8),
4619                                 v8_num(9.9),
4620                                 v8_num(10.11) };
4621   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4622   CHECK_EQ(4, a4->Length());
4623   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4624   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4625   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4626   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4627 }
4628
4629
4630 static void CheckUncle(v8::TryCatch* try_catch) {
4631   CHECK(try_catch->HasCaught());
4632   String::Utf8Value str_value(try_catch->Exception());
4633   CHECK_EQ(*str_value, "uncle?");
4634   try_catch->Reset();
4635 }
4636
4637
4638 THREADED_TEST(ConversionNumber) {
4639   LocalContext env;
4640   v8::HandleScope scope(env->GetIsolate());
4641   // Very large number.
4642   CompileRun("var obj = Math.pow(2,32) * 1237;");
4643   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4644   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4645   CHECK_EQ(0, obj->ToInt32()->Value());
4646   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4647   // Large number.
4648   CompileRun("var obj = -1234567890123;");
4649   obj = env->Global()->Get(v8_str("obj"));
4650   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4651   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4652   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4653   // Small positive integer.
4654   CompileRun("var obj = 42;");
4655   obj = env->Global()->Get(v8_str("obj"));
4656   CHECK_EQ(42.0, obj->ToNumber()->Value());
4657   CHECK_EQ(42, obj->ToInt32()->Value());
4658   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4659   // Negative integer.
4660   CompileRun("var obj = -37;");
4661   obj = env->Global()->Get(v8_str("obj"));
4662   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4663   CHECK_EQ(-37, obj->ToInt32()->Value());
4664   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4665   // Positive non-int32 integer.
4666   CompileRun("var obj = 0x81234567;");
4667   obj = env->Global()->Get(v8_str("obj"));
4668   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4669   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4670   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4671   // Fraction.
4672   CompileRun("var obj = 42.3;");
4673   obj = env->Global()->Get(v8_str("obj"));
4674   CHECK_EQ(42.3, obj->ToNumber()->Value());
4675   CHECK_EQ(42, obj->ToInt32()->Value());
4676   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4677   // Large negative fraction.
4678   CompileRun("var obj = -5726623061.75;");
4679   obj = env->Global()->Get(v8_str("obj"));
4680   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4681   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4682   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4683 }
4684
4685
4686 THREADED_TEST(isNumberType) {
4687   LocalContext env;
4688   v8::HandleScope scope(env->GetIsolate());
4689   // Very large number.
4690   CompileRun("var obj = Math.pow(2,32) * 1237;");
4691   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4692   CHECK(!obj->IsInt32());
4693   CHECK(!obj->IsUint32());
4694   // Large negative number.
4695   CompileRun("var obj = -1234567890123;");
4696   obj = env->Global()->Get(v8_str("obj"));
4697   CHECK(!obj->IsInt32());
4698   CHECK(!obj->IsUint32());
4699   // Small positive integer.
4700   CompileRun("var obj = 42;");
4701   obj = env->Global()->Get(v8_str("obj"));
4702   CHECK(obj->IsInt32());
4703   CHECK(obj->IsUint32());
4704   // Negative integer.
4705   CompileRun("var obj = -37;");
4706   obj = env->Global()->Get(v8_str("obj"));
4707   CHECK(obj->IsInt32());
4708   CHECK(!obj->IsUint32());
4709   // Positive non-int32 integer.
4710   CompileRun("var obj = 0x81234567;");
4711   obj = env->Global()->Get(v8_str("obj"));
4712   CHECK(!obj->IsInt32());
4713   CHECK(obj->IsUint32());
4714   // Fraction.
4715   CompileRun("var obj = 42.3;");
4716   obj = env->Global()->Get(v8_str("obj"));
4717   CHECK(!obj->IsInt32());
4718   CHECK(!obj->IsUint32());
4719   // Large negative fraction.
4720   CompileRun("var obj = -5726623061.75;");
4721   obj = env->Global()->Get(v8_str("obj"));
4722   CHECK(!obj->IsInt32());
4723   CHECK(!obj->IsUint32());
4724   // Positive zero
4725   CompileRun("var obj = 0.0;");
4726   obj = env->Global()->Get(v8_str("obj"));
4727   CHECK(obj->IsInt32());
4728   CHECK(obj->IsUint32());
4729   // Positive zero
4730   CompileRun("var obj = -0.0;");
4731   obj = env->Global()->Get(v8_str("obj"));
4732   CHECK(!obj->IsInt32());
4733   CHECK(!obj->IsUint32());
4734 }
4735
4736
4737 THREADED_TEST(ConversionException) {
4738   LocalContext env;
4739   v8::Isolate* isolate = env->GetIsolate();
4740   v8::HandleScope scope(isolate);
4741   CompileRun(
4742     "function TestClass() { };"
4743     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4744     "var obj = new TestClass();");
4745   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4746
4747   v8::TryCatch try_catch;
4748
4749   Local<Value> to_string_result = obj->ToString();
4750   CHECK(to_string_result.IsEmpty());
4751   CheckUncle(&try_catch);
4752
4753   Local<Value> to_number_result = obj->ToNumber();
4754   CHECK(to_number_result.IsEmpty());
4755   CheckUncle(&try_catch);
4756
4757   Local<Value> to_integer_result = obj->ToInteger();
4758   CHECK(to_integer_result.IsEmpty());
4759   CheckUncle(&try_catch);
4760
4761   Local<Value> to_uint32_result = obj->ToUint32();
4762   CHECK(to_uint32_result.IsEmpty());
4763   CheckUncle(&try_catch);
4764
4765   Local<Value> to_int32_result = obj->ToInt32();
4766   CHECK(to_int32_result.IsEmpty());
4767   CheckUncle(&try_catch);
4768
4769   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4770   CHECK(to_object_result.IsEmpty());
4771   CHECK(try_catch.HasCaught());
4772   try_catch.Reset();
4773
4774   int32_t int32_value = obj->Int32Value();
4775   CHECK_EQ(0, int32_value);
4776   CheckUncle(&try_catch);
4777
4778   uint32_t uint32_value = obj->Uint32Value();
4779   CHECK_EQ(0, uint32_value);
4780   CheckUncle(&try_catch);
4781
4782   double number_value = obj->NumberValue();
4783   CHECK_NE(0, std::isnan(number_value));
4784   CheckUncle(&try_catch);
4785
4786   int64_t integer_value = obj->IntegerValue();
4787   CHECK_EQ(0.0, static_cast<double>(integer_value));
4788   CheckUncle(&try_catch);
4789 }
4790
4791
4792 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4793   ApiTestFuzzer::Fuzz();
4794   args.GetIsolate()->ThrowException(v8_str("konto"));
4795 }
4796
4797
4798 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4799   if (args.Length() < 1) {
4800     args.GetReturnValue().Set(false);
4801     return;
4802   }
4803   v8::HandleScope scope(args.GetIsolate());
4804   v8::TryCatch try_catch;
4805   Local<Value> result = CompileRun(args[0]->ToString());
4806   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4807   args.GetReturnValue().Set(try_catch.HasCaught());
4808 }
4809
4810
4811 THREADED_TEST(APICatch) {
4812   v8::Isolate* isolate = CcTest::isolate();
4813   v8::HandleScope scope(isolate);
4814   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4815   templ->Set(v8_str("ThrowFromC"),
4816              v8::FunctionTemplate::New(isolate, ThrowFromC));
4817   LocalContext context(0, templ);
4818   CompileRun(
4819     "var thrown = false;"
4820     "try {"
4821     "  ThrowFromC();"
4822     "} catch (e) {"
4823     "  thrown = true;"
4824     "}");
4825   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4826   CHECK(thrown->BooleanValue());
4827 }
4828
4829
4830 THREADED_TEST(APIThrowTryCatch) {
4831   v8::Isolate* isolate = CcTest::isolate();
4832   v8::HandleScope scope(isolate);
4833   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4834   templ->Set(v8_str("ThrowFromC"),
4835              v8::FunctionTemplate::New(isolate, ThrowFromC));
4836   LocalContext context(0, templ);
4837   v8::TryCatch try_catch;
4838   CompileRun("ThrowFromC();");
4839   CHECK(try_catch.HasCaught());
4840 }
4841
4842
4843 // Test that a try-finally block doesn't shadow a try-catch block
4844 // when setting up an external handler.
4845 //
4846 // BUG(271): Some of the exception propagation does not work on the
4847 // ARM simulator because the simulator separates the C++ stack and the
4848 // JS stack.  This test therefore fails on the simulator.  The test is
4849 // not threaded to allow the threading tests to run on the simulator.
4850 TEST(TryCatchInTryFinally) {
4851   v8::Isolate* isolate = CcTest::isolate();
4852   v8::HandleScope scope(isolate);
4853   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4854   templ->Set(v8_str("CCatcher"),
4855              v8::FunctionTemplate::New(isolate, CCatcher));
4856   LocalContext context(0, templ);
4857   Local<Value> result = CompileRun("try {"
4858                                    "  try {"
4859                                    "    CCatcher('throw 7;');"
4860                                    "  } finally {"
4861                                    "  }"
4862                                    "} catch (e) {"
4863                                    "}");
4864   CHECK(result->IsTrue());
4865 }
4866
4867
4868 static void check_reference_error_message(
4869     v8::Handle<v8::Message> message,
4870     v8::Handle<v8::Value> data) {
4871   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4872   CHECK(message->Get()->Equals(v8_str(reference_error)));
4873 }
4874
4875
4876 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4877   ApiTestFuzzer::Fuzz();
4878   CHECK(false);
4879 }
4880
4881
4882 // Test that overwritten methods are not invoked on uncaught exception
4883 // formatting. However, they are invoked when performing normal error
4884 // string conversions.
4885 TEST(APIThrowMessageOverwrittenToString) {
4886   v8::Isolate* isolate = CcTest::isolate();
4887   v8::HandleScope scope(isolate);
4888   v8::V8::AddMessageListener(check_reference_error_message);
4889   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4890   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4891   LocalContext context(NULL, templ);
4892   CompileRun("asdf;");
4893   CompileRun("var limit = {};"
4894              "limit.valueOf = fail;"
4895              "Error.stackTraceLimit = limit;");
4896   CompileRun("asdf");
4897   CompileRun("Array.prototype.pop = fail;");
4898   CompileRun("Object.prototype.hasOwnProperty = fail;");
4899   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4900   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4901   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4902   CompileRun("ReferenceError.prototype.toString ="
4903              "  function() { return 'Whoops' }");
4904   CompileRun("asdf;");
4905   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4906   CompileRun("asdf;");
4907   CompileRun("ReferenceError.prototype.constructor = void 0;");
4908   CompileRun("asdf;");
4909   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4910   CompileRun("asdf;");
4911   CompileRun("ReferenceError.prototype = new Object();");
4912   CompileRun("asdf;");
4913   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4914   CHECK(string->Equals(v8_str("Whoops")));
4915   CompileRun("ReferenceError.prototype.constructor = new Object();"
4916              "ReferenceError.prototype.constructor.name = 1;"
4917              "Number.prototype.toString = function() { return 'Whoops'; };"
4918              "ReferenceError.prototype.toString = Object.prototype.toString;");
4919   CompileRun("asdf;");
4920   v8::V8::RemoveMessageListeners(check_reference_error_message);
4921 }
4922
4923
4924 static void check_custom_error_tostring(
4925     v8::Handle<v8::Message> message,
4926     v8::Handle<v8::Value> data) {
4927   const char* uncaught_error = "Uncaught MyError toString";
4928   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4929 }
4930
4931
4932 TEST(CustomErrorToString) {
4933   LocalContext context;
4934   v8::HandleScope scope(context->GetIsolate());
4935   v8::V8::AddMessageListener(check_custom_error_tostring);
4936   CompileRun(
4937     "function MyError(name, message) {                   "
4938     "  this.name = name;                                 "
4939     "  this.message = message;                           "
4940     "}                                                   "
4941     "MyError.prototype = Object.create(Error.prototype); "
4942     "MyError.prototype.toString = function() {           "
4943     "  return 'MyError toString';                        "
4944     "};                                                  "
4945     "throw new MyError('my name', 'my message');         ");
4946   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4947 }
4948
4949
4950 static void check_custom_error_message(
4951     v8::Handle<v8::Message> message,
4952     v8::Handle<v8::Value> data) {
4953   const char* uncaught_error = "Uncaught MyError: my message";
4954   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4955   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4956 }
4957
4958
4959 TEST(CustomErrorMessage) {
4960   LocalContext context;
4961   v8::HandleScope scope(context->GetIsolate());
4962   v8::V8::AddMessageListener(check_custom_error_message);
4963
4964   // Handlebars.
4965   CompileRun(
4966     "function MyError(msg) {                             "
4967     "  this.name = 'MyError';                            "
4968     "  this.message = msg;                               "
4969     "}                                                   "
4970     "MyError.prototype = new Error();                    "
4971     "throw new MyError('my message');                    ");
4972
4973   // Closure.
4974   CompileRun(
4975     "function MyError(msg) {                             "
4976     "  this.name = 'MyError';                            "
4977     "  this.message = msg;                               "
4978     "}                                                   "
4979     "inherits = function(childCtor, parentCtor) {        "
4980     "    function tempCtor() {};                         "
4981     "    tempCtor.prototype = parentCtor.prototype;      "
4982     "    childCtor.superClass_ = parentCtor.prototype;   "
4983     "    childCtor.prototype = new tempCtor();           "
4984     "    childCtor.prototype.constructor = childCtor;    "
4985     "};                                                  "
4986     "inherits(MyError, Error);                           "
4987     "throw new MyError('my message');                    ");
4988
4989   // Object.create.
4990   CompileRun(
4991     "function MyError(msg) {                             "
4992     "  this.name = 'MyError';                            "
4993     "  this.message = msg;                               "
4994     "}                                                   "
4995     "MyError.prototype = Object.create(Error.prototype); "
4996     "throw new MyError('my message');                    ");
4997
4998   v8::V8::RemoveMessageListeners(check_custom_error_message);
4999 }
5000
5001
5002 static void receive_message(v8::Handle<v8::Message> message,
5003                             v8::Handle<v8::Value> data) {
5004   message->Get();
5005   message_received = true;
5006 }
5007
5008
5009 TEST(APIThrowMessage) {
5010   message_received = false;
5011   v8::Isolate* isolate = CcTest::isolate();
5012   v8::HandleScope scope(isolate);
5013   v8::V8::AddMessageListener(receive_message);
5014   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5015   templ->Set(v8_str("ThrowFromC"),
5016              v8::FunctionTemplate::New(isolate, ThrowFromC));
5017   LocalContext context(0, templ);
5018   CompileRun("ThrowFromC();");
5019   CHECK(message_received);
5020   v8::V8::RemoveMessageListeners(receive_message);
5021 }
5022
5023
5024 TEST(APIThrowMessageAndVerboseTryCatch) {
5025   message_received = false;
5026   v8::Isolate* isolate = CcTest::isolate();
5027   v8::HandleScope scope(isolate);
5028   v8::V8::AddMessageListener(receive_message);
5029   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5030   templ->Set(v8_str("ThrowFromC"),
5031              v8::FunctionTemplate::New(isolate, ThrowFromC));
5032   LocalContext context(0, templ);
5033   v8::TryCatch try_catch;
5034   try_catch.SetVerbose(true);
5035   Local<Value> result = CompileRun("ThrowFromC();");
5036   CHECK(try_catch.HasCaught());
5037   CHECK(result.IsEmpty());
5038   CHECK(message_received);
5039   v8::V8::RemoveMessageListeners(receive_message);
5040 }
5041
5042
5043 TEST(APIStackOverflowAndVerboseTryCatch) {
5044   message_received = false;
5045   LocalContext context;
5046   v8::HandleScope scope(context->GetIsolate());
5047   v8::V8::AddMessageListener(receive_message);
5048   v8::TryCatch try_catch;
5049   try_catch.SetVerbose(true);
5050   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5051   CHECK(try_catch.HasCaught());
5052   CHECK(result.IsEmpty());
5053   CHECK(message_received);
5054   v8::V8::RemoveMessageListeners(receive_message);
5055 }
5056
5057
5058 THREADED_TEST(ExternalScriptException) {
5059   v8::Isolate* isolate = CcTest::isolate();
5060   v8::HandleScope scope(isolate);
5061   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5062   templ->Set(v8_str("ThrowFromC"),
5063              v8::FunctionTemplate::New(isolate, ThrowFromC));
5064   LocalContext context(0, templ);
5065
5066   v8::TryCatch try_catch;
5067   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5068   CHECK(result.IsEmpty());
5069   CHECK(try_catch.HasCaught());
5070   String::Utf8Value exception_value(try_catch.Exception());
5071   CHECK_EQ("konto", *exception_value);
5072 }
5073
5074
5075
5076 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5077   ApiTestFuzzer::Fuzz();
5078   CHECK_EQ(4, args.Length());
5079   int count = args[0]->Int32Value();
5080   int cInterval = args[2]->Int32Value();
5081   if (count == 0) {
5082     args.GetIsolate()->ThrowException(v8_str("FromC"));
5083     return;
5084   } else {
5085     Local<v8::Object> global =
5086         args.GetIsolate()->GetCurrentContext()->Global();
5087     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5088     v8::Handle<Value> argv[] = { v8_num(count - 1),
5089                                  args[1],
5090                                  args[2],
5091                                  args[3] };
5092     if (count % cInterval == 0) {
5093       v8::TryCatch try_catch;
5094       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5095       int expected = args[3]->Int32Value();
5096       if (try_catch.HasCaught()) {
5097         CHECK_EQ(expected, count);
5098         CHECK(result.IsEmpty());
5099         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5100       } else {
5101         CHECK_NE(expected, count);
5102       }
5103       args.GetReturnValue().Set(result);
5104       return;
5105     } else {
5106       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5107       return;
5108     }
5109   }
5110 }
5111
5112
5113 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5114   ApiTestFuzzer::Fuzz();
5115   CHECK_EQ(3, args.Length());
5116   bool equality = args[0]->BooleanValue();
5117   int count = args[1]->Int32Value();
5118   int expected = args[2]->Int32Value();
5119   if (equality) {
5120     CHECK_EQ(count, expected);
5121   } else {
5122     CHECK_NE(count, expected);
5123   }
5124 }
5125
5126
5127 THREADED_TEST(EvalInTryFinally) {
5128   LocalContext context;
5129   v8::HandleScope scope(context->GetIsolate());
5130   v8::TryCatch try_catch;
5131   CompileRun("(function() {"
5132              "  try {"
5133              "    eval('asldkf (*&^&*^');"
5134              "  } finally {"
5135              "    return;"
5136              "  }"
5137              "})()");
5138   CHECK(!try_catch.HasCaught());
5139 }
5140
5141
5142 // This test works by making a stack of alternating JavaScript and C
5143 // activations.  These activations set up exception handlers with regular
5144 // intervals, one interval for C activations and another for JavaScript
5145 // activations.  When enough activations have been created an exception is
5146 // thrown and we check that the right activation catches the exception and that
5147 // no other activations do.  The right activation is always the topmost one with
5148 // a handler, regardless of whether it is in JavaScript or C.
5149 //
5150 // The notation used to describe a test case looks like this:
5151 //
5152 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5153 //
5154 // Each entry is an activation, either JS or C.  The index is the count at that
5155 // level.  Stars identify activations with exception handlers, the @ identifies
5156 // the exception handler that should catch the exception.
5157 //
5158 // BUG(271): Some of the exception propagation does not work on the
5159 // ARM simulator because the simulator separates the C++ stack and the
5160 // JS stack.  This test therefore fails on the simulator.  The test is
5161 // not threaded to allow the threading tests to run on the simulator.
5162 TEST(ExceptionOrder) {
5163   v8::Isolate* isolate = CcTest::isolate();
5164   v8::HandleScope scope(isolate);
5165   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5166   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5167   templ->Set(v8_str("CThrowCountDown"),
5168              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5169   LocalContext context(0, templ);
5170   CompileRun(
5171     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5172     "  if (count == 0) throw 'FromJS';"
5173     "  if (count % jsInterval == 0) {"
5174     "    try {"
5175     "      var value = CThrowCountDown(count - 1,"
5176     "                                  jsInterval,"
5177     "                                  cInterval,"
5178     "                                  expected);"
5179     "      check(false, count, expected);"
5180     "      return value;"
5181     "    } catch (e) {"
5182     "      check(true, count, expected);"
5183     "    }"
5184     "  } else {"
5185     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5186     "  }"
5187     "}");
5188   Local<Function> fun =
5189       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5190
5191   const int argc = 4;
5192   //                             count      jsInterval cInterval  expected
5193
5194   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5195   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5196   fun->Call(fun, argc, a0);
5197
5198   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5199   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5200   fun->Call(fun, argc, a1);
5201
5202   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5203   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5204   fun->Call(fun, argc, a2);
5205
5206   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5207   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5208   fun->Call(fun, argc, a3);
5209
5210   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5211   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5212   fun->Call(fun, argc, a4);
5213
5214   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5215   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5216   fun->Call(fun, argc, a5);
5217 }
5218
5219
5220 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5221   ApiTestFuzzer::Fuzz();
5222   CHECK_EQ(1, args.Length());
5223   args.GetIsolate()->ThrowException(args[0]);
5224 }
5225
5226
5227 THREADED_TEST(ThrowValues) {
5228   v8::Isolate* isolate = CcTest::isolate();
5229   v8::HandleScope scope(isolate);
5230   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5231   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5232   LocalContext context(0, templ);
5233   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5234     "function Run(obj) {"
5235     "  try {"
5236     "    Throw(obj);"
5237     "  } catch (e) {"
5238     "    return e;"
5239     "  }"
5240     "  return 'no exception';"
5241     "}"
5242     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5243   CHECK_EQ(5, result->Length());
5244   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5245   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5246   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5247   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5248   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5249   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5250   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5251 }
5252
5253
5254 THREADED_TEST(CatchZero) {
5255   LocalContext context;
5256   v8::HandleScope scope(context->GetIsolate());
5257   v8::TryCatch try_catch;
5258   CHECK(!try_catch.HasCaught());
5259   CompileRun("throw 10");
5260   CHECK(try_catch.HasCaught());
5261   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5262   try_catch.Reset();
5263   CHECK(!try_catch.HasCaught());
5264   CompileRun("throw 0");
5265   CHECK(try_catch.HasCaught());
5266   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5267 }
5268
5269
5270 THREADED_TEST(CatchExceptionFromWith) {
5271   LocalContext context;
5272   v8::HandleScope scope(context->GetIsolate());
5273   v8::TryCatch try_catch;
5274   CHECK(!try_catch.HasCaught());
5275   CompileRun("var o = {}; with (o) { throw 42; }");
5276   CHECK(try_catch.HasCaught());
5277 }
5278
5279
5280 THREADED_TEST(TryCatchAndFinallyHidingException) {
5281   LocalContext context;
5282   v8::HandleScope scope(context->GetIsolate());
5283   v8::TryCatch try_catch;
5284   CHECK(!try_catch.HasCaught());
5285   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5286   CompileRun("f({toString: function() { throw 42; }});");
5287   CHECK(!try_catch.HasCaught());
5288 }
5289
5290
5291 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5292   v8::TryCatch try_catch;
5293 }
5294
5295
5296 THREADED_TEST(TryCatchAndFinally) {
5297   LocalContext context;
5298   v8::Isolate* isolate = context->GetIsolate();
5299   v8::HandleScope scope(isolate);
5300   context->Global()->Set(
5301       v8_str("native_with_try_catch"),
5302       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5303   v8::TryCatch try_catch;
5304   CHECK(!try_catch.HasCaught());
5305   CompileRun(
5306       "try {\n"
5307       "  throw new Error('a');\n"
5308       "} finally {\n"
5309       "  native_with_try_catch();\n"
5310       "}\n");
5311   CHECK(try_catch.HasCaught());
5312 }
5313
5314
5315 static void TryCatchNestedHelper(int depth) {
5316   if (depth > 0) {
5317     v8::TryCatch try_catch;
5318     try_catch.SetVerbose(true);
5319     TryCatchNestedHelper(depth - 1);
5320     CHECK(try_catch.HasCaught());
5321     try_catch.ReThrow();
5322   } else {
5323     CcTest::isolate()->ThrowException(v8_str("back"));
5324   }
5325 }
5326
5327
5328 TEST(TryCatchNested) {
5329   v8::V8::Initialize();
5330   LocalContext context;
5331   v8::HandleScope scope(context->GetIsolate());
5332   v8::TryCatch try_catch;
5333   TryCatchNestedHelper(5);
5334   CHECK(try_catch.HasCaught());
5335   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5336 }
5337
5338
5339 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5340   CHECK(try_catch->HasCaught());
5341   Handle<Message> message = try_catch->Message();
5342   Handle<Value> resource = message->GetScriptResourceName();
5343   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5344   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5345                      "Uncaught Error: a"));
5346   CHECK_EQ(1, message->GetLineNumber());
5347   CHECK_EQ(6, message->GetStartColumn());
5348 }
5349
5350
5351 void TryCatchMixedNestingHelper(
5352     const v8::FunctionCallbackInfo<v8::Value>& args) {
5353   ApiTestFuzzer::Fuzz();
5354   v8::TryCatch try_catch;
5355   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5356   CHECK(try_catch.HasCaught());
5357   TryCatchMixedNestingCheck(&try_catch);
5358   try_catch.ReThrow();
5359 }
5360
5361
5362 // This test ensures that an outer TryCatch in the following situation:
5363 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5364 // does not clobber the Message object generated for the inner TryCatch.
5365 // This exercises the ability of TryCatch.ReThrow() to restore the
5366 // inner pending Message before throwing the exception again.
5367 TEST(TryCatchMixedNesting) {
5368   v8::Isolate* isolate = CcTest::isolate();
5369   v8::HandleScope scope(isolate);
5370   v8::V8::Initialize();
5371   v8::TryCatch try_catch;
5372   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5373   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5374              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5375   LocalContext context(0, templ);
5376   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5377   TryCatchMixedNestingCheck(&try_catch);
5378 }
5379
5380
5381 THREADED_TEST(Equality) {
5382   LocalContext context;
5383   v8::Isolate* isolate = context->GetIsolate();
5384   v8::HandleScope scope(context->GetIsolate());
5385   // Check that equality works at all before relying on CHECK_EQ
5386   CHECK(v8_str("a")->Equals(v8_str("a")));
5387   CHECK(!v8_str("a")->Equals(v8_str("b")));
5388
5389   CHECK_EQ(v8_str("a"), v8_str("a"));
5390   CHECK_NE(v8_str("a"), v8_str("b"));
5391   CHECK_EQ(v8_num(1), v8_num(1));
5392   CHECK_EQ(v8_num(1.00), v8_num(1));
5393   CHECK_NE(v8_num(1), v8_num(2));
5394
5395   // Assume String is not internalized.
5396   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5397   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5398   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5399   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5400   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5401   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5402   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5403   CHECK(!not_a_number->StrictEquals(not_a_number));
5404   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5405   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5406
5407   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5408   v8::Persistent<v8::Object> alias(isolate, obj);
5409   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5410   alias.Reset();
5411
5412   CHECK(v8_str("a")->SameValue(v8_str("a")));
5413   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5414   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5415   CHECK(v8_num(1)->SameValue(v8_num(1)));
5416   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5417   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5418   CHECK(not_a_number->SameValue(not_a_number));
5419   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5420   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5421 }
5422
5423
5424 THREADED_TEST(MultiRun) {
5425   LocalContext context;
5426   v8::HandleScope scope(context->GetIsolate());
5427   Local<Script> script = v8_compile("x");
5428   for (int i = 0; i < 10; i++)
5429     script->Run();
5430 }
5431
5432
5433 static void GetXValue(Local<String> name,
5434                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5435   ApiTestFuzzer::Fuzz();
5436   CHECK_EQ(info.Data(), v8_str("donut"));
5437   CHECK_EQ(name, v8_str("x"));
5438   info.GetReturnValue().Set(name);
5439 }
5440
5441
5442 THREADED_TEST(SimplePropertyRead) {
5443   LocalContext context;
5444   v8::Isolate* isolate = context->GetIsolate();
5445   v8::HandleScope scope(isolate);
5446   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5447   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5448   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5449   Local<Script> script = v8_compile("obj.x");
5450   for (int i = 0; i < 10; i++) {
5451     Local<Value> result = script->Run();
5452     CHECK_EQ(result, v8_str("x"));
5453   }
5454 }
5455
5456
5457 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5458   LocalContext context;
5459   v8::Isolate* isolate = context->GetIsolate();
5460   v8::HandleScope scope(isolate);
5461   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5462   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5463   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5464
5465   // Uses getOwnPropertyDescriptor to check the configurable status
5466   Local<Script> script_desc = v8_compile(
5467       "var prop = Object.getOwnPropertyDescriptor( "
5468       "obj, 'x');"
5469       "prop.configurable;");
5470   Local<Value> result = script_desc->Run();
5471   CHECK_EQ(result->BooleanValue(), true);
5472
5473   // Redefine get - but still configurable
5474   Local<Script> script_define = v8_compile(
5475       "var desc = { get: function(){return 42; },"
5476       "            configurable: true };"
5477       "Object.defineProperty(obj, 'x', desc);"
5478       "obj.x");
5479   result = script_define->Run();
5480   CHECK_EQ(result, v8_num(42));
5481
5482   // Check that the accessor is still configurable
5483   result = script_desc->Run();
5484   CHECK_EQ(result->BooleanValue(), true);
5485
5486   // Redefine to a non-configurable
5487   script_define = v8_compile(
5488       "var desc = { get: function(){return 43; },"
5489       "             configurable: false };"
5490       "Object.defineProperty(obj, 'x', desc);"
5491       "obj.x");
5492   result = script_define->Run();
5493   CHECK_EQ(result, v8_num(43));
5494   result = script_desc->Run();
5495   CHECK_EQ(result->BooleanValue(), false);
5496
5497   // Make sure that it is not possible to redefine again
5498   v8::TryCatch try_catch;
5499   result = script_define->Run();
5500   CHECK(try_catch.HasCaught());
5501   String::Utf8Value exception_value(try_catch.Exception());
5502   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5503 }
5504
5505
5506 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5507   v8::Isolate* isolate = CcTest::isolate();
5508   v8::HandleScope scope(isolate);
5509   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5510   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5511   LocalContext context;
5512   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5513
5514   Local<Script> script_desc = v8_compile(
5515       "var prop ="
5516       "Object.getOwnPropertyDescriptor( "
5517       "obj, 'x');"
5518       "prop.configurable;");
5519   Local<Value> result = script_desc->Run();
5520   CHECK_EQ(result->BooleanValue(), true);
5521
5522   Local<Script> script_define = v8_compile(
5523       "var desc = {get: function(){return 42; },"
5524       "            configurable: true };"
5525       "Object.defineProperty(obj, 'x', desc);"
5526       "obj.x");
5527   result = script_define->Run();
5528   CHECK_EQ(result, v8_num(42));
5529
5530
5531   result = script_desc->Run();
5532   CHECK_EQ(result->BooleanValue(), true);
5533
5534
5535   script_define = v8_compile(
5536       "var desc = {get: function(){return 43; },"
5537       "            configurable: false };"
5538       "Object.defineProperty(obj, 'x', desc);"
5539       "obj.x");
5540   result = script_define->Run();
5541   CHECK_EQ(result, v8_num(43));
5542   result = script_desc->Run();
5543
5544   CHECK_EQ(result->BooleanValue(), false);
5545
5546   v8::TryCatch try_catch;
5547   result = script_define->Run();
5548   CHECK(try_catch.HasCaught());
5549   String::Utf8Value exception_value(try_catch.Exception());
5550   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5551 }
5552
5553
5554 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5555                                                 char const* name) {
5556   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5557 }
5558
5559
5560 THREADED_TEST(DefineAPIAccessorOnObject) {
5561   v8::Isolate* isolate = CcTest::isolate();
5562   v8::HandleScope scope(isolate);
5563   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5564   LocalContext context;
5565
5566   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5567   CompileRun("var obj2 = {};");
5568
5569   CHECK(CompileRun("obj1.x")->IsUndefined());
5570   CHECK(CompileRun("obj2.x")->IsUndefined());
5571
5572   CHECK(GetGlobalProperty(&context, "obj1")->
5573       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5574
5575   ExpectString("obj1.x", "x");
5576   CHECK(CompileRun("obj2.x")->IsUndefined());
5577
5578   CHECK(GetGlobalProperty(&context, "obj2")->
5579       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5580
5581   ExpectString("obj1.x", "x");
5582   ExpectString("obj2.x", "x");
5583
5584   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5585   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5586
5587   CompileRun("Object.defineProperty(obj1, 'x',"
5588              "{ get: function() { return 'y'; }, configurable: true })");
5589
5590   ExpectString("obj1.x", "y");
5591   ExpectString("obj2.x", "x");
5592
5593   CompileRun("Object.defineProperty(obj2, 'x',"
5594              "{ get: function() { return 'y'; }, configurable: true })");
5595
5596   ExpectString("obj1.x", "y");
5597   ExpectString("obj2.x", "y");
5598
5599   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5600   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5601
5602   CHECK(GetGlobalProperty(&context, "obj1")->
5603       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5604   CHECK(GetGlobalProperty(&context, "obj2")->
5605       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5606
5607   ExpectString("obj1.x", "x");
5608   ExpectString("obj2.x", "x");
5609
5610   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5611   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5612
5613   // Define getters/setters, but now make them not configurable.
5614   CompileRun("Object.defineProperty(obj1, 'x',"
5615              "{ get: function() { return 'z'; }, configurable: false })");
5616   CompileRun("Object.defineProperty(obj2, 'x',"
5617              "{ get: function() { return 'z'; }, configurable: false })");
5618
5619   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5620   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5621
5622   ExpectString("obj1.x", "z");
5623   ExpectString("obj2.x", "z");
5624
5625   CHECK(!GetGlobalProperty(&context, "obj1")->
5626       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5627   CHECK(!GetGlobalProperty(&context, "obj2")->
5628       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5629
5630   ExpectString("obj1.x", "z");
5631   ExpectString("obj2.x", "z");
5632 }
5633
5634
5635 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5636   v8::Isolate* isolate = CcTest::isolate();
5637   v8::HandleScope scope(isolate);
5638   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5639   LocalContext context;
5640
5641   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5642   CompileRun("var obj2 = {};");
5643
5644   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5645         v8_str("x"),
5646         GetXValue, NULL,
5647         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5648   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5649         v8_str("x"),
5650         GetXValue, NULL,
5651         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5652
5653   ExpectString("obj1.x", "x");
5654   ExpectString("obj2.x", "x");
5655
5656   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5657   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5658
5659   CHECK(!GetGlobalProperty(&context, "obj1")->
5660       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5661   CHECK(!GetGlobalProperty(&context, "obj2")->
5662       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5663
5664   {
5665     v8::TryCatch try_catch;
5666     CompileRun("Object.defineProperty(obj1, 'x',"
5667         "{get: function() { return 'func'; }})");
5668     CHECK(try_catch.HasCaught());
5669     String::Utf8Value exception_value(try_catch.Exception());
5670     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5671   }
5672   {
5673     v8::TryCatch try_catch;
5674     CompileRun("Object.defineProperty(obj2, 'x',"
5675         "{get: function() { return 'func'; }})");
5676     CHECK(try_catch.HasCaught());
5677     String::Utf8Value exception_value(try_catch.Exception());
5678     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5679   }
5680 }
5681
5682
5683 static void Get239Value(Local<String> name,
5684                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5685   ApiTestFuzzer::Fuzz();
5686   CHECK_EQ(info.Data(), v8_str("donut"));
5687   CHECK_EQ(name, v8_str("239"));
5688   info.GetReturnValue().Set(name);
5689 }
5690
5691
5692 THREADED_TEST(ElementAPIAccessor) {
5693   v8::Isolate* isolate = CcTest::isolate();
5694   v8::HandleScope scope(isolate);
5695   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5696   LocalContext context;
5697
5698   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5699   CompileRun("var obj2 = {};");
5700
5701   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5702         v8_str("239"),
5703         Get239Value, NULL,
5704         v8_str("donut")));
5705   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5706         v8_str("239"),
5707         Get239Value, NULL,
5708         v8_str("donut")));
5709
5710   ExpectString("obj1[239]", "239");
5711   ExpectString("obj2[239]", "239");
5712   ExpectString("obj1['239']", "239");
5713   ExpectString("obj2['239']", "239");
5714 }
5715
5716
5717 v8::Persistent<Value> xValue;
5718
5719
5720 static void SetXValue(Local<String> name,
5721                       Local<Value> value,
5722                       const v8::PropertyCallbackInfo<void>& info) {
5723   CHECK_EQ(value, v8_num(4));
5724   CHECK_EQ(info.Data(), v8_str("donut"));
5725   CHECK_EQ(name, v8_str("x"));
5726   CHECK(xValue.IsEmpty());
5727   xValue.Reset(info.GetIsolate(), value);
5728 }
5729
5730
5731 THREADED_TEST(SimplePropertyWrite) {
5732   v8::Isolate* isolate = CcTest::isolate();
5733   v8::HandleScope scope(isolate);
5734   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5735   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5736   LocalContext context;
5737   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5738   Local<Script> script = v8_compile("obj.x = 4");
5739   for (int i = 0; i < 10; i++) {
5740     CHECK(xValue.IsEmpty());
5741     script->Run();
5742     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5743     xValue.Reset();
5744   }
5745 }
5746
5747
5748 THREADED_TEST(SetterOnly) {
5749   v8::Isolate* isolate = CcTest::isolate();
5750   v8::HandleScope scope(isolate);
5751   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5752   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5753   LocalContext context;
5754   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5755   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5756   for (int i = 0; i < 10; i++) {
5757     CHECK(xValue.IsEmpty());
5758     script->Run();
5759     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5760     xValue.Reset();
5761   }
5762 }
5763
5764
5765 THREADED_TEST(NoAccessors) {
5766   v8::Isolate* isolate = CcTest::isolate();
5767   v8::HandleScope scope(isolate);
5768   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5769   templ->SetAccessor(v8_str("x"),
5770                      static_cast<v8::AccessorGetterCallback>(NULL),
5771                      NULL,
5772                      v8_str("donut"));
5773   LocalContext context;
5774   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5775   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5776   for (int i = 0; i < 10; i++) {
5777     script->Run();
5778   }
5779 }
5780
5781
5782 static void XPropertyGetter(Local<String> property,
5783                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5784   ApiTestFuzzer::Fuzz();
5785   CHECK(info.Data()->IsUndefined());
5786   info.GetReturnValue().Set(property);
5787 }
5788
5789
5790 THREADED_TEST(NamedInterceptorPropertyRead) {
5791   v8::Isolate* isolate = CcTest::isolate();
5792   v8::HandleScope scope(isolate);
5793   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5794   templ->SetNamedPropertyHandler(XPropertyGetter);
5795   LocalContext context;
5796   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5797   Local<Script> script = v8_compile("obj.x");
5798   for (int i = 0; i < 10; i++) {
5799     Local<Value> result = script->Run();
5800     CHECK_EQ(result, v8_str("x"));
5801   }
5802 }
5803
5804
5805 THREADED_TEST(NamedInterceptorDictionaryIC) {
5806   v8::Isolate* isolate = CcTest::isolate();
5807   v8::HandleScope scope(isolate);
5808   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5809   templ->SetNamedPropertyHandler(XPropertyGetter);
5810   LocalContext context;
5811   // Create an object with a named interceptor.
5812   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5813   Local<Script> script = v8_compile("interceptor_obj.x");
5814   for (int i = 0; i < 10; i++) {
5815     Local<Value> result = script->Run();
5816     CHECK_EQ(result, v8_str("x"));
5817   }
5818   // Create a slow case object and a function accessing a property in
5819   // that slow case object (with dictionary probing in generated
5820   // code). Then force object with a named interceptor into slow-case,
5821   // pass it to the function, and check that the interceptor is called
5822   // instead of accessing the local property.
5823   Local<Value> result =
5824       CompileRun("function get_x(o) { return o.x; };"
5825                  "var obj = { x : 42, y : 0 };"
5826                  "delete obj.y;"
5827                  "for (var i = 0; i < 10; i++) get_x(obj);"
5828                  "interceptor_obj.x = 42;"
5829                  "interceptor_obj.y = 10;"
5830                  "delete interceptor_obj.y;"
5831                  "get_x(interceptor_obj)");
5832   CHECK_EQ(result, v8_str("x"));
5833 }
5834
5835
5836 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5837   v8::Isolate* isolate = CcTest::isolate();
5838   v8::HandleScope scope(isolate);
5839   v8::Local<Context> context1 = Context::New(isolate);
5840
5841   context1->Enter();
5842   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5843   templ->SetNamedPropertyHandler(XPropertyGetter);
5844   // Create an object with a named interceptor.
5845   v8::Local<v8::Object> object = templ->NewInstance();
5846   context1->Global()->Set(v8_str("interceptor_obj"), object);
5847
5848   // Force the object into the slow case.
5849   CompileRun("interceptor_obj.y = 0;"
5850              "delete interceptor_obj.y;");
5851   context1->Exit();
5852
5853   {
5854     // Introduce the object into a different context.
5855     // Repeat named loads to exercise ICs.
5856     LocalContext context2;
5857     context2->Global()->Set(v8_str("interceptor_obj"), object);
5858     Local<Value> result =
5859       CompileRun("function get_x(o) { return o.x; }"
5860                  "interceptor_obj.x = 42;"
5861                  "for (var i=0; i != 10; i++) {"
5862                  "  get_x(interceptor_obj);"
5863                  "}"
5864                  "get_x(interceptor_obj)");
5865     // Check that the interceptor was actually invoked.
5866     CHECK_EQ(result, v8_str("x"));
5867   }
5868
5869   // Return to the original context and force some object to the slow case
5870   // to cause the NormalizedMapCache to verify.
5871   context1->Enter();
5872   CompileRun("var obj = { x : 0 }; delete obj.x;");
5873   context1->Exit();
5874 }
5875
5876
5877 static void SetXOnPrototypeGetter(
5878     Local<String> property,
5879     const v8::PropertyCallbackInfo<v8::Value>& info) {
5880   // Set x on the prototype object and do not handle the get request.
5881   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5882   proto.As<v8::Object>()->Set(v8_str("x"),
5883                               v8::Integer::New(info.GetIsolate(), 23));
5884 }
5885
5886
5887 // This is a regression test for http://crbug.com/20104. Map
5888 // transitions should not interfere with post interceptor lookup.
5889 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5890   v8::Isolate* isolate = CcTest::isolate();
5891   v8::HandleScope scope(isolate);
5892   Local<v8::FunctionTemplate> function_template =
5893       v8::FunctionTemplate::New(isolate);
5894   Local<v8::ObjectTemplate> instance_template
5895       = function_template->InstanceTemplate();
5896   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5897   LocalContext context;
5898   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5899   // Create an instance of F and introduce a map transition for x.
5900   CompileRun("var o = new F(); o.x = 23;");
5901   // Create an instance of F and invoke the getter. The result should be 23.
5902   Local<Value> result = CompileRun("o = new F(); o.x");
5903   CHECK_EQ(result->Int32Value(), 23);
5904 }
5905
5906
5907 static void IndexedPropertyGetter(
5908     uint32_t index,
5909     const v8::PropertyCallbackInfo<v8::Value>& info) {
5910   ApiTestFuzzer::Fuzz();
5911   if (index == 37) {
5912     info.GetReturnValue().Set(v8_num(625));
5913   }
5914 }
5915
5916
5917 static void IndexedPropertySetter(
5918     uint32_t index,
5919     Local<Value> value,
5920     const v8::PropertyCallbackInfo<v8::Value>& info) {
5921   ApiTestFuzzer::Fuzz();
5922   if (index == 39) {
5923     info.GetReturnValue().Set(value);
5924   }
5925 }
5926
5927
5928 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5929   v8::Isolate* isolate = CcTest::isolate();
5930   v8::HandleScope scope(isolate);
5931   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5932   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5933                                    IndexedPropertySetter);
5934   LocalContext context;
5935   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5936   Local<Script> getter_script = v8_compile(
5937       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5938   Local<Script> setter_script = v8_compile(
5939       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5940       "obj[17] = 23;"
5941       "obj.foo;");
5942   Local<Script> interceptor_setter_script = v8_compile(
5943       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5944       "obj[39] = 47;"
5945       "obj.foo;");  // This setter should not run, due to the interceptor.
5946   Local<Script> interceptor_getter_script = v8_compile(
5947       "obj[37];");
5948   Local<Value> result = getter_script->Run();
5949   CHECK_EQ(v8_num(5), result);
5950   result = setter_script->Run();
5951   CHECK_EQ(v8_num(23), result);
5952   result = interceptor_setter_script->Run();
5953   CHECK_EQ(v8_num(23), result);
5954   result = interceptor_getter_script->Run();
5955   CHECK_EQ(v8_num(625), result);
5956 }
5957
5958
5959 static void UnboxedDoubleIndexedPropertyGetter(
5960     uint32_t index,
5961     const v8::PropertyCallbackInfo<v8::Value>& info) {
5962   ApiTestFuzzer::Fuzz();
5963   if (index < 25) {
5964     info.GetReturnValue().Set(v8_num(index));
5965   }
5966 }
5967
5968
5969 static void UnboxedDoubleIndexedPropertySetter(
5970     uint32_t index,
5971     Local<Value> value,
5972     const v8::PropertyCallbackInfo<v8::Value>& info) {
5973   ApiTestFuzzer::Fuzz();
5974   if (index < 25) {
5975     info.GetReturnValue().Set(v8_num(index));
5976   }
5977 }
5978
5979
5980 void UnboxedDoubleIndexedPropertyEnumerator(
5981     const v8::PropertyCallbackInfo<v8::Array>& info) {
5982   // Force the list of returned keys to be stored in a FastDoubleArray.
5983   Local<Script> indexed_property_names_script = v8_compile(
5984       "keys = new Array(); keys[125000] = 1;"
5985       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5986       "keys.length = 25; keys;");
5987   Local<Value> result = indexed_property_names_script->Run();
5988   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5989 }
5990
5991
5992 // Make sure that the the interceptor code in the runtime properly handles
5993 // merging property name lists for double-array-backed arrays.
5994 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5995   v8::Isolate* isolate = CcTest::isolate();
5996   v8::HandleScope scope(isolate);
5997   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5998   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5999                                    UnboxedDoubleIndexedPropertySetter,
6000                                    0,
6001                                    0,
6002                                    UnboxedDoubleIndexedPropertyEnumerator);
6003   LocalContext context;
6004   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6005   // When obj is created, force it to be Stored in a FastDoubleArray.
6006   Local<Script> create_unboxed_double_script = v8_compile(
6007       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6008       "key_count = 0; "
6009       "for (x in obj) {key_count++;};"
6010       "obj;");
6011   Local<Value> result = create_unboxed_double_script->Run();
6012   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6013   Local<Script> key_count_check = v8_compile("key_count;");
6014   result = key_count_check->Run();
6015   CHECK_EQ(v8_num(40013), result);
6016 }
6017
6018
6019 void SloppyArgsIndexedPropertyEnumerator(
6020     const v8::PropertyCallbackInfo<v8::Array>& info) {
6021   // Force the list of returned keys to be stored in a Arguments object.
6022   Local<Script> indexed_property_names_script = v8_compile(
6023       "function f(w,x) {"
6024       " return arguments;"
6025       "}"
6026       "keys = f(0, 1, 2, 3);"
6027       "keys;");
6028   Local<Object> result =
6029       Local<Object>::Cast(indexed_property_names_script->Run());
6030   // Have to populate the handle manually, as it's not Cast-able.
6031   i::Handle<i::JSObject> o =
6032       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6033   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6034   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6035 }
6036
6037
6038 static void SloppyIndexedPropertyGetter(
6039     uint32_t index,
6040     const v8::PropertyCallbackInfo<v8::Value>& info) {
6041   ApiTestFuzzer::Fuzz();
6042   if (index < 4) {
6043     info.GetReturnValue().Set(v8_num(index));
6044   }
6045 }
6046
6047
6048 // Make sure that the the interceptor code in the runtime properly handles
6049 // merging property name lists for non-string arguments arrays.
6050 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6051   v8::Isolate* isolate = CcTest::isolate();
6052   v8::HandleScope scope(isolate);
6053   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6054   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6055                                    0,
6056                                    0,
6057                                    0,
6058                                    SloppyArgsIndexedPropertyEnumerator);
6059   LocalContext context;
6060   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6061   Local<Script> create_args_script = v8_compile(
6062       "var key_count = 0;"
6063       "for (x in obj) {key_count++;} key_count;");
6064   Local<Value> result = create_args_script->Run();
6065   CHECK_EQ(v8_num(4), result);
6066 }
6067
6068
6069 static void IdentityIndexedPropertyGetter(
6070     uint32_t index,
6071     const v8::PropertyCallbackInfo<v8::Value>& info) {
6072   info.GetReturnValue().Set(index);
6073 }
6074
6075
6076 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6077   v8::Isolate* isolate = CcTest::isolate();
6078   v8::HandleScope scope(isolate);
6079   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6080   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6081
6082   LocalContext context;
6083   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6084
6085   // Check fast object case.
6086   const char* fast_case_code =
6087       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6088   ExpectString(fast_case_code, "0");
6089
6090   // Check slow case.
6091   const char* slow_case_code =
6092       "obj.x = 1; delete obj.x;"
6093       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6094   ExpectString(slow_case_code, "1");
6095 }
6096
6097
6098 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6099   v8::Isolate* isolate = CcTest::isolate();
6100   v8::HandleScope scope(isolate);
6101   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6102   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6103
6104   LocalContext context;
6105   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6106
6107   const char* code =
6108       "try {"
6109       "  obj[0] = 239;"
6110       "  for (var i = 0; i < 100; i++) {"
6111       "    var v = obj[0];"
6112       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6113       "  }"
6114       "  'PASSED'"
6115       "} catch(e) {"
6116       "  e"
6117       "}";
6118   ExpectString(code, "PASSED");
6119 }
6120
6121
6122 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6123   v8::Isolate* isolate = CcTest::isolate();
6124   v8::HandleScope scope(isolate);
6125   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6126   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6127
6128   LocalContext context;
6129   Local<v8::Object> obj = templ->NewInstance();
6130   obj->TurnOnAccessCheck();
6131   context->Global()->Set(v8_str("obj"), obj);
6132
6133   const char* code =
6134       "try {"
6135       "  for (var i = 0; i < 100; i++) {"
6136       "    var v = obj[0];"
6137       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6138       "  }"
6139       "  'PASSED'"
6140       "} catch(e) {"
6141       "  e"
6142       "}";
6143   ExpectString(code, "PASSED");
6144 }
6145
6146
6147 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6148   i::FLAG_allow_natives_syntax = true;
6149   v8::Isolate* isolate = CcTest::isolate();
6150   v8::HandleScope scope(isolate);
6151   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6152   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6153
6154   LocalContext context;
6155   Local<v8::Object> obj = templ->NewInstance();
6156   context->Global()->Set(v8_str("obj"), obj);
6157
6158   const char* code =
6159       "try {"
6160       "  for (var i = 0; i < 100; i++) {"
6161       "    var expected = i;"
6162       "    if (i == 5) {"
6163       "      %EnableAccessChecks(obj);"
6164       "      expected = undefined;"
6165       "    }"
6166       "    var v = obj[i];"
6167       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6168       "    if (i == 5) %DisableAccessChecks(obj);"
6169       "  }"
6170       "  'PASSED'"
6171       "} catch(e) {"
6172       "  e"
6173       "}";
6174   ExpectString(code, "PASSED");
6175 }
6176
6177
6178 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6179   v8::Isolate* isolate = CcTest::isolate();
6180   v8::HandleScope scope(isolate);
6181   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6182   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6183
6184   LocalContext context;
6185   Local<v8::Object> obj = templ->NewInstance();
6186   context->Global()->Set(v8_str("obj"), obj);
6187
6188   const char* code =
6189       "try {"
6190       "  for (var i = 0; i < 100; i++) {"
6191       "    var v = obj[i];"
6192       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6193       "  }"
6194       "  'PASSED'"
6195       "} catch(e) {"
6196       "  e"
6197       "}";
6198   ExpectString(code, "PASSED");
6199 }
6200
6201
6202 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6203   v8::Isolate* isolate = CcTest::isolate();
6204   v8::HandleScope scope(isolate);
6205   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6206   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6207
6208   LocalContext context;
6209   Local<v8::Object> obj = templ->NewInstance();
6210   context->Global()->Set(v8_str("obj"), obj);
6211
6212   const char* code =
6213       "try {"
6214       "  for (var i = 0; i < 100; i++) {"
6215       "    var expected = i;"
6216       "    var key = i;"
6217       "    if (i == 25) {"
6218       "       key = -1;"
6219       "       expected = undefined;"
6220       "    }"
6221       "    if (i == 50) {"
6222       "       /* probe minimal Smi number on 32-bit platforms */"
6223       "       key = -(1 << 30);"
6224       "       expected = undefined;"
6225       "    }"
6226       "    if (i == 75) {"
6227       "       /* probe minimal Smi number on 64-bit platforms */"
6228       "       key = 1 << 31;"
6229       "       expected = undefined;"
6230       "    }"
6231       "    var v = obj[key];"
6232       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6233       "  }"
6234       "  'PASSED'"
6235       "} catch(e) {"
6236       "  e"
6237       "}";
6238   ExpectString(code, "PASSED");
6239 }
6240
6241
6242 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6243   v8::Isolate* isolate = CcTest::isolate();
6244   v8::HandleScope scope(isolate);
6245   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6246   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6247
6248   LocalContext context;
6249   Local<v8::Object> obj = templ->NewInstance();
6250   context->Global()->Set(v8_str("obj"), obj);
6251
6252   const char* code =
6253       "try {"
6254       "  for (var i = 0; i < 100; i++) {"
6255       "    var expected = i;"
6256       "    var key = i;"
6257       "    if (i == 50) {"
6258       "       key = 'foobar';"
6259       "       expected = undefined;"
6260       "    }"
6261       "    var v = obj[key];"
6262       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6263       "  }"
6264       "  'PASSED'"
6265       "} catch(e) {"
6266       "  e"
6267       "}";
6268   ExpectString(code, "PASSED");
6269 }
6270
6271
6272 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6273   v8::Isolate* isolate = CcTest::isolate();
6274   v8::HandleScope scope(isolate);
6275   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6276   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6277
6278   LocalContext context;
6279   Local<v8::Object> obj = templ->NewInstance();
6280   context->Global()->Set(v8_str("obj"), obj);
6281
6282   const char* code =
6283       "var original = obj;"
6284       "try {"
6285       "  for (var i = 0; i < 100; i++) {"
6286       "    var expected = i;"
6287       "    if (i == 50) {"
6288       "       obj = {50: 'foobar'};"
6289       "       expected = 'foobar';"
6290       "    }"
6291       "    var v = obj[i];"
6292       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6293       "    if (i == 50) obj = original;"
6294       "  }"
6295       "  'PASSED'"
6296       "} catch(e) {"
6297       "  e"
6298       "}";
6299   ExpectString(code, "PASSED");
6300 }
6301
6302
6303 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6304   v8::Isolate* isolate = CcTest::isolate();
6305   v8::HandleScope scope(isolate);
6306   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6307   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6308
6309   LocalContext context;
6310   Local<v8::Object> obj = templ->NewInstance();
6311   context->Global()->Set(v8_str("obj"), obj);
6312
6313   const char* code =
6314       "var original = obj;"
6315       "try {"
6316       "  for (var i = 0; i < 100; i++) {"
6317       "    var expected = i;"
6318       "    if (i == 5) {"
6319       "       obj = 239;"
6320       "       expected = undefined;"
6321       "    }"
6322       "    var v = obj[i];"
6323       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6324       "    if (i == 5) obj = original;"
6325       "  }"
6326       "  'PASSED'"
6327       "} catch(e) {"
6328       "  e"
6329       "}";
6330   ExpectString(code, "PASSED");
6331 }
6332
6333
6334 THREADED_TEST(IndexedInterceptorOnProto) {
6335   v8::Isolate* isolate = CcTest::isolate();
6336   v8::HandleScope scope(isolate);
6337   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6338   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6339
6340   LocalContext context;
6341   Local<v8::Object> obj = templ->NewInstance();
6342   context->Global()->Set(v8_str("obj"), obj);
6343
6344   const char* code =
6345       "var o = {__proto__: obj};"
6346       "try {"
6347       "  for (var i = 0; i < 100; i++) {"
6348       "    var v = o[i];"
6349       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6350       "  }"
6351       "  'PASSED'"
6352       "} catch(e) {"
6353       "  e"
6354       "}";
6355   ExpectString(code, "PASSED");
6356 }
6357
6358
6359 THREADED_TEST(MultiContexts) {
6360   v8::Isolate* isolate = CcTest::isolate();
6361   v8::HandleScope scope(isolate);
6362   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6363   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6364                                                         DummyCallHandler));
6365
6366   Local<String> password = v8_str("Password");
6367
6368   // Create an environment
6369   LocalContext context0(0, templ);
6370   context0->SetSecurityToken(password);
6371   v8::Handle<v8::Object> global0 = context0->Global();
6372   global0->Set(v8_str("custom"), v8_num(1234));
6373   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6374
6375   // Create an independent environment
6376   LocalContext context1(0, templ);
6377   context1->SetSecurityToken(password);
6378   v8::Handle<v8::Object> global1 = context1->Global();
6379   global1->Set(v8_str("custom"), v8_num(1234));
6380   CHECK_NE(global0, global1);
6381   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6382   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6383
6384   // Now create a new context with the old global
6385   LocalContext context2(0, templ, global1);
6386   context2->SetSecurityToken(password);
6387   v8::Handle<v8::Object> global2 = context2->Global();
6388   CHECK_EQ(global1, global2);
6389   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6390   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6391 }
6392
6393
6394 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6395   // Make sure that functions created by cloning boilerplates cannot
6396   // communicate through their __proto__ field.
6397
6398   v8::HandleScope scope(CcTest::isolate());
6399
6400   LocalContext env0;
6401   v8::Handle<v8::Object> global0 =
6402       env0->Global();
6403   v8::Handle<v8::Object> object0 =
6404       global0->Get(v8_str("Object")).As<v8::Object>();
6405   v8::Handle<v8::Object> tostring0 =
6406       object0->Get(v8_str("toString")).As<v8::Object>();
6407   v8::Handle<v8::Object> proto0 =
6408       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6409   proto0->Set(v8_str("custom"), v8_num(1234));
6410
6411   LocalContext env1;
6412   v8::Handle<v8::Object> global1 =
6413       env1->Global();
6414   v8::Handle<v8::Object> object1 =
6415       global1->Get(v8_str("Object")).As<v8::Object>();
6416   v8::Handle<v8::Object> tostring1 =
6417       object1->Get(v8_str("toString")).As<v8::Object>();
6418   v8::Handle<v8::Object> proto1 =
6419       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6420   CHECK(!proto1->Has(v8_str("custom")));
6421 }
6422
6423
6424 THREADED_TEST(Regress892105) {
6425   // Make sure that object and array literals created by cloning
6426   // boilerplates cannot communicate through their __proto__
6427   // field. This is rather difficult to check, but we try to add stuff
6428   // to Object.prototype and Array.prototype and create a new
6429   // environment. This should succeed.
6430
6431   v8::HandleScope scope(CcTest::isolate());
6432
6433   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6434                                 "Array.prototype.arr = 4567;"
6435                                 "8901");
6436
6437   LocalContext env0;
6438   Local<Script> script0 = v8_compile(source);
6439   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6440
6441   LocalContext env1;
6442   Local<Script> script1 = v8_compile(source);
6443   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6444 }
6445
6446
6447 THREADED_TEST(UndetectableObject) {
6448   LocalContext env;
6449   v8::HandleScope scope(env->GetIsolate());
6450
6451   Local<v8::FunctionTemplate> desc =
6452       v8::FunctionTemplate::New(env->GetIsolate());
6453   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6454
6455   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6456   env->Global()->Set(v8_str("undetectable"), obj);
6457
6458   ExpectString("undetectable.toString()", "[object Object]");
6459   ExpectString("typeof undetectable", "undefined");
6460   ExpectString("typeof(undetectable)", "undefined");
6461   ExpectBoolean("typeof undetectable == 'undefined'", true);
6462   ExpectBoolean("typeof undetectable == 'object'", false);
6463   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6464   ExpectBoolean("!undetectable", true);
6465
6466   ExpectObject("true&&undetectable", obj);
6467   ExpectBoolean("false&&undetectable", false);
6468   ExpectBoolean("true||undetectable", true);
6469   ExpectObject("false||undetectable", obj);
6470
6471   ExpectObject("undetectable&&true", obj);
6472   ExpectObject("undetectable&&false", obj);
6473   ExpectBoolean("undetectable||true", true);
6474   ExpectBoolean("undetectable||false", false);
6475
6476   ExpectBoolean("undetectable==null", true);
6477   ExpectBoolean("null==undetectable", true);
6478   ExpectBoolean("undetectable==undefined", true);
6479   ExpectBoolean("undefined==undetectable", true);
6480   ExpectBoolean("undetectable==undetectable", true);
6481
6482
6483   ExpectBoolean("undetectable===null", false);
6484   ExpectBoolean("null===undetectable", false);
6485   ExpectBoolean("undetectable===undefined", false);
6486   ExpectBoolean("undefined===undetectable", false);
6487   ExpectBoolean("undetectable===undetectable", true);
6488 }
6489
6490
6491 THREADED_TEST(VoidLiteral) {
6492   LocalContext env;
6493   v8::Isolate* isolate = env->GetIsolate();
6494   v8::HandleScope scope(isolate);
6495
6496   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6497   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6498
6499   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6500   env->Global()->Set(v8_str("undetectable"), obj);
6501
6502   ExpectBoolean("undefined == void 0", true);
6503   ExpectBoolean("undetectable == void 0", true);
6504   ExpectBoolean("null == void 0", true);
6505   ExpectBoolean("undefined === void 0", true);
6506   ExpectBoolean("undetectable === void 0", false);
6507   ExpectBoolean("null === void 0", false);
6508
6509   ExpectBoolean("void 0 == undefined", true);
6510   ExpectBoolean("void 0 == undetectable", true);
6511   ExpectBoolean("void 0 == null", true);
6512   ExpectBoolean("void 0 === undefined", true);
6513   ExpectBoolean("void 0 === undetectable", false);
6514   ExpectBoolean("void 0 === null", false);
6515
6516   ExpectString("(function() {"
6517                "  try {"
6518                "    return x === void 0;"
6519                "  } catch(e) {"
6520                "    return e.toString();"
6521                "  }"
6522                "})()",
6523                "ReferenceError: x is not defined");
6524   ExpectString("(function() {"
6525                "  try {"
6526                "    return void 0 === x;"
6527                "  } catch(e) {"
6528                "    return e.toString();"
6529                "  }"
6530                "})()",
6531                "ReferenceError: x is not defined");
6532 }
6533
6534
6535 THREADED_TEST(ExtensibleOnUndetectable) {
6536   LocalContext env;
6537   v8::Isolate* isolate = env->GetIsolate();
6538   v8::HandleScope scope(isolate);
6539
6540   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6541   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6542
6543   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6544   env->Global()->Set(v8_str("undetectable"), obj);
6545
6546   Local<String> source = v8_str("undetectable.x = 42;"
6547                                 "undetectable.x");
6548
6549   Local<Script> script = v8_compile(source);
6550
6551   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6552
6553   ExpectBoolean("Object.isExtensible(undetectable)", true);
6554
6555   source = v8_str("Object.preventExtensions(undetectable);");
6556   script = v8_compile(source);
6557   script->Run();
6558   ExpectBoolean("Object.isExtensible(undetectable)", false);
6559
6560   source = v8_str("undetectable.y = 2000;");
6561   script = v8_compile(source);
6562   script->Run();
6563   ExpectBoolean("undetectable.y == undefined", true);
6564 }
6565
6566
6567
6568 THREADED_TEST(UndetectableString) {
6569   LocalContext env;
6570   v8::HandleScope scope(env->GetIsolate());
6571
6572   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6573                                           String::kUndetectableString);
6574   env->Global()->Set(v8_str("undetectable"), obj);
6575
6576   ExpectString("undetectable", "foo");
6577   ExpectString("typeof undetectable", "undefined");
6578   ExpectString("typeof(undetectable)", "undefined");
6579   ExpectBoolean("typeof undetectable == 'undefined'", true);
6580   ExpectBoolean("typeof undetectable == 'string'", false);
6581   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6582   ExpectBoolean("!undetectable", true);
6583
6584   ExpectObject("true&&undetectable", obj);
6585   ExpectBoolean("false&&undetectable", false);
6586   ExpectBoolean("true||undetectable", true);
6587   ExpectObject("false||undetectable", obj);
6588
6589   ExpectObject("undetectable&&true", obj);
6590   ExpectObject("undetectable&&false", obj);
6591   ExpectBoolean("undetectable||true", true);
6592   ExpectBoolean("undetectable||false", false);
6593
6594   ExpectBoolean("undetectable==null", true);
6595   ExpectBoolean("null==undetectable", true);
6596   ExpectBoolean("undetectable==undefined", true);
6597   ExpectBoolean("undefined==undetectable", true);
6598   ExpectBoolean("undetectable==undetectable", true);
6599
6600
6601   ExpectBoolean("undetectable===null", false);
6602   ExpectBoolean("null===undetectable", false);
6603   ExpectBoolean("undetectable===undefined", false);
6604   ExpectBoolean("undefined===undetectable", false);
6605   ExpectBoolean("undetectable===undetectable", true);
6606 }
6607
6608
6609 TEST(UndetectableOptimized) {
6610   i::FLAG_allow_natives_syntax = true;
6611   LocalContext env;
6612   v8::HandleScope scope(env->GetIsolate());
6613
6614   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6615                                           String::kUndetectableString);
6616   env->Global()->Set(v8_str("undetectable"), obj);
6617   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6618
6619   ExpectString(
6620       "function testBranch() {"
6621       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6622       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6623       "}\n"
6624       "function testBool() {"
6625       "  var b1 = !%_IsUndetectableObject(undetectable);"
6626       "  var b2 = %_IsUndetectableObject(detectable);"
6627       "  if (b1) throw 3;"
6628       "  if (b2) throw 4;"
6629       "  return b1 == b2;"
6630       "}\n"
6631       "%OptimizeFunctionOnNextCall(testBranch);"
6632       "%OptimizeFunctionOnNextCall(testBool);"
6633       "for (var i = 0; i < 10; i++) {"
6634       "  testBranch();"
6635       "  testBool();"
6636       "}\n"
6637       "\"PASS\"",
6638       "PASS");
6639 }
6640
6641
6642 // The point of this test is type checking. We run it only so compilers
6643 // don't complain about an unused function.
6644 TEST(PersistentHandles) {
6645   LocalContext env;
6646   v8::Isolate* isolate = CcTest::isolate();
6647   v8::HandleScope scope(isolate);
6648   Local<String> str = v8_str("foo");
6649   v8::Persistent<String> p_str(isolate, str);
6650   p_str.Reset();
6651   Local<Script> scr = v8_compile("");
6652   v8::Persistent<Script> p_scr(isolate, scr);
6653   p_scr.Reset();
6654   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6655   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6656   p_templ.Reset();
6657 }
6658
6659
6660 static void HandleLogDelegator(
6661     const v8::FunctionCallbackInfo<v8::Value>& args) {
6662   ApiTestFuzzer::Fuzz();
6663 }
6664
6665
6666 THREADED_TEST(GlobalObjectTemplate) {
6667   v8::Isolate* isolate = CcTest::isolate();
6668   v8::HandleScope handle_scope(isolate);
6669   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6670   global_template->Set(v8_str("JSNI_Log"),
6671                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6672   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6673   Context::Scope context_scope(context);
6674   CompileRun("JSNI_Log('LOG')");
6675 }
6676
6677
6678 static const char* kSimpleExtensionSource =
6679   "function Foo() {"
6680   "  return 4;"
6681   "}";
6682
6683
6684 TEST(SimpleExtensions) {
6685   v8::HandleScope handle_scope(CcTest::isolate());
6686   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6687   const char* extension_names[] = { "simpletest" };
6688   v8::ExtensionConfiguration extensions(1, extension_names);
6689   v8::Handle<Context> context =
6690       Context::New(CcTest::isolate(), &extensions);
6691   Context::Scope lock(context);
6692   v8::Handle<Value> result = CompileRun("Foo()");
6693   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6694 }
6695
6696
6697 TEST(NullExtensions) {
6698   v8::HandleScope handle_scope(CcTest::isolate());
6699   v8::RegisterExtension(new Extension("nulltest", NULL));
6700   const char* extension_names[] = { "nulltest" };
6701   v8::ExtensionConfiguration extensions(1, extension_names);
6702   v8::Handle<Context> context =
6703       Context::New(CcTest::isolate(), &extensions);
6704   Context::Scope lock(context);
6705   v8::Handle<Value> result = CompileRun("1+3");
6706   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6707 }
6708
6709
6710 static const char* kEmbeddedExtensionSource =
6711     "function Ret54321(){return 54321;}~~@@$"
6712     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6713 static const int kEmbeddedExtensionSourceValidLen = 34;
6714
6715
6716 TEST(ExtensionMissingSourceLength) {
6717   v8::HandleScope handle_scope(CcTest::isolate());
6718   v8::RegisterExtension(new Extension("srclentest_fail",
6719                                       kEmbeddedExtensionSource));
6720   const char* extension_names[] = { "srclentest_fail" };
6721   v8::ExtensionConfiguration extensions(1, extension_names);
6722   v8::Handle<Context> context =
6723       Context::New(CcTest::isolate(), &extensions);
6724   CHECK_EQ(0, *context);
6725 }
6726
6727
6728 TEST(ExtensionWithSourceLength) {
6729   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6730        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6731     v8::HandleScope handle_scope(CcTest::isolate());
6732     i::ScopedVector<char> extension_name(32);
6733     i::SNPrintF(extension_name, "ext #%d", source_len);
6734     v8::RegisterExtension(new Extension(extension_name.start(),
6735                                         kEmbeddedExtensionSource, 0, 0,
6736                                         source_len));
6737     const char* extension_names[1] = { extension_name.start() };
6738     v8::ExtensionConfiguration extensions(1, extension_names);
6739     v8::Handle<Context> context =
6740       Context::New(CcTest::isolate(), &extensions);
6741     if (source_len == kEmbeddedExtensionSourceValidLen) {
6742       Context::Scope lock(context);
6743       v8::Handle<Value> result = CompileRun("Ret54321()");
6744       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6745     } else {
6746       // Anything but exactly the right length should fail to compile.
6747       CHECK_EQ(0, *context);
6748     }
6749   }
6750 }
6751
6752
6753 static const char* kEvalExtensionSource1 =
6754   "function UseEval1() {"
6755   "  var x = 42;"
6756   "  return eval('x');"
6757   "}";
6758
6759
6760 static const char* kEvalExtensionSource2 =
6761   "(function() {"
6762   "  var x = 42;"
6763   "  function e() {"
6764   "    return eval('x');"
6765   "  }"
6766   "  this.UseEval2 = e;"
6767   "})()";
6768
6769
6770 TEST(UseEvalFromExtension) {
6771   v8::HandleScope handle_scope(CcTest::isolate());
6772   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6773   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6774   const char* extension_names[] = { "evaltest1", "evaltest2" };
6775   v8::ExtensionConfiguration extensions(2, extension_names);
6776   v8::Handle<Context> context =
6777       Context::New(CcTest::isolate(), &extensions);
6778   Context::Scope lock(context);
6779   v8::Handle<Value> result = CompileRun("UseEval1()");
6780   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6781   result = CompileRun("UseEval2()");
6782   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6783 }
6784
6785
6786 static const char* kWithExtensionSource1 =
6787   "function UseWith1() {"
6788   "  var x = 42;"
6789   "  with({x:87}) { return x; }"
6790   "}";
6791
6792
6793
6794 static const char* kWithExtensionSource2 =
6795   "(function() {"
6796   "  var x = 42;"
6797   "  function e() {"
6798   "    with ({x:87}) { return x; }"
6799   "  }"
6800   "  this.UseWith2 = e;"
6801   "})()";
6802
6803
6804 TEST(UseWithFromExtension) {
6805   v8::HandleScope handle_scope(CcTest::isolate());
6806   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6807   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6808   const char* extension_names[] = { "withtest1", "withtest2" };
6809   v8::ExtensionConfiguration extensions(2, extension_names);
6810   v8::Handle<Context> context =
6811       Context::New(CcTest::isolate(), &extensions);
6812   Context::Scope lock(context);
6813   v8::Handle<Value> result = CompileRun("UseWith1()");
6814   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6815   result = CompileRun("UseWith2()");
6816   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6817 }
6818
6819
6820 TEST(AutoExtensions) {
6821   v8::HandleScope handle_scope(CcTest::isolate());
6822   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6823   extension->set_auto_enable(true);
6824   v8::RegisterExtension(extension);
6825   v8::Handle<Context> context =
6826       Context::New(CcTest::isolate());
6827   Context::Scope lock(context);
6828   v8::Handle<Value> result = CompileRun("Foo()");
6829   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6830 }
6831
6832
6833 static const char* kSyntaxErrorInExtensionSource =
6834     "[";
6835
6836
6837 // Test that a syntax error in an extension does not cause a fatal
6838 // error but results in an empty context.
6839 TEST(SyntaxErrorExtensions) {
6840   v8::HandleScope handle_scope(CcTest::isolate());
6841   v8::RegisterExtension(new Extension("syntaxerror",
6842                                       kSyntaxErrorInExtensionSource));
6843   const char* extension_names[] = { "syntaxerror" };
6844   v8::ExtensionConfiguration extensions(1, extension_names);
6845   v8::Handle<Context> context =
6846       Context::New(CcTest::isolate(), &extensions);
6847   CHECK(context.IsEmpty());
6848 }
6849
6850
6851 static const char* kExceptionInExtensionSource =
6852     "throw 42";
6853
6854
6855 // Test that an exception when installing an extension does not cause
6856 // a fatal error but results in an empty context.
6857 TEST(ExceptionExtensions) {
6858   v8::HandleScope handle_scope(CcTest::isolate());
6859   v8::RegisterExtension(new Extension("exception",
6860                                       kExceptionInExtensionSource));
6861   const char* extension_names[] = { "exception" };
6862   v8::ExtensionConfiguration extensions(1, extension_names);
6863   v8::Handle<Context> context =
6864       Context::New(CcTest::isolate(), &extensions);
6865   CHECK(context.IsEmpty());
6866 }
6867
6868
6869 static const char* kNativeCallInExtensionSource =
6870     "function call_runtime_last_index_of(x) {"
6871     "  return %StringLastIndexOf(x, 'bob', 10);"
6872     "}";
6873
6874
6875 static const char* kNativeCallTest =
6876     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6877
6878 // Test that a native runtime calls are supported in extensions.
6879 TEST(NativeCallInExtensions) {
6880   v8::HandleScope handle_scope(CcTest::isolate());
6881   v8::RegisterExtension(new Extension("nativecall",
6882                                       kNativeCallInExtensionSource));
6883   const char* extension_names[] = { "nativecall" };
6884   v8::ExtensionConfiguration extensions(1, extension_names);
6885   v8::Handle<Context> context =
6886       Context::New(CcTest::isolate(), &extensions);
6887   Context::Scope lock(context);
6888   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6889   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6890 }
6891
6892
6893 class NativeFunctionExtension : public Extension {
6894  public:
6895   NativeFunctionExtension(const char* name,
6896                           const char* source,
6897                           v8::FunctionCallback fun = &Echo)
6898       : Extension(name, source),
6899         function_(fun) { }
6900
6901   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6902       v8::Isolate* isolate,
6903       v8::Handle<v8::String> name) {
6904     return v8::FunctionTemplate::New(isolate, function_);
6905   }
6906
6907   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6908     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6909   }
6910  private:
6911   v8::FunctionCallback function_;
6912 };
6913
6914
6915 TEST(NativeFunctionDeclaration) {
6916   v8::HandleScope handle_scope(CcTest::isolate());
6917   const char* name = "nativedecl";
6918   v8::RegisterExtension(new NativeFunctionExtension(name,
6919                                                     "native function foo();"));
6920   const char* extension_names[] = { name };
6921   v8::ExtensionConfiguration extensions(1, extension_names);
6922   v8::Handle<Context> context =
6923       Context::New(CcTest::isolate(), &extensions);
6924   Context::Scope lock(context);
6925   v8::Handle<Value> result = CompileRun("foo(42);");
6926   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6927 }
6928
6929
6930 TEST(NativeFunctionDeclarationError) {
6931   v8::HandleScope handle_scope(CcTest::isolate());
6932   const char* name = "nativedeclerr";
6933   // Syntax error in extension code.
6934   v8::RegisterExtension(new NativeFunctionExtension(name,
6935                                                     "native\nfunction foo();"));
6936   const char* extension_names[] = { name };
6937   v8::ExtensionConfiguration extensions(1, extension_names);
6938   v8::Handle<Context> context =
6939       Context::New(CcTest::isolate(), &extensions);
6940   CHECK(context.IsEmpty());
6941 }
6942
6943
6944 TEST(NativeFunctionDeclarationErrorEscape) {
6945   v8::HandleScope handle_scope(CcTest::isolate());
6946   const char* name = "nativedeclerresc";
6947   // Syntax error in extension code - escape code in "native" means that
6948   // it's not treated as a keyword.
6949   v8::RegisterExtension(new NativeFunctionExtension(
6950       name,
6951       "nativ\\u0065 function foo();"));
6952   const char* extension_names[] = { name };
6953   v8::ExtensionConfiguration extensions(1, extension_names);
6954   v8::Handle<Context> context =
6955       Context::New(CcTest::isolate(), &extensions);
6956   CHECK(context.IsEmpty());
6957 }
6958
6959
6960 static void CheckDependencies(const char* name, const char* expected) {
6961   v8::HandleScope handle_scope(CcTest::isolate());
6962   v8::ExtensionConfiguration config(1, &name);
6963   LocalContext context(&config);
6964   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6965            context->Global()->Get(v8_str("loaded")));
6966 }
6967
6968
6969 /*
6970  * Configuration:
6971  *
6972  *     /-- B <--\
6973  * A <-          -- D <-- E
6974  *     \-- C <--/
6975  */
6976 THREADED_TEST(ExtensionDependency) {
6977   static const char* kEDeps[] = { "D" };
6978   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6979   static const char* kDDeps[] = { "B", "C" };
6980   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6981   static const char* kBCDeps[] = { "A" };
6982   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6983   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6984   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6985   CheckDependencies("A", "undefinedA");
6986   CheckDependencies("B", "undefinedAB");
6987   CheckDependencies("C", "undefinedAC");
6988   CheckDependencies("D", "undefinedABCD");
6989   CheckDependencies("E", "undefinedABCDE");
6990   v8::HandleScope handle_scope(CcTest::isolate());
6991   static const char* exts[2] = { "C", "E" };
6992   v8::ExtensionConfiguration config(2, exts);
6993   LocalContext context(&config);
6994   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6995 }
6996
6997
6998 static const char* kExtensionTestScript =
6999   "native function A();"
7000   "native function B();"
7001   "native function C();"
7002   "function Foo(i) {"
7003   "  if (i == 0) return A();"
7004   "  if (i == 1) return B();"
7005   "  if (i == 2) return C();"
7006   "}";
7007
7008
7009 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7010   ApiTestFuzzer::Fuzz();
7011   if (args.IsConstructCall()) {
7012     args.This()->Set(v8_str("data"), args.Data());
7013     args.GetReturnValue().SetNull();
7014     return;
7015   }
7016   args.GetReturnValue().Set(args.Data());
7017 }
7018
7019
7020 class FunctionExtension : public Extension {
7021  public:
7022   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7023   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7024       v8::Isolate* isolate,
7025       v8::Handle<String> name);
7026 };
7027
7028
7029 static int lookup_count = 0;
7030 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7031     v8::Isolate* isolate, v8::Handle<String> name) {
7032   lookup_count++;
7033   if (name->Equals(v8_str("A"))) {
7034     return v8::FunctionTemplate::New(
7035         isolate, CallFun, v8::Integer::New(isolate, 8));
7036   } else if (name->Equals(v8_str("B"))) {
7037     return v8::FunctionTemplate::New(
7038         isolate, CallFun, v8::Integer::New(isolate, 7));
7039   } else if (name->Equals(v8_str("C"))) {
7040     return v8::FunctionTemplate::New(
7041         isolate, CallFun, v8::Integer::New(isolate, 6));
7042   } else {
7043     return v8::Handle<v8::FunctionTemplate>();
7044   }
7045 }
7046
7047
7048 THREADED_TEST(FunctionLookup) {
7049   v8::RegisterExtension(new FunctionExtension());
7050   v8::HandleScope handle_scope(CcTest::isolate());
7051   static const char* exts[1] = { "functiontest" };
7052   v8::ExtensionConfiguration config(1, exts);
7053   LocalContext context(&config);
7054   CHECK_EQ(3, lookup_count);
7055   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7056            CompileRun("Foo(0)"));
7057   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7058            CompileRun("Foo(1)"));
7059   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7060            CompileRun("Foo(2)"));
7061 }
7062
7063
7064 THREADED_TEST(NativeFunctionConstructCall) {
7065   v8::RegisterExtension(new FunctionExtension());
7066   v8::HandleScope handle_scope(CcTest::isolate());
7067   static const char* exts[1] = { "functiontest" };
7068   v8::ExtensionConfiguration config(1, exts);
7069   LocalContext context(&config);
7070   for (int i = 0; i < 10; i++) {
7071     // Run a few times to ensure that allocation of objects doesn't
7072     // change behavior of a constructor function.
7073     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7074              CompileRun("(new A()).data"));
7075     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7076              CompileRun("(new B()).data"));
7077     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7078              CompileRun("(new C()).data"));
7079   }
7080 }
7081
7082
7083 static const char* last_location;
7084 static const char* last_message;
7085 void StoringErrorCallback(const char* location, const char* message) {
7086   if (last_location == NULL) {
7087     last_location = location;
7088     last_message = message;
7089   }
7090 }
7091
7092
7093 // ErrorReporting creates a circular extensions configuration and
7094 // tests that the fatal error handler gets called.  This renders V8
7095 // unusable and therefore this test cannot be run in parallel.
7096 TEST(ErrorReporting) {
7097   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7098   static const char* aDeps[] = { "B" };
7099   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7100   static const char* bDeps[] = { "A" };
7101   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7102   last_location = NULL;
7103   v8::ExtensionConfiguration config(1, bDeps);
7104   v8::Handle<Context> context =
7105       Context::New(CcTest::isolate(), &config);
7106   CHECK(context.IsEmpty());
7107   CHECK_NE(last_location, NULL);
7108 }
7109
7110
7111 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7112                                              v8::Handle<Value> data) {
7113   CHECK(message->GetScriptResourceName()->IsUndefined());
7114   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7115   message->GetLineNumber();
7116   message->GetSourceLine();
7117 }
7118
7119
7120 THREADED_TEST(ErrorWithMissingScriptInfo) {
7121   LocalContext context;
7122   v8::HandleScope scope(context->GetIsolate());
7123   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7124   CompileRun("throw Error()");
7125   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7126 }
7127
7128
7129 struct FlagAndPersistent {
7130   bool flag;
7131   v8::Persistent<v8::Object> handle;
7132 };
7133
7134
7135 static void DisposeAndSetFlag(
7136     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7137   data.GetParameter()->handle.Reset();
7138   data.GetParameter()->flag = true;
7139 }
7140
7141
7142 THREADED_TEST(IndependentWeakHandle) {
7143   v8::Isolate* iso = CcTest::isolate();
7144   v8::HandleScope scope(iso);
7145   v8::Handle<Context> context = Context::New(iso);
7146   Context::Scope context_scope(context);
7147
7148   FlagAndPersistent object_a, object_b;
7149
7150   {
7151     v8::HandleScope handle_scope(iso);
7152     object_a.handle.Reset(iso, v8::Object::New(iso));
7153     object_b.handle.Reset(iso, v8::Object::New(iso));
7154   }
7155
7156   object_a.flag = false;
7157   object_b.flag = false;
7158   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7159   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7160   CHECK(!object_b.handle.IsIndependent());
7161   object_a.handle.MarkIndependent();
7162   object_b.handle.MarkIndependent();
7163   CHECK(object_b.handle.IsIndependent());
7164   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7165   CHECK(object_a.flag);
7166   CHECK(object_b.flag);
7167 }
7168
7169
7170 static void InvokeScavenge() {
7171   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7172 }
7173
7174
7175 static void InvokeMarkSweep() {
7176   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7177 }
7178
7179
7180 static void ForceScavenge(
7181     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7182   data.GetParameter()->handle.Reset();
7183   data.GetParameter()->flag = true;
7184   InvokeScavenge();
7185 }
7186
7187
7188 static void ForceMarkSweep(
7189     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7190   data.GetParameter()->handle.Reset();
7191   data.GetParameter()->flag = true;
7192   InvokeMarkSweep();
7193 }
7194
7195
7196 THREADED_TEST(GCFromWeakCallbacks) {
7197   v8::Isolate* isolate = CcTest::isolate();
7198   v8::HandleScope scope(isolate);
7199   v8::Handle<Context> context = Context::New(isolate);
7200   Context::Scope context_scope(context);
7201
7202   static const int kNumberOfGCTypes = 2;
7203   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7204       Callback;
7205   Callback gc_forcing_callback[kNumberOfGCTypes] =
7206       {&ForceScavenge, &ForceMarkSweep};
7207
7208   typedef void (*GCInvoker)();
7209   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7210
7211   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7212     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7213       FlagAndPersistent object;
7214       {
7215         v8::HandleScope handle_scope(isolate);
7216         object.handle.Reset(isolate, v8::Object::New(isolate));
7217       }
7218       object.flag = false;
7219       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7220       object.handle.MarkIndependent();
7221       invoke_gc[outer_gc]();
7222       CHECK(object.flag);
7223     }
7224   }
7225 }
7226
7227
7228 static void RevivingCallback(
7229     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7230   data.GetParameter()->handle.ClearWeak();
7231   data.GetParameter()->flag = true;
7232 }
7233
7234
7235 THREADED_TEST(IndependentHandleRevival) {
7236   v8::Isolate* isolate = CcTest::isolate();
7237   v8::HandleScope scope(isolate);
7238   v8::Handle<Context> context = Context::New(isolate);
7239   Context::Scope context_scope(context);
7240
7241   FlagAndPersistent object;
7242   {
7243     v8::HandleScope handle_scope(isolate);
7244     v8::Local<v8::Object> o = v8::Object::New(isolate);
7245     object.handle.Reset(isolate, o);
7246     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7247     v8::Local<String> y_str = v8_str("y");
7248     o->Set(y_str, y_str);
7249   }
7250   object.flag = false;
7251   object.handle.SetWeak(&object, &RevivingCallback);
7252   object.handle.MarkIndependent();
7253   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7254   CHECK(object.flag);
7255   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7256   {
7257     v8::HandleScope handle_scope(isolate);
7258     v8::Local<v8::Object> o =
7259         v8::Local<v8::Object>::New(isolate, object.handle);
7260     v8::Local<String> y_str = v8_str("y");
7261     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7262     CHECK(o->Get(y_str)->Equals(y_str));
7263   }
7264 }
7265
7266
7267 v8::Handle<Function> args_fun;
7268
7269
7270 static void ArgumentsTestCallback(
7271     const v8::FunctionCallbackInfo<v8::Value>& args) {
7272   ApiTestFuzzer::Fuzz();
7273   v8::Isolate* isolate = args.GetIsolate();
7274   CHECK_EQ(args_fun, args.Callee());
7275   CHECK_EQ(3, args.Length());
7276   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7277   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7278   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7279   CHECK_EQ(v8::Undefined(isolate), args[3]);
7280   v8::HandleScope scope(args.GetIsolate());
7281   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7282 }
7283
7284
7285 THREADED_TEST(Arguments) {
7286   v8::Isolate* isolate = CcTest::isolate();
7287   v8::HandleScope scope(isolate);
7288   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7289   global->Set(v8_str("f"),
7290               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7291   LocalContext context(NULL, global);
7292   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7293   v8_compile("f(1, 2, 3)")->Run();
7294 }
7295
7296
7297 static void NoBlockGetterX(Local<String> name,
7298                            const v8::PropertyCallbackInfo<v8::Value>&) {
7299 }
7300
7301
7302 static void NoBlockGetterI(uint32_t index,
7303                            const v8::PropertyCallbackInfo<v8::Value>&) {
7304 }
7305
7306
7307 static void PDeleter(Local<String> name,
7308                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7309   if (!name->Equals(v8_str("foo"))) {
7310     return;  // not intercepted
7311   }
7312
7313   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7314 }
7315
7316
7317 static void IDeleter(uint32_t index,
7318                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7319   if (index != 2) {
7320     return;  // not intercepted
7321   }
7322
7323   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7324 }
7325
7326
7327 THREADED_TEST(Deleter) {
7328   v8::Isolate* isolate = CcTest::isolate();
7329   v8::HandleScope scope(isolate);
7330   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7331   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7332   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7333   LocalContext context;
7334   context->Global()->Set(v8_str("k"), obj->NewInstance());
7335   CompileRun(
7336     "k.foo = 'foo';"
7337     "k.bar = 'bar';"
7338     "k[2] = 2;"
7339     "k[4] = 4;");
7340   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7341   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7342
7343   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7344   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7345
7346   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7347   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7348
7349   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7350   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7351 }
7352
7353
7354 static void GetK(Local<String> name,
7355                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7356   ApiTestFuzzer::Fuzz();
7357   if (name->Equals(v8_str("foo")) ||
7358       name->Equals(v8_str("bar")) ||
7359       name->Equals(v8_str("baz"))) {
7360     info.GetReturnValue().SetUndefined();
7361   }
7362 }
7363
7364
7365 static void IndexedGetK(uint32_t index,
7366                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7367   ApiTestFuzzer::Fuzz();
7368   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7369 }
7370
7371
7372 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7373   ApiTestFuzzer::Fuzz();
7374   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7375   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7376   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7377   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7378   info.GetReturnValue().Set(result);
7379 }
7380
7381
7382 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7383   ApiTestFuzzer::Fuzz();
7384   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7385   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7386   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7387   info.GetReturnValue().Set(result);
7388 }
7389
7390
7391 THREADED_TEST(Enumerators) {
7392   v8::Isolate* isolate = CcTest::isolate();
7393   v8::HandleScope scope(isolate);
7394   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7395   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7396   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7397   LocalContext context;
7398   context->Global()->Set(v8_str("k"), obj->NewInstance());
7399   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7400     "k[10] = 0;"
7401     "k.a = 0;"
7402     "k[5] = 0;"
7403     "k.b = 0;"
7404     "k[4294967295] = 0;"
7405     "k.c = 0;"
7406     "k[4294967296] = 0;"
7407     "k.d = 0;"
7408     "k[140000] = 0;"
7409     "k.e = 0;"
7410     "k[30000000000] = 0;"
7411     "k.f = 0;"
7412     "var result = [];"
7413     "for (var prop in k) {"
7414     "  result.push(prop);"
7415     "}"
7416     "result"));
7417   // Check that we get all the property names returned including the
7418   // ones from the enumerators in the right order: indexed properties
7419   // in numerical order, indexed interceptor properties, named
7420   // properties in insertion order, named interceptor properties.
7421   // This order is not mandated by the spec, so this test is just
7422   // documenting our behavior.
7423   CHECK_EQ(17, result->Length());
7424   // Indexed properties in numerical order.
7425   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7426   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7427   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7428   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7429   // Indexed interceptor properties in the order they are returned
7430   // from the enumerator interceptor.
7431   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7432   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7433   // Named properties in insertion order.
7434   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7435   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7436   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7437   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7438   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7439   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7440   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7441   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7442   // Named interceptor properties.
7443   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7444   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7445   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7446 }
7447
7448
7449 int p_getter_count;
7450 int p_getter_count2;
7451
7452
7453 static void PGetter(Local<String> name,
7454                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7455   ApiTestFuzzer::Fuzz();
7456   p_getter_count++;
7457   v8::Handle<v8::Object> global =
7458       info.GetIsolate()->GetCurrentContext()->Global();
7459   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7460   if (name->Equals(v8_str("p1"))) {
7461     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7462   } else if (name->Equals(v8_str("p2"))) {
7463     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7464   } else if (name->Equals(v8_str("p3"))) {
7465     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7466   } else if (name->Equals(v8_str("p4"))) {
7467     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7468   }
7469 }
7470
7471
7472 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7473   ApiTestFuzzer::Fuzz();
7474   LocalContext context;
7475   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7476   CompileRun(
7477     "o1.__proto__ = { };"
7478     "var o2 = { __proto__: o1 };"
7479     "var o3 = { __proto__: o2 };"
7480     "var o4 = { __proto__: o3 };"
7481     "for (var i = 0; i < 10; i++) o4.p4;"
7482     "for (var i = 0; i < 10; i++) o3.p3;"
7483     "for (var i = 0; i < 10; i++) o2.p2;"
7484     "for (var i = 0; i < 10; i++) o1.p1;");
7485 }
7486
7487
7488 static void PGetter2(Local<String> name,
7489                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7490   ApiTestFuzzer::Fuzz();
7491   p_getter_count2++;
7492   v8::Handle<v8::Object> global =
7493       info.GetIsolate()->GetCurrentContext()->Global();
7494   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7495   if (name->Equals(v8_str("p1"))) {
7496     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7497   } else if (name->Equals(v8_str("p2"))) {
7498     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7499   } else if (name->Equals(v8_str("p3"))) {
7500     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7501   } else if (name->Equals(v8_str("p4"))) {
7502     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7503   }
7504 }
7505
7506
7507 THREADED_TEST(GetterHolders) {
7508   v8::Isolate* isolate = CcTest::isolate();
7509   v8::HandleScope scope(isolate);
7510   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7511   obj->SetAccessor(v8_str("p1"), PGetter);
7512   obj->SetAccessor(v8_str("p2"), PGetter);
7513   obj->SetAccessor(v8_str("p3"), PGetter);
7514   obj->SetAccessor(v8_str("p4"), PGetter);
7515   p_getter_count = 0;
7516   RunHolderTest(obj);
7517   CHECK_EQ(40, p_getter_count);
7518 }
7519
7520
7521 THREADED_TEST(PreInterceptorHolders) {
7522   v8::Isolate* isolate = CcTest::isolate();
7523   v8::HandleScope scope(isolate);
7524   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7525   obj->SetNamedPropertyHandler(PGetter2);
7526   p_getter_count2 = 0;
7527   RunHolderTest(obj);
7528   CHECK_EQ(40, p_getter_count2);
7529 }
7530
7531
7532 THREADED_TEST(ObjectInstantiation) {
7533   v8::Isolate* isolate = CcTest::isolate();
7534   v8::HandleScope scope(isolate);
7535   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7536   templ->SetAccessor(v8_str("t"), PGetter2);
7537   LocalContext context;
7538   context->Global()->Set(v8_str("o"), templ->NewInstance());
7539   for (int i = 0; i < 100; i++) {
7540     v8::HandleScope inner_scope(CcTest::isolate());
7541     v8::Handle<v8::Object> obj = templ->NewInstance();
7542     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7543     context->Global()->Set(v8_str("o2"), obj);
7544     v8::Handle<Value> value =
7545         CompileRun("o.__proto__ === o2.__proto__");
7546     CHECK_EQ(v8::True(isolate), value);
7547     context->Global()->Set(v8_str("o"), obj);
7548   }
7549 }
7550
7551
7552 static int StrCmp16(uint16_t* a, uint16_t* b) {
7553   while (true) {
7554     if (*a == 0 && *b == 0) return 0;
7555     if (*a != *b) return 0 + *a - *b;
7556     a++;
7557     b++;
7558   }
7559 }
7560
7561
7562 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7563   while (true) {
7564     if (n-- == 0) return 0;
7565     if (*a == 0 && *b == 0) return 0;
7566     if (*a != *b) return 0 + *a - *b;
7567     a++;
7568     b++;
7569   }
7570 }
7571
7572
7573 int GetUtf8Length(Handle<String> str) {
7574   int len = str->Utf8Length();
7575   if (len < 0) {
7576     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7577     i::String::Flatten(istr);
7578     len = str->Utf8Length();
7579   }
7580   return len;
7581 }
7582
7583
7584 THREADED_TEST(StringWrite) {
7585   LocalContext context;
7586   v8::HandleScope scope(context->GetIsolate());
7587   v8::Handle<String> str = v8_str("abcde");
7588   // abc<Icelandic eth><Unicode snowman>.
7589   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7590   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7591       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7592   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7593   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7594   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7595       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7596   // single lead surrogate
7597   uint16_t lead[1] = { 0xd800 };
7598   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7599       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7600   // single trail surrogate
7601   uint16_t trail[1] = { 0xdc00 };
7602   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7603       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7604   // surrogate pair
7605   uint16_t pair[2] = { 0xd800,  0xdc00 };
7606   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7607       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7608   const int kStride = 4;  // Must match stride in for loops in JS below.
7609   CompileRun(
7610       "var left = '';"
7611       "for (var i = 0; i < 0xd800; i += 4) {"
7612       "  left = left + String.fromCharCode(i);"
7613       "}");
7614   CompileRun(
7615       "var right = '';"
7616       "for (var i = 0; i < 0xd800; i += 4) {"
7617       "  right = String.fromCharCode(i) + right;"
7618       "}");
7619   v8::Handle<v8::Object> global = context->Global();
7620   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7621   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7622
7623   CHECK_EQ(5, str2->Length());
7624   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7625   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7626
7627   char buf[100];
7628   char utf8buf[0xd800 * 3];
7629   uint16_t wbuf[100];
7630   int len;
7631   int charlen;
7632
7633   memset(utf8buf, 0x1, 1000);
7634   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7635   CHECK_EQ(9, len);
7636   CHECK_EQ(5, charlen);
7637   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7638
7639   memset(utf8buf, 0x1, 1000);
7640   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7641   CHECK_EQ(8, len);
7642   CHECK_EQ(5, charlen);
7643   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7644
7645   memset(utf8buf, 0x1, 1000);
7646   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7647   CHECK_EQ(5, len);
7648   CHECK_EQ(4, charlen);
7649   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7650
7651   memset(utf8buf, 0x1, 1000);
7652   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7653   CHECK_EQ(5, len);
7654   CHECK_EQ(4, charlen);
7655   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7656
7657   memset(utf8buf, 0x1, 1000);
7658   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7659   CHECK_EQ(5, len);
7660   CHECK_EQ(4, charlen);
7661   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7662
7663   memset(utf8buf, 0x1, 1000);
7664   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7665   CHECK_EQ(3, len);
7666   CHECK_EQ(3, charlen);
7667   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7668
7669   memset(utf8buf, 0x1, 1000);
7670   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7671   CHECK_EQ(3, len);
7672   CHECK_EQ(3, charlen);
7673   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7674
7675   memset(utf8buf, 0x1, 1000);
7676   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7677   CHECK_EQ(2, len);
7678   CHECK_EQ(2, charlen);
7679   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7680
7681   // allow orphan surrogates by default
7682   memset(utf8buf, 0x1, 1000);
7683   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7684   CHECK_EQ(13, len);
7685   CHECK_EQ(8, charlen);
7686   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7687
7688   // replace orphan surrogates with unicode replacement character
7689   memset(utf8buf, 0x1, 1000);
7690   len = orphans_str->WriteUtf8(utf8buf,
7691                                sizeof(utf8buf),
7692                                &charlen,
7693                                String::REPLACE_INVALID_UTF8);
7694   CHECK_EQ(13, len);
7695   CHECK_EQ(8, charlen);
7696   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7697
7698   // replace single lead surrogate with unicode replacement character
7699   memset(utf8buf, 0x1, 1000);
7700   len = lead_str->WriteUtf8(utf8buf,
7701                             sizeof(utf8buf),
7702                             &charlen,
7703                             String::REPLACE_INVALID_UTF8);
7704   CHECK_EQ(4, len);
7705   CHECK_EQ(1, charlen);
7706   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7707
7708   // replace single trail surrogate with unicode replacement character
7709   memset(utf8buf, 0x1, 1000);
7710   len = trail_str->WriteUtf8(utf8buf,
7711                              sizeof(utf8buf),
7712                              &charlen,
7713                              String::REPLACE_INVALID_UTF8);
7714   CHECK_EQ(4, len);
7715   CHECK_EQ(1, charlen);
7716   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7717
7718   // do not replace / write anything if surrogate pair does not fit the buffer
7719   // space
7720   memset(utf8buf, 0x1, 1000);
7721   len = pair_str->WriteUtf8(utf8buf,
7722                              3,
7723                              &charlen,
7724                              String::REPLACE_INVALID_UTF8);
7725   CHECK_EQ(0, len);
7726   CHECK_EQ(0, charlen);
7727
7728   memset(utf8buf, 0x1, sizeof(utf8buf));
7729   len = GetUtf8Length(left_tree);
7730   int utf8_expected =
7731       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7732   CHECK_EQ(utf8_expected, len);
7733   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7734   CHECK_EQ(utf8_expected, len);
7735   CHECK_EQ(0xd800 / kStride, charlen);
7736   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7737   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7738   CHECK_EQ(0xc0 - kStride,
7739            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7740   CHECK_EQ(1, utf8buf[utf8_expected]);
7741
7742   memset(utf8buf, 0x1, sizeof(utf8buf));
7743   len = GetUtf8Length(right_tree);
7744   CHECK_EQ(utf8_expected, len);
7745   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7746   CHECK_EQ(utf8_expected, len);
7747   CHECK_EQ(0xd800 / kStride, charlen);
7748   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7749   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7750   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7751   CHECK_EQ(1, utf8buf[utf8_expected]);
7752
7753   memset(buf, 0x1, sizeof(buf));
7754   memset(wbuf, 0x1, sizeof(wbuf));
7755   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7756   CHECK_EQ(5, len);
7757   len = str->Write(wbuf);
7758   CHECK_EQ(5, len);
7759   CHECK_EQ(0, strcmp("abcde", buf));
7760   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7761   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7762
7763   memset(buf, 0x1, sizeof(buf));
7764   memset(wbuf, 0x1, sizeof(wbuf));
7765   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7766   CHECK_EQ(4, len);
7767   len = str->Write(wbuf, 0, 4);
7768   CHECK_EQ(4, len);
7769   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7770   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7771   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7772
7773   memset(buf, 0x1, sizeof(buf));
7774   memset(wbuf, 0x1, sizeof(wbuf));
7775   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7776   CHECK_EQ(5, len);
7777   len = str->Write(wbuf, 0, 5);
7778   CHECK_EQ(5, len);
7779   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7780   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7781   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7782
7783   memset(buf, 0x1, sizeof(buf));
7784   memset(wbuf, 0x1, sizeof(wbuf));
7785   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7786   CHECK_EQ(5, len);
7787   len = str->Write(wbuf, 0, 6);
7788   CHECK_EQ(5, len);
7789   CHECK_EQ(0, strcmp("abcde", buf));
7790   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7791   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7792
7793   memset(buf, 0x1, sizeof(buf));
7794   memset(wbuf, 0x1, sizeof(wbuf));
7795   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7796   CHECK_EQ(1, len);
7797   len = str->Write(wbuf, 4, -1);
7798   CHECK_EQ(1, len);
7799   CHECK_EQ(0, strcmp("e", buf));
7800   uint16_t answer5[] = {'e', '\0'};
7801   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7802
7803   memset(buf, 0x1, sizeof(buf));
7804   memset(wbuf, 0x1, sizeof(wbuf));
7805   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7806   CHECK_EQ(1, len);
7807   len = str->Write(wbuf, 4, 6);
7808   CHECK_EQ(1, len);
7809   CHECK_EQ(0, strcmp("e", buf));
7810   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7811
7812   memset(buf, 0x1, sizeof(buf));
7813   memset(wbuf, 0x1, sizeof(wbuf));
7814   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7815   CHECK_EQ(1, len);
7816   len = str->Write(wbuf, 4, 1);
7817   CHECK_EQ(1, len);
7818   CHECK_EQ(0, strncmp("e\1", buf, 2));
7819   uint16_t answer6[] = {'e', 0x101};
7820   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7821
7822   memset(buf, 0x1, sizeof(buf));
7823   memset(wbuf, 0x1, sizeof(wbuf));
7824   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7825   CHECK_EQ(1, len);
7826   len = str->Write(wbuf, 3, 1);
7827   CHECK_EQ(1, len);
7828   CHECK_EQ(0, strncmp("d\1", buf, 2));
7829   uint16_t answer7[] = {'d', 0x101};
7830   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7831
7832   memset(wbuf, 0x1, sizeof(wbuf));
7833   wbuf[5] = 'X';
7834   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7835   CHECK_EQ(5, len);
7836   CHECK_EQ('X', wbuf[5]);
7837   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7838   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7839   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7840   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7841   wbuf[5] = '\0';
7842   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7843
7844   memset(buf, 0x1, sizeof(buf));
7845   buf[5] = 'X';
7846   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7847                           0,
7848                           6,
7849                           String::NO_NULL_TERMINATION);
7850   CHECK_EQ(5, len);
7851   CHECK_EQ('X', buf[5]);
7852   CHECK_EQ(0, strncmp("abcde", buf, 5));
7853   CHECK_NE(0, strcmp("abcde", buf));
7854   buf[5] = '\0';
7855   CHECK_EQ(0, strcmp("abcde", buf));
7856
7857   memset(utf8buf, 0x1, sizeof(utf8buf));
7858   utf8buf[8] = 'X';
7859   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7860                         String::NO_NULL_TERMINATION);
7861   CHECK_EQ(8, len);
7862   CHECK_EQ('X', utf8buf[8]);
7863   CHECK_EQ(5, charlen);
7864   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7865   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7866   utf8buf[8] = '\0';
7867   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7868
7869   memset(utf8buf, 0x1, sizeof(utf8buf));
7870   utf8buf[5] = 'X';
7871   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7872                         String::NO_NULL_TERMINATION);
7873   CHECK_EQ(5, len);
7874   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7875   CHECK_EQ(5, charlen);
7876   utf8buf[5] = '\0';
7877   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7878
7879   memset(buf, 0x1, sizeof(buf));
7880   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7881   CHECK_EQ(7, len);
7882   CHECK_EQ(0, strcmp("abc", buf));
7883   CHECK_EQ(0, buf[3]);
7884   CHECK_EQ(0, strcmp("def", buf + 4));
7885
7886   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7887   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7888   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7889 }
7890
7891
7892 static void Utf16Helper(
7893     LocalContext& context,  // NOLINT
7894     const char* name,
7895     const char* lengths_name,
7896     int len) {
7897   Local<v8::Array> a =
7898       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7899   Local<v8::Array> alens =
7900       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7901   for (int i = 0; i < len; i++) {
7902     Local<v8::String> string =
7903       Local<v8::String>::Cast(a->Get(i));
7904     Local<v8::Number> expected_len =
7905       Local<v8::Number>::Cast(alens->Get(i));
7906     int length = GetUtf8Length(string);
7907     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7908   }
7909 }
7910
7911
7912 static uint16_t StringGet(Handle<String> str, int index) {
7913   i::Handle<i::String> istring =
7914       v8::Utils::OpenHandle(String::Cast(*str));
7915   return istring->Get(index);
7916 }
7917
7918
7919 static void WriteUtf8Helper(
7920     LocalContext& context,  // NOLINT
7921     const char* name,
7922     const char* lengths_name,
7923     int len) {
7924   Local<v8::Array> b =
7925       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7926   Local<v8::Array> alens =
7927       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7928   char buffer[1000];
7929   char buffer2[1000];
7930   for (int i = 0; i < len; i++) {
7931     Local<v8::String> string =
7932       Local<v8::String>::Cast(b->Get(i));
7933     Local<v8::Number> expected_len =
7934       Local<v8::Number>::Cast(alens->Get(i));
7935     int utf8_length = static_cast<int>(expected_len->Value());
7936     for (int j = utf8_length + 1; j >= 0; j--) {
7937       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7938       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7939       int nchars;
7940       int utf8_written =
7941           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7942       int utf8_written2 =
7943           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7944       CHECK_GE(utf8_length + 1, utf8_written);
7945       CHECK_GE(utf8_length, utf8_written2);
7946       for (int k = 0; k < utf8_written2; k++) {
7947         CHECK_EQ(buffer[k], buffer2[k]);
7948       }
7949       CHECK(nchars * 3 >= utf8_written - 1);
7950       CHECK(nchars <= utf8_written);
7951       if (j == utf8_length + 1) {
7952         CHECK_EQ(utf8_written2, utf8_length);
7953         CHECK_EQ(utf8_written2 + 1, utf8_written);
7954       }
7955       CHECK_EQ(buffer[utf8_written], 42);
7956       if (j > utf8_length) {
7957         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7958         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7959         Handle<String> roundtrip = v8_str(buffer);
7960         CHECK(roundtrip->Equals(string));
7961       } else {
7962         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7963       }
7964       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7965       if (nchars >= 2) {
7966         uint16_t trail = StringGet(string, nchars - 1);
7967         uint16_t lead = StringGet(string, nchars - 2);
7968         if (((lead & 0xfc00) == 0xd800) &&
7969             ((trail & 0xfc00) == 0xdc00)) {
7970           unsigned char u1 = buffer2[utf8_written2 - 4];
7971           unsigned char u2 = buffer2[utf8_written2 - 3];
7972           unsigned char u3 = buffer2[utf8_written2 - 2];
7973           unsigned char u4 = buffer2[utf8_written2 - 1];
7974           CHECK_EQ((u1 & 0xf8), 0xf0);
7975           CHECK_EQ((u2 & 0xc0), 0x80);
7976           CHECK_EQ((u3 & 0xc0), 0x80);
7977           CHECK_EQ((u4 & 0xc0), 0x80);
7978           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7979           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7980           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7981           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7982           CHECK_EQ((u1 & 0x3), c >> 18);
7983         }
7984       }
7985     }
7986   }
7987 }
7988
7989
7990 THREADED_TEST(Utf16) {
7991   LocalContext context;
7992   v8::HandleScope scope(context->GetIsolate());
7993   CompileRun(
7994       "var pad = '01234567890123456789';"
7995       "var p = [];"
7996       "var plens = [20, 3, 3];"
7997       "p.push('01234567890123456789');"
7998       "var lead = 0xd800;"
7999       "var trail = 0xdc00;"
8000       "p.push(String.fromCharCode(0xd800));"
8001       "p.push(String.fromCharCode(0xdc00));"
8002       "var a = [];"
8003       "var b = [];"
8004       "var c = [];"
8005       "var alens = [];"
8006       "for (var i = 0; i < 3; i++) {"
8007       "  p[1] = String.fromCharCode(lead++);"
8008       "  for (var j = 0; j < 3; j++) {"
8009       "    p[2] = String.fromCharCode(trail++);"
8010       "    a.push(p[i] + p[j]);"
8011       "    b.push(p[i] + p[j]);"
8012       "    c.push(p[i] + p[j]);"
8013       "    alens.push(plens[i] + plens[j]);"
8014       "  }"
8015       "}"
8016       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8017       "var a2 = [];"
8018       "var b2 = [];"
8019       "var c2 = [];"
8020       "var a2lens = [];"
8021       "for (var m = 0; m < 9; m++) {"
8022       "  for (var n = 0; n < 9; n++) {"
8023       "    a2.push(a[m] + a[n]);"
8024       "    b2.push(b[m] + b[n]);"
8025       "    var newc = 'x' + c[m] + c[n] + 'y';"
8026       "    c2.push(newc.substring(1, newc.length - 1));"
8027       "    var utf = alens[m] + alens[n];"  // And here.
8028            // The 'n's that start with 0xdc.. are 6-8
8029            // The 'm's that end with 0xd8.. are 1, 4 and 7
8030       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8031       "    a2lens.push(utf);"
8032       "  }"
8033       "}");
8034   Utf16Helper(context, "a", "alens", 9);
8035   Utf16Helper(context, "a2", "a2lens", 81);
8036   WriteUtf8Helper(context, "b", "alens", 9);
8037   WriteUtf8Helper(context, "b2", "a2lens", 81);
8038   WriteUtf8Helper(context, "c2", "a2lens", 81);
8039 }
8040
8041
8042 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8043   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8044   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8045   return *is1 == *is2;
8046 }
8047
8048 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8049                              const char* b) {
8050   Handle<String> symbol1 =
8051       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8052   Handle<String> symbol2 =
8053       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8054   CHECK(SameSymbol(symbol1, symbol2));
8055 }
8056
8057
8058 THREADED_TEST(Utf16Symbol) {
8059   LocalContext context;
8060   v8::HandleScope scope(context->GetIsolate());
8061
8062   Handle<String> symbol1 = v8::String::NewFromUtf8(
8063       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8064   Handle<String> symbol2 = v8::String::NewFromUtf8(
8065       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8066   CHECK(SameSymbol(symbol1, symbol2));
8067
8068   SameSymbolHelper(context->GetIsolate(),
8069                    "\360\220\220\205",  // 4 byte encoding.
8070                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8071   SameSymbolHelper(context->GetIsolate(),
8072                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8073                    "\360\220\220\206");  // 4 byte encoding.
8074   SameSymbolHelper(context->GetIsolate(),
8075                    "x\360\220\220\205",  // 4 byte encoding.
8076                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8077   SameSymbolHelper(context->GetIsolate(),
8078                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8079                    "x\360\220\220\206");  // 4 byte encoding.
8080   CompileRun(
8081       "var sym0 = 'benedictus';"
8082       "var sym0b = 'S\303\270ren';"
8083       "var sym1 = '\355\240\201\355\260\207';"
8084       "var sym2 = '\360\220\220\210';"
8085       "var sym3 = 'x\355\240\201\355\260\207';"
8086       "var sym4 = 'x\360\220\220\210';"
8087       "if (sym1.length != 2) throw sym1;"
8088       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8089       "if (sym2.length != 2) throw sym2;"
8090       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8091       "if (sym3.length != 3) throw sym3;"
8092       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8093       "if (sym4.length != 3) throw sym4;"
8094       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8095   Handle<String> sym0 = v8::String::NewFromUtf8(
8096       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8097   Handle<String> sym0b = v8::String::NewFromUtf8(
8098       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8099   Handle<String> sym1 =
8100       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8101                               v8::String::kInternalizedString);
8102   Handle<String> sym2 =
8103       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8104                               v8::String::kInternalizedString);
8105   Handle<String> sym3 = v8::String::NewFromUtf8(
8106       context->GetIsolate(), "x\355\240\201\355\260\207",
8107       v8::String::kInternalizedString);
8108   Handle<String> sym4 =
8109       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8110                               v8::String::kInternalizedString);
8111   v8::Local<v8::Object> global = context->Global();
8112   Local<Value> s0 = global->Get(v8_str("sym0"));
8113   Local<Value> s0b = global->Get(v8_str("sym0b"));
8114   Local<Value> s1 = global->Get(v8_str("sym1"));
8115   Local<Value> s2 = global->Get(v8_str("sym2"));
8116   Local<Value> s3 = global->Get(v8_str("sym3"));
8117   Local<Value> s4 = global->Get(v8_str("sym4"));
8118   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8119   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8120   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8121   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8122   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8123   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8124 }
8125
8126
8127 THREADED_TEST(ToArrayIndex) {
8128   LocalContext context;
8129   v8::Isolate* isolate = context->GetIsolate();
8130   v8::HandleScope scope(isolate);
8131
8132   v8::Handle<String> str = v8_str("42");
8133   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8134   CHECK(!index.IsEmpty());
8135   CHECK_EQ(42.0, index->Uint32Value());
8136   str = v8_str("42asdf");
8137   index = str->ToArrayIndex();
8138   CHECK(index.IsEmpty());
8139   str = v8_str("-42");
8140   index = str->ToArrayIndex();
8141   CHECK(index.IsEmpty());
8142   str = v8_str("4294967295");
8143   index = str->ToArrayIndex();
8144   CHECK(!index.IsEmpty());
8145   CHECK_EQ(4294967295.0, index->Uint32Value());
8146   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8147   index = num->ToArrayIndex();
8148   CHECK(!index.IsEmpty());
8149   CHECK_EQ(1.0, index->Uint32Value());
8150   num = v8::Number::New(isolate, -1);
8151   index = num->ToArrayIndex();
8152   CHECK(index.IsEmpty());
8153   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8154   index = obj->ToArrayIndex();
8155   CHECK(index.IsEmpty());
8156 }
8157
8158
8159 THREADED_TEST(ErrorConstruction) {
8160   LocalContext context;
8161   v8::HandleScope scope(context->GetIsolate());
8162
8163   v8::Handle<String> foo = v8_str("foo");
8164   v8::Handle<String> message = v8_str("message");
8165   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8166   CHECK(range_error->IsObject());
8167   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8168   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8169   CHECK(reference_error->IsObject());
8170   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8171   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8172   CHECK(syntax_error->IsObject());
8173   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8174   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8175   CHECK(type_error->IsObject());
8176   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8177   v8::Handle<Value> error = v8::Exception::Error(foo);
8178   CHECK(error->IsObject());
8179   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8180 }
8181
8182
8183 static void YGetter(Local<String> name,
8184                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8185   ApiTestFuzzer::Fuzz();
8186   info.GetReturnValue().Set(v8_num(10));
8187 }
8188
8189
8190 static void YSetter(Local<String> name,
8191                     Local<Value> value,
8192                     const v8::PropertyCallbackInfo<void>& info) {
8193   Local<Object> this_obj = Local<Object>::Cast(info.This());
8194   if (this_obj->Has(name)) this_obj->Delete(name);
8195   this_obj->Set(name, value);
8196 }
8197
8198
8199 THREADED_TEST(DeleteAccessor) {
8200   v8::Isolate* isolate = CcTest::isolate();
8201   v8::HandleScope scope(isolate);
8202   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8203   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8204   LocalContext context;
8205   v8::Handle<v8::Object> holder = obj->NewInstance();
8206   context->Global()->Set(v8_str("holder"), holder);
8207   v8::Handle<Value> result = CompileRun(
8208       "holder.y = 11; holder.y = 12; holder.y");
8209   CHECK_EQ(12, result->Uint32Value());
8210 }
8211
8212
8213 THREADED_TEST(TypeSwitch) {
8214   v8::Isolate* isolate = CcTest::isolate();
8215   v8::HandleScope scope(isolate);
8216   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8217   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8218   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8219   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8220   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8221   LocalContext context;
8222   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8223   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8224   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8225   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8226   for (int i = 0; i < 10; i++) {
8227     CHECK_EQ(0, type_switch->match(obj0));
8228     CHECK_EQ(1, type_switch->match(obj1));
8229     CHECK_EQ(2, type_switch->match(obj2));
8230     CHECK_EQ(3, type_switch->match(obj3));
8231     CHECK_EQ(3, type_switch->match(obj3));
8232     CHECK_EQ(2, type_switch->match(obj2));
8233     CHECK_EQ(1, type_switch->match(obj1));
8234     CHECK_EQ(0, type_switch->match(obj0));
8235   }
8236 }
8237
8238
8239 static int trouble_nesting = 0;
8240 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8241   ApiTestFuzzer::Fuzz();
8242   trouble_nesting++;
8243
8244   // Call a JS function that throws an uncaught exception.
8245   Local<v8::Object> arg_this =
8246       args.GetIsolate()->GetCurrentContext()->Global();
8247   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8248     arg_this->Get(v8_str("trouble_callee")) :
8249     arg_this->Get(v8_str("trouble_caller"));
8250   CHECK(trouble_callee->IsFunction());
8251   args.GetReturnValue().Set(
8252       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8253 }
8254
8255
8256 static int report_count = 0;
8257 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8258                                              v8::Handle<Value>) {
8259   report_count++;
8260 }
8261
8262
8263 // Counts uncaught exceptions, but other tests running in parallel
8264 // also have uncaught exceptions.
8265 TEST(ApiUncaughtException) {
8266   report_count = 0;
8267   LocalContext env;
8268   v8::Isolate* isolate = env->GetIsolate();
8269   v8::HandleScope scope(isolate);
8270   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8271
8272   Local<v8::FunctionTemplate> fun =
8273       v8::FunctionTemplate::New(isolate, TroubleCallback);
8274   v8::Local<v8::Object> global = env->Global();
8275   global->Set(v8_str("trouble"), fun->GetFunction());
8276
8277   CompileRun(
8278       "function trouble_callee() {"
8279       "  var x = null;"
8280       "  return x.foo;"
8281       "};"
8282       "function trouble_caller() {"
8283       "  trouble();"
8284       "};");
8285   Local<Value> trouble = global->Get(v8_str("trouble"));
8286   CHECK(trouble->IsFunction());
8287   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8288   CHECK(trouble_callee->IsFunction());
8289   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8290   CHECK(trouble_caller->IsFunction());
8291   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8292   CHECK_EQ(1, report_count);
8293   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8294 }
8295
8296 static const char* script_resource_name = "ExceptionInNativeScript.js";
8297 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8298                                                 v8::Handle<Value>) {
8299   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8300   CHECK(!name_val.IsEmpty() && name_val->IsString());
8301   v8::String::Utf8Value name(message->GetScriptResourceName());
8302   CHECK_EQ(script_resource_name, *name);
8303   CHECK_EQ(3, message->GetLineNumber());
8304   v8::String::Utf8Value source_line(message->GetSourceLine());
8305   CHECK_EQ("  new o.foo();", *source_line);
8306 }
8307
8308
8309 TEST(ExceptionInNativeScript) {
8310   LocalContext env;
8311   v8::Isolate* isolate = env->GetIsolate();
8312   v8::HandleScope scope(isolate);
8313   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8314
8315   Local<v8::FunctionTemplate> fun =
8316       v8::FunctionTemplate::New(isolate, TroubleCallback);
8317   v8::Local<v8::Object> global = env->Global();
8318   global->Set(v8_str("trouble"), fun->GetFunction());
8319
8320   CompileRunWithOrigin(
8321       "function trouble() {\n"
8322       "  var o = {};\n"
8323       "  new o.foo();\n"
8324       "};",
8325       script_resource_name);
8326   Local<Value> trouble = global->Get(v8_str("trouble"));
8327   CHECK(trouble->IsFunction());
8328   Function::Cast(*trouble)->Call(global, 0, NULL);
8329   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8330 }
8331
8332
8333 TEST(CompilationErrorUsingTryCatchHandler) {
8334   LocalContext env;
8335   v8::HandleScope scope(env->GetIsolate());
8336   v8::TryCatch try_catch;
8337   v8_compile("This doesn't &*&@#$&*^ compile.");
8338   CHECK_NE(NULL, *try_catch.Exception());
8339   CHECK(try_catch.HasCaught());
8340 }
8341
8342
8343 TEST(TryCatchFinallyUsingTryCatchHandler) {
8344   LocalContext env;
8345   v8::HandleScope scope(env->GetIsolate());
8346   v8::TryCatch try_catch;
8347   CompileRun("try { throw ''; } catch (e) {}");
8348   CHECK(!try_catch.HasCaught());
8349   CompileRun("try { throw ''; } finally {}");
8350   CHECK(try_catch.HasCaught());
8351   try_catch.Reset();
8352   CompileRun(
8353       "(function() {"
8354       "try { throw ''; } finally { return; }"
8355       "})()");
8356   CHECK(!try_catch.HasCaught());
8357   CompileRun(
8358       "(function()"
8359       "  { try { throw ''; } finally { throw 0; }"
8360       "})()");
8361   CHECK(try_catch.HasCaught());
8362 }
8363
8364
8365 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8366   v8::HandleScope scope(args.GetIsolate());
8367   CompileRun(args[0]->ToString());
8368 }
8369
8370
8371 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8372   v8::Isolate* isolate = CcTest::isolate();
8373   v8::HandleScope scope(isolate);
8374   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8375   templ->Set(v8_str("CEvaluate"),
8376              v8::FunctionTemplate::New(isolate, CEvaluate));
8377   LocalContext context(0, templ);
8378   v8::TryCatch try_catch;
8379   CompileRun("try {"
8380              "  CEvaluate('throw 1;');"
8381              "} finally {"
8382              "}");
8383   CHECK(try_catch.HasCaught());
8384   CHECK(!try_catch.Message().IsEmpty());
8385   String::Utf8Value exception_value(try_catch.Exception());
8386   CHECK_EQ(*exception_value, "1");
8387   try_catch.Reset();
8388   CompileRun("try {"
8389              "  CEvaluate('throw 1;');"
8390              "} finally {"
8391              "  throw 2;"
8392              "}");
8393   CHECK(try_catch.HasCaught());
8394   CHECK(!try_catch.Message().IsEmpty());
8395   String::Utf8Value finally_exception_value(try_catch.Exception());
8396   CHECK_EQ(*finally_exception_value, "2");
8397 }
8398
8399
8400 // For use within the TestSecurityHandler() test.
8401 static bool g_security_callback_result = false;
8402 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8403                                       Local<Value> name,
8404                                       v8::AccessType type,
8405                                       Local<Value> data) {
8406   printf("a\n");
8407   // Always allow read access.
8408   if (type == v8::ACCESS_GET)
8409     return true;
8410
8411   // Sometimes allow other access.
8412   return g_security_callback_result;
8413 }
8414
8415
8416 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8417                                         uint32_t key,
8418                                         v8::AccessType type,
8419                                         Local<Value> data) {
8420   printf("b\n");
8421   // Always allow read access.
8422   if (type == v8::ACCESS_GET)
8423     return true;
8424
8425   // Sometimes allow other access.
8426   return g_security_callback_result;
8427 }
8428
8429
8430 // SecurityHandler can't be run twice
8431 TEST(SecurityHandler) {
8432   v8::Isolate* isolate = CcTest::isolate();
8433   v8::HandleScope scope0(isolate);
8434   v8::Handle<v8::ObjectTemplate> global_template =
8435       v8::ObjectTemplate::New(isolate);
8436   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8437                                            IndexedSecurityTestCallback);
8438   // Create an environment
8439   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8440   context0->Enter();
8441
8442   v8::Handle<v8::Object> global0 = context0->Global();
8443   v8::Handle<Script> script0 = v8_compile("foo = 111");
8444   script0->Run();
8445   global0->Set(v8_str("0"), v8_num(999));
8446   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8447   CHECK_EQ(111, foo0->Int32Value());
8448   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8449   CHECK_EQ(999, z0->Int32Value());
8450
8451   // Create another environment, should fail security checks.
8452   v8::HandleScope scope1(isolate);
8453
8454   v8::Handle<Context> context1 =
8455     Context::New(isolate, NULL, global_template);
8456   context1->Enter();
8457
8458   v8::Handle<v8::Object> global1 = context1->Global();
8459   global1->Set(v8_str("othercontext"), global0);
8460   // This set will fail the security check.
8461   v8::Handle<Script> script1 =
8462     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8463   script1->Run();
8464   // This read will pass the security check.
8465   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8466   CHECK_EQ(111, foo1->Int32Value());
8467   // This read will pass the security check.
8468   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8469   CHECK_EQ(999, z1->Int32Value());
8470
8471   // Create another environment, should pass security checks.
8472   { g_security_callback_result = true;  // allow security handler to pass.
8473     v8::HandleScope scope2(isolate);
8474     LocalContext context2;
8475     v8::Handle<v8::Object> global2 = context2->Global();
8476     global2->Set(v8_str("othercontext"), global0);
8477     v8::Handle<Script> script2 =
8478         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8479     script2->Run();
8480     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8481     CHECK_EQ(333, foo2->Int32Value());
8482     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8483     CHECK_EQ(888, z2->Int32Value());
8484   }
8485
8486   context1->Exit();
8487   context0->Exit();
8488 }
8489
8490
8491 THREADED_TEST(SecurityChecks) {
8492   LocalContext env1;
8493   v8::HandleScope handle_scope(env1->GetIsolate());
8494   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8495
8496   Local<Value> foo = v8_str("foo");
8497   Local<Value> bar = v8_str("bar");
8498
8499   // Set to the same domain.
8500   env1->SetSecurityToken(foo);
8501
8502   // Create a function in env1.
8503   CompileRun("spy=function(){return spy;}");
8504   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8505   CHECK(spy->IsFunction());
8506
8507   // Create another function accessing global objects.
8508   CompileRun("spy2=function(){return new this.Array();}");
8509   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8510   CHECK(spy2->IsFunction());
8511
8512   // Switch to env2 in the same domain and invoke spy on env2.
8513   {
8514     env2->SetSecurityToken(foo);
8515     // Enter env2
8516     Context::Scope scope_env2(env2);
8517     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8518     CHECK(result->IsFunction());
8519   }
8520
8521   {
8522     env2->SetSecurityToken(bar);
8523     Context::Scope scope_env2(env2);
8524
8525     // Call cross_domain_call, it should throw an exception
8526     v8::TryCatch try_catch;
8527     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8528     CHECK(try_catch.HasCaught());
8529   }
8530 }
8531
8532
8533 // Regression test case for issue 1183439.
8534 THREADED_TEST(SecurityChecksForPrototypeChain) {
8535   LocalContext current;
8536   v8::HandleScope scope(current->GetIsolate());
8537   v8::Handle<Context> other = Context::New(current->GetIsolate());
8538
8539   // Change context to be able to get to the Object function in the
8540   // other context without hitting the security checks.
8541   v8::Local<Value> other_object;
8542   { Context::Scope scope(other);
8543     other_object = other->Global()->Get(v8_str("Object"));
8544     other->Global()->Set(v8_num(42), v8_num(87));
8545   }
8546
8547   current->Global()->Set(v8_str("other"), other->Global());
8548   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8549
8550   // Make sure the security check fails here and we get an undefined
8551   // result instead of getting the Object function. Repeat in a loop
8552   // to make sure to exercise the IC code.
8553   v8::Local<Script> access_other0 = v8_compile("other.Object");
8554   v8::Local<Script> access_other1 = v8_compile("other[42]");
8555   for (int i = 0; i < 5; i++) {
8556     CHECK(!access_other0->Run()->Equals(other_object));
8557     CHECK(access_other0->Run()->IsUndefined());
8558     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8559     CHECK(access_other1->Run()->IsUndefined());
8560   }
8561
8562   // Create an object that has 'other' in its prototype chain and make
8563   // sure we cannot access the Object function indirectly through
8564   // that. Repeat in a loop to make sure to exercise the IC code.
8565   v8_compile("function F() { };"
8566              "F.prototype = other;"
8567              "var f = new F();")->Run();
8568   v8::Local<Script> access_f0 = v8_compile("f.Object");
8569   v8::Local<Script> access_f1 = v8_compile("f[42]");
8570   for (int j = 0; j < 5; j++) {
8571     CHECK(!access_f0->Run()->Equals(other_object));
8572     CHECK(access_f0->Run()->IsUndefined());
8573     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8574     CHECK(access_f1->Run()->IsUndefined());
8575   }
8576
8577   // Now it gets hairy: Set the prototype for the other global object
8578   // to be the current global object. The prototype chain for 'f' now
8579   // goes through 'other' but ends up in the current global object.
8580   { Context::Scope scope(other);
8581     other->Global()->Set(v8_str("__proto__"), current->Global());
8582   }
8583   // Set a named and an index property on the current global
8584   // object. To force the lookup to go through the other global object,
8585   // the properties must not exist in the other global object.
8586   current->Global()->Set(v8_str("foo"), v8_num(100));
8587   current->Global()->Set(v8_num(99), v8_num(101));
8588   // Try to read the properties from f and make sure that the access
8589   // gets stopped by the security checks on the other global object.
8590   Local<Script> access_f2 = v8_compile("f.foo");
8591   Local<Script> access_f3 = v8_compile("f[99]");
8592   for (int k = 0; k < 5; k++) {
8593     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8594     CHECK(access_f2->Run()->IsUndefined());
8595     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8596     CHECK(access_f3->Run()->IsUndefined());
8597   }
8598 }
8599
8600
8601 static bool named_security_check_with_gc_called;
8602
8603 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8604                                         Local<Value> name,
8605                                         v8::AccessType type,
8606                                         Local<Value> data) {
8607   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8608   named_security_check_with_gc_called = true;
8609   return true;
8610 }
8611
8612
8613 static bool indexed_security_check_with_gc_called;
8614
8615 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8616                                               uint32_t key,
8617                                               v8::AccessType type,
8618                                               Local<Value> data) {
8619   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8620   indexed_security_check_with_gc_called = true;
8621   return true;
8622 }
8623
8624
8625 TEST(SecurityTestGCAllowed) {
8626   v8::Isolate* isolate = CcTest::isolate();
8627   v8::HandleScope handle_scope(isolate);
8628   v8::Handle<v8::ObjectTemplate> object_template =
8629       v8::ObjectTemplate::New(isolate);
8630   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8631                                            IndexedSecurityTestCallbackWithGC);
8632
8633   v8::Handle<Context> context = Context::New(isolate);
8634   v8::Context::Scope context_scope(context);
8635
8636   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8637
8638   named_security_check_with_gc_called = false;
8639   CompileRun("obj.foo = new String(1001);");
8640   CHECK(named_security_check_with_gc_called);
8641
8642   indexed_security_check_with_gc_called = false;
8643   CompileRun("obj[0] = new String(1002);");
8644   CHECK(indexed_security_check_with_gc_called);
8645
8646   named_security_check_with_gc_called = false;
8647   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8648   CHECK(named_security_check_with_gc_called);
8649
8650   indexed_security_check_with_gc_called = false;
8651   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8652   CHECK(indexed_security_check_with_gc_called);
8653 }
8654
8655
8656 THREADED_TEST(CrossDomainDelete) {
8657   LocalContext env1;
8658   v8::HandleScope handle_scope(env1->GetIsolate());
8659   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8660
8661   Local<Value> foo = v8_str("foo");
8662   Local<Value> bar = v8_str("bar");
8663
8664   // Set to the same domain.
8665   env1->SetSecurityToken(foo);
8666   env2->SetSecurityToken(foo);
8667
8668   env1->Global()->Set(v8_str("prop"), v8_num(3));
8669   env2->Global()->Set(v8_str("env1"), env1->Global());
8670
8671   // Change env2 to a different domain and delete env1.prop.
8672   env2->SetSecurityToken(bar);
8673   {
8674     Context::Scope scope_env2(env2);
8675     Local<Value> result =
8676         CompileRun("delete env1.prop");
8677     CHECK(result->IsFalse());
8678   }
8679
8680   // Check that env1.prop still exists.
8681   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8682   CHECK(v->IsNumber());
8683   CHECK_EQ(3, v->Int32Value());
8684 }
8685
8686
8687 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8688   LocalContext env1;
8689   v8::HandleScope handle_scope(env1->GetIsolate());
8690   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8691
8692   Local<Value> foo = v8_str("foo");
8693   Local<Value> bar = v8_str("bar");
8694
8695   // Set to the same domain.
8696   env1->SetSecurityToken(foo);
8697   env2->SetSecurityToken(foo);
8698
8699   env1->Global()->Set(v8_str("prop"), v8_num(3));
8700   env2->Global()->Set(v8_str("env1"), env1->Global());
8701
8702   // env1.prop is enumerable in env2.
8703   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8704   {
8705     Context::Scope scope_env2(env2);
8706     Local<Value> result = CompileRun(test);
8707     CHECK(result->IsTrue());
8708   }
8709
8710   // Change env2 to a different domain and test again.
8711   env2->SetSecurityToken(bar);
8712   {
8713     Context::Scope scope_env2(env2);
8714     Local<Value> result = CompileRun(test);
8715     CHECK(result->IsFalse());
8716   }
8717 }
8718
8719
8720 THREADED_TEST(CrossDomainForIn) {
8721   LocalContext env1;
8722   v8::HandleScope handle_scope(env1->GetIsolate());
8723   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8724
8725   Local<Value> foo = v8_str("foo");
8726   Local<Value> bar = v8_str("bar");
8727
8728   // Set to the same domain.
8729   env1->SetSecurityToken(foo);
8730   env2->SetSecurityToken(foo);
8731
8732   env1->Global()->Set(v8_str("prop"), v8_num(3));
8733   env2->Global()->Set(v8_str("env1"), env1->Global());
8734
8735   // Change env2 to a different domain and set env1's global object
8736   // as the __proto__ of an object in env2 and enumerate properties
8737   // in for-in. It shouldn't enumerate properties on env1's global
8738   // object.
8739   env2->SetSecurityToken(bar);
8740   {
8741     Context::Scope scope_env2(env2);
8742     Local<Value> result =
8743         CompileRun("(function(){var obj = {'__proto__':env1};"
8744                    "for (var p in obj)"
8745                    "   if (p == 'prop') return false;"
8746                    "return true;})()");
8747     CHECK(result->IsTrue());
8748   }
8749 }
8750
8751
8752 TEST(ContextDetachGlobal) {
8753   LocalContext env1;
8754   v8::HandleScope handle_scope(env1->GetIsolate());
8755   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8756
8757   Local<v8::Object> global1 = env1->Global();
8758
8759   Local<Value> foo = v8_str("foo");
8760
8761   // Set to the same domain.
8762   env1->SetSecurityToken(foo);
8763   env2->SetSecurityToken(foo);
8764
8765   // Enter env2
8766   env2->Enter();
8767
8768   // Create a function in env2 and add a reference to it in env1.
8769   Local<v8::Object> global2 = env2->Global();
8770   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8771   CompileRun("function getProp() {return prop;}");
8772
8773   env1->Global()->Set(v8_str("getProp"),
8774                       global2->Get(v8_str("getProp")));
8775
8776   // Detach env2's global, and reuse the global object of env2
8777   env2->Exit();
8778   env2->DetachGlobal();
8779
8780   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8781                                           0,
8782                                           v8::Handle<v8::ObjectTemplate>(),
8783                                           global2);
8784   env3->SetSecurityToken(v8_str("bar"));
8785   env3->Enter();
8786
8787   Local<v8::Object> global3 = env3->Global();
8788   CHECK_EQ(global2, global3);
8789   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8790   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8791   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8792   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8793   env3->Exit();
8794
8795   // Call getProp in env1, and it should return the value 1
8796   {
8797     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8798     CHECK(get_prop->IsFunction());
8799     v8::TryCatch try_catch;
8800     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8801     CHECK(!try_catch.HasCaught());
8802     CHECK_EQ(1, r->Int32Value());
8803   }
8804
8805   // Check that env3 is not accessible from env1
8806   {
8807     Local<Value> r = global3->Get(v8_str("prop2"));
8808     CHECK(r->IsUndefined());
8809   }
8810 }
8811
8812
8813 TEST(DetachGlobal) {
8814   LocalContext env1;
8815   v8::HandleScope scope(env1->GetIsolate());
8816
8817   // Create second environment.
8818   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8819
8820   Local<Value> foo = v8_str("foo");
8821
8822   // Set same security token for env1 and env2.
8823   env1->SetSecurityToken(foo);
8824   env2->SetSecurityToken(foo);
8825
8826   // Create a property on the global object in env2.
8827   {
8828     v8::Context::Scope scope(env2);
8829     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8830   }
8831
8832   // Create a reference to env2 global from env1 global.
8833   env1->Global()->Set(v8_str("other"), env2->Global());
8834
8835   // Check that we have access to other.p in env2 from env1.
8836   Local<Value> result = CompileRun("other.p");
8837   CHECK(result->IsInt32());
8838   CHECK_EQ(42, result->Int32Value());
8839
8840   // Hold on to global from env2 and detach global from env2.
8841   Local<v8::Object> global2 = env2->Global();
8842   env2->DetachGlobal();
8843
8844   // Check that the global has been detached. No other.p property can
8845   // be found.
8846   result = CompileRun("other.p");
8847   CHECK(result->IsUndefined());
8848
8849   // Reuse global2 for env3.
8850   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8851                                           0,
8852                                           v8::Handle<v8::ObjectTemplate>(),
8853                                           global2);
8854   CHECK_EQ(global2, env3->Global());
8855
8856   // Start by using the same security token for env3 as for env1 and env2.
8857   env3->SetSecurityToken(foo);
8858
8859   // Create a property on the global object in env3.
8860   {
8861     v8::Context::Scope scope(env3);
8862     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8863   }
8864
8865   // Check that other.p is now the property in env3 and that we have access.
8866   result = CompileRun("other.p");
8867   CHECK(result->IsInt32());
8868   CHECK_EQ(24, result->Int32Value());
8869
8870   // Change security token for env3 to something different from env1 and env2.
8871   env3->SetSecurityToken(v8_str("bar"));
8872
8873   // Check that we do not have access to other.p in env1. |other| is now
8874   // the global object for env3 which has a different security token,
8875   // so access should be blocked.
8876   result = CompileRun("other.p");
8877   CHECK(result->IsUndefined());
8878 }
8879
8880
8881 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8882   info.GetReturnValue().Set(
8883       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8884 }
8885
8886
8887 TEST(DetachedAccesses) {
8888   LocalContext env1;
8889   v8::HandleScope scope(env1->GetIsolate());
8890
8891   // Create second environment.
8892   Local<ObjectTemplate> inner_global_template =
8893       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8894   inner_global_template ->SetAccessorProperty(
8895       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8896   v8::Local<Context> env2 =
8897       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8898
8899   Local<Value> foo = v8_str("foo");
8900
8901   // Set same security token for env1 and env2.
8902   env1->SetSecurityToken(foo);
8903   env2->SetSecurityToken(foo);
8904
8905   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8906
8907   {
8908     v8::Context::Scope scope(env2);
8909     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8910     CompileRun(
8911         "function bound_x() { return x; }"
8912         "function get_x()   { return this.x; }"
8913         "function get_x_w() { return (function() {return this.x;})(); }");
8914     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8915     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8916     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8917     env1->Global()->Set(
8918         v8_str("this_x"),
8919         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8920   }
8921
8922   Local<Object> env2_global = env2->Global();
8923   env2_global->TurnOnAccessCheck();
8924   env2->DetachGlobal();
8925
8926   Local<Value> result;
8927   result = CompileRun("bound_x()");
8928   CHECK_EQ(v8_str("env2_x"), result);
8929   result = CompileRun("get_x()");
8930   CHECK(result->IsUndefined());
8931   result = CompileRun("get_x_w()");
8932   CHECK(result->IsUndefined());
8933   result = CompileRun("this_x()");
8934   CHECK_EQ(v8_str("env2_x"), result);
8935
8936   // Reattach env2's proxy
8937   env2 = Context::New(env1->GetIsolate(),
8938                       0,
8939                       v8::Handle<v8::ObjectTemplate>(),
8940                       env2_global);
8941   env2->SetSecurityToken(foo);
8942   {
8943     v8::Context::Scope scope(env2);
8944     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8945     env2->Global()->Set(v8_str("env1"), env1->Global());
8946     result = CompileRun(
8947         "results = [];"
8948         "for (var i = 0; i < 4; i++ ) {"
8949         "  results.push(env1.bound_x());"
8950         "  results.push(env1.get_x());"
8951         "  results.push(env1.get_x_w());"
8952         "  results.push(env1.this_x());"
8953         "}"
8954         "results");
8955     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8956     CHECK_EQ(16, results->Length());
8957     for (int i = 0; i < 16; i += 4) {
8958       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8959       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8960       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8961       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8962     }
8963   }
8964
8965   result = CompileRun(
8966       "results = [];"
8967       "for (var i = 0; i < 4; i++ ) {"
8968       "  results.push(bound_x());"
8969       "  results.push(get_x());"
8970       "  results.push(get_x_w());"
8971       "  results.push(this_x());"
8972       "}"
8973       "results");
8974   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8975   CHECK_EQ(16, results->Length());
8976   for (int i = 0; i < 16; i += 4) {
8977     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8978     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8979     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8980     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8981   }
8982
8983   result = CompileRun(
8984       "results = [];"
8985       "for (var i = 0; i < 4; i++ ) {"
8986       "  results.push(this.bound_x());"
8987       "  results.push(this.get_x());"
8988       "  results.push(this.get_x_w());"
8989       "  results.push(this.this_x());"
8990       "}"
8991       "results");
8992   results = Local<v8::Array>::Cast(result);
8993   CHECK_EQ(16, results->Length());
8994   for (int i = 0; i < 16; i += 4) {
8995     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8996     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8997     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8998     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8999   }
9000 }
9001
9002
9003 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9004 static bool NamedAccessBlocker(Local<v8::Object> global,
9005                                Local<Value> name,
9006                                v8::AccessType type,
9007                                Local<Value> data) {
9008   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9009       allowed_access_type[type];
9010 }
9011
9012
9013 static bool IndexedAccessBlocker(Local<v8::Object> global,
9014                                  uint32_t key,
9015                                  v8::AccessType type,
9016                                  Local<Value> data) {
9017   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9018       allowed_access_type[type];
9019 }
9020
9021
9022 static int g_echo_value_1 = -1;
9023 static int g_echo_value_2 = -1;
9024
9025
9026 static void EchoGetter(
9027     Local<String> name,
9028     const v8::PropertyCallbackInfo<v8::Value>& info) {
9029   info.GetReturnValue().Set(v8_num(g_echo_value_1));
9030 }
9031
9032
9033 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9034   info.GetReturnValue().Set(v8_num(g_echo_value_2));
9035 }
9036
9037
9038 static void EchoSetter(Local<String> name,
9039                        Local<Value> value,
9040                        const v8::PropertyCallbackInfo<void>&) {
9041   if (value->IsNumber())
9042     g_echo_value_1 = value->Int32Value();
9043 }
9044
9045
9046 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9047   v8::Handle<v8::Value> value = info[0];
9048   if (value->IsNumber())
9049     g_echo_value_2 = value->Int32Value();
9050 }
9051
9052
9053 static void UnreachableGetter(
9054     Local<String> name,
9055     const v8::PropertyCallbackInfo<v8::Value>& info) {
9056   CHECK(false);  // This function should not be called..
9057 }
9058
9059
9060 static void UnreachableSetter(Local<String>,
9061                               Local<Value>,
9062                               const v8::PropertyCallbackInfo<void>&) {
9063   CHECK(false);  // This function should nto be called.
9064 }
9065
9066
9067 static void UnreachableFunction(
9068     const v8::FunctionCallbackInfo<v8::Value>& info) {
9069   CHECK(false);  // This function should not be called..
9070 }
9071
9072
9073 TEST(AccessControl) {
9074   v8::Isolate* isolate = CcTest::isolate();
9075   v8::HandleScope handle_scope(isolate);
9076   v8::Handle<v8::ObjectTemplate> global_template =
9077       v8::ObjectTemplate::New(isolate);
9078
9079   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9080                                            IndexedAccessBlocker);
9081
9082   // Add an accessor accessible by cross-domain JS code.
9083   global_template->SetAccessor(
9084       v8_str("accessible_prop"),
9085       EchoGetter, EchoSetter,
9086       v8::Handle<Value>(),
9087       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9088
9089
9090   global_template->SetAccessorProperty(
9091       v8_str("accessible_js_prop"),
9092       v8::FunctionTemplate::New(isolate, EchoGetter),
9093       v8::FunctionTemplate::New(isolate, EchoSetter),
9094       v8::None,
9095       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9096
9097   // Add an accessor that is not accessible by cross-domain JS code.
9098   global_template->SetAccessor(v8_str("blocked_prop"),
9099                                UnreachableGetter, UnreachableSetter,
9100                                v8::Handle<Value>(),
9101                                v8::DEFAULT);
9102
9103   global_template->SetAccessorProperty(
9104       v8_str("blocked_js_prop"),
9105       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9106       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9107       v8::None,
9108       v8::DEFAULT);
9109
9110   // Create an environment
9111   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9112   context0->Enter();
9113
9114   v8::Handle<v8::Object> global0 = context0->Global();
9115
9116   // Define a property with JS getter and setter.
9117   CompileRun(
9118       "function getter() { return 'getter'; };\n"
9119       "function setter() { return 'setter'; }\n"
9120       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9121
9122   Local<Value> getter = global0->Get(v8_str("getter"));
9123   Local<Value> setter = global0->Get(v8_str("setter"));
9124
9125   // And define normal element.
9126   global0->Set(239, v8_str("239"));
9127
9128   // Define an element with JS getter and setter.
9129   CompileRun(
9130       "function el_getter() { return 'el_getter'; };\n"
9131       "function el_setter() { return 'el_setter'; };\n"
9132       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9133
9134   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9135   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9136
9137   v8::HandleScope scope1(isolate);
9138
9139   v8::Local<Context> context1 = Context::New(isolate);
9140   context1->Enter();
9141
9142   v8::Handle<v8::Object> global1 = context1->Global();
9143   global1->Set(v8_str("other"), global0);
9144
9145   // Access blocked property.
9146   CompileRun("other.blocked_prop = 1");
9147
9148   ExpectUndefined("other.blocked_prop");
9149   ExpectUndefined(
9150       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9151   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9152
9153   // Enable ACCESS_HAS
9154   allowed_access_type[v8::ACCESS_HAS] = true;
9155   ExpectUndefined("other.blocked_prop");
9156   // ... and now we can get the descriptor...
9157   ExpectUndefined(
9158       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9159   // ... and enumerate the property.
9160   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9161   allowed_access_type[v8::ACCESS_HAS] = false;
9162
9163   // Access blocked element.
9164   CompileRun("other[239] = 1");
9165
9166   ExpectUndefined("other[239]");
9167   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9168   ExpectFalse("propertyIsEnumerable.call(other, '239')");
9169
9170   // Enable ACCESS_HAS
9171   allowed_access_type[v8::ACCESS_HAS] = true;
9172   ExpectUndefined("other[239]");
9173   // ... and now we can get the descriptor...
9174   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9175   // ... and enumerate the property.
9176   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9177   allowed_access_type[v8::ACCESS_HAS] = false;
9178
9179   // Access a property with JS accessor.
9180   CompileRun("other.js_accessor_p = 2");
9181
9182   ExpectUndefined("other.js_accessor_p");
9183   ExpectUndefined(
9184       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9185
9186   // Enable ACCESS_HAS.
9187   allowed_access_type[v8::ACCESS_HAS] = true;
9188   ExpectUndefined("other.js_accessor_p");
9189   ExpectUndefined(
9190       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9191   ExpectUndefined(
9192       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9193   ExpectUndefined(
9194       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9195   allowed_access_type[v8::ACCESS_HAS] = false;
9196
9197   // Enable both ACCESS_HAS and ACCESS_GET.
9198   allowed_access_type[v8::ACCESS_HAS] = true;
9199   allowed_access_type[v8::ACCESS_GET] = true;
9200
9201   ExpectString("other.js_accessor_p", "getter");
9202   ExpectObject(
9203       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9204   ExpectUndefined(
9205       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9206   ExpectUndefined(
9207       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9208
9209   allowed_access_type[v8::ACCESS_GET] = false;
9210   allowed_access_type[v8::ACCESS_HAS] = false;
9211
9212   // Enable both ACCESS_HAS and ACCESS_SET.
9213   allowed_access_type[v8::ACCESS_HAS] = true;
9214   allowed_access_type[v8::ACCESS_SET] = true;
9215
9216   ExpectUndefined("other.js_accessor_p");
9217   ExpectUndefined(
9218       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9219   ExpectObject(
9220       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9221   ExpectUndefined(
9222       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9223
9224   allowed_access_type[v8::ACCESS_SET] = false;
9225   allowed_access_type[v8::ACCESS_HAS] = false;
9226
9227   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9228   allowed_access_type[v8::ACCESS_HAS] = true;
9229   allowed_access_type[v8::ACCESS_GET] = true;
9230   allowed_access_type[v8::ACCESS_SET] = true;
9231
9232   ExpectString("other.js_accessor_p", "getter");
9233   ExpectObject(
9234       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9235   ExpectObject(
9236       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9237   ExpectUndefined(
9238       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9239
9240   allowed_access_type[v8::ACCESS_SET] = false;
9241   allowed_access_type[v8::ACCESS_GET] = false;
9242   allowed_access_type[v8::ACCESS_HAS] = false;
9243
9244   // Access an element with JS accessor.
9245   CompileRun("other[42] = 2");
9246
9247   ExpectUndefined("other[42]");
9248   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9249
9250   // Enable ACCESS_HAS.
9251   allowed_access_type[v8::ACCESS_HAS] = true;
9252   ExpectUndefined("other[42]");
9253   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9254   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9255   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9256   allowed_access_type[v8::ACCESS_HAS] = false;
9257
9258   // Enable both ACCESS_HAS and ACCESS_GET.
9259   allowed_access_type[v8::ACCESS_HAS] = true;
9260   allowed_access_type[v8::ACCESS_GET] = true;
9261
9262   ExpectString("other[42]", "el_getter");
9263   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9264   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9265   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9266
9267   allowed_access_type[v8::ACCESS_GET] = false;
9268   allowed_access_type[v8::ACCESS_HAS] = false;
9269
9270   // Enable both ACCESS_HAS and ACCESS_SET.
9271   allowed_access_type[v8::ACCESS_HAS] = true;
9272   allowed_access_type[v8::ACCESS_SET] = true;
9273
9274   ExpectUndefined("other[42]");
9275   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9276   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9277   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9278
9279   allowed_access_type[v8::ACCESS_SET] = false;
9280   allowed_access_type[v8::ACCESS_HAS] = false;
9281
9282   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9283   allowed_access_type[v8::ACCESS_HAS] = true;
9284   allowed_access_type[v8::ACCESS_GET] = true;
9285   allowed_access_type[v8::ACCESS_SET] = true;
9286
9287   ExpectString("other[42]", "el_getter");
9288   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9289   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9290   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9291
9292   allowed_access_type[v8::ACCESS_SET] = false;
9293   allowed_access_type[v8::ACCESS_GET] = false;
9294   allowed_access_type[v8::ACCESS_HAS] = false;
9295
9296   v8::Handle<Value> value;
9297
9298   // Access accessible property
9299   value = CompileRun("other.accessible_prop = 3");
9300   CHECK(value->IsNumber());
9301   CHECK_EQ(3, value->Int32Value());
9302   CHECK_EQ(3, g_echo_value_1);
9303
9304   // Access accessible js property
9305   value = CompileRun("other.accessible_js_prop = 3");
9306   CHECK(value->IsNumber());
9307   CHECK_EQ(3, value->Int32Value());
9308   CHECK_EQ(3, g_echo_value_2);
9309
9310   value = CompileRun("other.accessible_prop");
9311   CHECK(value->IsNumber());
9312   CHECK_EQ(3, value->Int32Value());
9313
9314   value = CompileRun("other.accessible_js_prop");
9315   CHECK(value->IsNumber());
9316   CHECK_EQ(3, value->Int32Value());
9317
9318   value = CompileRun(
9319       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9320   CHECK(value->IsNumber());
9321   CHECK_EQ(3, value->Int32Value());
9322
9323   value = CompileRun(
9324       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9325   CHECK(value->IsNumber());
9326   CHECK_EQ(3, value->Int32Value());
9327
9328   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9329   CHECK(value->IsTrue());
9330
9331   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9332   CHECK(value->IsTrue());
9333
9334   // Enumeration doesn't enumerate accessors from inaccessible objects in
9335   // the prototype chain even if the accessors are in themselves accessible.
9336   value =
9337       CompileRun("(function(){var obj = {'__proto__':other};"
9338                  "for (var p in obj)"
9339                  "   if (p == 'accessible_prop' ||"
9340                  "       p == 'accessible_js_prop' ||"
9341                  "       p == 'blocked_js_prop' ||"
9342                  "       p == 'blocked_js_prop') {"
9343                  "     return false;"
9344                  "   }"
9345                  "return true;})()");
9346   CHECK(value->IsTrue());
9347
9348   context1->Exit();
9349   context0->Exit();
9350 }
9351
9352
9353 TEST(AccessControlES5) {
9354   v8::Isolate* isolate = CcTest::isolate();
9355   v8::HandleScope handle_scope(isolate);
9356   v8::Handle<v8::ObjectTemplate> global_template =
9357       v8::ObjectTemplate::New(isolate);
9358
9359   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9360                                            IndexedAccessBlocker);
9361
9362   // Add accessible accessor.
9363   global_template->SetAccessor(
9364       v8_str("accessible_prop"),
9365       EchoGetter, EchoSetter,
9366       v8::Handle<Value>(),
9367       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9368
9369
9370   // Add an accessor that is not accessible by cross-domain JS code.
9371   global_template->SetAccessor(v8_str("blocked_prop"),
9372                                UnreachableGetter, UnreachableSetter,
9373                                v8::Handle<Value>(),
9374                                v8::DEFAULT);
9375
9376   // Create an environment
9377   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9378   context0->Enter();
9379
9380   v8::Handle<v8::Object> global0 = context0->Global();
9381
9382   v8::Local<Context> context1 = Context::New(isolate);
9383   context1->Enter();
9384   v8::Handle<v8::Object> global1 = context1->Global();
9385   global1->Set(v8_str("other"), global0);
9386
9387   // Regression test for issue 1154.
9388   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9389
9390   ExpectUndefined("other.blocked_prop");
9391
9392   // Regression test for issue 1027.
9393   CompileRun("Object.defineProperty(\n"
9394              "  other, 'blocked_prop', {configurable: false})");
9395   ExpectUndefined("other.blocked_prop");
9396   ExpectUndefined(
9397       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9398
9399   // Regression test for issue 1171.
9400   ExpectTrue("Object.isExtensible(other)");
9401   CompileRun("Object.preventExtensions(other)");
9402   ExpectTrue("Object.isExtensible(other)");
9403
9404   // Object.seal and Object.freeze.
9405   CompileRun("Object.freeze(other)");
9406   ExpectTrue("Object.isExtensible(other)");
9407
9408   CompileRun("Object.seal(other)");
9409   ExpectTrue("Object.isExtensible(other)");
9410
9411   // Regression test for issue 1250.
9412   // Make sure that we can set the accessible accessors value using normal
9413   // assignment.
9414   CompileRun("other.accessible_prop = 42");
9415   CHECK_EQ(42, g_echo_value_1);
9416
9417   v8::Handle<Value> value;
9418   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9419   value = CompileRun("other.accessible_prop == 42");
9420   CHECK(value->IsTrue());
9421 }
9422
9423
9424 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9425                                             Local<Value> name,
9426                                             v8::AccessType type,
9427                                             Local<Value> data) {
9428   return false;
9429 }
9430
9431
9432 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9433                                               uint32_t key,
9434                                               v8::AccessType type,
9435                                               Local<Value> data) {
9436   return false;
9437 }
9438
9439
9440 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9441   v8::Isolate* isolate = CcTest::isolate();
9442   v8::HandleScope handle_scope(isolate);
9443   v8::Handle<v8::ObjectTemplate> obj_template =
9444       v8::ObjectTemplate::New(isolate);
9445
9446   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9447   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9448                                         GetOwnPropertyNamesIndexedBlocker);
9449
9450   // Create an environment
9451   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9452   context0->Enter();
9453
9454   v8::Handle<v8::Object> global0 = context0->Global();
9455
9456   v8::HandleScope scope1(CcTest::isolate());
9457
9458   v8::Local<Context> context1 = Context::New(isolate);
9459   context1->Enter();
9460
9461   v8::Handle<v8::Object> global1 = context1->Global();
9462   global1->Set(v8_str("other"), global0);
9463   global1->Set(v8_str("object"), obj_template->NewInstance());
9464
9465   v8::Handle<Value> value;
9466
9467   // Attempt to get the property names of the other global object and
9468   // of an object that requires access checks.  Accessing the other
9469   // global object should be blocked by access checks on the global
9470   // proxy object.  Accessing the object that requires access checks
9471   // is blocked by the access checks on the object itself.
9472   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9473   CHECK(value->IsTrue());
9474
9475   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9476   CHECK(value->IsTrue());
9477
9478   context1->Exit();
9479   context0->Exit();
9480 }
9481
9482
9483 static void IndexedPropertyEnumerator(
9484     const v8::PropertyCallbackInfo<v8::Array>& info) {
9485   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9486   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9487   result->Set(1, v8::Object::New(info.GetIsolate()));
9488   info.GetReturnValue().Set(result);
9489 }
9490
9491
9492 static void NamedPropertyEnumerator(
9493     const v8::PropertyCallbackInfo<v8::Array>& info) {
9494   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9495   result->Set(0, v8_str("x"));
9496   result->Set(1, v8::Object::New(info.GetIsolate()));
9497   info.GetReturnValue().Set(result);
9498 }
9499
9500
9501 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9502   v8::Isolate* isolate = CcTest::isolate();
9503   v8::HandleScope handle_scope(isolate);
9504   v8::Handle<v8::ObjectTemplate> obj_template =
9505       v8::ObjectTemplate::New(isolate);
9506
9507   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9508   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9509   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9510                                           IndexedPropertyEnumerator);
9511   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9512                                         NamedPropertyEnumerator);
9513
9514   LocalContext context;
9515   v8::Handle<v8::Object> global = context->Global();
9516   global->Set(v8_str("object"), obj_template->NewInstance());
9517
9518   v8::Handle<v8::Value> result =
9519       CompileRun("Object.getOwnPropertyNames(object)");
9520   CHECK(result->IsArray());
9521   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9522   CHECK_EQ(3, result_array->Length());
9523   CHECK(result_array->Get(0)->IsString());
9524   CHECK(result_array->Get(1)->IsString());
9525   CHECK(result_array->Get(2)->IsString());
9526   CHECK_EQ(v8_str("7"), result_array->Get(0));
9527   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9528   CHECK_EQ(v8_str("x"), result_array->Get(2));
9529 }
9530
9531
9532 static void ConstTenGetter(Local<String> name,
9533                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9534   info.GetReturnValue().Set(v8_num(10));
9535 }
9536
9537
9538 THREADED_TEST(CrossDomainAccessors) {
9539   v8::Isolate* isolate = CcTest::isolate();
9540   v8::HandleScope handle_scope(isolate);
9541
9542   v8::Handle<v8::FunctionTemplate> func_template =
9543       v8::FunctionTemplate::New(isolate);
9544
9545   v8::Handle<v8::ObjectTemplate> global_template =
9546       func_template->InstanceTemplate();
9547
9548   v8::Handle<v8::ObjectTemplate> proto_template =
9549       func_template->PrototypeTemplate();
9550
9551   // Add an accessor to proto that's accessible by cross-domain JS code.
9552   proto_template->SetAccessor(v8_str("accessible"),
9553                               ConstTenGetter, 0,
9554                               v8::Handle<Value>(),
9555                               v8::ALL_CAN_READ);
9556
9557   // Add an accessor that is not accessible by cross-domain JS code.
9558   global_template->SetAccessor(v8_str("unreachable"),
9559                                UnreachableGetter, 0,
9560                                v8::Handle<Value>(),
9561                                v8::DEFAULT);
9562
9563   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9564   context0->Enter();
9565
9566   Local<v8::Object> global = context0->Global();
9567   // Add a normal property that shadows 'accessible'
9568   global->Set(v8_str("accessible"), v8_num(11));
9569
9570   // Enter a new context.
9571   v8::HandleScope scope1(CcTest::isolate());
9572   v8::Local<Context> context1 = Context::New(isolate);
9573   context1->Enter();
9574
9575   v8::Handle<v8::Object> global1 = context1->Global();
9576   global1->Set(v8_str("other"), global);
9577
9578   // Should return 10, instead of 11
9579   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9580   CHECK(value->IsNumber());
9581   CHECK_EQ(10, value->Int32Value());
9582
9583   value = v8_compile("other.unreachable")->Run();
9584   CHECK(value->IsUndefined());
9585
9586   context1->Exit();
9587   context0->Exit();
9588 }
9589
9590
9591 static int named_access_count = 0;
9592 static int indexed_access_count = 0;
9593
9594 static bool NamedAccessCounter(Local<v8::Object> global,
9595                                Local<Value> name,
9596                                v8::AccessType type,
9597                                Local<Value> data) {
9598   named_access_count++;
9599   return true;
9600 }
9601
9602
9603 static bool IndexedAccessCounter(Local<v8::Object> global,
9604                                  uint32_t key,
9605                                  v8::AccessType type,
9606                                  Local<Value> data) {
9607   indexed_access_count++;
9608   return true;
9609 }
9610
9611
9612 // This one is too easily disturbed by other tests.
9613 TEST(AccessControlIC) {
9614   named_access_count = 0;
9615   indexed_access_count = 0;
9616
9617   v8::Isolate* isolate = CcTest::isolate();
9618   v8::HandleScope handle_scope(isolate);
9619
9620   // Create an environment.
9621   v8::Local<Context> context0 = Context::New(isolate);
9622   context0->Enter();
9623
9624   // Create an object that requires access-check functions to be
9625   // called for cross-domain access.
9626   v8::Handle<v8::ObjectTemplate> object_template =
9627       v8::ObjectTemplate::New(isolate);
9628   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9629                                            IndexedAccessCounter);
9630   Local<v8::Object> object = object_template->NewInstance();
9631
9632   v8::HandleScope scope1(isolate);
9633
9634   // Create another environment.
9635   v8::Local<Context> context1 = Context::New(isolate);
9636   context1->Enter();
9637
9638   // Make easy access to the object from the other environment.
9639   v8::Handle<v8::Object> global1 = context1->Global();
9640   global1->Set(v8_str("obj"), object);
9641
9642   v8::Handle<Value> value;
9643
9644   // Check that the named access-control function is called every time.
9645   CompileRun("function testProp(obj) {"
9646              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9647              "  for (var j = 0; j < 10; j++) obj.prop;"
9648              "  return obj.prop"
9649              "}");
9650   value = CompileRun("testProp(obj)");
9651   CHECK(value->IsNumber());
9652   CHECK_EQ(1, value->Int32Value());
9653   CHECK_EQ(21, named_access_count);
9654
9655   // Check that the named access-control function is called every time.
9656   CompileRun("var p = 'prop';"
9657              "function testKeyed(obj) {"
9658              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9659              "  for (var j = 0; j < 10; j++) obj[p];"
9660              "  return obj[p];"
9661              "}");
9662   // Use obj which requires access checks.  No inline caching is used
9663   // in that case.
9664   value = CompileRun("testKeyed(obj)");
9665   CHECK(value->IsNumber());
9666   CHECK_EQ(1, value->Int32Value());
9667   CHECK_EQ(42, named_access_count);
9668   // Force the inline caches into generic state and try again.
9669   CompileRun("testKeyed({ a: 0 })");
9670   CompileRun("testKeyed({ b: 0 })");
9671   value = CompileRun("testKeyed(obj)");
9672   CHECK(value->IsNumber());
9673   CHECK_EQ(1, value->Int32Value());
9674   CHECK_EQ(63, named_access_count);
9675
9676   // Check that the indexed access-control function is called every time.
9677   CompileRun("function testIndexed(obj) {"
9678              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9679              "  for (var j = 0; j < 10; j++) obj[0];"
9680              "  return obj[0]"
9681              "}");
9682   value = CompileRun("testIndexed(obj)");
9683   CHECK(value->IsNumber());
9684   CHECK_EQ(1, value->Int32Value());
9685   CHECK_EQ(21, indexed_access_count);
9686   // Force the inline caches into generic state.
9687   CompileRun("testIndexed(new Array(1))");
9688   // Test that the indexed access check is called.
9689   value = CompileRun("testIndexed(obj)");
9690   CHECK(value->IsNumber());
9691   CHECK_EQ(1, value->Int32Value());
9692   CHECK_EQ(42, indexed_access_count);
9693
9694   // Check that the named access check is called when invoking
9695   // functions on an object that requires access checks.
9696   CompileRun("obj.f = function() {}");
9697   CompileRun("function testCallNormal(obj) {"
9698              "  for (var i = 0; i < 10; i++) obj.f();"
9699              "}");
9700   CompileRun("testCallNormal(obj)");
9701   CHECK_EQ(74, named_access_count);
9702
9703   // Force obj into slow case.
9704   value = CompileRun("delete obj.prop");
9705   CHECK(value->BooleanValue());
9706   // Force inline caches into dictionary probing mode.
9707   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9708   // Test that the named access check is called.
9709   value = CompileRun("testProp(obj);");
9710   CHECK(value->IsNumber());
9711   CHECK_EQ(1, value->Int32Value());
9712   CHECK_EQ(96, named_access_count);
9713
9714   // Force the call inline cache into dictionary probing mode.
9715   CompileRun("o.f = function() {}; testCallNormal(o)");
9716   // Test that the named access check is still called for each
9717   // invocation of the function.
9718   value = CompileRun("testCallNormal(obj)");
9719   CHECK_EQ(106, named_access_count);
9720
9721   context1->Exit();
9722   context0->Exit();
9723 }
9724
9725
9726 static bool NamedAccessFlatten(Local<v8::Object> global,
9727                                Local<Value> name,
9728                                v8::AccessType type,
9729                                Local<Value> data) {
9730   char buf[100];
9731   int len;
9732
9733   CHECK(name->IsString());
9734
9735   memset(buf, 0x1, sizeof(buf));
9736   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9737   CHECK_EQ(4, len);
9738
9739   uint16_t buf2[100];
9740
9741   memset(buf, 0x1, sizeof(buf));
9742   len = name.As<String>()->Write(buf2);
9743   CHECK_EQ(4, len);
9744
9745   return true;
9746 }
9747
9748
9749 static bool IndexedAccessFlatten(Local<v8::Object> global,
9750                                  uint32_t key,
9751                                  v8::AccessType type,
9752                                  Local<Value> data) {
9753   return true;
9754 }
9755
9756
9757 // Regression test.  In access checks, operations that may cause
9758 // garbage collection are not allowed.  It used to be the case that
9759 // using the Write operation on a string could cause a garbage
9760 // collection due to flattening of the string.  This is no longer the
9761 // case.
9762 THREADED_TEST(AccessControlFlatten) {
9763   named_access_count = 0;
9764   indexed_access_count = 0;
9765
9766   v8::Isolate* isolate = CcTest::isolate();
9767   v8::HandleScope handle_scope(isolate);
9768
9769   // Create an environment.
9770   v8::Local<Context> context0 = Context::New(isolate);
9771   context0->Enter();
9772
9773   // Create an object that requires access-check functions to be
9774   // called for cross-domain access.
9775   v8::Handle<v8::ObjectTemplate> object_template =
9776       v8::ObjectTemplate::New(isolate);
9777   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9778                                            IndexedAccessFlatten);
9779   Local<v8::Object> object = object_template->NewInstance();
9780
9781   v8::HandleScope scope1(isolate);
9782
9783   // Create another environment.
9784   v8::Local<Context> context1 = Context::New(isolate);
9785   context1->Enter();
9786
9787   // Make easy access to the object from the other environment.
9788   v8::Handle<v8::Object> global1 = context1->Global();
9789   global1->Set(v8_str("obj"), object);
9790
9791   v8::Handle<Value> value;
9792
9793   value = v8_compile("var p = 'as' + 'df';")->Run();
9794   value = v8_compile("obj[p];")->Run();
9795
9796   context1->Exit();
9797   context0->Exit();
9798 }
9799
9800
9801 static void AccessControlNamedGetter(
9802     Local<String>,
9803     const v8::PropertyCallbackInfo<v8::Value>& info) {
9804   info.GetReturnValue().Set(42);
9805 }
9806
9807
9808 static void AccessControlNamedSetter(
9809     Local<String>,
9810     Local<Value> value,
9811     const v8::PropertyCallbackInfo<v8::Value>& info) {
9812   info.GetReturnValue().Set(value);
9813 }
9814
9815
9816 static void AccessControlIndexedGetter(
9817       uint32_t index,
9818       const v8::PropertyCallbackInfo<v8::Value>& info) {
9819   info.GetReturnValue().Set(v8_num(42));
9820 }
9821
9822
9823 static void AccessControlIndexedSetter(
9824     uint32_t,
9825     Local<Value> value,
9826     const v8::PropertyCallbackInfo<v8::Value>& info) {
9827   info.GetReturnValue().Set(value);
9828 }
9829
9830
9831 THREADED_TEST(AccessControlInterceptorIC) {
9832   named_access_count = 0;
9833   indexed_access_count = 0;
9834
9835   v8::Isolate* isolate = CcTest::isolate();
9836   v8::HandleScope handle_scope(isolate);
9837
9838   // Create an environment.
9839   v8::Local<Context> context0 = Context::New(isolate);
9840   context0->Enter();
9841
9842   // Create an object that requires access-check functions to be
9843   // called for cross-domain access.  The object also has interceptors
9844   // interceptor.
9845   v8::Handle<v8::ObjectTemplate> object_template =
9846       v8::ObjectTemplate::New(isolate);
9847   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9848                                            IndexedAccessCounter);
9849   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9850                                            AccessControlNamedSetter);
9851   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9852                                              AccessControlIndexedSetter);
9853   Local<v8::Object> object = object_template->NewInstance();
9854
9855   v8::HandleScope scope1(isolate);
9856
9857   // Create another environment.
9858   v8::Local<Context> context1 = Context::New(isolate);
9859   context1->Enter();
9860
9861   // Make easy access to the object from the other environment.
9862   v8::Handle<v8::Object> global1 = context1->Global();
9863   global1->Set(v8_str("obj"), object);
9864
9865   v8::Handle<Value> value;
9866
9867   // Check that the named access-control function is called every time
9868   // eventhough there is an interceptor on the object.
9869   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9870   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9871                      "obj.x")->Run();
9872   CHECK(value->IsNumber());
9873   CHECK_EQ(42, value->Int32Value());
9874   CHECK_EQ(21, named_access_count);
9875
9876   value = v8_compile("var p = 'x';")->Run();
9877   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9878   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9879                      "obj[p]")->Run();
9880   CHECK(value->IsNumber());
9881   CHECK_EQ(42, value->Int32Value());
9882   CHECK_EQ(42, named_access_count);
9883
9884   // Check that the indexed access-control function is called every
9885   // time eventhough there is an interceptor on the object.
9886   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9887   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9888                      "obj[0]")->Run();
9889   CHECK(value->IsNumber());
9890   CHECK_EQ(42, value->Int32Value());
9891   CHECK_EQ(21, indexed_access_count);
9892
9893   context1->Exit();
9894   context0->Exit();
9895 }
9896
9897
9898 THREADED_TEST(Version) {
9899   v8::V8::GetVersion();
9900 }
9901
9902
9903 static void InstanceFunctionCallback(
9904     const v8::FunctionCallbackInfo<v8::Value>& args) {
9905   ApiTestFuzzer::Fuzz();
9906   args.GetReturnValue().Set(v8_num(12));
9907 }
9908
9909
9910 THREADED_TEST(InstanceProperties) {
9911   LocalContext context;
9912   v8::Isolate* isolate = context->GetIsolate();
9913   v8::HandleScope handle_scope(isolate);
9914
9915   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9916   Local<ObjectTemplate> instance = t->InstanceTemplate();
9917
9918   instance->Set(v8_str("x"), v8_num(42));
9919   instance->Set(v8_str("f"),
9920                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9921
9922   Local<Value> o = t->GetFunction()->NewInstance();
9923
9924   context->Global()->Set(v8_str("i"), o);
9925   Local<Value> value = CompileRun("i.x");
9926   CHECK_EQ(42, value->Int32Value());
9927
9928   value = CompileRun("i.f()");
9929   CHECK_EQ(12, value->Int32Value());
9930 }
9931
9932
9933 static void GlobalObjectInstancePropertiesGet(
9934     Local<String> key,
9935     const v8::PropertyCallbackInfo<v8::Value>&) {
9936   ApiTestFuzzer::Fuzz();
9937 }
9938
9939
9940 THREADED_TEST(GlobalObjectInstanceProperties) {
9941   v8::Isolate* isolate = CcTest::isolate();
9942   v8::HandleScope handle_scope(isolate);
9943
9944   Local<Value> global_object;
9945
9946   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9947   t->InstanceTemplate()->SetNamedPropertyHandler(
9948       GlobalObjectInstancePropertiesGet);
9949   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9950   instance_template->Set(v8_str("x"), v8_num(42));
9951   instance_template->Set(v8_str("f"),
9952                          v8::FunctionTemplate::New(isolate,
9953                                                    InstanceFunctionCallback));
9954
9955   // The script to check how Crankshaft compiles missing global function
9956   // invocations.  function g is not defined and should throw on call.
9957   const char* script =
9958       "function wrapper(call) {"
9959       "  var x = 0, y = 1;"
9960       "  for (var i = 0; i < 1000; i++) {"
9961       "    x += i * 100;"
9962       "    y += i * 100;"
9963       "  }"
9964       "  if (call) g();"
9965       "}"
9966       "for (var i = 0; i < 17; i++) wrapper(false);"
9967       "var thrown = 0;"
9968       "try { wrapper(true); } catch (e) { thrown = 1; };"
9969       "thrown";
9970
9971   {
9972     LocalContext env(NULL, instance_template);
9973     // Hold on to the global object so it can be used again in another
9974     // environment initialization.
9975     global_object = env->Global();
9976
9977     Local<Value> value = CompileRun("x");
9978     CHECK_EQ(42, value->Int32Value());
9979     value = CompileRun("f()");
9980     CHECK_EQ(12, value->Int32Value());
9981     value = CompileRun(script);
9982     CHECK_EQ(1, value->Int32Value());
9983   }
9984
9985   {
9986     // Create new environment reusing the global object.
9987     LocalContext env(NULL, instance_template, global_object);
9988     Local<Value> value = CompileRun("x");
9989     CHECK_EQ(42, value->Int32Value());
9990     value = CompileRun("f()");
9991     CHECK_EQ(12, value->Int32Value());
9992     value = CompileRun(script);
9993     CHECK_EQ(1, value->Int32Value());
9994   }
9995 }
9996
9997
9998 THREADED_TEST(CallKnownGlobalReceiver) {
9999   v8::Isolate* isolate = CcTest::isolate();
10000   v8::HandleScope handle_scope(isolate);
10001
10002   Local<Value> global_object;
10003
10004   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10005   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10006
10007   // The script to check that we leave global object not
10008   // global object proxy on stack when we deoptimize from inside
10009   // arguments evaluation.
10010   // To provoke error we need to both force deoptimization
10011   // from arguments evaluation and to force CallIC to take
10012   // CallIC_Miss code path that can't cope with global proxy.
10013   const char* script =
10014       "function bar(x, y) { try { } finally { } }"
10015       "function baz(x) { try { } finally { } }"
10016       "function bom(x) { try { } finally { } }"
10017       "function foo(x) { bar([x], bom(2)); }"
10018       "for (var i = 0; i < 10000; i++) foo(1);"
10019       "foo";
10020
10021   Local<Value> foo;
10022   {
10023     LocalContext env(NULL, instance_template);
10024     // Hold on to the global object so it can be used again in another
10025     // environment initialization.
10026     global_object = env->Global();
10027     foo = CompileRun(script);
10028   }
10029
10030   {
10031     // Create new environment reusing the global object.
10032     LocalContext env(NULL, instance_template, global_object);
10033     env->Global()->Set(v8_str("foo"), foo);
10034     CompileRun("foo()");
10035   }
10036 }
10037
10038
10039 static void ShadowFunctionCallback(
10040     const v8::FunctionCallbackInfo<v8::Value>& args) {
10041   ApiTestFuzzer::Fuzz();
10042   args.GetReturnValue().Set(v8_num(42));
10043 }
10044
10045
10046 static int shadow_y;
10047 static int shadow_y_setter_call_count;
10048 static int shadow_y_getter_call_count;
10049
10050
10051 static void ShadowYSetter(Local<String>,
10052                           Local<Value>,
10053                           const v8::PropertyCallbackInfo<void>&) {
10054   shadow_y_setter_call_count++;
10055   shadow_y = 42;
10056 }
10057
10058
10059 static void ShadowYGetter(Local<String> name,
10060                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10061   ApiTestFuzzer::Fuzz();
10062   shadow_y_getter_call_count++;
10063   info.GetReturnValue().Set(v8_num(shadow_y));
10064 }
10065
10066
10067 static void ShadowIndexedGet(uint32_t index,
10068                              const v8::PropertyCallbackInfo<v8::Value>&) {
10069 }
10070
10071
10072 static void ShadowNamedGet(Local<String> key,
10073                            const v8::PropertyCallbackInfo<v8::Value>&) {
10074 }
10075
10076
10077 THREADED_TEST(ShadowObject) {
10078   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10079   v8::Isolate* isolate = CcTest::isolate();
10080   v8::HandleScope handle_scope(isolate);
10081
10082   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10083   LocalContext context(NULL, global_template);
10084
10085   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10086   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10087   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10088   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10089   Local<ObjectTemplate> instance = t->InstanceTemplate();
10090
10091   proto->Set(v8_str("f"),
10092              v8::FunctionTemplate::New(isolate,
10093                                        ShadowFunctionCallback,
10094                                        Local<Value>()));
10095   proto->Set(v8_str("x"), v8_num(12));
10096
10097   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10098
10099   Local<Value> o = t->GetFunction()->NewInstance();
10100   context->Global()->Set(v8_str("__proto__"), o);
10101
10102   Local<Value> value =
10103       CompileRun("this.propertyIsEnumerable(0)");
10104   CHECK(value->IsBoolean());
10105   CHECK(!value->BooleanValue());
10106
10107   value = CompileRun("x");
10108   CHECK_EQ(12, value->Int32Value());
10109
10110   value = CompileRun("f()");
10111   CHECK_EQ(42, value->Int32Value());
10112
10113   CompileRun("y = 43");
10114   CHECK_EQ(1, shadow_y_setter_call_count);
10115   value = CompileRun("y");
10116   CHECK_EQ(1, shadow_y_getter_call_count);
10117   CHECK_EQ(42, value->Int32Value());
10118 }
10119
10120
10121 THREADED_TEST(HiddenPrototype) {
10122   LocalContext context;
10123   v8::Isolate* isolate = context->GetIsolate();
10124   v8::HandleScope handle_scope(isolate);
10125
10126   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10127   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10128   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10129   t1->SetHiddenPrototype(true);
10130   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10131   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10132   t2->SetHiddenPrototype(true);
10133   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10134   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10135   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10136
10137   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10138   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10139   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10140   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10141
10142   // Setting the prototype on an object skips hidden prototypes.
10143   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10144   o0->Set(v8_str("__proto__"), o1);
10145   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10146   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10147   o0->Set(v8_str("__proto__"), o2);
10148   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10149   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10150   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10151   o0->Set(v8_str("__proto__"), o3);
10152   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10153   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10154   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10155   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10156
10157   // Getting the prototype of o0 should get the first visible one
10158   // which is o3.  Therefore, z should not be defined on the prototype
10159   // object.
10160   Local<Value> proto = o0->Get(v8_str("__proto__"));
10161   CHECK(proto->IsObject());
10162   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10163 }
10164
10165
10166 THREADED_TEST(HiddenPrototypeSet) {
10167   LocalContext context;
10168   v8::Isolate* isolate = context->GetIsolate();
10169   v8::HandleScope handle_scope(isolate);
10170
10171   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10172   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10173   ht->SetHiddenPrototype(true);
10174   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10175   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10176
10177   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10178   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10179   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10180   o->Set(v8_str("__proto__"), h);
10181   h->Set(v8_str("__proto__"), p);
10182
10183   // Setting a property that exists on the hidden prototype goes there.
10184   o->Set(v8_str("x"), v8_num(7));
10185   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10186   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10187   CHECK(p->Get(v8_str("x"))->IsUndefined());
10188
10189   // Setting a new property should not be forwarded to the hidden prototype.
10190   o->Set(v8_str("y"), v8_num(6));
10191   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10192   CHECK(h->Get(v8_str("y"))->IsUndefined());
10193   CHECK(p->Get(v8_str("y"))->IsUndefined());
10194
10195   // Setting a property that only exists on a prototype of the hidden prototype
10196   // is treated normally again.
10197   p->Set(v8_str("z"), v8_num(8));
10198   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10199   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10200   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10201   o->Set(v8_str("z"), v8_num(9));
10202   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10203   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10204   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10205 }
10206
10207
10208 // Regression test for issue 2457.
10209 THREADED_TEST(HiddenPrototypeIdentityHash) {
10210   LocalContext context;
10211   v8::HandleScope handle_scope(context->GetIsolate());
10212
10213   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10214   t->SetHiddenPrototype(true);
10215   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10216   Handle<Object> p = t->GetFunction()->NewInstance();
10217   Handle<Object> o = Object::New(context->GetIsolate());
10218   o->SetPrototype(p);
10219
10220   int hash = o->GetIdentityHash();
10221   USE(hash);
10222   o->Set(v8_str("foo"), v8_num(42));
10223   ASSERT_EQ(hash, o->GetIdentityHash());
10224 }
10225
10226
10227 THREADED_TEST(SetPrototype) {
10228   LocalContext context;
10229   v8::Isolate* isolate = context->GetIsolate();
10230   v8::HandleScope handle_scope(isolate);
10231
10232   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10233   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10234   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10235   t1->SetHiddenPrototype(true);
10236   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10237   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10238   t2->SetHiddenPrototype(true);
10239   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10240   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10241   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10242
10243   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10244   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10245   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10246   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10247
10248   // Setting the prototype on an object does not skip hidden prototypes.
10249   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10250   CHECK(o0->SetPrototype(o1));
10251   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10252   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10253   CHECK(o1->SetPrototype(o2));
10254   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10255   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10256   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10257   CHECK(o2->SetPrototype(o3));
10258   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10259   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10260   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10261   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10262
10263   // Getting the prototype of o0 should get the first visible one
10264   // which is o3.  Therefore, z should not be defined on the prototype
10265   // object.
10266   Local<Value> proto = o0->Get(v8_str("__proto__"));
10267   CHECK(proto->IsObject());
10268   CHECK_EQ(proto.As<v8::Object>(), o3);
10269
10270   // However, Object::GetPrototype ignores hidden prototype.
10271   Local<Value> proto0 = o0->GetPrototype();
10272   CHECK(proto0->IsObject());
10273   CHECK_EQ(proto0.As<v8::Object>(), o1);
10274
10275   Local<Value> proto1 = o1->GetPrototype();
10276   CHECK(proto1->IsObject());
10277   CHECK_EQ(proto1.As<v8::Object>(), o2);
10278
10279   Local<Value> proto2 = o2->GetPrototype();
10280   CHECK(proto2->IsObject());
10281   CHECK_EQ(proto2.As<v8::Object>(), o3);
10282 }
10283
10284
10285 // Getting property names of an object with a prototype chain that
10286 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10287 // crash the runtime.
10288 THREADED_TEST(Regress91517) {
10289   i::FLAG_allow_natives_syntax = true;
10290   LocalContext context;
10291   v8::Isolate* isolate = context->GetIsolate();
10292   v8::HandleScope handle_scope(isolate);
10293
10294   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10295   t1->SetHiddenPrototype(true);
10296   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10297   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10298   t2->SetHiddenPrototype(true);
10299   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10300   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10301   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10302   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10303   t3->SetHiddenPrototype(true);
10304   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10305   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10306   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10307
10308   // Force dictionary-based properties.
10309   i::ScopedVector<char> name_buf(1024);
10310   for (int i = 1; i <= 1000; i++) {
10311     i::SNPrintF(name_buf, "sdf%d", i);
10312     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10313   }
10314
10315   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10316   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10317   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10318   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10319
10320   // Create prototype chain of hidden prototypes.
10321   CHECK(o4->SetPrototype(o3));
10322   CHECK(o3->SetPrototype(o2));
10323   CHECK(o2->SetPrototype(o1));
10324
10325   // Call the runtime version of GetOwnPropertyNames() on the natively
10326   // created object through JavaScript.
10327   context->Global()->Set(v8_str("obj"), o4);
10328   // PROPERTY_ATTRIBUTES_NONE = 0
10329   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10330
10331   ExpectInt32("names.length", 1006);
10332   ExpectTrue("names.indexOf(\"baz\") >= 0");
10333   ExpectTrue("names.indexOf(\"boo\") >= 0");
10334   ExpectTrue("names.indexOf(\"foo\") >= 0");
10335   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10336   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10337   ExpectFalse("names[1005] == undefined");
10338 }
10339
10340
10341 // Getting property names of an object with a hidden and inherited
10342 // prototype should not duplicate the accessor properties inherited.
10343 THREADED_TEST(Regress269562) {
10344   i::FLAG_allow_natives_syntax = true;
10345   LocalContext context;
10346   v8::HandleScope handle_scope(context->GetIsolate());
10347
10348   Local<v8::FunctionTemplate> t1 =
10349       v8::FunctionTemplate::New(context->GetIsolate());
10350   t1->SetHiddenPrototype(true);
10351
10352   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10353   i1->SetAccessor(v8_str("foo"),
10354                   SimpleAccessorGetter, SimpleAccessorSetter);
10355   i1->SetAccessor(v8_str("bar"),
10356                   SimpleAccessorGetter, SimpleAccessorSetter);
10357   i1->SetAccessor(v8_str("baz"),
10358                   SimpleAccessorGetter, SimpleAccessorSetter);
10359   i1->Set(v8_str("n1"), v8_num(1));
10360   i1->Set(v8_str("n2"), v8_num(2));
10361
10362   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10363   Local<v8::FunctionTemplate> t2 =
10364       v8::FunctionTemplate::New(context->GetIsolate());
10365   t2->SetHiddenPrototype(true);
10366
10367   // Inherit from t1 and mark prototype as hidden.
10368   t2->Inherit(t1);
10369   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10370
10371   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10372   CHECK(o2->SetPrototype(o1));
10373
10374   v8::Local<v8::Symbol> sym =
10375       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10376   o1->Set(sym, v8_num(3));
10377   o1->SetHiddenValue(
10378       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10379
10380   // Call the runtime version of GetOwnPropertyNames() on
10381   // the natively created object through JavaScript.
10382   context->Global()->Set(v8_str("obj"), o2);
10383   context->Global()->Set(v8_str("sym"), sym);
10384   // PROPERTY_ATTRIBUTES_NONE = 0
10385   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10386
10387   ExpectInt32("names.length", 7);
10388   ExpectTrue("names.indexOf(\"foo\") >= 0");
10389   ExpectTrue("names.indexOf(\"bar\") >= 0");
10390   ExpectTrue("names.indexOf(\"baz\") >= 0");
10391   ExpectTrue("names.indexOf(\"n1\") >= 0");
10392   ExpectTrue("names.indexOf(\"n2\") >= 0");
10393   ExpectTrue("names.indexOf(sym) >= 0");
10394   ExpectTrue("names.indexOf(\"mine\") >= 0");
10395 }
10396
10397
10398 THREADED_TEST(FunctionReadOnlyPrototype) {
10399   LocalContext context;
10400   v8::Isolate* isolate = context->GetIsolate();
10401   v8::HandleScope handle_scope(isolate);
10402
10403   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10404   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10405   t1->ReadOnlyPrototype();
10406   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10407   // Configured value of ReadOnly flag.
10408   CHECK(CompileRun(
10409       "(function() {"
10410       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10411       "  return (descriptor['writable'] == false);"
10412       "})()")->BooleanValue());
10413   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10414   CHECK_EQ(42,
10415            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10416
10417   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10418   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10419   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10420   // Default value of ReadOnly flag.
10421   CHECK(CompileRun(
10422       "(function() {"
10423       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10424       "  return (descriptor['writable'] == true);"
10425       "})()")->BooleanValue());
10426   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10427 }
10428
10429
10430 THREADED_TEST(SetPrototypeThrows) {
10431   LocalContext context;
10432   v8::Isolate* isolate = context->GetIsolate();
10433   v8::HandleScope handle_scope(isolate);
10434
10435   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10436
10437   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10438   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10439
10440   CHECK(o0->SetPrototype(o1));
10441   // If setting the prototype leads to the cycle, SetPrototype should
10442   // return false and keep VM in sane state.
10443   v8::TryCatch try_catch;
10444   CHECK(!o1->SetPrototype(o0));
10445   CHECK(!try_catch.HasCaught());
10446   ASSERT(!CcTest::i_isolate()->has_pending_exception());
10447
10448   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10449 }
10450
10451
10452 THREADED_TEST(FunctionRemovePrototype) {
10453   LocalContext context;
10454   v8::Isolate* isolate = context->GetIsolate();
10455   v8::HandleScope handle_scope(isolate);
10456
10457   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10458   t1->RemovePrototype();
10459   Local<v8::Function> fun = t1->GetFunction();
10460   context->Global()->Set(v8_str("fun"), fun);
10461   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10462
10463   v8::TryCatch try_catch;
10464   CompileRun("new fun()");
10465   CHECK(try_catch.HasCaught());
10466
10467   try_catch.Reset();
10468   fun->NewInstance();
10469   CHECK(try_catch.HasCaught());
10470 }
10471
10472
10473 THREADED_TEST(GetterSetterExceptions) {
10474   LocalContext context;
10475   v8::Isolate* isolate = context->GetIsolate();
10476   v8::HandleScope handle_scope(isolate);
10477   CompileRun(
10478     "function Foo() { };"
10479     "function Throw() { throw 5; };"
10480     "var x = { };"
10481     "x.__defineSetter__('set', Throw);"
10482     "x.__defineGetter__('get', Throw);");
10483   Local<v8::Object> x =
10484       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10485   v8::TryCatch try_catch;
10486   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10487   x->Get(v8_str("get"));
10488   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10489   x->Get(v8_str("get"));
10490   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10491   x->Get(v8_str("get"));
10492   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10493   x->Get(v8_str("get"));
10494 }
10495
10496
10497 THREADED_TEST(Constructor) {
10498   LocalContext context;
10499   v8::Isolate* isolate = context->GetIsolate();
10500   v8::HandleScope handle_scope(isolate);
10501   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10502   templ->SetClassName(v8_str("Fun"));
10503   Local<Function> cons = templ->GetFunction();
10504   context->Global()->Set(v8_str("Fun"), cons);
10505   Local<v8::Object> inst = cons->NewInstance();
10506   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10507   CHECK(obj->IsJSObject());
10508   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10509   CHECK(value->BooleanValue());
10510 }
10511
10512
10513 static void ConstructorCallback(
10514     const v8::FunctionCallbackInfo<v8::Value>& args) {
10515   ApiTestFuzzer::Fuzz();
10516   Local<Object> This;
10517
10518   if (args.IsConstructCall()) {
10519     Local<Object> Holder = args.Holder();
10520     This = Object::New(args.GetIsolate());
10521     Local<Value> proto = Holder->GetPrototype();
10522     if (proto->IsObject()) {
10523       This->SetPrototype(proto);
10524     }
10525   } else {
10526     This = args.This();
10527   }
10528
10529   This->Set(v8_str("a"), args[0]);
10530   args.GetReturnValue().Set(This);
10531 }
10532
10533
10534 static void FakeConstructorCallback(
10535     const v8::FunctionCallbackInfo<v8::Value>& args) {
10536   ApiTestFuzzer::Fuzz();
10537   args.GetReturnValue().Set(args[0]);
10538 }
10539
10540
10541 THREADED_TEST(ConstructorForObject) {
10542   LocalContext context;
10543   v8::Isolate* isolate = context->GetIsolate();
10544   v8::HandleScope handle_scope(isolate);
10545
10546   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10547     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10548     Local<Object> instance = instance_template->NewInstance();
10549     context->Global()->Set(v8_str("obj"), instance);
10550     v8::TryCatch try_catch;
10551     Local<Value> value;
10552     CHECK(!try_catch.HasCaught());
10553
10554     // Call the Object's constructor with a 32-bit signed integer.
10555     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10556     CHECK(!try_catch.HasCaught());
10557     CHECK(value->IsInt32());
10558     CHECK_EQ(28, value->Int32Value());
10559
10560     Local<Value> args1[] = { v8_num(28) };
10561     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10562     CHECK(value_obj1->IsObject());
10563     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10564     value = object1->Get(v8_str("a"));
10565     CHECK(value->IsInt32());
10566     CHECK(!try_catch.HasCaught());
10567     CHECK_EQ(28, value->Int32Value());
10568
10569     // Call the Object's constructor with a String.
10570     value = CompileRun(
10571         "(function() { var o = new obj('tipli'); return o.a; })()");
10572     CHECK(!try_catch.HasCaught());
10573     CHECK(value->IsString());
10574     String::Utf8Value string_value1(value->ToString());
10575     CHECK_EQ("tipli", *string_value1);
10576
10577     Local<Value> args2[] = { v8_str("tipli") };
10578     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10579     CHECK(value_obj2->IsObject());
10580     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10581     value = object2->Get(v8_str("a"));
10582     CHECK(!try_catch.HasCaught());
10583     CHECK(value->IsString());
10584     String::Utf8Value string_value2(value->ToString());
10585     CHECK_EQ("tipli", *string_value2);
10586
10587     // Call the Object's constructor with a Boolean.
10588     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10589     CHECK(!try_catch.HasCaught());
10590     CHECK(value->IsBoolean());
10591     CHECK_EQ(true, value->BooleanValue());
10592
10593     Handle<Value> args3[] = { v8::True(isolate) };
10594     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10595     CHECK(value_obj3->IsObject());
10596     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10597     value = object3->Get(v8_str("a"));
10598     CHECK(!try_catch.HasCaught());
10599     CHECK(value->IsBoolean());
10600     CHECK_EQ(true, value->BooleanValue());
10601
10602     // Call the Object's constructor with undefined.
10603     Handle<Value> args4[] = { v8::Undefined(isolate) };
10604     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10605     CHECK(value_obj4->IsObject());
10606     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10607     value = object4->Get(v8_str("a"));
10608     CHECK(!try_catch.HasCaught());
10609     CHECK(value->IsUndefined());
10610
10611     // Call the Object's constructor with null.
10612     Handle<Value> args5[] = { v8::Null(isolate) };
10613     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10614     CHECK(value_obj5->IsObject());
10615     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10616     value = object5->Get(v8_str("a"));
10617     CHECK(!try_catch.HasCaught());
10618     CHECK(value->IsNull());
10619   }
10620
10621   // Check exception handling when there is no constructor set for the Object.
10622   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10623     Local<Object> instance = instance_template->NewInstance();
10624     context->Global()->Set(v8_str("obj2"), instance);
10625     v8::TryCatch try_catch;
10626     Local<Value> value;
10627     CHECK(!try_catch.HasCaught());
10628
10629     value = CompileRun("new obj2(28)");
10630     CHECK(try_catch.HasCaught());
10631     String::Utf8Value exception_value1(try_catch.Exception());
10632     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10633     try_catch.Reset();
10634
10635     Local<Value> args[] = { v8_num(29) };
10636     value = instance->CallAsConstructor(1, args);
10637     CHECK(try_catch.HasCaught());
10638     String::Utf8Value exception_value2(try_catch.Exception());
10639     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10640     try_catch.Reset();
10641   }
10642
10643   // Check the case when constructor throws exception.
10644   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10645     instance_template->SetCallAsFunctionHandler(ThrowValue);
10646     Local<Object> instance = instance_template->NewInstance();
10647     context->Global()->Set(v8_str("obj3"), instance);
10648     v8::TryCatch try_catch;
10649     Local<Value> value;
10650     CHECK(!try_catch.HasCaught());
10651
10652     value = CompileRun("new obj3(22)");
10653     CHECK(try_catch.HasCaught());
10654     String::Utf8Value exception_value1(try_catch.Exception());
10655     CHECK_EQ("22", *exception_value1);
10656     try_catch.Reset();
10657
10658     Local<Value> args[] = { v8_num(23) };
10659     value = instance->CallAsConstructor(1, args);
10660     CHECK(try_catch.HasCaught());
10661     String::Utf8Value exception_value2(try_catch.Exception());
10662     CHECK_EQ("23", *exception_value2);
10663     try_catch.Reset();
10664   }
10665
10666   // Check whether constructor returns with an object or non-object.
10667   { Local<FunctionTemplate> function_template =
10668         FunctionTemplate::New(isolate, FakeConstructorCallback);
10669     Local<Function> function = function_template->GetFunction();
10670     Local<Object> instance1 = function;
10671     context->Global()->Set(v8_str("obj4"), instance1);
10672     v8::TryCatch try_catch;
10673     Local<Value> value;
10674     CHECK(!try_catch.HasCaught());
10675
10676     CHECK(instance1->IsObject());
10677     CHECK(instance1->IsFunction());
10678
10679     value = CompileRun("new obj4(28)");
10680     CHECK(!try_catch.HasCaught());
10681     CHECK(value->IsObject());
10682
10683     Local<Value> args1[] = { v8_num(28) };
10684     value = instance1->CallAsConstructor(1, args1);
10685     CHECK(!try_catch.HasCaught());
10686     CHECK(value->IsObject());
10687
10688     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10689     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10690     Local<Object> instance2 = instance_template->NewInstance();
10691     context->Global()->Set(v8_str("obj5"), instance2);
10692     CHECK(!try_catch.HasCaught());
10693
10694     CHECK(instance2->IsObject());
10695     CHECK(!instance2->IsFunction());
10696
10697     value = CompileRun("new obj5(28)");
10698     CHECK(!try_catch.HasCaught());
10699     CHECK(!value->IsObject());
10700
10701     Local<Value> args2[] = { v8_num(28) };
10702     value = instance2->CallAsConstructor(1, args2);
10703     CHECK(!try_catch.HasCaught());
10704     CHECK(!value->IsObject());
10705   }
10706 }
10707
10708
10709 THREADED_TEST(FunctionDescriptorException) {
10710   LocalContext context;
10711   v8::Isolate* isolate = context->GetIsolate();
10712   v8::HandleScope handle_scope(isolate);
10713   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10714   templ->SetClassName(v8_str("Fun"));
10715   Local<Function> cons = templ->GetFunction();
10716   context->Global()->Set(v8_str("Fun"), cons);
10717   Local<Value> value = CompileRun(
10718     "function test() {"
10719     "  try {"
10720     "    (new Fun()).blah()"
10721     "  } catch (e) {"
10722     "    var str = String(e);"
10723     // "    if (str.indexOf('TypeError') == -1) return 1;"
10724     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10725     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10726     "    return 0;"
10727     "  }"
10728     "  return 4;"
10729     "}"
10730     "test();");
10731   CHECK_EQ(0, value->Int32Value());
10732 }
10733
10734
10735 THREADED_TEST(EvalAliasedDynamic) {
10736   LocalContext current;
10737   v8::HandleScope scope(current->GetIsolate());
10738
10739   // Tests where aliased eval can only be resolved dynamically.
10740   Local<Script> script = v8_compile(
10741       "function f(x) { "
10742       "  var foo = 2;"
10743       "  with (x) { return eval('foo'); }"
10744       "}"
10745       "foo = 0;"
10746       "result1 = f(new Object());"
10747       "result2 = f(this);"
10748       "var x = new Object();"
10749       "x.eval = function(x) { return 1; };"
10750       "result3 = f(x);");
10751   script->Run();
10752   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10753   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10754   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10755
10756   v8::TryCatch try_catch;
10757   script = v8_compile(
10758       "function f(x) { "
10759       "  var bar = 2;"
10760       "  with (x) { return eval('bar'); }"
10761       "}"
10762       "result4 = f(this)");
10763   script->Run();
10764   CHECK(!try_catch.HasCaught());
10765   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10766
10767   try_catch.Reset();
10768 }
10769
10770
10771 THREADED_TEST(CrossEval) {
10772   v8::HandleScope scope(CcTest::isolate());
10773   LocalContext other;
10774   LocalContext current;
10775
10776   Local<String> token = v8_str("<security token>");
10777   other->SetSecurityToken(token);
10778   current->SetSecurityToken(token);
10779
10780   // Set up reference from current to other.
10781   current->Global()->Set(v8_str("other"), other->Global());
10782
10783   // Check that new variables are introduced in other context.
10784   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10785   script->Run();
10786   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10787   CHECK_EQ(1234, foo->Int32Value());
10788   CHECK(!current->Global()->Has(v8_str("foo")));
10789
10790   // Check that writing to non-existing properties introduces them in
10791   // the other context.
10792   script = v8_compile("other.eval('na = 1234')");
10793   script->Run();
10794   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10795   CHECK(!current->Global()->Has(v8_str("na")));
10796
10797   // Check that global variables in current context are not visible in other
10798   // context.
10799   v8::TryCatch try_catch;
10800   script = v8_compile("var bar = 42; other.eval('bar');");
10801   Local<Value> result = script->Run();
10802   CHECK(try_catch.HasCaught());
10803   try_catch.Reset();
10804
10805   // Check that local variables in current context are not visible in other
10806   // context.
10807   script = v8_compile(
10808       "(function() { "
10809       "  var baz = 87;"
10810       "  return other.eval('baz');"
10811       "})();");
10812   result = script->Run();
10813   CHECK(try_catch.HasCaught());
10814   try_catch.Reset();
10815
10816   // Check that global variables in the other environment are visible
10817   // when evaluting code.
10818   other->Global()->Set(v8_str("bis"), v8_num(1234));
10819   script = v8_compile("other.eval('bis')");
10820   CHECK_EQ(1234, script->Run()->Int32Value());
10821   CHECK(!try_catch.HasCaught());
10822
10823   // Check that the 'this' pointer points to the global object evaluating
10824   // code.
10825   other->Global()->Set(v8_str("t"), other->Global());
10826   script = v8_compile("other.eval('this == t')");
10827   result = script->Run();
10828   CHECK(result->IsTrue());
10829   CHECK(!try_catch.HasCaught());
10830
10831   // Check that variables introduced in with-statement are not visible in
10832   // other context.
10833   script = v8_compile("with({x:2}){other.eval('x')}");
10834   result = script->Run();
10835   CHECK(try_catch.HasCaught());
10836   try_catch.Reset();
10837
10838   // Check that you cannot use 'eval.call' with another object than the
10839   // current global object.
10840   script = v8_compile("other.y = 1; eval.call(other, 'y')");
10841   result = script->Run();
10842   CHECK(try_catch.HasCaught());
10843 }
10844
10845
10846 // Test that calling eval in a context which has been detached from
10847 // its global throws an exception.  This behavior is consistent with
10848 // other JavaScript implementations.
10849 THREADED_TEST(EvalInDetachedGlobal) {
10850   v8::Isolate* isolate = CcTest::isolate();
10851   v8::HandleScope scope(isolate);
10852
10853   v8::Local<Context> context0 = Context::New(isolate);
10854   v8::Local<Context> context1 = Context::New(isolate);
10855
10856   // Set up function in context0 that uses eval from context0.
10857   context0->Enter();
10858   v8::Handle<v8::Value> fun =
10859       CompileRun("var x = 42;"
10860                  "(function() {"
10861                  "  var e = eval;"
10862                  "  return function(s) { return e(s); }"
10863                  "})()");
10864   context0->Exit();
10865
10866   // Put the function into context1 and call it before and after
10867   // detaching the global.  Before detaching, the call succeeds and
10868   // after detaching and exception is thrown.
10869   context1->Enter();
10870   context1->Global()->Set(v8_str("fun"), fun);
10871   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10872   CHECK_EQ(42, x_value->Int32Value());
10873   context0->DetachGlobal();
10874   v8::TryCatch catcher;
10875   x_value = CompileRun("fun('x')");
10876   CHECK(x_value.IsEmpty());
10877   CHECK(catcher.HasCaught());
10878   context1->Exit();
10879 }
10880
10881
10882 THREADED_TEST(CrossLazyLoad) {
10883   v8::HandleScope scope(CcTest::isolate());
10884   LocalContext other;
10885   LocalContext current;
10886
10887   Local<String> token = v8_str("<security token>");
10888   other->SetSecurityToken(token);
10889   current->SetSecurityToken(token);
10890
10891   // Set up reference from current to other.
10892   current->Global()->Set(v8_str("other"), other->Global());
10893
10894   // Trigger lazy loading in other context.
10895   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10896   Local<Value> value = script->Run();
10897   CHECK_EQ(42.0, value->NumberValue());
10898 }
10899
10900
10901 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10902   ApiTestFuzzer::Fuzz();
10903   if (args.IsConstructCall()) {
10904     if (args[0]->IsInt32()) {
10905       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10906       return;
10907     }
10908   }
10909
10910   args.GetReturnValue().Set(args[0]);
10911 }
10912
10913
10914 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10915   args.GetReturnValue().Set(args.This());
10916 }
10917
10918
10919 // Test that a call handler can be set for objects which will allow
10920 // non-function objects created through the API to be called as
10921 // functions.
10922 THREADED_TEST(CallAsFunction) {
10923   LocalContext context;
10924   v8::Isolate* isolate = context->GetIsolate();
10925   v8::HandleScope scope(isolate);
10926
10927   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10928     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10929     instance_template->SetCallAsFunctionHandler(call_as_function);
10930     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10931     context->Global()->Set(v8_str("obj"), instance);
10932     v8::TryCatch try_catch;
10933     Local<Value> value;
10934     CHECK(!try_catch.HasCaught());
10935
10936     value = CompileRun("obj(42)");
10937     CHECK(!try_catch.HasCaught());
10938     CHECK_EQ(42, value->Int32Value());
10939
10940     value = CompileRun("(function(o){return o(49)})(obj)");
10941     CHECK(!try_catch.HasCaught());
10942     CHECK_EQ(49, value->Int32Value());
10943
10944     // test special case of call as function
10945     value = CompileRun("[obj]['0'](45)");
10946     CHECK(!try_catch.HasCaught());
10947     CHECK_EQ(45, value->Int32Value());
10948
10949     value = CompileRun("obj.call = Function.prototype.call;"
10950                        "obj.call(null, 87)");
10951     CHECK(!try_catch.HasCaught());
10952     CHECK_EQ(87, value->Int32Value());
10953
10954     // Regression tests for bug #1116356: Calling call through call/apply
10955     // must work for non-function receivers.
10956     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10957     value = CompileRun(apply_99);
10958     CHECK(!try_catch.HasCaught());
10959     CHECK_EQ(99, value->Int32Value());
10960
10961     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10962     value = CompileRun(call_17);
10963     CHECK(!try_catch.HasCaught());
10964     CHECK_EQ(17, value->Int32Value());
10965
10966     // Check that the call-as-function handler can be called through
10967     // new.
10968     value = CompileRun("new obj(43)");
10969     CHECK(!try_catch.HasCaught());
10970     CHECK_EQ(-43, value->Int32Value());
10971
10972     // Check that the call-as-function handler can be called through
10973     // the API.
10974     v8::Handle<Value> args[] = { v8_num(28) };
10975     value = instance->CallAsFunction(instance, 1, args);
10976     CHECK(!try_catch.HasCaught());
10977     CHECK_EQ(28, value->Int32Value());
10978   }
10979
10980   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10981     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10982     USE(instance_template);
10983     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10984     context->Global()->Set(v8_str("obj2"), instance);
10985     v8::TryCatch try_catch;
10986     Local<Value> value;
10987     CHECK(!try_catch.HasCaught());
10988
10989     // Call an object without call-as-function handler through the JS
10990     value = CompileRun("obj2(28)");
10991     CHECK(value.IsEmpty());
10992     CHECK(try_catch.HasCaught());
10993     String::Utf8Value exception_value1(try_catch.Exception());
10994     // TODO(verwaest): Better message
10995     CHECK_EQ("TypeError: object is not a function",
10996              *exception_value1);
10997     try_catch.Reset();
10998
10999     // Call an object without call-as-function handler through the API
11000     value = CompileRun("obj2(28)");
11001     v8::Handle<Value> args[] = { v8_num(28) };
11002     value = instance->CallAsFunction(instance, 1, args);
11003     CHECK(value.IsEmpty());
11004     CHECK(try_catch.HasCaught());
11005     String::Utf8Value exception_value2(try_catch.Exception());
11006     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11007     try_catch.Reset();
11008   }
11009
11010   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11011     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11012     instance_template->SetCallAsFunctionHandler(ThrowValue);
11013     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11014     context->Global()->Set(v8_str("obj3"), instance);
11015     v8::TryCatch try_catch;
11016     Local<Value> value;
11017     CHECK(!try_catch.HasCaught());
11018
11019     // Catch the exception which is thrown by call-as-function handler
11020     value = CompileRun("obj3(22)");
11021     CHECK(try_catch.HasCaught());
11022     String::Utf8Value exception_value1(try_catch.Exception());
11023     CHECK_EQ("22", *exception_value1);
11024     try_catch.Reset();
11025
11026     v8::Handle<Value> args[] = { v8_num(23) };
11027     value = instance->CallAsFunction(instance, 1, args);
11028     CHECK(try_catch.HasCaught());
11029     String::Utf8Value exception_value2(try_catch.Exception());
11030     CHECK_EQ("23", *exception_value2);
11031     try_catch.Reset();
11032   }
11033
11034   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11035     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11036     instance_template->SetCallAsFunctionHandler(ReturnThis);
11037     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11038
11039     Local<v8::Value> a1 =
11040         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11041     CHECK(a1->StrictEquals(instance));
11042     Local<v8::Value> a2 =
11043         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11044     CHECK(a2->StrictEquals(instance));
11045     Local<v8::Value> a3 =
11046         instance->CallAsFunction(v8_num(42), 0, NULL);
11047     CHECK(a3->StrictEquals(instance));
11048     Local<v8::Value> a4 =
11049         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11050     CHECK(a4->StrictEquals(instance));
11051     Local<v8::Value> a5 =
11052         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11053     CHECK(a5->StrictEquals(instance));
11054   }
11055
11056   { CompileRun(
11057       "function ReturnThisSloppy() {"
11058       "  return this;"
11059       "}"
11060       "function ReturnThisStrict() {"
11061       "  'use strict';"
11062       "  return this;"
11063       "}");
11064     Local<Function> ReturnThisSloppy =
11065         Local<Function>::Cast(
11066             context->Global()->Get(v8_str("ReturnThisSloppy")));
11067     Local<Function> ReturnThisStrict =
11068         Local<Function>::Cast(
11069             context->Global()->Get(v8_str("ReturnThisStrict")));
11070
11071     Local<v8::Value> a1 =
11072         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11073     CHECK(a1->StrictEquals(context->Global()));
11074     Local<v8::Value> a2 =
11075         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11076     CHECK(a2->StrictEquals(context->Global()));
11077     Local<v8::Value> a3 =
11078         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11079     CHECK(a3->IsNumberObject());
11080     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11081     Local<v8::Value> a4 =
11082         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11083     CHECK(a4->IsStringObject());
11084     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11085     Local<v8::Value> a5 =
11086         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11087     CHECK(a5->IsBooleanObject());
11088     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11089
11090     Local<v8::Value> a6 =
11091         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11092     CHECK(a6->IsUndefined());
11093     Local<v8::Value> a7 =
11094         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11095     CHECK(a7->IsNull());
11096     Local<v8::Value> a8 =
11097         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11098     CHECK(a8->StrictEquals(v8_num(42)));
11099     Local<v8::Value> a9 =
11100         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11101     CHECK(a9->StrictEquals(v8_str("hello")));
11102     Local<v8::Value> a10 =
11103         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11104     CHECK(a10->StrictEquals(v8::True(isolate)));
11105   }
11106 }
11107
11108
11109 // Check whether a non-function object is callable.
11110 THREADED_TEST(CallableObject) {
11111   LocalContext context;
11112   v8::Isolate* isolate = context->GetIsolate();
11113   v8::HandleScope scope(isolate);
11114
11115   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11116     instance_template->SetCallAsFunctionHandler(call_as_function);
11117     Local<Object> instance = instance_template->NewInstance();
11118     v8::TryCatch try_catch;
11119
11120     CHECK(instance->IsCallable());
11121     CHECK(!try_catch.HasCaught());
11122   }
11123
11124   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11125     Local<Object> instance = instance_template->NewInstance();
11126     v8::TryCatch try_catch;
11127
11128     CHECK(!instance->IsCallable());
11129     CHECK(!try_catch.HasCaught());
11130   }
11131
11132   { Local<FunctionTemplate> function_template =
11133         FunctionTemplate::New(isolate, call_as_function);
11134     Local<Function> function = function_template->GetFunction();
11135     Local<Object> instance = function;
11136     v8::TryCatch try_catch;
11137
11138     CHECK(instance->IsCallable());
11139     CHECK(!try_catch.HasCaught());
11140   }
11141
11142   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11143     Local<Function> function = function_template->GetFunction();
11144     Local<Object> instance = function;
11145     v8::TryCatch try_catch;
11146
11147     CHECK(instance->IsCallable());
11148     CHECK(!try_catch.HasCaught());
11149   }
11150 }
11151
11152
11153 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11154   v8::HandleScope scope(isolate);
11155   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11156   for (int i = 0; i < iterations; i++) {
11157     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11158   }
11159   return Recurse(isolate, depth - 1, iterations);
11160 }
11161
11162
11163 THREADED_TEST(HandleIteration) {
11164   static const int kIterations = 500;
11165   static const int kNesting = 200;
11166   LocalContext context;
11167   v8::Isolate* isolate = context->GetIsolate();
11168   v8::HandleScope scope0(isolate);
11169   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11170   {
11171     v8::HandleScope scope1(isolate);
11172     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11173     for (int i = 0; i < kIterations; i++) {
11174       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11175       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11176     }
11177
11178     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11179     {
11180       v8::HandleScope scope2(CcTest::isolate());
11181       for (int j = 0; j < kIterations; j++) {
11182         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11183         CHECK_EQ(j + 1 + kIterations,
11184                  v8::HandleScope::NumberOfHandles(isolate));
11185       }
11186     }
11187     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11188   }
11189   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11190   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11191 }
11192
11193
11194 static void InterceptorHasOwnPropertyGetter(
11195     Local<String> name,
11196     const v8::PropertyCallbackInfo<v8::Value>& info) {
11197   ApiTestFuzzer::Fuzz();
11198 }
11199
11200
11201 THREADED_TEST(InterceptorHasOwnProperty) {
11202   LocalContext context;
11203   v8::Isolate* isolate = context->GetIsolate();
11204   v8::HandleScope scope(isolate);
11205   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11206   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11207   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11208   Local<Function> function = fun_templ->GetFunction();
11209   context->Global()->Set(v8_str("constructor"), function);
11210   v8::Handle<Value> value = CompileRun(
11211       "var o = new constructor();"
11212       "o.hasOwnProperty('ostehaps');");
11213   CHECK_EQ(false, value->BooleanValue());
11214   value = CompileRun(
11215       "o.ostehaps = 42;"
11216       "o.hasOwnProperty('ostehaps');");
11217   CHECK_EQ(true, value->BooleanValue());
11218   value = CompileRun(
11219       "var p = new constructor();"
11220       "p.hasOwnProperty('ostehaps');");
11221   CHECK_EQ(false, value->BooleanValue());
11222 }
11223
11224
11225 static void InterceptorHasOwnPropertyGetterGC(
11226     Local<String> name,
11227     const v8::PropertyCallbackInfo<v8::Value>& info) {
11228   ApiTestFuzzer::Fuzz();
11229   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11230 }
11231
11232
11233 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11234   LocalContext context;
11235   v8::Isolate* isolate = context->GetIsolate();
11236   v8::HandleScope scope(isolate);
11237   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11238   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11239   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11240   Local<Function> function = fun_templ->GetFunction();
11241   context->Global()->Set(v8_str("constructor"), function);
11242   // Let's first make some stuff so we can be sure to get a good GC.
11243   CompileRun(
11244       "function makestr(size) {"
11245       "  switch (size) {"
11246       "    case 1: return 'f';"
11247       "    case 2: return 'fo';"
11248       "    case 3: return 'foo';"
11249       "  }"
11250       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11251       "}"
11252       "var x = makestr(12345);"
11253       "x = makestr(31415);"
11254       "x = makestr(23456);");
11255   v8::Handle<Value> value = CompileRun(
11256       "var o = new constructor();"
11257       "o.__proto__ = new String(x);"
11258       "o.hasOwnProperty('ostehaps');");
11259   CHECK_EQ(false, value->BooleanValue());
11260 }
11261
11262
11263 typedef void (*NamedPropertyGetter)(
11264     Local<String> property,
11265     const v8::PropertyCallbackInfo<v8::Value>& info);
11266
11267
11268 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11269                                    const char* source,
11270                                    int expected) {
11271   v8::Isolate* isolate = CcTest::isolate();
11272   v8::HandleScope scope(isolate);
11273   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11274   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11275   LocalContext context;
11276   context->Global()->Set(v8_str("o"), templ->NewInstance());
11277   v8::Handle<Value> value = CompileRun(source);
11278   CHECK_EQ(expected, value->Int32Value());
11279 }
11280
11281
11282 static void InterceptorLoadICGetter(
11283     Local<String> name,
11284     const v8::PropertyCallbackInfo<v8::Value>& info) {
11285   ApiTestFuzzer::Fuzz();
11286   v8::Isolate* isolate = CcTest::isolate();
11287   CHECK_EQ(isolate, info.GetIsolate());
11288   CHECK_EQ(v8_str("data"), info.Data());
11289   CHECK_EQ(v8_str("x"), name);
11290   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11291 }
11292
11293
11294 // This test should hit the load IC for the interceptor case.
11295 THREADED_TEST(InterceptorLoadIC) {
11296   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11297     "var result = 0;"
11298     "for (var i = 0; i < 1000; i++) {"
11299     "  result = o.x;"
11300     "}",
11301     42);
11302 }
11303
11304
11305 // Below go several tests which verify that JITing for various
11306 // configurations of interceptor and explicit fields works fine
11307 // (those cases are special cased to get better performance).
11308
11309 static void InterceptorLoadXICGetter(
11310     Local<String> name,
11311     const v8::PropertyCallbackInfo<v8::Value>& info) {
11312   ApiTestFuzzer::Fuzz();
11313   info.GetReturnValue().Set(
11314       v8_str("x")->Equals(name) ?
11315           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11316           v8::Handle<v8::Value>());
11317 }
11318
11319
11320 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11321   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11322     "var result = 0;"
11323     "o.y = 239;"
11324     "for (var i = 0; i < 1000; i++) {"
11325     "  result = o.y;"
11326     "}",
11327     239);
11328 }
11329
11330
11331 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11332   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11333     "var result = 0;"
11334     "o.__proto__ = { 'y': 239 };"
11335     "for (var i = 0; i < 1000; i++) {"
11336     "  result = o.y + o.x;"
11337     "}",
11338     239 + 42);
11339 }
11340
11341
11342 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11343   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11344     "var result = 0;"
11345     "o.__proto__.y = 239;"
11346     "for (var i = 0; i < 1000; i++) {"
11347     "  result = o.y + o.x;"
11348     "}",
11349     239 + 42);
11350 }
11351
11352
11353 THREADED_TEST(InterceptorLoadICUndefined) {
11354   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11355     "var result = 0;"
11356     "for (var i = 0; i < 1000; i++) {"
11357     "  result = (o.y == undefined) ? 239 : 42;"
11358     "}",
11359     239);
11360 }
11361
11362
11363 THREADED_TEST(InterceptorLoadICWithOverride) {
11364   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11365     "fst = new Object();  fst.__proto__ = o;"
11366     "snd = new Object();  snd.__proto__ = fst;"
11367     "var result1 = 0;"
11368     "for (var i = 0; i < 1000;  i++) {"
11369     "  result1 = snd.x;"
11370     "}"
11371     "fst.x = 239;"
11372     "var result = 0;"
11373     "for (var i = 0; i < 1000; i++) {"
11374     "  result = snd.x;"
11375     "}"
11376     "result + result1",
11377     239 + 42);
11378 }
11379
11380
11381 // Test the case when we stored field into
11382 // a stub, but interceptor produced value on its own.
11383 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11384   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11385     "proto = new Object();"
11386     "o.__proto__ = proto;"
11387     "proto.x = 239;"
11388     "for (var i = 0; i < 1000; i++) {"
11389     "  o.x;"
11390     // Now it should be ICed and keep a reference to x defined on proto
11391     "}"
11392     "var result = 0;"
11393     "for (var i = 0; i < 1000; i++) {"
11394     "  result += o.x;"
11395     "}"
11396     "result;",
11397     42 * 1000);
11398 }
11399
11400
11401 // Test the case when we stored field into
11402 // a stub, but it got invalidated later on.
11403 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11404   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11405     "proto1 = new Object();"
11406     "proto2 = new Object();"
11407     "o.__proto__ = proto1;"
11408     "proto1.__proto__ = proto2;"
11409     "proto2.y = 239;"
11410     "for (var i = 0; i < 1000; i++) {"
11411     "  o.y;"
11412     // Now it should be ICed and keep a reference to y defined on proto2
11413     "}"
11414     "proto1.y = 42;"
11415     "var result = 0;"
11416     "for (var i = 0; i < 1000; i++) {"
11417     "  result += o.y;"
11418     "}"
11419     "result;",
11420     42 * 1000);
11421 }
11422
11423
11424 static int interceptor_load_not_handled_calls = 0;
11425 static void InterceptorLoadNotHandled(
11426     Local<String> name,
11427     const v8::PropertyCallbackInfo<v8::Value>& info) {
11428   ++interceptor_load_not_handled_calls;
11429 }
11430
11431
11432 // Test how post-interceptor lookups are done in the non-cacheable
11433 // case: the interceptor should not be invoked during this lookup.
11434 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11435   interceptor_load_not_handled_calls = 0;
11436   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11437     "receiver = new Object();"
11438     "receiver.__proto__ = o;"
11439     "proto = new Object();"
11440     "/* Make proto a slow-case object. */"
11441     "for (var i = 0; i < 1000; i++) {"
11442     "  proto[\"xxxxxxxx\" + i] = [];"
11443     "}"
11444     "proto.x = 17;"
11445     "o.__proto__ = proto;"
11446     "var result = 0;"
11447     "for (var i = 0; i < 1000; i++) {"
11448     "  result += receiver.x;"
11449     "}"
11450     "result;",
11451     17 * 1000);
11452   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11453 }
11454
11455
11456 // Test the case when we stored field into
11457 // a stub, but it got invalidated later on due to override on
11458 // global object which is between interceptor and fields' holders.
11459 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11460   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11461     "o.__proto__ = this;"  // set a global to be a proto of o.
11462     "this.__proto__.y = 239;"
11463     "for (var i = 0; i < 10; i++) {"
11464     "  if (o.y != 239) throw 'oops: ' + o.y;"
11465     // Now it should be ICed and keep a reference to y defined on field_holder.
11466     "}"
11467     "this.y = 42;"  // Assign on a global.
11468     "var result = 0;"
11469     "for (var i = 0; i < 10; i++) {"
11470     "  result += o.y;"
11471     "}"
11472     "result;",
11473     42 * 10);
11474 }
11475
11476
11477 static void SetOnThis(Local<String> name,
11478                       Local<Value> value,
11479                       const v8::PropertyCallbackInfo<void>& info) {
11480   Local<Object>::Cast(info.This())->ForceSet(name, value);
11481 }
11482
11483
11484 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11485   v8::Isolate* isolate = CcTest::isolate();
11486   v8::HandleScope scope(isolate);
11487   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11488   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11489   templ->SetAccessor(v8_str("y"), Return239Callback);
11490   LocalContext context;
11491   context->Global()->Set(v8_str("o"), templ->NewInstance());
11492
11493   // Check the case when receiver and interceptor's holder
11494   // are the same objects.
11495   v8::Handle<Value> value = CompileRun(
11496       "var result = 0;"
11497       "for (var i = 0; i < 7; i++) {"
11498       "  result = o.y;"
11499       "}");
11500   CHECK_EQ(239, value->Int32Value());
11501
11502   // Check the case when interceptor's holder is in proto chain
11503   // of receiver.
11504   value = CompileRun(
11505       "r = { __proto__: o };"
11506       "var result = 0;"
11507       "for (var i = 0; i < 7; i++) {"
11508       "  result = r.y;"
11509       "}");
11510   CHECK_EQ(239, value->Int32Value());
11511 }
11512
11513
11514 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11515   v8::Isolate* isolate = CcTest::isolate();
11516   v8::HandleScope scope(isolate);
11517   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11518   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11519   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11520   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11521
11522   LocalContext context;
11523   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11524   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11525
11526   // Check the case when receiver and interceptor's holder
11527   // are the same objects.
11528   v8::Handle<Value> value = CompileRun(
11529       "o.__proto__ = p;"
11530       "var result = 0;"
11531       "for (var i = 0; i < 7; i++) {"
11532       "  result = o.x + o.y;"
11533       "}");
11534   CHECK_EQ(239 + 42, value->Int32Value());
11535
11536   // Check the case when interceptor's holder is in proto chain
11537   // of receiver.
11538   value = CompileRun(
11539       "r = { __proto__: o };"
11540       "var result = 0;"
11541       "for (var i = 0; i < 7; i++) {"
11542       "  result = r.x + r.y;"
11543       "}");
11544   CHECK_EQ(239 + 42, value->Int32Value());
11545 }
11546
11547
11548 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11549   v8::Isolate* isolate = CcTest::isolate();
11550   v8::HandleScope scope(isolate);
11551   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11552   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11553   templ->SetAccessor(v8_str("y"), Return239Callback);
11554
11555   LocalContext context;
11556   context->Global()->Set(v8_str("o"), templ->NewInstance());
11557
11558   v8::Handle<Value> value = CompileRun(
11559     "fst = new Object();  fst.__proto__ = o;"
11560     "snd = new Object();  snd.__proto__ = fst;"
11561     "var result1 = 0;"
11562     "for (var i = 0; i < 7;  i++) {"
11563     "  result1 = snd.x;"
11564     "}"
11565     "fst.x = 239;"
11566     "var result = 0;"
11567     "for (var i = 0; i < 7; i++) {"
11568     "  result = snd.x;"
11569     "}"
11570     "result + result1");
11571   CHECK_EQ(239 + 42, value->Int32Value());
11572 }
11573
11574
11575 // Test the case when we stored callback into
11576 // a stub, but interceptor produced value on its own.
11577 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11578   v8::Isolate* isolate = CcTest::isolate();
11579   v8::HandleScope scope(isolate);
11580   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11581   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11582   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11583   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11584
11585   LocalContext context;
11586   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11587   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11588
11589   v8::Handle<Value> value = CompileRun(
11590     "o.__proto__ = p;"
11591     "for (var i = 0; i < 7; i++) {"
11592     "  o.x;"
11593     // Now it should be ICed and keep a reference to x defined on p
11594     "}"
11595     "var result = 0;"
11596     "for (var i = 0; i < 7; i++) {"
11597     "  result += o.x;"
11598     "}"
11599     "result");
11600   CHECK_EQ(42 * 7, value->Int32Value());
11601 }
11602
11603
11604 // Test the case when we stored callback into
11605 // a stub, but it got invalidated later on.
11606 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11607   v8::Isolate* isolate = CcTest::isolate();
11608   v8::HandleScope scope(isolate);
11609   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11610   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11611   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11612   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11613
11614   LocalContext context;
11615   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11616   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11617
11618   v8::Handle<Value> value = CompileRun(
11619     "inbetween = new Object();"
11620     "o.__proto__ = inbetween;"
11621     "inbetween.__proto__ = p;"
11622     "for (var i = 0; i < 10; i++) {"
11623     "  o.y;"
11624     // Now it should be ICed and keep a reference to y defined on p
11625     "}"
11626     "inbetween.y = 42;"
11627     "var result = 0;"
11628     "for (var i = 0; i < 10; i++) {"
11629     "  result += o.y;"
11630     "}"
11631     "result");
11632   CHECK_EQ(42 * 10, value->Int32Value());
11633 }
11634
11635
11636 // Test the case when we stored callback into
11637 // a stub, but it got invalidated later on due to override on
11638 // global object which is between interceptor and callbacks' holders.
11639 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11640   v8::Isolate* isolate = CcTest::isolate();
11641   v8::HandleScope scope(isolate);
11642   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11643   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11644   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11645   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11646
11647   LocalContext context;
11648   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11649   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11650
11651   v8::Handle<Value> value = CompileRun(
11652     "o.__proto__ = this;"
11653     "this.__proto__ = p;"
11654     "for (var i = 0; i < 10; i++) {"
11655     "  if (o.y != 239) throw 'oops: ' + o.y;"
11656     // Now it should be ICed and keep a reference to y defined on p
11657     "}"
11658     "this.y = 42;"
11659     "var result = 0;"
11660     "for (var i = 0; i < 10; i++) {"
11661     "  result += o.y;"
11662     "}"
11663     "result");
11664   CHECK_EQ(42 * 10, value->Int32Value());
11665 }
11666
11667
11668 static void InterceptorLoadICGetter0(
11669     Local<String> name,
11670     const v8::PropertyCallbackInfo<v8::Value>& info) {
11671   ApiTestFuzzer::Fuzz();
11672   CHECK(v8_str("x")->Equals(name));
11673   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11674 }
11675
11676
11677 THREADED_TEST(InterceptorReturningZero) {
11678   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11679      "o.x == undefined ? 1 : 0",
11680      0);
11681 }
11682
11683
11684 static void InterceptorStoreICSetter(
11685     Local<String> key,
11686     Local<Value> value,
11687     const v8::PropertyCallbackInfo<v8::Value>& info) {
11688   CHECK(v8_str("x")->Equals(key));
11689   CHECK_EQ(42, value->Int32Value());
11690   info.GetReturnValue().Set(value);
11691 }
11692
11693
11694 // This test should hit the store IC for the interceptor case.
11695 THREADED_TEST(InterceptorStoreIC) {
11696   v8::Isolate* isolate = CcTest::isolate();
11697   v8::HandleScope scope(isolate);
11698   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11699   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11700                                  InterceptorStoreICSetter,
11701                                  0, 0, 0, v8_str("data"));
11702   LocalContext context;
11703   context->Global()->Set(v8_str("o"), templ->NewInstance());
11704   CompileRun(
11705       "for (var i = 0; i < 1000; i++) {"
11706       "  o.x = 42;"
11707       "}");
11708 }
11709
11710
11711 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11712   v8::Isolate* isolate = CcTest::isolate();
11713   v8::HandleScope scope(isolate);
11714   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11715   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11716   LocalContext context;
11717   context->Global()->Set(v8_str("o"), templ->NewInstance());
11718   v8::Handle<Value> value = CompileRun(
11719     "for (var i = 0; i < 1000; i++) {"
11720     "  o.y = 239;"
11721     "}"
11722     "42 + o.y");
11723   CHECK_EQ(239 + 42, value->Int32Value());
11724 }
11725
11726
11727
11728
11729 v8::Handle<Value> call_ic_function;
11730 v8::Handle<Value> call_ic_function2;
11731 v8::Handle<Value> call_ic_function3;
11732
11733 static void InterceptorCallICGetter(
11734     Local<String> name,
11735     const v8::PropertyCallbackInfo<v8::Value>& info) {
11736   ApiTestFuzzer::Fuzz();
11737   CHECK(v8_str("x")->Equals(name));
11738   info.GetReturnValue().Set(call_ic_function);
11739 }
11740
11741
11742 // This test should hit the call IC for the interceptor case.
11743 THREADED_TEST(InterceptorCallIC) {
11744   v8::Isolate* isolate = CcTest::isolate();
11745   v8::HandleScope scope(isolate);
11746   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11747   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11748   LocalContext context;
11749   context->Global()->Set(v8_str("o"), templ->NewInstance());
11750   call_ic_function =
11751       v8_compile("function f(x) { return x + 1; }; f")->Run();
11752   v8::Handle<Value> value = CompileRun(
11753     "var result = 0;"
11754     "for (var i = 0; i < 1000; i++) {"
11755     "  result = o.x(41);"
11756     "}");
11757   CHECK_EQ(42, value->Int32Value());
11758 }
11759
11760
11761 // This test checks that if interceptor doesn't provide
11762 // a value, we can fetch regular value.
11763 THREADED_TEST(InterceptorCallICSeesOthers) {
11764   v8::Isolate* isolate = CcTest::isolate();
11765   v8::HandleScope scope(isolate);
11766   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11767   templ->SetNamedPropertyHandler(NoBlockGetterX);
11768   LocalContext context;
11769   context->Global()->Set(v8_str("o"), templ->NewInstance());
11770   v8::Handle<Value> value = CompileRun(
11771     "o.x = function f(x) { return x + 1; };"
11772     "var result = 0;"
11773     "for (var i = 0; i < 7; i++) {"
11774     "  result = o.x(41);"
11775     "}");
11776   CHECK_EQ(42, value->Int32Value());
11777 }
11778
11779
11780 static v8::Handle<Value> call_ic_function4;
11781 static void InterceptorCallICGetter4(
11782     Local<String> name,
11783     const v8::PropertyCallbackInfo<v8::Value>& info) {
11784   ApiTestFuzzer::Fuzz();
11785   CHECK(v8_str("x")->Equals(name));
11786   info.GetReturnValue().Set(call_ic_function4);
11787 }
11788
11789
11790 // This test checks that if interceptor provides a function,
11791 // even if we cached shadowed variant, interceptor's function
11792 // is invoked
11793 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11794   v8::Isolate* isolate = CcTest::isolate();
11795   v8::HandleScope scope(isolate);
11796   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11797   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11798   LocalContext context;
11799   context->Global()->Set(v8_str("o"), templ->NewInstance());
11800   call_ic_function4 =
11801       v8_compile("function f(x) { return x - 1; }; f")->Run();
11802   v8::Handle<Value> value = CompileRun(
11803     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11804     "var result = 0;"
11805     "for (var i = 0; i < 1000; i++) {"
11806     "  result = o.x(42);"
11807     "}");
11808   CHECK_EQ(41, value->Int32Value());
11809 }
11810
11811
11812 // Test the case when we stored cacheable lookup into
11813 // a stub, but it got invalidated later on
11814 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11815   v8::Isolate* isolate = CcTest::isolate();
11816   v8::HandleScope scope(isolate);
11817   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11818   templ->SetNamedPropertyHandler(NoBlockGetterX);
11819   LocalContext context;
11820   context->Global()->Set(v8_str("o"), templ->NewInstance());
11821   v8::Handle<Value> value = CompileRun(
11822     "proto1 = new Object();"
11823     "proto2 = new Object();"
11824     "o.__proto__ = proto1;"
11825     "proto1.__proto__ = proto2;"
11826     "proto2.y = function(x) { return x + 1; };"
11827     // Invoke it many times to compile a stub
11828     "for (var i = 0; i < 7; i++) {"
11829     "  o.y(42);"
11830     "}"
11831     "proto1.y = function(x) { return x - 1; };"
11832     "var result = 0;"
11833     "for (var i = 0; i < 7; i++) {"
11834     "  result += o.y(42);"
11835     "}");
11836   CHECK_EQ(41 * 7, value->Int32Value());
11837 }
11838
11839
11840 // This test checks that if interceptor doesn't provide a function,
11841 // cached constant function is used
11842 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11843   v8::Isolate* isolate = CcTest::isolate();
11844   v8::HandleScope scope(isolate);
11845   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11846   templ->SetNamedPropertyHandler(NoBlockGetterX);
11847   LocalContext context;
11848   context->Global()->Set(v8_str("o"), templ->NewInstance());
11849   v8::Handle<Value> value = CompileRun(
11850     "function inc(x) { return x + 1; };"
11851     "inc(1);"
11852     "o.x = inc;"
11853     "var result = 0;"
11854     "for (var i = 0; i < 1000; i++) {"
11855     "  result = o.x(42);"
11856     "}");
11857   CHECK_EQ(43, value->Int32Value());
11858 }
11859
11860
11861 static v8::Handle<Value> call_ic_function5;
11862 static void InterceptorCallICGetter5(
11863     Local<String> name,
11864     const v8::PropertyCallbackInfo<v8::Value>& info) {
11865   ApiTestFuzzer::Fuzz();
11866   if (v8_str("x")->Equals(name))
11867     info.GetReturnValue().Set(call_ic_function5);
11868 }
11869
11870
11871 // This test checks that if interceptor provides a function,
11872 // even if we cached constant function, interceptor's function
11873 // is invoked
11874 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11875   v8::Isolate* isolate = CcTest::isolate();
11876   v8::HandleScope scope(isolate);
11877   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11878   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11879   LocalContext context;
11880   context->Global()->Set(v8_str("o"), templ->NewInstance());
11881   call_ic_function5 =
11882       v8_compile("function f(x) { return x - 1; }; f")->Run();
11883   v8::Handle<Value> value = CompileRun(
11884     "function inc(x) { return x + 1; };"
11885     "inc(1);"
11886     "o.x = inc;"
11887     "var result = 0;"
11888     "for (var i = 0; i < 1000; i++) {"
11889     "  result = o.x(42);"
11890     "}");
11891   CHECK_EQ(41, value->Int32Value());
11892 }
11893
11894
11895 static v8::Handle<Value> call_ic_function6;
11896 static void InterceptorCallICGetter6(
11897     Local<String> name,
11898     const v8::PropertyCallbackInfo<v8::Value>& info) {
11899   ApiTestFuzzer::Fuzz();
11900   if (v8_str("x")->Equals(name))
11901     info.GetReturnValue().Set(call_ic_function6);
11902 }
11903
11904
11905 // Same test as above, except the code is wrapped in a function
11906 // to test the optimized compiler.
11907 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11908   i::FLAG_allow_natives_syntax = true;
11909   v8::Isolate* isolate = CcTest::isolate();
11910   v8::HandleScope scope(isolate);
11911   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11912   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11913   LocalContext context;
11914   context->Global()->Set(v8_str("o"), templ->NewInstance());
11915   call_ic_function6 =
11916       v8_compile("function f(x) { return x - 1; }; f")->Run();
11917   v8::Handle<Value> value = CompileRun(
11918     "function inc(x) { return x + 1; };"
11919     "inc(1);"
11920     "o.x = inc;"
11921     "function test() {"
11922     "  var result = 0;"
11923     "  for (var i = 0; i < 1000; i++) {"
11924     "    result = o.x(42);"
11925     "  }"
11926     "  return result;"
11927     "};"
11928     "test();"
11929     "test();"
11930     "test();"
11931     "%OptimizeFunctionOnNextCall(test);"
11932     "test()");
11933   CHECK_EQ(41, value->Int32Value());
11934 }
11935
11936
11937 // Test the case when we stored constant function into
11938 // a stub, but it got invalidated later on
11939 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11940   v8::Isolate* isolate = CcTest::isolate();
11941   v8::HandleScope scope(isolate);
11942   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11943   templ->SetNamedPropertyHandler(NoBlockGetterX);
11944   LocalContext context;
11945   context->Global()->Set(v8_str("o"), templ->NewInstance());
11946   v8::Handle<Value> value = CompileRun(
11947     "function inc(x) { return x + 1; };"
11948     "inc(1);"
11949     "proto1 = new Object();"
11950     "proto2 = new Object();"
11951     "o.__proto__ = proto1;"
11952     "proto1.__proto__ = proto2;"
11953     "proto2.y = inc;"
11954     // Invoke it many times to compile a stub
11955     "for (var i = 0; i < 7; i++) {"
11956     "  o.y(42);"
11957     "}"
11958     "proto1.y = function(x) { return x - 1; };"
11959     "var result = 0;"
11960     "for (var i = 0; i < 7; i++) {"
11961     "  result += o.y(42);"
11962     "}");
11963   CHECK_EQ(41 * 7, value->Int32Value());
11964 }
11965
11966
11967 // Test the case when we stored constant function into
11968 // a stub, but it got invalidated later on due to override on
11969 // global object which is between interceptor and constant function' holders.
11970 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11971   v8::Isolate* isolate = CcTest::isolate();
11972   v8::HandleScope scope(isolate);
11973   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11974   templ->SetNamedPropertyHandler(NoBlockGetterX);
11975   LocalContext context;
11976   context->Global()->Set(v8_str("o"), templ->NewInstance());
11977   v8::Handle<Value> value = CompileRun(
11978     "function inc(x) { return x + 1; };"
11979     "inc(1);"
11980     "o.__proto__ = this;"
11981     "this.__proto__.y = inc;"
11982     // Invoke it many times to compile a stub
11983     "for (var i = 0; i < 7; i++) {"
11984     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11985     "}"
11986     "this.y = function(x) { return x - 1; };"
11987     "var result = 0;"
11988     "for (var i = 0; i < 7; i++) {"
11989     "  result += o.y(42);"
11990     "}");
11991   CHECK_EQ(41 * 7, value->Int32Value());
11992 }
11993
11994
11995 // Test the case when actual function to call sits on global object.
11996 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11997   v8::Isolate* isolate = CcTest::isolate();
11998   v8::HandleScope scope(isolate);
11999   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12000   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12001
12002   LocalContext context;
12003   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12004
12005   v8::Handle<Value> value = CompileRun(
12006     "try {"
12007     "  o.__proto__ = this;"
12008     "  for (var i = 0; i < 10; i++) {"
12009     "    var v = o.parseFloat('239');"
12010     "    if (v != 239) throw v;"
12011       // Now it should be ICed and keep a reference to parseFloat.
12012     "  }"
12013     "  var result = 0;"
12014     "  for (var i = 0; i < 10; i++) {"
12015     "    result += o.parseFloat('239');"
12016     "  }"
12017     "  result"
12018     "} catch(e) {"
12019     "  e"
12020     "};");
12021   CHECK_EQ(239 * 10, value->Int32Value());
12022 }
12023
12024 static void InterceptorCallICFastApi(
12025     Local<String> name,
12026     const v8::PropertyCallbackInfo<v8::Value>& info) {
12027   ApiTestFuzzer::Fuzz();
12028   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12029   int* call_count =
12030       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12031   ++(*call_count);
12032   if ((*call_count) % 20 == 0) {
12033     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12034   }
12035 }
12036
12037 static void FastApiCallback_TrivialSignature(
12038     const v8::FunctionCallbackInfo<v8::Value>& args) {
12039   ApiTestFuzzer::Fuzz();
12040   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12041   v8::Isolate* isolate = CcTest::isolate();
12042   CHECK_EQ(isolate, args.GetIsolate());
12043   CHECK_EQ(args.This(), args.Holder());
12044   CHECK(args.Data()->Equals(v8_str("method_data")));
12045   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12046 }
12047
12048 static void FastApiCallback_SimpleSignature(
12049     const v8::FunctionCallbackInfo<v8::Value>& args) {
12050   ApiTestFuzzer::Fuzz();
12051   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12052   v8::Isolate* isolate = CcTest::isolate();
12053   CHECK_EQ(isolate, args.GetIsolate());
12054   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12055   CHECK(args.Data()->Equals(v8_str("method_data")));
12056   // Note, we're using HasRealNamedProperty instead of Has to avoid
12057   // invoking the interceptor again.
12058   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12059   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12060 }
12061
12062
12063 // Helper to maximize the odds of object moving.
12064 static void GenerateSomeGarbage() {
12065   CompileRun(
12066       "var garbage;"
12067       "for (var i = 0; i < 1000; i++) {"
12068       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12069       "}"
12070       "garbage = undefined;");
12071 }
12072
12073
12074 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12075   static int count = 0;
12076   if (count++ % 3 == 0) {
12077     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12078         // This should move the stub
12079     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12080   }
12081 }
12082
12083
12084 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12085   LocalContext context;
12086   v8::Isolate* isolate = context->GetIsolate();
12087   v8::HandleScope scope(isolate);
12088   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12089       v8::ObjectTemplate::New(isolate);
12090   nativeobject_templ->Set(isolate, "callback",
12091                           v8::FunctionTemplate::New(isolate,
12092                                                     DirectApiCallback));
12093   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12094   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12095   // call the api function multiple times to ensure direct call stub creation.
12096   CompileRun(
12097         "function f() {"
12098         "  for (var i = 1; i <= 30; i++) {"
12099         "    nativeobject.callback();"
12100         "  }"
12101         "}"
12102         "f();");
12103 }
12104
12105
12106 void ThrowingDirectApiCallback(
12107     const v8::FunctionCallbackInfo<v8::Value>& args) {
12108   args.GetIsolate()->ThrowException(v8_str("g"));
12109 }
12110
12111
12112 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12113   LocalContext context;
12114   v8::Isolate* isolate = context->GetIsolate();
12115   v8::HandleScope scope(isolate);
12116   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12117       v8::ObjectTemplate::New(isolate);
12118   nativeobject_templ->Set(isolate, "callback",
12119                           v8::FunctionTemplate::New(isolate,
12120                                                     ThrowingDirectApiCallback));
12121   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12122   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12123   // call the api function multiple times to ensure direct call stub creation.
12124   v8::Handle<Value> result = CompileRun(
12125       "var result = '';"
12126       "function f() {"
12127       "  for (var i = 1; i <= 5; i++) {"
12128       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12129       "  }"
12130       "}"
12131       "f(); result;");
12132   CHECK_EQ(v8_str("ggggg"), result);
12133 }
12134
12135
12136 static Handle<Value> DoDirectGetter() {
12137   if (++p_getter_count % 3 == 0) {
12138     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12139     GenerateSomeGarbage();
12140   }
12141   return v8_str("Direct Getter Result");
12142 }
12143
12144 static void DirectGetterCallback(
12145     Local<String> name,
12146     const v8::PropertyCallbackInfo<v8::Value>& info) {
12147   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12148   info.GetReturnValue().Set(DoDirectGetter());
12149 }
12150
12151
12152 template<typename Accessor>
12153 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12154   LocalContext context;
12155   v8::Isolate* isolate = context->GetIsolate();
12156   v8::HandleScope scope(isolate);
12157   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12158   obj->SetAccessor(v8_str("p1"), accessor);
12159   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12160   p_getter_count = 0;
12161   v8::Handle<v8::Value> result = CompileRun(
12162       "function f() {"
12163       "  for (var i = 0; i < 30; i++) o1.p1;"
12164       "  return o1.p1"
12165       "}"
12166       "f();");
12167   CHECK_EQ(v8_str("Direct Getter Result"), result);
12168   CHECK_EQ(31, p_getter_count);
12169 }
12170
12171
12172 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12173   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12174 }
12175
12176
12177 void ThrowingDirectGetterCallback(
12178     Local<String> name,
12179     const v8::PropertyCallbackInfo<v8::Value>& info) {
12180   info.GetIsolate()->ThrowException(v8_str("g"));
12181 }
12182
12183
12184 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12185   LocalContext context;
12186   v8::Isolate* isolate = context->GetIsolate();
12187   v8::HandleScope scope(isolate);
12188   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12189   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12190   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12191   v8::Handle<Value> result = CompileRun(
12192       "var result = '';"
12193       "for (var i = 0; i < 5; i++) {"
12194       "    try { o1.p1; } catch (e) { result += e; }"
12195       "}"
12196       "result;");
12197   CHECK_EQ(v8_str("ggggg"), result);
12198 }
12199
12200
12201 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12202   int interceptor_call_count = 0;
12203   v8::Isolate* isolate = CcTest::isolate();
12204   v8::HandleScope scope(isolate);
12205   v8::Handle<v8::FunctionTemplate> fun_templ =
12206       v8::FunctionTemplate::New(isolate);
12207   v8::Handle<v8::FunctionTemplate> method_templ =
12208       v8::FunctionTemplate::New(isolate,
12209                                 FastApiCallback_TrivialSignature,
12210                                 v8_str("method_data"),
12211                                 v8::Handle<v8::Signature>());
12212   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12213   proto_templ->Set(v8_str("method"), method_templ);
12214   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12215   templ->SetNamedPropertyHandler(
12216       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12217       v8::External::New(isolate, &interceptor_call_count));
12218   LocalContext context;
12219   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12220   GenerateSomeGarbage();
12221   context->Global()->Set(v8_str("o"), fun->NewInstance());
12222   CompileRun(
12223       "var result = 0;"
12224       "for (var i = 0; i < 100; i++) {"
12225       "  result = o.method(41);"
12226       "}");
12227   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12228   CHECK_EQ(100, interceptor_call_count);
12229 }
12230
12231
12232 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12233   int interceptor_call_count = 0;
12234   v8::Isolate* isolate = CcTest::isolate();
12235   v8::HandleScope scope(isolate);
12236   v8::Handle<v8::FunctionTemplate> fun_templ =
12237       v8::FunctionTemplate::New(isolate);
12238   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12239       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12240       v8::Signature::New(isolate, fun_templ));
12241   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12242   proto_templ->Set(v8_str("method"), method_templ);
12243   fun_templ->SetHiddenPrototype(true);
12244   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12245   templ->SetNamedPropertyHandler(
12246       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12247       v8::External::New(isolate, &interceptor_call_count));
12248   LocalContext context;
12249   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12250   GenerateSomeGarbage();
12251   context->Global()->Set(v8_str("o"), fun->NewInstance());
12252   CompileRun(
12253       "o.foo = 17;"
12254       "var receiver = {};"
12255       "receiver.__proto__ = o;"
12256       "var result = 0;"
12257       "for (var i = 0; i < 100; i++) {"
12258       "  result = receiver.method(41);"
12259       "}");
12260   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12261   CHECK_EQ(100, interceptor_call_count);
12262 }
12263
12264
12265 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12266   int interceptor_call_count = 0;
12267   v8::Isolate* isolate = CcTest::isolate();
12268   v8::HandleScope scope(isolate);
12269   v8::Handle<v8::FunctionTemplate> fun_templ =
12270       v8::FunctionTemplate::New(isolate);
12271   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12272       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12273       v8::Signature::New(isolate, fun_templ));
12274   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12275   proto_templ->Set(v8_str("method"), method_templ);
12276   fun_templ->SetHiddenPrototype(true);
12277   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12278   templ->SetNamedPropertyHandler(
12279       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12280       v8::External::New(isolate, &interceptor_call_count));
12281   LocalContext context;
12282   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12283   GenerateSomeGarbage();
12284   context->Global()->Set(v8_str("o"), fun->NewInstance());
12285   CompileRun(
12286       "o.foo = 17;"
12287       "var receiver = {};"
12288       "receiver.__proto__ = o;"
12289       "var result = 0;"
12290       "var saved_result = 0;"
12291       "for (var i = 0; i < 100; i++) {"
12292       "  result = receiver.method(41);"
12293       "  if (i == 50) {"
12294       "    saved_result = result;"
12295       "    receiver = {method: function(x) { return x - 1 }};"
12296       "  }"
12297       "}");
12298   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12299   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12300   CHECK_GE(interceptor_call_count, 50);
12301 }
12302
12303
12304 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12305   int interceptor_call_count = 0;
12306   v8::Isolate* isolate = CcTest::isolate();
12307   v8::HandleScope scope(isolate);
12308   v8::Handle<v8::FunctionTemplate> fun_templ =
12309       v8::FunctionTemplate::New(isolate);
12310   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12311       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12312       v8::Signature::New(isolate, fun_templ));
12313   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12314   proto_templ->Set(v8_str("method"), method_templ);
12315   fun_templ->SetHiddenPrototype(true);
12316   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12317   templ->SetNamedPropertyHandler(
12318       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12319       v8::External::New(isolate, &interceptor_call_count));
12320   LocalContext context;
12321   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12322   GenerateSomeGarbage();
12323   context->Global()->Set(v8_str("o"), fun->NewInstance());
12324   CompileRun(
12325       "o.foo = 17;"
12326       "var receiver = {};"
12327       "receiver.__proto__ = o;"
12328       "var result = 0;"
12329       "var saved_result = 0;"
12330       "for (var i = 0; i < 100; i++) {"
12331       "  result = receiver.method(41);"
12332       "  if (i == 50) {"
12333       "    saved_result = result;"
12334       "    o.method = function(x) { return x - 1 };"
12335       "  }"
12336       "}");
12337   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12338   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12339   CHECK_GE(interceptor_call_count, 50);
12340 }
12341
12342
12343 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12344   int interceptor_call_count = 0;
12345   v8::Isolate* isolate = CcTest::isolate();
12346   v8::HandleScope scope(isolate);
12347   v8::Handle<v8::FunctionTemplate> fun_templ =
12348       v8::FunctionTemplate::New(isolate);
12349   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12350       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12351       v8::Signature::New(isolate, fun_templ));
12352   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12353   proto_templ->Set(v8_str("method"), method_templ);
12354   fun_templ->SetHiddenPrototype(true);
12355   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12356   templ->SetNamedPropertyHandler(
12357       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12358       v8::External::New(isolate, &interceptor_call_count));
12359   LocalContext context;
12360   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12361   GenerateSomeGarbage();
12362   context->Global()->Set(v8_str("o"), fun->NewInstance());
12363   v8::TryCatch try_catch;
12364   CompileRun(
12365       "o.foo = 17;"
12366       "var receiver = {};"
12367       "receiver.__proto__ = o;"
12368       "var result = 0;"
12369       "var saved_result = 0;"
12370       "for (var i = 0; i < 100; i++) {"
12371       "  result = receiver.method(41);"
12372       "  if (i == 50) {"
12373       "    saved_result = result;"
12374       "    receiver = 333;"
12375       "  }"
12376       "}");
12377   CHECK(try_catch.HasCaught());
12378   // TODO(verwaest): Adjust message.
12379   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12380            try_catch.Exception()->ToString());
12381   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12382   CHECK_GE(interceptor_call_count, 50);
12383 }
12384
12385
12386 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12387   int interceptor_call_count = 0;
12388   v8::Isolate* isolate = CcTest::isolate();
12389   v8::HandleScope scope(isolate);
12390   v8::Handle<v8::FunctionTemplate> fun_templ =
12391       v8::FunctionTemplate::New(isolate);
12392   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12393       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12394       v8::Signature::New(isolate, fun_templ));
12395   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12396   proto_templ->Set(v8_str("method"), method_templ);
12397   fun_templ->SetHiddenPrototype(true);
12398   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12399   templ->SetNamedPropertyHandler(
12400       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12401       v8::External::New(isolate, &interceptor_call_count));
12402   LocalContext context;
12403   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12404   GenerateSomeGarbage();
12405   context->Global()->Set(v8_str("o"), fun->NewInstance());
12406   v8::TryCatch try_catch;
12407   CompileRun(
12408       "o.foo = 17;"
12409       "var receiver = {};"
12410       "receiver.__proto__ = o;"
12411       "var result = 0;"
12412       "var saved_result = 0;"
12413       "for (var i = 0; i < 100; i++) {"
12414       "  result = receiver.method(41);"
12415       "  if (i == 50) {"
12416       "    saved_result = result;"
12417       "    receiver = {method: receiver.method};"
12418       "  }"
12419       "}");
12420   CHECK(try_catch.HasCaught());
12421   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12422            try_catch.Exception()->ToString());
12423   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12424   CHECK_GE(interceptor_call_count, 50);
12425 }
12426
12427
12428 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12429   v8::Isolate* isolate = CcTest::isolate();
12430   v8::HandleScope scope(isolate);
12431   v8::Handle<v8::FunctionTemplate> fun_templ =
12432       v8::FunctionTemplate::New(isolate);
12433   v8::Handle<v8::FunctionTemplate> method_templ =
12434       v8::FunctionTemplate::New(isolate,
12435                                 FastApiCallback_TrivialSignature,
12436                                 v8_str("method_data"),
12437                                 v8::Handle<v8::Signature>());
12438   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12439   proto_templ->Set(v8_str("method"), method_templ);
12440   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12441   USE(templ);
12442   LocalContext context;
12443   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12444   GenerateSomeGarbage();
12445   context->Global()->Set(v8_str("o"), fun->NewInstance());
12446   CompileRun(
12447       "var result = 0;"
12448       "for (var i = 0; i < 100; i++) {"
12449       "  result = o.method(41);"
12450       "}");
12451
12452   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12453 }
12454
12455
12456 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12457   v8::Isolate* isolate = CcTest::isolate();
12458   v8::HandleScope scope(isolate);
12459   v8::Handle<v8::FunctionTemplate> fun_templ =
12460       v8::FunctionTemplate::New(isolate);
12461   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12462       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12463       v8::Signature::New(isolate, fun_templ));
12464   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12465   proto_templ->Set(v8_str("method"), method_templ);
12466   fun_templ->SetHiddenPrototype(true);
12467   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12468   CHECK(!templ.IsEmpty());
12469   LocalContext context;
12470   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12471   GenerateSomeGarbage();
12472   context->Global()->Set(v8_str("o"), fun->NewInstance());
12473   CompileRun(
12474       "o.foo = 17;"
12475       "var receiver = {};"
12476       "receiver.__proto__ = o;"
12477       "var result = 0;"
12478       "for (var i = 0; i < 100; i++) {"
12479       "  result = receiver.method(41);"
12480       "}");
12481
12482   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12483 }
12484
12485
12486 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12487   v8::Isolate* isolate = CcTest::isolate();
12488   v8::HandleScope scope(isolate);
12489   v8::Handle<v8::FunctionTemplate> fun_templ =
12490       v8::FunctionTemplate::New(isolate);
12491   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12492       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12493       v8::Signature::New(isolate, fun_templ));
12494   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12495   proto_templ->Set(v8_str("method"), method_templ);
12496   fun_templ->SetHiddenPrototype(true);
12497   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12498   CHECK(!templ.IsEmpty());
12499   LocalContext context;
12500   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12501   GenerateSomeGarbage();
12502   context->Global()->Set(v8_str("o"), fun->NewInstance());
12503   CompileRun(
12504       "o.foo = 17;"
12505       "var receiver = {};"
12506       "receiver.__proto__ = o;"
12507       "var result = 0;"
12508       "var saved_result = 0;"
12509       "for (var i = 0; i < 100; i++) {"
12510       "  result = receiver.method(41);"
12511       "  if (i == 50) {"
12512       "    saved_result = result;"
12513       "    receiver = {method: function(x) { return x - 1 }};"
12514       "  }"
12515       "}");
12516   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12517   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12518 }
12519
12520
12521 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12522   v8::Isolate* isolate = CcTest::isolate();
12523   v8::HandleScope scope(isolate);
12524   v8::Handle<v8::FunctionTemplate> fun_templ =
12525       v8::FunctionTemplate::New(isolate);
12526   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12527       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12528       v8::Signature::New(isolate, fun_templ));
12529   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12530   proto_templ->Set(v8_str("method"), method_templ);
12531   fun_templ->SetHiddenPrototype(true);
12532   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12533   CHECK(!templ.IsEmpty());
12534   LocalContext context;
12535   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12536   GenerateSomeGarbage();
12537   context->Global()->Set(v8_str("o"), fun->NewInstance());
12538   v8::TryCatch try_catch;
12539   CompileRun(
12540       "o.foo = 17;"
12541       "var receiver = {};"
12542       "receiver.__proto__ = o;"
12543       "var result = 0;"
12544       "var saved_result = 0;"
12545       "for (var i = 0; i < 100; i++) {"
12546       "  result = receiver.method(41);"
12547       "  if (i == 50) {"
12548       "    saved_result = result;"
12549       "    receiver = 333;"
12550       "  }"
12551       "}");
12552   CHECK(try_catch.HasCaught());
12553   // TODO(verwaest): Adjust message.
12554   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12555            try_catch.Exception()->ToString());
12556   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12557 }
12558
12559
12560 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12561   v8::Isolate* isolate = CcTest::isolate();
12562   v8::HandleScope scope(isolate);
12563   v8::Handle<v8::FunctionTemplate> fun_templ =
12564       v8::FunctionTemplate::New(isolate);
12565   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12566       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12567       v8::Signature::New(isolate, fun_templ));
12568   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12569   proto_templ->Set(v8_str("method"), method_templ);
12570   fun_templ->SetHiddenPrototype(true);
12571   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12572   CHECK(!templ.IsEmpty());
12573   LocalContext context;
12574   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12575   GenerateSomeGarbage();
12576   context->Global()->Set(v8_str("o"), fun->NewInstance());
12577   v8::TryCatch try_catch;
12578   CompileRun(
12579       "o.foo = 17;"
12580       "var receiver = {};"
12581       "receiver.__proto__ = o;"
12582       "var result = 0;"
12583       "var saved_result = 0;"
12584       "for (var i = 0; i < 100; i++) {"
12585       "  result = receiver.method(41);"
12586       "  if (i == 50) {"
12587       "    saved_result = result;"
12588       "    receiver = Object.create(receiver);"
12589       "  }"
12590       "}");
12591   CHECK(try_catch.HasCaught());
12592   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12593            try_catch.Exception()->ToString());
12594   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12595 }
12596
12597
12598 v8::Handle<Value> keyed_call_ic_function;
12599
12600 static void InterceptorKeyedCallICGetter(
12601     Local<String> name,
12602     const v8::PropertyCallbackInfo<v8::Value>& info) {
12603   ApiTestFuzzer::Fuzz();
12604   if (v8_str("x")->Equals(name)) {
12605     info.GetReturnValue().Set(keyed_call_ic_function);
12606   }
12607 }
12608
12609
12610 // Test the case when we stored cacheable lookup into
12611 // a stub, but the function name changed (to another cacheable function).
12612 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12613   v8::Isolate* isolate = CcTest::isolate();
12614   v8::HandleScope scope(isolate);
12615   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12616   templ->SetNamedPropertyHandler(NoBlockGetterX);
12617   LocalContext context;
12618   context->Global()->Set(v8_str("o"), templ->NewInstance());
12619   CompileRun(
12620     "proto = new Object();"
12621     "proto.y = function(x) { return x + 1; };"
12622     "proto.z = function(x) { return x - 1; };"
12623     "o.__proto__ = proto;"
12624     "var result = 0;"
12625     "var method = 'y';"
12626     "for (var i = 0; i < 10; i++) {"
12627     "  if (i == 5) { method = 'z'; };"
12628     "  result += o[method](41);"
12629     "}");
12630   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12631 }
12632
12633
12634 // Test the case when we stored cacheable lookup into
12635 // a stub, but the function name changed (and the new function is present
12636 // both before and after the interceptor in the prototype chain).
12637 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12638   v8::Isolate* isolate = CcTest::isolate();
12639   v8::HandleScope scope(isolate);
12640   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12641   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12642   LocalContext context;
12643   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12644   keyed_call_ic_function =
12645       v8_compile("function f(x) { return x - 1; }; f")->Run();
12646   CompileRun(
12647     "o = new Object();"
12648     "proto2 = new Object();"
12649     "o.y = function(x) { return x + 1; };"
12650     "proto2.y = function(x) { return x + 2; };"
12651     "o.__proto__ = proto1;"
12652     "proto1.__proto__ = proto2;"
12653     "var result = 0;"
12654     "var method = 'x';"
12655     "for (var i = 0; i < 10; i++) {"
12656     "  if (i == 5) { method = 'y'; };"
12657     "  result += o[method](41);"
12658     "}");
12659   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12660 }
12661
12662
12663 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12664 // on the global object.
12665 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12666   v8::Isolate* isolate = CcTest::isolate();
12667   v8::HandleScope scope(isolate);
12668   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12669   templ->SetNamedPropertyHandler(NoBlockGetterX);
12670   LocalContext context;
12671   context->Global()->Set(v8_str("o"), templ->NewInstance());
12672   CompileRun(
12673     "function inc(x) { return x + 1; };"
12674     "inc(1);"
12675     "function dec(x) { return x - 1; };"
12676     "dec(1);"
12677     "o.__proto__ = this;"
12678     "this.__proto__.x = inc;"
12679     "this.__proto__.y = dec;"
12680     "var result = 0;"
12681     "var method = 'x';"
12682     "for (var i = 0; i < 10; i++) {"
12683     "  if (i == 5) { method = 'y'; };"
12684     "  result += o[method](41);"
12685     "}");
12686   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12687 }
12688
12689
12690 // Test the case when actual function to call sits on global object.
12691 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12692   v8::Isolate* isolate = CcTest::isolate();
12693   v8::HandleScope scope(isolate);
12694   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12695   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12696   LocalContext context;
12697   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12698
12699   CompileRun(
12700     "function len(x) { return x.length; };"
12701     "o.__proto__ = this;"
12702     "var m = 'parseFloat';"
12703     "var result = 0;"
12704     "for (var i = 0; i < 10; i++) {"
12705     "  if (i == 5) {"
12706     "    m = 'len';"
12707     "    saved_result = result;"
12708     "  };"
12709     "  result = o[m]('239');"
12710     "}");
12711   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12712   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12713 }
12714
12715
12716 // Test the map transition before the interceptor.
12717 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12718   v8::Isolate* isolate = CcTest::isolate();
12719   v8::HandleScope scope(isolate);
12720   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12721   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12722   LocalContext context;
12723   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12724
12725   CompileRun(
12726     "var o = new Object();"
12727     "o.__proto__ = proto;"
12728     "o.method = function(x) { return x + 1; };"
12729     "var m = 'method';"
12730     "var result = 0;"
12731     "for (var i = 0; i < 10; i++) {"
12732     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12733     "  result += o[m](41);"
12734     "}");
12735   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12736 }
12737
12738
12739 // Test the map transition after the interceptor.
12740 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12741   v8::Isolate* isolate = CcTest::isolate();
12742   v8::HandleScope scope(isolate);
12743   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12744   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12745   LocalContext context;
12746   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12747
12748   CompileRun(
12749     "var proto = new Object();"
12750     "o.__proto__ = proto;"
12751     "proto.method = function(x) { return x + 1; };"
12752     "var m = 'method';"
12753     "var result = 0;"
12754     "for (var i = 0; i < 10; i++) {"
12755     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12756     "  result += o[m](41);"
12757     "}");
12758   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12759 }
12760
12761
12762 static int interceptor_call_count = 0;
12763
12764 static void InterceptorICRefErrorGetter(
12765     Local<String> name,
12766     const v8::PropertyCallbackInfo<v8::Value>& info) {
12767   ApiTestFuzzer::Fuzz();
12768   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12769     info.GetReturnValue().Set(call_ic_function2);
12770   }
12771 }
12772
12773
12774 // This test should hit load and call ICs for the interceptor case.
12775 // Once in a while, the interceptor will reply that a property was not
12776 // found in which case we should get a reference error.
12777 THREADED_TEST(InterceptorICReferenceErrors) {
12778   v8::Isolate* isolate = CcTest::isolate();
12779   v8::HandleScope scope(isolate);
12780   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12781   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12782   LocalContext context(0, templ, v8::Handle<Value>());
12783   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12784   v8::Handle<Value> value = CompileRun(
12785     "function f() {"
12786     "  for (var i = 0; i < 1000; i++) {"
12787     "    try { x; } catch(e) { return true; }"
12788     "  }"
12789     "  return false;"
12790     "};"
12791     "f();");
12792   CHECK_EQ(true, value->BooleanValue());
12793   interceptor_call_count = 0;
12794   value = CompileRun(
12795     "function g() {"
12796     "  for (var i = 0; i < 1000; i++) {"
12797     "    try { x(42); } catch(e) { return true; }"
12798     "  }"
12799     "  return false;"
12800     "};"
12801     "g();");
12802   CHECK_EQ(true, value->BooleanValue());
12803 }
12804
12805
12806 static int interceptor_ic_exception_get_count = 0;
12807
12808 static void InterceptorICExceptionGetter(
12809     Local<String> name,
12810     const v8::PropertyCallbackInfo<v8::Value>& info) {
12811   ApiTestFuzzer::Fuzz();
12812   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12813     info.GetReturnValue().Set(call_ic_function3);
12814   }
12815   if (interceptor_ic_exception_get_count == 20) {
12816     info.GetIsolate()->ThrowException(v8_num(42));
12817     return;
12818   }
12819 }
12820
12821
12822 // Test interceptor load/call IC where the interceptor throws an
12823 // exception once in a while.
12824 THREADED_TEST(InterceptorICGetterExceptions) {
12825   interceptor_ic_exception_get_count = 0;
12826   v8::Isolate* isolate = CcTest::isolate();
12827   v8::HandleScope scope(isolate);
12828   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12829   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12830   LocalContext context(0, templ, v8::Handle<Value>());
12831   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12832   v8::Handle<Value> value = CompileRun(
12833     "function f() {"
12834     "  for (var i = 0; i < 100; i++) {"
12835     "    try { x; } catch(e) { return true; }"
12836     "  }"
12837     "  return false;"
12838     "};"
12839     "f();");
12840   CHECK_EQ(true, value->BooleanValue());
12841   interceptor_ic_exception_get_count = 0;
12842   value = CompileRun(
12843     "function f() {"
12844     "  for (var i = 0; i < 100; i++) {"
12845     "    try { x(42); } catch(e) { return true; }"
12846     "  }"
12847     "  return false;"
12848     "};"
12849     "f();");
12850   CHECK_EQ(true, value->BooleanValue());
12851 }
12852
12853
12854 static int interceptor_ic_exception_set_count = 0;
12855
12856 static void InterceptorICExceptionSetter(
12857       Local<String> key,
12858       Local<Value> value,
12859       const v8::PropertyCallbackInfo<v8::Value>& info) {
12860   ApiTestFuzzer::Fuzz();
12861   if (++interceptor_ic_exception_set_count > 20) {
12862     info.GetIsolate()->ThrowException(v8_num(42));
12863   }
12864 }
12865
12866
12867 // Test interceptor store IC where the interceptor throws an exception
12868 // once in a while.
12869 THREADED_TEST(InterceptorICSetterExceptions) {
12870   interceptor_ic_exception_set_count = 0;
12871   v8::Isolate* isolate = CcTest::isolate();
12872   v8::HandleScope scope(isolate);
12873   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12874   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12875   LocalContext context(0, templ, v8::Handle<Value>());
12876   v8::Handle<Value> value = CompileRun(
12877     "function f() {"
12878     "  for (var i = 0; i < 100; i++) {"
12879     "    try { x = 42; } catch(e) { return true; }"
12880     "  }"
12881     "  return false;"
12882     "};"
12883     "f();");
12884   CHECK_EQ(true, value->BooleanValue());
12885 }
12886
12887
12888 // Test that we ignore null interceptors.
12889 THREADED_TEST(NullNamedInterceptor) {
12890   v8::Isolate* isolate = CcTest::isolate();
12891   v8::HandleScope scope(isolate);
12892   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12893   templ->SetNamedPropertyHandler(
12894       static_cast<v8::NamedPropertyGetterCallback>(0));
12895   LocalContext context;
12896   templ->Set(CcTest::isolate(), "x", v8_num(42));
12897   v8::Handle<v8::Object> obj = templ->NewInstance();
12898   context->Global()->Set(v8_str("obj"), obj);
12899   v8::Handle<Value> value = CompileRun("obj.x");
12900   CHECK(value->IsInt32());
12901   CHECK_EQ(42, value->Int32Value());
12902 }
12903
12904
12905 // Test that we ignore null interceptors.
12906 THREADED_TEST(NullIndexedInterceptor) {
12907   v8::Isolate* isolate = CcTest::isolate();
12908   v8::HandleScope scope(isolate);
12909   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12910   templ->SetIndexedPropertyHandler(
12911       static_cast<v8::IndexedPropertyGetterCallback>(0));
12912   LocalContext context;
12913   templ->Set(CcTest::isolate(), "42", v8_num(42));
12914   v8::Handle<v8::Object> obj = templ->NewInstance();
12915   context->Global()->Set(v8_str("obj"), obj);
12916   v8::Handle<Value> value = CompileRun("obj[42]");
12917   CHECK(value->IsInt32());
12918   CHECK_EQ(42, value->Int32Value());
12919 }
12920
12921
12922 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12923   v8::Isolate* isolate = CcTest::isolate();
12924   v8::HandleScope scope(isolate);
12925   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12926   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12927   LocalContext env;
12928   env->Global()->Set(v8_str("obj"),
12929                      templ->GetFunction()->NewInstance());
12930   ExpectTrue("obj.x === 42");
12931   ExpectTrue("!obj.propertyIsEnumerable('x')");
12932 }
12933
12934
12935 static void ThrowingGetter(Local<String> name,
12936                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12937   ApiTestFuzzer::Fuzz();
12938   info.GetIsolate()->ThrowException(Handle<Value>());
12939   info.GetReturnValue().SetUndefined();
12940 }
12941
12942
12943 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12944   LocalContext context;
12945   HandleScope scope(context->GetIsolate());
12946
12947   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12948   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12949   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12950
12951   Local<Object> instance = templ->GetFunction()->NewInstance();
12952
12953   Local<Object> another = Object::New(context->GetIsolate());
12954   another->SetPrototype(instance);
12955
12956   Local<Object> with_js_getter = CompileRun(
12957       "o = {};\n"
12958       "o.__defineGetter__('f', function() { throw undefined; });\n"
12959       "o\n").As<Object>();
12960   CHECK(!with_js_getter.IsEmpty());
12961
12962   TryCatch try_catch;
12963
12964   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12965   CHECK(try_catch.HasCaught());
12966   try_catch.Reset();
12967   CHECK(result.IsEmpty());
12968
12969   result = another->GetRealNamedProperty(v8_str("f"));
12970   CHECK(try_catch.HasCaught());
12971   try_catch.Reset();
12972   CHECK(result.IsEmpty());
12973
12974   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12975   CHECK(try_catch.HasCaught());
12976   try_catch.Reset();
12977   CHECK(result.IsEmpty());
12978
12979   result = another->Get(v8_str("f"));
12980   CHECK(try_catch.HasCaught());
12981   try_catch.Reset();
12982   CHECK(result.IsEmpty());
12983
12984   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12985   CHECK(try_catch.HasCaught());
12986   try_catch.Reset();
12987   CHECK(result.IsEmpty());
12988
12989   result = with_js_getter->Get(v8_str("f"));
12990   CHECK(try_catch.HasCaught());
12991   try_catch.Reset();
12992   CHECK(result.IsEmpty());
12993 }
12994
12995
12996 static void ThrowingCallbackWithTryCatch(
12997     const v8::FunctionCallbackInfo<v8::Value>& args) {
12998   TryCatch try_catch;
12999   // Verboseness is important: it triggers message delivery which can call into
13000   // external code.
13001   try_catch.SetVerbose(true);
13002   CompileRun("throw 'from JS';");
13003   CHECK(try_catch.HasCaught());
13004   CHECK(!CcTest::i_isolate()->has_pending_exception());
13005   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13006 }
13007
13008
13009 static int call_depth;
13010
13011
13012 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13013   TryCatch try_catch;
13014 }
13015
13016
13017 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13018   if (--call_depth) CompileRun("throw 'ThrowInJS';");
13019 }
13020
13021
13022 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13023   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13024 }
13025
13026
13027 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13028   Handle<String> errorMessageString = message->Get();
13029   CHECK(!errorMessageString.IsEmpty());
13030   message->GetStackTrace();
13031   message->GetScriptResourceName();
13032 }
13033
13034
13035 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13036   LocalContext context;
13037   v8::Isolate* isolate = context->GetIsolate();
13038   HandleScope scope(isolate);
13039
13040   Local<Function> func =
13041       FunctionTemplate::New(isolate,
13042                             ThrowingCallbackWithTryCatch)->GetFunction();
13043   context->Global()->Set(v8_str("func"), func);
13044
13045   MessageCallback callbacks[] =
13046       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13047   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13048     MessageCallback callback = callbacks[i];
13049     if (callback != NULL) {
13050       V8::AddMessageListener(callback);
13051     }
13052     // Some small number to control number of times message handler should
13053     // throw an exception.
13054     call_depth = 5;
13055     ExpectFalse(
13056         "var thrown = false;\n"
13057         "try { func(); } catch(e) { thrown = true; }\n"
13058         "thrown\n");
13059     if (callback != NULL) {
13060       V8::RemoveMessageListeners(callback);
13061     }
13062   }
13063 }
13064
13065
13066 static void ParentGetter(Local<String> name,
13067                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13068   ApiTestFuzzer::Fuzz();
13069   info.GetReturnValue().Set(v8_num(1));
13070 }
13071
13072
13073 static void ChildGetter(Local<String> name,
13074                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13075   ApiTestFuzzer::Fuzz();
13076   info.GetReturnValue().Set(v8_num(42));
13077 }
13078
13079
13080 THREADED_TEST(Overriding) {
13081   LocalContext context;
13082   v8::Isolate* isolate = context->GetIsolate();
13083   v8::HandleScope scope(isolate);
13084
13085   // Parent template.
13086   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13087   Local<ObjectTemplate> parent_instance_templ =
13088       parent_templ->InstanceTemplate();
13089   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13090
13091   // Template that inherits from the parent template.
13092   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13093   Local<ObjectTemplate> child_instance_templ =
13094       child_templ->InstanceTemplate();
13095   child_templ->Inherit(parent_templ);
13096   // Override 'f'.  The child version of 'f' should get called for child
13097   // instances.
13098   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13099   // Add 'g' twice.  The 'g' added last should get called for instances.
13100   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13101   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13102
13103   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13104   // so 'h' can be shadowed on the instance object.
13105   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13106   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13107       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13108
13109   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13110   // but the attribute does not have effect because it is duplicated with
13111   // NULL setter.
13112   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13113       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13114
13115
13116
13117   // Instantiate the child template.
13118   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13119
13120   // Check that the child function overrides the parent one.
13121   context->Global()->Set(v8_str("o"), instance);
13122   Local<Value> value = v8_compile("o.f")->Run();
13123   // Check that the 'g' that was added last is hit.
13124   CHECK_EQ(42, value->Int32Value());
13125   value = v8_compile("o.g")->Run();
13126   CHECK_EQ(42, value->Int32Value());
13127
13128   // Check that 'h' cannot be shadowed.
13129   value = v8_compile("o.h = 3; o.h")->Run();
13130   CHECK_EQ(1, value->Int32Value());
13131
13132   // Check that 'i' cannot be shadowed or changed.
13133   value = v8_compile("o.i = 3; o.i")->Run();
13134   CHECK_EQ(42, value->Int32Value());
13135 }
13136
13137
13138 static void IsConstructHandler(
13139     const v8::FunctionCallbackInfo<v8::Value>& args) {
13140   ApiTestFuzzer::Fuzz();
13141   args.GetReturnValue().Set(args.IsConstructCall());
13142 }
13143
13144
13145 THREADED_TEST(IsConstructCall) {
13146   v8::Isolate* isolate = CcTest::isolate();
13147   v8::HandleScope scope(isolate);
13148
13149   // Function template with call handler.
13150   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13151   templ->SetCallHandler(IsConstructHandler);
13152
13153   LocalContext context;
13154
13155   context->Global()->Set(v8_str("f"), templ->GetFunction());
13156   Local<Value> value = v8_compile("f()")->Run();
13157   CHECK(!value->BooleanValue());
13158   value = v8_compile("new f()")->Run();
13159   CHECK(value->BooleanValue());
13160 }
13161
13162
13163 THREADED_TEST(ObjectProtoToString) {
13164   v8::Isolate* isolate = CcTest::isolate();
13165   v8::HandleScope scope(isolate);
13166   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13167   templ->SetClassName(v8_str("MyClass"));
13168
13169   LocalContext context;
13170
13171   Local<String> customized_tostring = v8_str("customized toString");
13172
13173   // Replace Object.prototype.toString
13174   v8_compile("Object.prototype.toString = function() {"
13175                   "  return 'customized toString';"
13176                   "}")->Run();
13177
13178   // Normal ToString call should call replaced Object.prototype.toString
13179   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13180   Local<String> value = instance->ToString();
13181   CHECK(value->IsString() && value->Equals(customized_tostring));
13182
13183   // ObjectProtoToString should not call replace toString function.
13184   value = instance->ObjectProtoToString();
13185   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13186
13187   // Check global
13188   value = context->Global()->ObjectProtoToString();
13189   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13190
13191   // Check ordinary object
13192   Local<Value> object = v8_compile("new Object()")->Run();
13193   value = object.As<v8::Object>()->ObjectProtoToString();
13194   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13195 }
13196
13197
13198 THREADED_TEST(ObjectGetConstructorName) {
13199   LocalContext context;
13200   v8::HandleScope scope(context->GetIsolate());
13201   v8_compile("function Parent() {};"
13202              "function Child() {};"
13203              "Child.prototype = new Parent();"
13204              "var outer = { inner: function() { } };"
13205              "var p = new Parent();"
13206              "var c = new Child();"
13207              "var x = new outer.inner();")->Run();
13208
13209   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13210   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13211       v8_str("Parent")));
13212
13213   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13214   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13215       v8_str("Child")));
13216
13217   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13218   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13219       v8_str("outer.inner")));
13220 }
13221
13222
13223 bool ApiTestFuzzer::fuzzing_ = false;
13224 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13225 int ApiTestFuzzer::active_tests_;
13226 int ApiTestFuzzer::tests_being_run_;
13227 int ApiTestFuzzer::current_;
13228
13229
13230 // We are in a callback and want to switch to another thread (if we
13231 // are currently running the thread fuzzing test).
13232 void ApiTestFuzzer::Fuzz() {
13233   if (!fuzzing_) return;
13234   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13235   test->ContextSwitch();
13236 }
13237
13238
13239 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13240 // not start immediately.
13241 bool ApiTestFuzzer::NextThread() {
13242   int test_position = GetNextTestNumber();
13243   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13244   if (test_position == current_) {
13245     if (kLogThreading)
13246       printf("Stay with %s\n", test_name);
13247     return false;
13248   }
13249   if (kLogThreading) {
13250     printf("Switch from %s to %s\n",
13251            test_name,
13252            RegisterThreadedTest::nth(test_position)->name());
13253   }
13254   current_ = test_position;
13255   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13256   return true;
13257 }
13258
13259
13260 void ApiTestFuzzer::Run() {
13261   // When it is our turn...
13262   gate_.Wait();
13263   {
13264     // ... get the V8 lock and start running the test.
13265     v8::Locker locker(CcTest::isolate());
13266     CallTest();
13267   }
13268   // This test finished.
13269   active_ = false;
13270   active_tests_--;
13271   // If it was the last then signal that fact.
13272   if (active_tests_ == 0) {
13273     all_tests_done_.Signal();
13274   } else {
13275     // Otherwise select a new test and start that.
13276     NextThread();
13277   }
13278 }
13279
13280
13281 static unsigned linear_congruential_generator;
13282
13283
13284 void ApiTestFuzzer::SetUp(PartOfTest part) {
13285   linear_congruential_generator = i::FLAG_testing_prng_seed;
13286   fuzzing_ = true;
13287   int count = RegisterThreadedTest::count();
13288   int start =  count * part / (LAST_PART + 1);
13289   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13290   active_tests_ = tests_being_run_ = end - start + 1;
13291   for (int i = 0; i < tests_being_run_; i++) {
13292     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13293   }
13294   for (int i = 0; i < active_tests_; i++) {
13295     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13296   }
13297 }
13298
13299
13300 static void CallTestNumber(int test_number) {
13301   (RegisterThreadedTest::nth(test_number)->callback())();
13302 }
13303
13304
13305 void ApiTestFuzzer::RunAllTests() {
13306   // Set off the first test.
13307   current_ = -1;
13308   NextThread();
13309   // Wait till they are all done.
13310   all_tests_done_.Wait();
13311 }
13312
13313
13314 int ApiTestFuzzer::GetNextTestNumber() {
13315   int next_test;
13316   do {
13317     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13318     linear_congruential_generator *= 1664525u;
13319     linear_congruential_generator += 1013904223u;
13320   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13321   return next_test;
13322 }
13323
13324
13325 void ApiTestFuzzer::ContextSwitch() {
13326   // If the new thread is the same as the current thread there is nothing to do.
13327   if (NextThread()) {
13328     // Now it can start.
13329     v8::Unlocker unlocker(CcTest::isolate());
13330     // Wait till someone starts us again.
13331     gate_.Wait();
13332     // And we're off.
13333   }
13334 }
13335
13336
13337 void ApiTestFuzzer::TearDown() {
13338   fuzzing_ = false;
13339   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13340     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13341     if (fuzzer != NULL) fuzzer->Join();
13342   }
13343 }
13344
13345
13346 // Lets not be needlessly self-referential.
13347 TEST(Threading1) {
13348   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13349   ApiTestFuzzer::RunAllTests();
13350   ApiTestFuzzer::TearDown();
13351 }
13352
13353
13354 TEST(Threading2) {
13355   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13356   ApiTestFuzzer::RunAllTests();
13357   ApiTestFuzzer::TearDown();
13358 }
13359
13360
13361 TEST(Threading3) {
13362   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13363   ApiTestFuzzer::RunAllTests();
13364   ApiTestFuzzer::TearDown();
13365 }
13366
13367
13368 TEST(Threading4) {
13369   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13370   ApiTestFuzzer::RunAllTests();
13371   ApiTestFuzzer::TearDown();
13372 }
13373
13374
13375 void ApiTestFuzzer::CallTest() {
13376   v8::Isolate::Scope scope(CcTest::isolate());
13377   if (kLogThreading)
13378     printf("Start test %d\n", test_number_);
13379   CallTestNumber(test_number_);
13380   if (kLogThreading)
13381     printf("End test %d\n", test_number_);
13382 }
13383
13384
13385 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13386   v8::Isolate* isolate = args.GetIsolate();
13387   CHECK(v8::Locker::IsLocked(isolate));
13388   ApiTestFuzzer::Fuzz();
13389   v8::Unlocker unlocker(isolate);
13390   const char* code = "throw 7;";
13391   {
13392     v8::Locker nested_locker(isolate);
13393     v8::HandleScope scope(isolate);
13394     v8::Handle<Value> exception;
13395     { v8::TryCatch try_catch;
13396       v8::Handle<Value> value = CompileRun(code);
13397       CHECK(value.IsEmpty());
13398       CHECK(try_catch.HasCaught());
13399       // Make sure to wrap the exception in a new handle because
13400       // the handle returned from the TryCatch is destroyed
13401       // when the TryCatch is destroyed.
13402       exception = Local<Value>::New(isolate, try_catch.Exception());
13403     }
13404     args.GetIsolate()->ThrowException(exception);
13405   }
13406 }
13407
13408
13409 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13410   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13411   ApiTestFuzzer::Fuzz();
13412   v8::Unlocker unlocker(CcTest::isolate());
13413   const char* code = "throw 7;";
13414   {
13415     v8::Locker nested_locker(CcTest::isolate());
13416     v8::HandleScope scope(args.GetIsolate());
13417     v8::Handle<Value> value = CompileRun(code);
13418     CHECK(value.IsEmpty());
13419     args.GetReturnValue().Set(v8_str("foo"));
13420   }
13421 }
13422
13423
13424 // These are locking tests that don't need to be run again
13425 // as part of the locking aggregation tests.
13426 TEST(NestedLockers) {
13427   v8::Isolate* isolate = CcTest::isolate();
13428   v8::Locker locker(isolate);
13429   CHECK(v8::Locker::IsLocked(isolate));
13430   LocalContext env;
13431   v8::HandleScope scope(env->GetIsolate());
13432   Local<v8::FunctionTemplate> fun_templ =
13433       v8::FunctionTemplate::New(isolate, ThrowInJS);
13434   Local<Function> fun = fun_templ->GetFunction();
13435   env->Global()->Set(v8_str("throw_in_js"), fun);
13436   Local<Script> script = v8_compile("(function () {"
13437                                     "  try {"
13438                                     "    throw_in_js();"
13439                                     "    return 42;"
13440                                     "  } catch (e) {"
13441                                     "    return e * 13;"
13442                                     "  }"
13443                                     "})();");
13444   CHECK_EQ(91, script->Run()->Int32Value());
13445 }
13446
13447
13448 // These are locking tests that don't need to be run again
13449 // as part of the locking aggregation tests.
13450 TEST(NestedLockersNoTryCatch) {
13451   v8::Locker locker(CcTest::isolate());
13452   LocalContext env;
13453   v8::HandleScope scope(env->GetIsolate());
13454   Local<v8::FunctionTemplate> fun_templ =
13455       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13456   Local<Function> fun = fun_templ->GetFunction();
13457   env->Global()->Set(v8_str("throw_in_js"), fun);
13458   Local<Script> script = v8_compile("(function () {"
13459                                     "  try {"
13460                                     "    throw_in_js();"
13461                                     "    return 42;"
13462                                     "  } catch (e) {"
13463                                     "    return e * 13;"
13464                                     "  }"
13465                                     "})();");
13466   CHECK_EQ(91, script->Run()->Int32Value());
13467 }
13468
13469
13470 THREADED_TEST(RecursiveLocking) {
13471   v8::Locker locker(CcTest::isolate());
13472   {
13473     v8::Locker locker2(CcTest::isolate());
13474     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13475   }
13476 }
13477
13478
13479 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13480   ApiTestFuzzer::Fuzz();
13481   v8::Unlocker unlocker(CcTest::isolate());
13482 }
13483
13484
13485 THREADED_TEST(LockUnlockLock) {
13486   {
13487     v8::Locker locker(CcTest::isolate());
13488     v8::HandleScope scope(CcTest::isolate());
13489     LocalContext env;
13490     Local<v8::FunctionTemplate> fun_templ =
13491         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13492     Local<Function> fun = fun_templ->GetFunction();
13493     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13494     Local<Script> script = v8_compile("(function () {"
13495                                       "  unlock_for_a_moment();"
13496                                       "  return 42;"
13497                                       "})();");
13498     CHECK_EQ(42, script->Run()->Int32Value());
13499   }
13500   {
13501     v8::Locker locker(CcTest::isolate());
13502     v8::HandleScope scope(CcTest::isolate());
13503     LocalContext env;
13504     Local<v8::FunctionTemplate> fun_templ =
13505         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13506     Local<Function> fun = fun_templ->GetFunction();
13507     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13508     Local<Script> script = v8_compile("(function () {"
13509                                       "  unlock_for_a_moment();"
13510                                       "  return 42;"
13511                                       "})();");
13512     CHECK_EQ(42, script->Run()->Int32Value());
13513   }
13514 }
13515
13516
13517 static int GetGlobalObjectsCount() {
13518   int count = 0;
13519   i::HeapIterator it(CcTest::heap());
13520   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13521     if (object->IsJSGlobalObject()) count++;
13522   return count;
13523 }
13524
13525
13526 static void CheckSurvivingGlobalObjectsCount(int expected) {
13527   // We need to collect all garbage twice to be sure that everything
13528   // has been collected.  This is because inline caches are cleared in
13529   // the first garbage collection but some of the maps have already
13530   // been marked at that point.  Therefore some of the maps are not
13531   // collected until the second garbage collection.
13532   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13533   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13534   int count = GetGlobalObjectsCount();
13535 #ifdef DEBUG
13536   if (count != expected) CcTest::heap()->TracePathToGlobal();
13537 #endif
13538   CHECK_EQ(expected, count);
13539 }
13540
13541
13542 TEST(DontLeakGlobalObjects) {
13543   // Regression test for issues 1139850 and 1174891.
13544
13545   i::FLAG_expose_gc = true;
13546   v8::V8::Initialize();
13547
13548   for (int i = 0; i < 5; i++) {
13549     { v8::HandleScope scope(CcTest::isolate());
13550       LocalContext context;
13551     }
13552     v8::V8::ContextDisposedNotification();
13553     CheckSurvivingGlobalObjectsCount(0);
13554
13555     { v8::HandleScope scope(CcTest::isolate());
13556       LocalContext context;
13557       v8_compile("Date")->Run();
13558     }
13559     v8::V8::ContextDisposedNotification();
13560     CheckSurvivingGlobalObjectsCount(0);
13561
13562     { v8::HandleScope scope(CcTest::isolate());
13563       LocalContext context;
13564       v8_compile("/aaa/")->Run();
13565     }
13566     v8::V8::ContextDisposedNotification();
13567     CheckSurvivingGlobalObjectsCount(0);
13568
13569     { v8::HandleScope scope(CcTest::isolate());
13570       const char* extension_list[] = { "v8/gc" };
13571       v8::ExtensionConfiguration extensions(1, extension_list);
13572       LocalContext context(&extensions);
13573       v8_compile("gc();")->Run();
13574     }
13575     v8::V8::ContextDisposedNotification();
13576     CheckSurvivingGlobalObjectsCount(0);
13577   }
13578 }
13579
13580
13581 TEST(CopyablePersistent) {
13582   LocalContext context;
13583   v8::Isolate* isolate = context->GetIsolate();
13584   i::GlobalHandles* globals =
13585       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13586   int initial_handles = globals->global_handles_count();
13587   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13588       CopyableObject;
13589   {
13590     CopyableObject handle1;
13591     {
13592       v8::HandleScope scope(isolate);
13593       handle1.Reset(isolate, v8::Object::New(isolate));
13594     }
13595     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13596     CopyableObject  handle2;
13597     handle2 = handle1;
13598     CHECK(handle1 == handle2);
13599     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13600     CopyableObject handle3(handle2);
13601     CHECK(handle1 == handle3);
13602     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13603   }
13604   // Verify autodispose
13605   CHECK_EQ(initial_handles, globals->global_handles_count());
13606 }
13607
13608
13609 static void WeakApiCallback(
13610     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13611   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13612   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13613   data.GetParameter()->Reset();
13614   delete data.GetParameter();
13615 }
13616
13617
13618 TEST(WeakCallbackApi) {
13619   LocalContext context;
13620   v8::Isolate* isolate = context->GetIsolate();
13621   i::GlobalHandles* globals =
13622       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13623   int initial_handles = globals->global_handles_count();
13624   {
13625     v8::HandleScope scope(isolate);
13626     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13627     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13628     v8::Persistent<v8::Object>* handle =
13629         new v8::Persistent<v8::Object>(isolate, obj);
13630     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13631                                                              WeakApiCallback);
13632   }
13633   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13634       CollectAllGarbage(i::Heap::kNoGCFlags);
13635   // Verify disposed.
13636   CHECK_EQ(initial_handles, globals->global_handles_count());
13637 }
13638
13639
13640 v8::Persistent<v8::Object> some_object;
13641 v8::Persistent<v8::Object> bad_handle;
13642
13643 void NewPersistentHandleCallback(
13644     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13645   v8::HandleScope scope(data.GetIsolate());
13646   bad_handle.Reset(data.GetIsolate(), some_object);
13647   data.GetParameter()->Reset();
13648 }
13649
13650
13651 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13652   LocalContext context;
13653   v8::Isolate* isolate = context->GetIsolate();
13654
13655   v8::Persistent<v8::Object> handle1, handle2;
13656   {
13657     v8::HandleScope scope(isolate);
13658     some_object.Reset(isolate, v8::Object::New(isolate));
13659     handle1.Reset(isolate, v8::Object::New(isolate));
13660     handle2.Reset(isolate, v8::Object::New(isolate));
13661   }
13662   // Note: order is implementation dependent alas: currently
13663   // global handle nodes are processed by PostGarbageCollectionProcessing
13664   // in reverse allocation order, so if second allocated handle is deleted,
13665   // weak callback of the first handle would be able to 'reallocate' it.
13666   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13667   handle2.Reset();
13668   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13669 }
13670
13671
13672 v8::Persistent<v8::Object> to_be_disposed;
13673
13674 void DisposeAndForceGcCallback(
13675     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13676   to_be_disposed.Reset();
13677   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13678   data.GetParameter()->Reset();
13679 }
13680
13681
13682 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13683   LocalContext context;
13684   v8::Isolate* isolate = context->GetIsolate();
13685
13686   v8::Persistent<v8::Object> handle1, handle2;
13687   {
13688     v8::HandleScope scope(isolate);
13689     handle1.Reset(isolate, v8::Object::New(isolate));
13690     handle2.Reset(isolate, v8::Object::New(isolate));
13691   }
13692   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13693   to_be_disposed.Reset(isolate, handle2);
13694   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13695 }
13696
13697 void DisposingCallback(
13698     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13699   data.GetParameter()->Reset();
13700 }
13701
13702 void HandleCreatingCallback(
13703     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13704   v8::HandleScope scope(data.GetIsolate());
13705   v8::Persistent<v8::Object>(data.GetIsolate(),
13706                              v8::Object::New(data.GetIsolate()));
13707   data.GetParameter()->Reset();
13708 }
13709
13710
13711 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13712   LocalContext context;
13713   v8::Isolate* isolate = context->GetIsolate();
13714
13715   v8::Persistent<v8::Object> handle1, handle2, handle3;
13716   {
13717     v8::HandleScope scope(isolate);
13718     handle3.Reset(isolate, v8::Object::New(isolate));
13719     handle2.Reset(isolate, v8::Object::New(isolate));
13720     handle1.Reset(isolate, v8::Object::New(isolate));
13721   }
13722   handle2.SetWeak(&handle2, DisposingCallback);
13723   handle3.SetWeak(&handle3, HandleCreatingCallback);
13724   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13725 }
13726
13727
13728 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13729   v8::V8::Initialize();
13730
13731   const int nof = 2;
13732   const char* sources[nof] = {
13733     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13734     "Object()"
13735   };
13736
13737   for (int i = 0; i < nof; i++) {
13738     const char* source = sources[i];
13739     { v8::HandleScope scope(CcTest::isolate());
13740       LocalContext context;
13741       CompileRun(source);
13742     }
13743     { v8::HandleScope scope(CcTest::isolate());
13744       LocalContext context;
13745       CompileRun(source);
13746     }
13747   }
13748 }
13749
13750
13751 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13752   v8::EscapableHandleScope inner(env->GetIsolate());
13753   env->Enter();
13754   v8::Local<Value> three = v8_num(3);
13755   v8::Local<Value> value = inner.Escape(three);
13756   env->Exit();
13757   return value;
13758 }
13759
13760
13761 THREADED_TEST(NestedHandleScopeAndContexts) {
13762   v8::Isolate* isolate = CcTest::isolate();
13763   v8::HandleScope outer(isolate);
13764   v8::Local<Context> env = Context::New(isolate);
13765   env->Enter();
13766   v8::Handle<Value> value = NestedScope(env);
13767   v8::Handle<String> str(value->ToString());
13768   CHECK(!str.IsEmpty());
13769   env->Exit();
13770 }
13771
13772
13773 static bool MatchPointers(void* key1, void* key2) {
13774   return key1 == key2;
13775 }
13776
13777
13778 struct SymbolInfo {
13779   size_t id;
13780   size_t size;
13781   std::string name;
13782 };
13783
13784
13785 class SetFunctionEntryHookTest {
13786  public:
13787   SetFunctionEntryHookTest() {
13788     CHECK(instance_ == NULL);
13789     instance_ = this;
13790   }
13791   ~SetFunctionEntryHookTest() {
13792     CHECK(instance_ == this);
13793     instance_ = NULL;
13794   }
13795   void Reset() {
13796     symbols_.clear();
13797     symbol_locations_.clear();
13798     invocations_.clear();
13799   }
13800   void RunTest();
13801   void OnJitEvent(const v8::JitCodeEvent* event);
13802   static void JitEvent(const v8::JitCodeEvent* event) {
13803     CHECK(instance_ != NULL);
13804     instance_->OnJitEvent(event);
13805   }
13806
13807   void OnEntryHook(uintptr_t function,
13808                    uintptr_t return_addr_location);
13809   static void EntryHook(uintptr_t function,
13810                         uintptr_t return_addr_location) {
13811     CHECK(instance_ != NULL);
13812     instance_->OnEntryHook(function, return_addr_location);
13813   }
13814
13815   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13816     CHECK(instance_ != NULL);
13817     args.GetReturnValue().Set(v8_num(42));
13818   }
13819   void RunLoopInNewEnv(v8::Isolate* isolate);
13820
13821   // Records addr as location of symbol.
13822   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13823
13824   // Finds the symbol containing addr
13825   SymbolInfo* FindSymbolForAddr(i::Address addr);
13826   // Returns the number of invocations where the caller name contains
13827   // \p caller_name and the function name contains \p function_name.
13828   int CountInvocations(const char* caller_name,
13829                        const char* function_name);
13830
13831   i::Handle<i::JSFunction> foo_func_;
13832   i::Handle<i::JSFunction> bar_func_;
13833
13834   typedef std::map<size_t, SymbolInfo> SymbolMap;
13835   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13836   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13837   SymbolMap symbols_;
13838   SymbolLocationMap symbol_locations_;
13839   InvocationMap invocations_;
13840
13841   static SetFunctionEntryHookTest* instance_;
13842 };
13843 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13844
13845
13846 // Returns true if addr is in the range [start, start+len).
13847 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13848   if (start <= addr && start + len > addr)
13849     return true;
13850
13851   return false;
13852 }
13853
13854 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13855                                               SymbolInfo* symbol) {
13856   // Insert the symbol at the new location.
13857   SymbolLocationMap::iterator it =
13858       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13859   // Now erase symbols to the left and right that overlap this one.
13860   while (it != symbol_locations_.begin()) {
13861     SymbolLocationMap::iterator left = it;
13862     --left;
13863     if (!Overlaps(left->first, left->second->size, addr))
13864       break;
13865     symbol_locations_.erase(left);
13866   }
13867
13868   // Now erase symbols to the left and right that overlap this one.
13869   while (true) {
13870     SymbolLocationMap::iterator right = it;
13871     ++right;
13872     if (right == symbol_locations_.end())
13873         break;
13874     if (!Overlaps(addr, symbol->size, right->first))
13875       break;
13876     symbol_locations_.erase(right);
13877   }
13878 }
13879
13880
13881 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13882   switch (event->type) {
13883     case v8::JitCodeEvent::CODE_ADDED: {
13884         CHECK(event->code_start != NULL);
13885         CHECK_NE(0, static_cast<int>(event->code_len));
13886         CHECK(event->name.str != NULL);
13887         size_t symbol_id = symbols_.size();
13888
13889         // Record the new symbol.
13890         SymbolInfo& info = symbols_[symbol_id];
13891         info.id = symbol_id;
13892         info.size = event->code_len;
13893         info.name.assign(event->name.str, event->name.str + event->name.len);
13894
13895         // And record it's location.
13896         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13897       }
13898       break;
13899
13900     case v8::JitCodeEvent::CODE_MOVED: {
13901         // We would like to never see code move that we haven't seen before,
13902         // but the code creation event does not happen until the line endings
13903         // have been calculated (this is so that we can report the line in the
13904         // script at which the function source is found, see
13905         // Compiler::RecordFunctionCompilation) and the line endings
13906         // calculations can cause a GC, which can move the newly created code
13907         // before its existence can be logged.
13908         SymbolLocationMap::iterator it(
13909             symbol_locations_.find(
13910                 reinterpret_cast<i::Address>(event->code_start)));
13911         if (it != symbol_locations_.end()) {
13912           // Found a symbol at this location, move it.
13913           SymbolInfo* info = it->second;
13914           symbol_locations_.erase(it);
13915           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13916                          info);
13917         }
13918       }
13919     default:
13920       break;
13921   }
13922 }
13923
13924 void SetFunctionEntryHookTest::OnEntryHook(
13925     uintptr_t function, uintptr_t return_addr_location) {
13926   // Get the function's code object.
13927   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13928       reinterpret_cast<i::Address>(function));
13929   CHECK(function_code != NULL);
13930
13931   // Then try and look up the caller's code object.
13932   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13933
13934   // Count the invocation.
13935   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13936   SymbolInfo* function_symbol =
13937       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13938   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13939
13940   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13941     // Check that we have a symbol for the "bar" function at the right location.
13942     SymbolLocationMap::iterator it(
13943         symbol_locations_.find(function_code->instruction_start()));
13944     CHECK(it != symbol_locations_.end());
13945   }
13946
13947   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13948     // Check that we have a symbol for "foo" at the right location.
13949     SymbolLocationMap::iterator it(
13950         symbol_locations_.find(function_code->instruction_start()));
13951     CHECK(it != symbol_locations_.end());
13952   }
13953 }
13954
13955
13956 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13957   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13958   // Do we have a direct hit on a symbol?
13959   if (it != symbol_locations_.end()) {
13960     if (it->first == addr)
13961       return it->second;
13962   }
13963
13964   // If not a direct hit, it'll have to be the previous symbol.
13965   if (it == symbol_locations_.begin())
13966     return NULL;
13967
13968   --it;
13969   size_t offs = addr - it->first;
13970   if (offs < it->second->size)
13971     return it->second;
13972
13973   return NULL;
13974 }
13975
13976
13977 int SetFunctionEntryHookTest::CountInvocations(
13978     const char* caller_name, const char* function_name) {
13979   InvocationMap::iterator it(invocations_.begin());
13980   int invocations = 0;
13981   for (; it != invocations_.end(); ++it) {
13982     SymbolInfo* caller = it->first.first;
13983     SymbolInfo* function = it->first.second;
13984
13985     // Filter out non-matching functions.
13986     if (function_name != NULL) {
13987       if (function->name.find(function_name) == std::string::npos)
13988         continue;
13989     }
13990
13991     // Filter out non-matching callers.
13992     if (caller_name != NULL) {
13993       if (caller == NULL)
13994         continue;
13995       if (caller->name.find(caller_name) == std::string::npos)
13996         continue;
13997     }
13998
13999     // It matches add the invocation count to the tally.
14000     invocations += it->second;
14001   }
14002
14003   return invocations;
14004 }
14005
14006
14007 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14008   v8::HandleScope outer(isolate);
14009   v8::Local<Context> env = Context::New(isolate);
14010   env->Enter();
14011
14012   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14013   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14014   env->Global()->Set(v8_str("obj"), t->NewInstance());
14015
14016   const char* script =
14017       "function bar() {\n"
14018       "  var sum = 0;\n"
14019       "  for (i = 0; i < 100; ++i)\n"
14020       "    sum = foo(i);\n"
14021       "  return sum;\n"
14022       "}\n"
14023       "function foo(i) { return i * i; }\n"
14024       "// Invoke on the runtime function.\n"
14025       "obj.asdf()";
14026   CompileRun(script);
14027   bar_func_ = i::Handle<i::JSFunction>::cast(
14028           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14029   ASSERT(!bar_func_.is_null());
14030
14031   foo_func_ =
14032       i::Handle<i::JSFunction>::cast(
14033            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14034   ASSERT(!foo_func_.is_null());
14035
14036   v8::Handle<v8::Value> value = CompileRun("bar();");
14037   CHECK(value->IsNumber());
14038   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14039
14040   // Test the optimized codegen path.
14041   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14042                      "bar();");
14043   CHECK(value->IsNumber());
14044   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14045
14046   env->Exit();
14047 }
14048
14049
14050 void SetFunctionEntryHookTest::RunTest() {
14051   // Work in a new isolate throughout.
14052   v8::Isolate* isolate = v8::Isolate::New();
14053
14054   // Test setting the entry hook on the new isolate.
14055   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14056
14057   // Replacing the hook, once set should fail.
14058   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14059
14060   {
14061     v8::Isolate::Scope scope(isolate);
14062
14063     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14064
14065     RunLoopInNewEnv(isolate);
14066
14067     // Check the exepected invocation counts.
14068     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14069     CHECK_EQ(200, CountInvocations("bar", "foo"));
14070     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14071
14072     // Verify that we have an entry hook on some specific stubs.
14073     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14074     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14075     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14076   }
14077   isolate->Dispose();
14078
14079   Reset();
14080
14081   // Make sure a second isolate is unaffected by the previous entry hook.
14082   isolate = v8::Isolate::New();
14083   {
14084     v8::Isolate::Scope scope(isolate);
14085
14086     // Reset the entry count to zero and set the entry hook.
14087     RunLoopInNewEnv(isolate);
14088
14089     // We should record no invocations in this isolate.
14090     CHECK_EQ(0, static_cast<int>(invocations_.size()));
14091   }
14092   // Since the isolate has been used, we shouldn't be able to set an entry
14093   // hook anymore.
14094   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14095
14096   isolate->Dispose();
14097 }
14098
14099
14100 TEST(SetFunctionEntryHook) {
14101   // FunctionEntryHook does not work well with experimental natives.
14102   // Experimental natives are compiled during snapshot deserialization.
14103   // This test breaks because InstallGetter (function from snapshot that
14104   // only gets called from experimental natives) is compiled with entry hooks.
14105   i::FLAG_allow_natives_syntax = true;
14106   i::FLAG_use_inlining = false;
14107
14108   SetFunctionEntryHookTest test;
14109   test.RunTest();
14110 }
14111
14112
14113 static i::HashMap* code_map = NULL;
14114 static i::HashMap* jitcode_line_info = NULL;
14115 static int saw_bar = 0;
14116 static int move_events = 0;
14117
14118
14119 static bool FunctionNameIs(const char* expected,
14120                            const v8::JitCodeEvent* event) {
14121   // Log lines for functions are of the general form:
14122   // "LazyCompile:<type><function_name>", where the type is one of
14123   // "*", "~" or "".
14124   static const char kPreamble[] = "LazyCompile:";
14125   static size_t kPreambleLen = sizeof(kPreamble) - 1;
14126
14127   if (event->name.len < sizeof(kPreamble) - 1 ||
14128       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14129     return false;
14130   }
14131
14132   const char* tail = event->name.str + kPreambleLen;
14133   size_t tail_len = event->name.len - kPreambleLen;
14134   size_t expected_len = strlen(expected);
14135   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14136     --tail_len;
14137     ++tail;
14138   }
14139
14140   // Check for tails like 'bar :1'.
14141   if (tail_len > expected_len + 2 &&
14142       tail[expected_len] == ' ' &&
14143       tail[expected_len + 1] == ':' &&
14144       tail[expected_len + 2] &&
14145       !strncmp(tail, expected, expected_len)) {
14146     return true;
14147   }
14148
14149   if (tail_len != expected_len)
14150     return false;
14151
14152   return strncmp(tail, expected, expected_len) == 0;
14153 }
14154
14155
14156 static void event_handler(const v8::JitCodeEvent* event) {
14157   CHECK(event != NULL);
14158   CHECK(code_map != NULL);
14159   CHECK(jitcode_line_info != NULL);
14160
14161   class DummyJitCodeLineInfo {
14162   };
14163
14164   switch (event->type) {
14165     case v8::JitCodeEvent::CODE_ADDED: {
14166         CHECK(event->code_start != NULL);
14167         CHECK_NE(0, static_cast<int>(event->code_len));
14168         CHECK(event->name.str != NULL);
14169         i::HashMap::Entry* entry =
14170             code_map->Lookup(event->code_start,
14171                              i::ComputePointerHash(event->code_start),
14172                              true);
14173         entry->value = reinterpret_cast<void*>(event->code_len);
14174
14175         if (FunctionNameIs("bar", event)) {
14176           ++saw_bar;
14177         }
14178       }
14179       break;
14180
14181     case v8::JitCodeEvent::CODE_MOVED: {
14182         uint32_t hash = i::ComputePointerHash(event->code_start);
14183         // We would like to never see code move that we haven't seen before,
14184         // but the code creation event does not happen until the line endings
14185         // have been calculated (this is so that we can report the line in the
14186         // script at which the function source is found, see
14187         // Compiler::RecordFunctionCompilation) and the line endings
14188         // calculations can cause a GC, which can move the newly created code
14189         // before its existence can be logged.
14190         i::HashMap::Entry* entry =
14191             code_map->Lookup(event->code_start, hash, false);
14192         if (entry != NULL) {
14193           ++move_events;
14194
14195           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14196           code_map->Remove(event->code_start, hash);
14197
14198           entry = code_map->Lookup(event->new_code_start,
14199                                    i::ComputePointerHash(event->new_code_start),
14200                                    true);
14201           CHECK(entry != NULL);
14202           entry->value = reinterpret_cast<void*>(event->code_len);
14203         }
14204       }
14205       break;
14206
14207     case v8::JitCodeEvent::CODE_REMOVED:
14208       // Object/code removal events are currently not dispatched from the GC.
14209       CHECK(false);
14210       break;
14211
14212     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14213     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14214     // record it in jitcode_line_info.
14215     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14216         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14217         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14218         temp_event->user_data = line_info;
14219         i::HashMap::Entry* entry =
14220             jitcode_line_info->Lookup(line_info,
14221                                       i::ComputePointerHash(line_info),
14222                                       true);
14223         entry->value = reinterpret_cast<void*>(line_info);
14224       }
14225       break;
14226     // For these two events, we will check whether the event->user_data
14227     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14228     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14229     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14230         CHECK(event->user_data != NULL);
14231         uint32_t hash = i::ComputePointerHash(event->user_data);
14232         i::HashMap::Entry* entry =
14233             jitcode_line_info->Lookup(event->user_data, hash, false);
14234         CHECK(entry != NULL);
14235         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14236       }
14237       break;
14238
14239     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14240         CHECK(event->user_data != NULL);
14241         uint32_t hash = i::ComputePointerHash(event->user_data);
14242         i::HashMap::Entry* entry =
14243             jitcode_line_info->Lookup(event->user_data, hash, false);
14244         CHECK(entry != NULL);
14245       }
14246       break;
14247
14248     default:
14249       // Impossible event.
14250       CHECK(false);
14251       break;
14252   }
14253 }
14254
14255
14256 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14257   i::FLAG_stress_compaction = true;
14258   i::FLAG_incremental_marking = false;
14259   if (i::FLAG_never_compact) return;
14260   const char* script =
14261     "function bar() {"
14262     "  var sum = 0;"
14263     "  for (i = 0; i < 100; ++i)"
14264     "    sum = foo(i);"
14265     "  return sum;"
14266     "}"
14267     "function foo(i) { return i * i; };"
14268     "bar();";
14269
14270   // Run this test in a new isolate to make sure we don't
14271   // have remnants of state from other code.
14272   v8::Isolate* isolate = v8::Isolate::New();
14273   isolate->Enter();
14274   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14275   i::Heap* heap = i_isolate->heap();
14276
14277   {
14278     v8::HandleScope scope(isolate);
14279     i::HashMap code(MatchPointers);
14280     code_map = &code;
14281
14282     i::HashMap lineinfo(MatchPointers);
14283     jitcode_line_info = &lineinfo;
14284
14285     saw_bar = 0;
14286     move_events = 0;
14287
14288     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14289
14290     // Generate new code objects sparsely distributed across several
14291     // different fragmented code-space pages.
14292     const int kIterations = 10;
14293     for (int i = 0; i < kIterations; ++i) {
14294       LocalContext env(isolate);
14295       i::AlwaysAllocateScope always_allocate(i_isolate);
14296       SimulateFullSpace(heap->code_space());
14297       CompileRun(script);
14298
14299       // Keep a strong reference to the code object in the handle scope.
14300       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14301           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14302       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14303           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14304
14305       // Clear the compilation cache to get more wastage.
14306       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14307     }
14308
14309     // Force code movement.
14310     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14311
14312     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14313
14314     CHECK_LE(kIterations, saw_bar);
14315     CHECK_LT(0, move_events);
14316
14317     code_map = NULL;
14318     jitcode_line_info = NULL;
14319   }
14320
14321   isolate->Exit();
14322   isolate->Dispose();
14323
14324   // Do this in a new isolate.
14325   isolate = v8::Isolate::New();
14326   isolate->Enter();
14327
14328   // Verify that we get callbacks for existing code objects when we
14329   // request enumeration of existing code.
14330   {
14331     v8::HandleScope scope(isolate);
14332     LocalContext env(isolate);
14333     CompileRun(script);
14334
14335     // Now get code through initial iteration.
14336     i::HashMap code(MatchPointers);
14337     code_map = &code;
14338
14339     i::HashMap lineinfo(MatchPointers);
14340     jitcode_line_info = &lineinfo;
14341
14342     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14343     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14344
14345     jitcode_line_info = NULL;
14346     // We expect that we got some events. Note that if we could get code removal
14347     // notifications, we could compare two collections, one created by listening
14348     // from the time of creation of an isolate, and the other by subscribing
14349     // with EnumExisting.
14350     CHECK_LT(0, code.occupancy());
14351
14352     code_map = NULL;
14353   }
14354
14355   isolate->Exit();
14356   isolate->Dispose();
14357 }
14358
14359
14360 THREADED_TEST(ExternalAllocatedMemory) {
14361   v8::Isolate* isolate = CcTest::isolate();
14362   v8::HandleScope outer(isolate);
14363   v8::Local<Context> env(Context::New(isolate));
14364   CHECK(!env.IsEmpty());
14365   const int64_t kSize = 1024*1024;
14366   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14367   CHECK_EQ(baseline + kSize,
14368            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14369   CHECK_EQ(baseline,
14370            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14371 }
14372
14373
14374 // Regression test for issue 54, object templates with internal fields
14375 // but no accessors or interceptors did not get their internal field
14376 // count set on instances.
14377 THREADED_TEST(Regress54) {
14378   LocalContext context;
14379   v8::Isolate* isolate = context->GetIsolate();
14380   v8::HandleScope outer(isolate);
14381   static v8::Persistent<v8::ObjectTemplate> templ;
14382   if (templ.IsEmpty()) {
14383     v8::EscapableHandleScope inner(isolate);
14384     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14385     local->SetInternalFieldCount(1);
14386     templ.Reset(isolate, inner.Escape(local));
14387   }
14388   v8::Handle<v8::Object> result =
14389       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14390   CHECK_EQ(1, result->InternalFieldCount());
14391 }
14392
14393
14394 // If part of the threaded tests, this test makes ThreadingTest fail
14395 // on mac.
14396 TEST(CatchStackOverflow) {
14397   LocalContext context;
14398   v8::HandleScope scope(context->GetIsolate());
14399   v8::TryCatch try_catch;
14400   v8::Handle<v8::Value> result = CompileRun(
14401     "function f() {"
14402     "  return f();"
14403     "}"
14404     ""
14405     "f();");
14406   CHECK(result.IsEmpty());
14407 }
14408
14409
14410 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14411                                     const char* resource_name,
14412                                     int line_offset) {
14413   v8::HandleScope scope(CcTest::isolate());
14414   v8::TryCatch try_catch;
14415   v8::Handle<v8::Value> result = script->Run();
14416   CHECK(result.IsEmpty());
14417   CHECK(try_catch.HasCaught());
14418   v8::Handle<v8::Message> message = try_catch.Message();
14419   CHECK(!message.IsEmpty());
14420   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14421   CHECK_EQ(91, message->GetStartPosition());
14422   CHECK_EQ(92, message->GetEndPosition());
14423   CHECK_EQ(2, message->GetStartColumn());
14424   CHECK_EQ(3, message->GetEndColumn());
14425   v8::String::Utf8Value line(message->GetSourceLine());
14426   CHECK_EQ("  throw 'nirk';", *line);
14427   v8::String::Utf8Value name(message->GetScriptResourceName());
14428   CHECK_EQ(resource_name, *name);
14429 }
14430
14431
14432 THREADED_TEST(TryCatchSourceInfo) {
14433   LocalContext context;
14434   v8::HandleScope scope(context->GetIsolate());
14435   v8::Local<v8::String> source = v8_str(
14436       "function Foo() {\n"
14437       "  return Bar();\n"
14438       "}\n"
14439       "\n"
14440       "function Bar() {\n"
14441       "  return Baz();\n"
14442       "}\n"
14443       "\n"
14444       "function Baz() {\n"
14445       "  throw 'nirk';\n"
14446       "}\n"
14447       "\n"
14448       "Foo();\n");
14449
14450   const char* resource_name;
14451   v8::Handle<v8::Script> script;
14452   resource_name = "test.js";
14453   script = CompileWithOrigin(source, resource_name);
14454   CheckTryCatchSourceInfo(script, resource_name, 0);
14455
14456   resource_name = "test1.js";
14457   v8::ScriptOrigin origin1(
14458       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14459   script = v8::Script::Compile(source, &origin1);
14460   CheckTryCatchSourceInfo(script, resource_name, 0);
14461
14462   resource_name = "test2.js";
14463   v8::ScriptOrigin origin2(
14464       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14465       v8::Integer::New(context->GetIsolate(), 7));
14466   script = v8::Script::Compile(source, &origin2);
14467   CheckTryCatchSourceInfo(script, resource_name, 7);
14468 }
14469
14470
14471 THREADED_TEST(CompilationCache) {
14472   LocalContext context;
14473   v8::HandleScope scope(context->GetIsolate());
14474   v8::Handle<v8::String> source0 =
14475       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14476   v8::Handle<v8::String> source1 =
14477       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14478   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14479   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14480   v8::Handle<v8::Script> script2 =
14481       v8::Script::Compile(source0);  // different origin
14482   CHECK_EQ(1234, script0->Run()->Int32Value());
14483   CHECK_EQ(1234, script1->Run()->Int32Value());
14484   CHECK_EQ(1234, script2->Run()->Int32Value());
14485 }
14486
14487
14488 static void FunctionNameCallback(
14489     const v8::FunctionCallbackInfo<v8::Value>& args) {
14490   ApiTestFuzzer::Fuzz();
14491   args.GetReturnValue().Set(v8_num(42));
14492 }
14493
14494
14495 THREADED_TEST(CallbackFunctionName) {
14496   LocalContext context;
14497   v8::Isolate* isolate = context->GetIsolate();
14498   v8::HandleScope scope(isolate);
14499   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14500   t->Set(v8_str("asdf"),
14501          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14502   context->Global()->Set(v8_str("obj"), t->NewInstance());
14503   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14504   CHECK(value->IsString());
14505   v8::String::Utf8Value name(value);
14506   CHECK_EQ("asdf", *name);
14507 }
14508
14509
14510 THREADED_TEST(DateAccess) {
14511   LocalContext context;
14512   v8::HandleScope scope(context->GetIsolate());
14513   v8::Handle<v8::Value> date =
14514       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14515   CHECK(date->IsDate());
14516   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14517 }
14518
14519
14520 void CheckProperties(v8::Isolate* isolate,
14521                      v8::Handle<v8::Value> val,
14522                      int elmc,
14523                      const char* elmv[]) {
14524   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14525   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14526   CHECK_EQ(elmc, props->Length());
14527   for (int i = 0; i < elmc; i++) {
14528     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14529     CHECK_EQ(elmv[i], *elm);
14530   }
14531 }
14532
14533
14534 void CheckOwnProperties(v8::Isolate* isolate,
14535                         v8::Handle<v8::Value> val,
14536                         int elmc,
14537                         const char* elmv[]) {
14538   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14539   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14540   CHECK_EQ(elmc, props->Length());
14541   for (int i = 0; i < elmc; i++) {
14542     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14543     CHECK_EQ(elmv[i], *elm);
14544   }
14545 }
14546
14547
14548 THREADED_TEST(PropertyEnumeration) {
14549   LocalContext context;
14550   v8::Isolate* isolate = context->GetIsolate();
14551   v8::HandleScope scope(isolate);
14552   v8::Handle<v8::Value> obj = CompileRun(
14553       "var result = [];"
14554       "result[0] = {};"
14555       "result[1] = {a: 1, b: 2};"
14556       "result[2] = [1, 2, 3];"
14557       "var proto = {x: 1, y: 2, z: 3};"
14558       "var x = { __proto__: proto, w: 0, z: 1 };"
14559       "result[3] = x;"
14560       "result;");
14561   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14562   CHECK_EQ(4, elms->Length());
14563   int elmc0 = 0;
14564   const char** elmv0 = NULL;
14565   CheckProperties(
14566       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14567   CheckOwnProperties(
14568       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14569   int elmc1 = 2;
14570   const char* elmv1[] = {"a", "b"};
14571   CheckProperties(
14572       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14573   CheckOwnProperties(
14574       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14575   int elmc2 = 3;
14576   const char* elmv2[] = {"0", "1", "2"};
14577   CheckProperties(
14578       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14579   CheckOwnProperties(
14580       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14581   int elmc3 = 4;
14582   const char* elmv3[] = {"w", "z", "x", "y"};
14583   CheckProperties(
14584       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14585   int elmc4 = 2;
14586   const char* elmv4[] = {"w", "z"};
14587   CheckOwnProperties(
14588       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14589 }
14590
14591
14592 THREADED_TEST(PropertyEnumeration2) {
14593   LocalContext context;
14594   v8::Isolate* isolate = context->GetIsolate();
14595   v8::HandleScope scope(isolate);
14596   v8::Handle<v8::Value> obj = CompileRun(
14597       "var result = [];"
14598       "result[0] = {};"
14599       "result[1] = {a: 1, b: 2};"
14600       "result[2] = [1, 2, 3];"
14601       "var proto = {x: 1, y: 2, z: 3};"
14602       "var x = { __proto__: proto, w: 0, z: 1 };"
14603       "result[3] = x;"
14604       "result;");
14605   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14606   CHECK_EQ(4, elms->Length());
14607   int elmc0 = 0;
14608   const char** elmv0 = NULL;
14609   CheckProperties(isolate,
14610                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14611
14612   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14613   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14614   CHECK_EQ(0, props->Length());
14615   for (uint32_t i = 0; i < props->Length(); i++) {
14616     printf("p[%d]\n", i);
14617   }
14618 }
14619
14620 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14621                                   Local<Value> name,
14622                                   v8::AccessType type,
14623                                   Local<Value> data) {
14624   return type != v8::ACCESS_SET;
14625 }
14626
14627
14628 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14629                                     uint32_t key,
14630                                     v8::AccessType type,
14631                                     Local<Value> data) {
14632   return type != v8::ACCESS_SET;
14633 }
14634
14635
14636 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14637   LocalContext context;
14638   v8::Isolate* isolate = context->GetIsolate();
14639   v8::HandleScope scope(isolate);
14640   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14641   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14642                                  IndexedSetAccessBlocker);
14643   templ->Set(v8_str("x"), v8::True(isolate));
14644   Local<v8::Object> instance = templ->NewInstance();
14645   context->Global()->Set(v8_str("obj"), instance);
14646   Local<Value> value = CompileRun("obj.x");
14647   CHECK(value->BooleanValue());
14648 }
14649
14650
14651 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14652                                   Local<Value> name,
14653                                   v8::AccessType type,
14654                                   Local<Value> data) {
14655   return false;
14656 }
14657
14658
14659 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14660                                     uint32_t key,
14661                                     v8::AccessType type,
14662                                     Local<Value> data) {
14663   return false;
14664 }
14665
14666
14667
14668 THREADED_TEST(AccessChecksReenabledCorrectly) {
14669   LocalContext context;
14670   v8::Isolate* isolate = context->GetIsolate();
14671   v8::HandleScope scope(isolate);
14672   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14673   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14674                                  IndexedGetAccessBlocker);
14675   templ->Set(v8_str("a"), v8_str("a"));
14676   // Add more than 8 (see kMaxFastProperties) properties
14677   // so that the constructor will force copying map.
14678   // Cannot sprintf, gcc complains unsafety.
14679   char buf[4];
14680   for (char i = '0'; i <= '9' ; i++) {
14681     buf[0] = i;
14682     for (char j = '0'; j <= '9'; j++) {
14683       buf[1] = j;
14684       for (char k = '0'; k <= '9'; k++) {
14685         buf[2] = k;
14686         buf[3] = 0;
14687         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14688       }
14689     }
14690   }
14691
14692   Local<v8::Object> instance_1 = templ->NewInstance();
14693   context->Global()->Set(v8_str("obj_1"), instance_1);
14694
14695   Local<Value> value_1 = CompileRun("obj_1.a");
14696   CHECK(value_1->IsUndefined());
14697
14698   Local<v8::Object> instance_2 = templ->NewInstance();
14699   context->Global()->Set(v8_str("obj_2"), instance_2);
14700
14701   Local<Value> value_2 = CompileRun("obj_2.a");
14702   CHECK(value_2->IsUndefined());
14703 }
14704
14705
14706 // This tests that access check information remains on the global
14707 // object template when creating contexts.
14708 THREADED_TEST(AccessControlRepeatedContextCreation) {
14709   v8::Isolate* isolate = CcTest::isolate();
14710   v8::HandleScope handle_scope(isolate);
14711   v8::Handle<v8::ObjectTemplate> global_template =
14712       v8::ObjectTemplate::New(isolate);
14713   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14714                                            IndexedSetAccessBlocker);
14715   i::Handle<i::ObjectTemplateInfo> internal_template =
14716       v8::Utils::OpenHandle(*global_template);
14717   CHECK(!internal_template->constructor()->IsUndefined());
14718   i::Handle<i::FunctionTemplateInfo> constructor(
14719       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14720   CHECK(!constructor->access_check_info()->IsUndefined());
14721   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14722   CHECK(!context0.IsEmpty());
14723   CHECK(!constructor->access_check_info()->IsUndefined());
14724 }
14725
14726
14727 THREADED_TEST(TurnOnAccessCheck) {
14728   v8::Isolate* isolate = CcTest::isolate();
14729   v8::HandleScope handle_scope(isolate);
14730
14731   // Create an environment with access check to the global object disabled by
14732   // default.
14733   v8::Handle<v8::ObjectTemplate> global_template =
14734       v8::ObjectTemplate::New(isolate);
14735   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14736                                            IndexedGetAccessBlocker,
14737                                            v8::Handle<v8::Value>(),
14738                                            false);
14739   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14740   Context::Scope context_scope(context);
14741
14742   // Set up a property and a number of functions.
14743   context->Global()->Set(v8_str("a"), v8_num(1));
14744   CompileRun("function f1() {return a;}"
14745              "function f2() {return a;}"
14746              "function g1() {return h();}"
14747              "function g2() {return h();}"
14748              "function h() {return 1;}");
14749   Local<Function> f1 =
14750       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14751   Local<Function> f2 =
14752       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14753   Local<Function> g1 =
14754       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14755   Local<Function> g2 =
14756       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14757   Local<Function> h =
14758       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14759
14760   // Get the global object.
14761   v8::Handle<v8::Object> global = context->Global();
14762
14763   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14764   // uses the runtime system to retreive property a whereas f2 uses global load
14765   // inline cache.
14766   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14767   for (int i = 0; i < 4; i++) {
14768     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14769   }
14770
14771   // Same for g1 and g2.
14772   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14773   for (int i = 0; i < 4; i++) {
14774     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14775   }
14776
14777   // Detach the global and turn on access check.
14778   Local<Object> hidden_global = Local<Object>::Cast(
14779       context->Global()->GetPrototype());
14780   context->DetachGlobal();
14781   hidden_global->TurnOnAccessCheck();
14782
14783   // Failing access check to property get results in undefined.
14784   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14785   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14786
14787   // Failing access check to function call results in exception.
14788   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14789   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14790
14791   // No failing access check when just returning a constant.
14792   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14793 }
14794
14795
14796 static const char* kPropertyA = "a";
14797 static const char* kPropertyH = "h";
14798
14799 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14800                                        Local<Value> name,
14801                                        v8::AccessType type,
14802                                        Local<Value> data) {
14803   if (!name->IsString()) return false;
14804   i::Handle<i::String> name_handle =
14805       v8::Utils::OpenHandle(String::Cast(*name));
14806   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14807       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14808 }
14809
14810
14811 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14812   v8::Isolate* isolate = CcTest::isolate();
14813   v8::HandleScope handle_scope(isolate);
14814
14815   // Create an environment with access check to the global object disabled by
14816   // default. When the registered access checker will block access to properties
14817   // a and h.
14818   v8::Handle<v8::ObjectTemplate> global_template =
14819      v8::ObjectTemplate::New(isolate);
14820   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14821                                            IndexedGetAccessBlocker,
14822                                            v8::Handle<v8::Value>(),
14823                                            false);
14824   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14825   Context::Scope context_scope(context);
14826
14827   // Set up a property and a number of functions.
14828   context->Global()->Set(v8_str("a"), v8_num(1));
14829   static const char* source = "function f1() {return a;}"
14830                               "function f2() {return a;}"
14831                               "function g1() {return h();}"
14832                               "function g2() {return h();}"
14833                               "function h() {return 1;}";
14834
14835   CompileRun(source);
14836   Local<Function> f1;
14837   Local<Function> f2;
14838   Local<Function> g1;
14839   Local<Function> g2;
14840   Local<Function> h;
14841   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14842   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14843   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14844   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14845   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14846
14847   // Get the global object.
14848   v8::Handle<v8::Object> global = context->Global();
14849
14850   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14851   // uses the runtime system to retreive property a whereas f2 uses global load
14852   // inline cache.
14853   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14854   for (int i = 0; i < 4; i++) {
14855     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14856   }
14857
14858   // Same for g1 and g2.
14859   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14860   for (int i = 0; i < 4; i++) {
14861     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14862   }
14863
14864   // Detach the global and turn on access check now blocking access to property
14865   // a and function h.
14866   Local<Object> hidden_global = Local<Object>::Cast(
14867       context->Global()->GetPrototype());
14868   context->DetachGlobal();
14869   hidden_global->TurnOnAccessCheck();
14870
14871   // Failing access check to property get results in undefined.
14872   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14873   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14874
14875   // Failing access check to function call results in exception.
14876   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14877   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14878
14879   // No failing access check when just returning a constant.
14880   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14881
14882   // Now compile the source again. And get the newly compiled functions, except
14883   // for h for which access is blocked.
14884   CompileRun(source);
14885   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14886   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14887   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14888   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14889   CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14890
14891   // Failing access check to property get results in undefined.
14892   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14893   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14894
14895   // Failing access check to function call results in exception.
14896   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14897   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14898 }
14899
14900
14901 // Tests that ScriptData can be serialized and deserialized.
14902 TEST(PreCompileSerialization) {
14903   v8::V8::Initialize();
14904   LocalContext env;
14905   v8::Isolate* isolate = env->GetIsolate();
14906   HandleScope handle_scope(isolate);
14907
14908   i::FLAG_min_preparse_length = 0;
14909   const char* script = "function foo(a) { return a+1; }";
14910   v8::ScriptCompiler::Source source(v8_str(script));
14911   v8::ScriptCompiler::Compile(isolate, &source,
14912                               v8::ScriptCompiler::kProduceDataToCache);
14913   // Serialize.
14914   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14915   char* serialized_data = i::NewArray<char>(cd->length);
14916   i::MemCopy(serialized_data, cd->data, cd->length);
14917
14918   // Deserialize.
14919   i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
14920
14921   // Verify that the original is the same as the deserialized.
14922   CHECK_EQ(cd->length, deserialized->Length());
14923   CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
14924
14925   delete deserialized;
14926   i::DeleteArray(serialized_data);
14927 }
14928
14929
14930 // Attempts to deserialize bad data.
14931 TEST(PreCompileDeserializationError) {
14932   v8::V8::Initialize();
14933   const char* data = "DONT CARE";
14934   int invalid_size = 3;
14935   i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
14936   CHECK_EQ(NULL, sd);
14937 }
14938
14939
14940 TEST(CompileWithInvalidCachedData) {
14941   v8::V8::Initialize();
14942   v8::Isolate* isolate = CcTest::isolate();
14943   LocalContext context;
14944   v8::HandleScope scope(context->GetIsolate());
14945   i::FLAG_min_preparse_length = 0;
14946
14947   const char* script = "function foo(){ return 5;}\n"
14948       "function bar(){ return 6 + 7;}  foo();";
14949   v8::ScriptCompiler::Source source(v8_str(script));
14950   v8::ScriptCompiler::Compile(isolate, &source,
14951                               v8::ScriptCompiler::kProduceDataToCache);
14952   // source owns its cached data. Create a ScriptData based on it. The user
14953   // never needs to create ScriptDatas any more; we only need it here because we
14954   // want to modify the data before passing it back.
14955   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14956   // ScriptData does not take ownership of the buffers passed to it.
14957   i::ScriptData* sd =
14958       i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
14959   CHECK(!sd->HasError());
14960   // ScriptData private implementation details
14961   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14962   const int kFunctionEntrySize = i::FunctionEntry::kSize;
14963   const int kFunctionEntryStartOffset = 0;
14964   const int kFunctionEntryEndOffset = 1;
14965   unsigned* sd_data =
14966       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14967
14968   // Overwrite function bar's end position with 0.
14969   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14970   v8::TryCatch try_catch;
14971
14972   // Make the script slightly different so that we don't hit the compilation
14973   // cache. Don't change the lenghts of tokens.
14974   const char* script2 = "function foo(){ return 6;}\n"
14975       "function bar(){ return 6 + 7;}  foo();";
14976   v8::ScriptCompiler::Source source2(
14977       v8_str(script2),
14978       // CachedData doesn't take ownership of the buffers, Source takes
14979       // ownership of CachedData.
14980       new v8::ScriptCompiler::CachedData(
14981           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14982   Local<v8::UnboundScript> compiled_script =
14983       v8::ScriptCompiler::CompileUnbound(isolate, &source2);
14984
14985   CHECK(try_catch.HasCaught());
14986   {
14987     String::Utf8Value exception_value(try_catch.Message()->Get());
14988     CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
14989              *exception_value);
14990   }
14991
14992   try_catch.Reset();
14993   delete sd;
14994
14995   // Overwrite function bar's start position with 200. The function entry will
14996   // not be found when searching for it by position, and the compilation fails.
14997
14998   // ScriptData does not take ownership of the buffers passed to it.
14999   sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
15000   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
15001   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
15002       200;
15003   const char* script3 = "function foo(){ return 7;}\n"
15004       "function bar(){ return 6 + 7;}  foo();";
15005   v8::ScriptCompiler::Source source3(
15006       v8_str(script3),
15007       new v8::ScriptCompiler::CachedData(
15008           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
15009   compiled_script =
15010       v8::ScriptCompiler::CompileUnbound(isolate, &source3);
15011   CHECK(try_catch.HasCaught());
15012   {
15013     String::Utf8Value exception_value(try_catch.Message()->Get());
15014     CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
15015              *exception_value);
15016   }
15017   CHECK(compiled_script.IsEmpty());
15018   try_catch.Reset();
15019   delete sd;
15020
15021   // Try passing in cached data which is obviously invalid (wrong length).
15022   sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
15023   const char* script4 =
15024       "function foo(){ return 8;}\n"
15025       "function bar(){ return 6 + 7;}  foo();";
15026   v8::ScriptCompiler::Source source4(
15027       v8_str(script4),
15028       new v8::ScriptCompiler::CachedData(
15029           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
15030   compiled_script =
15031       v8::ScriptCompiler::CompileUnbound(isolate, &source4);
15032   CHECK(try_catch.HasCaught());
15033   {
15034     String::Utf8Value exception_value(try_catch.Message()->Get());
15035     CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
15036              *exception_value);
15037   }
15038   CHECK(compiled_script.IsEmpty());
15039   delete sd;
15040 }
15041
15042
15043 // This tests that we do not allow dictionary load/call inline caches
15044 // to use functions that have not yet been compiled.  The potential
15045 // problem of loading a function that has not yet been compiled can
15046 // arise because we share code between contexts via the compilation
15047 // cache.
15048 THREADED_TEST(DictionaryICLoadedFunction) {
15049   v8::HandleScope scope(CcTest::isolate());
15050   // Test LoadIC.
15051   for (int i = 0; i < 2; i++) {
15052     LocalContext context;
15053     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15054     context->Global()->Delete(v8_str("tmp"));
15055     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15056   }
15057   // Test CallIC.
15058   for (int i = 0; i < 2; i++) {
15059     LocalContext context;
15060     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15061     context->Global()->Delete(v8_str("tmp"));
15062     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15063   }
15064 }
15065
15066
15067 // Test that cross-context new calls use the context of the callee to
15068 // create the new JavaScript object.
15069 THREADED_TEST(CrossContextNew) {
15070   v8::Isolate* isolate = CcTest::isolate();
15071   v8::HandleScope scope(isolate);
15072   v8::Local<Context> context0 = Context::New(isolate);
15073   v8::Local<Context> context1 = Context::New(isolate);
15074
15075   // Allow cross-domain access.
15076   Local<String> token = v8_str("<security token>");
15077   context0->SetSecurityToken(token);
15078   context1->SetSecurityToken(token);
15079
15080   // Set an 'x' property on the Object prototype and define a
15081   // constructor function in context0.
15082   context0->Enter();
15083   CompileRun("Object.prototype.x = 42; function C() {};");
15084   context0->Exit();
15085
15086   // Call the constructor function from context0 and check that the
15087   // result has the 'x' property.
15088   context1->Enter();
15089   context1->Global()->Set(v8_str("other"), context0->Global());
15090   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15091   CHECK(value->IsInt32());
15092   CHECK_EQ(42, value->Int32Value());
15093   context1->Exit();
15094 }
15095
15096
15097 // Verify that we can clone an object
15098 TEST(ObjectClone) {
15099   LocalContext env;
15100   v8::Isolate* isolate = env->GetIsolate();
15101   v8::HandleScope scope(isolate);
15102
15103   const char* sample =
15104     "var rv = {};"      \
15105     "rv.alpha = 'hello';" \
15106     "rv.beta = 123;"     \
15107     "rv;";
15108
15109   // Create an object, verify basics.
15110   Local<Value> val = CompileRun(sample);
15111   CHECK(val->IsObject());
15112   Local<v8::Object> obj = val.As<v8::Object>();
15113   obj->Set(v8_str("gamma"), v8_str("cloneme"));
15114
15115   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15116   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15117   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15118
15119   // Clone it.
15120   Local<v8::Object> clone = obj->Clone();
15121   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15122   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15123   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15124
15125   // Set a property on the clone, verify each object.
15126   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15127   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15128   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15129 }
15130
15131
15132 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15133  public:
15134   explicit AsciiVectorResource(i::Vector<const char> vector)
15135       : data_(vector) {}
15136   virtual ~AsciiVectorResource() {}
15137   virtual size_t length() const { return data_.length(); }
15138   virtual const char* data() const { return data_.start(); }
15139  private:
15140   i::Vector<const char> data_;
15141 };
15142
15143
15144 class UC16VectorResource : public v8::String::ExternalStringResource {
15145  public:
15146   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15147       : data_(vector) {}
15148   virtual ~UC16VectorResource() {}
15149   virtual size_t length() const { return data_.length(); }
15150   virtual const i::uc16* data() const { return data_.start(); }
15151  private:
15152   i::Vector<const i::uc16> data_;
15153 };
15154
15155
15156 static void MorphAString(i::String* string,
15157                          AsciiVectorResource* ascii_resource,
15158                          UC16VectorResource* uc16_resource) {
15159   CHECK(i::StringShape(string).IsExternal());
15160   if (string->IsOneByteRepresentation()) {
15161     // Check old map is not internalized or long.
15162     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15163     // Morph external string to be TwoByte string.
15164     string->set_map(CcTest::heap()->external_string_map());
15165     i::ExternalTwoByteString* morphed =
15166          i::ExternalTwoByteString::cast(string);
15167     morphed->set_resource(uc16_resource);
15168   } else {
15169     // Check old map is not internalized or long.
15170     CHECK(string->map() == CcTest::heap()->external_string_map());
15171     // Morph external string to be ASCII string.
15172     string->set_map(CcTest::heap()->external_ascii_string_map());
15173     i::ExternalAsciiString* morphed =
15174          i::ExternalAsciiString::cast(string);
15175     morphed->set_resource(ascii_resource);
15176   }
15177 }
15178
15179
15180 // Test that we can still flatten a string if the components it is built up
15181 // from have been turned into 16 bit strings in the mean time.
15182 THREADED_TEST(MorphCompositeStringTest) {
15183   char utf_buffer[129];
15184   const char* c_string = "Now is the time for all good men"
15185                          " to come to the aid of the party";
15186   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15187   {
15188     LocalContext env;
15189     i::Factory* factory = CcTest::i_isolate()->factory();
15190     v8::HandleScope scope(env->GetIsolate());
15191     AsciiVectorResource ascii_resource(
15192         i::Vector<const char>(c_string, i::StrLength(c_string)));
15193     UC16VectorResource uc16_resource(
15194         i::Vector<const uint16_t>(two_byte_string,
15195                                   i::StrLength(c_string)));
15196
15197     Local<String> lhs(v8::Utils::ToLocal(
15198         factory->NewExternalStringFromAscii(&ascii_resource)
15199             .ToHandleChecked()));
15200     Local<String> rhs(v8::Utils::ToLocal(
15201         factory->NewExternalStringFromAscii(&ascii_resource)
15202             .ToHandleChecked()));
15203
15204     env->Global()->Set(v8_str("lhs"), lhs);
15205     env->Global()->Set(v8_str("rhs"), rhs);
15206
15207     CompileRun(
15208         "var cons = lhs + rhs;"
15209         "var slice = lhs.substring(1, lhs.length - 1);"
15210         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15211
15212     CHECK(lhs->IsOneByte());
15213     CHECK(rhs->IsOneByte());
15214
15215     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15216     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15217
15218     // This should UTF-8 without flattening, since everything is ASCII.
15219     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15220     CHECK_EQ(128, cons->Utf8Length());
15221     int nchars = -1;
15222     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15223     CHECK_EQ(128, nchars);
15224     CHECK_EQ(0, strcmp(
15225         utf_buffer,
15226         "Now is the time for all good men to come to the aid of the party"
15227         "Now is the time for all good men to come to the aid of the party"));
15228
15229     // Now do some stuff to make sure the strings are flattened, etc.
15230     CompileRun(
15231         "/[^a-z]/.test(cons);"
15232         "/[^a-z]/.test(slice);"
15233         "/[^a-z]/.test(slice_on_cons);");
15234     const char* expected_cons =
15235         "Now is the time for all good men to come to the aid of the party"
15236         "Now is the time for all good men to come to the aid of the party";
15237     const char* expected_slice =
15238         "ow is the time for all good men to come to the aid of the part";
15239     const char* expected_slice_on_cons =
15240         "ow is the time for all good men to come to the aid of the party"
15241         "Now is the time for all good men to come to the aid of the part";
15242     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15243              env->Global()->Get(v8_str("cons")));
15244     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15245              env->Global()->Get(v8_str("slice")));
15246     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15247              env->Global()->Get(v8_str("slice_on_cons")));
15248   }
15249   i::DeleteArray(two_byte_string);
15250 }
15251
15252
15253 TEST(CompileExternalTwoByteSource) {
15254   LocalContext context;
15255   v8::HandleScope scope(context->GetIsolate());
15256
15257   // This is a very short list of sources, which currently is to check for a
15258   // regression caused by r2703.
15259   const char* ascii_sources[] = {
15260     "0.5",
15261     "-0.5",   // This mainly testes PushBack in the Scanner.
15262     "--0.5",  // This mainly testes PushBack in the Scanner.
15263     NULL
15264   };
15265
15266   // Compile the sources as external two byte strings.
15267   for (int i = 0; ascii_sources[i] != NULL; i++) {
15268     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15269     TestResource* uc16_resource = new TestResource(two_byte_string);
15270     v8::Local<v8::String> source =
15271         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15272     v8::Script::Compile(source);
15273   }
15274 }
15275
15276
15277 #ifndef V8_INTERPRETED_REGEXP
15278
15279 struct RegExpInterruptionData {
15280   int loop_count;
15281   UC16VectorResource* string_resource;
15282   v8::Persistent<v8::String> string;
15283 } regexp_interruption_data;
15284
15285
15286 class RegExpInterruptionThread : public i::Thread {
15287  public:
15288   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15289       : Thread("TimeoutThread"), isolate_(isolate) {}
15290
15291   virtual void Run() {
15292     for (regexp_interruption_data.loop_count = 0;
15293          regexp_interruption_data.loop_count < 7;
15294          regexp_interruption_data.loop_count++) {
15295       i::OS::Sleep(50);  // Wait a bit before requesting GC.
15296       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15297     }
15298     i::OS::Sleep(50);  // Wait a bit before terminating.
15299     v8::V8::TerminateExecution(isolate_);
15300   }
15301
15302  private:
15303   v8::Isolate* isolate_;
15304 };
15305
15306
15307 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15308   if (regexp_interruption_data.loop_count != 2) return;
15309   v8::HandleScope scope(CcTest::isolate());
15310   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15311       CcTest::isolate(), regexp_interruption_data.string);
15312   string->MakeExternal(regexp_interruption_data.string_resource);
15313 }
15314
15315
15316 // Test that RegExp execution can be interrupted.  Specifically, we test
15317 // * interrupting with GC
15318 // * turn the subject string from one-byte internal to two-byte external string
15319 // * force termination
15320 TEST(RegExpInterruption) {
15321   v8::HandleScope scope(CcTest::isolate());
15322   LocalContext env;
15323
15324   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15325
15326   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15327   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15328   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15329   v8::Local<v8::String> string = v8_str(ascii_content);
15330
15331   CcTest::global()->Set(v8_str("a"), string);
15332   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15333   regexp_interruption_data.string_resource = new UC16VectorResource(
15334       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15335
15336   v8::TryCatch try_catch;
15337   timeout_thread.Start();
15338
15339   CompileRun("/((a*)*)*b/.exec(a)");
15340   CHECK(try_catch.HasTerminated());
15341
15342   timeout_thread.Join();
15343
15344   regexp_interruption_data.string.Reset();
15345   i::DeleteArray(uc16_content);
15346 }
15347
15348 #endif  // V8_INTERPRETED_REGEXP
15349
15350
15351 // Test that we cannot set a property on the global object if there
15352 // is a read-only property in the prototype chain.
15353 TEST(ReadOnlyPropertyInGlobalProto) {
15354   v8::Isolate* isolate = CcTest::isolate();
15355   v8::HandleScope scope(isolate);
15356   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15357   LocalContext context(0, templ);
15358   v8::Handle<v8::Object> global = context->Global();
15359   v8::Handle<v8::Object> global_proto =
15360       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15361   global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15362   global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15363   // Check without 'eval' or 'with'.
15364   v8::Handle<v8::Value> res =
15365       CompileRun("function f() { x = 42; return x; }; f()");
15366   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15367   // Check with 'eval'.
15368   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15369   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15370   // Check with 'with'.
15371   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15372   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15373 }
15374
15375 static int force_set_set_count = 0;
15376 static int force_set_get_count = 0;
15377 bool pass_on_get = false;
15378
15379 static void ForceSetGetter(v8::Local<v8::String> name,
15380                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15381   force_set_get_count++;
15382   if (pass_on_get) {
15383     return;
15384   }
15385   info.GetReturnValue().Set(3);
15386 }
15387
15388 static void ForceSetSetter(v8::Local<v8::String> name,
15389                            v8::Local<v8::Value> value,
15390                            const v8::PropertyCallbackInfo<void>& info) {
15391   force_set_set_count++;
15392 }
15393
15394 static void ForceSetInterceptSetter(
15395     v8::Local<v8::String> name,
15396     v8::Local<v8::Value> value,
15397     const v8::PropertyCallbackInfo<v8::Value>& info) {
15398   force_set_set_count++;
15399   info.GetReturnValue().SetUndefined();
15400 }
15401
15402
15403 TEST(ForceSet) {
15404   force_set_get_count = 0;
15405   force_set_set_count = 0;
15406   pass_on_get = false;
15407
15408   v8::Isolate* isolate = CcTest::isolate();
15409   v8::HandleScope scope(isolate);
15410   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15411   v8::Handle<v8::String> access_property =
15412       v8::String::NewFromUtf8(isolate, "a");
15413   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15414   LocalContext context(NULL, templ);
15415   v8::Handle<v8::Object> global = context->Global();
15416
15417   // Ordinary properties
15418   v8::Handle<v8::String> simple_property =
15419       v8::String::NewFromUtf8(isolate, "p");
15420   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15421   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15422   // This should fail because the property is read-only
15423   global->Set(simple_property, v8::Int32::New(isolate, 5));
15424   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15425   // This should succeed even though the property is read-only
15426   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15427   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15428
15429   // Accessors
15430   CHECK_EQ(0, force_set_set_count);
15431   CHECK_EQ(0, force_set_get_count);
15432   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15433   // CHECK_EQ the property shouldn't override it, just call the setter
15434   // which in this case does nothing.
15435   global->Set(access_property, v8::Int32::New(isolate, 7));
15436   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15437   CHECK_EQ(1, force_set_set_count);
15438   CHECK_EQ(2, force_set_get_count);
15439   // Forcing the property to be set should override the accessor without
15440   // calling it
15441   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15442   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15443   CHECK_EQ(1, force_set_set_count);
15444   CHECK_EQ(2, force_set_get_count);
15445 }
15446
15447
15448 TEST(ForceSetWithInterceptor) {
15449   force_set_get_count = 0;
15450   force_set_set_count = 0;
15451   pass_on_get = false;
15452
15453   v8::Isolate* isolate = CcTest::isolate();
15454   v8::HandleScope scope(isolate);
15455   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15456   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15457   LocalContext context(NULL, templ);
15458   v8::Handle<v8::Object> global = context->Global();
15459
15460   v8::Handle<v8::String> some_property =
15461       v8::String::NewFromUtf8(isolate, "a");
15462   CHECK_EQ(0, force_set_set_count);
15463   CHECK_EQ(0, force_set_get_count);
15464   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15465   // Setting the property shouldn't override it, just call the setter
15466   // which in this case does nothing.
15467   global->Set(some_property, v8::Int32::New(isolate, 7));
15468   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15469   CHECK_EQ(1, force_set_set_count);
15470   CHECK_EQ(2, force_set_get_count);
15471   // Getting the property when the interceptor returns an empty handle
15472   // should yield undefined, since the property isn't present on the
15473   // object itself yet.
15474   pass_on_get = true;
15475   CHECK(global->Get(some_property)->IsUndefined());
15476   CHECK_EQ(1, force_set_set_count);
15477   CHECK_EQ(3, force_set_get_count);
15478   // Forcing the property to be set should cause the value to be
15479   // set locally without calling the interceptor.
15480   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15481   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15482   CHECK_EQ(1, force_set_set_count);
15483   CHECK_EQ(4, force_set_get_count);
15484   // Reenabling the interceptor should cause it to take precedence over
15485   // the property
15486   pass_on_get = false;
15487   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15488   CHECK_EQ(1, force_set_set_count);
15489   CHECK_EQ(5, force_set_get_count);
15490   // The interceptor should also work for other properties
15491   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15492                   ->Int32Value());
15493   CHECK_EQ(1, force_set_set_count);
15494   CHECK_EQ(6, force_set_get_count);
15495 }
15496
15497
15498 THREADED_TEST(ForceDelete) {
15499   v8::Isolate* isolate = CcTest::isolate();
15500   v8::HandleScope scope(isolate);
15501   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15502   LocalContext context(NULL, templ);
15503   v8::Handle<v8::Object> global = context->Global();
15504
15505   // Ordinary properties
15506   v8::Handle<v8::String> simple_property =
15507       v8::String::NewFromUtf8(isolate, "p");
15508   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15509   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15510   // This should fail because the property is dont-delete.
15511   CHECK(!global->Delete(simple_property));
15512   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15513   // This should succeed even though the property is dont-delete.
15514   CHECK(global->ForceDelete(simple_property));
15515   CHECK(global->Get(simple_property)->IsUndefined());
15516 }
15517
15518
15519 static int force_delete_interceptor_count = 0;
15520 static bool pass_on_delete = false;
15521
15522
15523 static void ForceDeleteDeleter(
15524     v8::Local<v8::String> name,
15525     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15526   force_delete_interceptor_count++;
15527   if (pass_on_delete) return;
15528   info.GetReturnValue().Set(true);
15529 }
15530
15531
15532 THREADED_TEST(ForceDeleteWithInterceptor) {
15533   force_delete_interceptor_count = 0;
15534   pass_on_delete = false;
15535
15536   v8::Isolate* isolate = CcTest::isolate();
15537   v8::HandleScope scope(isolate);
15538   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15539   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15540   LocalContext context(NULL, templ);
15541   v8::Handle<v8::Object> global = context->Global();
15542
15543   v8::Handle<v8::String> some_property =
15544       v8::String::NewFromUtf8(isolate, "a");
15545   global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15546
15547   // Deleting a property should get intercepted and nothing should
15548   // happen.
15549   CHECK_EQ(0, force_delete_interceptor_count);
15550   CHECK(global->Delete(some_property));
15551   CHECK_EQ(1, force_delete_interceptor_count);
15552   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15553   // Deleting the property when the interceptor returns an empty
15554   // handle should not delete the property since it is DontDelete.
15555   pass_on_delete = true;
15556   CHECK(!global->Delete(some_property));
15557   CHECK_EQ(2, force_delete_interceptor_count);
15558   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15559   // Forcing the property to be deleted should delete the value
15560   // without calling the interceptor.
15561   CHECK(global->ForceDelete(some_property));
15562   CHECK(global->Get(some_property)->IsUndefined());
15563   CHECK_EQ(2, force_delete_interceptor_count);
15564 }
15565
15566
15567 // Make sure that forcing a delete invalidates any IC stubs, so we
15568 // don't read the hole value.
15569 THREADED_TEST(ForceDeleteIC) {
15570   LocalContext context;
15571   v8::HandleScope scope(context->GetIsolate());
15572   // Create a DontDelete variable on the global object.
15573   CompileRun("this.__proto__ = { foo: 'horse' };"
15574              "var foo = 'fish';"
15575              "function f() { return foo.length; }");
15576   // Initialize the IC for foo in f.
15577   CompileRun("for (var i = 0; i < 4; i++) f();");
15578   // Make sure the value of foo is correct before the deletion.
15579   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15580   // Force the deletion of foo.
15581   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15582   // Make sure the value for foo is read from the prototype, and that
15583   // we don't get in trouble with reading the deleted cell value
15584   // sentinel.
15585   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15586 }
15587
15588
15589 TEST(InlinedFunctionAcrossContexts) {
15590   i::FLAG_allow_natives_syntax = true;
15591   v8::Isolate* isolate = CcTest::isolate();
15592   v8::HandleScope outer_scope(isolate);
15593   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15594   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15595   ctx1->Enter();
15596
15597   {
15598     v8::HandleScope inner_scope(CcTest::isolate());
15599     CompileRun("var G = 42; function foo() { return G; }");
15600     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15601     ctx2->Enter();
15602     ctx2->Global()->Set(v8_str("o"), foo);
15603     v8::Local<v8::Value> res = CompileRun(
15604         "function f() { return o(); }"
15605         "for (var i = 0; i < 10; ++i) f();"
15606         "%OptimizeFunctionOnNextCall(f);"
15607         "f();");
15608     CHECK_EQ(42, res->Int32Value());
15609     ctx2->Exit();
15610     v8::Handle<v8::String> G_property =
15611         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15612     CHECK(ctx1->Global()->ForceDelete(G_property));
15613     ctx2->Enter();
15614     ExpectString(
15615         "(function() {"
15616         "  try {"
15617         "    return f();"
15618         "  } catch(e) {"
15619         "    return e.toString();"
15620         "  }"
15621         " })()",
15622         "ReferenceError: G is not defined");
15623     ctx2->Exit();
15624     ctx1->Exit();
15625   }
15626 }
15627
15628
15629 static v8::Local<Context> calling_context0;
15630 static v8::Local<Context> calling_context1;
15631 static v8::Local<Context> calling_context2;
15632
15633
15634 // Check that the call to the callback is initiated in
15635 // calling_context2, the directly calling context is calling_context1
15636 // and the callback itself is in calling_context0.
15637 static void GetCallingContextCallback(
15638     const v8::FunctionCallbackInfo<v8::Value>& args) {
15639   ApiTestFuzzer::Fuzz();
15640   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15641   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15642   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15643   args.GetReturnValue().Set(42);
15644 }
15645
15646
15647 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15648   i::Isolate* isolate = CcTest::i_isolate();
15649   CHECK(isolate != NULL);
15650   CHECK(isolate->context() == NULL);
15651   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15652   v8::HandleScope scope(v8_isolate);
15653   // The following should not crash, but return an empty handle.
15654   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15655   CHECK(current.IsEmpty());
15656 }
15657
15658
15659 THREADED_TEST(GetCallingContext) {
15660   v8::Isolate* isolate = CcTest::isolate();
15661   v8::HandleScope scope(isolate);
15662
15663   Local<Context> calling_context0(Context::New(isolate));
15664   Local<Context> calling_context1(Context::New(isolate));
15665   Local<Context> calling_context2(Context::New(isolate));
15666   ::calling_context0 = calling_context0;
15667   ::calling_context1 = calling_context1;
15668   ::calling_context2 = calling_context2;
15669
15670   // Allow cross-domain access.
15671   Local<String> token = v8_str("<security token>");
15672   calling_context0->SetSecurityToken(token);
15673   calling_context1->SetSecurityToken(token);
15674   calling_context2->SetSecurityToken(token);
15675
15676   // Create an object with a C++ callback in context0.
15677   calling_context0->Enter();
15678   Local<v8::FunctionTemplate> callback_templ =
15679       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15680   calling_context0->Global()->Set(v8_str("callback"),
15681                                   callback_templ->GetFunction());
15682   calling_context0->Exit();
15683
15684   // Expose context0 in context1 and set up a function that calls the
15685   // callback function.
15686   calling_context1->Enter();
15687   calling_context1->Global()->Set(v8_str("context0"),
15688                                   calling_context0->Global());
15689   CompileRun("function f() { context0.callback() }");
15690   calling_context1->Exit();
15691
15692   // Expose context1 in context2 and call the callback function in
15693   // context0 indirectly through f in context1.
15694   calling_context2->Enter();
15695   calling_context2->Global()->Set(v8_str("context1"),
15696                                   calling_context1->Global());
15697   CompileRun("context1.f()");
15698   calling_context2->Exit();
15699   ::calling_context0.Clear();
15700   ::calling_context1.Clear();
15701   ::calling_context2.Clear();
15702 }
15703
15704
15705 // Check that a variable declaration with no explicit initialization
15706 // value does shadow an existing property in the prototype chain.
15707 THREADED_TEST(InitGlobalVarInProtoChain) {
15708   LocalContext context;
15709   v8::HandleScope scope(context->GetIsolate());
15710   // Introduce a variable in the prototype chain.
15711   CompileRun("__proto__.x = 42");
15712   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15713   CHECK(!result->IsUndefined());
15714   CHECK_EQ(43, result->Int32Value());
15715 }
15716
15717
15718 // Regression test for issue 398.
15719 // If a function is added to an object, creating a constant function
15720 // field, and the result is cloned, replacing the constant function on the
15721 // original should not affect the clone.
15722 // See http://code.google.com/p/v8/issues/detail?id=398
15723 THREADED_TEST(ReplaceConstantFunction) {
15724   LocalContext context;
15725   v8::Isolate* isolate = context->GetIsolate();
15726   v8::HandleScope scope(isolate);
15727   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15728   v8::Handle<v8::FunctionTemplate> func_templ =
15729       v8::FunctionTemplate::New(isolate);
15730   v8::Handle<v8::String> foo_string =
15731       v8::String::NewFromUtf8(isolate, "foo");
15732   obj->Set(foo_string, func_templ->GetFunction());
15733   v8::Handle<v8::Object> obj_clone = obj->Clone();
15734   obj_clone->Set(foo_string,
15735                  v8::String::NewFromUtf8(isolate, "Hello"));
15736   CHECK(!obj->Get(foo_string)->IsUndefined());
15737 }
15738
15739
15740 static void CheckElementValue(i::Isolate* isolate,
15741                               int expected,
15742                               i::Handle<i::Object> obj,
15743                               int offset) {
15744   i::Object* element =
15745       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15746   CHECK_EQ(expected, i::Smi::cast(element)->value());
15747 }
15748
15749
15750 THREADED_TEST(PixelArray) {
15751   LocalContext context;
15752   i::Isolate* isolate = CcTest::i_isolate();
15753   i::Factory* factory = isolate->factory();
15754   v8::HandleScope scope(context->GetIsolate());
15755   const int kElementCount = 260;
15756   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15757   i::Handle<i::ExternalUint8ClampedArray> pixels =
15758       i::Handle<i::ExternalUint8ClampedArray>::cast(
15759           factory->NewExternalArray(kElementCount,
15760                                     v8::kExternalUint8ClampedArray,
15761                                     pixel_data));
15762   // Force GC to trigger verification.
15763   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15764   for (int i = 0; i < kElementCount; i++) {
15765     pixels->set(i, i % 256);
15766   }
15767   // Force GC to trigger verification.
15768   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15769   for (int i = 0; i < kElementCount; i++) {
15770     CHECK_EQ(i % 256, pixels->get_scalar(i));
15771     CHECK_EQ(i % 256, pixel_data[i]);
15772   }
15773
15774   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15775   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15776   // Set the elements to be the pixels.
15777   // jsobj->set_elements(*pixels);
15778   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15779   CheckElementValue(isolate, 1, jsobj, 1);
15780   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15781   context->Global()->Set(v8_str("pixels"), obj);
15782   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15783   CHECK_EQ(1503, result->Int32Value());
15784   result = CompileRun("pixels[1]");
15785   CHECK_EQ(1, result->Int32Value());
15786
15787   result = CompileRun("var sum = 0;"
15788                       "for (var i = 0; i < 8; i++) {"
15789                       "  sum += pixels[i] = pixels[i] = -i;"
15790                       "}"
15791                       "sum;");
15792   CHECK_EQ(-28, result->Int32Value());
15793
15794   result = CompileRun("var sum = 0;"
15795                       "for (var i = 0; i < 8; i++) {"
15796                       "  sum += pixels[i] = pixels[i] = 0;"
15797                       "}"
15798                       "sum;");
15799   CHECK_EQ(0, result->Int32Value());
15800
15801   result = CompileRun("var sum = 0;"
15802                       "for (var i = 0; i < 8; i++) {"
15803                       "  sum += pixels[i] = pixels[i] = 255;"
15804                       "}"
15805                       "sum;");
15806   CHECK_EQ(8 * 255, result->Int32Value());
15807
15808   result = CompileRun("var sum = 0;"
15809                       "for (var i = 0; i < 8; i++) {"
15810                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15811                       "}"
15812                       "sum;");
15813   CHECK_EQ(2076, result->Int32Value());
15814
15815   result = CompileRun("var sum = 0;"
15816                       "for (var i = 0; i < 8; i++) {"
15817                       "  sum += pixels[i] = pixels[i] = i;"
15818                       "}"
15819                       "sum;");
15820   CHECK_EQ(28, result->Int32Value());
15821
15822   result = CompileRun("var sum = 0;"
15823                       "for (var i = 0; i < 8; i++) {"
15824                       "  sum += pixels[i];"
15825                       "}"
15826                       "sum;");
15827   CHECK_EQ(28, result->Int32Value());
15828
15829   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15830                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15831   i::Handle<i::Object> no_failure;
15832   no_failure = i::JSObject::SetElement(
15833       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15834   ASSERT(!no_failure.is_null());
15835   USE(no_failure);
15836   CheckElementValue(isolate, 2, jsobj, 1);
15837   *value.location() = i::Smi::FromInt(256);
15838   no_failure = i::JSObject::SetElement(
15839       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15840   ASSERT(!no_failure.is_null());
15841   USE(no_failure);
15842   CheckElementValue(isolate, 255, jsobj, 1);
15843   *value.location() = i::Smi::FromInt(-1);
15844   no_failure = i::JSObject::SetElement(
15845       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15846   ASSERT(!no_failure.is_null());
15847   USE(no_failure);
15848   CheckElementValue(isolate, 0, jsobj, 1);
15849
15850   result = CompileRun("for (var i = 0; i < 8; i++) {"
15851                       "  pixels[i] = (i * 65) - 109;"
15852                       "}"
15853                       "pixels[1] + pixels[6];");
15854   CHECK_EQ(255, result->Int32Value());
15855   CheckElementValue(isolate, 0, jsobj, 0);
15856   CheckElementValue(isolate, 0, jsobj, 1);
15857   CheckElementValue(isolate, 21, jsobj, 2);
15858   CheckElementValue(isolate, 86, jsobj, 3);
15859   CheckElementValue(isolate, 151, jsobj, 4);
15860   CheckElementValue(isolate, 216, jsobj, 5);
15861   CheckElementValue(isolate, 255, jsobj, 6);
15862   CheckElementValue(isolate, 255, jsobj, 7);
15863   result = CompileRun("var sum = 0;"
15864                       "for (var i = 0; i < 8; i++) {"
15865                       "  sum += pixels[i];"
15866                       "}"
15867                       "sum;");
15868   CHECK_EQ(984, result->Int32Value());
15869
15870   result = CompileRun("for (var i = 0; i < 8; i++) {"
15871                       "  pixels[i] = (i * 1.1);"
15872                       "}"
15873                       "pixels[1] + pixels[6];");
15874   CHECK_EQ(8, result->Int32Value());
15875   CheckElementValue(isolate, 0, jsobj, 0);
15876   CheckElementValue(isolate, 1, jsobj, 1);
15877   CheckElementValue(isolate, 2, jsobj, 2);
15878   CheckElementValue(isolate, 3, jsobj, 3);
15879   CheckElementValue(isolate, 4, jsobj, 4);
15880   CheckElementValue(isolate, 6, jsobj, 5);
15881   CheckElementValue(isolate, 7, jsobj, 6);
15882   CheckElementValue(isolate, 8, jsobj, 7);
15883
15884   result = CompileRun("for (var i = 0; i < 8; i++) {"
15885                       "  pixels[7] = undefined;"
15886                       "}"
15887                       "pixels[7];");
15888   CHECK_EQ(0, result->Int32Value());
15889   CheckElementValue(isolate, 0, jsobj, 7);
15890
15891   result = CompileRun("for (var i = 0; i < 8; i++) {"
15892                       "  pixels[6] = '2.3';"
15893                       "}"
15894                       "pixels[6];");
15895   CHECK_EQ(2, result->Int32Value());
15896   CheckElementValue(isolate, 2, jsobj, 6);
15897
15898   result = CompileRun("for (var i = 0; i < 8; i++) {"
15899                       "  pixels[5] = NaN;"
15900                       "}"
15901                       "pixels[5];");
15902   CHECK_EQ(0, result->Int32Value());
15903   CheckElementValue(isolate, 0, jsobj, 5);
15904
15905   result = CompileRun("for (var i = 0; i < 8; i++) {"
15906                       "  pixels[8] = Infinity;"
15907                       "}"
15908                       "pixels[8];");
15909   CHECK_EQ(255, result->Int32Value());
15910   CheckElementValue(isolate, 255, jsobj, 8);
15911
15912   result = CompileRun("for (var i = 0; i < 8; i++) {"
15913                       "  pixels[9] = -Infinity;"
15914                       "}"
15915                       "pixels[9];");
15916   CHECK_EQ(0, result->Int32Value());
15917   CheckElementValue(isolate, 0, jsobj, 9);
15918
15919   result = CompileRun("pixels[3] = 33;"
15920                       "delete pixels[3];"
15921                       "pixels[3];");
15922   CHECK_EQ(33, result->Int32Value());
15923
15924   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15925                       "pixels[2] = 12; pixels[3] = 13;"
15926                       "pixels.__defineGetter__('2',"
15927                       "function() { return 120; });"
15928                       "pixels[2];");
15929   CHECK_EQ(12, result->Int32Value());
15930
15931   result = CompileRun("var js_array = new Array(40);"
15932                       "js_array[0] = 77;"
15933                       "js_array;");
15934   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15935
15936   result = CompileRun("pixels[1] = 23;"
15937                       "pixels.__proto__ = [];"
15938                       "js_array.__proto__ = pixels;"
15939                       "js_array.concat(pixels);");
15940   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15941   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15942
15943   result = CompileRun("pixels[1] = 23;");
15944   CHECK_EQ(23, result->Int32Value());
15945
15946   // Test for index greater than 255.  Regression test for:
15947   // http://code.google.com/p/chromium/issues/detail?id=26337.
15948   result = CompileRun("pixels[256] = 255;");
15949   CHECK_EQ(255, result->Int32Value());
15950   result = CompileRun("var i = 0;"
15951                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15952                       "i");
15953   CHECK_EQ(255, result->Int32Value());
15954
15955   // Make sure that pixel array ICs recognize when a non-pixel array
15956   // is passed to it.
15957   result = CompileRun("function pa_load(p) {"
15958                       "  var sum = 0;"
15959                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15960                       "  return sum;"
15961                       "}"
15962                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15963                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15964                       "just_ints = new Object();"
15965                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15966                       "for (var i = 0; i < 10; ++i) {"
15967                       "  result = pa_load(just_ints);"
15968                       "}"
15969                       "result");
15970   CHECK_EQ(32640, result->Int32Value());
15971
15972   // Make sure that pixel array ICs recognize out-of-bound accesses.
15973   result = CompileRun("function pa_load(p, start) {"
15974                       "  var sum = 0;"
15975                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15976                       "  return sum;"
15977                       "}"
15978                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15979                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15980                       "for (var i = 0; i < 10; ++i) {"
15981                       "  result = pa_load(pixels,-10);"
15982                       "}"
15983                       "result");
15984   CHECK_EQ(0, result->Int32Value());
15985
15986   // Make sure that generic ICs properly handles a pixel array.
15987   result = CompileRun("function pa_load(p) {"
15988                       "  var sum = 0;"
15989                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15990                       "  return sum;"
15991                       "}"
15992                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15993                       "just_ints = new Object();"
15994                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15995                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15996                       "for (var i = 0; i < 10; ++i) {"
15997                       "  result = pa_load(pixels);"
15998                       "}"
15999                       "result");
16000   CHECK_EQ(32640, result->Int32Value());
16001
16002   // Make sure that generic load ICs recognize out-of-bound accesses in
16003   // pixel arrays.
16004   result = CompileRun("function pa_load(p, start) {"
16005                       "  var sum = 0;"
16006                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16007                       "  return sum;"
16008                       "}"
16009                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16010                       "just_ints = new Object();"
16011                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16012                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16013                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16014                       "for (var i = 0; i < 10; ++i) {"
16015                       "  result = pa_load(pixels,-10);"
16016                       "}"
16017                       "result");
16018   CHECK_EQ(0, result->Int32Value());
16019
16020   // Make sure that generic ICs properly handles other types than pixel
16021   // arrays (that the inlined fast pixel array test leaves the right information
16022   // in the right registers).
16023   result = CompileRun("function pa_load(p) {"
16024                       "  var sum = 0;"
16025                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16026                       "  return sum;"
16027                       "}"
16028                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16029                       "just_ints = new Object();"
16030                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16031                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16032                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16033                       "sparse_array = new Object();"
16034                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16035                       "sparse_array[1000000] = 3;"
16036                       "for (var i = 0; i < 10; ++i) {"
16037                       "  result = pa_load(sparse_array);"
16038                       "}"
16039                       "result");
16040   CHECK_EQ(32640, result->Int32Value());
16041
16042   // Make sure that pixel array store ICs clamp values correctly.
16043   result = CompileRun("function pa_store(p) {"
16044                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16045                       "}"
16046                       "pa_store(pixels);"
16047                       "var sum = 0;"
16048                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16049                       "sum");
16050   CHECK_EQ(48896, result->Int32Value());
16051
16052   // Make sure that pixel array stores correctly handle accesses outside
16053   // of the pixel array..
16054   result = CompileRun("function pa_store(p,start) {"
16055                       "  for (var j = 0; j < 256; j++) {"
16056                       "    p[j+start] = j * 2;"
16057                       "  }"
16058                       "}"
16059                       "pa_store(pixels,0);"
16060                       "pa_store(pixels,-128);"
16061                       "var sum = 0;"
16062                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16063                       "sum");
16064   CHECK_EQ(65280, result->Int32Value());
16065
16066   // Make sure that the generic store stub correctly handle accesses outside
16067   // of the pixel array..
16068   result = CompileRun("function pa_store(p,start) {"
16069                       "  for (var j = 0; j < 256; j++) {"
16070                       "    p[j+start] = j * 2;"
16071                       "  }"
16072                       "}"
16073                       "pa_store(pixels,0);"
16074                       "just_ints = new Object();"
16075                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16076                       "pa_store(just_ints, 0);"
16077                       "pa_store(pixels,-128);"
16078                       "var sum = 0;"
16079                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16080                       "sum");
16081   CHECK_EQ(65280, result->Int32Value());
16082
16083   // Make sure that the generic keyed store stub clamps pixel array values
16084   // correctly.
16085   result = CompileRun("function pa_store(p) {"
16086                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16087                       "}"
16088                       "pa_store(pixels);"
16089                       "just_ints = new Object();"
16090                       "pa_store(just_ints);"
16091                       "pa_store(pixels);"
16092                       "var sum = 0;"
16093                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16094                       "sum");
16095   CHECK_EQ(48896, result->Int32Value());
16096
16097   // Make sure that pixel array loads are optimized by crankshaft.
16098   result = CompileRun("function pa_load(p) {"
16099                       "  var sum = 0;"
16100                       "  for (var i=0; i<256; ++i) {"
16101                       "    sum += p[i];"
16102                       "  }"
16103                       "  return sum; "
16104                       "}"
16105                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16106                       "for (var i = 0; i < 5000; ++i) {"
16107                       "  result = pa_load(pixels);"
16108                       "}"
16109                       "result");
16110   CHECK_EQ(32640, result->Int32Value());
16111
16112   // Make sure that pixel array stores are optimized by crankshaft.
16113   result = CompileRun("function pa_init(p) {"
16114                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16115                       "}"
16116                       "function pa_load(p) {"
16117                       "  var sum = 0;"
16118                       "  for (var i=0; i<256; ++i) {"
16119                       "    sum += p[i];"
16120                       "  }"
16121                       "  return sum; "
16122                       "}"
16123                       "for (var i = 0; i < 5000; ++i) {"
16124                       "  pa_init(pixels);"
16125                       "}"
16126                       "result = pa_load(pixels);"
16127                       "result");
16128   CHECK_EQ(32640, result->Int32Value());
16129
16130   free(pixel_data);
16131 }
16132
16133
16134 THREADED_TEST(PixelArrayInfo) {
16135   LocalContext context;
16136   v8::HandleScope scope(context->GetIsolate());
16137   for (int size = 0; size < 100; size += 10) {
16138     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16139     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16140     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16141     CHECK(obj->HasIndexedPropertiesInPixelData());
16142     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16143     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16144     free(pixel_data);
16145   }
16146 }
16147
16148
16149 static void NotHandledIndexedPropertyGetter(
16150     uint32_t index,
16151     const v8::PropertyCallbackInfo<v8::Value>& info) {
16152   ApiTestFuzzer::Fuzz();
16153 }
16154
16155
16156 static void NotHandledIndexedPropertySetter(
16157     uint32_t index,
16158     Local<Value> value,
16159     const v8::PropertyCallbackInfo<v8::Value>& info) {
16160   ApiTestFuzzer::Fuzz();
16161 }
16162
16163
16164 THREADED_TEST(PixelArrayWithInterceptor) {
16165   LocalContext context;
16166   i::Factory* factory = CcTest::i_isolate()->factory();
16167   v8::Isolate* isolate = context->GetIsolate();
16168   v8::HandleScope scope(isolate);
16169   const int kElementCount = 260;
16170   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16171   i::Handle<i::ExternalUint8ClampedArray> pixels =
16172       i::Handle<i::ExternalUint8ClampedArray>::cast(
16173           factory->NewExternalArray(kElementCount,
16174                                     v8::kExternalUint8ClampedArray,
16175                                     pixel_data));
16176   for (int i = 0; i < kElementCount; i++) {
16177     pixels->set(i, i % 256);
16178   }
16179   v8::Handle<v8::ObjectTemplate> templ =
16180       v8::ObjectTemplate::New(context->GetIsolate());
16181   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16182                                    NotHandledIndexedPropertySetter);
16183   v8::Handle<v8::Object> obj = templ->NewInstance();
16184   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16185   context->Global()->Set(v8_str("pixels"), obj);
16186   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16187   CHECK_EQ(1, result->Int32Value());
16188   result = CompileRun("var sum = 0;"
16189                       "for (var i = 0; i < 8; i++) {"
16190                       "  sum += pixels[i] = pixels[i] = -i;"
16191                       "}"
16192                       "sum;");
16193   CHECK_EQ(-28, result->Int32Value());
16194   result = CompileRun("pixels.hasOwnProperty('1')");
16195   CHECK(result->BooleanValue());
16196   free(pixel_data);
16197 }
16198
16199
16200 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16201   switch (array_type) {
16202     case v8::kExternalInt8Array:
16203     case v8::kExternalUint8Array:
16204     case v8::kExternalUint8ClampedArray:
16205       return 1;
16206       break;
16207     case v8::kExternalInt16Array:
16208     case v8::kExternalUint16Array:
16209       return 2;
16210       break;
16211     case v8::kExternalInt32Array:
16212     case v8::kExternalUint32Array:
16213     case v8::kExternalFloat32Array:
16214       return 4;
16215       break;
16216     case v8::kExternalFloat64Array:
16217       return 8;
16218       break;
16219     default:
16220       UNREACHABLE();
16221       return -1;
16222   }
16223   UNREACHABLE();
16224   return -1;
16225 }
16226
16227
16228 template <class ExternalArrayClass, class ElementType>
16229 static void ObjectWithExternalArrayTestHelper(
16230     Handle<Context> context,
16231     v8::Handle<Object> obj,
16232     int element_count,
16233     v8::ExternalArrayType array_type,
16234     int64_t low, int64_t high) {
16235   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16236   i::Isolate* isolate = jsobj->GetIsolate();
16237   obj->Set(v8_str("field"),
16238            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16239   context->Global()->Set(v8_str("ext_array"), obj);
16240   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16241   CHECK_EQ(1503, result->Int32Value());
16242   result = CompileRun("ext_array[1]");
16243   CHECK_EQ(1, result->Int32Value());
16244
16245   // Check assigned smis
16246   result = CompileRun("for (var i = 0; i < 8; i++) {"
16247                       "  ext_array[i] = i;"
16248                       "}"
16249                       "var sum = 0;"
16250                       "for (var i = 0; i < 8; i++) {"
16251                       "  sum += ext_array[i];"
16252                       "}"
16253                       "sum;");
16254
16255   CHECK_EQ(28, result->Int32Value());
16256   // Check pass through of assigned smis
16257   result = CompileRun("var sum = 0;"
16258                       "for (var i = 0; i < 8; i++) {"
16259                       "  sum += ext_array[i] = ext_array[i] = -i;"
16260                       "}"
16261                       "sum;");
16262   CHECK_EQ(-28, result->Int32Value());
16263
16264
16265   // Check assigned smis in reverse order
16266   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16267                       "  ext_array[i] = i;"
16268                       "}"
16269                       "var sum = 0;"
16270                       "for (var i = 0; i < 8; i++) {"
16271                       "  sum += ext_array[i];"
16272                       "}"
16273                       "sum;");
16274   CHECK_EQ(28, result->Int32Value());
16275
16276   // Check pass through of assigned HeapNumbers
16277   result = CompileRun("var sum = 0;"
16278                       "for (var i = 0; i < 16; i+=2) {"
16279                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16280                       "}"
16281                       "sum;");
16282   CHECK_EQ(-28, result->Int32Value());
16283
16284   // Check assigned HeapNumbers
16285   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16286                       "  ext_array[i] = (i * 0.5);"
16287                       "}"
16288                       "var sum = 0;"
16289                       "for (var i = 0; i < 16; i+=2) {"
16290                       "  sum += ext_array[i];"
16291                       "}"
16292                       "sum;");
16293   CHECK_EQ(28, result->Int32Value());
16294
16295   // Check assigned HeapNumbers in reverse order
16296   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16297                       "  ext_array[i] = (i * 0.5);"
16298                       "}"
16299                       "var sum = 0;"
16300                       "for (var i = 0; i < 16; i+=2) {"
16301                       "  sum += ext_array[i];"
16302                       "}"
16303                       "sum;");
16304   CHECK_EQ(28, result->Int32Value());
16305
16306   i::ScopedVector<char> test_buf(1024);
16307
16308   // Check legal boundary conditions.
16309   // The repeated loads and stores ensure the ICs are exercised.
16310   const char* boundary_program =
16311       "var res = 0;"
16312       "for (var i = 0; i < 16; i++) {"
16313       "  ext_array[i] = %lld;"
16314       "  if (i > 8) {"
16315       "    res = ext_array[i];"
16316       "  }"
16317       "}"
16318       "res;";
16319   i::SNPrintF(test_buf,
16320               boundary_program,
16321               low);
16322   result = CompileRun(test_buf.start());
16323   CHECK_EQ(low, result->IntegerValue());
16324
16325   i::SNPrintF(test_buf,
16326               boundary_program,
16327               high);
16328   result = CompileRun(test_buf.start());
16329   CHECK_EQ(high, result->IntegerValue());
16330
16331   // Check misprediction of type in IC.
16332   result = CompileRun("var tmp_array = ext_array;"
16333                       "var sum = 0;"
16334                       "for (var i = 0; i < 8; i++) {"
16335                       "  tmp_array[i] = i;"
16336                       "  sum += tmp_array[i];"
16337                       "  if (i == 4) {"
16338                       "    tmp_array = {};"
16339                       "  }"
16340                       "}"
16341                       "sum;");
16342   // Force GC to trigger verification.
16343   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16344   CHECK_EQ(28, result->Int32Value());
16345
16346   // Make sure out-of-range loads do not throw.
16347   i::SNPrintF(test_buf,
16348               "var caught_exception = false;"
16349               "try {"
16350               "  ext_array[%d];"
16351               "} catch (e) {"
16352               "  caught_exception = true;"
16353               "}"
16354               "caught_exception;",
16355               element_count);
16356   result = CompileRun(test_buf.start());
16357   CHECK_EQ(false, result->BooleanValue());
16358
16359   // Make sure out-of-range stores do not throw.
16360   i::SNPrintF(test_buf,
16361               "var caught_exception = false;"
16362               "try {"
16363               "  ext_array[%d] = 1;"
16364               "} catch (e) {"
16365               "  caught_exception = true;"
16366               "}"
16367               "caught_exception;",
16368               element_count);
16369   result = CompileRun(test_buf.start());
16370   CHECK_EQ(false, result->BooleanValue());
16371
16372   // Check other boundary conditions, values and operations.
16373   result = CompileRun("for (var i = 0; i < 8; i++) {"
16374                       "  ext_array[7] = undefined;"
16375                       "}"
16376                       "ext_array[7];");
16377   CHECK_EQ(0, result->Int32Value());
16378   if (array_type == v8::kExternalFloat64Array ||
16379       array_type == v8::kExternalFloat32Array) {
16380     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16381              static_cast<int>(
16382                  i::Object::GetElement(
16383                      isolate, jsobj, 7).ToHandleChecked()->Number()));
16384   } else {
16385     CheckElementValue(isolate, 0, jsobj, 7);
16386   }
16387
16388   result = CompileRun("for (var i = 0; i < 8; i++) {"
16389                       "  ext_array[6] = '2.3';"
16390                       "}"
16391                       "ext_array[6];");
16392   CHECK_EQ(2, result->Int32Value());
16393   CHECK_EQ(2,
16394            static_cast<int>(
16395                i::Object::GetElement(
16396                    isolate, jsobj, 6).ToHandleChecked()->Number()));
16397
16398   if (array_type != v8::kExternalFloat32Array &&
16399       array_type != v8::kExternalFloat64Array) {
16400     // Though the specification doesn't state it, be explicit about
16401     // converting NaNs and +/-Infinity to zero.
16402     result = CompileRun("for (var i = 0; i < 8; i++) {"
16403                         "  ext_array[i] = 5;"
16404                         "}"
16405                         "for (var i = 0; i < 8; i++) {"
16406                         "  ext_array[i] = NaN;"
16407                         "}"
16408                         "ext_array[5];");
16409     CHECK_EQ(0, result->Int32Value());
16410     CheckElementValue(isolate, 0, jsobj, 5);
16411
16412     result = CompileRun("for (var i = 0; i < 8; i++) {"
16413                         "  ext_array[i] = 5;"
16414                         "}"
16415                         "for (var i = 0; i < 8; i++) {"
16416                         "  ext_array[i] = Infinity;"
16417                         "}"
16418                         "ext_array[5];");
16419     int expected_value =
16420         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16421     CHECK_EQ(expected_value, result->Int32Value());
16422     CheckElementValue(isolate, expected_value, jsobj, 5);
16423
16424     result = CompileRun("for (var i = 0; i < 8; i++) {"
16425                         "  ext_array[i] = 5;"
16426                         "}"
16427                         "for (var i = 0; i < 8; i++) {"
16428                         "  ext_array[i] = -Infinity;"
16429                         "}"
16430                         "ext_array[5];");
16431     CHECK_EQ(0, result->Int32Value());
16432     CheckElementValue(isolate, 0, jsobj, 5);
16433
16434     // Check truncation behavior of integral arrays.
16435     const char* unsigned_data =
16436         "var source_data = [0.6, 10.6];"
16437         "var expected_results = [0, 10];";
16438     const char* signed_data =
16439         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16440         "var expected_results = [0, 10, 0, -10];";
16441     const char* pixel_data =
16442         "var source_data = [0.6, 10.6];"
16443         "var expected_results = [1, 11];";
16444     bool is_unsigned =
16445         (array_type == v8::kExternalUint8Array ||
16446          array_type == v8::kExternalUint16Array ||
16447          array_type == v8::kExternalUint32Array);
16448     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16449
16450     i::SNPrintF(test_buf,
16451                 "%s"
16452                 "var all_passed = true;"
16453                 "for (var i = 0; i < source_data.length; i++) {"
16454                 "  for (var j = 0; j < 8; j++) {"
16455                 "    ext_array[j] = source_data[i];"
16456                 "  }"
16457                 "  all_passed = all_passed &&"
16458                 "               (ext_array[5] == expected_results[i]);"
16459                 "}"
16460                 "all_passed;",
16461                 (is_unsigned ?
16462                      unsigned_data :
16463                      (is_pixel_data ? pixel_data : signed_data)));
16464     result = CompileRun(test_buf.start());
16465     CHECK_EQ(true, result->BooleanValue());
16466   }
16467
16468   i::Handle<ExternalArrayClass> array(
16469       ExternalArrayClass::cast(jsobj->elements()));
16470   for (int i = 0; i < element_count; i++) {
16471     array->set(i, static_cast<ElementType>(i));
16472   }
16473
16474   // Test complex assignments
16475   result = CompileRun("function ee_op_test_complex_func(sum) {"
16476                       " for (var i = 0; i < 40; ++i) {"
16477                       "   sum += (ext_array[i] += 1);"
16478                       "   sum += (ext_array[i] -= 1);"
16479                       " } "
16480                       " return sum;"
16481                       "}"
16482                       "sum=0;"
16483                       "for (var i=0;i<10000;++i) {"
16484                       "  sum=ee_op_test_complex_func(sum);"
16485                       "}"
16486                       "sum;");
16487   CHECK_EQ(16000000, result->Int32Value());
16488
16489   // Test count operations
16490   result = CompileRun("function ee_op_test_count_func(sum) {"
16491                       " for (var i = 0; i < 40; ++i) {"
16492                       "   sum += (++ext_array[i]);"
16493                       "   sum += (--ext_array[i]);"
16494                       " } "
16495                       " return sum;"
16496                       "}"
16497                       "sum=0;"
16498                       "for (var i=0;i<10000;++i) {"
16499                       "  sum=ee_op_test_count_func(sum);"
16500                       "}"
16501                       "sum;");
16502   CHECK_EQ(16000000, result->Int32Value());
16503
16504   result = CompileRun("ext_array[3] = 33;"
16505                       "delete ext_array[3];"
16506                       "ext_array[3];");
16507   CHECK_EQ(33, result->Int32Value());
16508
16509   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16510                       "ext_array[2] = 12; ext_array[3] = 13;"
16511                       "ext_array.__defineGetter__('2',"
16512                       "function() { return 120; });"
16513                       "ext_array[2];");
16514   CHECK_EQ(12, result->Int32Value());
16515
16516   result = CompileRun("var js_array = new Array(40);"
16517                       "js_array[0] = 77;"
16518                       "js_array;");
16519   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16520
16521   result = CompileRun("ext_array[1] = 23;"
16522                       "ext_array.__proto__ = [];"
16523                       "js_array.__proto__ = ext_array;"
16524                       "js_array.concat(ext_array);");
16525   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16526   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16527
16528   result = CompileRun("ext_array[1] = 23;");
16529   CHECK_EQ(23, result->Int32Value());
16530 }
16531
16532
16533 template <class FixedTypedArrayClass,
16534           i::ElementsKind elements_kind,
16535           class ElementType>
16536 static void FixedTypedArrayTestHelper(
16537     v8::ExternalArrayType array_type,
16538     ElementType low,
16539     ElementType high) {
16540   i::FLAG_allow_natives_syntax = true;
16541   LocalContext context;
16542   i::Isolate* isolate = CcTest::i_isolate();
16543   i::Factory* factory = isolate->factory();
16544   v8::HandleScope scope(context->GetIsolate());
16545   const int kElementCount = 260;
16546   i::Handle<FixedTypedArrayClass> fixed_array =
16547     i::Handle<FixedTypedArrayClass>::cast(
16548         factory->NewFixedTypedArray(kElementCount, array_type));
16549   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16550            fixed_array->map()->instance_type());
16551   CHECK_EQ(kElementCount, fixed_array->length());
16552   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16553   for (int i = 0; i < kElementCount; i++) {
16554     fixed_array->set(i, static_cast<ElementType>(i));
16555   }
16556   // Force GC to trigger verification.
16557   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16558   for (int i = 0; i < kElementCount; i++) {
16559     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16560              static_cast<int64_t>(fixed_array->get_scalar(i)));
16561   }
16562   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16563   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16564   i::Handle<i::Map> fixed_array_map =
16565       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16566   jsobj->set_map(*fixed_array_map);
16567   jsobj->set_elements(*fixed_array);
16568
16569   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16570       context.local(), obj, kElementCount, array_type,
16571       static_cast<int64_t>(low),
16572       static_cast<int64_t>(high));
16573 }
16574
16575
16576 THREADED_TEST(FixedUint8Array) {
16577   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16578     v8::kExternalUint8Array,
16579     0x0, 0xFF);
16580 }
16581
16582
16583 THREADED_TEST(FixedUint8ClampedArray) {
16584   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16585                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16586     v8::kExternalUint8ClampedArray,
16587     0x0, 0xFF);
16588 }
16589
16590
16591 THREADED_TEST(FixedInt8Array) {
16592   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16593     v8::kExternalInt8Array,
16594     -0x80, 0x7F);
16595 }
16596
16597
16598 THREADED_TEST(FixedUint16Array) {
16599   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16600     v8::kExternalUint16Array,
16601     0x0, 0xFFFF);
16602 }
16603
16604
16605 THREADED_TEST(FixedInt16Array) {
16606   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16607     v8::kExternalInt16Array,
16608     -0x8000, 0x7FFF);
16609 }
16610
16611
16612 THREADED_TEST(FixedUint32Array) {
16613   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16614     v8::kExternalUint32Array,
16615     0x0, UINT_MAX);
16616 }
16617
16618
16619 THREADED_TEST(FixedInt32Array) {
16620   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16621     v8::kExternalInt32Array,
16622     INT_MIN, INT_MAX);
16623 }
16624
16625
16626 THREADED_TEST(FixedFloat32Array) {
16627   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16628     v8::kExternalFloat32Array,
16629     -500, 500);
16630 }
16631
16632
16633 THREADED_TEST(FixedFloat64Array) {
16634   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16635     v8::kExternalFloat64Array,
16636     -500, 500);
16637 }
16638
16639
16640 template <class ExternalArrayClass, class ElementType>
16641 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16642                                     int64_t low,
16643                                     int64_t high) {
16644   LocalContext context;
16645   i::Isolate* isolate = CcTest::i_isolate();
16646   i::Factory* factory = isolate->factory();
16647   v8::HandleScope scope(context->GetIsolate());
16648   const int kElementCount = 40;
16649   int element_size = ExternalArrayElementSize(array_type);
16650   ElementType* array_data =
16651       static_cast<ElementType*>(malloc(kElementCount * element_size));
16652   i::Handle<ExternalArrayClass> array =
16653       i::Handle<ExternalArrayClass>::cast(
16654           factory->NewExternalArray(kElementCount, array_type, array_data));
16655   // Force GC to trigger verification.
16656   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16657   for (int i = 0; i < kElementCount; i++) {
16658     array->set(i, static_cast<ElementType>(i));
16659   }
16660   // Force GC to trigger verification.
16661   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16662   for (int i = 0; i < kElementCount; i++) {
16663     CHECK_EQ(static_cast<int64_t>(i),
16664              static_cast<int64_t>(array->get_scalar(i)));
16665     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16666   }
16667
16668   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16669   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16670   // Set the elements to be the external array.
16671   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16672                                                array_type,
16673                                                kElementCount);
16674   CHECK_EQ(1,
16675            static_cast<int>(
16676                i::Object::GetElement(
16677                    isolate, jsobj, 1).ToHandleChecked()->Number()));
16678
16679   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16680       context.local(), obj, kElementCount, array_type, low, high);
16681
16682   v8::Handle<v8::Value> result;
16683
16684   // Test more complex manipulations which cause eax to contain values
16685   // that won't be completely overwritten by loads from the arrays.
16686   // This catches bugs in the instructions used for the KeyedLoadIC
16687   // for byte and word types.
16688   {
16689     const int kXSize = 300;
16690     const int kYSize = 300;
16691     const int kLargeElementCount = kXSize * kYSize * 4;
16692     ElementType* large_array_data =
16693         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16694     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16695     // Set the elements to be the external array.
16696     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16697                                                        array_type,
16698                                                        kLargeElementCount);
16699     context->Global()->Set(v8_str("large_array"), large_obj);
16700     // Initialize contents of a few rows.
16701     for (int x = 0; x < 300; x++) {
16702       int row = 0;
16703       int offset = row * 300 * 4;
16704       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16705       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16706       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16707       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16708       row = 150;
16709       offset = row * 300 * 4;
16710       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16711       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16712       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16713       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16714       row = 298;
16715       offset = row * 300 * 4;
16716       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16717       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16718       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16719       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16720     }
16721     // The goal of the code below is to make "offset" large enough
16722     // that the computation of the index (which goes into eax) has
16723     // high bits set which will not be overwritten by a byte or short
16724     // load.
16725     result = CompileRun("var failed = false;"
16726                         "var offset = 0;"
16727                         "for (var i = 0; i < 300; i++) {"
16728                         "  if (large_array[4 * i] != 127 ||"
16729                         "      large_array[4 * i + 1] != 0 ||"
16730                         "      large_array[4 * i + 2] != 0 ||"
16731                         "      large_array[4 * i + 3] != 127) {"
16732                         "    failed = true;"
16733                         "  }"
16734                         "}"
16735                         "offset = 150 * 300 * 4;"
16736                         "for (var i = 0; i < 300; i++) {"
16737                         "  if (large_array[offset + 4 * i] != 127 ||"
16738                         "      large_array[offset + 4 * i + 1] != 0 ||"
16739                         "      large_array[offset + 4 * i + 2] != 0 ||"
16740                         "      large_array[offset + 4 * i + 3] != 127) {"
16741                         "    failed = true;"
16742                         "  }"
16743                         "}"
16744                         "offset = 298 * 300 * 4;"
16745                         "for (var i = 0; i < 300; i++) {"
16746                         "  if (large_array[offset + 4 * i] != 127 ||"
16747                         "      large_array[offset + 4 * i + 1] != 0 ||"
16748                         "      large_array[offset + 4 * i + 2] != 0 ||"
16749                         "      large_array[offset + 4 * i + 3] != 127) {"
16750                         "    failed = true;"
16751                         "  }"
16752                         "}"
16753                         "!failed;");
16754     CHECK_EQ(true, result->BooleanValue());
16755     free(large_array_data);
16756   }
16757
16758   // The "" property descriptor is overloaded to store information about
16759   // the external array. Ensure that setting and accessing the "" property
16760   // works (it should overwrite the information cached about the external
16761   // array in the DescriptorArray) in various situations.
16762   result = CompileRun("ext_array[''] = 23; ext_array['']");
16763   CHECK_EQ(23, result->Int32Value());
16764
16765   // Property "" set after the external array is associated with the object.
16766   {
16767     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16768     obj2->Set(v8_str("ee_test_field"),
16769               v8::Int32::New(context->GetIsolate(), 256));
16770     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16771     // Set the elements to be the external array.
16772     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16773                                                   array_type,
16774                                                   kElementCount);
16775     context->Global()->Set(v8_str("ext_array"), obj2);
16776     result = CompileRun("ext_array['']");
16777     CHECK_EQ(1503, result->Int32Value());
16778   }
16779
16780   // Property "" set after the external array is associated with the object.
16781   {
16782     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16783     obj2->Set(v8_str("ee_test_field_2"),
16784               v8::Int32::New(context->GetIsolate(), 256));
16785     // Set the elements to be the external array.
16786     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16787                                                   array_type,
16788                                                   kElementCount);
16789     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16790     context->Global()->Set(v8_str("ext_array"), obj2);
16791     result = CompileRun("ext_array['']");
16792     CHECK_EQ(1503, result->Int32Value());
16793   }
16794
16795   // Should reuse the map from previous test.
16796   {
16797     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16798     obj2->Set(v8_str("ee_test_field_2"),
16799               v8::Int32::New(context->GetIsolate(), 256));
16800     // Set the elements to be the external array. Should re-use the map
16801     // from previous test.
16802     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16803                                                   array_type,
16804                                                   kElementCount);
16805     context->Global()->Set(v8_str("ext_array"), obj2);
16806     result = CompileRun("ext_array['']");
16807   }
16808
16809   // Property "" is a constant function that shouldn't not be interfered with
16810   // when an external array is set.
16811   {
16812     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16813     // Start
16814     obj2->Set(v8_str("ee_test_field3"),
16815               v8::Int32::New(context->GetIsolate(), 256));
16816
16817     // Add a constant function to an object.
16818     context->Global()->Set(v8_str("ext_array"), obj2);
16819     result = CompileRun("ext_array[''] = function() {return 1503;};"
16820                         "ext_array['']();");
16821
16822     // Add an external array transition to the same map that
16823     // has the constant transition.
16824     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16825     obj3->Set(v8_str("ee_test_field3"),
16826               v8::Int32::New(context->GetIsolate(), 256));
16827     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16828                                                   array_type,
16829                                                   kElementCount);
16830     context->Global()->Set(v8_str("ext_array"), obj3);
16831   }
16832
16833   // If a external array transition is in the map, it should get clobbered
16834   // by a constant function.
16835   {
16836     // Add an external array transition.
16837     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16838     obj3->Set(v8_str("ee_test_field4"),
16839               v8::Int32::New(context->GetIsolate(), 256));
16840     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16841                                                   array_type,
16842                                                   kElementCount);
16843
16844     // Add a constant function to the same map that just got an external array
16845     // transition.
16846     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16847     obj2->Set(v8_str("ee_test_field4"),
16848               v8::Int32::New(context->GetIsolate(), 256));
16849     context->Global()->Set(v8_str("ext_array"), obj2);
16850     result = CompileRun("ext_array[''] = function() {return 1503;};"
16851                         "ext_array['']();");
16852   }
16853
16854   free(array_data);
16855 }
16856
16857
16858 THREADED_TEST(ExternalInt8Array) {
16859   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16860       v8::kExternalInt8Array,
16861       -128,
16862       127);
16863 }
16864
16865
16866 THREADED_TEST(ExternalUint8Array) {
16867   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16868       v8::kExternalUint8Array,
16869       0,
16870       255);
16871 }
16872
16873
16874 THREADED_TEST(ExternalUint8ClampedArray) {
16875   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16876       v8::kExternalUint8ClampedArray,
16877       0,
16878       255);
16879 }
16880
16881
16882 THREADED_TEST(ExternalInt16Array) {
16883   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16884       v8::kExternalInt16Array,
16885       -32768,
16886       32767);
16887 }
16888
16889
16890 THREADED_TEST(ExternalUint16Array) {
16891   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16892       v8::kExternalUint16Array,
16893       0,
16894       65535);
16895 }
16896
16897
16898 THREADED_TEST(ExternalInt32Array) {
16899   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16900       v8::kExternalInt32Array,
16901       INT_MIN,   // -2147483648
16902       INT_MAX);  //  2147483647
16903 }
16904
16905
16906 THREADED_TEST(ExternalUint32Array) {
16907   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16908       v8::kExternalUint32Array,
16909       0,
16910       UINT_MAX);  // 4294967295
16911 }
16912
16913
16914 THREADED_TEST(ExternalFloat32Array) {
16915   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16916       v8::kExternalFloat32Array,
16917       -500,
16918       500);
16919 }
16920
16921
16922 THREADED_TEST(ExternalFloat64Array) {
16923   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16924       v8::kExternalFloat64Array,
16925       -500,
16926       500);
16927 }
16928
16929
16930 THREADED_TEST(ExternalArrays) {
16931   TestExternalInt8Array();
16932   TestExternalUint8Array();
16933   TestExternalInt16Array();
16934   TestExternalUint16Array();
16935   TestExternalInt32Array();
16936   TestExternalUint32Array();
16937   TestExternalFloat32Array();
16938 }
16939
16940
16941 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16942   LocalContext context;
16943   v8::HandleScope scope(context->GetIsolate());
16944   for (int size = 0; size < 100; size += 10) {
16945     int element_size = ExternalArrayElementSize(array_type);
16946     void* external_data = malloc(size * element_size);
16947     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16948     obj->SetIndexedPropertiesToExternalArrayData(
16949         external_data, array_type, size);
16950     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16951     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16952     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16953     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16954     free(external_data);
16955   }
16956 }
16957
16958
16959 THREADED_TEST(ExternalArrayInfo) {
16960   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16961   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16962   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16963   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16964   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16965   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16966   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16967   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16968   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16969 }
16970
16971
16972 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16973                           v8::ExternalArrayType array_type,
16974                           int size) {
16975   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16976   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16977   last_location = last_message = NULL;
16978   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16979   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16980   CHECK_NE(NULL, last_location);
16981   CHECK_NE(NULL, last_message);
16982 }
16983
16984
16985 TEST(ExternalArrayLimits) {
16986   LocalContext context;
16987   v8::Isolate* isolate = context->GetIsolate();
16988   v8::HandleScope scope(isolate);
16989   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16990   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16991   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16992   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16993   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16994   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16995   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16996   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16997   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16998   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16999   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17000   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17001   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17002   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17003   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17004   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17005   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17006   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17007 }
17008
17009
17010 template <typename ElementType, typename TypedArray,
17011           class ExternalArrayClass>
17012 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17013                           int64_t low, int64_t high) {
17014   const int kElementCount = 50;
17015
17016   i::ScopedVector<ElementType> backing_store(kElementCount+2);
17017
17018   LocalContext env;
17019   v8::Isolate* isolate = env->GetIsolate();
17020   v8::HandleScope handle_scope(isolate);
17021
17022   Local<v8::ArrayBuffer> ab =
17023       v8::ArrayBuffer::New(isolate, backing_store.start(),
17024                            (kElementCount + 2) * sizeof(ElementType));
17025   Local<TypedArray> ta =
17026       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17027   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17028   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17029   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17030   CHECK_EQ(kElementCount*sizeof(ElementType),
17031            static_cast<int>(ta->ByteLength()));
17032   CHECK_EQ(ab, ta->Buffer());
17033
17034   ElementType* data = backing_store.start() + 2;
17035   for (int i = 0; i < kElementCount; i++) {
17036     data[i] = static_cast<ElementType>(i);
17037   }
17038
17039   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17040       env.local(), ta, kElementCount, array_type, low, high);
17041 }
17042
17043
17044 THREADED_TEST(Uint8Array) {
17045   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17046       v8::kExternalUint8Array, 0, 0xFF);
17047 }
17048
17049
17050 THREADED_TEST(Int8Array) {
17051   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17052       v8::kExternalInt8Array, -0x80, 0x7F);
17053 }
17054
17055
17056 THREADED_TEST(Uint16Array) {
17057   TypedArrayTestHelper<uint16_t,
17058                        v8::Uint16Array,
17059                        i::ExternalUint16Array>(
17060       v8::kExternalUint16Array, 0, 0xFFFF);
17061 }
17062
17063
17064 THREADED_TEST(Int16Array) {
17065   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17066       v8::kExternalInt16Array, -0x8000, 0x7FFF);
17067 }
17068
17069
17070 THREADED_TEST(Uint32Array) {
17071   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17072       v8::kExternalUint32Array, 0, UINT_MAX);
17073 }
17074
17075
17076 THREADED_TEST(Int32Array) {
17077   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17078       v8::kExternalInt32Array, INT_MIN, INT_MAX);
17079 }
17080
17081
17082 THREADED_TEST(Float32Array) {
17083   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17084       v8::kExternalFloat32Array, -500, 500);
17085 }
17086
17087
17088 THREADED_TEST(Float64Array) {
17089   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17090       v8::kExternalFloat64Array, -500, 500);
17091 }
17092
17093
17094 THREADED_TEST(Uint8ClampedArray) {
17095   TypedArrayTestHelper<uint8_t,
17096                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17097       v8::kExternalUint8ClampedArray, 0, 0xFF);
17098 }
17099
17100
17101 THREADED_TEST(DataView) {
17102   const int kSize = 50;
17103
17104   i::ScopedVector<uint8_t> backing_store(kSize+2);
17105
17106   LocalContext env;
17107   v8::Isolate* isolate = env->GetIsolate();
17108   v8::HandleScope handle_scope(isolate);
17109
17110   Local<v8::ArrayBuffer> ab =
17111       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17112   Local<v8::DataView> dv =
17113       v8::DataView::New(ab, 2, kSize);
17114   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17115   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17116   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17117   CHECK_EQ(ab, dv->Buffer());
17118 }
17119
17120
17121 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17122   THREADED_TEST(Is##View) {                                                   \
17123     LocalContext env;                                                         \
17124     v8::Isolate* isolate = env->GetIsolate();                                 \
17125     v8::HandleScope handle_scope(isolate);                                    \
17126                                                                               \
17127     Handle<Value> result = CompileRun(                                        \
17128         "var ab = new ArrayBuffer(128);"                                      \
17129         "new " #View "(ab)");                                                 \
17130     CHECK(result->IsArrayBufferView());                                       \
17131     CHECK(result->Is##View());                                                \
17132     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17133   }
17134
17135 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17136 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17137 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17138 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17139 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17140 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17141 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17142 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17143 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17144 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17145
17146 #undef IS_ARRAY_BUFFER_VIEW_TEST
17147
17148
17149
17150 THREADED_TEST(ScriptContextDependence) {
17151   LocalContext c1;
17152   v8::HandleScope scope(c1->GetIsolate());
17153   const char *source = "foo";
17154   v8::Handle<v8::Script> dep = v8_compile(source);
17155   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17156       c1->GetIsolate(), source));
17157   v8::Handle<v8::UnboundScript> indep =
17158       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17159   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17160                     v8::Integer::New(c1->GetIsolate(), 100));
17161   CHECK_EQ(dep->Run()->Int32Value(), 100);
17162   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17163   LocalContext c2;
17164   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17165                     v8::Integer::New(c2->GetIsolate(), 101));
17166   CHECK_EQ(dep->Run()->Int32Value(), 100);
17167   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17168 }
17169
17170
17171 THREADED_TEST(StackTrace) {
17172   LocalContext context;
17173   v8::HandleScope scope(context->GetIsolate());
17174   v8::TryCatch try_catch;
17175   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17176   v8::Handle<v8::String> src =
17177       v8::String::NewFromUtf8(context->GetIsolate(), source);
17178   v8::Handle<v8::String> origin =
17179       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17180   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17181   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17182       ->BindToCurrentContext()
17183       ->Run();
17184   CHECK(try_catch.HasCaught());
17185   v8::String::Utf8Value stack(try_catch.StackTrace());
17186   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17187 }
17188
17189
17190 // Checks that a StackFrame has certain expected values.
17191 void checkStackFrame(const char* expected_script_name,
17192     const char* expected_func_name, int expected_line_number,
17193     int expected_column, bool is_eval, bool is_constructor,
17194     v8::Handle<v8::StackFrame> frame) {
17195   v8::HandleScope scope(CcTest::isolate());
17196   v8::String::Utf8Value func_name(frame->GetFunctionName());
17197   v8::String::Utf8Value script_name(frame->GetScriptName());
17198   if (*script_name == NULL) {
17199     // The situation where there is no associated script, like for evals.
17200     CHECK(expected_script_name == NULL);
17201   } else {
17202     CHECK(strstr(*script_name, expected_script_name) != NULL);
17203   }
17204   CHECK(strstr(*func_name, expected_func_name) != NULL);
17205   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17206   CHECK_EQ(expected_column, frame->GetColumn());
17207   CHECK_EQ(is_eval, frame->IsEval());
17208   CHECK_EQ(is_constructor, frame->IsConstructor());
17209 }
17210
17211
17212 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17213   v8::HandleScope scope(args.GetIsolate());
17214   const char* origin = "capture-stack-trace-test";
17215   const int kOverviewTest = 1;
17216   const int kDetailedTest = 2;
17217
17218   ASSERT(args.Length() == 1);
17219
17220   int testGroup = args[0]->Int32Value();
17221   if (testGroup == kOverviewTest) {
17222     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17223         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17224     CHECK_EQ(4, stackTrace->GetFrameCount());
17225     checkStackFrame(origin, "bar", 2, 10, false, false,
17226                     stackTrace->GetFrame(0));
17227     checkStackFrame(origin, "foo", 6, 3, false, false,
17228                     stackTrace->GetFrame(1));
17229     // This is the source string inside the eval which has the call to foo.
17230     checkStackFrame(NULL, "", 1, 5, false, false,
17231                     stackTrace->GetFrame(2));
17232     // The last frame is an anonymous function which has the initial eval call.
17233     checkStackFrame(origin, "", 8, 7, false, false,
17234                     stackTrace->GetFrame(3));
17235
17236     CHECK(stackTrace->AsArray()->IsArray());
17237   } else if (testGroup == kDetailedTest) {
17238     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17239         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17240     CHECK_EQ(4, stackTrace->GetFrameCount());
17241     checkStackFrame(origin, "bat", 4, 22, false, false,
17242                     stackTrace->GetFrame(0));
17243     checkStackFrame(origin, "baz", 8, 3, false, true,
17244                     stackTrace->GetFrame(1));
17245     bool is_eval = true;
17246     // This is the source string inside the eval which has the call to baz.
17247     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17248                     stackTrace->GetFrame(2));
17249     // The last frame is an anonymous function which has the initial eval call.
17250     checkStackFrame(origin, "", 10, 1, false, false,
17251                     stackTrace->GetFrame(3));
17252
17253     CHECK(stackTrace->AsArray()->IsArray());
17254   }
17255 }
17256
17257
17258 // Tests the C++ StackTrace API.
17259 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17260 // THREADED_TEST(CaptureStackTrace) {
17261 TEST(CaptureStackTrace) {
17262   v8::Isolate* isolate = CcTest::isolate();
17263   v8::HandleScope scope(isolate);
17264   v8::Handle<v8::String> origin =
17265       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17266   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17267   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17268              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17269   LocalContext context(0, templ);
17270
17271   // Test getting OVERVIEW information. Should ignore information that is not
17272   // script name, function name, line number, and column offset.
17273   const char *overview_source =
17274     "function bar() {\n"
17275     "  var y; AnalyzeStackInNativeCode(1);\n"
17276     "}\n"
17277     "function foo() {\n"
17278     "\n"
17279     "  bar();\n"
17280     "}\n"
17281     "var x;eval('new foo();');";
17282   v8::Handle<v8::String> overview_src =
17283       v8::String::NewFromUtf8(isolate, overview_source);
17284   v8::ScriptCompiler::Source script_source(overview_src,
17285                                            v8::ScriptOrigin(origin));
17286   v8::Handle<Value> overview_result(
17287       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17288           ->BindToCurrentContext()
17289           ->Run());
17290   CHECK(!overview_result.IsEmpty());
17291   CHECK(overview_result->IsObject());
17292
17293   // Test getting DETAILED information.
17294   const char *detailed_source =
17295     "function bat() {AnalyzeStackInNativeCode(2);\n"
17296     "}\n"
17297     "\n"
17298     "function baz() {\n"
17299     "  bat();\n"
17300     "}\n"
17301     "eval('new baz();');";
17302   v8::Handle<v8::String> detailed_src =
17303       v8::String::NewFromUtf8(isolate, detailed_source);
17304   // Make the script using a non-zero line and column offset.
17305   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17306   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17307   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17308   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17309   v8::Handle<v8::UnboundScript> detailed_script(
17310       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17311   v8::Handle<Value> detailed_result(
17312       detailed_script->BindToCurrentContext()->Run());
17313   CHECK(!detailed_result.IsEmpty());
17314   CHECK(detailed_result->IsObject());
17315 }
17316
17317
17318 static void StackTraceForUncaughtExceptionListener(
17319     v8::Handle<v8::Message> message,
17320     v8::Handle<Value>) {
17321   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17322   CHECK_EQ(2, stack_trace->GetFrameCount());
17323   checkStackFrame("origin", "foo", 2, 3, false, false,
17324                   stack_trace->GetFrame(0));
17325   checkStackFrame("origin", "bar", 5, 3, false, false,
17326                   stack_trace->GetFrame(1));
17327 }
17328
17329
17330 TEST(CaptureStackTraceForUncaughtException) {
17331   report_count = 0;
17332   LocalContext env;
17333   v8::HandleScope scope(env->GetIsolate());
17334   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17335   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17336
17337   CompileRunWithOrigin(
17338       "function foo() {\n"
17339       "  throw 1;\n"
17340       "};\n"
17341       "function bar() {\n"
17342       "  foo();\n"
17343       "};",
17344       "origin");
17345   v8::Local<v8::Object> global = env->Global();
17346   Local<Value> trouble = global->Get(v8_str("bar"));
17347   CHECK(trouble->IsFunction());
17348   Function::Cast(*trouble)->Call(global, 0, NULL);
17349   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17350   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17351 }
17352
17353
17354 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17355   LocalContext env;
17356   v8::HandleScope scope(env->GetIsolate());
17357   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17358                                                     1024,
17359                                                     v8::StackTrace::kDetailed);
17360
17361   CompileRun(
17362       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17363       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17364       "    'isConstructor'];\n"
17365       "for (var i = 0; i < setters.length; i++) {\n"
17366       "  var prop = setters[i];\n"
17367       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17368       "}\n");
17369   CompileRun("throw 'exception';");
17370   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17371 }
17372
17373
17374 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17375                                      v8::Handle<v8::Value> data) {
17376   // Use the frame where JavaScript is called from.
17377   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17378   CHECK(!stack_trace.IsEmpty());
17379   int frame_count = stack_trace->GetFrameCount();
17380   CHECK_EQ(3, frame_count);
17381   int line_number[] = {1, 2, 5};
17382   for (int i = 0; i < frame_count; i++) {
17383     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17384   }
17385 }
17386
17387
17388 // Test that we only return the stack trace at the site where the exception
17389 // is first thrown (not where it is rethrown).
17390 TEST(RethrowStackTrace) {
17391   LocalContext env;
17392   v8::HandleScope scope(env->GetIsolate());
17393   // We make sure that
17394   // - the stack trace of the ReferenceError in g() is reported.
17395   // - the stack trace is not overwritten when e1 is rethrown by t().
17396   // - the stack trace of e2 does not overwrite that of e1.
17397   const char* source =
17398       "function g() { error; }          \n"
17399       "function f() { g(); }            \n"
17400       "function t(e) { throw e; }       \n"
17401       "try {                            \n"
17402       "  f();                           \n"
17403       "} catch (e1) {                   \n"
17404       "  try {                          \n"
17405       "    error;                       \n"
17406       "  } catch (e2) {                 \n"
17407       "    t(e1);                       \n"
17408       "  }                              \n"
17409       "}                                \n";
17410   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17411   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17412   CompileRun(source);
17413   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17414   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17415 }
17416
17417
17418 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17419                                               v8::Handle<v8::Value> data) {
17420   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17421   CHECK(!stack_trace.IsEmpty());
17422   int frame_count = stack_trace->GetFrameCount();
17423   CHECK_EQ(2, frame_count);
17424   int line_number[] = {3, 7};
17425   for (int i = 0; i < frame_count; i++) {
17426     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17427   }
17428 }
17429
17430
17431 // Test that we do not recognize identity for primitive exceptions.
17432 TEST(RethrowPrimitiveStackTrace) {
17433   LocalContext env;
17434   v8::HandleScope scope(env->GetIsolate());
17435   // We do not capture stack trace for non Error objects on creation time.
17436   // Instead, we capture the stack trace on last throw.
17437   const char* source =
17438       "function g() { throw 404; }      \n"
17439       "function f() { g(); }            \n"
17440       "function t(e) { throw e; }       \n"
17441       "try {                            \n"
17442       "  f();                           \n"
17443       "} catch (e1) {                   \n"
17444       "  t(e1)                          \n"
17445       "}                                \n";
17446   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17447   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17448   CompileRun(source);
17449   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17450   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17451 }
17452
17453
17454 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17455                                               v8::Handle<v8::Value> data) {
17456   // Use the frame where JavaScript is called from.
17457   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17458   CHECK(!stack_trace.IsEmpty());
17459   CHECK_EQ(1, stack_trace->GetFrameCount());
17460   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17461 }
17462
17463
17464 // Test that the stack trace is captured when the error object is created and
17465 // not where it is thrown.
17466 TEST(RethrowExistingStackTrace) {
17467   LocalContext env;
17468   v8::HandleScope scope(env->GetIsolate());
17469   const char* source =
17470       "var e = new Error();           \n"
17471       "throw e;                       \n";
17472   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17473   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17474   CompileRun(source);
17475   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17476   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17477 }
17478
17479
17480 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17481                                                v8::Handle<v8::Value> data) {
17482   // Use the frame where JavaScript is called from.
17483   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17484   CHECK(!stack_trace.IsEmpty());
17485   CHECK_EQ(1, stack_trace->GetFrameCount());
17486   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17487 }
17488
17489
17490 // Test that the stack trace is captured where the bogus Error object is thrown.
17491 TEST(RethrowBogusErrorStackTrace) {
17492   LocalContext env;
17493   v8::HandleScope scope(env->GetIsolate());
17494   const char* source =
17495       "var e = {__proto__: new Error()} \n"
17496       "throw e;                         \n";
17497   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17498   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17499   CompileRun(source);
17500   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17501   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17502 }
17503
17504
17505 void AnalyzeStackOfEvalWithSourceURL(
17506     const v8::FunctionCallbackInfo<v8::Value>& args) {
17507   v8::HandleScope scope(args.GetIsolate());
17508   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17509       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17510   CHECK_EQ(5, stackTrace->GetFrameCount());
17511   v8::Handle<v8::String> url = v8_str("eval_url");
17512   for (int i = 0; i < 3; i++) {
17513     v8::Handle<v8::String> name =
17514         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17515     CHECK(!name.IsEmpty());
17516     CHECK_EQ(url, name);
17517   }
17518 }
17519
17520
17521 TEST(SourceURLInStackTrace) {
17522   v8::Isolate* isolate = CcTest::isolate();
17523   v8::HandleScope scope(isolate);
17524   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17525   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17526              v8::FunctionTemplate::New(isolate,
17527                                        AnalyzeStackOfEvalWithSourceURL));
17528   LocalContext context(0, templ);
17529
17530   const char *source =
17531     "function outer() {\n"
17532     "function bar() {\n"
17533     "  AnalyzeStackOfEvalWithSourceURL();\n"
17534     "}\n"
17535     "function foo() {\n"
17536     "\n"
17537     "  bar();\n"
17538     "}\n"
17539     "foo();\n"
17540     "}\n"
17541     "eval('(' + outer +')()%s');";
17542
17543   i::ScopedVector<char> code(1024);
17544   i::SNPrintF(code, source, "//# sourceURL=eval_url");
17545   CHECK(CompileRun(code.start())->IsUndefined());
17546   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17547   CHECK(CompileRun(code.start())->IsUndefined());
17548 }
17549
17550
17551 static int scriptIdInStack[2];
17552
17553 void AnalyzeScriptIdInStack(
17554     const v8::FunctionCallbackInfo<v8::Value>& args) {
17555   v8::HandleScope scope(args.GetIsolate());
17556   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17557       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17558   CHECK_EQ(2, stackTrace->GetFrameCount());
17559   for (int i = 0; i < 2; i++) {
17560     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17561   }
17562 }
17563
17564
17565 TEST(ScriptIdInStackTrace) {
17566   v8::Isolate* isolate = CcTest::isolate();
17567   v8::HandleScope scope(isolate);
17568   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17569   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17570              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17571   LocalContext context(0, templ);
17572
17573   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17574     isolate,
17575     "function foo() {\n"
17576     "  AnalyzeScriptIdInStack();"
17577     "}\n"
17578     "foo();\n");
17579   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17580   script->Run();
17581   for (int i = 0; i < 2; i++) {
17582     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17583     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17584   }
17585 }
17586
17587
17588 void AnalyzeStackOfInlineScriptWithSourceURL(
17589     const v8::FunctionCallbackInfo<v8::Value>& args) {
17590   v8::HandleScope scope(args.GetIsolate());
17591   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17592       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17593   CHECK_EQ(4, stackTrace->GetFrameCount());
17594   v8::Handle<v8::String> url = v8_str("url");
17595   for (int i = 0; i < 3; i++) {
17596     v8::Handle<v8::String> name =
17597         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17598     CHECK(!name.IsEmpty());
17599     CHECK_EQ(url, name);
17600   }
17601 }
17602
17603
17604 TEST(InlineScriptWithSourceURLInStackTrace) {
17605   v8::Isolate* isolate = CcTest::isolate();
17606   v8::HandleScope scope(isolate);
17607   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17608   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17609              v8::FunctionTemplate::New(
17610                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17611   LocalContext context(0, templ);
17612
17613   const char *source =
17614     "function outer() {\n"
17615     "function bar() {\n"
17616     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17617     "}\n"
17618     "function foo() {\n"
17619     "\n"
17620     "  bar();\n"
17621     "}\n"
17622     "foo();\n"
17623     "}\n"
17624     "outer()\n%s";
17625
17626   i::ScopedVector<char> code(1024);
17627   i::SNPrintF(code, source, "//# sourceURL=source_url");
17628   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17629   i::SNPrintF(code, source, "//@ sourceURL=source_url");
17630   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17631 }
17632
17633
17634 void AnalyzeStackOfDynamicScriptWithSourceURL(
17635     const v8::FunctionCallbackInfo<v8::Value>& args) {
17636   v8::HandleScope scope(args.GetIsolate());
17637   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17638       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17639   CHECK_EQ(4, stackTrace->GetFrameCount());
17640   v8::Handle<v8::String> url = v8_str("source_url");
17641   for (int i = 0; i < 3; i++) {
17642     v8::Handle<v8::String> name =
17643         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17644     CHECK(!name.IsEmpty());
17645     CHECK_EQ(url, name);
17646   }
17647 }
17648
17649
17650 TEST(DynamicWithSourceURLInStackTrace) {
17651   v8::Isolate* isolate = CcTest::isolate();
17652   v8::HandleScope scope(isolate);
17653   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17654   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17655              v8::FunctionTemplate::New(
17656                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17657   LocalContext context(0, templ);
17658
17659   const char *source =
17660     "function outer() {\n"
17661     "function bar() {\n"
17662     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17663     "}\n"
17664     "function foo() {\n"
17665     "\n"
17666     "  bar();\n"
17667     "}\n"
17668     "foo();\n"
17669     "}\n"
17670     "outer()\n%s";
17671
17672   i::ScopedVector<char> code(1024);
17673   i::SNPrintF(code, source, "//# sourceURL=source_url");
17674   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17675   i::SNPrintF(code, source, "//@ sourceURL=source_url");
17676   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17677 }
17678
17679
17680 TEST(DynamicWithSourceURLInStackTraceString) {
17681   LocalContext context;
17682   v8::HandleScope scope(context->GetIsolate());
17683
17684   const char *source =
17685     "function outer() {\n"
17686     "  function foo() {\n"
17687     "    FAIL.FAIL;\n"
17688     "  }\n"
17689     "  foo();\n"
17690     "}\n"
17691     "outer()\n%s";
17692
17693   i::ScopedVector<char> code(1024);
17694   i::SNPrintF(code, source, "//# sourceURL=source_url");
17695   v8::TryCatch try_catch;
17696   CompileRunWithOrigin(code.start(), "", 0, 0);
17697   CHECK(try_catch.HasCaught());
17698   v8::String::Utf8Value stack(try_catch.StackTrace());
17699   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17700 }
17701
17702
17703 static void CreateGarbageInOldSpace() {
17704   i::Factory* factory = CcTest::i_isolate()->factory();
17705   v8::HandleScope scope(CcTest::isolate());
17706   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17707   for (int i = 0; i < 1000; i++) {
17708     factory->NewFixedArray(1000, i::TENURED);
17709   }
17710 }
17711
17712
17713 // Test that idle notification can be handled and eventually returns true.
17714 TEST(IdleNotification) {
17715   const intptr_t MB = 1024 * 1024;
17716   LocalContext env;
17717   v8::HandleScope scope(env->GetIsolate());
17718   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17719   CreateGarbageInOldSpace();
17720   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17721   CHECK_GT(size_with_garbage, initial_size + MB);
17722   bool finished = false;
17723   for (int i = 0; i < 200 && !finished; i++) {
17724     finished = v8::V8::IdleNotification();
17725   }
17726   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17727   CHECK(finished);
17728   CHECK_LT(final_size, initial_size + 1);
17729 }
17730
17731
17732 // Test that idle notification can be handled and eventually collects garbage.
17733 TEST(IdleNotificationWithSmallHint) {
17734   const intptr_t MB = 1024 * 1024;
17735   const int IdlePauseInMs = 900;
17736   LocalContext env;
17737   v8::HandleScope scope(env->GetIsolate());
17738   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17739   CreateGarbageInOldSpace();
17740   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17741   CHECK_GT(size_with_garbage, initial_size + MB);
17742   bool finished = false;
17743   for (int i = 0; i < 200 && !finished; i++) {
17744     finished = v8::V8::IdleNotification(IdlePauseInMs);
17745   }
17746   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17747   CHECK(finished);
17748   CHECK_LT(final_size, initial_size + 1);
17749 }
17750
17751
17752 // Test that idle notification can be handled and eventually collects garbage.
17753 TEST(IdleNotificationWithLargeHint) {
17754   const intptr_t MB = 1024 * 1024;
17755   const int IdlePauseInMs = 900;
17756   LocalContext env;
17757   v8::HandleScope scope(env->GetIsolate());
17758   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17759   CreateGarbageInOldSpace();
17760   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17761   CHECK_GT(size_with_garbage, initial_size + MB);
17762   bool finished = false;
17763   for (int i = 0; i < 200 && !finished; i++) {
17764     finished = v8::V8::IdleNotification(IdlePauseInMs);
17765   }
17766   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17767   CHECK(finished);
17768   CHECK_LT(final_size, initial_size + 1);
17769 }
17770
17771
17772 TEST(Regress2107) {
17773   const intptr_t MB = 1024 * 1024;
17774   const int kShortIdlePauseInMs = 100;
17775   const int kLongIdlePauseInMs = 1000;
17776   LocalContext env;
17777   v8::Isolate* isolate = env->GetIsolate();
17778   v8::HandleScope scope(env->GetIsolate());
17779   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17780   // Send idle notification to start a round of incremental GCs.
17781   v8::V8::IdleNotification(kShortIdlePauseInMs);
17782   // Emulate 7 page reloads.
17783   for (int i = 0; i < 7; i++) {
17784     {
17785       v8::HandleScope inner_scope(env->GetIsolate());
17786       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17787       ctx->Enter();
17788       CreateGarbageInOldSpace();
17789       ctx->Exit();
17790     }
17791     v8::V8::ContextDisposedNotification();
17792     v8::V8::IdleNotification(kLongIdlePauseInMs);
17793   }
17794   // Create garbage and check that idle notification still collects it.
17795   CreateGarbageInOldSpace();
17796   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17797   CHECK_GT(size_with_garbage, initial_size + MB);
17798   bool finished = false;
17799   for (int i = 0; i < 200 && !finished; i++) {
17800     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17801   }
17802   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17803   CHECK_LT(final_size, initial_size + 1);
17804 }
17805
17806
17807 TEST(Regress2333) {
17808   LocalContext env;
17809   for (int i = 0; i < 3; i++) {
17810     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17811   }
17812 }
17813
17814 static uint32_t* stack_limit;
17815
17816 static void GetStackLimitCallback(
17817     const v8::FunctionCallbackInfo<v8::Value>& args) {
17818   stack_limit = reinterpret_cast<uint32_t*>(
17819       CcTest::i_isolate()->stack_guard()->real_climit());
17820 }
17821
17822
17823 // Uses the address of a local variable to determine the stack top now.
17824 // Given a size, returns an address that is that far from the current
17825 // top of stack.
17826 static uint32_t* ComputeStackLimit(uint32_t size) {
17827   uint32_t* answer = &size - (size / sizeof(size));
17828   // If the size is very large and the stack is very near the bottom of
17829   // memory then the calculation above may wrap around and give an address
17830   // that is above the (downwards-growing) stack.  In that case we return
17831   // a very low address.
17832   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17833   return answer;
17834 }
17835
17836
17837 // We need at least 165kB for an x64 debug build with clang and ASAN.
17838 static const int stack_breathing_room = 256 * i::KB;
17839
17840
17841 TEST(SetResourceConstraints) {
17842   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17843
17844   // Set stack limit.
17845   v8::ResourceConstraints constraints;
17846   constraints.set_stack_limit(set_limit);
17847   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17848
17849   // Execute a script.
17850   LocalContext env;
17851   v8::HandleScope scope(env->GetIsolate());
17852   Local<v8::FunctionTemplate> fun_templ =
17853       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17854   Local<Function> fun = fun_templ->GetFunction();
17855   env->Global()->Set(v8_str("get_stack_limit"), fun);
17856   CompileRun("get_stack_limit();");
17857
17858   CHECK(stack_limit == set_limit);
17859 }
17860
17861
17862 TEST(SetResourceConstraintsInThread) {
17863   uint32_t* set_limit;
17864   {
17865     v8::Locker locker(CcTest::isolate());
17866     set_limit = ComputeStackLimit(stack_breathing_room);
17867
17868     // Set stack limit.
17869     v8::ResourceConstraints constraints;
17870     constraints.set_stack_limit(set_limit);
17871     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17872
17873     // Execute a script.
17874     v8::HandleScope scope(CcTest::isolate());
17875     LocalContext env;
17876     Local<v8::FunctionTemplate> fun_templ =
17877         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17878     Local<Function> fun = fun_templ->GetFunction();
17879     env->Global()->Set(v8_str("get_stack_limit"), fun);
17880     CompileRun("get_stack_limit();");
17881
17882     CHECK(stack_limit == set_limit);
17883   }
17884   {
17885     v8::Locker locker(CcTest::isolate());
17886     CHECK(stack_limit == set_limit);
17887   }
17888 }
17889
17890
17891 THREADED_TEST(GetHeapStatistics) {
17892   LocalContext c1;
17893   v8::HandleScope scope(c1->GetIsolate());
17894   v8::HeapStatistics heap_statistics;
17895   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17896   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17897   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17898   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17899   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17900 }
17901
17902
17903 class VisitorImpl : public v8::ExternalResourceVisitor {
17904  public:
17905   explicit VisitorImpl(TestResource** resource) {
17906     for (int i = 0; i < 4; i++) {
17907       resource_[i] = resource[i];
17908       found_resource_[i] = false;
17909     }
17910   }
17911   virtual ~VisitorImpl() {}
17912   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17913     if (!string->IsExternal()) {
17914       CHECK(string->IsExternalAscii());
17915       return;
17916     }
17917     v8::String::ExternalStringResource* resource =
17918         string->GetExternalStringResource();
17919     CHECK(resource);
17920     for (int i = 0; i < 4; i++) {
17921       if (resource_[i] == resource) {
17922         CHECK(!found_resource_[i]);
17923         found_resource_[i] = true;
17924       }
17925     }
17926   }
17927   void CheckVisitedResources() {
17928     for (int i = 0; i < 4; i++) {
17929       CHECK(found_resource_[i]);
17930     }
17931   }
17932
17933  private:
17934   v8::String::ExternalStringResource* resource_[4];
17935   bool found_resource_[4];
17936 };
17937
17938
17939 TEST(ExternalizeOldSpaceTwoByteCons) {
17940   LocalContext env;
17941   v8::HandleScope scope(env->GetIsolate());
17942   v8::Local<v8::String> cons =
17943       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17944   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17945   CcTest::heap()->CollectAllAvailableGarbage();
17946   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17947             *v8::Utils::OpenHandle(*cons)));
17948
17949   TestResource* resource = new TestResource(
17950       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17951   cons->MakeExternal(resource);
17952
17953   CHECK(cons->IsExternal());
17954   CHECK_EQ(resource, cons->GetExternalStringResource());
17955   String::Encoding encoding;
17956   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17957   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17958 }
17959
17960
17961 TEST(ExternalizeOldSpaceOneByteCons) {
17962   LocalContext env;
17963   v8::HandleScope scope(env->GetIsolate());
17964   v8::Local<v8::String> cons =
17965       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17966   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17967   CcTest::heap()->CollectAllAvailableGarbage();
17968   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17969             *v8::Utils::OpenHandle(*cons)));
17970
17971   TestAsciiResource* resource =
17972       new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17973   cons->MakeExternal(resource);
17974
17975   CHECK(cons->IsExternalAscii());
17976   CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17977   String::Encoding encoding;
17978   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17979   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17980 }
17981
17982
17983 TEST(VisitExternalStrings) {
17984   LocalContext env;
17985   v8::HandleScope scope(env->GetIsolate());
17986   const char* string = "Some string";
17987   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17988   TestResource* resource[4];
17989   resource[0] = new TestResource(two_byte_string);
17990   v8::Local<v8::String> string0 =
17991       v8::String::NewExternal(env->GetIsolate(), resource[0]);
17992   resource[1] = new TestResource(two_byte_string, NULL, false);
17993   v8::Local<v8::String> string1 =
17994       v8::String::NewExternal(env->GetIsolate(), resource[1]);
17995
17996   // Externalized symbol.
17997   resource[2] = new TestResource(two_byte_string, NULL, false);
17998   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17999       env->GetIsolate(), string, v8::String::kInternalizedString);
18000   CHECK(string2->MakeExternal(resource[2]));
18001
18002   // Symbolized External.
18003   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18004   v8::Local<v8::String> string3 =
18005       v8::String::NewExternal(env->GetIsolate(), resource[3]);
18006   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
18007   // Turn into a symbol.
18008   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18009   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18010       string3_i).is_null());
18011   CHECK(string3_i->IsInternalizedString());
18012
18013   // We need to add usages for string* to avoid warnings in GCC 4.7
18014   CHECK(string0->IsExternal());
18015   CHECK(string1->IsExternal());
18016   CHECK(string2->IsExternal());
18017   CHECK(string3->IsExternal());
18018
18019   VisitorImpl visitor(resource);
18020   v8::V8::VisitExternalResources(&visitor);
18021   visitor.CheckVisitedResources();
18022 }
18023
18024
18025 TEST(ExternalStringCollectedAtTearDown) {
18026   int destroyed = 0;
18027   v8::Isolate* isolate = v8::Isolate::New();
18028   { v8::Isolate::Scope isolate_scope(isolate);
18029     v8::HandleScope handle_scope(isolate);
18030     const char* s = "One string to test them all, one string to find them.";
18031     TestAsciiResource* inscription =
18032         new TestAsciiResource(i::StrDup(s), &destroyed);
18033     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18034     // Ring is still alive.  Orcs are roaming freely across our lands.
18035     CHECK_EQ(0, destroyed);
18036     USE(ring);
18037   }
18038
18039   isolate->Dispose();
18040   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18041   CHECK_EQ(1, destroyed);
18042 }
18043
18044
18045 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18046   int destroyed = 0;
18047   v8::Isolate* isolate = v8::Isolate::New();
18048   { v8::Isolate::Scope isolate_scope(isolate);
18049     LocalContext env(isolate);
18050     v8::HandleScope handle_scope(isolate);
18051     CompileRun("var ring = 'One string to test them all';");
18052     const char* s = "One string to test them all";
18053     TestAsciiResource* inscription =
18054         new TestAsciiResource(i::StrDup(s), &destroyed);
18055     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18056     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18057     ring->MakeExternal(inscription);
18058     // Ring is still alive.  Orcs are roaming freely across our lands.
18059     CHECK_EQ(0, destroyed);
18060     USE(ring);
18061   }
18062
18063   isolate->Dispose();
18064   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18065   CHECK_EQ(1, destroyed);
18066 }
18067
18068
18069 TEST(ExternalInternalizedStringCollectedAtGC) {
18070   int destroyed = 0;
18071   { LocalContext env;
18072     v8::HandleScope handle_scope(env->GetIsolate());
18073     CompileRun("var ring = 'One string to test them all';");
18074     const char* s = "One string to test them all";
18075     TestAsciiResource* inscription =
18076         new TestAsciiResource(i::StrDup(s), &destroyed);
18077     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18078     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18079     ring->MakeExternal(inscription);
18080     // Ring is still alive.  Orcs are roaming freely across our lands.
18081     CHECK_EQ(0, destroyed);
18082     USE(ring);
18083   }
18084
18085   // Garbage collector deals swift blows to evil.
18086   CcTest::i_isolate()->compilation_cache()->Clear();
18087   CcTest::heap()->CollectAllAvailableGarbage();
18088
18089   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18090   CHECK_EQ(1, destroyed);
18091 }
18092
18093
18094 static double DoubleFromBits(uint64_t value) {
18095   double target;
18096   i::MemCopy(&target, &value, sizeof(target));
18097   return target;
18098 }
18099
18100
18101 static uint64_t DoubleToBits(double value) {
18102   uint64_t target;
18103   i::MemCopy(&target, &value, sizeof(target));
18104   return target;
18105 }
18106
18107
18108 static double DoubleToDateTime(double input) {
18109   double date_limit = 864e13;
18110   if (std::isnan(input) || input < -date_limit || input > date_limit) {
18111     return i::OS::nan_value();
18112   }
18113   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18114 }
18115
18116
18117 // We don't have a consistent way to write 64-bit constants syntactically, so we
18118 // split them into two 32-bit constants and combine them programmatically.
18119 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18120   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18121 }
18122
18123
18124 THREADED_TEST(QuietSignalingNaNs) {
18125   LocalContext context;
18126   v8::Isolate* isolate = context->GetIsolate();
18127   v8::HandleScope scope(isolate);
18128   v8::TryCatch try_catch;
18129
18130   // Special double values.
18131   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18132   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18133   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18134   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18135   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18136   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18137   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18138
18139   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18140   // on either side of the epoch.
18141   double date_limit = 864e13;
18142
18143   double test_values[] = {
18144       snan,
18145       qnan,
18146       infinity,
18147       max_normal,
18148       date_limit + 1,
18149       date_limit,
18150       min_normal,
18151       max_denormal,
18152       min_denormal,
18153       0,
18154       -0,
18155       -min_denormal,
18156       -max_denormal,
18157       -min_normal,
18158       -date_limit,
18159       -date_limit - 1,
18160       -max_normal,
18161       -infinity,
18162       -qnan,
18163       -snan
18164   };
18165   int num_test_values = 20;
18166
18167   for (int i = 0; i < num_test_values; i++) {
18168     double test_value = test_values[i];
18169
18170     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18171     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18172     double stored_number = number->NumberValue();
18173     if (!std::isnan(test_value)) {
18174       CHECK_EQ(test_value, stored_number);
18175     } else {
18176       uint64_t stored_bits = DoubleToBits(stored_number);
18177       // Check if quiet nan (bits 51..62 all set).
18178 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18179       // Most significant fraction bit for quiet nan is set to 0
18180       // on MIPS architecture. Allowed by IEEE-754.
18181       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18182 #else
18183       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18184 #endif
18185     }
18186
18187     // Check that Date::New preserves non-NaNs in the date range and
18188     // quiets SNaNs.
18189     v8::Handle<v8::Value> date =
18190         v8::Date::New(isolate, test_value);
18191     double expected_stored_date = DoubleToDateTime(test_value);
18192     double stored_date = date->NumberValue();
18193     if (!std::isnan(expected_stored_date)) {
18194       CHECK_EQ(expected_stored_date, stored_date);
18195     } else {
18196       uint64_t stored_bits = DoubleToBits(stored_date);
18197       // Check if quiet nan (bits 51..62 all set).
18198 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18199       // Most significant fraction bit for quiet nan is set to 0
18200       // on MIPS architecture. Allowed by IEEE-754.
18201       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18202 #else
18203       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18204 #endif
18205     }
18206   }
18207 }
18208
18209
18210 static void SpaghettiIncident(
18211     const v8::FunctionCallbackInfo<v8::Value>& args) {
18212   v8::HandleScope scope(args.GetIsolate());
18213   v8::TryCatch tc;
18214   v8::Handle<v8::String> str(args[0]->ToString());
18215   USE(str);
18216   if (tc.HasCaught())
18217     tc.ReThrow();
18218 }
18219
18220
18221 // Test that an exception can be propagated down through a spaghetti
18222 // stack using ReThrow.
18223 THREADED_TEST(SpaghettiStackReThrow) {
18224   v8::Isolate* isolate = CcTest::isolate();
18225   v8::HandleScope scope(isolate);
18226   LocalContext context;
18227   context->Global()->Set(
18228       v8::String::NewFromUtf8(isolate, "s"),
18229       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18230   v8::TryCatch try_catch;
18231   CompileRun(
18232       "var i = 0;"
18233       "var o = {"
18234       "  toString: function () {"
18235       "    if (i == 10) {"
18236       "      throw 'Hey!';"
18237       "    } else {"
18238       "      i++;"
18239       "      return s(o);"
18240       "    }"
18241       "  }"
18242       "};"
18243       "s(o);");
18244   CHECK(try_catch.HasCaught());
18245   v8::String::Utf8Value value(try_catch.Exception());
18246   CHECK_EQ(0, strcmp(*value, "Hey!"));
18247 }
18248
18249
18250 TEST(Regress528) {
18251   v8::V8::Initialize();
18252   v8::Isolate* isolate = CcTest::isolate();
18253   v8::HandleScope scope(isolate);
18254   v8::Local<Context> other_context;
18255   int gc_count;
18256
18257   // Create a context used to keep the code from aging in the compilation
18258   // cache.
18259   other_context = Context::New(isolate);
18260
18261   // Context-dependent context data creates reference from the compilation
18262   // cache to the global object.
18263   const char* source_simple = "1";
18264   {
18265     v8::HandleScope scope(isolate);
18266     v8::Local<Context> context = Context::New(isolate);
18267
18268     context->Enter();
18269     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18270     context->SetEmbedderData(0, obj);
18271     CompileRun(source_simple);
18272     context->Exit();
18273   }
18274   v8::V8::ContextDisposedNotification();
18275   for (gc_count = 1; gc_count < 10; gc_count++) {
18276     other_context->Enter();
18277     CompileRun(source_simple);
18278     other_context->Exit();
18279     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18280     if (GetGlobalObjectsCount() == 1) break;
18281   }
18282   CHECK_GE(2, gc_count);
18283   CHECK_EQ(1, GetGlobalObjectsCount());
18284
18285   // Eval in a function creates reference from the compilation cache to the
18286   // global object.
18287   const char* source_eval = "function f(){eval('1')}; f()";
18288   {
18289     v8::HandleScope scope(isolate);
18290     v8::Local<Context> context = Context::New(isolate);
18291
18292     context->Enter();
18293     CompileRun(source_eval);
18294     context->Exit();
18295   }
18296   v8::V8::ContextDisposedNotification();
18297   for (gc_count = 1; gc_count < 10; gc_count++) {
18298     other_context->Enter();
18299     CompileRun(source_eval);
18300     other_context->Exit();
18301     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18302     if (GetGlobalObjectsCount() == 1) break;
18303   }
18304   CHECK_GE(2, gc_count);
18305   CHECK_EQ(1, GetGlobalObjectsCount());
18306
18307   // Looking up the line number for an exception creates reference from the
18308   // compilation cache to the global object.
18309   const char* source_exception = "function f(){throw 1;} f()";
18310   {
18311     v8::HandleScope scope(isolate);
18312     v8::Local<Context> context = Context::New(isolate);
18313
18314     context->Enter();
18315     v8::TryCatch try_catch;
18316     CompileRun(source_exception);
18317     CHECK(try_catch.HasCaught());
18318     v8::Handle<v8::Message> message = try_catch.Message();
18319     CHECK(!message.IsEmpty());
18320     CHECK_EQ(1, message->GetLineNumber());
18321     context->Exit();
18322   }
18323   v8::V8::ContextDisposedNotification();
18324   for (gc_count = 1; gc_count < 10; gc_count++) {
18325     other_context->Enter();
18326     CompileRun(source_exception);
18327     other_context->Exit();
18328     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18329     if (GetGlobalObjectsCount() == 1) break;
18330   }
18331   CHECK_GE(2, gc_count);
18332   CHECK_EQ(1, GetGlobalObjectsCount());
18333
18334   v8::V8::ContextDisposedNotification();
18335 }
18336
18337
18338 THREADED_TEST(ScriptOrigin) {
18339   LocalContext env;
18340   v8::HandleScope scope(env->GetIsolate());
18341   v8::ScriptOrigin origin =
18342       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18343   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18344       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18345   v8::Script::Compile(script, &origin)->Run();
18346   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18347       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18348   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18349       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18350
18351   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18352   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18353   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18354
18355   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18356   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18357   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18358 }
18359
18360
18361 THREADED_TEST(FunctionGetInferredName) {
18362   LocalContext env;
18363   v8::HandleScope scope(env->GetIsolate());
18364   v8::ScriptOrigin origin =
18365       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18366   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18367       env->GetIsolate(),
18368       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18369   v8::Script::Compile(script, &origin)->Run();
18370   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18371       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18372   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18373 }
18374
18375
18376 THREADED_TEST(FunctionGetDisplayName) {
18377   LocalContext env;
18378   v8::HandleScope scope(env->GetIsolate());
18379   const char* code = "var error = false;"
18380                      "function a() { this.x = 1; };"
18381                      "a.displayName = 'display_a';"
18382                      "var b = (function() {"
18383                      "  var f = function() { this.x = 2; };"
18384                      "  f.displayName = 'display_b';"
18385                      "  return f;"
18386                      "})();"
18387                      "var c = function() {};"
18388                      "c.__defineGetter__('displayName', function() {"
18389                      "  error = true;"
18390                      "  throw new Error();"
18391                      "});"
18392                      "function d() {};"
18393                      "d.__defineGetter__('displayName', function() {"
18394                      "  error = true;"
18395                      "  return 'wrong_display_name';"
18396                      "});"
18397                      "function e() {};"
18398                      "e.displayName = 'wrong_display_name';"
18399                      "e.__defineSetter__('displayName', function() {"
18400                      "  error = true;"
18401                      "  throw new Error();"
18402                      "});"
18403                      "function f() {};"
18404                      "f.displayName = { 'foo': 6, toString: function() {"
18405                      "  error = true;"
18406                      "  return 'wrong_display_name';"
18407                      "}};"
18408                      "var g = function() {"
18409                      "  arguments.callee.displayName = 'set_in_runtime';"
18410                      "}; g();"
18411                      ;
18412   v8::ScriptOrigin origin =
18413       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18414   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18415       ->Run();
18416   v8::Local<v8::Value> error =
18417       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18418   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18419       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18420   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18421       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18422   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18423       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18424   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18425       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18426   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18427       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18428   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18429       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18430   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18431       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18432   CHECK_EQ(false, error->BooleanValue());
18433   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18434   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18435   CHECK(c->GetDisplayName()->IsUndefined());
18436   CHECK(d->GetDisplayName()->IsUndefined());
18437   CHECK(e->GetDisplayName()->IsUndefined());
18438   CHECK(f->GetDisplayName()->IsUndefined());
18439   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18440 }
18441
18442
18443 THREADED_TEST(ScriptLineNumber) {
18444   LocalContext env;
18445   v8::HandleScope scope(env->GetIsolate());
18446   v8::ScriptOrigin origin =
18447       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18448   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18449       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18450   v8::Script::Compile(script, &origin)->Run();
18451   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18452       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18453   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18454       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18455   CHECK_EQ(0, f->GetScriptLineNumber());
18456   CHECK_EQ(2, g->GetScriptLineNumber());
18457 }
18458
18459
18460 THREADED_TEST(ScriptColumnNumber) {
18461   LocalContext env;
18462   v8::Isolate* isolate = env->GetIsolate();
18463   v8::HandleScope scope(isolate);
18464   v8::ScriptOrigin origin =
18465       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18466                        v8::Integer::New(isolate, 3),
18467                        v8::Integer::New(isolate, 2));
18468   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18469       isolate, "function foo() {}\n\n     function bar() {}");
18470   v8::Script::Compile(script, &origin)->Run();
18471   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18472       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18473   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18474       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18475   CHECK_EQ(14, foo->GetScriptColumnNumber());
18476   CHECK_EQ(17, bar->GetScriptColumnNumber());
18477 }
18478
18479
18480 THREADED_TEST(FunctionIsBuiltin) {
18481   LocalContext env;
18482   v8::Isolate* isolate = env->GetIsolate();
18483   v8::HandleScope scope(isolate);
18484   v8::Local<v8::Function> f;
18485   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18486   CHECK(f->IsBuiltin());
18487   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18488   CHECK(f->IsBuiltin());
18489   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18490   CHECK(f->IsBuiltin());
18491   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18492   CHECK(f->IsBuiltin());
18493   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18494   CHECK(!f->IsBuiltin());
18495 }
18496
18497
18498 THREADED_TEST(FunctionGetScriptId) {
18499   LocalContext env;
18500   v8::Isolate* isolate = env->GetIsolate();
18501   v8::HandleScope scope(isolate);
18502   v8::ScriptOrigin origin =
18503       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18504                        v8::Integer::New(isolate, 3),
18505                        v8::Integer::New(isolate, 2));
18506   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18507       isolate, "function foo() {}\n\n     function bar() {}");
18508   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18509   script->Run();
18510   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18511       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18512   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18513       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18514   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18515   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18516 }
18517
18518
18519 THREADED_TEST(FunctionGetBoundFunction) {
18520   LocalContext env;
18521   v8::HandleScope scope(env->GetIsolate());
18522   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18523       env->GetIsolate(), "test"));
18524   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18525       env->GetIsolate(),
18526       "var a = new Object();\n"
18527       "a.x = 1;\n"
18528       "function f () { return this.x };\n"
18529       "var g = f.bind(a);\n"
18530       "var b = g();");
18531   v8::Script::Compile(script, &origin)->Run();
18532   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18533       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18534   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18535       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18536   CHECK(g->GetBoundFunction()->IsFunction());
18537   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18538       g->GetBoundFunction());
18539   CHECK_EQ(f->GetName(), original_function->GetName());
18540   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18541   CHECK_EQ(f->GetScriptColumnNumber(),
18542            original_function->GetScriptColumnNumber());
18543 }
18544
18545
18546 static void GetterWhichReturns42(
18547     Local<String> name,
18548     const v8::PropertyCallbackInfo<v8::Value>& info) {
18549   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18550   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18551   info.GetReturnValue().Set(v8_num(42));
18552 }
18553
18554
18555 static void SetterWhichSetsYOnThisTo23(
18556     Local<String> name,
18557     Local<Value> value,
18558     const v8::PropertyCallbackInfo<void>& info) {
18559   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18560   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18561   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18562 }
18563
18564
18565 void FooGetInterceptor(Local<String> name,
18566                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18567   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18568   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18569   if (!name->Equals(v8_str("foo"))) return;
18570   info.GetReturnValue().Set(v8_num(42));
18571 }
18572
18573
18574 void FooSetInterceptor(Local<String> name,
18575                        Local<Value> value,
18576                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18577   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18578   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18579   if (!name->Equals(v8_str("foo"))) return;
18580   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18581   info.GetReturnValue().Set(v8_num(23));
18582 }
18583
18584
18585 TEST(SetterOnConstructorPrototype) {
18586   v8::Isolate* isolate = CcTest::isolate();
18587   v8::HandleScope scope(isolate);
18588   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18589   templ->SetAccessor(v8_str("x"),
18590                      GetterWhichReturns42,
18591                      SetterWhichSetsYOnThisTo23);
18592   LocalContext context;
18593   context->Global()->Set(v8_str("P"), templ->NewInstance());
18594   CompileRun("function C1() {"
18595              "  this.x = 23;"
18596              "};"
18597              "C1.prototype = P;"
18598              "function C2() {"
18599              "  this.x = 23"
18600              "};"
18601              "C2.prototype = { };"
18602              "C2.prototype.__proto__ = P;");
18603
18604   v8::Local<v8::Script> script;
18605   script = v8_compile("new C1();");
18606   for (int i = 0; i < 10; i++) {
18607     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18608     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18609     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18610   }
18611
18612 script = v8_compile("new C2();");
18613   for (int i = 0; i < 10; i++) {
18614     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18615     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18616     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18617   }
18618 }
18619
18620
18621 static void NamedPropertyGetterWhichReturns42(
18622     Local<String> name,
18623     const v8::PropertyCallbackInfo<v8::Value>& info) {
18624   info.GetReturnValue().Set(v8_num(42));
18625 }
18626
18627
18628 static void NamedPropertySetterWhichSetsYOnThisTo23(
18629     Local<String> name,
18630     Local<Value> value,
18631     const v8::PropertyCallbackInfo<v8::Value>& info) {
18632   if (name->Equals(v8_str("x"))) {
18633     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18634   }
18635 }
18636
18637
18638 THREADED_TEST(InterceptorOnConstructorPrototype) {
18639   v8::Isolate* isolate = CcTest::isolate();
18640   v8::HandleScope scope(isolate);
18641   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18642   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18643                                  NamedPropertySetterWhichSetsYOnThisTo23);
18644   LocalContext context;
18645   context->Global()->Set(v8_str("P"), templ->NewInstance());
18646   CompileRun("function C1() {"
18647              "  this.x = 23;"
18648              "};"
18649              "C1.prototype = P;"
18650              "function C2() {"
18651              "  this.x = 23"
18652              "};"
18653              "C2.prototype = { };"
18654              "C2.prototype.__proto__ = P;");
18655
18656   v8::Local<v8::Script> script;
18657   script = v8_compile("new C1();");
18658   for (int i = 0; i < 10; i++) {
18659     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18660     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18661     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18662   }
18663
18664   script = v8_compile("new C2();");
18665   for (int i = 0; i < 10; i++) {
18666     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18667     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18668     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18669   }
18670 }
18671
18672
18673 TEST(Regress618) {
18674   const char* source = "function C1() {"
18675                        "  this.x = 23;"
18676                        "};"
18677                        "C1.prototype = P;";
18678
18679   LocalContext context;
18680   v8::Isolate* isolate = context->GetIsolate();
18681   v8::HandleScope scope(isolate);
18682   v8::Local<v8::Script> script;
18683
18684   // Use a simple object as prototype.
18685   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18686   prototype->Set(v8_str("y"), v8_num(42));
18687   context->Global()->Set(v8_str("P"), prototype);
18688
18689   // This compile will add the code to the compilation cache.
18690   CompileRun(source);
18691
18692   script = v8_compile("new C1();");
18693   // Allow enough iterations for the inobject slack tracking logic
18694   // to finalize instance size and install the fast construct stub.
18695   for (int i = 0; i < 256; i++) {
18696     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18697     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18698     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18699   }
18700
18701   // Use an API object with accessors as prototype.
18702   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18703   templ->SetAccessor(v8_str("x"),
18704                      GetterWhichReturns42,
18705                      SetterWhichSetsYOnThisTo23);
18706   context->Global()->Set(v8_str("P"), templ->NewInstance());
18707
18708   // This compile will get the code from the compilation cache.
18709   CompileRun(source);
18710
18711   script = v8_compile("new C1();");
18712   for (int i = 0; i < 10; i++) {
18713     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18714     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18715     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18716   }
18717 }
18718
18719 v8::Isolate* gc_callbacks_isolate = NULL;
18720 int prologue_call_count = 0;
18721 int epilogue_call_count = 0;
18722 int prologue_call_count_second = 0;
18723 int epilogue_call_count_second = 0;
18724 int prologue_call_count_alloc = 0;
18725 int epilogue_call_count_alloc = 0;
18726
18727 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18728   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18729   ++prologue_call_count;
18730 }
18731
18732
18733 void PrologueCallback(v8::Isolate* isolate,
18734                       v8::GCType,
18735                       v8::GCCallbackFlags flags) {
18736   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18737   CHECK_EQ(gc_callbacks_isolate, isolate);
18738   ++prologue_call_count;
18739 }
18740
18741
18742 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18743   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18744   ++epilogue_call_count;
18745 }
18746
18747
18748 void EpilogueCallback(v8::Isolate* isolate,
18749                       v8::GCType,
18750                       v8::GCCallbackFlags flags) {
18751   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18752   CHECK_EQ(gc_callbacks_isolate, isolate);
18753   ++epilogue_call_count;
18754 }
18755
18756
18757 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18758   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18759   ++prologue_call_count_second;
18760 }
18761
18762
18763 void PrologueCallbackSecond(v8::Isolate* isolate,
18764                             v8::GCType,
18765                             v8::GCCallbackFlags flags) {
18766   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18767   CHECK_EQ(gc_callbacks_isolate, isolate);
18768   ++prologue_call_count_second;
18769 }
18770
18771
18772 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18773   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18774   ++epilogue_call_count_second;
18775 }
18776
18777
18778 void EpilogueCallbackSecond(v8::Isolate* isolate,
18779                             v8::GCType,
18780                             v8::GCCallbackFlags flags) {
18781   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18782   CHECK_EQ(gc_callbacks_isolate, isolate);
18783   ++epilogue_call_count_second;
18784 }
18785
18786
18787 void PrologueCallbackAlloc(v8::Isolate* isolate,
18788                            v8::GCType,
18789                            v8::GCCallbackFlags flags) {
18790   v8::HandleScope scope(isolate);
18791
18792   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18793   CHECK_EQ(gc_callbacks_isolate, isolate);
18794   ++prologue_call_count_alloc;
18795
18796   // Simulate full heap to see if we will reenter this callback
18797   SimulateFullSpace(CcTest::heap()->new_space());
18798
18799   Local<Object> obj = Object::New(isolate);
18800   CHECK(!obj.IsEmpty());
18801
18802   CcTest::heap()->CollectAllGarbage(
18803       i::Heap::kAbortIncrementalMarkingMask);
18804 }
18805
18806
18807 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18808                            v8::GCType,
18809                            v8::GCCallbackFlags flags) {
18810   v8::HandleScope scope(isolate);
18811
18812   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18813   CHECK_EQ(gc_callbacks_isolate, isolate);
18814   ++epilogue_call_count_alloc;
18815
18816   // Simulate full heap to see if we will reenter this callback
18817   SimulateFullSpace(CcTest::heap()->new_space());
18818
18819   Local<Object> obj = Object::New(isolate);
18820   CHECK(!obj.IsEmpty());
18821
18822   CcTest::heap()->CollectAllGarbage(
18823       i::Heap::kAbortIncrementalMarkingMask);
18824 }
18825
18826
18827 TEST(GCCallbacksOld) {
18828   LocalContext context;
18829
18830   v8::V8::AddGCPrologueCallback(PrologueCallback);
18831   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18832   CHECK_EQ(0, prologue_call_count);
18833   CHECK_EQ(0, epilogue_call_count);
18834   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18835   CHECK_EQ(1, prologue_call_count);
18836   CHECK_EQ(1, epilogue_call_count);
18837   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18838   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18839   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18840   CHECK_EQ(2, prologue_call_count);
18841   CHECK_EQ(2, epilogue_call_count);
18842   CHECK_EQ(1, prologue_call_count_second);
18843   CHECK_EQ(1, epilogue_call_count_second);
18844   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18845   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18846   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18847   CHECK_EQ(2, prologue_call_count);
18848   CHECK_EQ(2, epilogue_call_count);
18849   CHECK_EQ(2, prologue_call_count_second);
18850   CHECK_EQ(2, epilogue_call_count_second);
18851   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18852   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18853   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18854   CHECK_EQ(2, prologue_call_count);
18855   CHECK_EQ(2, epilogue_call_count);
18856   CHECK_EQ(2, prologue_call_count_second);
18857   CHECK_EQ(2, epilogue_call_count_second);
18858 }
18859
18860
18861 TEST(GCCallbacks) {
18862   LocalContext context;
18863   v8::Isolate* isolate = context->GetIsolate();
18864   gc_callbacks_isolate = isolate;
18865   isolate->AddGCPrologueCallback(PrologueCallback);
18866   isolate->AddGCEpilogueCallback(EpilogueCallback);
18867   CHECK_EQ(0, prologue_call_count);
18868   CHECK_EQ(0, epilogue_call_count);
18869   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18870   CHECK_EQ(1, prologue_call_count);
18871   CHECK_EQ(1, epilogue_call_count);
18872   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18873   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18874   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18875   CHECK_EQ(2, prologue_call_count);
18876   CHECK_EQ(2, epilogue_call_count);
18877   CHECK_EQ(1, prologue_call_count_second);
18878   CHECK_EQ(1, epilogue_call_count_second);
18879   isolate->RemoveGCPrologueCallback(PrologueCallback);
18880   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18881   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18882   CHECK_EQ(2, prologue_call_count);
18883   CHECK_EQ(2, epilogue_call_count);
18884   CHECK_EQ(2, prologue_call_count_second);
18885   CHECK_EQ(2, epilogue_call_count_second);
18886   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18887   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18888   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18889   CHECK_EQ(2, prologue_call_count);
18890   CHECK_EQ(2, epilogue_call_count);
18891   CHECK_EQ(2, prologue_call_count_second);
18892   CHECK_EQ(2, epilogue_call_count_second);
18893
18894   CHECK_EQ(0, prologue_call_count_alloc);
18895   CHECK_EQ(0, epilogue_call_count_alloc);
18896   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18897   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18898   CcTest::heap()->CollectAllGarbage(
18899       i::Heap::kAbortIncrementalMarkingMask);
18900   CHECK_EQ(1, prologue_call_count_alloc);
18901   CHECK_EQ(1, epilogue_call_count_alloc);
18902   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18903   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18904 }
18905
18906
18907 THREADED_TEST(AddToJSFunctionResultCache) {
18908   i::FLAG_stress_compaction = false;
18909   i::FLAG_allow_natives_syntax = true;
18910   v8::HandleScope scope(CcTest::isolate());
18911
18912   LocalContext context;
18913
18914   const char* code =
18915       "(function() {"
18916       "  var key0 = 'a';"
18917       "  var key1 = 'b';"
18918       "  var r0 = %_GetFromCache(0, key0);"
18919       "  var r1 = %_GetFromCache(0, key1);"
18920       "  var r0_ = %_GetFromCache(0, key0);"
18921       "  if (r0 !== r0_)"
18922       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18923       "  var r1_ = %_GetFromCache(0, key1);"
18924       "  if (r1 !== r1_)"
18925       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18926       "  return 'PASSED';"
18927       "})()";
18928   CcTest::heap()->ClearJSFunctionResultCaches();
18929   ExpectString(code, "PASSED");
18930 }
18931
18932
18933 THREADED_TEST(FillJSFunctionResultCache) {
18934   i::FLAG_allow_natives_syntax = true;
18935   LocalContext context;
18936   v8::HandleScope scope(context->GetIsolate());
18937
18938   const char* code =
18939       "(function() {"
18940       "  var k = 'a';"
18941       "  var r = %_GetFromCache(0, k);"
18942       "  for (var i = 0; i < 16; i++) {"
18943       "    %_GetFromCache(0, 'a' + i);"
18944       "  };"
18945       "  if (r === %_GetFromCache(0, k))"
18946       "    return 'FAILED: k0CacheSize is too small';"
18947       "  return 'PASSED';"
18948       "})()";
18949   CcTest::heap()->ClearJSFunctionResultCaches();
18950   ExpectString(code, "PASSED");
18951 }
18952
18953
18954 THREADED_TEST(RoundRobinGetFromCache) {
18955   i::FLAG_allow_natives_syntax = true;
18956   LocalContext context;
18957   v8::HandleScope scope(context->GetIsolate());
18958
18959   const char* code =
18960       "(function() {"
18961       "  var keys = [];"
18962       "  for (var i = 0; i < 16; i++) keys.push(i);"
18963       "  var values = [];"
18964       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18965       "  for (var i = 0; i < 16; i++) {"
18966       "    var v = %_GetFromCache(0, keys[i]);"
18967       "    if (v.toString() !== values[i].toString())"
18968       "      return 'Wrong value for ' + "
18969       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18970       "  };"
18971       "  return 'PASSED';"
18972       "})()";
18973   CcTest::heap()->ClearJSFunctionResultCaches();
18974   ExpectString(code, "PASSED");
18975 }
18976
18977
18978 THREADED_TEST(ReverseGetFromCache) {
18979   i::FLAG_allow_natives_syntax = true;
18980   LocalContext context;
18981   v8::HandleScope scope(context->GetIsolate());
18982
18983   const char* code =
18984       "(function() {"
18985       "  var keys = [];"
18986       "  for (var i = 0; i < 16; i++) keys.push(i);"
18987       "  var values = [];"
18988       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18989       "  for (var i = 15; i >= 16; i--) {"
18990       "    var v = %_GetFromCache(0, keys[i]);"
18991       "    if (v !== values[i])"
18992       "      return 'Wrong value for ' + "
18993       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18994       "  };"
18995       "  return 'PASSED';"
18996       "})()";
18997   CcTest::heap()->ClearJSFunctionResultCaches();
18998   ExpectString(code, "PASSED");
18999 }
19000
19001
19002 THREADED_TEST(TestEviction) {
19003   i::FLAG_allow_natives_syntax = true;
19004   LocalContext context;
19005   v8::HandleScope scope(context->GetIsolate());
19006
19007   const char* code =
19008       "(function() {"
19009       "  for (var i = 0; i < 2*16; i++) {"
19010       "    %_GetFromCache(0, 'a' + i);"
19011       "  };"
19012       "  return 'PASSED';"
19013       "})()";
19014   CcTest::heap()->ClearJSFunctionResultCaches();
19015   ExpectString(code, "PASSED");
19016 }
19017
19018
19019 THREADED_TEST(TwoByteStringInAsciiCons) {
19020   // See Chromium issue 47824.
19021   LocalContext context;
19022   v8::HandleScope scope(context->GetIsolate());
19023
19024   const char* init_code =
19025       "var str1 = 'abelspendabel';"
19026       "var str2 = str1 + str1 + str1;"
19027       "str2;";
19028   Local<Value> result = CompileRun(init_code);
19029
19030   Local<Value> indexof = CompileRun("str2.indexOf('els')");
19031   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19032
19033   CHECK(result->IsString());
19034   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19035   int length = string->length();
19036   CHECK(string->IsOneByteRepresentation());
19037
19038   i::Handle<i::String> flat_string = i::String::Flatten(string);
19039
19040   CHECK(string->IsOneByteRepresentation());
19041   CHECK(flat_string->IsOneByteRepresentation());
19042
19043   // Create external resource.
19044   uint16_t* uc16_buffer = new uint16_t[length + 1];
19045
19046   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19047   uc16_buffer[length] = 0;
19048
19049   TestResource resource(uc16_buffer);
19050
19051   flat_string->MakeExternal(&resource);
19052
19053   CHECK(flat_string->IsTwoByteRepresentation());
19054
19055   // If the cons string has been short-circuited, skip the following checks.
19056   if (!string.is_identical_to(flat_string)) {
19057     // At this point, we should have a Cons string which is flat and ASCII,
19058     // with a first half that is a two-byte string (although it only contains
19059     // ASCII characters). This is a valid sequence of steps, and it can happen
19060     // in real pages.
19061     CHECK(string->IsOneByteRepresentation());
19062     i::ConsString* cons = i::ConsString::cast(*string);
19063     CHECK_EQ(0, cons->second()->length());
19064     CHECK(cons->first()->IsTwoByteRepresentation());
19065   }
19066
19067   // Check that some string operations work.
19068
19069   // Atom RegExp.
19070   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19071   CHECK_EQ(6, reresult->Int32Value());
19072
19073   // Nonatom RegExp.
19074   reresult = CompileRun("str2.match(/abe./g).length;");
19075   CHECK_EQ(6, reresult->Int32Value());
19076
19077   reresult = CompileRun("str2.search(/bel/g);");
19078   CHECK_EQ(1, reresult->Int32Value());
19079
19080   reresult = CompileRun("str2.search(/be./g);");
19081   CHECK_EQ(1, reresult->Int32Value());
19082
19083   ExpectTrue("/bel/g.test(str2);");
19084
19085   ExpectTrue("/be./g.test(str2);");
19086
19087   reresult = CompileRun("/bel/g.exec(str2);");
19088   CHECK(!reresult->IsNull());
19089
19090   reresult = CompileRun("/be./g.exec(str2);");
19091   CHECK(!reresult->IsNull());
19092
19093   ExpectString("str2.substring(2, 10);", "elspenda");
19094
19095   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19096
19097   ExpectString("str2.charAt(2);", "e");
19098
19099   ExpectObject("str2.indexOf('els');", indexof);
19100
19101   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19102
19103   reresult = CompileRun("str2.charCodeAt(2);");
19104   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19105 }
19106
19107
19108 TEST(ContainsOnlyOneByte) {
19109   v8::V8::Initialize();
19110   v8::Isolate* isolate = CcTest::isolate();
19111   v8::HandleScope scope(isolate);
19112   // Make a buffer long enough that it won't automatically be converted.
19113   const int length = 512;
19114   // Ensure word aligned assignment.
19115   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19116   i::SmartArrayPointer<uintptr_t>
19117   aligned_contents(new uintptr_t[aligned_length]);
19118   uint16_t* string_contents =
19119       reinterpret_cast<uint16_t*>(aligned_contents.get());
19120   // Set to contain only one byte.
19121   for (int i = 0; i < length-1; i++) {
19122     string_contents[i] = 0x41;
19123   }
19124   string_contents[length-1] = 0;
19125   // Simple case.
19126   Handle<String> string =
19127       String::NewExternal(isolate,
19128                           new TestResource(string_contents, NULL, false));
19129   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19130   // Counter example.
19131   string = String::NewFromTwoByte(isolate, string_contents);
19132   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19133   // Test left right and balanced cons strings.
19134   Handle<String> base = String::NewFromUtf8(isolate, "a");
19135   Handle<String> left = base;
19136   Handle<String> right = base;
19137   for (int i = 0; i < 1000; i++) {
19138     left = String::Concat(base, left);
19139     right = String::Concat(right, base);
19140   }
19141   Handle<String> balanced = String::Concat(left, base);
19142   balanced = String::Concat(balanced, right);
19143   Handle<String> cons_strings[] = {left, balanced, right};
19144   Handle<String> two_byte =
19145       String::NewExternal(isolate,
19146                           new TestResource(string_contents, NULL, false));
19147   USE(two_byte); USE(cons_strings);
19148   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19149     // Base assumptions.
19150     string = cons_strings[i];
19151     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19152     // Test left and right concatentation.
19153     string = String::Concat(two_byte, cons_strings[i]);
19154     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19155     string = String::Concat(cons_strings[i], two_byte);
19156     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19157   }
19158   // Set bits in different positions
19159   // for strings of different lengths and alignments.
19160   for (int alignment = 0; alignment < 7; alignment++) {
19161     for (int size = 2; alignment + size < length; size *= 2) {
19162       int zero_offset = size + alignment;
19163       string_contents[zero_offset] = 0;
19164       for (int i = 0; i < size; i++) {
19165         int shift = 8 + (i % 7);
19166         string_contents[alignment + i] = 1 << shift;
19167         string = String::NewExternal(
19168             isolate,
19169             new TestResource(string_contents + alignment, NULL, false));
19170         CHECK_EQ(size, string->Length());
19171         CHECK(!string->ContainsOnlyOneByte());
19172         string_contents[alignment + i] = 0x41;
19173       }
19174       string_contents[zero_offset] = 0x41;
19175     }
19176   }
19177 }
19178
19179
19180 // Failed access check callback that performs a GC on each invocation.
19181 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19182                                  v8::AccessType type,
19183                                  Local<v8::Value> data) {
19184   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19185 }
19186
19187
19188 TEST(GCInFailedAccessCheckCallback) {
19189   // Install a failed access check callback that performs a GC on each
19190   // invocation. Then force the callback to be called from va
19191
19192   v8::V8::Initialize();
19193   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19194
19195   v8::Isolate* isolate = CcTest::isolate();
19196   v8::HandleScope scope(isolate);
19197
19198   // Create an ObjectTemplate for global objects and install access
19199   // check callbacks that will block access.
19200   v8::Handle<v8::ObjectTemplate> global_template =
19201       v8::ObjectTemplate::New(isolate);
19202   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19203                                            IndexedGetAccessBlocker,
19204                                            v8::Handle<v8::Value>(),
19205                                            false);
19206
19207   // Create a context and set an x property on it's global object.
19208   LocalContext context0(NULL, global_template);
19209   context0->Global()->Set(v8_str("x"), v8_num(42));
19210   v8::Handle<v8::Object> global0 = context0->Global();
19211
19212   // Create a context with a different security token so that the
19213   // failed access check callback will be called on each access.
19214   LocalContext context1(NULL, global_template);
19215   context1->Global()->Set(v8_str("other"), global0);
19216
19217   // Get property with failed access check.
19218   ExpectUndefined("other.x");
19219
19220   // Get element with failed access check.
19221   ExpectUndefined("other[0]");
19222
19223   // Set property with failed access check.
19224   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19225   CHECK(result->IsObject());
19226
19227   // Set element with failed access check.
19228   result = CompileRun("other[0] = new Object()");
19229   CHECK(result->IsObject());
19230
19231   // Get property attribute with failed access check.
19232   ExpectFalse("\'x\' in other");
19233
19234   // Get property attribute for element with failed access check.
19235   ExpectFalse("0 in other");
19236
19237   // Delete property.
19238   ExpectFalse("delete other.x");
19239
19240   // Delete element.
19241   CHECK_EQ(false, global0->Delete(0));
19242
19243   // DefineAccessor.
19244   CHECK_EQ(false,
19245            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19246
19247   // Define JavaScript accessor.
19248   ExpectUndefined("Object.prototype.__defineGetter__.call("
19249                   "    other, \'x\', function() { return 42; })");
19250
19251   // LookupAccessor.
19252   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19253                   "    other, \'x\')");
19254
19255   // HasOwnElement.
19256   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19257
19258   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19259   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19260   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19261
19262   // Reset the failed access check callback so it does not influence
19263   // the other tests.
19264   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19265 }
19266
19267
19268 TEST(IsolateNewDispose) {
19269   v8::Isolate* current_isolate = CcTest::isolate();
19270   v8::Isolate* isolate = v8::Isolate::New();
19271   CHECK(isolate != NULL);
19272   CHECK(current_isolate != isolate);
19273   CHECK(current_isolate == CcTest::isolate());
19274
19275   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19276   last_location = last_message = NULL;
19277   isolate->Dispose();
19278   CHECK_EQ(last_location, NULL);
19279   CHECK_EQ(last_message, NULL);
19280 }
19281
19282
19283 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19284   v8::Isolate* isolate = v8::Isolate::New();
19285   {
19286     v8::Isolate::Scope i_scope(isolate);
19287     v8::HandleScope scope(isolate);
19288     LocalContext context(isolate);
19289     // Run something in this isolate.
19290     ExpectTrue("true");
19291     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19292     last_location = last_message = NULL;
19293     // Still entered, should fail.
19294     isolate->Dispose();
19295     CHECK_NE(last_location, NULL);
19296     CHECK_NE(last_message, NULL);
19297   }
19298   isolate->Dispose();
19299 }
19300
19301
19302 TEST(RunTwoIsolatesOnSingleThread) {
19303   // Run isolate 1.
19304   v8::Isolate* isolate1 = v8::Isolate::New();
19305   isolate1->Enter();
19306   v8::Persistent<v8::Context> context1;
19307   {
19308     v8::HandleScope scope(isolate1);
19309     context1.Reset(isolate1, Context::New(isolate1));
19310   }
19311
19312   {
19313     v8::HandleScope scope(isolate1);
19314     v8::Local<v8::Context> context =
19315         v8::Local<v8::Context>::New(isolate1, context1);
19316     v8::Context::Scope context_scope(context);
19317     // Run something in new isolate.
19318     CompileRun("var foo = 'isolate 1';");
19319     ExpectString("function f() { return foo; }; f()", "isolate 1");
19320   }
19321
19322   // Run isolate 2.
19323   v8::Isolate* isolate2 = v8::Isolate::New();
19324   v8::Persistent<v8::Context> context2;
19325
19326   {
19327     v8::Isolate::Scope iscope(isolate2);
19328     v8::HandleScope scope(isolate2);
19329     context2.Reset(isolate2, Context::New(isolate2));
19330     v8::Local<v8::Context> context =
19331         v8::Local<v8::Context>::New(isolate2, context2);
19332     v8::Context::Scope context_scope(context);
19333
19334     // Run something in new isolate.
19335     CompileRun("var foo = 'isolate 2';");
19336     ExpectString("function f() { return foo; }; f()", "isolate 2");
19337   }
19338
19339   {
19340     v8::HandleScope scope(isolate1);
19341     v8::Local<v8::Context> context =
19342         v8::Local<v8::Context>::New(isolate1, context1);
19343     v8::Context::Scope context_scope(context);
19344     // Now again in isolate 1
19345     ExpectString("function f() { return foo; }; f()", "isolate 1");
19346   }
19347
19348   isolate1->Exit();
19349
19350   // Run some stuff in default isolate.
19351   v8::Persistent<v8::Context> context_default;
19352   {
19353     v8::Isolate* isolate = CcTest::isolate();
19354     v8::Isolate::Scope iscope(isolate);
19355     v8::HandleScope scope(isolate);
19356     context_default.Reset(isolate, Context::New(isolate));
19357   }
19358
19359   {
19360     v8::HandleScope scope(CcTest::isolate());
19361     v8::Local<v8::Context> context =
19362         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19363     v8::Context::Scope context_scope(context);
19364     // Variables in other isolates should be not available, verify there
19365     // is an exception.
19366     ExpectTrue("function f() {"
19367                "  try {"
19368                "    foo;"
19369                "    return false;"
19370                "  } catch(e) {"
19371                "    return true;"
19372                "  }"
19373                "};"
19374                "var isDefaultIsolate = true;"
19375                "f()");
19376   }
19377
19378   isolate1->Enter();
19379
19380   {
19381     v8::Isolate::Scope iscope(isolate2);
19382     v8::HandleScope scope(isolate2);
19383     v8::Local<v8::Context> context =
19384         v8::Local<v8::Context>::New(isolate2, context2);
19385     v8::Context::Scope context_scope(context);
19386     ExpectString("function f() { return foo; }; f()", "isolate 2");
19387   }
19388
19389   {
19390     v8::HandleScope scope(v8::Isolate::GetCurrent());
19391     v8::Local<v8::Context> context =
19392         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19393     v8::Context::Scope context_scope(context);
19394     ExpectString("function f() { return foo; }; f()", "isolate 1");
19395   }
19396
19397   {
19398     v8::Isolate::Scope iscope(isolate2);
19399     context2.Reset();
19400   }
19401
19402   context1.Reset();
19403   isolate1->Exit();
19404
19405   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19406   last_location = last_message = NULL;
19407
19408   isolate1->Dispose();
19409   CHECK_EQ(last_location, NULL);
19410   CHECK_EQ(last_message, NULL);
19411
19412   isolate2->Dispose();
19413   CHECK_EQ(last_location, NULL);
19414   CHECK_EQ(last_message, NULL);
19415
19416   // Check that default isolate still runs.
19417   {
19418     v8::HandleScope scope(CcTest::isolate());
19419     v8::Local<v8::Context> context =
19420         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19421     v8::Context::Scope context_scope(context);
19422     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19423   }
19424 }
19425
19426
19427 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19428   v8::Isolate::Scope isolate_scope(isolate);
19429   v8::HandleScope scope(isolate);
19430   LocalContext context(isolate);
19431   i::ScopedVector<char> code(1024);
19432   i::SNPrintF(code, "function fib(n) {"
19433                     "  if (n <= 2) return 1;"
19434                     "  return fib(n-1) + fib(n-2);"
19435                     "}"
19436                     "fib(%d)", limit);
19437   Local<Value> value = CompileRun(code.start());
19438   CHECK(value->IsNumber());
19439   return static_cast<int>(value->NumberValue());
19440 }
19441
19442 class IsolateThread : public v8::internal::Thread {
19443  public:
19444   IsolateThread(v8::Isolate* isolate, int fib_limit)
19445       : Thread("IsolateThread"),
19446         isolate_(isolate),
19447         fib_limit_(fib_limit),
19448         result_(0) { }
19449
19450   void Run() {
19451     result_ = CalcFibonacci(isolate_, fib_limit_);
19452   }
19453
19454   int result() { return result_; }
19455
19456  private:
19457   v8::Isolate* isolate_;
19458   int fib_limit_;
19459   int result_;
19460 };
19461
19462
19463 TEST(MultipleIsolatesOnIndividualThreads) {
19464   v8::Isolate* isolate1 = v8::Isolate::New();
19465   v8::Isolate* isolate2 = v8::Isolate::New();
19466
19467   IsolateThread thread1(isolate1, 21);
19468   IsolateThread thread2(isolate2, 12);
19469
19470   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19471   thread1.Start();
19472   thread2.Start();
19473
19474   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19475   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19476
19477   thread1.Join();
19478   thread2.Join();
19479
19480   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19481   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19482   CHECK_EQ(result1, 10946);
19483   CHECK_EQ(result2, 144);
19484   CHECK_EQ(result1, thread1.result());
19485   CHECK_EQ(result2, thread2.result());
19486
19487   isolate1->Dispose();
19488   isolate2->Dispose();
19489 }
19490
19491
19492 TEST(IsolateDifferentContexts) {
19493   v8::Isolate* isolate = v8::Isolate::New();
19494   Local<v8::Context> context;
19495   {
19496     v8::Isolate::Scope isolate_scope(isolate);
19497     v8::HandleScope handle_scope(isolate);
19498     context = v8::Context::New(isolate);
19499     v8::Context::Scope context_scope(context);
19500     Local<Value> v = CompileRun("2");
19501     CHECK(v->IsNumber());
19502     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19503   }
19504   {
19505     v8::Isolate::Scope isolate_scope(isolate);
19506     v8::HandleScope handle_scope(isolate);
19507     context = v8::Context::New(isolate);
19508     v8::Context::Scope context_scope(context);
19509     Local<Value> v = CompileRun("22");
19510     CHECK(v->IsNumber());
19511     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19512   }
19513   isolate->Dispose();
19514 }
19515
19516 class InitDefaultIsolateThread : public v8::internal::Thread {
19517  public:
19518   enum TestCase {
19519     SetResourceConstraints,
19520     SetFatalHandler,
19521     SetCounterFunction,
19522     SetCreateHistogramFunction,
19523     SetAddHistogramSampleFunction
19524   };
19525
19526   explicit InitDefaultIsolateThread(TestCase testCase)
19527       : Thread("InitDefaultIsolateThread"),
19528         testCase_(testCase),
19529         result_(false) { }
19530
19531   void Run() {
19532     v8::Isolate* isolate = v8::Isolate::New();
19533     isolate->Enter();
19534     switch (testCase_) {
19535       case SetResourceConstraints: {
19536         v8::ResourceConstraints constraints;
19537         constraints.set_max_semi_space_size(1);
19538         constraints.set_max_old_space_size(4);
19539         v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19540         break;
19541       }
19542
19543       case SetFatalHandler:
19544         v8::V8::SetFatalErrorHandler(NULL);
19545         break;
19546
19547       case SetCounterFunction:
19548         CcTest::isolate()->SetCounterFunction(NULL);
19549         break;
19550
19551       case SetCreateHistogramFunction:
19552         CcTest::isolate()->SetCreateHistogramFunction(NULL);
19553         break;
19554
19555       case SetAddHistogramSampleFunction:
19556         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19557         break;
19558     }
19559     isolate->Exit();
19560     isolate->Dispose();
19561     result_ = true;
19562   }
19563
19564   bool result() { return result_; }
19565
19566  private:
19567   TestCase testCase_;
19568   bool result_;
19569 };
19570
19571
19572 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19573   InitDefaultIsolateThread thread(testCase);
19574   thread.Start();
19575   thread.Join();
19576   CHECK_EQ(thread.result(), true);
19577 }
19578
19579
19580 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19581   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19582 }
19583
19584
19585 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19586   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19587 }
19588
19589
19590 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19591   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19592 }
19593
19594
19595 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19596   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19597 }
19598
19599
19600 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19601   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19602 }
19603
19604
19605 TEST(StringCheckMultipleContexts) {
19606   const char* code =
19607       "(function() { return \"a\".charAt(0); })()";
19608
19609   {
19610     // Run the code twice in the first context to initialize the call IC.
19611     LocalContext context1;
19612     v8::HandleScope scope(context1->GetIsolate());
19613     ExpectString(code, "a");
19614     ExpectString(code, "a");
19615   }
19616
19617   {
19618     // Change the String.prototype in the second context and check
19619     // that the right function gets called.
19620     LocalContext context2;
19621     v8::HandleScope scope(context2->GetIsolate());
19622     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19623     ExpectString(code, "not a");
19624   }
19625 }
19626
19627
19628 TEST(NumberCheckMultipleContexts) {
19629   const char* code =
19630       "(function() { return (42).toString(); })()";
19631
19632   {
19633     // Run the code twice in the first context to initialize the call IC.
19634     LocalContext context1;
19635     v8::HandleScope scope(context1->GetIsolate());
19636     ExpectString(code, "42");
19637     ExpectString(code, "42");
19638   }
19639
19640   {
19641     // Change the Number.prototype in the second context and check
19642     // that the right function gets called.
19643     LocalContext context2;
19644     v8::HandleScope scope(context2->GetIsolate());
19645     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19646     ExpectString(code, "not 42");
19647   }
19648 }
19649
19650
19651 TEST(BooleanCheckMultipleContexts) {
19652   const char* code =
19653       "(function() { return true.toString(); })()";
19654
19655   {
19656     // Run the code twice in the first context to initialize the call IC.
19657     LocalContext context1;
19658     v8::HandleScope scope(context1->GetIsolate());
19659     ExpectString(code, "true");
19660     ExpectString(code, "true");
19661   }
19662
19663   {
19664     // Change the Boolean.prototype in the second context and check
19665     // that the right function gets called.
19666     LocalContext context2;
19667     v8::HandleScope scope(context2->GetIsolate());
19668     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19669     ExpectString(code, "");
19670   }
19671 }
19672
19673
19674 TEST(DontDeleteCellLoadIC) {
19675   const char* function_code =
19676       "function readCell() { while (true) { return cell; } }";
19677
19678   {
19679     // Run the code twice in the first context to initialize the load
19680     // IC for a don't delete cell.
19681     LocalContext context1;
19682     v8::HandleScope scope(context1->GetIsolate());
19683     CompileRun("var cell = \"first\";");
19684     ExpectBoolean("delete cell", false);
19685     CompileRun(function_code);
19686     ExpectString("readCell()", "first");
19687     ExpectString("readCell()", "first");
19688   }
19689
19690   {
19691     // Use a deletable cell in the second context.
19692     LocalContext context2;
19693     v8::HandleScope scope(context2->GetIsolate());
19694     CompileRun("cell = \"second\";");
19695     CompileRun(function_code);
19696     ExpectString("readCell()", "second");
19697     ExpectBoolean("delete cell", true);
19698     ExpectString("(function() {"
19699                  "  try {"
19700                  "    return readCell();"
19701                  "  } catch(e) {"
19702                  "    return e.toString();"
19703                  "  }"
19704                  "})()",
19705                  "ReferenceError: cell is not defined");
19706     CompileRun("cell = \"new_second\";");
19707     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19708     ExpectString("readCell()", "new_second");
19709     ExpectString("readCell()", "new_second");
19710   }
19711 }
19712
19713
19714 TEST(DontDeleteCellLoadICForceDelete) {
19715   const char* function_code =
19716       "function readCell() { while (true) { return cell; } }";
19717
19718   // Run the code twice to initialize the load IC for a don't delete
19719   // cell.
19720   LocalContext context;
19721   v8::HandleScope scope(context->GetIsolate());
19722   CompileRun("var cell = \"value\";");
19723   ExpectBoolean("delete cell", false);
19724   CompileRun(function_code);
19725   ExpectString("readCell()", "value");
19726   ExpectString("readCell()", "value");
19727
19728   // Delete the cell using the API and check the inlined code works
19729   // correctly.
19730   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19731   ExpectString("(function() {"
19732                "  try {"
19733                "    return readCell();"
19734                "  } catch(e) {"
19735                "    return e.toString();"
19736                "  }"
19737                "})()",
19738                "ReferenceError: cell is not defined");
19739 }
19740
19741
19742 TEST(DontDeleteCellLoadICAPI) {
19743   const char* function_code =
19744       "function readCell() { while (true) { return cell; } }";
19745
19746   // Run the code twice to initialize the load IC for a don't delete
19747   // cell created using the API.
19748   LocalContext context;
19749   v8::HandleScope scope(context->GetIsolate());
19750   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19751   ExpectBoolean("delete cell", false);
19752   CompileRun(function_code);
19753   ExpectString("readCell()", "value");
19754   ExpectString("readCell()", "value");
19755
19756   // Delete the cell using the API and check the inlined code works
19757   // correctly.
19758   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19759   ExpectString("(function() {"
19760                "  try {"
19761                "    return readCell();"
19762                "  } catch(e) {"
19763                "    return e.toString();"
19764                "  }"
19765                "})()",
19766                "ReferenceError: cell is not defined");
19767 }
19768
19769
19770 class Visitor42 : public v8::PersistentHandleVisitor {
19771  public:
19772   explicit Visitor42(v8::Persistent<v8::Object>* object)
19773       : counter_(0), object_(object) { }
19774
19775   virtual void VisitPersistentHandle(Persistent<Value>* value,
19776                                      uint16_t class_id) {
19777     if (class_id != 42) return;
19778     CHECK_EQ(42, value->WrapperClassId());
19779     v8::Isolate* isolate = CcTest::isolate();
19780     v8::HandleScope handle_scope(isolate);
19781     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19782     v8::Handle<v8::Value> object =
19783         v8::Local<v8::Object>::New(isolate, *object_);
19784     CHECK(handle->IsObject());
19785     CHECK_EQ(Handle<Object>::Cast(handle), object);
19786     ++counter_;
19787   }
19788
19789   int counter_;
19790   v8::Persistent<v8::Object>* object_;
19791 };
19792
19793
19794 TEST(PersistentHandleVisitor) {
19795   LocalContext context;
19796   v8::Isolate* isolate = context->GetIsolate();
19797   v8::HandleScope scope(isolate);
19798   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19799   CHECK_EQ(0, object.WrapperClassId());
19800   object.SetWrapperClassId(42);
19801   CHECK_EQ(42, object.WrapperClassId());
19802
19803   Visitor42 visitor(&object);
19804   v8::V8::VisitHandlesWithClassIds(&visitor);
19805   CHECK_EQ(1, visitor.counter_);
19806
19807   object.Reset();
19808 }
19809
19810
19811 TEST(WrapperClassId) {
19812   LocalContext context;
19813   v8::Isolate* isolate = context->GetIsolate();
19814   v8::HandleScope scope(isolate);
19815   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19816   CHECK_EQ(0, object.WrapperClassId());
19817   object.SetWrapperClassId(65535);
19818   CHECK_EQ(65535, object.WrapperClassId());
19819   object.Reset();
19820 }
19821
19822
19823 TEST(PersistentHandleInNewSpaceVisitor) {
19824   LocalContext context;
19825   v8::Isolate* isolate = context->GetIsolate();
19826   v8::HandleScope scope(isolate);
19827   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19828   CHECK_EQ(0, object1.WrapperClassId());
19829   object1.SetWrapperClassId(42);
19830   CHECK_EQ(42, object1.WrapperClassId());
19831
19832   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19833
19834   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19835   CHECK_EQ(0, object2.WrapperClassId());
19836   object2.SetWrapperClassId(42);
19837   CHECK_EQ(42, object2.WrapperClassId());
19838
19839   Visitor42 visitor(&object2);
19840   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19841   CHECK_EQ(1, visitor.counter_);
19842
19843   object1.Reset();
19844   object2.Reset();
19845 }
19846
19847
19848 TEST(RegExp) {
19849   LocalContext context;
19850   v8::HandleScope scope(context->GetIsolate());
19851
19852   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19853   CHECK(re->IsRegExp());
19854   CHECK(re->GetSource()->Equals(v8_str("foo")));
19855   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19856
19857   re = v8::RegExp::New(v8_str("bar"),
19858                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19859                                                       v8::RegExp::kGlobal));
19860   CHECK(re->IsRegExp());
19861   CHECK(re->GetSource()->Equals(v8_str("bar")));
19862   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19863            static_cast<int>(re->GetFlags()));
19864
19865   re = v8::RegExp::New(v8_str("baz"),
19866                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19867                                                       v8::RegExp::kMultiline));
19868   CHECK(re->IsRegExp());
19869   CHECK(re->GetSource()->Equals(v8_str("baz")));
19870   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19871            static_cast<int>(re->GetFlags()));
19872
19873   re = CompileRun("/quux/").As<v8::RegExp>();
19874   CHECK(re->IsRegExp());
19875   CHECK(re->GetSource()->Equals(v8_str("quux")));
19876   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19877
19878   re = CompileRun("/quux/gm").As<v8::RegExp>();
19879   CHECK(re->IsRegExp());
19880   CHECK(re->GetSource()->Equals(v8_str("quux")));
19881   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19882            static_cast<int>(re->GetFlags()));
19883
19884   // Override the RegExp constructor and check the API constructor
19885   // still works.
19886   CompileRun("RegExp = function() {}");
19887
19888   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19889   CHECK(re->IsRegExp());
19890   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19891   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19892
19893   re = v8::RegExp::New(v8_str("foobarbaz"),
19894                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19895                                                       v8::RegExp::kMultiline));
19896   CHECK(re->IsRegExp());
19897   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19898   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19899            static_cast<int>(re->GetFlags()));
19900
19901   context->Global()->Set(v8_str("re"), re);
19902   ExpectTrue("re.test('FoobarbaZ')");
19903
19904   // RegExps are objects on which you can set properties.
19905   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19906   v8::Handle<v8::Value> value(CompileRun("re.property"));
19907   CHECK_EQ(32, value->Int32Value());
19908
19909   v8::TryCatch try_catch;
19910   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19911   CHECK(re.IsEmpty());
19912   CHECK(try_catch.HasCaught());
19913   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19914   ExpectTrue("ex instanceof SyntaxError");
19915 }
19916
19917
19918 THREADED_TEST(Equals) {
19919   LocalContext localContext;
19920   v8::HandleScope handleScope(localContext->GetIsolate());
19921
19922   v8::Handle<v8::Object> globalProxy = localContext->Global();
19923   v8::Handle<Value> global = globalProxy->GetPrototype();
19924
19925   CHECK(global->StrictEquals(global));
19926   CHECK(!global->StrictEquals(globalProxy));
19927   CHECK(!globalProxy->StrictEquals(global));
19928   CHECK(globalProxy->StrictEquals(globalProxy));
19929
19930   CHECK(global->Equals(global));
19931   CHECK(!global->Equals(globalProxy));
19932   CHECK(!globalProxy->Equals(global));
19933   CHECK(globalProxy->Equals(globalProxy));
19934 }
19935
19936
19937 static void Getter(v8::Local<v8::String> property,
19938                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19939   info.GetReturnValue().Set(v8_str("42!"));
19940 }
19941
19942
19943 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19944   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19945   result->Set(0, v8_str("universalAnswer"));
19946   info.GetReturnValue().Set(result);
19947 }
19948
19949
19950 TEST(NamedEnumeratorAndForIn) {
19951   LocalContext context;
19952   v8::Isolate* isolate = context->GetIsolate();
19953   v8::HandleScope handle_scope(isolate);
19954   v8::Context::Scope context_scope(context.local());
19955
19956   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19957   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19958   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19959   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19960         "var result = []; for (var k in o) result.push(k); result"));
19961   CHECK_EQ(1, result->Length());
19962   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19963 }
19964
19965
19966 TEST(DefinePropertyPostDetach) {
19967   LocalContext context;
19968   v8::HandleScope scope(context->GetIsolate());
19969   v8::Handle<v8::Object> proxy = context->Global();
19970   v8::Handle<v8::Function> define_property =
19971       CompileRun("(function() {"
19972                  "  Object.defineProperty("
19973                  "    this,"
19974                  "    1,"
19975                  "    { configurable: true, enumerable: true, value: 3 });"
19976                  "})").As<Function>();
19977   context->DetachGlobal();
19978   define_property->Call(proxy, 0, NULL);
19979 }
19980
19981
19982 static void InstallContextId(v8::Handle<Context> context, int id) {
19983   Context::Scope scope(context);
19984   CompileRun("Object.prototype").As<Object>()->
19985       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19986 }
19987
19988
19989 static void CheckContextId(v8::Handle<Object> object, int expected) {
19990   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19991 }
19992
19993
19994 THREADED_TEST(CreationContext) {
19995   v8::Isolate* isolate = CcTest::isolate();
19996   HandleScope handle_scope(isolate);
19997   Handle<Context> context1 = Context::New(isolate);
19998   InstallContextId(context1, 1);
19999   Handle<Context> context2 = Context::New(isolate);
20000   InstallContextId(context2, 2);
20001   Handle<Context> context3 = Context::New(isolate);
20002   InstallContextId(context3, 3);
20003
20004   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20005
20006   Local<Object> object1;
20007   Local<Function> func1;
20008   {
20009     Context::Scope scope(context1);
20010     object1 = Object::New(isolate);
20011     func1 = tmpl->GetFunction();
20012   }
20013
20014   Local<Object> object2;
20015   Local<Function> func2;
20016   {
20017     Context::Scope scope(context2);
20018     object2 = Object::New(isolate);
20019     func2 = tmpl->GetFunction();
20020   }
20021
20022   Local<Object> instance1;
20023   Local<Object> instance2;
20024
20025   {
20026     Context::Scope scope(context3);
20027     instance1 = func1->NewInstance();
20028     instance2 = func2->NewInstance();
20029   }
20030
20031   CHECK(object1->CreationContext() == context1);
20032   CheckContextId(object1, 1);
20033   CHECK(func1->CreationContext() == context1);
20034   CheckContextId(func1, 1);
20035   CHECK(instance1->CreationContext() == context1);
20036   CheckContextId(instance1, 1);
20037   CHECK(object2->CreationContext() == context2);
20038   CheckContextId(object2, 2);
20039   CHECK(func2->CreationContext() == context2);
20040   CheckContextId(func2, 2);
20041   CHECK(instance2->CreationContext() == context2);
20042   CheckContextId(instance2, 2);
20043
20044   {
20045     Context::Scope scope(context1);
20046     CHECK(object1->CreationContext() == context1);
20047     CheckContextId(object1, 1);
20048     CHECK(func1->CreationContext() == context1);
20049     CheckContextId(func1, 1);
20050     CHECK(instance1->CreationContext() == context1);
20051     CheckContextId(instance1, 1);
20052     CHECK(object2->CreationContext() == context2);
20053     CheckContextId(object2, 2);
20054     CHECK(func2->CreationContext() == context2);
20055     CheckContextId(func2, 2);
20056     CHECK(instance2->CreationContext() == context2);
20057     CheckContextId(instance2, 2);
20058   }
20059
20060   {
20061     Context::Scope scope(context2);
20062     CHECK(object1->CreationContext() == context1);
20063     CheckContextId(object1, 1);
20064     CHECK(func1->CreationContext() == context1);
20065     CheckContextId(func1, 1);
20066     CHECK(instance1->CreationContext() == context1);
20067     CheckContextId(instance1, 1);
20068     CHECK(object2->CreationContext() == context2);
20069     CheckContextId(object2, 2);
20070     CHECK(func2->CreationContext() == context2);
20071     CheckContextId(func2, 2);
20072     CHECK(instance2->CreationContext() == context2);
20073     CheckContextId(instance2, 2);
20074   }
20075 }
20076
20077
20078 THREADED_TEST(CreationContextOfJsFunction) {
20079   HandleScope handle_scope(CcTest::isolate());
20080   Handle<Context> context = Context::New(CcTest::isolate());
20081   InstallContextId(context, 1);
20082
20083   Local<Object> function;
20084   {
20085     Context::Scope scope(context);
20086     function = CompileRun("function foo() {}; foo").As<Object>();
20087   }
20088
20089   CHECK(function->CreationContext() == context);
20090   CheckContextId(function, 1);
20091 }
20092
20093
20094 void HasOwnPropertyIndexedPropertyGetter(
20095     uint32_t index,
20096     const v8::PropertyCallbackInfo<v8::Value>& info) {
20097   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20098 }
20099
20100
20101 void HasOwnPropertyNamedPropertyGetter(
20102     Local<String> property,
20103     const v8::PropertyCallbackInfo<v8::Value>& info) {
20104   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20105 }
20106
20107
20108 void HasOwnPropertyIndexedPropertyQuery(
20109     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20110   if (index == 42) info.GetReturnValue().Set(1);
20111 }
20112
20113
20114 void HasOwnPropertyNamedPropertyQuery(
20115     Local<String> property,
20116     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20117   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20118 }
20119
20120
20121 void HasOwnPropertyNamedPropertyQuery2(
20122     Local<String> property,
20123     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20124   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20125 }
20126
20127
20128 void HasOwnPropertyAccessorGetter(
20129     Local<String> property,
20130     const v8::PropertyCallbackInfo<v8::Value>& info) {
20131   info.GetReturnValue().Set(v8_str("yes"));
20132 }
20133
20134
20135 TEST(HasOwnProperty) {
20136   LocalContext env;
20137   v8::Isolate* isolate = env->GetIsolate();
20138   v8::HandleScope scope(isolate);
20139   { // Check normal properties and defined getters.
20140     Handle<Value> value = CompileRun(
20141         "function Foo() {"
20142         "    this.foo = 11;"
20143         "    this.__defineGetter__('baz', function() { return 1; });"
20144         "};"
20145         "function Bar() { "
20146         "    this.bar = 13;"
20147         "    this.__defineGetter__('bla', function() { return 2; });"
20148         "};"
20149         "Bar.prototype = new Foo();"
20150         "new Bar();");
20151     CHECK(value->IsObject());
20152     Handle<Object> object = value->ToObject();
20153     CHECK(object->Has(v8_str("foo")));
20154     CHECK(!object->HasOwnProperty(v8_str("foo")));
20155     CHECK(object->HasOwnProperty(v8_str("bar")));
20156     CHECK(object->Has(v8_str("baz")));
20157     CHECK(!object->HasOwnProperty(v8_str("baz")));
20158     CHECK(object->HasOwnProperty(v8_str("bla")));
20159   }
20160   { // Check named getter interceptors.
20161     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20162     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20163     Handle<Object> instance = templ->NewInstance();
20164     CHECK(!instance->HasOwnProperty(v8_str("42")));
20165     CHECK(instance->HasOwnProperty(v8_str("foo")));
20166     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20167   }
20168   { // Check indexed getter interceptors.
20169     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20170     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20171     Handle<Object> instance = templ->NewInstance();
20172     CHECK(instance->HasOwnProperty(v8_str("42")));
20173     CHECK(!instance->HasOwnProperty(v8_str("43")));
20174     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20175   }
20176   { // Check named query interceptors.
20177     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20178     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20179     Handle<Object> instance = templ->NewInstance();
20180     CHECK(instance->HasOwnProperty(v8_str("foo")));
20181     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20182   }
20183   { // Check indexed query interceptors.
20184     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20185     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20186     Handle<Object> instance = templ->NewInstance();
20187     CHECK(instance->HasOwnProperty(v8_str("42")));
20188     CHECK(!instance->HasOwnProperty(v8_str("41")));
20189   }
20190   { // Check callbacks.
20191     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20192     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20193     Handle<Object> instance = templ->NewInstance();
20194     CHECK(instance->HasOwnProperty(v8_str("foo")));
20195     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20196   }
20197   { // Check that query wins on disagreement.
20198     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20199     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20200                                    0,
20201                                    HasOwnPropertyNamedPropertyQuery2);
20202     Handle<Object> instance = templ->NewInstance();
20203     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20204     CHECK(instance->HasOwnProperty(v8_str("bar")));
20205   }
20206 }
20207
20208
20209 TEST(IndexedInterceptorWithStringProto) {
20210   v8::Isolate* isolate = CcTest::isolate();
20211   v8::HandleScope scope(isolate);
20212   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20213   templ->SetIndexedPropertyHandler(NULL,
20214                                    NULL,
20215                                    HasOwnPropertyIndexedPropertyQuery);
20216   LocalContext context;
20217   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20218   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20219   // These should be intercepted.
20220   CHECK(CompileRun("42 in obj")->BooleanValue());
20221   CHECK(CompileRun("'42' in obj")->BooleanValue());
20222   // These should fall through to the String prototype.
20223   CHECK(CompileRun("0 in obj")->BooleanValue());
20224   CHECK(CompileRun("'0' in obj")->BooleanValue());
20225   // And these should both fail.
20226   CHECK(!CompileRun("32 in obj")->BooleanValue());
20227   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20228 }
20229
20230
20231 void CheckCodeGenerationAllowed() {
20232   Handle<Value> result = CompileRun("eval('42')");
20233   CHECK_EQ(42, result->Int32Value());
20234   result = CompileRun("(function(e) { return e('42'); })(eval)");
20235   CHECK_EQ(42, result->Int32Value());
20236   result = CompileRun("var f = new Function('return 42'); f()");
20237   CHECK_EQ(42, result->Int32Value());
20238 }
20239
20240
20241 void CheckCodeGenerationDisallowed() {
20242   TryCatch try_catch;
20243
20244   Handle<Value> result = CompileRun("eval('42')");
20245   CHECK(result.IsEmpty());
20246   CHECK(try_catch.HasCaught());
20247   try_catch.Reset();
20248
20249   result = CompileRun("(function(e) { return e('42'); })(eval)");
20250   CHECK(result.IsEmpty());
20251   CHECK(try_catch.HasCaught());
20252   try_catch.Reset();
20253
20254   result = CompileRun("var f = new Function('return 42'); f()");
20255   CHECK(result.IsEmpty());
20256   CHECK(try_catch.HasCaught());
20257 }
20258
20259
20260 bool CodeGenerationAllowed(Local<Context> context) {
20261   ApiTestFuzzer::Fuzz();
20262   return true;
20263 }
20264
20265
20266 bool CodeGenerationDisallowed(Local<Context> context) {
20267   ApiTestFuzzer::Fuzz();
20268   return false;
20269 }
20270
20271
20272 THREADED_TEST(AllowCodeGenFromStrings) {
20273   LocalContext context;
20274   v8::HandleScope scope(context->GetIsolate());
20275
20276   // eval and the Function constructor allowed by default.
20277   CHECK(context->IsCodeGenerationFromStringsAllowed());
20278   CheckCodeGenerationAllowed();
20279
20280   // Disallow eval and the Function constructor.
20281   context->AllowCodeGenerationFromStrings(false);
20282   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20283   CheckCodeGenerationDisallowed();
20284
20285   // Allow again.
20286   context->AllowCodeGenerationFromStrings(true);
20287   CheckCodeGenerationAllowed();
20288
20289   // Disallow but setting a global callback that will allow the calls.
20290   context->AllowCodeGenerationFromStrings(false);
20291   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20292   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20293   CheckCodeGenerationAllowed();
20294
20295   // Set a callback that disallows the code generation.
20296   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20297   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20298   CheckCodeGenerationDisallowed();
20299 }
20300
20301
20302 TEST(SetErrorMessageForCodeGenFromStrings) {
20303   LocalContext context;
20304   v8::HandleScope scope(context->GetIsolate());
20305   TryCatch try_catch;
20306
20307   Handle<String> message = v8_str("Message") ;
20308   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20309   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20310   context->AllowCodeGenerationFromStrings(false);
20311   context->SetErrorMessageForCodeGenerationFromStrings(message);
20312   Handle<Value> result = CompileRun("eval('42')");
20313   CHECK(result.IsEmpty());
20314   CHECK(try_catch.HasCaught());
20315   Handle<String> actual_message = try_catch.Message()->Get();
20316   CHECK(expected_message->Equals(actual_message));
20317 }
20318
20319
20320 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20321 }
20322
20323
20324 THREADED_TEST(CallAPIFunctionOnNonObject) {
20325   LocalContext context;
20326   v8::Isolate* isolate = context->GetIsolate();
20327   v8::HandleScope scope(isolate);
20328   Handle<FunctionTemplate> templ =
20329       v8::FunctionTemplate::New(isolate, NonObjectThis);
20330   Handle<Function> function = templ->GetFunction();
20331   context->Global()->Set(v8_str("f"), function);
20332   TryCatch try_catch;
20333   CompileRun("f.call(2)");
20334 }
20335
20336
20337 // Regression test for issue 1470.
20338 THREADED_TEST(ReadOnlyIndexedProperties) {
20339   v8::Isolate* isolate = CcTest::isolate();
20340   v8::HandleScope scope(isolate);
20341   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20342
20343   LocalContext context;
20344   Local<v8::Object> obj = templ->NewInstance();
20345   context->Global()->Set(v8_str("obj"), obj);
20346   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20347   obj->Set(v8_str("1"), v8_str("foobar"));
20348   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20349   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20350   obj->Set(v8_num(2), v8_str("foobar"));
20351   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20352
20353   // Test non-smi case.
20354   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20355   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20356   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20357 }
20358
20359
20360 THREADED_TEST(Regress1516) {
20361   LocalContext context;
20362   v8::HandleScope scope(context->GetIsolate());
20363
20364   { v8::HandleScope temp_scope(context->GetIsolate());
20365     CompileRun("({'a': 0})");
20366   }
20367
20368   int elements;
20369   { i::MapCache* map_cache =
20370         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20371     elements = map_cache->NumberOfElements();
20372     CHECK_LE(1, elements);
20373   }
20374
20375   CcTest::heap()->CollectAllGarbage(
20376       i::Heap::kAbortIncrementalMarkingMask);
20377   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20378     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20379       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20380       CHECK_GT(elements, map_cache->NumberOfElements());
20381     }
20382   }
20383 }
20384
20385
20386 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20387                                                 Local<Value> name,
20388                                                 v8::AccessType type,
20389                                                 Local<Value> data) {
20390   // Only block read access to __proto__.
20391   if (type == v8::ACCESS_GET &&
20392       name->IsString() &&
20393       name->ToString()->Length() == 9 &&
20394       name->ToString()->Utf8Length() == 9) {
20395     char buffer[10];
20396     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20397     return strncmp(buffer, "__proto__", 9) != 0;
20398   }
20399
20400   return true;
20401 }
20402
20403
20404 THREADED_TEST(Regress93759) {
20405   v8::Isolate* isolate = CcTest::isolate();
20406   HandleScope scope(isolate);
20407
20408   // Template for object with security check.
20409   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20410   // We don't do indexing, so any callback can be used for that.
20411   no_proto_template->SetAccessCheckCallbacks(
20412       BlockProtoNamedSecurityTestCallback,
20413       IndexedSecurityTestCallback);
20414
20415   // Templates for objects with hidden prototypes and possibly security check.
20416   Local<FunctionTemplate> hidden_proto_template =
20417       v8::FunctionTemplate::New(isolate);
20418   hidden_proto_template->SetHiddenPrototype(true);
20419
20420   Local<FunctionTemplate> protected_hidden_proto_template =
20421       v8::FunctionTemplate::New(isolate);
20422   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20423       BlockProtoNamedSecurityTestCallback,
20424       IndexedSecurityTestCallback);
20425   protected_hidden_proto_template->SetHiddenPrototype(true);
20426
20427   // Context for "foreign" objects used in test.
20428   Local<Context> context = v8::Context::New(isolate);
20429   context->Enter();
20430
20431   // Plain object, no security check.
20432   Local<Object> simple_object = Object::New(isolate);
20433
20434   // Object with explicit security check.
20435   Local<Object> protected_object =
20436       no_proto_template->NewInstance();
20437
20438   // JSGlobalProxy object, always have security check.
20439   Local<Object> proxy_object =
20440       context->Global();
20441
20442   // Global object, the  prototype of proxy_object. No security checks.
20443   Local<Object> global_object =
20444       proxy_object->GetPrototype()->ToObject();
20445
20446   // Hidden prototype without security check.
20447   Local<Object> hidden_prototype =
20448       hidden_proto_template->GetFunction()->NewInstance();
20449   Local<Object> object_with_hidden =
20450     Object::New(isolate);
20451   object_with_hidden->SetPrototype(hidden_prototype);
20452
20453   // Hidden prototype with security check on the hidden prototype.
20454   Local<Object> protected_hidden_prototype =
20455       protected_hidden_proto_template->GetFunction()->NewInstance();
20456   Local<Object> object_with_protected_hidden =
20457     Object::New(isolate);
20458   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20459
20460   context->Exit();
20461
20462   // Template for object for second context. Values to test are put on it as
20463   // properties.
20464   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20465   global_template->Set(v8_str("simple"), simple_object);
20466   global_template->Set(v8_str("protected"), protected_object);
20467   global_template->Set(v8_str("global"), global_object);
20468   global_template->Set(v8_str("proxy"), proxy_object);
20469   global_template->Set(v8_str("hidden"), object_with_hidden);
20470   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20471
20472   LocalContext context2(NULL, global_template);
20473
20474   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20475   CHECK(result1->Equals(simple_object->GetPrototype()));
20476
20477   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20478   CHECK(result2->Equals(Undefined(isolate)));
20479
20480   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20481   CHECK(result3->Equals(global_object->GetPrototype()));
20482
20483   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20484   CHECK(result4->Equals(Undefined(isolate)));
20485
20486   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20487   CHECK(result5->Equals(
20488       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20489
20490   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20491   CHECK(result6->Equals(Undefined(isolate)));
20492 }
20493
20494
20495 THREADED_TEST(Regress125988) {
20496   v8::HandleScope scope(CcTest::isolate());
20497   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20498   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20499   LocalContext env;
20500   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20501   CompileRun("var a = new Object();"
20502              "var b = new Intercept();"
20503              "var c = new Object();"
20504              "c.__proto__ = b;"
20505              "b.__proto__ = a;"
20506              "a.x = 23;"
20507              "for (var i = 0; i < 3; i++) c.x;");
20508   ExpectBoolean("c.hasOwnProperty('x')", false);
20509   ExpectInt32("c.x", 23);
20510   CompileRun("a.y = 42;"
20511              "for (var i = 0; i < 3; i++) c.x;");
20512   ExpectBoolean("c.hasOwnProperty('x')", false);
20513   ExpectInt32("c.x", 23);
20514   ExpectBoolean("c.hasOwnProperty('y')", false);
20515   ExpectInt32("c.y", 42);
20516 }
20517
20518
20519 static void TestReceiver(Local<Value> expected_result,
20520                          Local<Value> expected_receiver,
20521                          const char* code) {
20522   Local<Value> result = CompileRun(code);
20523   CHECK(result->IsObject());
20524   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20525   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20526 }
20527
20528
20529 THREADED_TEST(ForeignFunctionReceiver) {
20530   v8::Isolate* isolate = CcTest::isolate();
20531   HandleScope scope(isolate);
20532
20533   // Create two contexts with different "id" properties ('i' and 'o').
20534   // Call a function both from its own context and from a the foreign
20535   // context, and see what "this" is bound to (returning both "this"
20536   // and "this.id" for comparison).
20537
20538   Local<Context> foreign_context = v8::Context::New(isolate);
20539   foreign_context->Enter();
20540   Local<Value> foreign_function =
20541     CompileRun("function func() { return { 0: this.id, "
20542                "                           1: this, "
20543                "                           toString: function() { "
20544                "                               return this[0];"
20545                "                           }"
20546                "                         };"
20547                "}"
20548                "var id = 'i';"
20549                "func;");
20550   CHECK(foreign_function->IsFunction());
20551   foreign_context->Exit();
20552
20553   LocalContext context;
20554
20555   Local<String> password = v8_str("Password");
20556   // Don't get hit by security checks when accessing foreign_context's
20557   // global receiver (aka. global proxy).
20558   context->SetSecurityToken(password);
20559   foreign_context->SetSecurityToken(password);
20560
20561   Local<String> i = v8_str("i");
20562   Local<String> o = v8_str("o");
20563   Local<String> id = v8_str("id");
20564
20565   CompileRun("function ownfunc() { return { 0: this.id, "
20566              "                              1: this, "
20567              "                              toString: function() { "
20568              "                                  return this[0];"
20569              "                              }"
20570              "                             };"
20571              "}"
20572              "var id = 'o';"
20573              "ownfunc");
20574   context->Global()->Set(v8_str("func"), foreign_function);
20575
20576   // Sanity check the contexts.
20577   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20578   CHECK(o->Equals(context->Global()->Get(id)));
20579
20580   // Checking local function's receiver.
20581   // Calling function using its call/apply methods.
20582   TestReceiver(o, context->Global(), "ownfunc.call()");
20583   TestReceiver(o, context->Global(), "ownfunc.apply()");
20584   // Making calls through built-in functions.
20585   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20586   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20587   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20588   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20589   // Calling with environment record as base.
20590   TestReceiver(o, context->Global(), "ownfunc()");
20591   // Calling with no base.
20592   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20593
20594   // Checking foreign function return value.
20595   // Calling function using its call/apply methods.
20596   TestReceiver(i, foreign_context->Global(), "func.call()");
20597   TestReceiver(i, foreign_context->Global(), "func.apply()");
20598   // Calling function using another context's call/apply methods.
20599   TestReceiver(i, foreign_context->Global(),
20600                "Function.prototype.call.call(func)");
20601   TestReceiver(i, foreign_context->Global(),
20602                "Function.prototype.call.apply(func)");
20603   TestReceiver(i, foreign_context->Global(),
20604                "Function.prototype.apply.call(func)");
20605   TestReceiver(i, foreign_context->Global(),
20606                "Function.prototype.apply.apply(func)");
20607   // Making calls through built-in functions.
20608   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20609   // ToString(func()) is func()[0], i.e., the returned this.id.
20610   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20611   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20612   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20613
20614   // Calling with environment record as base.
20615   TestReceiver(i, foreign_context->Global(), "func()");
20616   // Calling with no base.
20617   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20618 }
20619
20620
20621 uint8_t callback_fired = 0;
20622
20623
20624 void CallCompletedCallback1() {
20625   i::OS::Print("Firing callback 1.\n");
20626   callback_fired ^= 1;  // Toggle first bit.
20627 }
20628
20629
20630 void CallCompletedCallback2() {
20631   i::OS::Print("Firing callback 2.\n");
20632   callback_fired ^= 2;  // Toggle second bit.
20633 }
20634
20635
20636 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20637   int32_t level = args[0]->Int32Value();
20638   if (level < 3) {
20639     level++;
20640     i::OS::Print("Entering recursion level %d.\n", level);
20641     char script[64];
20642     i::Vector<char> script_vector(script, sizeof(script));
20643     i::SNPrintF(script_vector, "recursion(%d)", level);
20644     CompileRun(script_vector.start());
20645     i::OS::Print("Leaving recursion level %d.\n", level);
20646     CHECK_EQ(0, callback_fired);
20647   } else {
20648     i::OS::Print("Recursion ends.\n");
20649     CHECK_EQ(0, callback_fired);
20650   }
20651 }
20652
20653
20654 TEST(CallCompletedCallback) {
20655   LocalContext env;
20656   v8::HandleScope scope(env->GetIsolate());
20657   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20658       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20659   env->Global()->Set(v8_str("recursion"),
20660                      recursive_runtime->GetFunction());
20661   // Adding the same callback a second time has no effect.
20662   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20663   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20664   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20665   i::OS::Print("--- Script (1) ---\n");
20666   Local<Script> script = v8::Script::Compile(
20667       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20668   script->Run();
20669   CHECK_EQ(3, callback_fired);
20670
20671   i::OS::Print("\n--- Script (2) ---\n");
20672   callback_fired = 0;
20673   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20674   script->Run();
20675   CHECK_EQ(2, callback_fired);
20676
20677   i::OS::Print("\n--- Function ---\n");
20678   callback_fired = 0;
20679   Local<Function> recursive_function =
20680       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20681   v8::Handle<Value> args[] = { v8_num(0) };
20682   recursive_function->Call(env->Global(), 1, args);
20683   CHECK_EQ(2, callback_fired);
20684 }
20685
20686
20687 void CallCompletedCallbackNoException() {
20688   v8::HandleScope scope(CcTest::isolate());
20689   CompileRun("1+1;");
20690 }
20691
20692
20693 void CallCompletedCallbackException() {
20694   v8::HandleScope scope(CcTest::isolate());
20695   CompileRun("throw 'second exception';");
20696 }
20697
20698
20699 TEST(CallCompletedCallbackOneException) {
20700   LocalContext env;
20701   v8::HandleScope scope(env->GetIsolate());
20702   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20703   CompileRun("throw 'exception';");
20704 }
20705
20706
20707 TEST(CallCompletedCallbackTwoExceptions) {
20708   LocalContext env;
20709   v8::HandleScope scope(env->GetIsolate());
20710   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20711   CompileRun("throw 'first exception';");
20712 }
20713
20714
20715 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20716   v8::HandleScope scope(info.GetIsolate());
20717   CompileRun("ext1Calls++;");
20718 }
20719
20720
20721 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20722   v8::HandleScope scope(info.GetIsolate());
20723   CompileRun("ext2Calls++;");
20724 }
20725
20726
20727 void* g_passed_to_three = NULL;
20728
20729
20730 static void MicrotaskThree(void* data) {
20731   g_passed_to_three = data;
20732 }
20733
20734
20735 TEST(EnqueueMicrotask) {
20736   LocalContext env;
20737   v8::HandleScope scope(env->GetIsolate());
20738   CompileRun(
20739       "var ext1Calls = 0;"
20740       "var ext2Calls = 0;");
20741   CompileRun("1+1;");
20742   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20743   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20744
20745   env->GetIsolate()->EnqueueMicrotask(
20746       Function::New(env->GetIsolate(), MicrotaskOne));
20747   CompileRun("1+1;");
20748   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20749   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20750
20751   env->GetIsolate()->EnqueueMicrotask(
20752       Function::New(env->GetIsolate(), MicrotaskOne));
20753   env->GetIsolate()->EnqueueMicrotask(
20754       Function::New(env->GetIsolate(), MicrotaskTwo));
20755   CompileRun("1+1;");
20756   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20757   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20758
20759   env->GetIsolate()->EnqueueMicrotask(
20760       Function::New(env->GetIsolate(), MicrotaskTwo));
20761   CompileRun("1+1;");
20762   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20763   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20764
20765   CompileRun("1+1;");
20766   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20767   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20768
20769   g_passed_to_three = NULL;
20770   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20771   CompileRun("1+1;");
20772   CHECK_EQ(NULL, g_passed_to_three);
20773   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20774   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20775
20776   int dummy;
20777   env->GetIsolate()->EnqueueMicrotask(
20778       Function::New(env->GetIsolate(), MicrotaskOne));
20779   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20780   env->GetIsolate()->EnqueueMicrotask(
20781       Function::New(env->GetIsolate(), MicrotaskTwo));
20782   CompileRun("1+1;");
20783   CHECK_EQ(&dummy, g_passed_to_three);
20784   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20785   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20786   g_passed_to_three = NULL;
20787 }
20788
20789
20790 static void MicrotaskExceptionOne(
20791     const v8::FunctionCallbackInfo<Value>& info) {
20792   v8::HandleScope scope(info.GetIsolate());
20793   CompileRun("exception1Calls++;");
20794   info.GetIsolate()->ThrowException(
20795       v8::Exception::Error(v8_str("first")));
20796 }
20797
20798
20799 static void MicrotaskExceptionTwo(
20800     const v8::FunctionCallbackInfo<Value>& info) {
20801   v8::HandleScope scope(info.GetIsolate());
20802   CompileRun("exception2Calls++;");
20803   info.GetIsolate()->ThrowException(
20804       v8::Exception::Error(v8_str("second")));
20805 }
20806
20807
20808 TEST(RunMicrotasksIgnoresThrownExceptions) {
20809   LocalContext env;
20810   v8::Isolate* isolate = env->GetIsolate();
20811   v8::HandleScope scope(isolate);
20812   CompileRun(
20813       "var exception1Calls = 0;"
20814       "var exception2Calls = 0;");
20815   isolate->EnqueueMicrotask(
20816       Function::New(isolate, MicrotaskExceptionOne));
20817   isolate->EnqueueMicrotask(
20818       Function::New(isolate, MicrotaskExceptionTwo));
20819   TryCatch try_catch;
20820   CompileRun("1+1;");
20821   CHECK(!try_catch.HasCaught());
20822   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20823   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20824 }
20825
20826
20827 TEST(SetAutorunMicrotasks) {
20828   LocalContext env;
20829   v8::HandleScope scope(env->GetIsolate());
20830   CompileRun(
20831       "var ext1Calls = 0;"
20832       "var ext2Calls = 0;");
20833   CompileRun("1+1;");
20834   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20835   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20836
20837   env->GetIsolate()->EnqueueMicrotask(
20838       Function::New(env->GetIsolate(), MicrotaskOne));
20839   CompileRun("1+1;");
20840   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20841   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20842
20843   env->GetIsolate()->SetAutorunMicrotasks(false);
20844   env->GetIsolate()->EnqueueMicrotask(
20845       Function::New(env->GetIsolate(), MicrotaskOne));
20846   env->GetIsolate()->EnqueueMicrotask(
20847       Function::New(env->GetIsolate(), MicrotaskTwo));
20848   CompileRun("1+1;");
20849   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20850   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20851
20852   env->GetIsolate()->RunMicrotasks();
20853   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20854   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20855
20856   env->GetIsolate()->EnqueueMicrotask(
20857       Function::New(env->GetIsolate(), MicrotaskTwo));
20858   CompileRun("1+1;");
20859   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20860   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20861
20862   env->GetIsolate()->RunMicrotasks();
20863   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20864   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20865
20866   env->GetIsolate()->SetAutorunMicrotasks(true);
20867   env->GetIsolate()->EnqueueMicrotask(
20868       Function::New(env->GetIsolate(), MicrotaskTwo));
20869   CompileRun("1+1;");
20870   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20871   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20872
20873   env->GetIsolate()->EnqueueMicrotask(
20874       Function::New(env->GetIsolate(), MicrotaskTwo));
20875   {
20876     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20877     CompileRun("1+1;");
20878     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20879     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20880   }
20881
20882   CompileRun("1+1;");
20883   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20884   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20885 }
20886
20887
20888 TEST(RunMicrotasksWithoutEnteringContext) {
20889   v8::Isolate* isolate = CcTest::isolate();
20890   HandleScope handle_scope(isolate);
20891   isolate->SetAutorunMicrotasks(false);
20892   Handle<Context> context = Context::New(isolate);
20893   {
20894     Context::Scope context_scope(context);
20895     CompileRun("var ext1Calls = 0;");
20896     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
20897   }
20898   isolate->RunMicrotasks();
20899   {
20900     Context::Scope context_scope(context);
20901     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20902   }
20903   isolate->SetAutorunMicrotasks(true);
20904 }
20905
20906
20907 #ifdef DEBUG
20908 static int probes_counter = 0;
20909 static int misses_counter = 0;
20910 static int updates_counter = 0;
20911
20912
20913 static int* LookupCounter(const char* name) {
20914   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20915     return &probes_counter;
20916   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20917     return &misses_counter;
20918   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20919     return &updates_counter;
20920   }
20921   return NULL;
20922 }
20923
20924
20925 static const char* kMegamorphicTestProgram =
20926     "function ClassA() { };"
20927     "function ClassB() { };"
20928     "ClassA.prototype.foo = function() { };"
20929     "ClassB.prototype.foo = function() { };"
20930     "function fooify(obj) { obj.foo(); };"
20931     "var a = new ClassA();"
20932     "var b = new ClassB();"
20933     "for (var i = 0; i < 10000; i++) {"
20934     "  fooify(a);"
20935     "  fooify(b);"
20936     "}";
20937 #endif
20938
20939
20940 static void StubCacheHelper(bool primary) {
20941 #ifdef DEBUG
20942   i::FLAG_native_code_counters = true;
20943   if (primary) {
20944     i::FLAG_test_primary_stub_cache = true;
20945   } else {
20946     i::FLAG_test_secondary_stub_cache = true;
20947   }
20948   i::FLAG_crankshaft = false;
20949   LocalContext env;
20950   env->GetIsolate()->SetCounterFunction(LookupCounter);
20951   v8::HandleScope scope(env->GetIsolate());
20952   int initial_probes = probes_counter;
20953   int initial_misses = misses_counter;
20954   int initial_updates = updates_counter;
20955   CompileRun(kMegamorphicTestProgram);
20956   int probes = probes_counter - initial_probes;
20957   int misses = misses_counter - initial_misses;
20958   int updates = updates_counter - initial_updates;
20959   CHECK_LT(updates, 10);
20960   CHECK_LT(misses, 10);
20961   // TODO(verwaest): Update this test to overflow the degree of polymorphism
20962   // before megamorphism. The number of probes will only work once we teach the
20963   // serializer to embed references to counters in the stubs, given that the
20964   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20965   CHECK_GE(probes, 0);
20966 #endif
20967 }
20968
20969
20970 TEST(SecondaryStubCache) {
20971   StubCacheHelper(true);
20972 }
20973
20974
20975 TEST(PrimaryStubCache) {
20976   StubCacheHelper(false);
20977 }
20978
20979
20980 #ifdef DEBUG
20981 static int cow_arrays_created_runtime = 0;
20982
20983
20984 static int* LookupCounterCOWArrays(const char* name) {
20985   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20986     return &cow_arrays_created_runtime;
20987   }
20988   return NULL;
20989 }
20990 #endif
20991
20992
20993 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20994 #ifdef DEBUG
20995   i::FLAG_native_code_counters = true;
20996   LocalContext env;
20997   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
20998   v8::HandleScope scope(env->GetIsolate());
20999   int initial_cow_arrays = cow_arrays_created_runtime;
21000   CompileRun("var o = [1, 2, 3];");
21001   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21002   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21003   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21004   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21005   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21006 #endif
21007 }
21008
21009
21010 TEST(StaticGetters) {
21011   LocalContext context;
21012   i::Factory* factory = CcTest::i_isolate()->factory();
21013   v8::Isolate* isolate = CcTest::isolate();
21014   v8::HandleScope scope(isolate);
21015   i::Handle<i::Object> undefined_value = factory->undefined_value();
21016   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21017   i::Handle<i::Object> null_value = factory->null_value();
21018   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21019   i::Handle<i::Object> true_value = factory->true_value();
21020   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21021   i::Handle<i::Object> false_value = factory->false_value();
21022   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21023 }
21024
21025
21026 UNINITIALIZED_TEST(IsolateEmbedderData) {
21027   CcTest::DisableAutomaticDispose();
21028   v8::Isolate* isolate = v8::Isolate::New();
21029   isolate->Enter();
21030   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21031   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21032     CHECK_EQ(NULL, isolate->GetData(slot));
21033     CHECK_EQ(NULL, i_isolate->GetData(slot));
21034   }
21035   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21036     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21037     isolate->SetData(slot, data);
21038   }
21039   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21040     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21041     CHECK_EQ(data, isolate->GetData(slot));
21042     CHECK_EQ(data, i_isolate->GetData(slot));
21043   }
21044   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21045     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21046     isolate->SetData(slot, data);
21047   }
21048   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21049     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21050     CHECK_EQ(data, isolate->GetData(slot));
21051     CHECK_EQ(data, i_isolate->GetData(slot));
21052   }
21053   isolate->Exit();
21054   isolate->Dispose();
21055 }
21056
21057
21058 TEST(StringEmpty) {
21059   LocalContext context;
21060   i::Factory* factory = CcTest::i_isolate()->factory();
21061   v8::Isolate* isolate = CcTest::isolate();
21062   v8::HandleScope scope(isolate);
21063   i::Handle<i::Object> empty_string = factory->empty_string();
21064   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21065 }
21066
21067
21068 static int instance_checked_getter_count = 0;
21069 static void InstanceCheckedGetter(
21070     Local<String> name,
21071     const v8::PropertyCallbackInfo<v8::Value>& info) {
21072   CHECK_EQ(name, v8_str("foo"));
21073   instance_checked_getter_count++;
21074   info.GetReturnValue().Set(v8_num(11));
21075 }
21076
21077
21078 static int instance_checked_setter_count = 0;
21079 static void InstanceCheckedSetter(Local<String> name,
21080                       Local<Value> value,
21081                       const v8::PropertyCallbackInfo<void>& info) {
21082   CHECK_EQ(name, v8_str("foo"));
21083   CHECK_EQ(value, v8_num(23));
21084   instance_checked_setter_count++;
21085 }
21086
21087
21088 static void CheckInstanceCheckedResult(int getters,
21089                                        int setters,
21090                                        bool expects_callbacks,
21091                                        TryCatch* try_catch) {
21092   if (expects_callbacks) {
21093     CHECK(!try_catch->HasCaught());
21094     CHECK_EQ(getters, instance_checked_getter_count);
21095     CHECK_EQ(setters, instance_checked_setter_count);
21096   } else {
21097     CHECK(try_catch->HasCaught());
21098     CHECK_EQ(0, instance_checked_getter_count);
21099     CHECK_EQ(0, instance_checked_setter_count);
21100   }
21101   try_catch->Reset();
21102 }
21103
21104
21105 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21106   instance_checked_getter_count = 0;
21107   instance_checked_setter_count = 0;
21108   TryCatch try_catch;
21109
21110   // Test path through generic runtime code.
21111   CompileRun("obj.foo");
21112   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21113   CompileRun("obj.foo = 23");
21114   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21115
21116   // Test path through generated LoadIC and StoredIC.
21117   CompileRun("function test_get(o) { o.foo; }"
21118              "test_get(obj);");
21119   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21120   CompileRun("test_get(obj);");
21121   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21122   CompileRun("test_get(obj);");
21123   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21124   CompileRun("function test_set(o) { o.foo = 23; }"
21125              "test_set(obj);");
21126   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21127   CompileRun("test_set(obj);");
21128   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21129   CompileRun("test_set(obj);");
21130   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21131
21132   // Test path through optimized code.
21133   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21134              "test_get(obj);");
21135   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21136   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21137              "test_set(obj);");
21138   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21139
21140   // Cleanup so that closures start out fresh in next check.
21141   CompileRun("%DeoptimizeFunction(test_get);"
21142              "%ClearFunctionTypeFeedback(test_get);"
21143              "%DeoptimizeFunction(test_set);"
21144              "%ClearFunctionTypeFeedback(test_set);");
21145 }
21146
21147
21148 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21149   v8::internal::FLAG_allow_natives_syntax = true;
21150   LocalContext context;
21151   v8::HandleScope scope(context->GetIsolate());
21152
21153   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21154   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21155   inst->SetAccessor(v8_str("foo"),
21156                     InstanceCheckedGetter, InstanceCheckedSetter,
21157                     Handle<Value>(),
21158                     v8::DEFAULT,
21159                     v8::None,
21160                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21161   context->Global()->Set(v8_str("f"), templ->GetFunction());
21162
21163   printf("Testing positive ...\n");
21164   CompileRun("var obj = new f();");
21165   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21166   CheckInstanceCheckedAccessors(true);
21167
21168   printf("Testing negative ...\n");
21169   CompileRun("var obj = {};"
21170              "obj.__proto__ = new f();");
21171   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21172   CheckInstanceCheckedAccessors(false);
21173 }
21174
21175
21176 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21177   v8::internal::FLAG_allow_natives_syntax = true;
21178   LocalContext context;
21179   v8::HandleScope scope(context->GetIsolate());
21180
21181   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21182   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21183   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21184   inst->SetAccessor(v8_str("foo"),
21185                     InstanceCheckedGetter, InstanceCheckedSetter,
21186                     Handle<Value>(),
21187                     v8::DEFAULT,
21188                     v8::None,
21189                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21190   context->Global()->Set(v8_str("f"), templ->GetFunction());
21191
21192   printf("Testing positive ...\n");
21193   CompileRun("var obj = new f();");
21194   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21195   CheckInstanceCheckedAccessors(true);
21196
21197   printf("Testing negative ...\n");
21198   CompileRun("var obj = {};"
21199              "obj.__proto__ = new f();");
21200   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21201   CheckInstanceCheckedAccessors(false);
21202 }
21203
21204
21205 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21206   v8::internal::FLAG_allow_natives_syntax = true;
21207   LocalContext context;
21208   v8::HandleScope scope(context->GetIsolate());
21209
21210   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21211   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21212   proto->SetAccessor(v8_str("foo"),
21213                      InstanceCheckedGetter, InstanceCheckedSetter,
21214                      Handle<Value>(),
21215                      v8::DEFAULT,
21216                      v8::None,
21217                      v8::AccessorSignature::New(context->GetIsolate(), templ));
21218   context->Global()->Set(v8_str("f"), templ->GetFunction());
21219
21220   printf("Testing positive ...\n");
21221   CompileRun("var obj = new f();");
21222   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21223   CheckInstanceCheckedAccessors(true);
21224
21225   printf("Testing negative ...\n");
21226   CompileRun("var obj = {};"
21227              "obj.__proto__ = new f();");
21228   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21229   CheckInstanceCheckedAccessors(false);
21230
21231   printf("Testing positive with modified prototype chain ...\n");
21232   CompileRun("var obj = new f();"
21233              "var pro = {};"
21234              "pro.__proto__ = obj.__proto__;"
21235              "obj.__proto__ = pro;");
21236   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21237   CheckInstanceCheckedAccessors(true);
21238 }
21239
21240
21241 TEST(TryFinallyMessage) {
21242   LocalContext context;
21243   v8::HandleScope scope(context->GetIsolate());
21244   {
21245     // Test that the original error message is not lost if there is a
21246     // recursive call into Javascript is done in the finally block, e.g. to
21247     // initialize an IC. (crbug.com/129171)
21248     TryCatch try_catch;
21249     const char* trigger_ic =
21250         "try {                      \n"
21251         "  throw new Error('test'); \n"
21252         "} finally {                \n"
21253         "  var x = 0;               \n"
21254         "  x++;                     \n"  // Trigger an IC initialization here.
21255         "}                          \n";
21256     CompileRun(trigger_ic);
21257     CHECK(try_catch.HasCaught());
21258     Local<Message> message = try_catch.Message();
21259     CHECK(!message.IsEmpty());
21260     CHECK_EQ(2, message->GetLineNumber());
21261   }
21262
21263   {
21264     // Test that the original exception message is indeed overwritten if
21265     // a new error is thrown in the finally block.
21266     TryCatch try_catch;
21267     const char* throw_again =
21268         "try {                       \n"
21269         "  throw new Error('test');  \n"
21270         "} finally {                 \n"
21271         "  var x = 0;                \n"
21272         "  x++;                      \n"
21273         "  throw new Error('again'); \n"  // This is the new uncaught error.
21274         "}                           \n";
21275     CompileRun(throw_again);
21276     CHECK(try_catch.HasCaught());
21277     Local<Message> message = try_catch.Message();
21278     CHECK(!message.IsEmpty());
21279     CHECK_EQ(6, message->GetLineNumber());
21280   }
21281 }
21282
21283
21284 static void Helper137002(bool do_store,
21285                          bool polymorphic,
21286                          bool remove_accessor,
21287                          bool interceptor) {
21288   LocalContext context;
21289   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21290   if (interceptor) {
21291     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21292   } else {
21293     templ->SetAccessor(v8_str("foo"),
21294                        GetterWhichReturns42,
21295                        SetterWhichSetsYOnThisTo23);
21296   }
21297   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21298
21299   // Turn monomorphic on slow object with native accessor, then turn
21300   // polymorphic, finally optimize to create negative lookup and fail.
21301   CompileRun(do_store ?
21302              "function f(x) { x.foo = void 0; }" :
21303              "function f(x) { return x.foo; }");
21304   CompileRun("obj.y = void 0;");
21305   if (!interceptor) {
21306     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21307   }
21308   CompileRun("obj.__proto__ = null;"
21309              "f(obj); f(obj); f(obj);");
21310   if (polymorphic) {
21311     CompileRun("f({});");
21312   }
21313   CompileRun("obj.y = void 0;"
21314              "%OptimizeFunctionOnNextCall(f);");
21315   if (remove_accessor) {
21316     CompileRun("delete obj.foo;");
21317   }
21318   CompileRun("var result = f(obj);");
21319   if (do_store) {
21320     CompileRun("result = obj.y;");
21321   }
21322   if (remove_accessor && !interceptor) {
21323     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21324   } else {
21325     CHECK_EQ(do_store ? 23 : 42,
21326              context->Global()->Get(v8_str("result"))->Int32Value());
21327   }
21328 }
21329
21330
21331 THREADED_TEST(Regress137002a) {
21332   i::FLAG_allow_natives_syntax = true;
21333   i::FLAG_compilation_cache = false;
21334   v8::HandleScope scope(CcTest::isolate());
21335   for (int i = 0; i < 16; i++) {
21336     Helper137002(i & 8, i & 4, i & 2, i & 1);
21337   }
21338 }
21339
21340
21341 THREADED_TEST(Regress137002b) {
21342   i::FLAG_allow_natives_syntax = true;
21343   LocalContext context;
21344   v8::Isolate* isolate = context->GetIsolate();
21345   v8::HandleScope scope(isolate);
21346   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21347   templ->SetAccessor(v8_str("foo"),
21348                      GetterWhichReturns42,
21349                      SetterWhichSetsYOnThisTo23);
21350   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21351
21352   // Turn monomorphic on slow object with native accessor, then just
21353   // delete the property and fail.
21354   CompileRun("function load(x) { return x.foo; }"
21355              "function store(x) { x.foo = void 0; }"
21356              "function keyed_load(x, key) { return x[key]; }"
21357              // Second version of function has a different source (add void 0)
21358              // so that it does not share code with the first version.  This
21359              // ensures that the ICs are monomorphic.
21360              "function load2(x) { void 0; return x.foo; }"
21361              "function store2(x) { void 0; x.foo = void 0; }"
21362              "function keyed_load2(x, key) { void 0; return x[key]; }"
21363
21364              "obj.y = void 0;"
21365              "obj.__proto__ = null;"
21366              "var subobj = {};"
21367              "subobj.y = void 0;"
21368              "subobj.__proto__ = obj;"
21369              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21370
21371              // Make the ICs monomorphic.
21372              "load(obj); load(obj);"
21373              "load2(subobj); load2(subobj);"
21374              "store(obj); store(obj);"
21375              "store2(subobj); store2(subobj);"
21376              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21377              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21378
21379              // Actually test the shiny new ICs and better not crash. This
21380              // serves as a regression test for issue 142088 as well.
21381              "load(obj);"
21382              "load2(subobj);"
21383              "store(obj);"
21384              "store2(subobj);"
21385              "keyed_load(obj, 'foo');"
21386              "keyed_load2(subobj, 'foo');"
21387
21388              // Delete the accessor.  It better not be called any more now.
21389              "delete obj.foo;"
21390              "obj.y = void 0;"
21391              "subobj.y = void 0;"
21392
21393              "var load_result = load(obj);"
21394              "var load_result2 = load2(subobj);"
21395              "var keyed_load_result = keyed_load(obj, 'foo');"
21396              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21397              "store(obj);"
21398              "store2(subobj);"
21399              "var y_from_obj = obj.y;"
21400              "var y_from_subobj = subobj.y;");
21401   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21402   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21403   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21404   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21405   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21406   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21407 }
21408
21409
21410 THREADED_TEST(Regress142088) {
21411   i::FLAG_allow_natives_syntax = true;
21412   LocalContext context;
21413   v8::Isolate* isolate = context->GetIsolate();
21414   v8::HandleScope scope(isolate);
21415   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21416   templ->SetAccessor(v8_str("foo"),
21417                      GetterWhichReturns42,
21418                      SetterWhichSetsYOnThisTo23);
21419   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21420
21421   CompileRun("function load(x) { return x.foo; }"
21422              "var o = Object.create(obj);"
21423              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21424              "load(o); load(o); load(o); load(o);");
21425 }
21426
21427
21428 THREADED_TEST(Regress3337) {
21429   LocalContext context;
21430   v8::Isolate* isolate = context->GetIsolate();
21431   v8::HandleScope scope(isolate);
21432   Local<v8::Object> o1 = Object::New(isolate);
21433   Local<v8::Object> o2 = Object::New(isolate);
21434   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21435   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21436   CHECK(io1->map() == io2->map());
21437   o1->SetIndexedPropertiesToExternalArrayData(
21438       NULL, v8::kExternalUint32Array, 0);
21439   o2->SetIndexedPropertiesToExternalArrayData(
21440       NULL, v8::kExternalUint32Array, 0);
21441   CHECK(io1->map() == io2->map());
21442 }
21443
21444
21445 THREADED_TEST(Regress137496) {
21446   i::FLAG_expose_gc = true;
21447   LocalContext context;
21448   v8::HandleScope scope(context->GetIsolate());
21449
21450   // Compile a try-finally clause where the finally block causes a GC
21451   // while there still is a message pending for external reporting.
21452   TryCatch try_catch;
21453   try_catch.SetVerbose(true);
21454   CompileRun("try { throw new Error(); } finally { gc(); }");
21455   CHECK(try_catch.HasCaught());
21456 }
21457
21458
21459 THREADED_TEST(Regress149912) {
21460   LocalContext context;
21461   v8::HandleScope scope(context->GetIsolate());
21462   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21463   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21464   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21465   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21466 }
21467
21468
21469 THREADED_TEST(Regress157124) {
21470   LocalContext context;
21471   v8::Isolate* isolate = context->GetIsolate();
21472   v8::HandleScope scope(isolate);
21473   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21474   Local<Object> obj = templ->NewInstance();
21475   obj->GetIdentityHash();
21476   obj->DeleteHiddenValue(v8_str("Bug"));
21477 }
21478
21479
21480 THREADED_TEST(Regress2535) {
21481   i::FLAG_harmony_collections = true;
21482   i::FLAG_harmony_symbols = true;
21483   LocalContext context;
21484   v8::HandleScope scope(context->GetIsolate());
21485   Local<Value> set_value = CompileRun("new Set();");
21486   Local<Object> set_object(Local<Object>::Cast(set_value));
21487   CHECK_EQ(0, set_object->InternalFieldCount());
21488   Local<Value> map_value = CompileRun("new Map();");
21489   Local<Object> map_object(Local<Object>::Cast(map_value));
21490   CHECK_EQ(0, map_object->InternalFieldCount());
21491 }
21492
21493
21494 THREADED_TEST(Regress2746) {
21495   LocalContext context;
21496   v8::Isolate* isolate = context->GetIsolate();
21497   v8::HandleScope scope(isolate);
21498   Local<Object> obj = Object::New(isolate);
21499   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21500   obj->SetHiddenValue(key, v8::Undefined(isolate));
21501   Local<Value> value = obj->GetHiddenValue(key);
21502   CHECK(!value.IsEmpty());
21503   CHECK(value->IsUndefined());
21504 }
21505
21506
21507 THREADED_TEST(Regress260106) {
21508   LocalContext context;
21509   v8::Isolate* isolate = context->GetIsolate();
21510   v8::HandleScope scope(isolate);
21511   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21512                                                         DummyCallHandler);
21513   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21514   Local<Function> function = templ->GetFunction();
21515   CHECK(!function.IsEmpty());
21516   CHECK(function->IsFunction());
21517 }
21518
21519
21520 THREADED_TEST(JSONParseObject) {
21521   LocalContext context;
21522   HandleScope scope(context->GetIsolate());
21523   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21524   Handle<Object> global = context->Global();
21525   global->Set(v8_str("obj"), obj);
21526   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21527 }
21528
21529
21530 THREADED_TEST(JSONParseNumber) {
21531   LocalContext context;
21532   HandleScope scope(context->GetIsolate());
21533   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21534   Handle<Object> global = context->Global();
21535   global->Set(v8_str("obj"), obj);
21536   ExpectString("JSON.stringify(obj)", "42");
21537 }
21538
21539
21540 #if V8_OS_POSIX
21541 class ThreadInterruptTest {
21542  public:
21543   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21544   ~ThreadInterruptTest() {}
21545
21546   void RunTest() {
21547     InterruptThread i_thread(this);
21548     i_thread.Start();
21549
21550     sem_.Wait();
21551     CHECK_EQ(kExpectedValue, sem_value_);
21552   }
21553
21554  private:
21555   static const int kExpectedValue = 1;
21556
21557   class InterruptThread : public i::Thread {
21558    public:
21559     explicit InterruptThread(ThreadInterruptTest* test)
21560         : Thread("InterruptThread"), test_(test) {}
21561
21562     virtual void Run() {
21563       struct sigaction action;
21564
21565       // Ensure that we'll enter waiting condition
21566       i::OS::Sleep(100);
21567
21568       // Setup signal handler
21569       memset(&action, 0, sizeof(action));
21570       action.sa_handler = SignalHandler;
21571       sigaction(SIGCHLD, &action, NULL);
21572
21573       // Send signal
21574       kill(getpid(), SIGCHLD);
21575
21576       // Ensure that if wait has returned because of error
21577       i::OS::Sleep(100);
21578
21579       // Set value and signal semaphore
21580       test_->sem_value_ = 1;
21581       test_->sem_.Signal();
21582     }
21583
21584     static void SignalHandler(int signal) {
21585     }
21586
21587    private:
21588      ThreadInterruptTest* test_;
21589   };
21590
21591   i::Semaphore sem_;
21592   volatile int sem_value_;
21593 };
21594
21595
21596 THREADED_TEST(SemaphoreInterruption) {
21597   ThreadInterruptTest().RunTest();
21598 }
21599
21600
21601 #endif  // V8_OS_POSIX
21602
21603
21604 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21605                                      Local<Value> name,
21606                                      v8::AccessType type,
21607                                      Local<Value> data) {
21608   i::PrintF("Named access blocked.\n");
21609   return false;
21610 }
21611
21612
21613 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21614                                      uint32_t key,
21615                                      v8::AccessType type,
21616                                      Local<Value> data) {
21617   i::PrintF("Indexed access blocked.\n");
21618   return false;
21619 }
21620
21621
21622 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21623   CHECK(false);
21624 }
21625
21626
21627 TEST(JSONStringifyAccessCheck) {
21628   v8::V8::Initialize();
21629   v8::Isolate* isolate = CcTest::isolate();
21630   v8::HandleScope scope(isolate);
21631
21632   // Create an ObjectTemplate for global objects and install access
21633   // check callbacks that will block access.
21634   v8::Handle<v8::ObjectTemplate> global_template =
21635       v8::ObjectTemplate::New(isolate);
21636   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21637                                            IndexAccessAlwaysBlocked);
21638
21639   // Create a context and set an x property on it's global object.
21640   LocalContext context0(NULL, global_template);
21641   v8::Handle<v8::Object> global0 = context0->Global();
21642   global0->Set(v8_str("x"), v8_num(42));
21643   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21644
21645   for (int i = 0; i < 2; i++) {
21646     if (i == 1) {
21647       // Install a toJSON function on the second run.
21648       v8::Handle<v8::FunctionTemplate> toJSON =
21649           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21650
21651       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21652     }
21653     // Create a context with a different security token so that the
21654     // failed access check callback will be called on each access.
21655     LocalContext context1(NULL, global_template);
21656     context1->Global()->Set(v8_str("other"), global0);
21657
21658     ExpectString("JSON.stringify(other)", "{}");
21659     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21660                  "{\"a\":{},\"b\":[\"c\"]}");
21661     ExpectString("JSON.stringify([other, 'b', 'c'])",
21662                  "[{},\"b\",\"c\"]");
21663
21664     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21665     array->Set(0, v8_str("a"));
21666     array->Set(1, v8_str("b"));
21667     context1->Global()->Set(v8_str("array"), array);
21668     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21669     array->TurnOnAccessCheck();
21670     ExpectString("JSON.stringify(array)", "[]");
21671     ExpectString("JSON.stringify([array])", "[[]]");
21672     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21673   }
21674 }
21675
21676
21677 bool access_check_fail_thrown = false;
21678 bool catch_callback_called = false;
21679
21680
21681 // Failed access check callback that performs a GC on each invocation.
21682 void FailedAccessCheckThrows(Local<v8::Object> target,
21683                              v8::AccessType type,
21684                              Local<v8::Value> data) {
21685   access_check_fail_thrown = true;
21686   i::PrintF("Access check failed. Error thrown.\n");
21687   CcTest::isolate()->ThrowException(
21688       v8::Exception::Error(v8_str("cross context")));
21689 }
21690
21691
21692 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21693   for (int i = 0; i < args.Length(); i++) {
21694     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21695   }
21696   catch_callback_called = true;
21697 }
21698
21699
21700 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21701   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21702 }
21703
21704
21705 void CheckCorrectThrow(const char* script) {
21706   // Test that the script, when wrapped into a try-catch, triggers the catch
21707   // clause due to failed access check throwing an exception.
21708   // The subsequent try-catch should run without any exception.
21709   access_check_fail_thrown = false;
21710   catch_callback_called = false;
21711   i::ScopedVector<char> source(1024);
21712   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21713   CompileRun(source.start());
21714   CHECK(access_check_fail_thrown);
21715   CHECK(catch_callback_called);
21716
21717   access_check_fail_thrown = false;
21718   catch_callback_called = false;
21719   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21720   CHECK(!access_check_fail_thrown);
21721   CHECK(!catch_callback_called);
21722 }
21723
21724
21725 TEST(AccessCheckThrows) {
21726   i::FLAG_allow_natives_syntax = true;
21727   v8::V8::Initialize();
21728   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21729   v8::Isolate* isolate = CcTest::isolate();
21730   v8::HandleScope scope(isolate);
21731
21732   // Create an ObjectTemplate for global objects and install access
21733   // check callbacks that will block access.
21734   v8::Handle<v8::ObjectTemplate> global_template =
21735       v8::ObjectTemplate::New(isolate);
21736   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21737                                            IndexAccessAlwaysBlocked);
21738
21739   // Create a context and set an x property on it's global object.
21740   LocalContext context0(NULL, global_template);
21741   context0->Global()->Set(v8_str("x"), v8_num(42));
21742   v8::Handle<v8::Object> global0 = context0->Global();
21743
21744   // Create a context with a different security token so that the
21745   // failed access check callback will be called on each access.
21746   LocalContext context1(NULL, global_template);
21747   context1->Global()->Set(v8_str("other"), global0);
21748
21749   v8::Handle<v8::FunctionTemplate> catcher_fun =
21750       v8::FunctionTemplate::New(isolate, CatcherCallback);
21751   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21752
21753   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21754       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21755   context1->Global()->Set(v8_str("has_own_property"),
21756                           has_own_property_fun->GetFunction());
21757
21758   { v8::TryCatch try_catch;
21759     access_check_fail_thrown = false;
21760     CompileRun("other.x;");
21761     CHECK(access_check_fail_thrown);
21762     CHECK(try_catch.HasCaught());
21763   }
21764
21765   CheckCorrectThrow("other.x");
21766   CheckCorrectThrow("other[1]");
21767   CheckCorrectThrow("JSON.stringify(other)");
21768   CheckCorrectThrow("has_own_property(other, 'x')");
21769   CheckCorrectThrow("%GetProperty(other, 'x')");
21770   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21771   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21772   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21773   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21774   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21775   CheckCorrectThrow("%HasProperty(other, 'x')");
21776   CheckCorrectThrow("%HasElement(other, 1)");
21777   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21778   CheckCorrectThrow("%GetPropertyNames(other)");
21779   // PROPERTY_ATTRIBUTES_NONE = 0
21780   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21781   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21782                         "other, 'x', null, null, 1)");
21783
21784   // Reset the failed access check callback so it does not influence
21785   // the other tests.
21786   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21787 }
21788
21789
21790 THREADED_TEST(Regress256330) {
21791   i::FLAG_allow_natives_syntax = true;
21792   LocalContext context;
21793   v8::HandleScope scope(context->GetIsolate());
21794   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21795   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21796   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21797   CompileRun("\"use strict\"; var o = new Bug;"
21798              "function f(o) { o.x = 10; };"
21799              "f(o); f(o); f(o);"
21800              "%OptimizeFunctionOnNextCall(f);"
21801              "f(o);");
21802   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21803 }
21804
21805
21806 THREADED_TEST(CrankshaftInterceptorSetter) {
21807   i::FLAG_allow_natives_syntax = true;
21808   v8::HandleScope scope(CcTest::isolate());
21809   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21810   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21811   LocalContext env;
21812   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21813   CompileRun("var obj = new Obj;"
21814              // Initialize fields to avoid transitions later.
21815              "obj.age = 0;"
21816              "obj.accessor_age = 42;"
21817              "function setter(i) { this.accessor_age = i; };"
21818              "function getter() { return this.accessor_age; };"
21819              "function setAge(i) { obj.age = i; };"
21820              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21821              "setAge(1);"
21822              "setAge(2);"
21823              "setAge(3);"
21824              "%OptimizeFunctionOnNextCall(setAge);"
21825              "setAge(4);");
21826   // All stores went through the interceptor.
21827   ExpectInt32("obj.interceptor_age", 4);
21828   ExpectInt32("obj.accessor_age", 42);
21829 }
21830
21831
21832 THREADED_TEST(CrankshaftInterceptorGetter) {
21833   i::FLAG_allow_natives_syntax = true;
21834   v8::HandleScope scope(CcTest::isolate());
21835   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21836   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21837   LocalContext env;
21838   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21839   CompileRun("var obj = new Obj;"
21840              // Initialize fields to avoid transitions later.
21841              "obj.age = 1;"
21842              "obj.accessor_age = 42;"
21843              "function getter() { return this.accessor_age; };"
21844              "function getAge() { return obj.interceptor_age; };"
21845              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21846              "getAge();"
21847              "getAge();"
21848              "getAge();"
21849              "%OptimizeFunctionOnNextCall(getAge);");
21850   // Access through interceptor.
21851   ExpectInt32("getAge()", 1);
21852 }
21853
21854
21855 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21856   i::FLAG_allow_natives_syntax = true;
21857   v8::HandleScope scope(CcTest::isolate());
21858   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21859   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21860   LocalContext env;
21861   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21862   CompileRun("var obj = new Obj;"
21863              "obj.__proto__.interceptor_age = 42;"
21864              "obj.age = 100;"
21865              "function getAge() { return obj.interceptor_age; };");
21866   ExpectInt32("getAge();", 100);
21867   ExpectInt32("getAge();", 100);
21868   ExpectInt32("getAge();", 100);
21869   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21870   // Access through interceptor.
21871   ExpectInt32("getAge();", 100);
21872 }
21873
21874
21875 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21876   i::FLAG_allow_natives_syntax = true;
21877   v8::HandleScope scope(CcTest::isolate());
21878   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21879   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21880   LocalContext env;
21881   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21882   CompileRun("var obj = new Obj;"
21883              "obj.age = 100000;"
21884              "function setAge(i) { obj.age = i };"
21885              "setAge(100);"
21886              "setAge(101);"
21887              "setAge(102);"
21888              "%OptimizeFunctionOnNextCall(setAge);"
21889              "setAge(103);");
21890   ExpectInt32("obj.age", 100000);
21891   ExpectInt32("obj.interceptor_age", 103);
21892 }
21893
21894
21895 class RequestInterruptTestBase {
21896  public:
21897   RequestInterruptTestBase()
21898       : env_(),
21899         isolate_(env_->GetIsolate()),
21900         sem_(0),
21901         warmup_(20000),
21902         should_continue_(true) {
21903   }
21904
21905   virtual ~RequestInterruptTestBase() { }
21906
21907   virtual void StartInterruptThread() = 0;
21908
21909   virtual void TestBody() = 0;
21910
21911   void RunTest() {
21912     StartInterruptThread();
21913
21914     v8::HandleScope handle_scope(isolate_);
21915
21916     TestBody();
21917
21918     isolate_->ClearInterrupt();
21919
21920     // Verify we arrived here because interruptor was called
21921     // not due to a bug causing us to exit the loop too early.
21922     CHECK(!should_continue());
21923   }
21924
21925   void WakeUpInterruptor() {
21926     sem_.Signal();
21927   }
21928
21929   bool should_continue() const { return should_continue_; }
21930
21931   bool ShouldContinue() {
21932     if (warmup_ > 0) {
21933       if (--warmup_ == 0) {
21934         WakeUpInterruptor();
21935       }
21936     }
21937
21938     return should_continue_;
21939   }
21940
21941   static void ShouldContinueCallback(
21942       const v8::FunctionCallbackInfo<Value>& info) {
21943     RequestInterruptTestBase* test =
21944         reinterpret_cast<RequestInterruptTestBase*>(
21945             info.Data().As<v8::External>()->Value());
21946     info.GetReturnValue().Set(test->ShouldContinue());
21947   }
21948
21949   LocalContext env_;
21950   v8::Isolate* isolate_;
21951   i::Semaphore sem_;
21952   int warmup_;
21953   bool should_continue_;
21954 };
21955
21956
21957 class RequestInterruptTestBaseWithSimpleInterrupt
21958     : public RequestInterruptTestBase {
21959  public:
21960   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
21961
21962   virtual void StartInterruptThread() {
21963     i_thread.Start();
21964   }
21965
21966  private:
21967   class InterruptThread : public i::Thread {
21968    public:
21969     explicit InterruptThread(RequestInterruptTestBase* test)
21970         : Thread("RequestInterruptTest"), test_(test) {}
21971
21972     virtual void Run() {
21973       test_->sem_.Wait();
21974       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21975     }
21976
21977     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21978       reinterpret_cast<RequestInterruptTestBase*>(data)->
21979           should_continue_ = false;
21980     }
21981
21982    private:
21983      RequestInterruptTestBase* test_;
21984   };
21985
21986   InterruptThread i_thread;
21987 };
21988
21989
21990 class RequestInterruptTestWithFunctionCall
21991     : public RequestInterruptTestBaseWithSimpleInterrupt {
21992  public:
21993   virtual void TestBody() {
21994     Local<Function> func = Function::New(
21995         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21996     env_->Global()->Set(v8_str("ShouldContinue"), func);
21997
21998     CompileRun("while (ShouldContinue()) { }");
21999   }
22000 };
22001
22002
22003 class RequestInterruptTestWithMethodCall
22004     : public RequestInterruptTestBaseWithSimpleInterrupt {
22005  public:
22006   virtual void TestBody() {
22007     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22008     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22009     proto->Set(v8_str("shouldContinue"), Function::New(
22010         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22011     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22012
22013     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22014   }
22015 };
22016
22017
22018 class RequestInterruptTestWithAccessor
22019     : public RequestInterruptTestBaseWithSimpleInterrupt {
22020  public:
22021   virtual void TestBody() {
22022     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22023     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22024     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22025         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22026     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22027
22028     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22029   }
22030 };
22031
22032
22033 class RequestInterruptTestWithNativeAccessor
22034     : public RequestInterruptTestBaseWithSimpleInterrupt {
22035  public:
22036   virtual void TestBody() {
22037     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22038     t->InstanceTemplate()->SetNativeDataProperty(
22039         v8_str("shouldContinue"),
22040         &ShouldContinueNativeGetter,
22041         NULL,
22042         v8::External::New(isolate_, this));
22043     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22044
22045     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22046   }
22047
22048  private:
22049   static void ShouldContinueNativeGetter(
22050       Local<String> property,
22051       const v8::PropertyCallbackInfo<v8::Value>& info) {
22052     RequestInterruptTestBase* test =
22053         reinterpret_cast<RequestInterruptTestBase*>(
22054             info.Data().As<v8::External>()->Value());
22055     info.GetReturnValue().Set(test->ShouldContinue());
22056   }
22057 };
22058
22059
22060 class RequestInterruptTestWithMethodCallAndInterceptor
22061     : public RequestInterruptTestBaseWithSimpleInterrupt {
22062  public:
22063   virtual void TestBody() {
22064     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22065     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22066     proto->Set(v8_str("shouldContinue"), Function::New(
22067         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22068     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22069     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22070
22071     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22072
22073     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22074   }
22075
22076  private:
22077   static void EmptyInterceptor(
22078       Local<String> property,
22079       const v8::PropertyCallbackInfo<v8::Value>& info) {
22080   }
22081 };
22082
22083
22084 class RequestInterruptTestWithMathAbs
22085     : public RequestInterruptTestBaseWithSimpleInterrupt {
22086  public:
22087   virtual void TestBody() {
22088     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22089         isolate_,
22090         WakeUpInterruptorCallback,
22091         v8::External::New(isolate_, this)));
22092
22093     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22094         isolate_,
22095         ShouldContinueCallback,
22096         v8::External::New(isolate_, this)));
22097
22098     i::FLAG_allow_natives_syntax = true;
22099     CompileRun("function loopish(o) {"
22100                "  var pre = 10;"
22101                "  while (o.abs(1) > 0) {"
22102                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22103                "    if (pre > 0) {"
22104                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
22105                "    }"
22106                "  }"
22107                "}"
22108                "var i = 50;"
22109                "var obj = {abs: function () { return i-- }, x: null};"
22110                "delete obj.x;"
22111                "loopish(obj);"
22112                "%OptimizeFunctionOnNextCall(loopish);"
22113                "loopish(Math);");
22114
22115     i::FLAG_allow_natives_syntax = false;
22116   }
22117
22118  private:
22119   static void WakeUpInterruptorCallback(
22120       const v8::FunctionCallbackInfo<Value>& info) {
22121     if (!info[0]->BooleanValue()) return;
22122
22123     RequestInterruptTestBase* test =
22124         reinterpret_cast<RequestInterruptTestBase*>(
22125             info.Data().As<v8::External>()->Value());
22126     test->WakeUpInterruptor();
22127   }
22128
22129   static void ShouldContinueCallback(
22130       const v8::FunctionCallbackInfo<Value>& info) {
22131     RequestInterruptTestBase* test =
22132         reinterpret_cast<RequestInterruptTestBase*>(
22133             info.Data().As<v8::External>()->Value());
22134     info.GetReturnValue().Set(test->should_continue());
22135   }
22136 };
22137
22138
22139 TEST(RequestInterruptTestWithFunctionCall) {
22140   RequestInterruptTestWithFunctionCall().RunTest();
22141 }
22142
22143
22144 TEST(RequestInterruptTestWithMethodCall) {
22145   RequestInterruptTestWithMethodCall().RunTest();
22146 }
22147
22148
22149 TEST(RequestInterruptTestWithAccessor) {
22150   RequestInterruptTestWithAccessor().RunTest();
22151 }
22152
22153
22154 TEST(RequestInterruptTestWithNativeAccessor) {
22155   RequestInterruptTestWithNativeAccessor().RunTest();
22156 }
22157
22158
22159 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22160   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22161 }
22162
22163
22164 TEST(RequestInterruptTestWithMathAbs) {
22165   RequestInterruptTestWithMathAbs().RunTest();
22166 }
22167
22168
22169 class ClearInterruptFromAnotherThread
22170     : public RequestInterruptTestBase {
22171  public:
22172   ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22173
22174   virtual void StartInterruptThread() {
22175     i_thread.Start();
22176   }
22177
22178   virtual void TestBody() {
22179     Local<Function> func = Function::New(
22180         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22181     env_->Global()->Set(v8_str("ShouldContinue"), func);
22182
22183     CompileRun("while (ShouldContinue()) { }");
22184   }
22185
22186  private:
22187   class InterruptThread : public i::Thread {
22188    public:
22189     explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22190         : Thread("RequestInterruptTest"), test_(test) {}
22191
22192     virtual void Run() {
22193       test_->sem_.Wait();
22194       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22195       test_->sem_.Wait();
22196       test_->isolate_->ClearInterrupt();
22197       test_->sem2_.Signal();
22198     }
22199
22200     static void OnInterrupt(v8::Isolate* isolate, void* data) {
22201       ClearInterruptFromAnotherThread* test =
22202           reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22203       test->sem_.Signal();
22204       bool success = test->sem2_.WaitFor(i::TimeDelta::FromSeconds(2));
22205       // Crash instead of timeout to make this failure more prominent.
22206       CHECK(success);
22207       test->should_continue_ = false;
22208     }
22209
22210    private:
22211      ClearInterruptFromAnotherThread* test_;
22212   };
22213
22214   InterruptThread i_thread;
22215   i::Semaphore sem2_;
22216 };
22217
22218
22219 TEST(ClearInterruptFromAnotherThread) {
22220   ClearInterruptFromAnotherThread().RunTest();
22221 }
22222
22223
22224 static Local<Value> function_new_expected_env;
22225 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22226   CHECK_EQ(function_new_expected_env, info.Data());
22227   info.GetReturnValue().Set(17);
22228 }
22229
22230
22231 THREADED_TEST(FunctionNew) {
22232   LocalContext env;
22233   v8::Isolate* isolate = env->GetIsolate();
22234   v8::HandleScope scope(isolate);
22235   Local<Object> data = v8::Object::New(isolate);
22236   function_new_expected_env = data;
22237   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22238   env->Global()->Set(v8_str("func"), func);
22239   Local<Value> result = CompileRun("func();");
22240   CHECK_EQ(v8::Integer::New(isolate, 17), result);
22241   // Verify function not cached
22242   int serial_number =
22243       i::Smi::cast(v8::Utils::OpenHandle(*func)
22244           ->shared()->get_api_func_data()->serial_number())->value();
22245   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22246   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22247   i::Handle<i::Object> elm =
22248       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22249   CHECK(elm->IsUndefined());
22250   // Verify that each Function::New creates a new function instance
22251   Local<Object> data2 = v8::Object::New(isolate);
22252   function_new_expected_env = data2;
22253   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22254   CHECK(!func2->IsNull());
22255   CHECK_NE(func, func2);
22256   env->Global()->Set(v8_str("func2"), func2);
22257   Local<Value> result2 = CompileRun("func2();");
22258   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22259 }
22260
22261
22262 TEST(EscapeableHandleScope) {
22263   HandleScope outer_scope(CcTest::isolate());
22264   LocalContext context;
22265   const int runs = 10;
22266   Local<String> values[runs];
22267   for (int i = 0; i < runs; i++) {
22268     v8::EscapableHandleScope inner_scope(CcTest::isolate());
22269     Local<String> value;
22270     if (i != 0) value = v8_str("escape value");
22271     values[i] = inner_scope.Escape(value);
22272   }
22273   for (int i = 0; i < runs; i++) {
22274     Local<String> expected;
22275     if (i != 0) {
22276       CHECK_EQ(v8_str("escape value"), values[i]);
22277     } else {
22278       CHECK(values[i].IsEmpty());
22279     }
22280   }
22281 }
22282
22283
22284 static void SetterWhichExpectsThisAndHolderToDiffer(
22285     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22286   CHECK(info.Holder() != info.This());
22287 }
22288
22289
22290 TEST(Regress239669) {
22291   LocalContext context;
22292   v8::Isolate* isolate = context->GetIsolate();
22293   v8::HandleScope scope(isolate);
22294   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22295   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22296   context->Global()->Set(v8_str("P"), templ->NewInstance());
22297   CompileRun(
22298       "function C1() {"
22299       "  this.x = 23;"
22300       "};"
22301       "C1.prototype = P;"
22302       "for (var i = 0; i < 4; i++ ) {"
22303       "  new C1();"
22304       "}");
22305 }
22306
22307
22308 class ApiCallOptimizationChecker {
22309  private:
22310   static Local<Object> data;
22311   static Local<Object> receiver;
22312   static Local<Object> holder;
22313   static Local<Object> callee;
22314   static int count;
22315
22316   static void OptimizationCallback(
22317       const v8::FunctionCallbackInfo<v8::Value>& info) {
22318     CHECK(callee == info.Callee());
22319     CHECK(data == info.Data());
22320     CHECK(receiver == info.This());
22321     if (info.Length() == 1) {
22322       CHECK_EQ(v8_num(1), info[0]);
22323     }
22324     CHECK(holder == info.Holder());
22325     count++;
22326     info.GetReturnValue().Set(v8_str("returned"));
22327   }
22328
22329  public:
22330   enum SignatureType {
22331     kNoSignature,
22332     kSignatureOnReceiver,
22333     kSignatureOnPrototype
22334   };
22335
22336   void RunAll() {
22337     SignatureType signature_types[] =
22338       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22339     for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22340       SignatureType signature_type = signature_types[i];
22341       for (int j = 0; j < 2; j++) {
22342         bool global = j == 0;
22343         int key = signature_type +
22344             ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22345         Run(signature_type, global, key);
22346       }
22347     }
22348   }
22349
22350   void Run(SignatureType signature_type, bool global, int key) {
22351     v8::Isolate* isolate = CcTest::isolate();
22352     v8::HandleScope scope(isolate);
22353     // Build a template for signature checks.
22354     Local<v8::ObjectTemplate> signature_template;
22355     Local<v8::Signature> signature;
22356     {
22357       Local<v8::FunctionTemplate> parent_template =
22358         FunctionTemplate::New(isolate);
22359       parent_template->SetHiddenPrototype(true);
22360       Local<v8::FunctionTemplate> function_template
22361           = FunctionTemplate::New(isolate);
22362       function_template->Inherit(parent_template);
22363       switch (signature_type) {
22364         case kNoSignature:
22365           break;
22366         case kSignatureOnReceiver:
22367           signature = v8::Signature::New(isolate, function_template);
22368           break;
22369         case kSignatureOnPrototype:
22370           signature = v8::Signature::New(isolate, parent_template);
22371           break;
22372       }
22373       signature_template = function_template->InstanceTemplate();
22374     }
22375     // Global object must pass checks.
22376     Local<v8::Context> context =
22377         v8::Context::New(isolate, NULL, signature_template);
22378     v8::Context::Scope context_scope(context);
22379     // Install regular object that can pass signature checks.
22380     Local<Object> function_receiver = signature_template->NewInstance();
22381     context->Global()->Set(v8_str("function_receiver"), function_receiver);
22382     // Get the holder objects.
22383     Local<Object> inner_global =
22384         Local<Object>::Cast(context->Global()->GetPrototype());
22385     // Install functions on hidden prototype object if there is one.
22386     data = Object::New(isolate);
22387     Local<FunctionTemplate> function_template = FunctionTemplate::New(
22388         isolate, OptimizationCallback, data, signature);
22389     Local<Function> function = function_template->GetFunction();
22390     Local<Object> global_holder = inner_global;
22391     Local<Object> function_holder = function_receiver;
22392     if (signature_type == kSignatureOnPrototype) {
22393       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22394       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22395     }
22396     global_holder->Set(v8_str("g_f"), function);
22397     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22398     function_holder->Set(v8_str("f"), function);
22399     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22400     // Initialize expected values.
22401     callee = function;
22402     count = 0;
22403     if (global) {
22404       receiver = context->Global();
22405       holder = inner_global;
22406     } else {
22407       holder = function_receiver;
22408       // If not using a signature, add something else to the prototype chain
22409       // to test the case that holder != receiver
22410       if (signature_type == kNoSignature) {
22411         receiver = Local<Object>::Cast(CompileRun(
22412             "var receiver_subclass = {};\n"
22413             "receiver_subclass.__proto__ = function_receiver;\n"
22414             "receiver_subclass"));
22415       } else {
22416         receiver = Local<Object>::Cast(CompileRun(
22417           "var receiver_subclass = function_receiver;\n"
22418           "receiver_subclass"));
22419       }
22420     }
22421     // With no signature, the holder is not set.
22422     if (signature_type == kNoSignature) holder = receiver;
22423     // build wrap_function
22424     i::ScopedVector<char> wrap_function(200);
22425     if (global) {
22426       i::SNPrintF(
22427           wrap_function,
22428           "function wrap_f_%d() { var f = g_f; return f(); }\n"
22429           "function wrap_get_%d() { return this.g_acc; }\n"
22430           "function wrap_set_%d() { return this.g_acc = 1; }\n",
22431           key, key, key);
22432     } else {
22433       i::SNPrintF(
22434           wrap_function,
22435           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22436           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22437           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22438           key, key, key);
22439     }
22440     // build source string
22441     i::ScopedVector<char> source(1000);
22442     i::SNPrintF(
22443         source,
22444         "%s\n"  // wrap functions
22445         "function wrap_f() { return wrap_f_%d(); }\n"
22446         "function wrap_get() { return wrap_get_%d(); }\n"
22447         "function wrap_set() { return wrap_set_%d(); }\n"
22448         "check = function(returned) {\n"
22449         "  if (returned !== 'returned') { throw returned; }\n"
22450         "}\n"
22451         "\n"
22452         "check(wrap_f());\n"
22453         "check(wrap_f());\n"
22454         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22455         "check(wrap_f());\n"
22456         "\n"
22457         "check(wrap_get());\n"
22458         "check(wrap_get());\n"
22459         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22460         "check(wrap_get());\n"
22461         "\n"
22462         "check = function(returned) {\n"
22463         "  if (returned !== 1) { throw returned; }\n"
22464         "}\n"
22465         "check(wrap_set());\n"
22466         "check(wrap_set());\n"
22467         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22468         "check(wrap_set());\n",
22469         wrap_function.start(), key, key, key, key, key, key);
22470     v8::TryCatch try_catch;
22471     CompileRun(source.start());
22472     ASSERT(!try_catch.HasCaught());
22473     CHECK_EQ(9, count);
22474   }
22475 };
22476
22477
22478 Local<Object> ApiCallOptimizationChecker::data;
22479 Local<Object> ApiCallOptimizationChecker::receiver;
22480 Local<Object> ApiCallOptimizationChecker::holder;
22481 Local<Object> ApiCallOptimizationChecker::callee;
22482 int ApiCallOptimizationChecker::count = 0;
22483
22484
22485 TEST(TestFunctionCallOptimization) {
22486   i::FLAG_allow_natives_syntax = true;
22487   ApiCallOptimizationChecker checker;
22488   checker.RunAll();
22489 }
22490
22491
22492 static const char* last_event_message;
22493 static int last_event_status;
22494 void StoringEventLoggerCallback(const char* message, int status) {
22495     last_event_message = message;
22496     last_event_status = status;
22497 }
22498
22499
22500 TEST(EventLogging) {
22501   v8::Isolate* isolate = CcTest::isolate();
22502   isolate->SetEventLogger(StoringEventLoggerCallback);
22503   v8::internal::HistogramTimer histogramTimer(
22504       "V8.Test", 0, 10000, 50,
22505       reinterpret_cast<v8::internal::Isolate*>(isolate));
22506   histogramTimer.Start();
22507   CHECK_EQ("V8.Test", last_event_message);
22508   CHECK_EQ(0, last_event_status);
22509   histogramTimer.Stop();
22510   CHECK_EQ("V8.Test", last_event_message);
22511   CHECK_EQ(1, last_event_status);
22512 }
22513
22514
22515 TEST(Promises) {
22516   LocalContext context;
22517   v8::Isolate* isolate = context->GetIsolate();
22518   v8::HandleScope scope(isolate);
22519   Handle<Object> global = context->Global();
22520
22521   // Creation.
22522   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22523   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22524   Handle<v8::Promise> p = pr->GetPromise();
22525   Handle<v8::Promise> r = rr->GetPromise();
22526
22527   // IsPromise predicate.
22528   CHECK(p->IsPromise());
22529   CHECK(r->IsPromise());
22530   Handle<Value> o = v8::Object::New(isolate);
22531   CHECK(!o->IsPromise());
22532
22533   // Resolution and rejection.
22534   pr->Resolve(v8::Integer::New(isolate, 1));
22535   CHECK(p->IsPromise());
22536   rr->Reject(v8::Integer::New(isolate, 2));
22537   CHECK(r->IsPromise());
22538
22539   // Chaining non-pending promises.
22540   CompileRun(
22541       "var x1 = 0;\n"
22542       "var x2 = 0;\n"
22543       "function f1(x) { x1 = x; return x+1 };\n"
22544       "function f2(x) { x2 = x; return x+1 };\n");
22545   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22546   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22547
22548   p->Chain(f1);
22549   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22550   isolate->RunMicrotasks();
22551   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22552
22553   p->Catch(f2);
22554   isolate->RunMicrotasks();
22555   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22556
22557   r->Catch(f2);
22558   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22559   isolate->RunMicrotasks();
22560   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22561
22562   r->Chain(f1);
22563   isolate->RunMicrotasks();
22564   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22565
22566   // Chaining pending promises.
22567   CompileRun("x1 = x2 = 0;");
22568   pr = v8::Promise::Resolver::New(isolate);
22569   rr = v8::Promise::Resolver::New(isolate);
22570
22571   pr->GetPromise()->Chain(f1);
22572   rr->GetPromise()->Catch(f2);
22573   isolate->RunMicrotasks();
22574   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22575   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22576
22577   pr->Resolve(v8::Integer::New(isolate, 1));
22578   rr->Reject(v8::Integer::New(isolate, 2));
22579   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22580   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22581
22582   isolate->RunMicrotasks();
22583   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22584   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22585
22586   // Multi-chaining.
22587   CompileRun("x1 = x2 = 0;");
22588   pr = v8::Promise::Resolver::New(isolate);
22589   pr->GetPromise()->Chain(f1)->Chain(f2);
22590   pr->Resolve(v8::Integer::New(isolate, 3));
22591   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22592   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22593   isolate->RunMicrotasks();
22594   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22595   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22596
22597   CompileRun("x1 = x2 = 0;");
22598   rr = v8::Promise::Resolver::New(isolate);
22599   rr->GetPromise()->Catch(f1)->Chain(f2);
22600   rr->Reject(v8::Integer::New(isolate, 3));
22601   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22602   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22603   isolate->RunMicrotasks();
22604   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22605   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22606 }
22607
22608
22609 TEST(PromiseThen) {
22610   LocalContext context;
22611   v8::Isolate* isolate = context->GetIsolate();
22612   v8::HandleScope scope(isolate);
22613   Handle<Object> global = context->Global();
22614
22615   // Creation.
22616   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22617   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22618   Handle<v8::Promise> p = pr->GetPromise();
22619   Handle<v8::Promise> q = qr->GetPromise();
22620
22621   CHECK(p->IsPromise());
22622   CHECK(q->IsPromise());
22623
22624   pr->Resolve(v8::Integer::New(isolate, 1));
22625   qr->Resolve(p);
22626
22627   // Chaining non-pending promises.
22628   CompileRun(
22629       "var x1 = 0;\n"
22630       "var x2 = 0;\n"
22631       "function f1(x) { x1 = x; return x+1 };\n"
22632       "function f2(x) { x2 = x; return x+1 };\n");
22633   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22634   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22635
22636   // Chain
22637   q->Chain(f1);
22638   CHECK(global->Get(v8_str("x1"))->IsNumber());
22639   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22640   isolate->RunMicrotasks();
22641   CHECK(!global->Get(v8_str("x1"))->IsNumber());
22642   CHECK_EQ(p, global->Get(v8_str("x1")));
22643
22644   // Then
22645   CompileRun("x1 = x2 = 0;");
22646   q->Then(f1);
22647   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22648   isolate->RunMicrotasks();
22649   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22650
22651   // Then
22652   CompileRun("x1 = x2 = 0;");
22653   pr = v8::Promise::Resolver::New(isolate);
22654   qr = v8::Promise::Resolver::New(isolate);
22655
22656   qr->Resolve(pr);
22657   qr->GetPromise()->Then(f1)->Then(f2);
22658
22659   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22660   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22661   isolate->RunMicrotasks();
22662   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22663   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22664
22665   pr->Resolve(v8::Integer::New(isolate, 3));
22666
22667   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22668   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22669   isolate->RunMicrotasks();
22670   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22671   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22672 }
22673
22674
22675 TEST(DisallowJavascriptExecutionScope) {
22676   LocalContext context;
22677   v8::Isolate* isolate = context->GetIsolate();
22678   v8::HandleScope scope(isolate);
22679   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22680       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22681   CompileRun("2+2");
22682 }
22683
22684
22685 TEST(AllowJavascriptExecutionScope) {
22686   LocalContext context;
22687   v8::Isolate* isolate = context->GetIsolate();
22688   v8::HandleScope scope(isolate);
22689   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22690       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22691   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22692       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22693   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22694     CompileRun("1+1");
22695   }
22696 }
22697
22698
22699 TEST(ThrowOnJavascriptExecution) {
22700   LocalContext context;
22701   v8::Isolate* isolate = context->GetIsolate();
22702   v8::HandleScope scope(isolate);
22703   v8::TryCatch try_catch;
22704   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22705       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22706   CompileRun("1+1");
22707   CHECK(try_catch.HasCaught());
22708 }
22709
22710
22711 TEST(Regress354123) {
22712   LocalContext current;
22713   v8::Isolate* isolate = current->GetIsolate();
22714   v8::HandleScope scope(isolate);
22715
22716   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22717   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22718   current->Global()->Set(v8_str("friend"), templ->NewInstance());
22719
22720   // Test access using __proto__ from the prototype chain.
22721   named_access_count = 0;
22722   CompileRun("friend.__proto__ = {};");
22723   CHECK_EQ(2, named_access_count);
22724   CompileRun("friend.__proto__;");
22725   CHECK_EQ(4, named_access_count);
22726
22727   // Test access using __proto__ as a hijacked function (A).
22728   named_access_count = 0;
22729   CompileRun("var p = Object.prototype;"
22730              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22731              "f.call(friend, {});");
22732   CHECK_EQ(1, named_access_count);
22733   CompileRun("var p = Object.prototype;"
22734              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22735              "f.call(friend);");
22736   CHECK_EQ(2, named_access_count);
22737
22738   // Test access using __proto__ as a hijacked function (B).
22739   named_access_count = 0;
22740   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22741              "f.call(friend, {});");
22742   CHECK_EQ(1, named_access_count);
22743   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22744              "f.call(friend);");
22745   CHECK_EQ(2, named_access_count);
22746
22747   // Test access using Object.setPrototypeOf reflective method.
22748   named_access_count = 0;
22749   CompileRun("Object.setPrototypeOf(friend, {});");
22750   CHECK_EQ(1, named_access_count);
22751   CompileRun("Object.getPrototypeOf(friend);");
22752   CHECK_EQ(2, named_access_count);
22753 }
22754
22755
22756 TEST(CaptureStackTraceForStackOverflow) {
22757   v8::internal::FLAG_stack_size = 150;
22758   LocalContext current;
22759   v8::Isolate* isolate = current->GetIsolate();
22760   v8::HandleScope scope(isolate);
22761   V8::SetCaptureStackTraceForUncaughtExceptions(
22762       true, 10, v8::StackTrace::kDetailed);
22763   v8::TryCatch try_catch;
22764   CompileRun("(function f(x) { f(x+1); })(0)");
22765   CHECK(try_catch.HasCaught());
22766 }
22767
22768
22769 TEST(ScriptNameAndLineNumber) {
22770   LocalContext env;
22771   v8::Isolate* isolate = env->GetIsolate();
22772   v8::HandleScope scope(isolate);
22773   const char* url = "http://www.foo.com/foo.js";
22774   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22775   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22776   Local<Script> script = v8::ScriptCompiler::Compile(
22777       isolate, &script_source);
22778   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22779   CHECK(!script_name.IsEmpty());
22780   CHECK(script_name->IsString());
22781   String::Utf8Value utf8_name(script_name);
22782   CHECK_EQ(url, *utf8_name);
22783   int line_number = script->GetUnboundScript()->GetLineNumber(0);
22784   CHECK_EQ(13, line_number);
22785 }
22786
22787
22788 Local<v8::Context> call_eval_context;
22789 Local<v8::Function> call_eval_bound_function;
22790 static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
22791   v8::Context::Scope scope(call_eval_context);
22792   args.GetReturnValue().Set(
22793       call_eval_bound_function->Call(call_eval_context->Global(), 0, NULL));
22794 }
22795
22796
22797 TEST(CrossActivationEval) {
22798   LocalContext env;
22799   v8::Isolate* isolate = env->GetIsolate();
22800   v8::HandleScope scope(isolate);
22801   {
22802     call_eval_context = v8::Context::New(isolate);
22803     v8::Context::Scope scope(call_eval_context);
22804     call_eval_bound_function =
22805         Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
22806   }
22807   env->Global()->Set(v8_str("CallEval"),
22808       v8::FunctionTemplate::New(isolate, CallEval)->GetFunction());
22809   Local<Value> result = CompileRun("CallEval();");
22810   CHECK_EQ(result, v8::Integer::New(isolate, 1));
22811 }