Merge remote-tracking branch 'upstream/v0.10'
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <limits.h>
29
30 #ifndef WIN32
31 #include <signal.h>  // kill
32 #include <unistd.h>  // getpid
33 #endif  // WIN32
34 #include <string>
35 #include <map>
36
37 #include "v8.h"
38
39 #include "api.h"
40 #include "arguments.h"
41 #include "cctest.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
45 #include "isolate.h"
46 #include "objects.h"
47 #include "parser.h"
48 #include "platform.h"
49 #include "snapshot.h"
50 #include "unicode-inl.h"
51 #include "utils.h"
52 #include "vm-state.h"
53
54 static const bool kLogThreading = false;
55
56 using ::v8::AccessorInfo;
57 using ::v8::Arguments;
58 using ::v8::Boolean;
59 using ::v8::BooleanObject;
60 using ::v8::Context;
61 using ::v8::Extension;
62 using ::v8::Function;
63 using ::v8::FunctionTemplate;
64 using ::v8::Handle;
65 using ::v8::HandleScope;
66 using ::v8::Local;
67 using ::v8::Message;
68 using ::v8::MessageCallback;
69 using ::v8::Object;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::Script;
73 using ::v8::StackTrace;
74 using ::v8::String;
75 using ::v8::TryCatch;
76 using ::v8::Undefined;
77 using ::v8::UniqueId;
78 using ::v8::V8;
79 using ::v8::Value;
80
81
82 #define THREADED_PROFILED_TEST(Name)                                 \
83   static void Test##Name();                                          \
84   TEST(Name##WithProfiler) {                                         \
85     RunWithProfiler(&Test##Name);                                    \
86   }                                                                  \
87   THREADED_TEST(Name)
88
89 void RunWithProfiler(void (*test)()) {
90   LocalContext env;
91   v8::HandleScope scope(env->GetIsolate());
92   v8::Local<v8::String> profile_name = v8::String::New("my_profile1");
93   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
94
95   cpu_profiler->StartCpuProfiling(profile_name);
96   (*test)();
97   cpu_profiler->DeleteAllCpuProfiles();
98 }
99
100
101 static void ExpectString(const char* code, const char* expected) {
102   Local<Value> result = CompileRun(code);
103   CHECK(result->IsString());
104   String::Utf8Value utf8(result);
105   CHECK_EQ(expected, *utf8);
106 }
107
108
109 static void ExpectInt32(const char* code, int expected) {
110   Local<Value> result = CompileRun(code);
111   CHECK(result->IsInt32());
112   CHECK_EQ(expected, result->Int32Value());
113 }
114
115
116 static void ExpectBoolean(const char* code, bool expected) {
117   Local<Value> result = CompileRun(code);
118   CHECK(result->IsBoolean());
119   CHECK_EQ(expected, result->BooleanValue());
120 }
121
122
123 static void ExpectTrue(const char* code) {
124   ExpectBoolean(code, true);
125 }
126
127
128 static void ExpectFalse(const char* code) {
129   ExpectBoolean(code, false);
130 }
131
132
133 static void ExpectObject(const char* code, Local<Value> expected) {
134   Local<Value> result = CompileRun(code);
135   CHECK(result->Equals(expected));
136 }
137
138
139 static void ExpectUndefined(const char* code) {
140   Local<Value> result = CompileRun(code);
141   CHECK(result->IsUndefined());
142 }
143
144
145 static int signature_callback_count;
146 static void IncrementingSignatureCallback(
147     const v8::FunctionCallbackInfo<v8::Value>& args) {
148   ApiTestFuzzer::Fuzz();
149   signature_callback_count++;
150   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
151   for (int i = 0; i < args.Length(); i++)
152     result->Set(v8::Integer::New(i), args[i]);
153   args.GetReturnValue().Set(result);
154 }
155
156
157 static void SignatureCallback(
158     const v8::FunctionCallbackInfo<v8::Value>& args) {
159   ApiTestFuzzer::Fuzz();
160   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
161   for (int i = 0; i < args.Length(); i++) {
162     result->Set(v8::Integer::New(i), args[i]);
163   }
164   args.GetReturnValue().Set(result);
165 }
166
167
168 THREADED_TEST(Handles) {
169   v8::HandleScope scope(v8::Isolate::GetCurrent());
170   Local<Context> local_env;
171   {
172     LocalContext env;
173     local_env = env.local();
174   }
175
176   // Local context should still be live.
177   CHECK(!local_env.IsEmpty());
178   local_env->Enter();
179
180   v8::Handle<v8::Primitive> undef = v8::Undefined();
181   CHECK(!undef.IsEmpty());
182   CHECK(undef->IsUndefined());
183
184   const char* c_source = "1 + 2 + 3";
185   Local<String> source = String::New(c_source);
186   Local<Script> script = Script::Compile(source);
187   CHECK_EQ(6, script->Run()->Int32Value());
188
189   local_env->Exit();
190 }
191
192
193 THREADED_TEST(IsolateOfContext) {
194   v8::HandleScope scope(v8::Isolate::GetCurrent());
195   v8::Handle<Context> env = Context::New(v8::Isolate::GetCurrent());
196
197   CHECK(!env->InContext());
198   CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
199   env->Enter();
200   CHECK(env->InContext());
201   CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
202   env->Exit();
203   CHECK(!env->InContext());
204   CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
205 }
206
207
208 THREADED_TEST(ReceiverSignature) {
209   LocalContext env;
210   v8::HandleScope scope(env->GetIsolate());
211   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
212   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
213   fun->PrototypeTemplate()->Set(
214       v8_str("m"),
215       v8::FunctionTemplate::New(IncrementingSignatureCallback,
216                                 v8::Handle<Value>(),
217                                 sig));
218   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
219   signature_callback_count = 0;
220   CompileRun(
221       "var o = new Fun();"
222       "o.m();");
223   CHECK_EQ(1, signature_callback_count);
224   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
225   sub_fun->Inherit(fun);
226   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
227   CompileRun(
228       "var o = new SubFun();"
229       "o.m();");
230   CHECK_EQ(2, signature_callback_count);
231
232   v8::TryCatch try_catch;
233   CompileRun(
234       "var o = { };"
235       "o.m = Fun.prototype.m;"
236       "o.m();");
237   CHECK_EQ(2, signature_callback_count);
238   CHECK(try_catch.HasCaught());
239   try_catch.Reset();
240   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
241   sub_fun->Inherit(fun);
242   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
243   CompileRun(
244       "var o = new UnrelFun();"
245       "o.m = Fun.prototype.m;"
246       "o.m();");
247   CHECK_EQ(2, signature_callback_count);
248   CHECK(try_catch.HasCaught());
249 }
250
251
252 THREADED_TEST(ArgumentSignature) {
253   LocalContext env;
254   v8::HandleScope scope(env->GetIsolate());
255   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
256   cons->SetClassName(v8_str("Cons"));
257   v8::Handle<v8::Signature> sig =
258       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
259   v8::Handle<v8::FunctionTemplate> fun =
260       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
261   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
262   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
263
264   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
265   CHECK(value1->IsTrue());
266
267   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
268   CHECK(value2->IsTrue());
269
270   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
271   CHECK(value3->IsTrue());
272
273   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
274   cons1->SetClassName(v8_str("Cons1"));
275   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
276   cons2->SetClassName(v8_str("Cons2"));
277   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
278   cons3->SetClassName(v8_str("Cons3"));
279
280   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
281   v8::Handle<v8::Signature> wsig =
282       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
283   v8::Handle<v8::FunctionTemplate> fun2 =
284       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
285
286   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
287   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
288   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
289   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
290   v8::Handle<Value> value4 = CompileRun(
291       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
292       "'[object Cons1],[object Cons2],[object Cons3]'");
293   CHECK(value4->IsTrue());
294
295   v8::Handle<Value> value5 = CompileRun(
296       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
297   CHECK(value5->IsTrue());
298
299   v8::Handle<Value> value6 = CompileRun(
300       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
301   CHECK(value6->IsTrue());
302
303   v8::Handle<Value> value7 = CompileRun(
304       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
305       "'[object Cons1],[object Cons2],[object Cons3],d';");
306   CHECK(value7->IsTrue());
307
308   v8::Handle<Value> value8 = CompileRun(
309       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
310   CHECK(value8->IsTrue());
311 }
312
313
314 THREADED_TEST(HulIgennem) {
315   LocalContext env;
316   v8::HandleScope scope(env->GetIsolate());
317   v8::Handle<v8::Primitive> undef = v8::Undefined();
318   Local<String> undef_str = undef->ToString();
319   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
320   undef_str->WriteUtf8(value);
321   CHECK_EQ(0, strcmp(value, "undefined"));
322   i::DeleteArray(value);
323 }
324
325
326 THREADED_TEST(Access) {
327   LocalContext env;
328   v8::HandleScope scope(env->GetIsolate());
329   Local<v8::Object> obj = v8::Object::New();
330   Local<Value> foo_before = obj->Get(v8_str("foo"));
331   CHECK(foo_before->IsUndefined());
332   Local<String> bar_str = v8_str("bar");
333   obj->Set(v8_str("foo"), bar_str);
334   Local<Value> foo_after = obj->Get(v8_str("foo"));
335   CHECK(!foo_after->IsUndefined());
336   CHECK(foo_after->IsString());
337   CHECK_EQ(bar_str, foo_after);
338 }
339
340
341 THREADED_TEST(AccessElement) {
342   LocalContext env;
343   v8::HandleScope scope(env->GetIsolate());
344   Local<v8::Object> obj = v8::Object::New();
345   Local<Value> before = obj->Get(1);
346   CHECK(before->IsUndefined());
347   Local<String> bar_str = v8_str("bar");
348   obj->Set(1, bar_str);
349   Local<Value> after = obj->Get(1);
350   CHECK(!after->IsUndefined());
351   CHECK(after->IsString());
352   CHECK_EQ(bar_str, after);
353
354   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
355   CHECK_EQ(v8_str("a"), value->Get(0));
356   CHECK_EQ(v8_str("b"), value->Get(1));
357 }
358
359
360 THREADED_TEST(Script) {
361   LocalContext env;
362   v8::HandleScope scope(env->GetIsolate());
363   const char* c_source = "1 + 2 + 3";
364   Local<String> source = String::New(c_source);
365   Local<Script> script = Script::Compile(source);
366   CHECK_EQ(6, script->Run()->Int32Value());
367 }
368
369
370 static uint16_t* AsciiToTwoByteString(const char* source) {
371   int array_length = i::StrLength(source) + 1;
372   uint16_t* converted = i::NewArray<uint16_t>(array_length);
373   for (int i = 0; i < array_length; i++) converted[i] = source[i];
374   return converted;
375 }
376
377
378 class TestResource: public String::ExternalStringResource {
379  public:
380   explicit TestResource(uint16_t* data, int* counter = NULL)
381     : data_(data), length_(0), counter_(counter) {
382     while (data[length_]) ++length_;
383   }
384
385   ~TestResource() {
386     i::DeleteArray(data_);
387     if (counter_ != NULL) ++*counter_;
388   }
389
390   const uint16_t* data() const {
391     return data_;
392   }
393
394   size_t length() const {
395     return length_;
396   }
397  private:
398   uint16_t* data_;
399   size_t length_;
400   int* counter_;
401 };
402
403
404 class TestAsciiResource: public String::ExternalAsciiStringResource {
405  public:
406   explicit TestAsciiResource(const char* data, int* counter = NULL)
407     : data_(data), length_(strlen(data)), counter_(counter) { }
408
409   ~TestAsciiResource() {
410     i::DeleteArray(data_);
411     if (counter_ != NULL) ++*counter_;
412   }
413
414   const char* data() const {
415     return data_;
416   }
417
418   size_t length() const {
419     return length_;
420   }
421  private:
422   const char* data_;
423   size_t length_;
424   int* counter_;
425 };
426
427
428 THREADED_TEST(ScriptUsingStringResource) {
429   int dispose_count = 0;
430   const char* c_source = "1 + 2 * 3";
431   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
432   {
433     LocalContext env;
434     v8::HandleScope scope(env->GetIsolate());
435     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
436     Local<String> source = String::NewExternal(resource);
437     Local<Script> script = Script::Compile(source);
438     Local<Value> value = script->Run();
439     CHECK(value->IsNumber());
440     CHECK_EQ(7, value->Int32Value());
441     CHECK(source->IsExternal());
442     CHECK_EQ(resource,
443              static_cast<TestResource*>(source->GetExternalStringResource()));
444     String::Encoding encoding = String::UNKNOWN_ENCODING;
445     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
446              source->GetExternalStringResourceBase(&encoding));
447     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
448     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
449     CHECK_EQ(0, dispose_count);
450   }
451   v8::internal::Isolate::Current()->compilation_cache()->Clear();
452   HEAP->CollectAllAvailableGarbage();
453   CHECK_EQ(1, dispose_count);
454 }
455
456
457 THREADED_TEST(ScriptUsingAsciiStringResource) {
458   int dispose_count = 0;
459   const char* c_source = "1 + 2 * 3";
460   {
461     LocalContext env;
462     v8::HandleScope scope(env->GetIsolate());
463     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
464                                                         &dispose_count);
465     Local<String> source = String::NewExternal(resource);
466     CHECK(source->IsExternalAscii());
467     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
468              source->GetExternalAsciiStringResource());
469     String::Encoding encoding = String::UNKNOWN_ENCODING;
470     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
471              source->GetExternalStringResourceBase(&encoding));
472     CHECK_EQ(String::ASCII_ENCODING, encoding);
473     Local<Script> script = Script::Compile(source);
474     Local<Value> value = script->Run();
475     CHECK(value->IsNumber());
476     CHECK_EQ(7, value->Int32Value());
477     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
478     CHECK_EQ(0, dispose_count);
479   }
480   i::Isolate::Current()->compilation_cache()->Clear();
481   HEAP->CollectAllAvailableGarbage();
482   CHECK_EQ(1, dispose_count);
483 }
484
485
486 THREADED_TEST(ScriptMakingExternalString) {
487   int dispose_count = 0;
488   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
489   {
490     LocalContext env;
491     v8::HandleScope scope(env->GetIsolate());
492     Local<String> source = String::New(two_byte_source);
493     // Trigger GCs so that the newly allocated string moves to old gen.
494     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
495     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
496     CHECK_EQ(source->IsExternal(), false);
497     CHECK_EQ(source->IsExternalAscii(), false);
498     String::Encoding encoding = String::UNKNOWN_ENCODING;
499     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
500     CHECK_EQ(String::ASCII_ENCODING, encoding);
501     bool success = source->MakeExternal(new TestResource(two_byte_source,
502                                                          &dispose_count));
503     CHECK(success);
504     Local<Script> script = Script::Compile(source);
505     Local<Value> value = script->Run();
506     CHECK(value->IsNumber());
507     CHECK_EQ(7, value->Int32Value());
508     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
509     CHECK_EQ(0, dispose_count);
510   }
511   i::Isolate::Current()->compilation_cache()->Clear();
512   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
513   CHECK_EQ(1, dispose_count);
514 }
515
516
517 THREADED_TEST(ScriptMakingExternalAsciiString) {
518   int dispose_count = 0;
519   const char* c_source = "1 + 2 * 3";
520   {
521     LocalContext env;
522     v8::HandleScope scope(env->GetIsolate());
523     Local<String> source = v8_str(c_source);
524     // Trigger GCs so that the newly allocated string moves to old gen.
525     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
526     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
527     bool success = source->MakeExternal(
528         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
529     CHECK(success);
530     Local<Script> script = Script::Compile(source);
531     Local<Value> value = script->Run();
532     CHECK(value->IsNumber());
533     CHECK_EQ(7, value->Int32Value());
534     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
535     CHECK_EQ(0, dispose_count);
536   }
537   i::Isolate::Current()->compilation_cache()->Clear();
538   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
539   CHECK_EQ(1, dispose_count);
540 }
541
542
543 TEST(MakingExternalStringConditions) {
544   LocalContext env;
545   v8::HandleScope scope(env->GetIsolate());
546
547   // Free some space in the new space so that we can check freshness.
548   HEAP->CollectGarbage(i::NEW_SPACE);
549   HEAP->CollectGarbage(i::NEW_SPACE);
550
551   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
552   Local<String> small_string = String::New(two_byte_string);
553   i::DeleteArray(two_byte_string);
554
555   // We should refuse to externalize newly created small string.
556   CHECK(!small_string->CanMakeExternal());
557   // Trigger GCs so that the newly allocated string moves to old gen.
558   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
559   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
560   // Old space strings should be accepted.
561   CHECK(small_string->CanMakeExternal());
562
563   two_byte_string = AsciiToTwoByteString("small string 2");
564   small_string = String::New(two_byte_string);
565   i::DeleteArray(two_byte_string);
566
567   // We should refuse externalizing newly created small string.
568   CHECK(!small_string->CanMakeExternal());
569   for (int i = 0; i < 100; i++) {
570     String::Value value(small_string);
571   }
572   // Frequently used strings should be accepted.
573   CHECK(small_string->CanMakeExternal());
574
575   const int buf_size = 10 * 1024;
576   char* buf = i::NewArray<char>(buf_size);
577   memset(buf, 'a', buf_size);
578   buf[buf_size - 1] = '\0';
579
580   two_byte_string = AsciiToTwoByteString(buf);
581   Local<String> large_string = String::New(two_byte_string);
582   i::DeleteArray(buf);
583   i::DeleteArray(two_byte_string);
584   // Large strings should be immediately accepted.
585   CHECK(large_string->CanMakeExternal());
586 }
587
588
589 TEST(MakingExternalAsciiStringConditions) {
590   LocalContext env;
591   v8::HandleScope scope(env->GetIsolate());
592
593   // Free some space in the new space so that we can check freshness.
594   HEAP->CollectGarbage(i::NEW_SPACE);
595   HEAP->CollectGarbage(i::NEW_SPACE);
596
597   Local<String> small_string = String::New("s1");
598   // We should refuse to externalize newly created small string.
599   CHECK(!small_string->CanMakeExternal());
600   // Trigger GCs so that the newly allocated string moves to old gen.
601   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
602   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
603   // Old space strings should be accepted.
604   CHECK(small_string->CanMakeExternal());
605
606   small_string = String::New("small string 2");
607   // We should refuse externalizing newly created small string.
608   CHECK(!small_string->CanMakeExternal());
609   for (int i = 0; i < 100; i++) {
610     String::Value value(small_string);
611   }
612   // Frequently used strings should be accepted.
613   CHECK(small_string->CanMakeExternal());
614
615   const int buf_size = 10 * 1024;
616   char* buf = i::NewArray<char>(buf_size);
617   memset(buf, 'a', buf_size);
618   buf[buf_size - 1] = '\0';
619   Local<String> large_string = String::New(buf);
620   i::DeleteArray(buf);
621   // Large strings should be immediately accepted.
622   CHECK(large_string->CanMakeExternal());
623 }
624
625
626 TEST(MakingExternalUnalignedAsciiString) {
627   LocalContext env;
628   v8::HandleScope scope(env->GetIsolate());
629
630   CompileRun("function cons(a, b) { return a + b; }"
631              "function slice(a) { return a.substring(1); }");
632   // Create a cons string that will land in old pointer space.
633   Local<String> cons = Local<String>::Cast(CompileRun(
634       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
635   // Create a sliced string that will land in old pointer space.
636   Local<String> slice = Local<String>::Cast(CompileRun(
637       "slice('abcdefghijklmnopqrstuvwxyz');"));
638
639   // Trigger GCs so that the newly allocated string moves to old gen.
640   SimulateFullSpace(HEAP->old_pointer_space());
641   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
642   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
643
644   // Turn into external string with unaligned resource data.
645   int dispose_count = 0;
646   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
647   bool success = cons->MakeExternal(
648       new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
649   CHECK(success);
650   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
651   success = slice->MakeExternal(
652       new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
653   CHECK(success);
654
655   // Trigger GCs and force evacuation.
656   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
657   HEAP->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
658 }
659
660
661 THREADED_TEST(UsingExternalString) {
662   i::Factory* factory = i::Isolate::Current()->factory();
663   {
664     v8::HandleScope scope(v8::Isolate::GetCurrent());
665     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
666     Local<String> string =
667         String::NewExternal(new TestResource(two_byte_string));
668     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
669     // Trigger GCs so that the newly allocated string moves to old gen.
670     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
671     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
672     i::Handle<i::String> isymbol =
673         factory->InternalizedStringFromString(istring);
674     CHECK(isymbol->IsInternalizedString());
675   }
676   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
677   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
678 }
679
680
681 THREADED_TEST(UsingExternalAsciiString) {
682   i::Factory* factory = i::Isolate::Current()->factory();
683   {
684     v8::HandleScope scope(v8::Isolate::GetCurrent());
685     const char* one_byte_string = "test string";
686     Local<String> string = String::NewExternal(
687         new TestAsciiResource(i::StrDup(one_byte_string)));
688     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
689     // Trigger GCs so that the newly allocated string moves to old gen.
690     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
691     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
692     i::Handle<i::String> isymbol =
693         factory->InternalizedStringFromString(istring);
694     CHECK(isymbol->IsInternalizedString());
695   }
696   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
697   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
698 }
699
700
701 THREADED_TEST(ScavengeExternalString) {
702   i::FLAG_stress_compaction = false;
703   i::FLAG_gc_global = false;
704   int dispose_count = 0;
705   bool in_new_space = false;
706   {
707     v8::HandleScope scope(v8::Isolate::GetCurrent());
708     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
709     Local<String> string =
710       String::NewExternal(new TestResource(two_byte_string,
711                                            &dispose_count));
712     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713     HEAP->CollectGarbage(i::NEW_SPACE);
714     in_new_space = HEAP->InNewSpace(*istring);
715     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
716     CHECK_EQ(0, dispose_count);
717   }
718   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
719   CHECK_EQ(1, dispose_count);
720 }
721
722
723 THREADED_TEST(ScavengeExternalAsciiString) {
724   i::FLAG_stress_compaction = false;
725   i::FLAG_gc_global = false;
726   int dispose_count = 0;
727   bool in_new_space = false;
728   {
729     v8::HandleScope scope(v8::Isolate::GetCurrent());
730     const char* one_byte_string = "test string";
731     Local<String> string = String::NewExternal(
732         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
733     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
734     HEAP->CollectGarbage(i::NEW_SPACE);
735     in_new_space = HEAP->InNewSpace(*istring);
736     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
737     CHECK_EQ(0, dispose_count);
738   }
739   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
740   CHECK_EQ(1, dispose_count);
741 }
742
743
744 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
745  public:
746   // Only used by non-threaded tests, so it can use static fields.
747   static int dispose_calls;
748   static int dispose_count;
749
750   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
751       : TestAsciiResource(data, &dispose_count),
752         dispose_(dispose) { }
753
754   void Dispose() {
755     ++dispose_calls;
756     if (dispose_) delete this;
757   }
758  private:
759   bool dispose_;
760 };
761
762
763 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
764 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
765
766
767 TEST(ExternalStringWithDisposeHandling) {
768   const char* c_source = "1 + 2 * 3";
769
770   // Use a stack allocated external string resource allocated object.
771   TestAsciiResourceWithDisposeControl::dispose_count = 0;
772   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
773   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
774   {
775     LocalContext env;
776     v8::HandleScope scope(env->GetIsolate());
777     Local<String> source =  String::NewExternal(&res_stack);
778     Local<Script> script = Script::Compile(source);
779     Local<Value> value = script->Run();
780     CHECK(value->IsNumber());
781     CHECK_EQ(7, value->Int32Value());
782     HEAP->CollectAllAvailableGarbage();
783     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
784   }
785   i::Isolate::Current()->compilation_cache()->Clear();
786   HEAP->CollectAllAvailableGarbage();
787   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
788   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
789
790   // Use a heap allocated external string resource allocated object.
791   TestAsciiResourceWithDisposeControl::dispose_count = 0;
792   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
793   TestAsciiResource* res_heap =
794       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
795   {
796     LocalContext env;
797     v8::HandleScope scope(env->GetIsolate());
798     Local<String> source =  String::NewExternal(res_heap);
799     Local<Script> script = Script::Compile(source);
800     Local<Value> value = script->Run();
801     CHECK(value->IsNumber());
802     CHECK_EQ(7, value->Int32Value());
803     HEAP->CollectAllAvailableGarbage();
804     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
805   }
806   i::Isolate::Current()->compilation_cache()->Clear();
807   HEAP->CollectAllAvailableGarbage();
808   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
809   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
810 }
811
812
813 THREADED_TEST(StringConcat) {
814   {
815     LocalContext env;
816     v8::HandleScope scope(env->GetIsolate());
817     const char* one_byte_string_1 = "function a_times_t";
818     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
819     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
820     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
821     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
822     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
823     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
824     Local<String> left = v8_str(one_byte_string_1);
825
826     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
827     Local<String> right = String::New(two_byte_source);
828     i::DeleteArray(two_byte_source);
829
830     Local<String> source = String::Concat(left, right);
831     right = String::NewExternal(
832         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
833     source = String::Concat(source, right);
834     right = String::NewExternal(
835         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
836     source = String::Concat(source, right);
837     right = v8_str(one_byte_string_2);
838     source = String::Concat(source, right);
839
840     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
841     right = String::New(two_byte_source);
842     i::DeleteArray(two_byte_source);
843
844     source = String::Concat(source, right);
845     right = String::NewExternal(
846         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
847     source = String::Concat(source, right);
848     Local<Script> script = Script::Compile(source);
849     Local<Value> value = script->Run();
850     CHECK(value->IsNumber());
851     CHECK_EQ(68, value->Int32Value());
852   }
853   i::Isolate::Current()->compilation_cache()->Clear();
854   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
855   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
856 }
857
858
859 THREADED_TEST(GlobalProperties) {
860   LocalContext env;
861   v8::HandleScope scope(env->GetIsolate());
862   v8::Handle<v8::Object> global = env->Global();
863   global->Set(v8_str("pi"), v8_num(3.1415926));
864   Local<Value> pi = global->Get(v8_str("pi"));
865   CHECK_EQ(3.1415926, pi->NumberValue());
866 }
867
868
869 template<typename T>
870 static void CheckReturnValue(const T& t, i::Address callback) {
871   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
872   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
873   CHECK_EQ(v8::Isolate::GetCurrent(), t.GetIsolate());
874   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
875   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
876   // Verify reset
877   bool is_runtime = (*o)->IsTheHole();
878   rv.Set(true);
879   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
880   rv.Set(v8::Handle<v8::Object>());
881   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
882   CHECK_EQ(is_runtime, (*o)->IsTheHole());
883
884   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
885   // If CPU profiler is active check that when API callback is invoked
886   // VMState is set to EXTERNAL.
887   if (isolate->cpu_profiler()->is_profiling()) {
888     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
889     CHECK(isolate->external_callback_scope());
890     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
891   }
892 }
893
894
895 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
896                                  i::Address callback) {
897   ApiTestFuzzer::Fuzz();
898   CheckReturnValue(info, callback);
899   info.GetReturnValue().Set(v8_str("bad value"));
900   info.GetReturnValue().Set(v8_num(102));
901 }
902
903
904 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
905   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
906 }
907
908
909 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
910   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
911 }
912
913 static void construct_callback(
914     const v8::FunctionCallbackInfo<Value>& info) {
915   ApiTestFuzzer::Fuzz();
916   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
917   info.This()->Set(v8_str("x"), v8_num(1));
918   info.This()->Set(v8_str("y"), v8_num(2));
919   info.GetReturnValue().Set(v8_str("bad value"));
920   info.GetReturnValue().Set(info.This());
921 }
922
923
924 static void Return239Callback(
925     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
926   ApiTestFuzzer::Fuzz();
927   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
928   info.GetReturnValue().Set(v8_str("bad value"));
929   info.GetReturnValue().Set(v8_num(239));
930 }
931
932
933 template<typename Handler>
934 static void TestFunctionTemplateInitializer(Handler handler,
935                                             Handler handler_2) {
936   // Test constructor calls.
937   {
938     LocalContext env;
939     v8::HandleScope scope(env->GetIsolate());
940
941     Local<v8::FunctionTemplate> fun_templ =
942         v8::FunctionTemplate::New(handler);
943     Local<Function> fun = fun_templ->GetFunction();
944     env->Global()->Set(v8_str("obj"), fun);
945     Local<Script> script = v8_compile("obj()");
946     for (int i = 0; i < 30; i++) {
947       CHECK_EQ(102, script->Run()->Int32Value());
948     }
949   }
950   // Use SetCallHandler to initialize a function template, should work like
951   // the previous one.
952   {
953     LocalContext env;
954     v8::HandleScope scope(env->GetIsolate());
955
956     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
957     fun_templ->SetCallHandler(handler_2);
958     Local<Function> fun = fun_templ->GetFunction();
959     env->Global()->Set(v8_str("obj"), fun);
960     Local<Script> script = v8_compile("obj()");
961     for (int i = 0; i < 30; i++) {
962       CHECK_EQ(102, script->Run()->Int32Value());
963     }
964   }
965 }
966
967
968 template<typename Constructor, typename Accessor>
969 static void TestFunctionTemplateAccessor(Constructor constructor,
970                                          Accessor accessor) {
971   LocalContext env;
972   v8::HandleScope scope(env->GetIsolate());
973
974   Local<v8::FunctionTemplate> fun_templ =
975       v8::FunctionTemplate::New(constructor);
976   fun_templ->SetClassName(v8_str("funky"));
977   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
978   Local<Function> fun = fun_templ->GetFunction();
979   env->Global()->Set(v8_str("obj"), fun);
980   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
981   CHECK_EQ(v8_str("[object funky]"), result);
982   CompileRun("var obj_instance = new obj();");
983   Local<Script> script;
984   script = v8_compile("obj_instance.x");
985   for (int i = 0; i < 30; i++) {
986     CHECK_EQ(1, script->Run()->Int32Value());
987   }
988   script = v8_compile("obj_instance.m");
989   for (int i = 0; i < 30; i++) {
990     CHECK_EQ(239, script->Run()->Int32Value());
991   }
992 }
993
994
995 THREADED_PROFILED_TEST(FunctionTemplate) {
996   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
997   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
998 }
999
1000
1001 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1002   ApiTestFuzzer::Fuzz();
1003   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1004   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1005 }
1006
1007
1008 template<typename Callback>
1009 static void TestSimpleCallback(Callback callback) {
1010   LocalContext env;
1011   v8::HandleScope scope(env->GetIsolate());
1012
1013   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1014   object_template->Set("callback", v8::FunctionTemplate::New(callback));
1015   v8::Local<v8::Object> object = object_template->NewInstance();
1016   (*env)->Global()->Set(v8_str("callback_object"), object);
1017   v8::Handle<v8::Script> script;
1018   script = v8_compile("callback_object.callback(17)");
1019   for (int i = 0; i < 30; i++) {
1020     CHECK_EQ(51424, script->Run()->Int32Value());
1021   }
1022   script = v8_compile("callback_object.callback(17, 24)");
1023   for (int i = 0; i < 30; i++) {
1024     CHECK_EQ(51425, script->Run()->Int32Value());
1025   }
1026 }
1027
1028
1029 THREADED_PROFILED_TEST(SimpleCallback) {
1030   TestSimpleCallback(SimpleCallback);
1031 }
1032
1033
1034 template<typename T>
1035 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1036
1037 // constant return values
1038 static int32_t fast_return_value_int32 = 471;
1039 static uint32_t fast_return_value_uint32 = 571;
1040 static const double kFastReturnValueDouble = 2.7;
1041 // variable return values
1042 static bool fast_return_value_bool = false;
1043 enum ReturnValueOddball {
1044   kNullReturnValue,
1045   kUndefinedReturnValue,
1046   kEmptyStringReturnValue
1047 };
1048 static ReturnValueOddball fast_return_value_void;
1049 static bool fast_return_value_object_is_empty = false;
1050
1051 // Helper function to avoid compiler error: insufficient contextual information
1052 // to determine type when applying FUNCTION_ADDR to a template function.
1053 static i::Address address_of(v8::FunctionCallback callback) {
1054   return FUNCTION_ADDR(callback);
1055 }
1056
1057 template<>
1058 void FastReturnValueCallback<int32_t>(
1059     const v8::FunctionCallbackInfo<v8::Value>& info) {
1060   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1061   info.GetReturnValue().Set(fast_return_value_int32);
1062 }
1063
1064 template<>
1065 void FastReturnValueCallback<uint32_t>(
1066     const v8::FunctionCallbackInfo<v8::Value>& info) {
1067   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1068   info.GetReturnValue().Set(fast_return_value_uint32);
1069 }
1070
1071 template<>
1072 void FastReturnValueCallback<double>(
1073     const v8::FunctionCallbackInfo<v8::Value>& info) {
1074   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1075   info.GetReturnValue().Set(kFastReturnValueDouble);
1076 }
1077
1078 template<>
1079 void FastReturnValueCallback<bool>(
1080     const v8::FunctionCallbackInfo<v8::Value>& info) {
1081   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1082   info.GetReturnValue().Set(fast_return_value_bool);
1083 }
1084
1085 template<>
1086 void FastReturnValueCallback<void>(
1087     const v8::FunctionCallbackInfo<v8::Value>& info) {
1088   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1089   switch (fast_return_value_void) {
1090     case kNullReturnValue:
1091       info.GetReturnValue().SetNull();
1092       break;
1093     case kUndefinedReturnValue:
1094       info.GetReturnValue().SetUndefined();
1095       break;
1096     case kEmptyStringReturnValue:
1097       info.GetReturnValue().SetEmptyString();
1098       break;
1099   }
1100 }
1101
1102 template<>
1103 void FastReturnValueCallback<Object>(
1104     const v8::FunctionCallbackInfo<v8::Value>& info) {
1105   v8::Handle<v8::Object> object;
1106   if (!fast_return_value_object_is_empty) object = Object::New();
1107   info.GetReturnValue().Set(object);
1108 }
1109
1110 template<typename T>
1111 Handle<Value> TestFastReturnValues() {
1112   LocalContext env;
1113   v8::HandleScope scope(env->GetIsolate());
1114   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1115   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1116   object_template->Set("callback", v8::FunctionTemplate::New(callback));
1117   v8::Local<v8::Object> object = object_template->NewInstance();
1118   (*env)->Global()->Set(v8_str("callback_object"), object);
1119   return scope.Close(CompileRun("callback_object.callback()"));
1120 }
1121
1122
1123 THREADED_PROFILED_TEST(FastReturnValues) {
1124   LocalContext env;
1125   v8::HandleScope scope(v8::Isolate::GetCurrent());
1126   v8::Handle<v8::Value> value;
1127   // check int32_t and uint32_t
1128   int32_t int_values[] = {
1129       0, 234, -723,
1130       i::Smi::kMinValue, i::Smi::kMaxValue
1131   };
1132   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1133     for (int modifier = -1; modifier <= 1; modifier++) {
1134       int int_value = int_values[i] + modifier;
1135       // check int32_t
1136       fast_return_value_int32 = int_value;
1137       value = TestFastReturnValues<int32_t>();
1138       CHECK(value->IsInt32());
1139       CHECK(fast_return_value_int32 == value->Int32Value());
1140       // check uint32_t
1141       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1142       value = TestFastReturnValues<uint32_t>();
1143       CHECK(value->IsUint32());
1144       CHECK(fast_return_value_uint32 == value->Uint32Value());
1145     }
1146   }
1147   // check double
1148   value = TestFastReturnValues<double>();
1149   CHECK(value->IsNumber());
1150   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1151   // check bool values
1152   for (int i = 0; i < 2; i++) {
1153     fast_return_value_bool = i == 0;
1154     value = TestFastReturnValues<bool>();
1155     CHECK(value->IsBoolean());
1156     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1157   }
1158   // check oddballs
1159   ReturnValueOddball oddballs[] = {
1160       kNullReturnValue,
1161       kUndefinedReturnValue,
1162       kEmptyStringReturnValue
1163   };
1164   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1165     fast_return_value_void = oddballs[i];
1166     value = TestFastReturnValues<void>();
1167     switch (fast_return_value_void) {
1168       case kNullReturnValue:
1169         CHECK(value->IsNull());
1170         break;
1171       case kUndefinedReturnValue:
1172         CHECK(value->IsUndefined());
1173         break;
1174       case kEmptyStringReturnValue:
1175         CHECK(value->IsString());
1176         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1177         break;
1178     }
1179   }
1180   // check handles
1181   fast_return_value_object_is_empty = false;
1182   value = TestFastReturnValues<Object>();
1183   CHECK(value->IsObject());
1184   fast_return_value_object_is_empty = true;
1185   value = TestFastReturnValues<Object>();
1186   CHECK(value->IsUndefined());
1187 }
1188
1189
1190 THREADED_TEST(FunctionTemplateSetLength) {
1191   LocalContext env;
1192   v8::HandleScope scope(env->GetIsolate());
1193   {
1194     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
1195         handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
1196     Local<Function> fun = fun_templ->GetFunction();
1197     env->Global()->Set(v8_str("obj"), fun);
1198     Local<Script> script = v8_compile("obj.length");
1199     CHECK_EQ(23, script->Run()->Int32Value());
1200   }
1201   {
1202     Local<v8::FunctionTemplate> fun_templ =
1203         v8::FunctionTemplate::New(handle_callback);
1204     fun_templ->SetLength(22);
1205     Local<Function> fun = fun_templ->GetFunction();
1206     env->Global()->Set(v8_str("obj"), fun);
1207     Local<Script> script = v8_compile("obj.length");
1208     CHECK_EQ(22, script->Run()->Int32Value());
1209   }
1210   {
1211     // Without setting length it defaults to 0.
1212     Local<v8::FunctionTemplate> fun_templ =
1213         v8::FunctionTemplate::New(handle_callback);
1214     Local<Function> fun = fun_templ->GetFunction();
1215     env->Global()->Set(v8_str("obj"), fun);
1216     Local<Script> script = v8_compile("obj.length");
1217     CHECK_EQ(0, script->Run()->Int32Value());
1218   }
1219 }
1220
1221
1222 static void* expected_ptr;
1223 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1224   void* ptr = v8::External::Cast(*args.Data())->Value();
1225   CHECK_EQ(expected_ptr, ptr);
1226   args.GetReturnValue().Set(true);
1227 }
1228
1229
1230 static void TestExternalPointerWrapping() {
1231   LocalContext env;
1232   v8::HandleScope scope(env->GetIsolate());
1233
1234   v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
1235
1236   v8::Handle<v8::Object> obj = v8::Object::New();
1237   obj->Set(v8_str("func"),
1238            v8::FunctionTemplate::New(callback, data)->GetFunction());
1239   env->Global()->Set(v8_str("obj"), obj);
1240
1241   CHECK(CompileRun(
1242         "function foo() {\n"
1243         "  for (var i = 0; i < 13; i++) obj.func();\n"
1244         "}\n"
1245         "foo(), true")->BooleanValue());
1246 }
1247
1248
1249 THREADED_TEST(ExternalWrap) {
1250   // Check heap allocated object.
1251   int* ptr = new int;
1252   expected_ptr = ptr;
1253   TestExternalPointerWrapping();
1254   delete ptr;
1255
1256   // Check stack allocated object.
1257   int foo;
1258   expected_ptr = &foo;
1259   TestExternalPointerWrapping();
1260
1261   // Check not aligned addresses.
1262   const int n = 100;
1263   char* s = new char[n];
1264   for (int i = 0; i < n; i++) {
1265     expected_ptr = s + i;
1266     TestExternalPointerWrapping();
1267   }
1268
1269   delete[] s;
1270
1271   // Check several invalid addresses.
1272   expected_ptr = reinterpret_cast<void*>(1);
1273   TestExternalPointerWrapping();
1274
1275   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1276   TestExternalPointerWrapping();
1277
1278   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1279   TestExternalPointerWrapping();
1280
1281 #if defined(V8_HOST_ARCH_X64)
1282   // Check a value with a leading 1 bit in x64 Smi encoding.
1283   expected_ptr = reinterpret_cast<void*>(0x400000000);
1284   TestExternalPointerWrapping();
1285
1286   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1287   TestExternalPointerWrapping();
1288
1289   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1290   TestExternalPointerWrapping();
1291 #endif
1292 }
1293
1294
1295 THREADED_TEST(FindInstanceInPrototypeChain) {
1296   LocalContext env;
1297   v8::HandleScope scope(env->GetIsolate());
1298
1299   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
1300   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
1301   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
1302   derived->Inherit(base);
1303
1304   Local<v8::Function> base_function = base->GetFunction();
1305   Local<v8::Function> derived_function = derived->GetFunction();
1306   Local<v8::Function> other_function = other->GetFunction();
1307
1308   Local<v8::Object> base_instance = base_function->NewInstance();
1309   Local<v8::Object> derived_instance = derived_function->NewInstance();
1310   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1311   Local<v8::Object> other_instance = other_function->NewInstance();
1312   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1313   other_instance->Set(v8_str("__proto__"), derived_instance2);
1314
1315   // base_instance is only an instance of base.
1316   CHECK_EQ(base_instance,
1317            base_instance->FindInstanceInPrototypeChain(base));
1318   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1319   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1320
1321   // derived_instance is an instance of base and derived.
1322   CHECK_EQ(derived_instance,
1323            derived_instance->FindInstanceInPrototypeChain(base));
1324   CHECK_EQ(derived_instance,
1325            derived_instance->FindInstanceInPrototypeChain(derived));
1326   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1327
1328   // other_instance is an instance of other and its immediate
1329   // prototype derived_instance2 is an instance of base and derived.
1330   // Note, derived_instance is an instance of base and derived too,
1331   // but it comes after derived_instance2 in the prototype chain of
1332   // other_instance.
1333   CHECK_EQ(derived_instance2,
1334            other_instance->FindInstanceInPrototypeChain(base));
1335   CHECK_EQ(derived_instance2,
1336            other_instance->FindInstanceInPrototypeChain(derived));
1337   CHECK_EQ(other_instance,
1338            other_instance->FindInstanceInPrototypeChain(other));
1339 }
1340
1341
1342 THREADED_TEST(TinyInteger) {
1343   LocalContext env;
1344   v8::HandleScope scope(env->GetIsolate());
1345   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1346
1347   int32_t value = 239;
1348   Local<v8::Integer> value_obj = v8::Integer::New(value);
1349   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1350
1351   value_obj = v8::Integer::New(value, isolate);
1352   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1353 }
1354
1355
1356 THREADED_TEST(BigSmiInteger) {
1357   LocalContext env;
1358   v8::HandleScope scope(env->GetIsolate());
1359   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1360
1361   int32_t value = i::Smi::kMaxValue;
1362   // We cannot add one to a Smi::kMaxValue without wrapping.
1363   if (i::kSmiValueSize < 32) {
1364     CHECK(i::Smi::IsValid(value));
1365     CHECK(!i::Smi::IsValid(value + 1));
1366
1367     Local<v8::Integer> value_obj = v8::Integer::New(value);
1368     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1369
1370     value_obj = v8::Integer::New(value, isolate);
1371     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1372   }
1373 }
1374
1375
1376 THREADED_TEST(BigInteger) {
1377   LocalContext env;
1378   v8::HandleScope scope(env->GetIsolate());
1379   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1380
1381   // We cannot add one to a Smi::kMaxValue without wrapping.
1382   if (i::kSmiValueSize < 32) {
1383     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1384     // The code will not be run in that case, due to the "if" guard.
1385     int32_t value =
1386         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1387     CHECK(value > i::Smi::kMaxValue);
1388     CHECK(!i::Smi::IsValid(value));
1389
1390     Local<v8::Integer> value_obj = v8::Integer::New(value);
1391     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1392
1393     value_obj = v8::Integer::New(value, isolate);
1394     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1395   }
1396 }
1397
1398
1399 THREADED_TEST(TinyUnsignedInteger) {
1400   LocalContext env;
1401   v8::HandleScope scope(env->GetIsolate());
1402   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1403
1404   uint32_t value = 239;
1405
1406   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1407   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1408
1409   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1410   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1411 }
1412
1413
1414 THREADED_TEST(BigUnsignedSmiInteger) {
1415   LocalContext env;
1416   v8::HandleScope scope(env->GetIsolate());
1417   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1418
1419   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1420   CHECK(i::Smi::IsValid(value));
1421   CHECK(!i::Smi::IsValid(value + 1));
1422
1423   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1424   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1425
1426   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1427   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1428 }
1429
1430
1431 THREADED_TEST(BigUnsignedInteger) {
1432   LocalContext env;
1433   v8::HandleScope scope(env->GetIsolate());
1434   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1435
1436   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1437   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1438   CHECK(!i::Smi::IsValid(value));
1439
1440   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1441   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1442
1443   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1444   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1445 }
1446
1447
1448 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1449   LocalContext env;
1450   v8::HandleScope scope(env->GetIsolate());
1451   v8::Isolate* isolate = v8::Isolate::GetCurrent();
1452
1453   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1454   uint32_t value = INT32_MAX_AS_UINT + 1;
1455   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1456
1457   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1458   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1459
1460   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1461   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1462 }
1463
1464
1465 THREADED_TEST(IsNativeError) {
1466   LocalContext env;
1467   v8::HandleScope scope(env->GetIsolate());
1468   v8::Handle<Value> syntax_error = CompileRun(
1469       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1470   CHECK(syntax_error->IsNativeError());
1471   v8::Handle<Value> not_error = CompileRun("{a:42}");
1472   CHECK(!not_error->IsNativeError());
1473   v8::Handle<Value> not_object = CompileRun("42");
1474   CHECK(!not_object->IsNativeError());
1475 }
1476
1477
1478 THREADED_TEST(StringObject) {
1479   LocalContext env;
1480   v8::HandleScope scope(env->GetIsolate());
1481   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1482   CHECK(boxed_string->IsStringObject());
1483   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1484   CHECK(!unboxed_string->IsStringObject());
1485   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1486   CHECK(!boxed_not_string->IsStringObject());
1487   v8::Handle<Value> not_object = CompileRun("0");
1488   CHECK(!not_object->IsStringObject());
1489   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1490   CHECK(!as_boxed.IsEmpty());
1491   Local<v8::String> the_string = as_boxed->ValueOf();
1492   CHECK(!the_string.IsEmpty());
1493   ExpectObject("\"test\"", the_string);
1494   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1495   CHECK(new_boxed_string->IsStringObject());
1496   as_boxed = new_boxed_string.As<v8::StringObject>();
1497   the_string = as_boxed->ValueOf();
1498   CHECK(!the_string.IsEmpty());
1499   ExpectObject("\"test\"", the_string);
1500 }
1501
1502
1503 THREADED_TEST(NumberObject) {
1504   LocalContext env;
1505   v8::HandleScope scope(env->GetIsolate());
1506   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1507   CHECK(boxed_number->IsNumberObject());
1508   v8::Handle<Value> unboxed_number = CompileRun("42");
1509   CHECK(!unboxed_number->IsNumberObject());
1510   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1511   CHECK(!boxed_not_number->IsNumberObject());
1512   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1513   CHECK(!as_boxed.IsEmpty());
1514   double the_number = as_boxed->ValueOf();
1515   CHECK_EQ(42.0, the_number);
1516   v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1517   CHECK(new_boxed_number->IsNumberObject());
1518   as_boxed = new_boxed_number.As<v8::NumberObject>();
1519   the_number = as_boxed->ValueOf();
1520   CHECK_EQ(43.0, the_number);
1521 }
1522
1523
1524 THREADED_TEST(BooleanObject) {
1525   LocalContext env;
1526   v8::HandleScope scope(env->GetIsolate());
1527   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1528   CHECK(boxed_boolean->IsBooleanObject());
1529   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1530   CHECK(!unboxed_boolean->IsBooleanObject());
1531   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1532   CHECK(!boxed_not_boolean->IsBooleanObject());
1533   v8::Handle<v8::BooleanObject> as_boxed =
1534       boxed_boolean.As<v8::BooleanObject>();
1535   CHECK(!as_boxed.IsEmpty());
1536   bool the_boolean = as_boxed->ValueOf();
1537   CHECK_EQ(true, the_boolean);
1538   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1539   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1540   CHECK(boxed_true->IsBooleanObject());
1541   CHECK(boxed_false->IsBooleanObject());
1542   as_boxed = boxed_true.As<v8::BooleanObject>();
1543   CHECK_EQ(true, as_boxed->ValueOf());
1544   as_boxed = boxed_false.As<v8::BooleanObject>();
1545   CHECK_EQ(false, as_boxed->ValueOf());
1546 }
1547
1548
1549 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1550   LocalContext env;
1551   v8::HandleScope scope(env->GetIsolate());
1552
1553   Local<Value> primitive_false = Boolean::New(false);
1554   CHECK(primitive_false->IsBoolean());
1555   CHECK(!primitive_false->IsBooleanObject());
1556   CHECK(!primitive_false->BooleanValue());
1557   CHECK(!primitive_false->IsTrue());
1558   CHECK(primitive_false->IsFalse());
1559
1560   Local<Value> false_value = BooleanObject::New(false);
1561   CHECK(!false_value->IsBoolean());
1562   CHECK(false_value->IsBooleanObject());
1563   CHECK(false_value->BooleanValue());
1564   CHECK(!false_value->IsTrue());
1565   CHECK(!false_value->IsFalse());
1566
1567   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1568   CHECK(!false_boolean_object->IsBoolean());
1569   CHECK(false_boolean_object->IsBooleanObject());
1570   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1571   // CHECK(false_boolean_object->BooleanValue());
1572   CHECK(!false_boolean_object->ValueOf());
1573   CHECK(!false_boolean_object->IsTrue());
1574   CHECK(!false_boolean_object->IsFalse());
1575
1576   Local<Value> primitive_true = Boolean::New(true);
1577   CHECK(primitive_true->IsBoolean());
1578   CHECK(!primitive_true->IsBooleanObject());
1579   CHECK(primitive_true->BooleanValue());
1580   CHECK(primitive_true->IsTrue());
1581   CHECK(!primitive_true->IsFalse());
1582
1583   Local<Value> true_value = BooleanObject::New(true);
1584   CHECK(!true_value->IsBoolean());
1585   CHECK(true_value->IsBooleanObject());
1586   CHECK(true_value->BooleanValue());
1587   CHECK(!true_value->IsTrue());
1588   CHECK(!true_value->IsFalse());
1589
1590   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1591   CHECK(!true_boolean_object->IsBoolean());
1592   CHECK(true_boolean_object->IsBooleanObject());
1593   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1594   // CHECK(true_boolean_object->BooleanValue());
1595   CHECK(true_boolean_object->ValueOf());
1596   CHECK(!true_boolean_object->IsTrue());
1597   CHECK(!true_boolean_object->IsFalse());
1598 }
1599
1600
1601 THREADED_TEST(Number) {
1602   LocalContext env;
1603   v8::HandleScope scope(env->GetIsolate());
1604   double PI = 3.1415926;
1605   Local<v8::Number> pi_obj = v8::Number::New(PI);
1606   CHECK_EQ(PI, pi_obj->NumberValue());
1607 }
1608
1609
1610 THREADED_TEST(ToNumber) {
1611   LocalContext env;
1612   v8::HandleScope scope(env->GetIsolate());
1613   Local<String> str = v8_str("3.1415926");
1614   CHECK_EQ(3.1415926, str->NumberValue());
1615   v8::Handle<v8::Boolean> t = v8::True();
1616   CHECK_EQ(1.0, t->NumberValue());
1617   v8::Handle<v8::Boolean> f = v8::False();
1618   CHECK_EQ(0.0, f->NumberValue());
1619 }
1620
1621
1622 THREADED_TEST(Date) {
1623   LocalContext env;
1624   v8::HandleScope scope(env->GetIsolate());
1625   double PI = 3.1415926;
1626   Local<Value> date = v8::Date::New(PI);
1627   CHECK_EQ(3.0, date->NumberValue());
1628   date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1629   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1630 }
1631
1632
1633 THREADED_TEST(Boolean) {
1634   LocalContext env;
1635   v8::HandleScope scope(env->GetIsolate());
1636   v8::Handle<v8::Boolean> t = v8::True();
1637   CHECK(t->Value());
1638   v8::Handle<v8::Boolean> f = v8::False();
1639   CHECK(!f->Value());
1640   v8::Handle<v8::Primitive> u = v8::Undefined();
1641   CHECK(!u->BooleanValue());
1642   v8::Handle<v8::Primitive> n = v8::Null();
1643   CHECK(!n->BooleanValue());
1644   v8::Handle<String> str1 = v8_str("");
1645   CHECK(!str1->BooleanValue());
1646   v8::Handle<String> str2 = v8_str("x");
1647   CHECK(str2->BooleanValue());
1648   CHECK(!v8::Number::New(0)->BooleanValue());
1649   CHECK(v8::Number::New(-1)->BooleanValue());
1650   CHECK(v8::Number::New(1)->BooleanValue());
1651   CHECK(v8::Number::New(42)->BooleanValue());
1652   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1653 }
1654
1655
1656 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1657   ApiTestFuzzer::Fuzz();
1658   args.GetReturnValue().Set(v8_num(13.4));
1659 }
1660
1661
1662 static void GetM(Local<String> name,
1663                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1664   ApiTestFuzzer::Fuzz();
1665   info.GetReturnValue().Set(v8_num(876));
1666 }
1667
1668
1669 THREADED_TEST(GlobalPrototype) {
1670   v8::HandleScope scope(v8::Isolate::GetCurrent());
1671   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1672   func_templ->PrototypeTemplate()->Set(
1673       "dummy",
1674       v8::FunctionTemplate::New(DummyCallHandler));
1675   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1676   templ->Set("x", v8_num(200));
1677   templ->SetAccessor(v8_str("m"), GetM);
1678   LocalContext env(0, templ);
1679   v8::Handle<Script> script(v8_compile("dummy()"));
1680   v8::Handle<Value> result(script->Run());
1681   CHECK_EQ(13.4, result->NumberValue());
1682   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1683   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1684 }
1685
1686
1687 THREADED_TEST(ObjectTemplate) {
1688   v8::HandleScope scope(v8::Isolate::GetCurrent());
1689   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1690   templ1->Set("x", v8_num(10));
1691   templ1->Set("y", v8_num(13));
1692   LocalContext env;
1693   Local<v8::Object> instance1 = templ1->NewInstance();
1694   env->Global()->Set(v8_str("p"), instance1);
1695   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1696   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1697   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1698   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1699   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1700   templ2->Set("a", v8_num(12));
1701   templ2->Set("b", templ1);
1702   Local<v8::Object> instance2 = templ2->NewInstance();
1703   env->Global()->Set(v8_str("q"), instance2);
1704   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1705   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1706   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1707   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1708 }
1709
1710
1711 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1712   ApiTestFuzzer::Fuzz();
1713   args.GetReturnValue().Set(v8_num(17.2));
1714 }
1715
1716
1717 static void GetKnurd(Local<String> property,
1718                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1719   ApiTestFuzzer::Fuzz();
1720   info.GetReturnValue().Set(v8_num(15.2));
1721 }
1722
1723
1724 THREADED_TEST(DescriptorInheritance) {
1725   v8::HandleScope scope(v8::Isolate::GetCurrent());
1726   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1727   super->PrototypeTemplate()->Set("flabby",
1728                                   v8::FunctionTemplate::New(GetFlabby));
1729   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1730
1731   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1732
1733   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1734   base1->Inherit(super);
1735   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1736
1737   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1738   base2->Inherit(super);
1739   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1740
1741   LocalContext env;
1742
1743   env->Global()->Set(v8_str("s"), super->GetFunction());
1744   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1745   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1746
1747   // Checks right __proto__ chain.
1748   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1749   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1750
1751   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1752
1753   // Instance accessor should not be visible on function object or its prototype
1754   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1755   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1756   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1757
1758   env->Global()->Set(v8_str("obj"),
1759                      base1->GetFunction()->NewInstance());
1760   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1761   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1762   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1763   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1764   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1765
1766   env->Global()->Set(v8_str("obj2"),
1767                      base2->GetFunction()->NewInstance());
1768   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1769   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1770   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1771   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1772   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1773
1774   // base1 and base2 cannot cross reference to each's prototype
1775   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1776   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1777 }
1778
1779
1780 int echo_named_call_count;
1781
1782
1783 static void EchoNamedProperty(Local<String> name,
1784                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1785   ApiTestFuzzer::Fuzz();
1786   CHECK_EQ(v8_str("data"), info.Data());
1787   echo_named_call_count++;
1788   info.GetReturnValue().Set(name);
1789 }
1790
1791
1792 // Helper functions for Interceptor/Accessor interaction tests
1793
1794 void SimpleAccessorGetter(Local<String> name,
1795                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1796   Handle<Object> self = info.This();
1797   info.GetReturnValue().Set(
1798       self->Get(String::Concat(v8_str("accessor_"), name)));
1799 }
1800
1801 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1802                           const v8::PropertyCallbackInfo<void>& info) {
1803   Handle<Object> self = info.This();
1804   self->Set(String::Concat(v8_str("accessor_"), name), value);
1805 }
1806
1807 void EmptyInterceptorGetter(Local<String> name,
1808                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1809 }
1810
1811 void EmptyInterceptorSetter(Local<String> name,
1812                             Local<Value> value,
1813                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1814 }
1815
1816 void InterceptorGetter(Local<String> name,
1817                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1818   // Intercept names that start with 'interceptor_'.
1819   String::Utf8Value utf8(name);
1820   char* name_str = *utf8;
1821   char prefix[] = "interceptor_";
1822   int i;
1823   for (i = 0; name_str[i] && prefix[i]; ++i) {
1824     if (name_str[i] != prefix[i]) return;
1825   }
1826   Handle<Object> self = info.This();
1827   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1828 }
1829
1830 void InterceptorSetter(Local<String> name,
1831                        Local<Value> value,
1832                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1833   // Intercept accesses that set certain integer values.
1834   if (value->IsInt32() && value->Int32Value() < 10000) {
1835     Handle<Object> self = info.This();
1836     self->SetHiddenValue(name, value);
1837     info.GetReturnValue().Set(value);
1838   }
1839 }
1840
1841 void AddAccessor(Handle<FunctionTemplate> templ,
1842                  Handle<String> name,
1843                  v8::AccessorGetterCallback getter,
1844                  v8::AccessorSetterCallback setter) {
1845   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1846 }
1847
1848 void AddInterceptor(Handle<FunctionTemplate> templ,
1849                     v8::NamedPropertyGetterCallback getter,
1850                     v8::NamedPropertySetterCallback setter) {
1851   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1852 }
1853
1854
1855 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1856   v8::HandleScope scope(v8::Isolate::GetCurrent());
1857   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1858   Handle<FunctionTemplate> child = FunctionTemplate::New();
1859   child->Inherit(parent);
1860   AddAccessor(parent, v8_str("age"),
1861               SimpleAccessorGetter, SimpleAccessorSetter);
1862   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1863   LocalContext env;
1864   env->Global()->Set(v8_str("Child"), child->GetFunction());
1865   CompileRun("var child = new Child;"
1866              "child.age = 10;");
1867   ExpectBoolean("child.hasOwnProperty('age')", false);
1868   ExpectInt32("child.age", 10);
1869   ExpectInt32("child.accessor_age", 10);
1870 }
1871
1872
1873 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1874   v8::HandleScope scope(v8::Isolate::GetCurrent());
1875   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1876   Handle<FunctionTemplate> child = FunctionTemplate::New();
1877   child->Inherit(parent);
1878   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1879   LocalContext env;
1880   env->Global()->Set(v8_str("Child"), child->GetFunction());
1881   CompileRun("var child = new Child;"
1882              "var parent = child.__proto__;"
1883              "Object.defineProperty(parent, 'age', "
1884              "  {get: function(){ return this.accessor_age; }, "
1885              "   set: function(v){ this.accessor_age = v; }, "
1886              "   enumerable: true, configurable: true});"
1887              "child.age = 10;");
1888   ExpectBoolean("child.hasOwnProperty('age')", false);
1889   ExpectInt32("child.age", 10);
1890   ExpectInt32("child.accessor_age", 10);
1891 }
1892
1893
1894 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1895   v8::HandleScope scope(v8::Isolate::GetCurrent());
1896   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1897   Handle<FunctionTemplate> child = FunctionTemplate::New();
1898   child->Inherit(parent);
1899   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1900   LocalContext env;
1901   env->Global()->Set(v8_str("Child"), child->GetFunction());
1902   CompileRun("var child = new Child;"
1903              "var parent = child.__proto__;"
1904              "parent.name = 'Alice';");
1905   ExpectBoolean("child.hasOwnProperty('name')", false);
1906   ExpectString("child.name", "Alice");
1907   CompileRun("child.name = 'Bob';");
1908   ExpectString("child.name", "Bob");
1909   ExpectBoolean("child.hasOwnProperty('name')", true);
1910   ExpectString("parent.name", "Alice");
1911 }
1912
1913
1914 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1915   v8::HandleScope scope(v8::Isolate::GetCurrent());
1916   Handle<FunctionTemplate> templ = FunctionTemplate::New();
1917   AddAccessor(templ, v8_str("age"),
1918               SimpleAccessorGetter, SimpleAccessorSetter);
1919   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1920   LocalContext env;
1921   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1922   CompileRun("var obj = new Obj;"
1923              "function setAge(i){ obj.age = i; };"
1924              "for(var i = 0; i <= 10000; i++) setAge(i);");
1925   // All i < 10000 go to the interceptor.
1926   ExpectInt32("obj.interceptor_age", 9999);
1927   // The last i goes to the accessor.
1928   ExpectInt32("obj.accessor_age", 10000);
1929 }
1930
1931
1932 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1933   v8::HandleScope scope(v8::Isolate::GetCurrent());
1934   Handle<FunctionTemplate> templ = FunctionTemplate::New();
1935   AddAccessor(templ, v8_str("age"),
1936               SimpleAccessorGetter, SimpleAccessorSetter);
1937   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1938   LocalContext env;
1939   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1940   CompileRun("var obj = new Obj;"
1941              "function setAge(i){ obj.age = i; };"
1942              "for(var i = 20000; i >= 9999; i--) setAge(i);");
1943   // All i >= 10000 go to the accessor.
1944   ExpectInt32("obj.accessor_age", 10000);
1945   // The last i goes to the interceptor.
1946   ExpectInt32("obj.interceptor_age", 9999);
1947 }
1948
1949
1950 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1951   v8::HandleScope scope(v8::Isolate::GetCurrent());
1952   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1953   Handle<FunctionTemplate> child = FunctionTemplate::New();
1954   child->Inherit(parent);
1955   AddAccessor(parent, v8_str("age"),
1956               SimpleAccessorGetter, SimpleAccessorSetter);
1957   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1958   LocalContext env;
1959   env->Global()->Set(v8_str("Child"), child->GetFunction());
1960   CompileRun("var child = new Child;"
1961              "function setAge(i){ child.age = i; };"
1962              "for(var i = 0; i <= 10000; i++) setAge(i);");
1963   // All i < 10000 go to the interceptor.
1964   ExpectInt32("child.interceptor_age", 9999);
1965   // The last i goes to the accessor.
1966   ExpectInt32("child.accessor_age", 10000);
1967 }
1968
1969
1970 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1971   v8::HandleScope scope(v8::Isolate::GetCurrent());
1972   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1973   Handle<FunctionTemplate> child = FunctionTemplate::New();
1974   child->Inherit(parent);
1975   AddAccessor(parent, v8_str("age"),
1976               SimpleAccessorGetter, SimpleAccessorSetter);
1977   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1978   LocalContext env;
1979   env->Global()->Set(v8_str("Child"), child->GetFunction());
1980   CompileRun("var child = new Child;"
1981              "function setAge(i){ child.age = i; };"
1982              "for(var i = 20000; i >= 9999; i--) setAge(i);");
1983   // All i >= 10000 go to the accessor.
1984   ExpectInt32("child.accessor_age", 10000);
1985   // The last i goes to the interceptor.
1986   ExpectInt32("child.interceptor_age", 9999);
1987 }
1988
1989
1990 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1991   v8::HandleScope scope(v8::Isolate::GetCurrent());
1992   Handle<FunctionTemplate> templ = FunctionTemplate::New();
1993   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1994   LocalContext env;
1995   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1996   CompileRun("var obj = new Obj;"
1997              "function setter(i) { this.accessor_age = i; };"
1998              "function getter() { return this.accessor_age; };"
1999              "function setAge(i) { obj.age = i; };"
2000              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2001              "for(var i = 0; i <= 10000; i++) setAge(i);");
2002   // All i < 10000 go to the interceptor.
2003   ExpectInt32("obj.interceptor_age", 9999);
2004   // The last i goes to the JavaScript accessor.
2005   ExpectInt32("obj.accessor_age", 10000);
2006   // The installed JavaScript getter is still intact.
2007   // This last part is a regression test for issue 1651 and relies on the fact
2008   // that both interceptor and accessor are being installed on the same object.
2009   ExpectInt32("obj.age", 10000);
2010   ExpectBoolean("obj.hasOwnProperty('age')", true);
2011   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2012 }
2013
2014
2015 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2016   v8::HandleScope scope(v8::Isolate::GetCurrent());
2017   Handle<FunctionTemplate> templ = FunctionTemplate::New();
2018   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2019   LocalContext env;
2020   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2021   CompileRun("var obj = new Obj;"
2022              "function setter(i) { this.accessor_age = i; };"
2023              "function getter() { return this.accessor_age; };"
2024              "function setAge(i) { obj.age = i; };"
2025              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2026              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2027   // All i >= 10000 go to the accessor.
2028   ExpectInt32("obj.accessor_age", 10000);
2029   // The last i goes to the interceptor.
2030   ExpectInt32("obj.interceptor_age", 9999);
2031   // The installed JavaScript getter is still intact.
2032   // This last part is a regression test for issue 1651 and relies on the fact
2033   // that both interceptor and accessor are being installed on the same object.
2034   ExpectInt32("obj.age", 10000);
2035   ExpectBoolean("obj.hasOwnProperty('age')", true);
2036   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2037 }
2038
2039
2040 THREADED_TEST(SwitchFromInterceptorToProperty) {
2041   v8::HandleScope scope(v8::Isolate::GetCurrent());
2042   Handle<FunctionTemplate> parent = FunctionTemplate::New();
2043   Handle<FunctionTemplate> child = FunctionTemplate::New();
2044   child->Inherit(parent);
2045   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2046   LocalContext env;
2047   env->Global()->Set(v8_str("Child"), child->GetFunction());
2048   CompileRun("var child = new Child;"
2049              "function setAge(i){ child.age = i; };"
2050              "for(var i = 0; i <= 10000; i++) setAge(i);");
2051   // All i < 10000 go to the interceptor.
2052   ExpectInt32("child.interceptor_age", 9999);
2053   // The last i goes to child's own property.
2054   ExpectInt32("child.age", 10000);
2055 }
2056
2057
2058 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2059   v8::HandleScope scope(v8::Isolate::GetCurrent());
2060   Handle<FunctionTemplate> parent = FunctionTemplate::New();
2061   Handle<FunctionTemplate> child = FunctionTemplate::New();
2062   child->Inherit(parent);
2063   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2064   LocalContext env;
2065   env->Global()->Set(v8_str("Child"), child->GetFunction());
2066   CompileRun("var child = new Child;"
2067              "function setAge(i){ child.age = i; };"
2068              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2069   // All i >= 10000 go to child's own property.
2070   ExpectInt32("child.age", 10000);
2071   // The last i goes to the interceptor.
2072   ExpectInt32("child.interceptor_age", 9999);
2073 }
2074
2075
2076 THREADED_TEST(NamedPropertyHandlerGetter) {
2077   echo_named_call_count = 0;
2078   v8::HandleScope scope(v8::Isolate::GetCurrent());
2079   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2080   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2081                                                      0, 0, 0, 0,
2082                                                      v8_str("data"));
2083   LocalContext env;
2084   env->Global()->Set(v8_str("obj"),
2085                      templ->GetFunction()->NewInstance());
2086   CHECK_EQ(echo_named_call_count, 0);
2087   v8_compile("obj.x")->Run();
2088   CHECK_EQ(echo_named_call_count, 1);
2089   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2090   v8::Handle<Value> str = CompileRun(code);
2091   String::Utf8Value value(str);
2092   CHECK_EQ(*value, "oddlepoddle");
2093   // Check default behavior
2094   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2095   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2096   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2097 }
2098
2099
2100 int echo_indexed_call_count = 0;
2101
2102
2103 static void EchoIndexedProperty(
2104     uint32_t index,
2105     const v8::PropertyCallbackInfo<v8::Value>& info) {
2106   ApiTestFuzzer::Fuzz();
2107   CHECK_EQ(v8_num(637), info.Data());
2108   echo_indexed_call_count++;
2109   info.GetReturnValue().Set(v8_num(index));
2110 }
2111
2112
2113 THREADED_TEST(IndexedPropertyHandlerGetter) {
2114   v8::HandleScope scope(v8::Isolate::GetCurrent());
2115   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2116   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2117                                                        0, 0, 0, 0,
2118                                                        v8_num(637));
2119   LocalContext env;
2120   env->Global()->Set(v8_str("obj"),
2121                      templ->GetFunction()->NewInstance());
2122   Local<Script> script = v8_compile("obj[900]");
2123   CHECK_EQ(script->Run()->Int32Value(), 900);
2124 }
2125
2126
2127 v8::Handle<v8::Object> bottom;
2128
2129 static void CheckThisIndexedPropertyHandler(
2130     uint32_t index,
2131     const v8::PropertyCallbackInfo<v8::Value>& info) {
2132   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2133   ApiTestFuzzer::Fuzz();
2134   CHECK(info.This()->Equals(bottom));
2135 }
2136
2137 static void CheckThisNamedPropertyHandler(
2138     Local<String> name,
2139     const v8::PropertyCallbackInfo<v8::Value>& info) {
2140   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2141   ApiTestFuzzer::Fuzz();
2142   CHECK(info.This()->Equals(bottom));
2143 }
2144
2145 void CheckThisIndexedPropertySetter(
2146     uint32_t index,
2147     Local<Value> value,
2148     const v8::PropertyCallbackInfo<v8::Value>& info) {
2149   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2150   ApiTestFuzzer::Fuzz();
2151   CHECK(info.This()->Equals(bottom));
2152 }
2153
2154
2155 void CheckThisNamedPropertySetter(
2156     Local<String> property,
2157     Local<Value> value,
2158     const v8::PropertyCallbackInfo<v8::Value>& info) {
2159   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2160   ApiTestFuzzer::Fuzz();
2161   CHECK(info.This()->Equals(bottom));
2162 }
2163
2164 void CheckThisIndexedPropertyQuery(
2165     uint32_t index,
2166     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2167   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2168   ApiTestFuzzer::Fuzz();
2169   CHECK(info.This()->Equals(bottom));
2170 }
2171
2172
2173 void CheckThisNamedPropertyQuery(
2174     Local<String> property,
2175     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2176   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2177   ApiTestFuzzer::Fuzz();
2178   CHECK(info.This()->Equals(bottom));
2179 }
2180
2181
2182 void CheckThisIndexedPropertyDeleter(
2183     uint32_t index,
2184     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2185   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2186   ApiTestFuzzer::Fuzz();
2187   CHECK(info.This()->Equals(bottom));
2188 }
2189
2190
2191 void CheckThisNamedPropertyDeleter(
2192     Local<String> property,
2193     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2194   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2195   ApiTestFuzzer::Fuzz();
2196   CHECK(info.This()->Equals(bottom));
2197 }
2198
2199
2200 void CheckThisIndexedPropertyEnumerator(
2201     const v8::PropertyCallbackInfo<v8::Array>& info) {
2202   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2203   ApiTestFuzzer::Fuzz();
2204   CHECK(info.This()->Equals(bottom));
2205 }
2206
2207
2208 void CheckThisNamedPropertyEnumerator(
2209     const v8::PropertyCallbackInfo<v8::Array>& info) {
2210   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2211   ApiTestFuzzer::Fuzz();
2212   CHECK(info.This()->Equals(bottom));
2213 }
2214
2215
2216 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2217   LocalContext env;
2218   v8::HandleScope scope(env->GetIsolate());
2219
2220   // Set up a prototype chain with three interceptors.
2221   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2222   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2223       CheckThisIndexedPropertyHandler,
2224       CheckThisIndexedPropertySetter,
2225       CheckThisIndexedPropertyQuery,
2226       CheckThisIndexedPropertyDeleter,
2227       CheckThisIndexedPropertyEnumerator);
2228
2229   templ->InstanceTemplate()->SetNamedPropertyHandler(
2230       CheckThisNamedPropertyHandler,
2231       CheckThisNamedPropertySetter,
2232       CheckThisNamedPropertyQuery,
2233       CheckThisNamedPropertyDeleter,
2234       CheckThisNamedPropertyEnumerator);
2235
2236   bottom = templ->GetFunction()->NewInstance();
2237   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2238   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2239
2240   bottom->SetPrototype(middle);
2241   middle->SetPrototype(top);
2242   env->Global()->Set(v8_str("obj"), bottom);
2243
2244   // Indexed and named get.
2245   Script::Compile(v8_str("obj[0]"))->Run();
2246   Script::Compile(v8_str("obj.x"))->Run();
2247
2248   // Indexed and named set.
2249   Script::Compile(v8_str("obj[1] = 42"))->Run();
2250   Script::Compile(v8_str("obj.y = 42"))->Run();
2251
2252   // Indexed and named query.
2253   Script::Compile(v8_str("0 in obj"))->Run();
2254   Script::Compile(v8_str("'x' in obj"))->Run();
2255
2256   // Indexed and named deleter.
2257   Script::Compile(v8_str("delete obj[0]"))->Run();
2258   Script::Compile(v8_str("delete obj.x"))->Run();
2259
2260   // Enumerators.
2261   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2262 }
2263
2264
2265 static void PrePropertyHandlerGet(
2266     Local<String> key,
2267     const v8::PropertyCallbackInfo<v8::Value>& info) {
2268   ApiTestFuzzer::Fuzz();
2269   if (v8_str("pre")->Equals(key)) {
2270     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2271   }
2272 }
2273
2274
2275 static void PrePropertyHandlerQuery(
2276     Local<String> key,
2277     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2278   if (v8_str("pre")->Equals(key)) {
2279     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2280   }
2281 }
2282
2283
2284 THREADED_TEST(PrePropertyHandler) {
2285   v8::HandleScope scope(v8::Isolate::GetCurrent());
2286   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
2287   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2288                                                     0,
2289                                                     PrePropertyHandlerQuery);
2290   LocalContext env(NULL, desc->InstanceTemplate());
2291   Script::Compile(v8_str(
2292       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2293   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2294   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2295   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2296   CHECK_EQ(v8_str("Object: on"), result_on);
2297   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2298   CHECK(result_post.IsEmpty());
2299 }
2300
2301
2302 THREADED_TEST(UndefinedIsNotEnumerable) {
2303   LocalContext env;
2304   v8::HandleScope scope(env->GetIsolate());
2305   v8::Handle<Value> result = Script::Compile(v8_str(
2306       "this.propertyIsEnumerable(undefined)"))->Run();
2307   CHECK(result->IsFalse());
2308 }
2309
2310
2311 v8::Handle<Script> call_recursively_script;
2312 static const int kTargetRecursionDepth = 200;  // near maximum
2313
2314
2315 static void CallScriptRecursivelyCall(
2316     const v8::FunctionCallbackInfo<v8::Value>& args) {
2317   ApiTestFuzzer::Fuzz();
2318   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2319   if (depth == kTargetRecursionDepth) return;
2320   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2321   args.GetReturnValue().Set(call_recursively_script->Run());
2322 }
2323
2324
2325 static void CallFunctionRecursivelyCall(
2326     const v8::FunctionCallbackInfo<v8::Value>& args) {
2327   ApiTestFuzzer::Fuzz();
2328   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2329   if (depth == kTargetRecursionDepth) {
2330     printf("[depth = %d]\n", depth);
2331     return;
2332   }
2333   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2334   v8::Handle<Value> function =
2335       args.This()->Get(v8_str("callFunctionRecursively"));
2336   args.GetReturnValue().Set(
2337       function.As<Function>()->Call(args.This(), 0, NULL));
2338 }
2339
2340
2341 THREADED_TEST(DeepCrossLanguageRecursion) {
2342   v8::HandleScope scope(v8::Isolate::GetCurrent());
2343   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2344   global->Set(v8_str("callScriptRecursively"),
2345               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
2346   global->Set(v8_str("callFunctionRecursively"),
2347               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
2348   LocalContext env(NULL, global);
2349
2350   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2351   call_recursively_script = v8_compile("callScriptRecursively()");
2352   call_recursively_script->Run();
2353   call_recursively_script = v8::Handle<Script>();
2354
2355   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2356   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2357 }
2358
2359
2360 static void ThrowingPropertyHandlerGet(
2361     Local<String> key,
2362     const v8::PropertyCallbackInfo<v8::Value>& info) {
2363   ApiTestFuzzer::Fuzz();
2364   info.GetReturnValue().Set(v8::ThrowException(key));
2365 }
2366
2367
2368 static void ThrowingPropertyHandlerSet(
2369     Local<String> key,
2370     Local<Value>,
2371     const v8::PropertyCallbackInfo<v8::Value>& info) {
2372   v8::ThrowException(key);
2373   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2374 }
2375
2376
2377 THREADED_TEST(CallbackExceptionRegression) {
2378   v8::HandleScope scope(v8::Isolate::GetCurrent());
2379   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2380   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2381                                ThrowingPropertyHandlerSet);
2382   LocalContext env;
2383   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2384   v8::Handle<Value> otto = Script::Compile(v8_str(
2385       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2386   CHECK_EQ(v8_str("otto"), otto);
2387   v8::Handle<Value> netto = Script::Compile(v8_str(
2388       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2389   CHECK_EQ(v8_str("netto"), netto);
2390 }
2391
2392
2393 THREADED_TEST(FunctionPrototype) {
2394   v8::HandleScope scope(v8::Isolate::GetCurrent());
2395   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2396   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2397   LocalContext env;
2398   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2399   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2400   CHECK_EQ(script->Run()->Int32Value(), 321);
2401 }
2402
2403
2404 THREADED_TEST(InternalFields) {
2405   LocalContext env;
2406   v8::HandleScope scope(env->GetIsolate());
2407
2408   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2409   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2410   instance_templ->SetInternalFieldCount(1);
2411   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2412   CHECK_EQ(1, obj->InternalFieldCount());
2413   CHECK(obj->GetInternalField(0)->IsUndefined());
2414   obj->SetInternalField(0, v8_num(17));
2415   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2416 }
2417
2418
2419 THREADED_TEST(GlobalObjectInternalFields) {
2420   v8::HandleScope scope(v8::Isolate::GetCurrent());
2421   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2422   global_template->SetInternalFieldCount(1);
2423   LocalContext env(NULL, global_template);
2424   v8::Handle<v8::Object> global_proxy = env->Global();
2425   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2426   CHECK_EQ(1, global->InternalFieldCount());
2427   CHECK(global->GetInternalField(0)->IsUndefined());
2428   global->SetInternalField(0, v8_num(17));
2429   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2430 }
2431
2432
2433 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2434   LocalContext env;
2435   v8::HandleScope scope(v8::Isolate::GetCurrent());
2436
2437   v8::Local<v8::Object> global = env->Global();
2438   global->Set(0, v8::String::New("value"));
2439   CHECK(global->HasRealIndexedProperty(0));
2440 }
2441
2442
2443 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2444                                                void* value) {
2445   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2446   obj->SetAlignedPointerInInternalField(0, value);
2447   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2448   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2449 }
2450
2451
2452 THREADED_TEST(InternalFieldsAlignedPointers) {
2453   LocalContext env;
2454   v8::HandleScope scope(env->GetIsolate());
2455
2456   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2457   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2458   instance_templ->SetInternalFieldCount(1);
2459   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2460   CHECK_EQ(1, obj->InternalFieldCount());
2461
2462   CheckAlignedPointerInInternalField(obj, NULL);
2463
2464   int* heap_allocated = new int[100];
2465   CheckAlignedPointerInInternalField(obj, heap_allocated);
2466   delete[] heap_allocated;
2467
2468   int stack_allocated[100];
2469   CheckAlignedPointerInInternalField(obj, stack_allocated);
2470
2471   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2472   CheckAlignedPointerInInternalField(obj, huge);
2473 }
2474
2475
2476 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2477                                               int index,
2478                                               void* value) {
2479   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2480   (*env)->SetAlignedPointerInEmbedderData(index, value);
2481   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2482   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2483 }
2484
2485
2486 static void* AlignedTestPointer(int i) {
2487   return reinterpret_cast<void*>(i * 1234);
2488 }
2489
2490
2491 THREADED_TEST(EmbedderDataAlignedPointers) {
2492   LocalContext env;
2493   v8::HandleScope scope(env->GetIsolate());
2494
2495   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2496
2497   int* heap_allocated = new int[100];
2498   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2499   delete[] heap_allocated;
2500
2501   int stack_allocated[100];
2502   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2503
2504   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2505   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2506
2507   // Test growing of the embedder data's backing store.
2508   for (int i = 0; i < 100; i++) {
2509     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2510   }
2511   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2512   for (int i = 0; i < 100; i++) {
2513     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2514   }
2515 }
2516
2517
2518 static void CheckEmbedderData(LocalContext* env,
2519                               int index,
2520                               v8::Handle<Value> data) {
2521   (*env)->SetEmbedderData(index, data);
2522   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2523 }
2524
2525
2526 THREADED_TEST(EmbedderData) {
2527   LocalContext env;
2528   v8::HandleScope scope(env->GetIsolate());
2529
2530   CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2531   CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2532   CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2533   CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2534 }
2535
2536
2537 THREADED_TEST(IdentityHash) {
2538   LocalContext env;
2539   v8::HandleScope scope(env->GetIsolate());
2540
2541   // Ensure that the test starts with an fresh heap to test whether the hash
2542   // code is based on the address.
2543   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2544   Local<v8::Object> obj = v8::Object::New();
2545   int hash = obj->GetIdentityHash();
2546   int hash1 = obj->GetIdentityHash();
2547   CHECK_EQ(hash, hash1);
2548   int hash2 = v8::Object::New()->GetIdentityHash();
2549   // Since the identity hash is essentially a random number two consecutive
2550   // objects should not be assigned the same hash code. If the test below fails
2551   // the random number generator should be evaluated.
2552   CHECK_NE(hash, hash2);
2553   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2554   int hash3 = v8::Object::New()->GetIdentityHash();
2555   // Make sure that the identity hash is not based on the initial address of
2556   // the object alone. If the test below fails the random number generator
2557   // should be evaluated.
2558   CHECK_NE(hash, hash3);
2559   int hash4 = obj->GetIdentityHash();
2560   CHECK_EQ(hash, hash4);
2561
2562   // Check identity hashes behaviour in the presence of JS accessors.
2563   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2564   {
2565     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2566     Local<v8::Object> o1 = v8::Object::New();
2567     Local<v8::Object> o2 = v8::Object::New();
2568     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2569   }
2570   {
2571     CompileRun(
2572         "function cnst() { return 42; };\n"
2573         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2574     Local<v8::Object> o1 = v8::Object::New();
2575     Local<v8::Object> o2 = v8::Object::New();
2576     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2577   }
2578 }
2579
2580
2581 THREADED_TEST(SymbolProperties) {
2582   i::FLAG_harmony_symbols = true;
2583
2584   LocalContext env;
2585   v8::Isolate* isolate = env->GetIsolate();
2586   v8::HandleScope scope(isolate);
2587
2588   v8::Local<v8::Object> obj = v8::Object::New();
2589   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2590   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2591
2592   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2593
2594   // Check basic symbol functionality.
2595   CHECK(sym1->IsSymbol());
2596   CHECK(sym2->IsSymbol());
2597   CHECK(!obj->IsSymbol());
2598
2599   CHECK(sym1->Equals(sym1));
2600   CHECK(sym2->Equals(sym2));
2601   CHECK(!sym1->Equals(sym2));
2602   CHECK(!sym2->Equals(sym1));
2603   CHECK(sym1->StrictEquals(sym1));
2604   CHECK(sym2->StrictEquals(sym2));
2605   CHECK(!sym1->StrictEquals(sym2));
2606   CHECK(!sym2->StrictEquals(sym1));
2607
2608   CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
2609
2610   v8::Local<v8::Value> sym_val = sym2;
2611   CHECK(sym_val->IsSymbol());
2612   CHECK(sym_val->Equals(sym2));
2613   CHECK(sym_val->StrictEquals(sym2));
2614   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2615
2616   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2617   CHECK(sym_obj->IsSymbolObject());
2618   CHECK(!sym2->IsSymbolObject());
2619   CHECK(!obj->IsSymbolObject());
2620   CHECK(sym_obj->Equals(sym2));
2621   CHECK(!sym_obj->StrictEquals(sym2));
2622   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2623   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2624
2625   // Make sure delete of a non-existent symbol property works.
2626   CHECK(obj->Delete(sym1));
2627   CHECK(!obj->Has(sym1));
2628
2629   CHECK(obj->Set(sym1, v8::Integer::New(1503)));
2630   CHECK(obj->Has(sym1));
2631   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2632   CHECK(obj->Set(sym1, v8::Integer::New(2002)));
2633   CHECK(obj->Has(sym1));
2634   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2635   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2636
2637   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2638   int num_props = obj->GetPropertyNames()->Length();
2639   CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
2640   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2641   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2642
2643   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2644
2645   // Add another property and delete it afterwards to force the object in
2646   // slow case.
2647   CHECK(obj->Set(sym2, v8::Integer::New(2008)));
2648   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2649   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2650   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2651   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2652
2653   CHECK(obj->Has(sym1));
2654   CHECK(obj->Has(sym2));
2655   CHECK(obj->Delete(sym2));
2656   CHECK(obj->Has(sym1));
2657   CHECK(!obj->Has(sym2));
2658   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2659   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2660 }
2661
2662
2663 class ScopedArrayBufferContents {
2664  public:
2665   explicit ScopedArrayBufferContents(
2666       const v8::ArrayBuffer::Contents& contents)
2667     : contents_(contents) {}
2668   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2669   void* Data() const { return contents_.Data(); }
2670   size_t ByteLength() const { return contents_.ByteLength(); }
2671  private:
2672   const v8::ArrayBuffer::Contents contents_;
2673 };
2674
2675 template <typename T>
2676 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2677   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2678   for (int i = 0; i < value->InternalFieldCount(); i++) {
2679     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2680   }
2681 }
2682
2683
2684 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2685   i::FLAG_harmony_array_buffer = true;
2686   i::FLAG_harmony_typed_arrays = true;
2687
2688   LocalContext env;
2689   v8::Isolate* isolate = env->GetIsolate();
2690   v8::HandleScope handle_scope(isolate);
2691
2692   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
2693   CheckInternalFieldsAreZero(ab);
2694   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2695   CHECK(!ab->IsExternal());
2696   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2697
2698   ScopedArrayBufferContents ab_contents(ab->Externalize());
2699   CHECK(ab->IsExternal());
2700
2701   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2702   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2703   ASSERT(data != NULL);
2704   env->Global()->Set(v8_str("ab"), ab);
2705
2706   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2707   CHECK_EQ(1024, result->Int32Value());
2708
2709   result = CompileRun("var u8 = new Uint8Array(ab);"
2710                       "u8[0] = 0xFF;"
2711                       "u8[1] = 0xAA;"
2712                       "u8.length");
2713   CHECK_EQ(1024, result->Int32Value());
2714   CHECK_EQ(0xFF, data[0]);
2715   CHECK_EQ(0xAA, data[1]);
2716   data[0] = 0xCC;
2717   data[1] = 0x11;
2718   result = CompileRun("u8[0] + u8[1]");
2719   CHECK_EQ(0xDD, result->Int32Value());
2720 }
2721
2722
2723 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2724   i::FLAG_harmony_array_buffer = true;
2725   i::FLAG_harmony_typed_arrays = true;
2726
2727   LocalContext env;
2728   v8::Isolate* isolate = env->GetIsolate();
2729   v8::HandleScope handle_scope(isolate);
2730
2731
2732   v8::Local<v8::Value> result =
2733       CompileRun("var ab1 = new ArrayBuffer(2);"
2734                  "var u8_a = new Uint8Array(ab1);"
2735                  "u8_a[0] = 0xAA;"
2736                  "u8_a[1] = 0xFF; u8_a.buffer");
2737   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2738   CheckInternalFieldsAreZero(ab1);
2739   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2740   CHECK(!ab1->IsExternal());
2741   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2742   CHECK(ab1->IsExternal());
2743
2744   result = CompileRun("ab1.byteLength");
2745   CHECK_EQ(2, result->Int32Value());
2746   result = CompileRun("u8_a[0]");
2747   CHECK_EQ(0xAA, result->Int32Value());
2748   result = CompileRun("u8_a[1]");
2749   CHECK_EQ(0xFF, result->Int32Value());
2750   result = CompileRun("var u8_b = new Uint8Array(ab1);"
2751                       "u8_b[0] = 0xBB;"
2752                       "u8_a[0]");
2753   CHECK_EQ(0xBB, result->Int32Value());
2754   result = CompileRun("u8_b[1]");
2755   CHECK_EQ(0xFF, result->Int32Value());
2756
2757   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2758   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2759   CHECK_EQ(0xBB, ab1_data[0]);
2760   CHECK_EQ(0xFF, ab1_data[1]);
2761   ab1_data[0] = 0xCC;
2762   ab1_data[1] = 0x11;
2763   result = CompileRun("u8_a[0] + u8_a[1]");
2764   CHECK_EQ(0xDD, result->Int32Value());
2765 }
2766
2767
2768 THREADED_TEST(ArrayBuffer_External) {
2769   i::FLAG_harmony_array_buffer = true;
2770   i::FLAG_harmony_typed_arrays = true;
2771
2772   LocalContext env;
2773   v8::Isolate* isolate = env->GetIsolate();
2774   v8::HandleScope handle_scope(isolate);
2775
2776   i::ScopedVector<uint8_t> my_data(100);
2777   memset(my_data.start(), 0, 100);
2778   Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100);
2779   CheckInternalFieldsAreZero(ab3);
2780   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2781   CHECK(ab3->IsExternal());
2782
2783   env->Global()->Set(v8_str("ab3"), ab3);
2784
2785   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2786   CHECK_EQ(100, result->Int32Value());
2787
2788   result = CompileRun("var u8_b = new Uint8Array(ab3);"
2789                       "u8_b[0] = 0xBB;"
2790                       "u8_b[1] = 0xCC;"
2791                       "u8_b.length");
2792   CHECK_EQ(100, result->Int32Value());
2793   CHECK_EQ(0xBB, my_data[0]);
2794   CHECK_EQ(0xCC, my_data[1]);
2795   my_data[0] = 0xCC;
2796   my_data[1] = 0x11;
2797   result = CompileRun("u8_b[0] + u8_b[1]");
2798   CHECK_EQ(0xDD, result->Int32Value());
2799 }
2800
2801
2802 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2803   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2804   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2805 }
2806
2807
2808 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2809   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2810   CHECK_EQ(0, static_cast<int>(ta->Length()));
2811   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2812 }
2813
2814
2815 static void CheckIsTypedArrayVarNeutered(const char* name) {
2816   i::ScopedVector<char> source(1024);
2817   i::OS::SNPrintF(source,
2818       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2819       name, name, name);
2820   CHECK(CompileRun(source.start())->IsTrue());
2821   v8::Handle<v8::TypedArray> ta =
2822     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2823   CheckIsNeutered(ta);
2824 }
2825
2826
2827 template <typename TypedArray, int kElementSize>
2828 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2829                                          int byteOffset,
2830                                          int length) {
2831   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2832   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2833   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2834   CHECK_EQ(length, static_cast<int>(ta->Length()));
2835   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2836   return ta;
2837 }
2838
2839
2840 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2841   LocalContext env;
2842   v8::Isolate* isolate = env->GetIsolate();
2843   v8::HandleScope handle_scope(isolate);
2844
2845   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(1024);
2846
2847   v8::Handle<v8::Uint8Array> u8a =
2848     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2849   v8::Handle<v8::Uint8ClampedArray> u8c =
2850     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2851   v8::Handle<v8::Int8Array> i8a =
2852     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2853
2854   v8::Handle<v8::Uint16Array> u16a =
2855     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2856   v8::Handle<v8::Int16Array> i16a =
2857     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2858
2859   v8::Handle<v8::Uint32Array> u32a =
2860     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2861   v8::Handle<v8::Int32Array> i32a =
2862     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2863
2864   v8::Handle<v8::Float32Array> f32a =
2865     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2866   v8::Handle<v8::Float64Array> f64a =
2867     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2868
2869   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2870   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2871   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2872   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2873
2874   ScopedArrayBufferContents contents(buffer->Externalize());
2875   buffer->Neuter();
2876   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2877   CheckIsNeutered(u8a);
2878   CheckIsNeutered(u8c);
2879   CheckIsNeutered(i8a);
2880   CheckIsNeutered(u16a);
2881   CheckIsNeutered(i16a);
2882   CheckIsNeutered(u32a);
2883   CheckIsNeutered(i32a);
2884   CheckIsNeutered(f32a);
2885   CheckIsNeutered(f64a);
2886   CheckDataViewIsNeutered(dv);
2887 }
2888
2889
2890 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2891   LocalContext env;
2892   v8::Isolate* isolate = env->GetIsolate();
2893   v8::HandleScope handle_scope(isolate);
2894
2895   CompileRun(
2896       "var ab = new ArrayBuffer(1024);"
2897       "var u8a = new Uint8Array(ab, 1, 1023);"
2898       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2899       "var i8a = new Int8Array(ab, 1, 1023);"
2900       "var u16a = new Uint16Array(ab, 2, 511);"
2901       "var i16a = new Int16Array(ab, 2, 511);"
2902       "var u32a = new Uint32Array(ab, 4, 255);"
2903       "var i32a = new Int32Array(ab, 4, 255);"
2904       "var f32a = new Float32Array(ab, 4, 255);"
2905       "var f64a = new Float64Array(ab, 8, 127);"
2906       "var dv = new DataView(ab, 1, 1023);");
2907
2908   v8::Handle<v8::ArrayBuffer> ab =
2909       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2910
2911   v8::Handle<v8::DataView> dv =
2912     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2913
2914   ScopedArrayBufferContents contents(ab->Externalize());
2915   ab->Neuter();
2916   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2917   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2918
2919   CheckIsTypedArrayVarNeutered("u8a");
2920   CheckIsTypedArrayVarNeutered("u8c");
2921   CheckIsTypedArrayVarNeutered("i8a");
2922   CheckIsTypedArrayVarNeutered("u16a");
2923   CheckIsTypedArrayVarNeutered("i16a");
2924   CheckIsTypedArrayVarNeutered("u32a");
2925   CheckIsTypedArrayVarNeutered("i32a");
2926   CheckIsTypedArrayVarNeutered("f32a");
2927   CheckIsTypedArrayVarNeutered("f64a");
2928
2929   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2930   CheckDataViewIsNeutered(dv);
2931 }
2932
2933
2934
2935 THREADED_TEST(HiddenProperties) {
2936   LocalContext env;
2937   v8::HandleScope scope(env->GetIsolate());
2938
2939   v8::Local<v8::Object> obj = v8::Object::New();
2940   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2941   v8::Local<v8::String> empty = v8_str("");
2942   v8::Local<v8::String> prop_name = v8_str("prop_name");
2943
2944   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2945
2946   // Make sure delete of a non-existent hidden value works
2947   CHECK(obj->DeleteHiddenValue(key));
2948
2949   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2950   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2951   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2952   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2953
2954   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2955
2956   // Make sure we do not find the hidden property.
2957   CHECK(!obj->Has(empty));
2958   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2959   CHECK(obj->Get(empty)->IsUndefined());
2960   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2961   CHECK(obj->Set(empty, v8::Integer::New(2003)));
2962   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2963   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2964
2965   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2966
2967   // Add another property and delete it afterwards to force the object in
2968   // slow case.
2969   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2970   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2971   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2972   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2973   CHECK(obj->Delete(prop_name));
2974   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2975
2976   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2977
2978   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2979   CHECK(obj->GetHiddenValue(key).IsEmpty());
2980
2981   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2982   CHECK(obj->DeleteHiddenValue(key));
2983   CHECK(obj->GetHiddenValue(key).IsEmpty());
2984 }
2985
2986
2987 THREADED_TEST(Regress97784) {
2988   // Regression test for crbug.com/97784
2989   // Messing with the Object.prototype should not have effect on
2990   // hidden properties.
2991   LocalContext env;
2992   v8::HandleScope scope(env->GetIsolate());
2993
2994   v8::Local<v8::Object> obj = v8::Object::New();
2995   v8::Local<v8::String> key = v8_str("hidden");
2996
2997   CompileRun(
2998       "set_called = false;"
2999       "Object.defineProperty("
3000       "    Object.prototype,"
3001       "    'hidden',"
3002       "    {get: function() { return 45; },"
3003       "     set: function() { set_called = true; }})");
3004
3005   CHECK(obj->GetHiddenValue(key).IsEmpty());
3006   // Make sure that the getter and setter from Object.prototype is not invoked.
3007   // If it did we would have full access to the hidden properties in
3008   // the accessor.
3009   CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
3010   ExpectFalse("set_called");
3011   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3012 }
3013
3014
3015 static bool interceptor_for_hidden_properties_called;
3016 static void InterceptorForHiddenProperties(
3017     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3018   interceptor_for_hidden_properties_called = true;
3019 }
3020
3021
3022 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3023   LocalContext context;
3024   v8::HandleScope scope(context->GetIsolate());
3025
3026   interceptor_for_hidden_properties_called = false;
3027
3028   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3029
3030   // Associate an interceptor with an object and start setting hidden values.
3031   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
3032   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3033   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3034   Local<v8::Function> function = fun_templ->GetFunction();
3035   Local<v8::Object> obj = function->NewInstance();
3036   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
3037   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3038   CHECK(!interceptor_for_hidden_properties_called);
3039 }
3040
3041
3042 THREADED_TEST(External) {
3043   v8::HandleScope scope(v8::Isolate::GetCurrent());
3044   int x = 3;
3045   Local<v8::External> ext = v8::External::New(&x);
3046   LocalContext env;
3047   env->Global()->Set(v8_str("ext"), ext);
3048   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3049   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3050   int* ptr = static_cast<int*>(reext->Value());
3051   CHECK_EQ(x, 3);
3052   *ptr = 10;
3053   CHECK_EQ(x, 10);
3054
3055   // Make sure unaligned pointers are wrapped properly.
3056   char* data = i::StrDup("0123456789");
3057   Local<v8::Value> zero = v8::External::New(&data[0]);
3058   Local<v8::Value> one = v8::External::New(&data[1]);
3059   Local<v8::Value> two = v8::External::New(&data[2]);
3060   Local<v8::Value> three = v8::External::New(&data[3]);
3061
3062   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3063   CHECK_EQ('0', *char_ptr);
3064   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3065   CHECK_EQ('1', *char_ptr);
3066   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3067   CHECK_EQ('2', *char_ptr);
3068   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3069   CHECK_EQ('3', *char_ptr);
3070   i::DeleteArray(data);
3071 }
3072
3073
3074 THREADED_TEST(GlobalHandle) {
3075   v8::Isolate* isolate = v8::Isolate::GetCurrent();
3076   v8::Persistent<String> global;
3077   {
3078     v8::HandleScope scope(isolate);
3079     global.Reset(isolate, v8_str("str"));
3080   }
3081   {
3082     v8::HandleScope scope(isolate);
3083     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3084   }
3085   global.Dispose();
3086   global.Clear();
3087   {
3088     v8::HandleScope scope(isolate);
3089     global.Reset(isolate, v8_str("str"));
3090   }
3091   {
3092     v8::HandleScope scope(isolate);
3093     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3094   }
3095   global.Dispose();
3096 }
3097
3098
3099 THREADED_TEST(ResettingGlobalHandle) {
3100   v8::Isolate* isolate = v8::Isolate::GetCurrent();
3101   v8::Persistent<String> global;
3102   {
3103     v8::HandleScope scope(isolate);
3104     global.Reset(isolate, v8_str("str"));
3105   }
3106   v8::internal::GlobalHandles* global_handles =
3107       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3108   int initial_handle_count = global_handles->global_handles_count();
3109   {
3110     v8::HandleScope scope(isolate);
3111     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3112   }
3113   {
3114     v8::HandleScope scope(isolate);
3115     global.Reset(isolate, v8_str("longer"));
3116   }
3117   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3118   {
3119     v8::HandleScope scope(isolate);
3120     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3121   }
3122   global.Dispose(isolate);
3123   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3124 }
3125
3126
3127 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3128   v8::Isolate* isolate = v8::Isolate::GetCurrent();
3129   v8::Persistent<String> global;
3130   {
3131     v8::HandleScope scope(isolate);
3132     global.Reset(isolate, v8_str("str"));
3133   }
3134   v8::internal::GlobalHandles* global_handles =
3135       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3136   int initial_handle_count = global_handles->global_handles_count();
3137   {
3138     v8::HandleScope scope(isolate);
3139     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3140   }
3141   {
3142     v8::HandleScope scope(isolate);
3143     Local<String> empty;
3144     global.Reset(isolate, empty);
3145   }
3146   CHECK(global.IsEmpty());
3147   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3148 }
3149
3150
3151 THREADED_TEST(ClearAndLeakGlobal) {
3152   v8::Isolate* isolate = v8::Isolate::GetCurrent();
3153   v8::internal::GlobalHandles* global_handles = NULL;
3154   int initial_handle_count = 0;
3155   v8::Persistent<String> global;
3156   {
3157     v8::HandleScope scope(isolate);
3158     Local<String> str = v8_str("str");
3159     global_handles =
3160         reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3161     initial_handle_count = global_handles->global_handles_count();
3162     global.Reset(isolate, str);
3163   }
3164   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3165   String* str = global.ClearAndLeak();
3166   CHECK(global.IsEmpty());
3167   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3168   global_handles->Destroy(reinterpret_cast<i::Object**>(str));
3169   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3170 }
3171
3172
3173 THREADED_TEST(GlobalHandleUpcast) {
3174   v8::Isolate* isolate = v8::Isolate::GetCurrent();
3175   v8::HandleScope scope(isolate);
3176   v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
3177   v8::Persistent<String> global_string(isolate, local);
3178 #ifdef V8_USE_UNSAFE_HANDLES
3179   v8::Persistent<Value> global_value =
3180       v8::Persistent<Value>::Cast(global_string);
3181 #else
3182   v8::Persistent<Value>& global_value =
3183       v8::Persistent<Value>::Cast(global_string);
3184 #endif
3185   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3186   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3187   global_string.Dispose();
3188 }
3189
3190
3191 THREADED_TEST(LocalHandle) {
3192   v8::HandleScope scope(v8::Isolate::GetCurrent());
3193   v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
3194   CHECK_EQ(local->Length(), 3);
3195
3196   local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str"));
3197   CHECK_EQ(local->Length(), 3);
3198 }
3199
3200
3201 class WeakCallCounter {
3202  public:
3203   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3204   int id() { return id_; }
3205   void increment() { number_of_weak_calls_++; }
3206   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3207  private:
3208   int id_;
3209   int number_of_weak_calls_;
3210 };
3211
3212
3213 static void WeakPointerCallback(v8::Isolate* isolate,
3214                                 Persistent<Value>* handle,
3215                                 WeakCallCounter* counter) {
3216   CHECK_EQ(1234, counter->id());
3217   counter->increment();
3218   handle->Dispose(isolate);
3219 }
3220
3221
3222 static UniqueId MakeUniqueId(const Persistent<Value>& p) {
3223   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3224 }
3225
3226
3227 THREADED_TEST(ApiObjectGroups) {
3228   LocalContext env;
3229   v8::Isolate* iso = env->GetIsolate();
3230   HandleScope scope(iso);
3231
3232   Persistent<Value> g1s1;
3233   Persistent<Value> g1s2;
3234   Persistent<Value> g1c1;
3235   Persistent<Value> g2s1;
3236   Persistent<Value> g2s2;
3237   Persistent<Value> g2c1;
3238
3239   WeakCallCounter counter(1234);
3240
3241   {
3242     HandleScope scope(iso);
3243     g1s1.Reset(iso, Object::New());
3244     g1s2.Reset(iso, Object::New());
3245     g1c1.Reset(iso, Object::New());
3246     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3247     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3248     g1c1.MakeWeak(&counter, &WeakPointerCallback);
3249
3250     g2s1.Reset(iso, Object::New());
3251     g2s2.Reset(iso, Object::New());
3252     g2c1.Reset(iso, Object::New());
3253     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3254     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3255     g2c1.MakeWeak(&counter, &WeakPointerCallback);
3256   }
3257
3258   Persistent<Value> root(iso, g1s1);  // make a root.
3259
3260   // Connect group 1 and 2, make a cycle.
3261   {
3262     HandleScope scope(iso);
3263     CHECK(Local<Object>::New(iso, g1s2.As<Object>())->
3264             Set(0, Local<Value>::New(iso, g2s2)));
3265     CHECK(Local<Object>::New(iso, g2s1.As<Object>())->
3266             Set(0, Local<Value>::New(iso, g1s1)));
3267   }
3268
3269   {
3270     UniqueId id1 = MakeUniqueId(g1s1);
3271     UniqueId id2 = MakeUniqueId(g2s2);
3272     iso->SetObjectGroupId(g1s1, id1);
3273     iso->SetObjectGroupId(g1s2, id1);
3274     iso->SetReferenceFromGroup(id1, g1c1);
3275     iso->SetObjectGroupId(g2s1, id2);
3276     iso->SetObjectGroupId(g2s2, id2);
3277     iso->SetReferenceFromGroup(id2, g2c1);
3278   }
3279   // Do a single full GC, ensure incremental marking is stopped.
3280   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3281       iso)->heap();
3282   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3283
3284   // All object should be alive.
3285   CHECK_EQ(0, counter.NumberOfWeakCalls());
3286
3287   // Weaken the root.
3288   root.MakeWeak(&counter, &WeakPointerCallback);
3289   // But make children strong roots---all the objects (except for children)
3290   // should be collectable now.
3291   g1c1.ClearWeak(iso);
3292   g2c1.ClearWeak(iso);
3293
3294   // Groups are deleted, rebuild groups.
3295   {
3296     UniqueId id1 = MakeUniqueId(g1s1);
3297     UniqueId id2 = MakeUniqueId(g2s2);
3298     iso->SetObjectGroupId(g1s1, id1);
3299     iso->SetObjectGroupId(g1s2, id1);
3300     iso->SetReferenceFromGroup(id1, g1c1);
3301     iso->SetObjectGroupId(g2s1, id2);
3302     iso->SetObjectGroupId(g2s2, id2);
3303     iso->SetReferenceFromGroup(id2, g2c1);
3304   }
3305
3306   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3307
3308   // All objects should be gone. 5 global handles in total.
3309   CHECK_EQ(5, counter.NumberOfWeakCalls());
3310
3311   // And now make children weak again and collect them.
3312   g1c1.MakeWeak(&counter, &WeakPointerCallback);
3313   g2c1.MakeWeak(&counter, &WeakPointerCallback);
3314
3315   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3316   CHECK_EQ(7, counter.NumberOfWeakCalls());
3317 }
3318
3319
3320 THREADED_TEST(ApiObjectGroupsCycle) {
3321   LocalContext env;
3322   v8::Isolate* iso = env->GetIsolate();
3323   HandleScope scope(iso);
3324
3325   WeakCallCounter counter(1234);
3326
3327   Persistent<Value> g1s1;
3328   Persistent<Value> g1s2;
3329   Persistent<Value> g2s1;
3330   Persistent<Value> g2s2;
3331   Persistent<Value> g3s1;
3332   Persistent<Value> g3s2;
3333   Persistent<Value> g4s1;
3334   Persistent<Value> g4s2;
3335
3336   {
3337     HandleScope scope(iso);
3338     g1s1.Reset(iso, Object::New());
3339     g1s2.Reset(iso, Object::New());
3340     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3341     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3342     CHECK(g1s1.IsWeak(iso));
3343     CHECK(g1s2.IsWeak(iso));
3344
3345     g2s1.Reset(iso, Object::New());
3346     g2s2.Reset(iso, Object::New());
3347     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3348     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3349     CHECK(g2s1.IsWeak(iso));
3350     CHECK(g2s2.IsWeak(iso));
3351
3352     g3s1.Reset(iso, Object::New());
3353     g3s2.Reset(iso, Object::New());
3354     g3s1.MakeWeak(&counter, &WeakPointerCallback);
3355     g3s2.MakeWeak(&counter, &WeakPointerCallback);
3356     CHECK(g3s1.IsWeak(iso));
3357     CHECK(g3s2.IsWeak(iso));
3358
3359     g4s1.Reset(iso, Object::New());
3360     g4s2.Reset(iso, Object::New());
3361     g4s1.MakeWeak(&counter, &WeakPointerCallback);
3362     g4s2.MakeWeak(&counter, &WeakPointerCallback);
3363     CHECK(g4s1.IsWeak(iso));
3364     CHECK(g4s2.IsWeak(iso));
3365   }
3366
3367   Persistent<Value> root(iso, g1s1);  // make a root.
3368
3369   // Connect groups.  We're building the following cycle:
3370   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3371   // groups.
3372   {
3373     UniqueId id1 = MakeUniqueId(g1s1);
3374     UniqueId id2 = MakeUniqueId(g2s1);
3375     UniqueId id3 = MakeUniqueId(g3s1);
3376     UniqueId id4 = MakeUniqueId(g4s1);
3377     iso->SetObjectGroupId(g1s1, id1);
3378     iso->SetObjectGroupId(g1s2, id1);
3379     iso->SetReferenceFromGroup(id1, g2s1);
3380     iso->SetObjectGroupId(g2s1, id2);
3381     iso->SetObjectGroupId(g2s2, id2);
3382     iso->SetReferenceFromGroup(id2, g3s1);
3383     iso->SetObjectGroupId(g3s1, id3);
3384     iso->SetObjectGroupId(g3s2, id3);
3385     iso->SetReferenceFromGroup(id3, g4s1);
3386     iso->SetObjectGroupId(g4s1, id4);
3387     iso->SetObjectGroupId(g4s2, id4);
3388     iso->SetReferenceFromGroup(id4, g1s1);
3389   }
3390   // Do a single full GC
3391   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3392       iso)->heap();
3393   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3394
3395   // All object should be alive.
3396   CHECK_EQ(0, counter.NumberOfWeakCalls());
3397
3398   // Weaken the root.
3399   root.MakeWeak(&counter, &WeakPointerCallback);
3400
3401   // Groups are deleted, rebuild groups.
3402   {
3403     UniqueId id1 = MakeUniqueId(g1s1);
3404     UniqueId id2 = MakeUniqueId(g2s1);
3405     UniqueId id3 = MakeUniqueId(g3s1);
3406     UniqueId id4 = MakeUniqueId(g4s1);
3407     iso->SetObjectGroupId(g1s1, id1);
3408     iso->SetObjectGroupId(g1s2, id1);
3409     iso->SetReferenceFromGroup(id1, g2s1);
3410     iso->SetObjectGroupId(g2s1, id2);
3411     iso->SetObjectGroupId(g2s2, id2);
3412     iso->SetReferenceFromGroup(id2, g3s1);
3413     iso->SetObjectGroupId(g3s1, id3);
3414     iso->SetObjectGroupId(g3s2, id3);
3415     iso->SetReferenceFromGroup(id3, g4s1);
3416     iso->SetObjectGroupId(g4s1, id4);
3417     iso->SetObjectGroupId(g4s2, id4);
3418     iso->SetReferenceFromGroup(id4, g1s1);
3419   }
3420
3421   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3422
3423   // All objects should be gone. 9 global handles in total.
3424   CHECK_EQ(9, counter.NumberOfWeakCalls());
3425 }
3426
3427
3428 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3429 // on the buildbots, so was made non-threaded for the time being.
3430 TEST(ApiObjectGroupsCycleForScavenger) {
3431   i::FLAG_stress_compaction = false;
3432   i::FLAG_gc_global = false;
3433   LocalContext env;
3434   v8::Isolate* iso = env->GetIsolate();
3435   HandleScope scope(iso);
3436
3437   WeakCallCounter counter(1234);
3438
3439   Persistent<Value> g1s1;
3440   Persistent<Value> g1s2;
3441   Persistent<Value> g2s1;
3442   Persistent<Value> g2s2;
3443   Persistent<Value> g3s1;
3444   Persistent<Value> g3s2;
3445
3446   {
3447     HandleScope scope(iso);
3448     g1s1.Reset(iso, Object::New());
3449     g1s2.Reset(iso, Object::New());
3450     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3451     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3452
3453     g2s1.Reset(iso, Object::New());
3454     g2s2.Reset(iso, Object::New());
3455     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3456     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3457
3458     g3s1.Reset(iso, Object::New());
3459     g3s2.Reset(iso, Object::New());
3460     g3s1.MakeWeak(&counter, &WeakPointerCallback);
3461     g3s2.MakeWeak(&counter, &WeakPointerCallback);
3462   }
3463
3464   // Make a root.
3465   Persistent<Value> root(iso, g1s1);
3466   root.MarkPartiallyDependent(iso);
3467
3468   // Connect groups.  We're building the following cycle:
3469   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3470   // groups.
3471   {
3472     HandleScope handle_scope(iso);
3473     g1s1.MarkPartiallyDependent(iso);
3474     g1s2.MarkPartiallyDependent(iso);
3475     g2s1.MarkPartiallyDependent(iso);
3476     g2s2.MarkPartiallyDependent(iso);
3477     g3s1.MarkPartiallyDependent(iso);
3478     g3s2.MarkPartiallyDependent(iso);
3479     iso->SetObjectGroupId(g1s1, UniqueId(1));
3480     iso->SetObjectGroupId(g1s2, UniqueId(1));
3481     Local<Object>::New(iso, g1s1.As<Object>())->Set(
3482         v8_str("x"), Local<Value>::New(iso, g2s1));
3483     iso->SetObjectGroupId(g2s1, UniqueId(2));
3484     iso->SetObjectGroupId(g2s2, UniqueId(2));
3485     Local<Object>::New(iso, g2s1.As<Object>())->Set(
3486         v8_str("x"), Local<Value>::New(iso, g3s1));
3487     iso->SetObjectGroupId(g3s1, UniqueId(3));
3488     iso->SetObjectGroupId(g3s2, UniqueId(3));
3489     Local<Object>::New(iso, g3s1.As<Object>())->Set(
3490         v8_str("x"), Local<Value>::New(iso, g1s1));
3491   }
3492
3493   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3494       iso)->heap();
3495   heap->CollectGarbage(i::NEW_SPACE);
3496
3497   // All objects should be alive.
3498   CHECK_EQ(0, counter.NumberOfWeakCalls());
3499
3500   // Weaken the root.
3501   root.MakeWeak(&counter, &WeakPointerCallback);
3502   root.MarkPartiallyDependent(iso);
3503
3504   v8::Isolate* isolate = v8::Isolate::GetCurrent();
3505   // Groups are deleted, rebuild groups.
3506   {
3507     HandleScope handle_scope(iso);
3508     g1s1.MarkPartiallyDependent(isolate);
3509     g1s2.MarkPartiallyDependent(isolate);
3510     g2s1.MarkPartiallyDependent(isolate);
3511     g2s2.MarkPartiallyDependent(isolate);
3512     g3s1.MarkPartiallyDependent(isolate);
3513     g3s2.MarkPartiallyDependent(isolate);
3514     iso->SetObjectGroupId(g1s1, UniqueId(1));
3515     iso->SetObjectGroupId(g1s2, UniqueId(1));
3516     Local<Object>::New(iso, g1s1.As<Object>())->Set(
3517         v8_str("x"), Local<Value>::New(iso, g2s1));
3518     iso->SetObjectGroupId(g2s1, UniqueId(2));
3519     iso->SetObjectGroupId(g2s2, UniqueId(2));
3520     Local<Object>::New(iso, g2s1.As<Object>())->Set(
3521         v8_str("x"), Local<Value>::New(iso, g3s1));
3522     iso->SetObjectGroupId(g3s1, UniqueId(3));
3523     iso->SetObjectGroupId(g3s2, UniqueId(3));
3524     Local<Object>::New(iso, g3s1.As<Object>())->Set(
3525         v8_str("x"), Local<Value>::New(iso, g1s1));
3526   }
3527
3528   heap->CollectGarbage(i::NEW_SPACE);
3529
3530   // All objects should be gone. 7 global handles in total.
3531   CHECK_EQ(7, counter.NumberOfWeakCalls());
3532 }
3533
3534
3535 THREADED_TEST(ScriptException) {
3536   LocalContext env;
3537   v8::HandleScope scope(env->GetIsolate());
3538   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3539   v8::TryCatch try_catch;
3540   Local<Value> result = script->Run();
3541   CHECK(result.IsEmpty());
3542   CHECK(try_catch.HasCaught());
3543   String::Utf8Value exception_value(try_catch.Exception());
3544   CHECK_EQ(*exception_value, "panama!");
3545 }
3546
3547
3548 TEST(TryCatchCustomException) {
3549   LocalContext env;
3550   v8::HandleScope scope(env->GetIsolate());
3551   v8::TryCatch try_catch;
3552   CompileRun("function CustomError() { this.a = 'b'; }"
3553              "(function f() { throw new CustomError(); })();");
3554   CHECK(try_catch.HasCaught());
3555   CHECK(try_catch.Exception()->ToObject()->
3556             Get(v8_str("a"))->Equals(v8_str("b")));
3557 }
3558
3559
3560 bool message_received;
3561
3562
3563 static void check_message_0(v8::Handle<v8::Message> message,
3564                             v8::Handle<Value> data) {
3565   CHECK_EQ(5.76, data->NumberValue());
3566   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3567   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3568   message_received = true;
3569 }
3570
3571
3572 THREADED_TEST(MessageHandler0) {
3573   message_received = false;
3574   v8::HandleScope scope(v8::Isolate::GetCurrent());
3575   CHECK(!message_received);
3576   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3577   LocalContext context;
3578   v8::ScriptOrigin origin =
3579       v8::ScriptOrigin(v8_str("6.75"));
3580   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3581                                                   &origin);
3582   script->SetData(v8_str("7.56"));
3583   script->Run();
3584   CHECK(message_received);
3585   // clear out the message listener
3586   v8::V8::RemoveMessageListeners(check_message_0);
3587 }
3588
3589
3590 static void check_message_1(v8::Handle<v8::Message> message,
3591                             v8::Handle<Value> data) {
3592   CHECK(data->IsNumber());
3593   CHECK_EQ(1337, data->Int32Value());
3594   message_received = true;
3595 }
3596
3597
3598 TEST(MessageHandler1) {
3599   message_received = false;
3600   v8::HandleScope scope(v8::Isolate::GetCurrent());
3601   CHECK(!message_received);
3602   v8::V8::AddMessageListener(check_message_1);
3603   LocalContext context;
3604   CompileRun("throw 1337;");
3605   CHECK(message_received);
3606   // clear out the message listener
3607   v8::V8::RemoveMessageListeners(check_message_1);
3608 }
3609
3610
3611 static void check_message_2(v8::Handle<v8::Message> message,
3612                             v8::Handle<Value> data) {
3613   LocalContext context;
3614   CHECK(data->IsObject());
3615   v8::Local<v8::Value> hidden_property =
3616       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
3617   CHECK(v8_str("hidden value")->Equals(hidden_property));
3618   message_received = true;
3619 }
3620
3621
3622 TEST(MessageHandler2) {
3623   message_received = false;
3624   v8::HandleScope scope(v8::Isolate::GetCurrent());
3625   CHECK(!message_received);
3626   v8::V8::AddMessageListener(check_message_2);
3627   LocalContext context;
3628   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
3629   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
3630                                            v8_str("hidden value"));
3631   context->Global()->Set(v8_str("error"), error);
3632   CompileRun("throw error;");
3633   CHECK(message_received);
3634   // clear out the message listener
3635   v8::V8::RemoveMessageListeners(check_message_2);
3636 }
3637
3638
3639 THREADED_TEST(GetSetProperty) {
3640   LocalContext context;
3641   v8::HandleScope scope(context->GetIsolate());
3642   context->Global()->Set(v8_str("foo"), v8_num(14));
3643   context->Global()->Set(v8_str("12"), v8_num(92));
3644   context->Global()->Set(v8::Integer::New(16), v8_num(32));
3645   context->Global()->Set(v8_num(13), v8_num(56));
3646   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
3647   CHECK_EQ(14, foo->Int32Value());
3648   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
3649   CHECK_EQ(92, twelve->Int32Value());
3650   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
3651   CHECK_EQ(32, sixteen->Int32Value());
3652   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
3653   CHECK_EQ(56, thirteen->Int32Value());
3654   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
3655   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
3656   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
3657   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
3658   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
3659   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
3660   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
3661   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
3662   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
3663 }
3664
3665
3666 THREADED_TEST(PropertyAttributes) {
3667   LocalContext context;
3668   v8::HandleScope scope(context->GetIsolate());
3669   // none
3670   Local<String> prop = v8_str("none");
3671   context->Global()->Set(prop, v8_num(7));
3672   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3673   // read-only
3674   prop = v8_str("read_only");
3675   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
3676   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3677   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
3678   Script::Compile(v8_str("read_only = 9"))->Run();
3679   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3680   context->Global()->Set(prop, v8_num(10));
3681   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3682   // dont-delete
3683   prop = v8_str("dont_delete");
3684   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
3685   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3686   Script::Compile(v8_str("delete dont_delete"))->Run();
3687   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3688   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
3689   // dont-enum
3690   prop = v8_str("dont_enum");
3691   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
3692   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
3693   // absent
3694   prop = v8_str("absent");
3695   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3696   Local<Value> fake_prop = v8_num(1);
3697   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
3698   // exception
3699   TryCatch try_catch;
3700   Local<Value> exception =
3701       CompileRun("({ toString: function() { throw 'exception';} })");
3702   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
3703   CHECK(try_catch.HasCaught());
3704   String::Utf8Value exception_value(try_catch.Exception());
3705   CHECK_EQ("exception", *exception_value);
3706   try_catch.Reset();
3707 }
3708
3709
3710 THREADED_TEST(Array) {
3711   LocalContext context;
3712   v8::HandleScope scope(context->GetIsolate());
3713   Local<v8::Array> array = v8::Array::New();
3714   CHECK_EQ(0, array->Length());
3715   CHECK(array->Get(0)->IsUndefined());
3716   CHECK(!array->Has(0));
3717   CHECK(array->Get(100)->IsUndefined());
3718   CHECK(!array->Has(100));
3719   array->Set(2, v8_num(7));
3720   CHECK_EQ(3, array->Length());
3721   CHECK(!array->Has(0));
3722   CHECK(!array->Has(1));
3723   CHECK(array->Has(2));
3724   CHECK_EQ(7, array->Get(2)->Int32Value());
3725   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
3726   Local<v8::Array> arr = obj.As<v8::Array>();
3727   CHECK_EQ(3, arr->Length());
3728   CHECK_EQ(1, arr->Get(0)->Int32Value());
3729   CHECK_EQ(2, arr->Get(1)->Int32Value());
3730   CHECK_EQ(3, arr->Get(2)->Int32Value());
3731   array = v8::Array::New(27);
3732   CHECK_EQ(27, array->Length());
3733   array = v8::Array::New(-27);
3734   CHECK_EQ(0, array->Length());
3735 }
3736
3737
3738 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
3739   v8::HandleScope scope(args.GetIsolate());
3740   ApiTestFuzzer::Fuzz();
3741   Local<v8::Array> result = v8::Array::New(args.Length());
3742   for (int i = 0; i < args.Length(); i++)
3743     result->Set(i, args[i]);
3744   args.GetReturnValue().Set(scope.Close(result));
3745 }
3746
3747
3748 THREADED_TEST(Vector) {
3749   v8::HandleScope scope(v8::Isolate::GetCurrent());
3750   Local<ObjectTemplate> global = ObjectTemplate::New();
3751   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
3752   LocalContext context(0, global);
3753
3754   const char* fun = "f()";
3755   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
3756   CHECK_EQ(0, a0->Length());
3757
3758   const char* fun2 = "f(11)";
3759   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
3760   CHECK_EQ(1, a1->Length());
3761   CHECK_EQ(11, a1->Get(0)->Int32Value());
3762
3763   const char* fun3 = "f(12, 13)";
3764   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
3765   CHECK_EQ(2, a2->Length());
3766   CHECK_EQ(12, a2->Get(0)->Int32Value());
3767   CHECK_EQ(13, a2->Get(1)->Int32Value());
3768
3769   const char* fun4 = "f(14, 15, 16)";
3770   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
3771   CHECK_EQ(3, a3->Length());
3772   CHECK_EQ(14, a3->Get(0)->Int32Value());
3773   CHECK_EQ(15, a3->Get(1)->Int32Value());
3774   CHECK_EQ(16, a3->Get(2)->Int32Value());
3775
3776   const char* fun5 = "f(17, 18, 19, 20)";
3777   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
3778   CHECK_EQ(4, a4->Length());
3779   CHECK_EQ(17, a4->Get(0)->Int32Value());
3780   CHECK_EQ(18, a4->Get(1)->Int32Value());
3781   CHECK_EQ(19, a4->Get(2)->Int32Value());
3782   CHECK_EQ(20, a4->Get(3)->Int32Value());
3783 }
3784
3785
3786 THREADED_TEST(FunctionCall) {
3787   LocalContext context;
3788   v8::HandleScope scope(context->GetIsolate());
3789   CompileRun(
3790     "function Foo() {"
3791     "  var result = [];"
3792     "  for (var i = 0; i < arguments.length; i++) {"
3793     "    result.push(arguments[i]);"
3794     "  }"
3795     "  return result;"
3796     "}");
3797   Local<Function> Foo =
3798       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3799
3800   v8::Handle<Value>* args0 = NULL;
3801   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
3802   CHECK_EQ(0, a0->Length());
3803
3804   v8::Handle<Value> args1[] = { v8_num(1.1) };
3805   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
3806   CHECK_EQ(1, a1->Length());
3807   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3808
3809   v8::Handle<Value> args2[] = { v8_num(2.2),
3810                                 v8_num(3.3) };
3811   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
3812   CHECK_EQ(2, a2->Length());
3813   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3814   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3815
3816   v8::Handle<Value> args3[] = { v8_num(4.4),
3817                                 v8_num(5.5),
3818                                 v8_num(6.6) };
3819   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
3820   CHECK_EQ(3, a3->Length());
3821   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3822   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3823   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3824
3825   v8::Handle<Value> args4[] = { v8_num(7.7),
3826                                 v8_num(8.8),
3827                                 v8_num(9.9),
3828                                 v8_num(10.11) };
3829   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
3830   CHECK_EQ(4, a4->Length());
3831   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3832   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3833   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3834   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3835 }
3836
3837
3838 static const char* js_code_causing_out_of_memory =
3839     "var a = new Array(); while(true) a.push(a);";
3840
3841
3842 // These tests run for a long time and prevent us from running tests
3843 // that come after them so they cannot run in parallel.
3844 TEST(OutOfMemory) {
3845   // It's not possible to read a snapshot into a heap with different dimensions.
3846   if (i::Snapshot::IsEnabled()) return;
3847   // Set heap limits.
3848   static const int K = 1024;
3849   v8::ResourceConstraints constraints;
3850   constraints.set_max_young_space_size(256 * K);
3851   constraints.set_max_old_space_size(5 * K * K);
3852   v8::SetResourceConstraints(&constraints);
3853
3854   // Execute a script that causes out of memory.
3855   LocalContext context;
3856   v8::HandleScope scope(context->GetIsolate());
3857   v8::V8::IgnoreOutOfMemoryException();
3858   Local<Script> script =
3859       Script::Compile(String::New(js_code_causing_out_of_memory));
3860   Local<Value> result = script->Run();
3861
3862   // Check for out of memory state.
3863   CHECK(result.IsEmpty());
3864   CHECK(context->HasOutOfMemoryException());
3865 }
3866
3867
3868 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
3869   ApiTestFuzzer::Fuzz();
3870
3871   LocalContext context;
3872   v8::HandleScope scope(context->GetIsolate());
3873   Local<Script> script =
3874       Script::Compile(String::New(js_code_causing_out_of_memory));
3875   Local<Value> result = script->Run();
3876
3877   // Check for out of memory state.
3878   CHECK(result.IsEmpty());
3879   CHECK(context->HasOutOfMemoryException());
3880
3881   args.GetReturnValue().Set(result);
3882 }
3883
3884
3885 TEST(OutOfMemoryNested) {
3886   // It's not possible to read a snapshot into a heap with different dimensions.
3887   if (i::Snapshot::IsEnabled()) return;
3888   // Set heap limits.
3889   static const int K = 1024;
3890   v8::ResourceConstraints constraints;
3891   constraints.set_max_young_space_size(256 * K);
3892   constraints.set_max_old_space_size(5 * K * K);
3893   v8::SetResourceConstraints(&constraints);
3894
3895   v8::HandleScope scope(v8::Isolate::GetCurrent());
3896   Local<ObjectTemplate> templ = ObjectTemplate::New();
3897   templ->Set(v8_str("ProvokeOutOfMemory"),
3898              v8::FunctionTemplate::New(ProvokeOutOfMemory));
3899   LocalContext context(0, templ);
3900   v8::V8::IgnoreOutOfMemoryException();
3901   Local<Value> result = CompileRun(
3902     "var thrown = false;"
3903     "try {"
3904     "  ProvokeOutOfMemory();"
3905     "} catch (e) {"
3906     "  thrown = true;"
3907     "}");
3908   // Check for out of memory state.
3909   CHECK(result.IsEmpty());
3910   CHECK(context->HasOutOfMemoryException());
3911 }
3912
3913
3914 TEST(HugeConsStringOutOfMemory) {
3915   // It's not possible to read a snapshot into a heap with different dimensions.
3916   if (i::Snapshot::IsEnabled()) return;
3917   // Set heap limits.
3918   static const int K = 1024;
3919   v8::ResourceConstraints constraints;
3920   constraints.set_max_young_space_size(256 * K);
3921   constraints.set_max_old_space_size(4 * K * K);
3922   v8::SetResourceConstraints(&constraints);
3923
3924   // Execute a script that causes out of memory.
3925   v8::V8::IgnoreOutOfMemoryException();
3926
3927   LocalContext context;
3928   v8::HandleScope scope(context->GetIsolate());
3929
3930   // Build huge string. This should fail with out of memory exception.
3931   Local<Value> result = CompileRun(
3932     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
3933     "for (var i = 0; i < 22; i++) { str = str + str; }");
3934
3935   // Check for out of memory state.
3936   CHECK(result.IsEmpty());
3937   CHECK(context->HasOutOfMemoryException());
3938 }
3939
3940
3941 THREADED_TEST(ConstructCall) {
3942   LocalContext context;
3943   v8::HandleScope scope(context->GetIsolate());
3944   CompileRun(
3945     "function Foo() {"
3946     "  var result = [];"
3947     "  for (var i = 0; i < arguments.length; i++) {"
3948     "    result.push(arguments[i]);"
3949     "  }"
3950     "  return result;"
3951     "}");
3952   Local<Function> Foo =
3953       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3954
3955   v8::Handle<Value>* args0 = NULL;
3956   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
3957   CHECK_EQ(0, a0->Length());
3958
3959   v8::Handle<Value> args1[] = { v8_num(1.1) };
3960   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
3961   CHECK_EQ(1, a1->Length());
3962   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3963
3964   v8::Handle<Value> args2[] = { v8_num(2.2),
3965                                 v8_num(3.3) };
3966   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
3967   CHECK_EQ(2, a2->Length());
3968   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3969   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3970
3971   v8::Handle<Value> args3[] = { v8_num(4.4),
3972                                 v8_num(5.5),
3973                                 v8_num(6.6) };
3974   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
3975   CHECK_EQ(3, a3->Length());
3976   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3977   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3978   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3979
3980   v8::Handle<Value> args4[] = { v8_num(7.7),
3981                                 v8_num(8.8),
3982                                 v8_num(9.9),
3983                                 v8_num(10.11) };
3984   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
3985   CHECK_EQ(4, a4->Length());
3986   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3987   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3988   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3989   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3990 }
3991
3992
3993 static void CheckUncle(v8::TryCatch* try_catch) {
3994   CHECK(try_catch->HasCaught());
3995   String::Utf8Value str_value(try_catch->Exception());
3996   CHECK_EQ(*str_value, "uncle?");
3997   try_catch->Reset();
3998 }
3999
4000
4001 THREADED_TEST(ConversionNumber) {
4002   LocalContext env;
4003   v8::HandleScope scope(env->GetIsolate());
4004   // Very large number.
4005   CompileRun("var obj = Math.pow(2,32) * 1237;");
4006   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4007   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4008   CHECK_EQ(0, obj->ToInt32()->Value());
4009   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4010   // Large number.
4011   CompileRun("var obj = -1234567890123;");
4012   obj = env->Global()->Get(v8_str("obj"));
4013   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4014   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4015   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4016   // Small positive integer.
4017   CompileRun("var obj = 42;");
4018   obj = env->Global()->Get(v8_str("obj"));
4019   CHECK_EQ(42.0, obj->ToNumber()->Value());
4020   CHECK_EQ(42, obj->ToInt32()->Value());
4021   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4022   // Negative integer.
4023   CompileRun("var obj = -37;");
4024   obj = env->Global()->Get(v8_str("obj"));
4025   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4026   CHECK_EQ(-37, obj->ToInt32()->Value());
4027   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4028   // Positive non-int32 integer.
4029   CompileRun("var obj = 0x81234567;");
4030   obj = env->Global()->Get(v8_str("obj"));
4031   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4032   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4033   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4034   // Fraction.
4035   CompileRun("var obj = 42.3;");
4036   obj = env->Global()->Get(v8_str("obj"));
4037   CHECK_EQ(42.3, obj->ToNumber()->Value());
4038   CHECK_EQ(42, obj->ToInt32()->Value());
4039   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4040   // Large negative fraction.
4041   CompileRun("var obj = -5726623061.75;");
4042   obj = env->Global()->Get(v8_str("obj"));
4043   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4044   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4045   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4046 }
4047
4048
4049 THREADED_TEST(isNumberType) {
4050   LocalContext env;
4051   v8::HandleScope scope(env->GetIsolate());
4052   // Very large number.
4053   CompileRun("var obj = Math.pow(2,32) * 1237;");
4054   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4055   CHECK(!obj->IsInt32());
4056   CHECK(!obj->IsUint32());
4057   // Large negative number.
4058   CompileRun("var obj = -1234567890123;");
4059   obj = env->Global()->Get(v8_str("obj"));
4060   CHECK(!obj->IsInt32());
4061   CHECK(!obj->IsUint32());
4062   // Small positive integer.
4063   CompileRun("var obj = 42;");
4064   obj = env->Global()->Get(v8_str("obj"));
4065   CHECK(obj->IsInt32());
4066   CHECK(obj->IsUint32());
4067   // Negative integer.
4068   CompileRun("var obj = -37;");
4069   obj = env->Global()->Get(v8_str("obj"));
4070   CHECK(obj->IsInt32());
4071   CHECK(!obj->IsUint32());
4072   // Positive non-int32 integer.
4073   CompileRun("var obj = 0x81234567;");
4074   obj = env->Global()->Get(v8_str("obj"));
4075   CHECK(!obj->IsInt32());
4076   CHECK(obj->IsUint32());
4077   // Fraction.
4078   CompileRun("var obj = 42.3;");
4079   obj = env->Global()->Get(v8_str("obj"));
4080   CHECK(!obj->IsInt32());
4081   CHECK(!obj->IsUint32());
4082   // Large negative fraction.
4083   CompileRun("var obj = -5726623061.75;");
4084   obj = env->Global()->Get(v8_str("obj"));
4085   CHECK(!obj->IsInt32());
4086   CHECK(!obj->IsUint32());
4087   // Positive zero
4088   CompileRun("var obj = 0.0;");
4089   obj = env->Global()->Get(v8_str("obj"));
4090   CHECK(obj->IsInt32());
4091   CHECK(obj->IsUint32());
4092   // Positive zero
4093   CompileRun("var obj = -0.0;");
4094   obj = env->Global()->Get(v8_str("obj"));
4095   CHECK(!obj->IsInt32());
4096   CHECK(!obj->IsUint32());
4097 }
4098
4099
4100 THREADED_TEST(ConversionException) {
4101   LocalContext env;
4102   v8::HandleScope scope(env->GetIsolate());
4103   CompileRun(
4104     "function TestClass() { };"
4105     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4106     "var obj = new TestClass();");
4107   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4108
4109   v8::TryCatch try_catch;
4110
4111   Local<Value> to_string_result = obj->ToString();
4112   CHECK(to_string_result.IsEmpty());
4113   CheckUncle(&try_catch);
4114
4115   Local<Value> to_number_result = obj->ToNumber();
4116   CHECK(to_number_result.IsEmpty());
4117   CheckUncle(&try_catch);
4118
4119   Local<Value> to_integer_result = obj->ToInteger();
4120   CHECK(to_integer_result.IsEmpty());
4121   CheckUncle(&try_catch);
4122
4123   Local<Value> to_uint32_result = obj->ToUint32();
4124   CHECK(to_uint32_result.IsEmpty());
4125   CheckUncle(&try_catch);
4126
4127   Local<Value> to_int32_result = obj->ToInt32();
4128   CHECK(to_int32_result.IsEmpty());
4129   CheckUncle(&try_catch);
4130
4131   Local<Value> to_object_result = v8::Undefined()->ToObject();
4132   CHECK(to_object_result.IsEmpty());
4133   CHECK(try_catch.HasCaught());
4134   try_catch.Reset();
4135
4136   int32_t int32_value = obj->Int32Value();
4137   CHECK_EQ(0, int32_value);
4138   CheckUncle(&try_catch);
4139
4140   uint32_t uint32_value = obj->Uint32Value();
4141   CHECK_EQ(0, uint32_value);
4142   CheckUncle(&try_catch);
4143
4144   double number_value = obj->NumberValue();
4145   CHECK_NE(0, std::isnan(number_value));
4146   CheckUncle(&try_catch);
4147
4148   int64_t integer_value = obj->IntegerValue();
4149   CHECK_EQ(0.0, static_cast<double>(integer_value));
4150   CheckUncle(&try_catch);
4151 }
4152
4153
4154 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4155   ApiTestFuzzer::Fuzz();
4156   v8::ThrowException(v8_str("konto"));
4157 }
4158
4159
4160 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4161   if (args.Length() < 1) {
4162     args.GetReturnValue().Set(false);
4163     return;
4164   }
4165   v8::HandleScope scope(args.GetIsolate());
4166   v8::TryCatch try_catch;
4167   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4168   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4169   args.GetReturnValue().Set(try_catch.HasCaught());
4170 }
4171
4172
4173 THREADED_TEST(APICatch) {
4174   v8::HandleScope scope(v8::Isolate::GetCurrent());
4175   Local<ObjectTemplate> templ = ObjectTemplate::New();
4176   templ->Set(v8_str("ThrowFromC"),
4177              v8::FunctionTemplate::New(ThrowFromC));
4178   LocalContext context(0, templ);
4179   CompileRun(
4180     "var thrown = false;"
4181     "try {"
4182     "  ThrowFromC();"
4183     "} catch (e) {"
4184     "  thrown = true;"
4185     "}");
4186   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4187   CHECK(thrown->BooleanValue());
4188 }
4189
4190
4191 THREADED_TEST(APIThrowTryCatch) {
4192   v8::HandleScope scope(v8::Isolate::GetCurrent());
4193   Local<ObjectTemplate> templ = ObjectTemplate::New();
4194   templ->Set(v8_str("ThrowFromC"),
4195              v8::FunctionTemplate::New(ThrowFromC));
4196   LocalContext context(0, templ);
4197   v8::TryCatch try_catch;
4198   CompileRun("ThrowFromC();");
4199   CHECK(try_catch.HasCaught());
4200 }
4201
4202
4203 // Test that a try-finally block doesn't shadow a try-catch block
4204 // when setting up an external handler.
4205 //
4206 // BUG(271): Some of the exception propagation does not work on the
4207 // ARM simulator because the simulator separates the C++ stack and the
4208 // JS stack.  This test therefore fails on the simulator.  The test is
4209 // not threaded to allow the threading tests to run on the simulator.
4210 TEST(TryCatchInTryFinally) {
4211   v8::HandleScope scope(v8::Isolate::GetCurrent());
4212   Local<ObjectTemplate> templ = ObjectTemplate::New();
4213   templ->Set(v8_str("CCatcher"),
4214              v8::FunctionTemplate::New(CCatcher));
4215   LocalContext context(0, templ);
4216   Local<Value> result = CompileRun("try {"
4217                                    "  try {"
4218                                    "    CCatcher('throw 7;');"
4219                                    "  } finally {"
4220                                    "  }"
4221                                    "} catch (e) {"
4222                                    "}");
4223   CHECK(result->IsTrue());
4224 }
4225
4226
4227 static void check_reference_error_message(
4228     v8::Handle<v8::Message> message,
4229     v8::Handle<v8::Value> data) {
4230   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4231   CHECK(message->Get()->Equals(v8_str(reference_error)));
4232 }
4233
4234
4235 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4236   ApiTestFuzzer::Fuzz();
4237   CHECK(false);
4238 }
4239
4240
4241 // Test that overwritten methods are not invoked on uncaught exception
4242 // formatting. However, they are invoked when performing normal error
4243 // string conversions.
4244 TEST(APIThrowMessageOverwrittenToString) {
4245   v8::HandleScope scope(v8::Isolate::GetCurrent());
4246   v8::V8::AddMessageListener(check_reference_error_message);
4247   Local<ObjectTemplate> templ = ObjectTemplate::New();
4248   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
4249   LocalContext context(NULL, templ);
4250   CompileRun("asdf;");
4251   CompileRun("var limit = {};"
4252              "limit.valueOf = fail;"
4253              "Error.stackTraceLimit = limit;");
4254   CompileRun("asdf");
4255   CompileRun("Array.prototype.pop = fail;");
4256   CompileRun("Object.prototype.hasOwnProperty = fail;");
4257   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4258   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4259   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4260   CompileRun("ReferenceError.prototype.toString ="
4261              "  function() { return 'Whoops' }");
4262   CompileRun("asdf;");
4263   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4264   CompileRun("asdf;");
4265   CompileRun("ReferenceError.prototype.constructor = void 0;");
4266   CompileRun("asdf;");
4267   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4268   CompileRun("asdf;");
4269   CompileRun("ReferenceError.prototype = new Object();");
4270   CompileRun("asdf;");
4271   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4272   CHECK(string->Equals(v8_str("Whoops")));
4273   CompileRun("ReferenceError.prototype.constructor = new Object();"
4274              "ReferenceError.prototype.constructor.name = 1;"
4275              "Number.prototype.toString = function() { return 'Whoops'; };"
4276              "ReferenceError.prototype.toString = Object.prototype.toString;");
4277   CompileRun("asdf;");
4278   v8::V8::RemoveMessageListeners(check_reference_error_message);
4279 }
4280
4281
4282 static void check_custom_error_message(
4283     v8::Handle<v8::Message> message,
4284     v8::Handle<v8::Value> data) {
4285   const char* uncaught_error = "Uncaught MyError toString";
4286   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4287 }
4288
4289
4290 TEST(CustomErrorToString) {
4291   LocalContext context;
4292   v8::HandleScope scope(context->GetIsolate());
4293   v8::V8::AddMessageListener(check_custom_error_message);
4294   CompileRun(
4295     "function MyError(name, message) {                   "
4296     "  this.name = name;                                 "
4297     "  this.message = message;                           "
4298     "}                                                   "
4299     "MyError.prototype = Object.create(Error.prototype); "
4300     "MyError.prototype.toString = function() {           "
4301     "  return 'MyError toString';                        "
4302     "};                                                  "
4303     "throw new MyError('my name', 'my message');         ");
4304   v8::V8::RemoveMessageListeners(check_custom_error_message);
4305 }
4306
4307
4308 static void receive_message(v8::Handle<v8::Message> message,
4309                             v8::Handle<v8::Value> data) {
4310   message->Get();
4311   message_received = true;
4312 }
4313
4314
4315 TEST(APIThrowMessage) {
4316   message_received = false;
4317   v8::HandleScope scope(v8::Isolate::GetCurrent());
4318   v8::V8::AddMessageListener(receive_message);
4319   Local<ObjectTemplate> templ = ObjectTemplate::New();
4320   templ->Set(v8_str("ThrowFromC"),
4321              v8::FunctionTemplate::New(ThrowFromC));
4322   LocalContext context(0, templ);
4323   CompileRun("ThrowFromC();");
4324   CHECK(message_received);
4325   v8::V8::RemoveMessageListeners(receive_message);
4326 }
4327
4328
4329 TEST(APIThrowMessageAndVerboseTryCatch) {
4330   message_received = false;
4331   v8::HandleScope scope(v8::Isolate::GetCurrent());
4332   v8::V8::AddMessageListener(receive_message);
4333   Local<ObjectTemplate> templ = ObjectTemplate::New();
4334   templ->Set(v8_str("ThrowFromC"),
4335              v8::FunctionTemplate::New(ThrowFromC));
4336   LocalContext context(0, templ);
4337   v8::TryCatch try_catch;
4338   try_catch.SetVerbose(true);
4339   Local<Value> result = CompileRun("ThrowFromC();");
4340   CHECK(try_catch.HasCaught());
4341   CHECK(result.IsEmpty());
4342   CHECK(message_received);
4343   v8::V8::RemoveMessageListeners(receive_message);
4344 }
4345
4346
4347 TEST(APIStackOverflowAndVerboseTryCatch) {
4348   message_received = false;
4349   LocalContext context;
4350   v8::HandleScope scope(context->GetIsolate());
4351   v8::V8::AddMessageListener(receive_message);
4352   v8::TryCatch try_catch;
4353   try_catch.SetVerbose(true);
4354   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4355   CHECK(try_catch.HasCaught());
4356   CHECK(result.IsEmpty());
4357   CHECK(message_received);
4358   v8::V8::RemoveMessageListeners(receive_message);
4359 }
4360
4361
4362 THREADED_TEST(ExternalScriptException) {
4363   v8::HandleScope scope(v8::Isolate::GetCurrent());
4364   Local<ObjectTemplate> templ = ObjectTemplate::New();
4365   templ->Set(v8_str("ThrowFromC"),
4366              v8::FunctionTemplate::New(ThrowFromC));
4367   LocalContext context(0, templ);
4368
4369   v8::TryCatch try_catch;
4370   Local<Script> script
4371       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4372   Local<Value> result = script->Run();
4373   CHECK(result.IsEmpty());
4374   CHECK(try_catch.HasCaught());
4375   String::Utf8Value exception_value(try_catch.Exception());
4376   CHECK_EQ("konto", *exception_value);
4377 }
4378
4379
4380
4381 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
4382   ApiTestFuzzer::Fuzz();
4383   CHECK_EQ(4, args.Length());
4384   int count = args[0]->Int32Value();
4385   int cInterval = args[2]->Int32Value();
4386   if (count == 0) {
4387     v8::ThrowException(v8_str("FromC"));
4388     return;
4389   } else {
4390     Local<v8::Object> global = Context::GetCurrent()->Global();
4391     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
4392     v8::Handle<Value> argv[] = { v8_num(count - 1),
4393                                  args[1],
4394                                  args[2],
4395                                  args[3] };
4396     if (count % cInterval == 0) {
4397       v8::TryCatch try_catch;
4398       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
4399       int expected = args[3]->Int32Value();
4400       if (try_catch.HasCaught()) {
4401         CHECK_EQ(expected, count);
4402         CHECK(result.IsEmpty());
4403         CHECK(!i::Isolate::Current()->has_scheduled_exception());
4404       } else {
4405         CHECK_NE(expected, count);
4406       }
4407       args.GetReturnValue().Set(result);
4408       return;
4409     } else {
4410       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
4411       return;
4412     }
4413   }
4414 }
4415
4416
4417 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
4418   ApiTestFuzzer::Fuzz();
4419   CHECK_EQ(3, args.Length());
4420   bool equality = args[0]->BooleanValue();
4421   int count = args[1]->Int32Value();
4422   int expected = args[2]->Int32Value();
4423   if (equality) {
4424     CHECK_EQ(count, expected);
4425   } else {
4426     CHECK_NE(count, expected);
4427   }
4428 }
4429
4430
4431 THREADED_TEST(EvalInTryFinally) {
4432   LocalContext context;
4433   v8::HandleScope scope(context->GetIsolate());
4434   v8::TryCatch try_catch;
4435   CompileRun("(function() {"
4436              "  try {"
4437              "    eval('asldkf (*&^&*^');"
4438              "  } finally {"
4439              "    return;"
4440              "  }"
4441              "})()");
4442   CHECK(!try_catch.HasCaught());
4443 }
4444
4445
4446 // This test works by making a stack of alternating JavaScript and C
4447 // activations.  These activations set up exception handlers with regular
4448 // intervals, one interval for C activations and another for JavaScript
4449 // activations.  When enough activations have been created an exception is
4450 // thrown and we check that the right activation catches the exception and that
4451 // no other activations do.  The right activation is always the topmost one with
4452 // a handler, regardless of whether it is in JavaScript or C.
4453 //
4454 // The notation used to describe a test case looks like this:
4455 //
4456 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
4457 //
4458 // Each entry is an activation, either JS or C.  The index is the count at that
4459 // level.  Stars identify activations with exception handlers, the @ identifies
4460 // the exception handler that should catch the exception.
4461 //
4462 // BUG(271): Some of the exception propagation does not work on the
4463 // ARM simulator because the simulator separates the C++ stack and the
4464 // JS stack.  This test therefore fails on the simulator.  The test is
4465 // not threaded to allow the threading tests to run on the simulator.
4466 TEST(ExceptionOrder) {
4467   v8::HandleScope scope(v8::Isolate::GetCurrent());
4468   Local<ObjectTemplate> templ = ObjectTemplate::New();
4469   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
4470   templ->Set(v8_str("CThrowCountDown"),
4471              v8::FunctionTemplate::New(CThrowCountDown));
4472   LocalContext context(0, templ);
4473   CompileRun(
4474     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
4475     "  if (count == 0) throw 'FromJS';"
4476     "  if (count % jsInterval == 0) {"
4477     "    try {"
4478     "      var value = CThrowCountDown(count - 1,"
4479     "                                  jsInterval,"
4480     "                                  cInterval,"
4481     "                                  expected);"
4482     "      check(false, count, expected);"
4483     "      return value;"
4484     "    } catch (e) {"
4485     "      check(true, count, expected);"
4486     "    }"
4487     "  } else {"
4488     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
4489     "  }"
4490     "}");
4491   Local<Function> fun =
4492       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
4493
4494   const int argc = 4;
4495   //                             count      jsInterval cInterval  expected
4496
4497   // *JS[4] *C[3] @JS[2] C[1] JS[0]
4498   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
4499   fun->Call(fun, argc, a0);
4500
4501   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
4502   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
4503   fun->Call(fun, argc, a1);
4504
4505   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
4506   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
4507   fun->Call(fun, argc, a2);
4508
4509   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
4510   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
4511   fun->Call(fun, argc, a3);
4512
4513   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
4514   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
4515   fun->Call(fun, argc, a4);
4516
4517   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
4518   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
4519   fun->Call(fun, argc, a5);
4520 }
4521
4522
4523 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
4524   ApiTestFuzzer::Fuzz();
4525   CHECK_EQ(1, args.Length());
4526   v8::ThrowException(args[0]);
4527 }
4528
4529
4530 THREADED_TEST(ThrowValues) {
4531   v8::HandleScope scope(v8::Isolate::GetCurrent());
4532   Local<ObjectTemplate> templ = ObjectTemplate::New();
4533   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
4534   LocalContext context(0, templ);
4535   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4536     "function Run(obj) {"
4537     "  try {"
4538     "    Throw(obj);"
4539     "  } catch (e) {"
4540     "    return e;"
4541     "  }"
4542     "  return 'no exception';"
4543     "}"
4544     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
4545   CHECK_EQ(5, result->Length());
4546   CHECK(result->Get(v8::Integer::New(0))->IsString());
4547   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
4548   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
4549   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
4550   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
4551   CHECK(result->Get(v8::Integer::New(3))->IsNull());
4552   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
4553 }
4554
4555
4556 THREADED_TEST(CatchZero) {
4557   LocalContext context;
4558   v8::HandleScope scope(context->GetIsolate());
4559   v8::TryCatch try_catch;
4560   CHECK(!try_catch.HasCaught());
4561   Script::Compile(v8_str("throw 10"))->Run();
4562   CHECK(try_catch.HasCaught());
4563   CHECK_EQ(10, try_catch.Exception()->Int32Value());
4564   try_catch.Reset();
4565   CHECK(!try_catch.HasCaught());
4566   Script::Compile(v8_str("throw 0"))->Run();
4567   CHECK(try_catch.HasCaught());
4568   CHECK_EQ(0, try_catch.Exception()->Int32Value());
4569 }
4570
4571
4572 THREADED_TEST(CatchExceptionFromWith) {
4573   LocalContext context;
4574   v8::HandleScope scope(context->GetIsolate());
4575   v8::TryCatch try_catch;
4576   CHECK(!try_catch.HasCaught());
4577   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
4578   CHECK(try_catch.HasCaught());
4579 }
4580
4581
4582 THREADED_TEST(TryCatchAndFinallyHidingException) {
4583   LocalContext context;
4584   v8::HandleScope scope(context->GetIsolate());
4585   v8::TryCatch try_catch;
4586   CHECK(!try_catch.HasCaught());
4587   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
4588   CompileRun("f({toString: function() { throw 42; }});");
4589   CHECK(!try_catch.HasCaught());
4590 }
4591
4592
4593 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
4594   v8::TryCatch try_catch;
4595 }
4596
4597
4598 THREADED_TEST(TryCatchAndFinally) {
4599   LocalContext context;
4600   v8::HandleScope scope(context->GetIsolate());
4601   context->Global()->Set(
4602       v8_str("native_with_try_catch"),
4603       v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
4604   v8::TryCatch try_catch;
4605   CHECK(!try_catch.HasCaught());
4606   CompileRun(
4607       "try {\n"
4608       "  throw new Error('a');\n"
4609       "} finally {\n"
4610       "  native_with_try_catch();\n"
4611       "}\n");
4612   CHECK(try_catch.HasCaught());
4613 }
4614
4615
4616 static void TryCatchNestedHelper(int depth) {
4617   if (depth > 0) {
4618     v8::TryCatch try_catch;
4619     try_catch.SetVerbose(true);
4620     TryCatchNestedHelper(depth - 1);
4621     CHECK(try_catch.HasCaught());
4622     try_catch.ReThrow();
4623   } else {
4624     v8::ThrowException(v8_str("back"));
4625   }
4626 }
4627
4628
4629 TEST(TryCatchNested) {
4630   v8::V8::Initialize();
4631   LocalContext context;
4632   v8::HandleScope scope(context->GetIsolate());
4633   v8::TryCatch try_catch;
4634   TryCatchNestedHelper(5);
4635   CHECK(try_catch.HasCaught());
4636   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
4637 }
4638
4639
4640 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
4641   CHECK(try_catch->HasCaught());
4642   Handle<Message> message = try_catch->Message();
4643   Handle<Value> resource = message->GetScriptResourceName();
4644   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
4645   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
4646                      "Uncaught Error: a"));
4647   CHECK_EQ(1, message->GetLineNumber());
4648   CHECK_EQ(6, message->GetStartColumn());
4649 }
4650
4651
4652 void TryCatchMixedNestingHelper(
4653     const v8::FunctionCallbackInfo<v8::Value>& args) {
4654   ApiTestFuzzer::Fuzz();
4655   v8::TryCatch try_catch;
4656   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
4657   CHECK(try_catch.HasCaught());
4658   TryCatchMixedNestingCheck(&try_catch);
4659   try_catch.ReThrow();
4660 }
4661
4662
4663 // This test ensures that an outer TryCatch in the following situation:
4664 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
4665 // does not clobber the Message object generated for the inner TryCatch.
4666 // This exercises the ability of TryCatch.ReThrow() to restore the
4667 // inner pending Message before throwing the exception again.
4668 TEST(TryCatchMixedNesting) {
4669   v8::HandleScope scope(v8::Isolate::GetCurrent());
4670   v8::V8::Initialize();
4671   v8::TryCatch try_catch;
4672   Local<ObjectTemplate> templ = ObjectTemplate::New();
4673   templ->Set(v8_str("TryCatchMixedNestingHelper"),
4674              v8::FunctionTemplate::New(TryCatchMixedNestingHelper));
4675   LocalContext context(0, templ);
4676   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
4677   TryCatchMixedNestingCheck(&try_catch);
4678 }
4679
4680
4681 THREADED_TEST(Equality) {
4682   LocalContext context;
4683   v8::Isolate* isolate = context->GetIsolate();
4684   v8::HandleScope scope(context->GetIsolate());
4685   // Check that equality works at all before relying on CHECK_EQ
4686   CHECK(v8_str("a")->Equals(v8_str("a")));
4687   CHECK(!v8_str("a")->Equals(v8_str("b")));
4688
4689   CHECK_EQ(v8_str("a"), v8_str("a"));
4690   CHECK_NE(v8_str("a"), v8_str("b"));
4691   CHECK_EQ(v8_num(1), v8_num(1));
4692   CHECK_EQ(v8_num(1.00), v8_num(1));
4693   CHECK_NE(v8_num(1), v8_num(2));
4694
4695   // Assume String is not internalized.
4696   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
4697   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
4698   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
4699   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
4700   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
4701   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
4702   Local<Value> not_a_number = v8_num(i::OS::nan_value());
4703   CHECK(!not_a_number->StrictEquals(not_a_number));
4704   CHECK(v8::False()->StrictEquals(v8::False()));
4705   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
4706
4707   v8::Handle<v8::Object> obj = v8::Object::New();
4708   v8::Persistent<v8::Object> alias(isolate, obj);
4709   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
4710   alias.Dispose(isolate);
4711 }
4712
4713
4714 THREADED_TEST(MultiRun) {
4715   LocalContext context;
4716   v8::HandleScope scope(context->GetIsolate());
4717   Local<Script> script = Script::Compile(v8_str("x"));
4718   for (int i = 0; i < 10; i++)
4719     script->Run();
4720 }
4721
4722
4723 static void GetXValue(Local<String> name,
4724                       const v8::PropertyCallbackInfo<v8::Value>& info) {
4725   ApiTestFuzzer::Fuzz();
4726   CHECK_EQ(info.Data(), v8_str("donut"));
4727   CHECK_EQ(name, v8_str("x"));
4728   info.GetReturnValue().Set(name);
4729 }
4730
4731
4732 THREADED_TEST(SimplePropertyRead) {
4733   LocalContext context;
4734   v8::HandleScope scope(context->GetIsolate());
4735   Local<ObjectTemplate> templ = ObjectTemplate::New();
4736   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
4737   context->Global()->Set(v8_str("obj"), templ->NewInstance());
4738   Local<Script> script = Script::Compile(v8_str("obj.x"));
4739   for (int i = 0; i < 10; i++) {
4740     Local<Value> result = script->Run();
4741     CHECK_EQ(result, v8_str("x"));
4742   }
4743 }
4744
4745
4746 THREADED_TEST(DefinePropertyOnAPIAccessor) {
4747   LocalContext context;
4748   v8::HandleScope scope(context->GetIsolate());
4749   Local<ObjectTemplate> templ = ObjectTemplate::New();
4750   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
4751   context->Global()->Set(v8_str("obj"), templ->NewInstance());
4752
4753   // Uses getOwnPropertyDescriptor to check the configurable status
4754   Local<Script> script_desc
4755     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
4756                              "obj, 'x');"
4757                              "prop.configurable;"));
4758   Local<Value> result = script_desc->Run();
4759   CHECK_EQ(result->BooleanValue(), true);
4760
4761   // Redefine get - but still configurable
4762   Local<Script> script_define
4763     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
4764                              "            configurable: true };"
4765                              "Object.defineProperty(obj, 'x', desc);"
4766                              "obj.x"));
4767   result = script_define->Run();
4768   CHECK_EQ(result, v8_num(42));
4769
4770   // Check that the accessor is still configurable
4771   result = script_desc->Run();
4772   CHECK_EQ(result->BooleanValue(), true);
4773
4774   // Redefine to a non-configurable
4775   script_define
4776     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
4777                              "             configurable: false };"
4778                              "Object.defineProperty(obj, 'x', desc);"
4779                              "obj.x"));
4780   result = script_define->Run();
4781   CHECK_EQ(result, v8_num(43));
4782   result = script_desc->Run();
4783   CHECK_EQ(result->BooleanValue(), false);
4784
4785   // Make sure that it is not possible to redefine again
4786   v8::TryCatch try_catch;
4787   result = script_define->Run();
4788   CHECK(try_catch.HasCaught());
4789   String::Utf8Value exception_value(try_catch.Exception());
4790   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4791 }
4792
4793
4794 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
4795   v8::HandleScope scope(v8::Isolate::GetCurrent());
4796   Local<ObjectTemplate> templ = ObjectTemplate::New();
4797   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
4798   LocalContext context;
4799   context->Global()->Set(v8_str("obj"), templ->NewInstance());
4800
4801   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
4802                                     "Object.getOwnPropertyDescriptor( "
4803                                     "obj, 'x');"
4804                                     "prop.configurable;"));
4805   Local<Value> result = script_desc->Run();
4806   CHECK_EQ(result->BooleanValue(), true);
4807
4808   Local<Script> script_define =
4809     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
4810                            "            configurable: true };"
4811                            "Object.defineProperty(obj, 'x', desc);"
4812                            "obj.x"));
4813   result = script_define->Run();
4814   CHECK_EQ(result, v8_num(42));
4815
4816
4817   result = script_desc->Run();
4818   CHECK_EQ(result->BooleanValue(), true);
4819
4820
4821   script_define =
4822     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
4823                            "            configurable: false };"
4824                            "Object.defineProperty(obj, 'x', desc);"
4825                            "obj.x"));
4826   result = script_define->Run();
4827   CHECK_EQ(result, v8_num(43));
4828   result = script_desc->Run();
4829
4830   CHECK_EQ(result->BooleanValue(), false);
4831
4832   v8::TryCatch try_catch;
4833   result = script_define->Run();
4834   CHECK(try_catch.HasCaught());
4835   String::Utf8Value exception_value(try_catch.Exception());
4836   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4837 }
4838
4839
4840 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
4841                                                 char const* name) {
4842   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
4843 }
4844
4845
4846 THREADED_TEST(DefineAPIAccessorOnObject) {
4847   v8::HandleScope scope(v8::Isolate::GetCurrent());
4848   Local<ObjectTemplate> templ = ObjectTemplate::New();
4849   LocalContext context;
4850
4851   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4852   CompileRun("var obj2 = {};");
4853
4854   CHECK(CompileRun("obj1.x")->IsUndefined());
4855   CHECK(CompileRun("obj2.x")->IsUndefined());
4856
4857   CHECK(GetGlobalProperty(&context, "obj1")->
4858       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4859
4860   ExpectString("obj1.x", "x");
4861   CHECK(CompileRun("obj2.x")->IsUndefined());
4862
4863   CHECK(GetGlobalProperty(&context, "obj2")->
4864       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4865
4866   ExpectString("obj1.x", "x");
4867   ExpectString("obj2.x", "x");
4868
4869   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4870   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4871
4872   CompileRun("Object.defineProperty(obj1, 'x',"
4873              "{ get: function() { return 'y'; }, configurable: true })");
4874
4875   ExpectString("obj1.x", "y");
4876   ExpectString("obj2.x", "x");
4877
4878   CompileRun("Object.defineProperty(obj2, 'x',"
4879              "{ get: function() { return 'y'; }, configurable: true })");
4880
4881   ExpectString("obj1.x", "y");
4882   ExpectString("obj2.x", "y");
4883
4884   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4885   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4886
4887   CHECK(GetGlobalProperty(&context, "obj1")->
4888       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4889   CHECK(GetGlobalProperty(&context, "obj2")->
4890       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4891
4892   ExpectString("obj1.x", "x");
4893   ExpectString("obj2.x", "x");
4894
4895   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4896   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4897
4898   // Define getters/setters, but now make them not configurable.
4899   CompileRun("Object.defineProperty(obj1, 'x',"
4900              "{ get: function() { return 'z'; }, configurable: false })");
4901   CompileRun("Object.defineProperty(obj2, 'x',"
4902              "{ get: function() { return 'z'; }, configurable: false })");
4903
4904   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4905   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4906
4907   ExpectString("obj1.x", "z");
4908   ExpectString("obj2.x", "z");
4909
4910   CHECK(!GetGlobalProperty(&context, "obj1")->
4911       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4912   CHECK(!GetGlobalProperty(&context, "obj2")->
4913       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4914
4915   ExpectString("obj1.x", "z");
4916   ExpectString("obj2.x", "z");
4917 }
4918
4919
4920 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
4921   v8::HandleScope scope(v8::Isolate::GetCurrent());
4922   Local<ObjectTemplate> templ = ObjectTemplate::New();
4923   LocalContext context;
4924
4925   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4926   CompileRun("var obj2 = {};");
4927
4928   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4929         v8_str("x"),
4930         GetXValue, NULL,
4931         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4932   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4933         v8_str("x"),
4934         GetXValue, NULL,
4935         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4936
4937   ExpectString("obj1.x", "x");
4938   ExpectString("obj2.x", "x");
4939
4940   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4941   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4942
4943   CHECK(!GetGlobalProperty(&context, "obj1")->
4944       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4945   CHECK(!GetGlobalProperty(&context, "obj2")->
4946       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4947
4948   {
4949     v8::TryCatch try_catch;
4950     CompileRun("Object.defineProperty(obj1, 'x',"
4951         "{get: function() { return 'func'; }})");
4952     CHECK(try_catch.HasCaught());
4953     String::Utf8Value exception_value(try_catch.Exception());
4954     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4955   }
4956   {
4957     v8::TryCatch try_catch;
4958     CompileRun("Object.defineProperty(obj2, 'x',"
4959         "{get: function() { return 'func'; }})");
4960     CHECK(try_catch.HasCaught());
4961     String::Utf8Value exception_value(try_catch.Exception());
4962     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4963   }
4964 }
4965
4966
4967 static void Get239Value(Local<String> name,
4968                         const v8::PropertyCallbackInfo<v8::Value>& info) {
4969   ApiTestFuzzer::Fuzz();
4970   CHECK_EQ(info.Data(), v8_str("donut"));
4971   CHECK_EQ(name, v8_str("239"));
4972   info.GetReturnValue().Set(name);
4973 }
4974
4975
4976 THREADED_TEST(ElementAPIAccessor) {
4977   v8::HandleScope scope(v8::Isolate::GetCurrent());
4978   Local<ObjectTemplate> templ = ObjectTemplate::New();
4979   LocalContext context;
4980
4981   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4982   CompileRun("var obj2 = {};");
4983
4984   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4985         v8_str("239"),
4986         Get239Value, NULL,
4987         v8_str("donut")));
4988   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4989         v8_str("239"),
4990         Get239Value, NULL,
4991         v8_str("donut")));
4992
4993   ExpectString("obj1[239]", "239");
4994   ExpectString("obj2[239]", "239");
4995   ExpectString("obj1['239']", "239");
4996   ExpectString("obj2['239']", "239");
4997 }
4998
4999
5000 v8::Persistent<Value> xValue;
5001
5002
5003 static void SetXValue(Local<String> name,
5004                       Local<Value> value,
5005                       const v8::PropertyCallbackInfo<void>& info) {
5006   CHECK_EQ(value, v8_num(4));
5007   CHECK_EQ(info.Data(), v8_str("donut"));
5008   CHECK_EQ(name, v8_str("x"));
5009   CHECK(xValue.IsEmpty());
5010   xValue.Reset(info.GetIsolate(), value);
5011 }
5012
5013
5014 THREADED_TEST(SimplePropertyWrite) {
5015   v8::HandleScope scope(v8::Isolate::GetCurrent());
5016   Local<ObjectTemplate> templ = ObjectTemplate::New();
5017   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5018   LocalContext context;
5019   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5020   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5021   for (int i = 0; i < 10; i++) {
5022     CHECK(xValue.IsEmpty());
5023     script->Run();
5024     CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue));
5025     xValue.Dispose(context->GetIsolate());
5026     xValue.Clear();
5027   }
5028 }
5029
5030
5031 THREADED_TEST(SetterOnly) {
5032   v8::HandleScope scope(v8::Isolate::GetCurrent());
5033   Local<ObjectTemplate> templ = ObjectTemplate::New();
5034   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5035   LocalContext context;
5036   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5037   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5038   for (int i = 0; i < 10; i++) {
5039     CHECK(xValue.IsEmpty());
5040     script->Run();
5041     CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue));
5042     xValue.Dispose(context->GetIsolate());
5043     xValue.Clear();
5044   }
5045 }
5046
5047
5048 THREADED_TEST(NoAccessors) {
5049   v8::HandleScope scope(v8::Isolate::GetCurrent());
5050   Local<ObjectTemplate> templ = ObjectTemplate::New();
5051   templ->SetAccessor(v8_str("x"),
5052                      static_cast<v8::AccessorGetterCallback>(NULL),
5053                      NULL,
5054                      v8_str("donut"));
5055   LocalContext context;
5056   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5057   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5058   for (int i = 0; i < 10; i++) {
5059     script->Run();
5060   }
5061 }
5062
5063
5064 static void XPropertyGetter(Local<String> property,
5065                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5066   ApiTestFuzzer::Fuzz();
5067   CHECK(info.Data()->IsUndefined());
5068   info.GetReturnValue().Set(property);
5069 }
5070
5071
5072 THREADED_TEST(NamedInterceptorPropertyRead) {
5073   v8::HandleScope scope(v8::Isolate::GetCurrent());
5074   Local<ObjectTemplate> templ = ObjectTemplate::New();
5075   templ->SetNamedPropertyHandler(XPropertyGetter);
5076   LocalContext context;
5077   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5078   Local<Script> script = Script::Compile(v8_str("obj.x"));
5079   for (int i = 0; i < 10; i++) {
5080     Local<Value> result = script->Run();
5081     CHECK_EQ(result, v8_str("x"));
5082   }
5083 }
5084
5085
5086 THREADED_TEST(NamedInterceptorDictionaryIC) {
5087   v8::HandleScope scope(v8::Isolate::GetCurrent());
5088   Local<ObjectTemplate> templ = ObjectTemplate::New();
5089   templ->SetNamedPropertyHandler(XPropertyGetter);
5090   LocalContext context;
5091   // Create an object with a named interceptor.
5092   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5093   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5094   for (int i = 0; i < 10; i++) {
5095     Local<Value> result = script->Run();
5096     CHECK_EQ(result, v8_str("x"));
5097   }
5098   // Create a slow case object and a function accessing a property in
5099   // that slow case object (with dictionary probing in generated
5100   // code). Then force object with a named interceptor into slow-case,
5101   // pass it to the function, and check that the interceptor is called
5102   // instead of accessing the local property.
5103   Local<Value> result =
5104       CompileRun("function get_x(o) { return o.x; };"
5105                  "var obj = { x : 42, y : 0 };"
5106                  "delete obj.y;"
5107                  "for (var i = 0; i < 10; i++) get_x(obj);"
5108                  "interceptor_obj.x = 42;"
5109                  "interceptor_obj.y = 10;"
5110                  "delete interceptor_obj.y;"
5111                  "get_x(interceptor_obj)");
5112   CHECK_EQ(result, v8_str("x"));
5113 }
5114
5115
5116 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5117   v8::Isolate* isolate = v8::Isolate::GetCurrent();
5118   v8::HandleScope scope(isolate);
5119   v8::Local<Context> context1 = Context::New(isolate);
5120
5121   context1->Enter();
5122   Local<ObjectTemplate> templ = ObjectTemplate::New();
5123   templ->SetNamedPropertyHandler(XPropertyGetter);
5124   // Create an object with a named interceptor.
5125   v8::Local<v8::Object> object = templ->NewInstance();
5126   context1->Global()->Set(v8_str("interceptor_obj"), object);
5127
5128   // Force the object into the slow case.
5129   CompileRun("interceptor_obj.y = 0;"
5130              "delete interceptor_obj.y;");
5131   context1->Exit();
5132
5133   {
5134     // Introduce the object into a different context.
5135     // Repeat named loads to exercise ICs.
5136     LocalContext context2;
5137     context2->Global()->Set(v8_str("interceptor_obj"), object);
5138     Local<Value> result =
5139       CompileRun("function get_x(o) { return o.x; }"
5140                  "interceptor_obj.x = 42;"
5141                  "for (var i=0; i != 10; i++) {"
5142                  "  get_x(interceptor_obj);"
5143                  "}"
5144                  "get_x(interceptor_obj)");
5145     // Check that the interceptor was actually invoked.
5146     CHECK_EQ(result, v8_str("x"));
5147   }
5148
5149   // Return to the original context and force some object to the slow case
5150   // to cause the NormalizedMapCache to verify.
5151   context1->Enter();
5152   CompileRun("var obj = { x : 0 }; delete obj.x;");
5153   context1->Exit();
5154 }
5155
5156
5157 static void SetXOnPrototypeGetter(
5158     Local<String> property,
5159     const v8::PropertyCallbackInfo<v8::Value>& info) {
5160   // Set x on the prototype object and do not handle the get request.
5161   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5162   proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
5163 }
5164
5165
5166 // This is a regression test for http://crbug.com/20104. Map
5167 // transitions should not interfere with post interceptor lookup.
5168 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5169   v8::HandleScope scope(v8::Isolate::GetCurrent());
5170   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
5171   Local<v8::ObjectTemplate> instance_template
5172       = function_template->InstanceTemplate();
5173   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5174   LocalContext context;
5175   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5176   // Create an instance of F and introduce a map transition for x.
5177   CompileRun("var o = new F(); o.x = 23;");
5178   // Create an instance of F and invoke the getter. The result should be 23.
5179   Local<Value> result = CompileRun("o = new F(); o.x");
5180   CHECK_EQ(result->Int32Value(), 23);
5181 }
5182
5183
5184 static void IndexedPropertyGetter(
5185     uint32_t index,
5186     const v8::PropertyCallbackInfo<v8::Value>& info) {
5187   ApiTestFuzzer::Fuzz();
5188   if (index == 37) {
5189     info.GetReturnValue().Set(v8_num(625));
5190   }
5191 }
5192
5193
5194 static void IndexedPropertySetter(
5195     uint32_t index,
5196     Local<Value> value,
5197     const v8::PropertyCallbackInfo<v8::Value>& info) {
5198   ApiTestFuzzer::Fuzz();
5199   if (index == 39) {
5200     info.GetReturnValue().Set(value);
5201   }
5202 }
5203
5204
5205 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5206   v8::HandleScope scope(v8::Isolate::GetCurrent());
5207   Local<ObjectTemplate> templ = ObjectTemplate::New();
5208   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5209                                    IndexedPropertySetter);
5210   LocalContext context;
5211   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5212   Local<Script> getter_script = Script::Compile(v8_str(
5213       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5214   Local<Script> setter_script = Script::Compile(v8_str(
5215       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5216       "obj[17] = 23;"
5217       "obj.foo;"));
5218   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5219       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5220       "obj[39] = 47;"
5221       "obj.foo;"));  // This setter should not run, due to the interceptor.
5222   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5223       "obj[37];"));
5224   Local<Value> result = getter_script->Run();
5225   CHECK_EQ(v8_num(5), result);
5226   result = setter_script->Run();
5227   CHECK_EQ(v8_num(23), result);
5228   result = interceptor_setter_script->Run();
5229   CHECK_EQ(v8_num(23), result);
5230   result = interceptor_getter_script->Run();
5231   CHECK_EQ(v8_num(625), result);
5232 }
5233
5234
5235 static void UnboxedDoubleIndexedPropertyGetter(
5236     uint32_t index,
5237     const v8::PropertyCallbackInfo<v8::Value>& info) {
5238   ApiTestFuzzer::Fuzz();
5239   if (index < 25) {
5240     info.GetReturnValue().Set(v8_num(index));
5241   }
5242 }
5243
5244
5245 static void UnboxedDoubleIndexedPropertySetter(
5246     uint32_t index,
5247     Local<Value> value,
5248     const v8::PropertyCallbackInfo<v8::Value>& info) {
5249   ApiTestFuzzer::Fuzz();
5250   if (index < 25) {
5251     info.GetReturnValue().Set(v8_num(index));
5252   }
5253 }
5254
5255
5256 void UnboxedDoubleIndexedPropertyEnumerator(
5257     const v8::PropertyCallbackInfo<v8::Array>& info) {
5258   // Force the list of returned keys to be stored in a FastDoubleArray.
5259   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5260       "keys = new Array(); keys[125000] = 1;"
5261       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5262       "keys.length = 25; keys;"));
5263   Local<Value> result = indexed_property_names_script->Run();
5264   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5265 }
5266
5267
5268 // Make sure that the the interceptor code in the runtime properly handles
5269 // merging property name lists for double-array-backed arrays.
5270 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5271   v8::HandleScope scope(v8::Isolate::GetCurrent());
5272   Local<ObjectTemplate> templ = ObjectTemplate::New();
5273   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5274                                    UnboxedDoubleIndexedPropertySetter,
5275                                    0,
5276                                    0,
5277                                    UnboxedDoubleIndexedPropertyEnumerator);
5278   LocalContext context;
5279   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5280   // When obj is created, force it to be Stored in a FastDoubleArray.
5281   Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5282       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5283       "key_count = 0; "
5284       "for (x in obj) {key_count++;};"
5285       "obj;"));
5286   Local<Value> result = create_unboxed_double_script->Run();
5287   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5288   Local<Script> key_count_check = Script::Compile(v8_str(
5289       "key_count;"));
5290   result = key_count_check->Run();
5291   CHECK_EQ(v8_num(40013), result);
5292 }
5293
5294
5295 void NonStrictArgsIndexedPropertyEnumerator(
5296     const v8::PropertyCallbackInfo<v8::Array>& info) {
5297   // Force the list of returned keys to be stored in a Arguments object.
5298   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5299       "function f(w,x) {"
5300       " return arguments;"
5301       "}"
5302       "keys = f(0, 1, 2, 3);"
5303       "keys;"));
5304   Local<Object> result =
5305       Local<Object>::Cast(indexed_property_names_script->Run());
5306   // Have to populate the handle manually, as it's not Cast-able.
5307   i::Handle<i::JSObject> o =
5308       v8::Utils::OpenHandle<Object, i::JSObject>(result);
5309   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5310   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5311 }
5312
5313
5314 static void NonStrictIndexedPropertyGetter(
5315     uint32_t index,
5316     const v8::PropertyCallbackInfo<v8::Value>& info) {
5317   ApiTestFuzzer::Fuzz();
5318   if (index < 4) {
5319     info.GetReturnValue().Set(v8_num(index));
5320   }
5321 }
5322
5323
5324 // Make sure that the the interceptor code in the runtime properly handles
5325 // merging property name lists for non-string arguments arrays.
5326 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5327   v8::HandleScope scope(v8::Isolate::GetCurrent());
5328   Local<ObjectTemplate> templ = ObjectTemplate::New();
5329   templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5330                                    0,
5331                                    0,
5332                                    0,
5333                                    NonStrictArgsIndexedPropertyEnumerator);
5334   LocalContext context;
5335   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5336   Local<Script> create_args_script =
5337       Script::Compile(v8_str(
5338           "var key_count = 0;"
5339           "for (x in obj) {key_count++;} key_count;"));
5340   Local<Value> result = create_args_script->Run();
5341   CHECK_EQ(v8_num(4), result);
5342 }
5343
5344
5345 static void IdentityIndexedPropertyGetter(
5346     uint32_t index,
5347     const v8::PropertyCallbackInfo<v8::Value>& info) {
5348   info.GetReturnValue().Set(index);
5349 }
5350
5351
5352 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
5353   v8::HandleScope scope(v8::Isolate::GetCurrent());
5354   Local<ObjectTemplate> templ = ObjectTemplate::New();
5355   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5356
5357   LocalContext context;
5358   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5359
5360   // Check fast object case.
5361   const char* fast_case_code =
5362       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
5363   ExpectString(fast_case_code, "0");
5364
5365   // Check slow case.
5366   const char* slow_case_code =
5367       "obj.x = 1; delete obj.x;"
5368       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
5369   ExpectString(slow_case_code, "1");
5370 }
5371
5372
5373 THREADED_TEST(IndexedInterceptorWithNoSetter) {
5374   v8::HandleScope scope(v8::Isolate::GetCurrent());
5375   Local<ObjectTemplate> templ = ObjectTemplate::New();
5376   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5377
5378   LocalContext context;
5379   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5380
5381   const char* code =
5382       "try {"
5383       "  obj[0] = 239;"
5384       "  for (var i = 0; i < 100; i++) {"
5385       "    var v = obj[0];"
5386       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
5387       "  }"
5388       "  'PASSED'"
5389       "} catch(e) {"
5390       "  e"
5391       "}";
5392   ExpectString(code, "PASSED");
5393 }
5394
5395
5396 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
5397   v8::HandleScope scope(v8::Isolate::GetCurrent());
5398   Local<ObjectTemplate> templ = ObjectTemplate::New();
5399   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5400
5401   LocalContext context;
5402   Local<v8::Object> obj = templ->NewInstance();
5403   obj->TurnOnAccessCheck();
5404   context->Global()->Set(v8_str("obj"), obj);
5405
5406   const char* code =
5407       "try {"
5408       "  for (var i = 0; i < 100; i++) {"
5409       "    var v = obj[0];"
5410       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
5411       "  }"
5412       "  'PASSED'"
5413       "} catch(e) {"
5414       "  e"
5415       "}";
5416   ExpectString(code, "PASSED");
5417 }
5418
5419
5420 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
5421   i::FLAG_allow_natives_syntax = true;
5422   v8::HandleScope scope(v8::Isolate::GetCurrent());
5423   Local<ObjectTemplate> templ = ObjectTemplate::New();
5424   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5425
5426   LocalContext context;
5427   Local<v8::Object> obj = templ->NewInstance();
5428   context->Global()->Set(v8_str("obj"), obj);
5429
5430   const char* code =
5431       "try {"
5432       "  for (var i = 0; i < 100; i++) {"
5433       "    var expected = i;"
5434       "    if (i == 5) {"
5435       "      %EnableAccessChecks(obj);"
5436       "      expected = undefined;"
5437       "    }"
5438       "    var v = obj[i];"
5439       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5440       "    if (i == 5) %DisableAccessChecks(obj);"
5441       "  }"
5442       "  'PASSED'"
5443       "} catch(e) {"
5444       "  e"
5445       "}";
5446   ExpectString(code, "PASSED");
5447 }
5448
5449
5450 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
5451   v8::HandleScope scope(v8::Isolate::GetCurrent());
5452   Local<ObjectTemplate> templ = ObjectTemplate::New();
5453   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5454
5455   LocalContext context;
5456   Local<v8::Object> obj = templ->NewInstance();
5457   context->Global()->Set(v8_str("obj"), obj);
5458
5459   const char* code =
5460       "try {"
5461       "  for (var i = 0; i < 100; i++) {"
5462       "    var v = obj[i];"
5463       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5464       "  }"
5465       "  'PASSED'"
5466       "} catch(e) {"
5467       "  e"
5468       "}";
5469   ExpectString(code, "PASSED");
5470 }
5471
5472
5473 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
5474   v8::HandleScope scope(v8::Isolate::GetCurrent());
5475   Local<ObjectTemplate> templ = ObjectTemplate::New();
5476   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5477
5478   LocalContext context;
5479   Local<v8::Object> obj = templ->NewInstance();
5480   context->Global()->Set(v8_str("obj"), obj);
5481
5482   const char* code =
5483       "try {"
5484       "  for (var i = 0; i < 100; i++) {"
5485       "    var expected = i;"
5486       "    var key = i;"
5487       "    if (i == 25) {"
5488       "       key = -1;"
5489       "       expected = undefined;"
5490       "    }"
5491       "    if (i == 50) {"
5492       "       /* probe minimal Smi number on 32-bit platforms */"
5493       "       key = -(1 << 30);"
5494       "       expected = undefined;"
5495       "    }"
5496       "    if (i == 75) {"
5497       "       /* probe minimal Smi number on 64-bit platforms */"
5498       "       key = 1 << 31;"
5499       "       expected = undefined;"
5500       "    }"
5501       "    var v = obj[key];"
5502       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5503       "  }"
5504       "  'PASSED'"
5505       "} catch(e) {"
5506       "  e"
5507       "}";
5508   ExpectString(code, "PASSED");
5509 }
5510
5511
5512 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
5513   v8::HandleScope scope(v8::Isolate::GetCurrent());
5514   Local<ObjectTemplate> templ = ObjectTemplate::New();
5515   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5516
5517   LocalContext context;
5518   Local<v8::Object> obj = templ->NewInstance();
5519   context->Global()->Set(v8_str("obj"), obj);
5520
5521   const char* code =
5522       "try {"
5523       "  for (var i = 0; i < 100; i++) {"
5524       "    var expected = i;"
5525       "    var key = i;"
5526       "    if (i == 50) {"
5527       "       key = 'foobar';"
5528       "       expected = undefined;"
5529       "    }"
5530       "    var v = obj[key];"
5531       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5532       "  }"
5533       "  'PASSED'"
5534       "} catch(e) {"
5535       "  e"
5536       "}";
5537   ExpectString(code, "PASSED");
5538 }
5539
5540
5541 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
5542   v8::HandleScope scope(v8::Isolate::GetCurrent());
5543   Local<ObjectTemplate> templ = ObjectTemplate::New();
5544   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5545
5546   LocalContext context;
5547   Local<v8::Object> obj = templ->NewInstance();
5548   context->Global()->Set(v8_str("obj"), obj);
5549
5550   const char* code =
5551       "var original = obj;"
5552       "try {"
5553       "  for (var i = 0; i < 100; i++) {"
5554       "    var expected = i;"
5555       "    if (i == 50) {"
5556       "       obj = {50: 'foobar'};"
5557       "       expected = 'foobar';"
5558       "    }"
5559       "    var v = obj[i];"
5560       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5561       "    if (i == 50) obj = original;"
5562       "  }"
5563       "  'PASSED'"
5564       "} catch(e) {"
5565       "  e"
5566       "}";
5567   ExpectString(code, "PASSED");
5568 }
5569
5570
5571 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
5572   v8::HandleScope scope(v8::Isolate::GetCurrent());
5573   Local<ObjectTemplate> templ = ObjectTemplate::New();
5574   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5575
5576   LocalContext context;
5577   Local<v8::Object> obj = templ->NewInstance();
5578   context->Global()->Set(v8_str("obj"), obj);
5579
5580   const char* code =
5581       "var original = obj;"
5582       "try {"
5583       "  for (var i = 0; i < 100; i++) {"
5584       "    var expected = i;"
5585       "    if (i == 5) {"
5586       "       obj = 239;"
5587       "       expected = undefined;"
5588       "    }"
5589       "    var v = obj[i];"
5590       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5591       "    if (i == 5) obj = original;"
5592       "  }"
5593       "  'PASSED'"
5594       "} catch(e) {"
5595       "  e"
5596       "}";
5597   ExpectString(code, "PASSED");
5598 }
5599
5600
5601 THREADED_TEST(IndexedInterceptorOnProto) {
5602   v8::HandleScope scope(v8::Isolate::GetCurrent());
5603   Local<ObjectTemplate> templ = ObjectTemplate::New();
5604   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5605
5606   LocalContext context;
5607   Local<v8::Object> obj = templ->NewInstance();
5608   context->Global()->Set(v8_str("obj"), obj);
5609
5610   const char* code =
5611       "var o = {__proto__: obj};"
5612       "try {"
5613       "  for (var i = 0; i < 100; i++) {"
5614       "    var v = o[i];"
5615       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5616       "  }"
5617       "  'PASSED'"
5618       "} catch(e) {"
5619       "  e"
5620       "}";
5621   ExpectString(code, "PASSED");
5622 }
5623
5624
5625 THREADED_TEST(MultiContexts) {
5626   v8::HandleScope scope(v8::Isolate::GetCurrent());
5627   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
5628   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
5629
5630   Local<String> password = v8_str("Password");
5631
5632   // Create an environment
5633   LocalContext context0(0, templ);
5634   context0->SetSecurityToken(password);
5635   v8::Handle<v8::Object> global0 = context0->Global();
5636   global0->Set(v8_str("custom"), v8_num(1234));
5637   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5638
5639   // Create an independent environment
5640   LocalContext context1(0, templ);
5641   context1->SetSecurityToken(password);
5642   v8::Handle<v8::Object> global1 = context1->Global();
5643   global1->Set(v8_str("custom"), v8_num(1234));
5644   CHECK_NE(global0, global1);
5645   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5646   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5647
5648   // Now create a new context with the old global
5649   LocalContext context2(0, templ, global1);
5650   context2->SetSecurityToken(password);
5651   v8::Handle<v8::Object> global2 = context2->Global();
5652   CHECK_EQ(global1, global2);
5653   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5654   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5655 }
5656
5657
5658 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5659   // Make sure that functions created by cloning boilerplates cannot
5660   // communicate through their __proto__ field.
5661
5662   v8::HandleScope scope(v8::Isolate::GetCurrent());
5663
5664   LocalContext env0;
5665   v8::Handle<v8::Object> global0 =
5666       env0->Global();
5667   v8::Handle<v8::Object> object0 =
5668       global0->Get(v8_str("Object")).As<v8::Object>();
5669   v8::Handle<v8::Object> tostring0 =
5670       object0->Get(v8_str("toString")).As<v8::Object>();
5671   v8::Handle<v8::Object> proto0 =
5672       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5673   proto0->Set(v8_str("custom"), v8_num(1234));
5674
5675   LocalContext env1;
5676   v8::Handle<v8::Object> global1 =
5677       env1->Global();
5678   v8::Handle<v8::Object> object1 =
5679       global1->Get(v8_str("Object")).As<v8::Object>();
5680   v8::Handle<v8::Object> tostring1 =
5681       object1->Get(v8_str("toString")).As<v8::Object>();
5682   v8::Handle<v8::Object> proto1 =
5683       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5684   CHECK(!proto1->Has(v8_str("custom")));
5685 }
5686
5687
5688 THREADED_TEST(Regress892105) {
5689   // Make sure that object and array literals created by cloning
5690   // boilerplates cannot communicate through their __proto__
5691   // field. This is rather difficult to check, but we try to add stuff
5692   // to Object.prototype and Array.prototype and create a new
5693   // environment. This should succeed.
5694
5695   v8::HandleScope scope(v8::Isolate::GetCurrent());
5696
5697   Local<String> source = v8_str("Object.prototype.obj = 1234;"
5698                                 "Array.prototype.arr = 4567;"
5699                                 "8901");
5700
5701   LocalContext env0;
5702   Local<Script> script0 = Script::Compile(source);
5703   CHECK_EQ(8901.0, script0->Run()->NumberValue());
5704
5705   LocalContext env1;
5706   Local<Script> script1 = Script::Compile(source);
5707   CHECK_EQ(8901.0, script1->Run()->NumberValue());
5708 }
5709
5710
5711 THREADED_TEST(UndetectableObject) {
5712   LocalContext env;
5713   v8::HandleScope scope(env->GetIsolate());
5714
5715   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5716   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5717
5718   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5719   env->Global()->Set(v8_str("undetectable"), obj);
5720
5721   ExpectString("undetectable.toString()", "[object Object]");
5722   ExpectString("typeof undetectable", "undefined");
5723   ExpectString("typeof(undetectable)", "undefined");
5724   ExpectBoolean("typeof undetectable == 'undefined'", true);
5725   ExpectBoolean("typeof undetectable == 'object'", false);
5726   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5727   ExpectBoolean("!undetectable", true);
5728
5729   ExpectObject("true&&undetectable", obj);
5730   ExpectBoolean("false&&undetectable", false);
5731   ExpectBoolean("true||undetectable", true);
5732   ExpectObject("false||undetectable", obj);
5733
5734   ExpectObject("undetectable&&true", obj);
5735   ExpectObject("undetectable&&false", obj);
5736   ExpectBoolean("undetectable||true", true);
5737   ExpectBoolean("undetectable||false", false);
5738
5739   ExpectBoolean("undetectable==null", true);
5740   ExpectBoolean("null==undetectable", true);
5741   ExpectBoolean("undetectable==undefined", true);
5742   ExpectBoolean("undefined==undetectable", true);
5743   ExpectBoolean("undetectable==undetectable", true);
5744
5745
5746   ExpectBoolean("undetectable===null", false);
5747   ExpectBoolean("null===undetectable", false);
5748   ExpectBoolean("undetectable===undefined", false);
5749   ExpectBoolean("undefined===undetectable", false);
5750   ExpectBoolean("undetectable===undetectable", true);
5751 }
5752
5753
5754 THREADED_TEST(VoidLiteral) {
5755   LocalContext env;
5756   v8::HandleScope scope(env->GetIsolate());
5757
5758   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5759   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5760
5761   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5762   env->Global()->Set(v8_str("undetectable"), obj);
5763
5764   ExpectBoolean("undefined == void 0", true);
5765   ExpectBoolean("undetectable == void 0", true);
5766   ExpectBoolean("null == void 0", true);
5767   ExpectBoolean("undefined === void 0", true);
5768   ExpectBoolean("undetectable === void 0", false);
5769   ExpectBoolean("null === void 0", false);
5770
5771   ExpectBoolean("void 0 == undefined", true);
5772   ExpectBoolean("void 0 == undetectable", true);
5773   ExpectBoolean("void 0 == null", true);
5774   ExpectBoolean("void 0 === undefined", true);
5775   ExpectBoolean("void 0 === undetectable", false);
5776   ExpectBoolean("void 0 === null", false);
5777
5778   ExpectString("(function() {"
5779                "  try {"
5780                "    return x === void 0;"
5781                "  } catch(e) {"
5782                "    return e.toString();"
5783                "  }"
5784                "})()",
5785                "ReferenceError: x is not defined");
5786   ExpectString("(function() {"
5787                "  try {"
5788                "    return void 0 === x;"
5789                "  } catch(e) {"
5790                "    return e.toString();"
5791                "  }"
5792                "})()",
5793                "ReferenceError: x is not defined");
5794 }
5795
5796
5797 THREADED_TEST(ExtensibleOnUndetectable) {
5798   LocalContext env;
5799   v8::HandleScope scope(env->GetIsolate());
5800
5801   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5802   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
5803
5804   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5805   env->Global()->Set(v8_str("undetectable"), obj);
5806
5807   Local<String> source = v8_str("undetectable.x = 42;"
5808                                 "undetectable.x");
5809
5810   Local<Script> script = Script::Compile(source);
5811
5812   CHECK_EQ(v8::Integer::New(42), script->Run());
5813
5814   ExpectBoolean("Object.isExtensible(undetectable)", true);
5815
5816   source = v8_str("Object.preventExtensions(undetectable);");
5817   script = Script::Compile(source);
5818   script->Run();
5819   ExpectBoolean("Object.isExtensible(undetectable)", false);
5820
5821   source = v8_str("undetectable.y = 2000;");
5822   script = Script::Compile(source);
5823   script->Run();
5824   ExpectBoolean("undetectable.y == undefined", true);
5825 }
5826
5827
5828
5829 THREADED_TEST(UndetectableString) {
5830   LocalContext env;
5831   v8::HandleScope scope(env->GetIsolate());
5832
5833   Local<String> obj = String::NewUndetectable("foo");
5834   env->Global()->Set(v8_str("undetectable"), obj);
5835
5836   ExpectString("undetectable", "foo");
5837   ExpectString("typeof undetectable", "undefined");
5838   ExpectString("typeof(undetectable)", "undefined");
5839   ExpectBoolean("typeof undetectable == 'undefined'", true);
5840   ExpectBoolean("typeof undetectable == 'string'", false);
5841   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5842   ExpectBoolean("!undetectable", true);
5843
5844   ExpectObject("true&&undetectable", obj);
5845   ExpectBoolean("false&&undetectable", false);
5846   ExpectBoolean("true||undetectable", true);
5847   ExpectObject("false||undetectable", obj);
5848
5849   ExpectObject("undetectable&&true", obj);
5850   ExpectObject("undetectable&&false", obj);
5851   ExpectBoolean("undetectable||true", true);
5852   ExpectBoolean("undetectable||false", false);
5853
5854   ExpectBoolean("undetectable==null", true);
5855   ExpectBoolean("null==undetectable", true);
5856   ExpectBoolean("undetectable==undefined", true);
5857   ExpectBoolean("undefined==undetectable", true);
5858   ExpectBoolean("undetectable==undetectable", true);
5859
5860
5861   ExpectBoolean("undetectable===null", false);
5862   ExpectBoolean("null===undetectable", false);
5863   ExpectBoolean("undetectable===undefined", false);
5864   ExpectBoolean("undefined===undetectable", false);
5865   ExpectBoolean("undetectable===undetectable", true);
5866 }
5867
5868
5869 TEST(UndetectableOptimized) {
5870   i::FLAG_allow_natives_syntax = true;
5871   LocalContext env;
5872   v8::HandleScope scope(env->GetIsolate());
5873
5874   Local<String> obj = String::NewUndetectable("foo");
5875   env->Global()->Set(v8_str("undetectable"), obj);
5876   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
5877
5878   ExpectString(
5879       "function testBranch() {"
5880       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
5881       "  if (%_IsUndetectableObject(detectable)) throw 2;"
5882       "}\n"
5883       "function testBool() {"
5884       "  var b1 = !%_IsUndetectableObject(undetectable);"
5885       "  var b2 = %_IsUndetectableObject(detectable);"
5886       "  if (b1) throw 3;"
5887       "  if (b2) throw 4;"
5888       "  return b1 == b2;"
5889       "}\n"
5890       "%OptimizeFunctionOnNextCall(testBranch);"
5891       "%OptimizeFunctionOnNextCall(testBool);"
5892       "for (var i = 0; i < 10; i++) {"
5893       "  testBranch();"
5894       "  testBool();"
5895       "}\n"
5896       "\"PASS\"",
5897       "PASS");
5898 }
5899
5900
5901 template <typename T> static void USE(T) { }
5902
5903
5904 // This test is not intended to be run, just type checked.
5905 static inline void PersistentHandles(v8::Isolate* isolate) {
5906   USE(PersistentHandles);
5907   Local<String> str = v8_str("foo");
5908   v8::Persistent<String> p_str(isolate, str);
5909   p_str.Dispose();
5910   Local<Script> scr = Script::Compile(v8_str(""));
5911   v8::Persistent<Script> p_scr(isolate, scr);
5912   p_scr.Dispose();
5913   Local<ObjectTemplate> templ = ObjectTemplate::New();
5914   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
5915   p_templ.Dispose();
5916 }
5917
5918
5919 static void HandleLogDelegator(
5920     const v8::FunctionCallbackInfo<v8::Value>& args) {
5921   ApiTestFuzzer::Fuzz();
5922 }
5923
5924
5925 THREADED_TEST(GlobalObjectTemplate) {
5926   v8::Isolate* isolate = v8::Isolate::GetCurrent();
5927   v8::HandleScope handle_scope(isolate);
5928   Local<ObjectTemplate> global_template = ObjectTemplate::New();
5929   global_template->Set(v8_str("JSNI_Log"),
5930                        v8::FunctionTemplate::New(HandleLogDelegator));
5931   v8::Local<Context> context = Context::New(isolate, 0, global_template);
5932   Context::Scope context_scope(context);
5933   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
5934 }
5935
5936
5937 static const char* kSimpleExtensionSource =
5938   "function Foo() {"
5939   "  return 4;"
5940   "}";
5941
5942
5943 THREADED_TEST(SimpleExtensions) {
5944   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5945   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
5946   const char* extension_names[] = { "simpletest" };
5947   v8::ExtensionConfiguration extensions(1, extension_names);
5948   v8::Handle<Context> context =
5949       Context::New(v8::Isolate::GetCurrent(), &extensions);
5950   Context::Scope lock(context);
5951   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5952   CHECK_EQ(result, v8::Integer::New(4));
5953 }
5954
5955
5956 THREADED_TEST(NullExtensions) {
5957   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5958   v8::RegisterExtension(new Extension("nulltest", NULL));
5959   const char* extension_names[] = { "nulltest" };
5960   v8::ExtensionConfiguration extensions(1, extension_names);
5961   v8::Handle<Context> context =
5962       Context::New(v8::Isolate::GetCurrent(), &extensions);
5963   Context::Scope lock(context);
5964   v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
5965   CHECK_EQ(result, v8::Integer::New(4));
5966 }
5967
5968
5969 static const char* kEmbeddedExtensionSource =
5970     "function Ret54321(){return 54321;}~~@@$"
5971     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5972 static const int kEmbeddedExtensionSourceValidLen = 34;
5973
5974
5975 THREADED_TEST(ExtensionMissingSourceLength) {
5976   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5977   v8::RegisterExtension(new Extension("srclentest_fail",
5978                                       kEmbeddedExtensionSource));
5979   const char* extension_names[] = { "srclentest_fail" };
5980   v8::ExtensionConfiguration extensions(1, extension_names);
5981   v8::Handle<Context> context =
5982       Context::New(v8::Isolate::GetCurrent(), &extensions);
5983   CHECK_EQ(0, *context);
5984 }
5985
5986
5987 THREADED_TEST(ExtensionWithSourceLength) {
5988   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5989        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
5990     v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5991     i::ScopedVector<char> extension_name(32);
5992     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
5993     v8::RegisterExtension(new Extension(extension_name.start(),
5994                                         kEmbeddedExtensionSource, 0, 0,
5995                                         source_len));
5996     const char* extension_names[1] = { extension_name.start() };
5997     v8::ExtensionConfiguration extensions(1, extension_names);
5998     v8::Handle<Context> context =
5999       Context::New(v8::Isolate::GetCurrent(), &extensions);
6000     if (source_len == kEmbeddedExtensionSourceValidLen) {
6001       Context::Scope lock(context);
6002       v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6003       CHECK_EQ(v8::Integer::New(54321), result);
6004     } else {
6005       // Anything but exactly the right length should fail to compile.
6006       CHECK_EQ(0, *context);
6007     }
6008   }
6009 }
6010
6011
6012 static const char* kEvalExtensionSource1 =
6013   "function UseEval1() {"
6014   "  var x = 42;"
6015   "  return eval('x');"
6016   "}";
6017
6018
6019 static const char* kEvalExtensionSource2 =
6020   "(function() {"
6021   "  var x = 42;"
6022   "  function e() {"
6023   "    return eval('x');"
6024   "  }"
6025   "  this.UseEval2 = e;"
6026   "})()";
6027
6028
6029 THREADED_TEST(UseEvalFromExtension) {
6030   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6031   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6032   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6033   const char* extension_names[] = { "evaltest1", "evaltest2" };
6034   v8::ExtensionConfiguration extensions(2, extension_names);
6035   v8::Handle<Context> context =
6036       Context::New(v8::Isolate::GetCurrent(), &extensions);
6037   Context::Scope lock(context);
6038   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6039   CHECK_EQ(result, v8::Integer::New(42));
6040   result = Script::Compile(v8_str("UseEval2()"))->Run();
6041   CHECK_EQ(result, v8::Integer::New(42));
6042 }
6043
6044
6045 static const char* kWithExtensionSource1 =
6046   "function UseWith1() {"
6047   "  var x = 42;"
6048   "  with({x:87}) { return x; }"
6049   "}";
6050
6051
6052
6053 static const char* kWithExtensionSource2 =
6054   "(function() {"
6055   "  var x = 42;"
6056   "  function e() {"
6057   "    with ({x:87}) { return x; }"
6058   "  }"
6059   "  this.UseWith2 = e;"
6060   "})()";
6061
6062
6063 THREADED_TEST(UseWithFromExtension) {
6064   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6065   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6066   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6067   const char* extension_names[] = { "withtest1", "withtest2" };
6068   v8::ExtensionConfiguration extensions(2, extension_names);
6069   v8::Handle<Context> context =
6070       Context::New(v8::Isolate::GetCurrent(), &extensions);
6071   Context::Scope lock(context);
6072   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6073   CHECK_EQ(result, v8::Integer::New(87));
6074   result = Script::Compile(v8_str("UseWith2()"))->Run();
6075   CHECK_EQ(result, v8::Integer::New(87));
6076 }
6077
6078
6079 THREADED_TEST(AutoExtensions) {
6080   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6081   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6082   extension->set_auto_enable(true);
6083   v8::RegisterExtension(extension);
6084   v8::Handle<Context> context =
6085       Context::New(v8::Isolate::GetCurrent());
6086   Context::Scope lock(context);
6087   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6088   CHECK_EQ(result, v8::Integer::New(4));
6089 }
6090
6091
6092 static const char* kSyntaxErrorInExtensionSource =
6093     "[";
6094
6095
6096 // Test that a syntax error in an extension does not cause a fatal
6097 // error but results in an empty context.
6098 THREADED_TEST(SyntaxErrorExtensions) {
6099   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6100   v8::RegisterExtension(new Extension("syntaxerror",
6101                                       kSyntaxErrorInExtensionSource));
6102   const char* extension_names[] = { "syntaxerror" };
6103   v8::ExtensionConfiguration extensions(1, extension_names);
6104   v8::Handle<Context> context =
6105       Context::New(v8::Isolate::GetCurrent(), &extensions);
6106   CHECK(context.IsEmpty());
6107 }
6108
6109
6110 static const char* kExceptionInExtensionSource =
6111     "throw 42";
6112
6113
6114 // Test that an exception when installing an extension does not cause
6115 // a fatal error but results in an empty context.
6116 THREADED_TEST(ExceptionExtensions) {
6117   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6118   v8::RegisterExtension(new Extension("exception",
6119                                       kExceptionInExtensionSource));
6120   const char* extension_names[] = { "exception" };
6121   v8::ExtensionConfiguration extensions(1, extension_names);
6122   v8::Handle<Context> context =
6123       Context::New(v8::Isolate::GetCurrent(), &extensions);
6124   CHECK(context.IsEmpty());
6125 }
6126
6127
6128 static const char* kNativeCallInExtensionSource =
6129     "function call_runtime_last_index_of(x) {"
6130     "  return %StringLastIndexOf(x, 'bob', 10);"
6131     "}";
6132
6133
6134 static const char* kNativeCallTest =
6135     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6136
6137 // Test that a native runtime calls are supported in extensions.
6138 THREADED_TEST(NativeCallInExtensions) {
6139   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6140   v8::RegisterExtension(new Extension("nativecall",
6141                                       kNativeCallInExtensionSource));
6142   const char* extension_names[] = { "nativecall" };
6143   v8::ExtensionConfiguration extensions(1, extension_names);
6144   v8::Handle<Context> context =
6145       Context::New(v8::Isolate::GetCurrent(), &extensions);
6146   Context::Scope lock(context);
6147   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6148   CHECK_EQ(result, v8::Integer::New(3));
6149 }
6150
6151
6152 class NativeFunctionExtension : public Extension {
6153  public:
6154   NativeFunctionExtension(const char* name,
6155                           const char* source,
6156                           v8::FunctionCallback fun = &Echo)
6157       : Extension(name, source),
6158         function_(fun) { }
6159
6160   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6161       v8::Handle<v8::String> name) {
6162     return v8::FunctionTemplate::New(function_);
6163   }
6164
6165   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6166     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6167   }
6168  private:
6169   v8::FunctionCallback function_;
6170 };
6171
6172
6173 THREADED_TEST(NativeFunctionDeclaration) {
6174   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6175   const char* name = "nativedecl";
6176   v8::RegisterExtension(new NativeFunctionExtension(name,
6177                                                     "native function foo();"));
6178   const char* extension_names[] = { name };
6179   v8::ExtensionConfiguration extensions(1, extension_names);
6180   v8::Handle<Context> context =
6181       Context::New(v8::Isolate::GetCurrent(), &extensions);
6182   Context::Scope lock(context);
6183   v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6184   CHECK_EQ(result, v8::Integer::New(42));
6185 }
6186
6187
6188 THREADED_TEST(NativeFunctionDeclarationError) {
6189   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6190   const char* name = "nativedeclerr";
6191   // Syntax error in extension code.
6192   v8::RegisterExtension(new NativeFunctionExtension(name,
6193                                                     "native\nfunction foo();"));
6194   const char* extension_names[] = { name };
6195   v8::ExtensionConfiguration extensions(1, extension_names);
6196   v8::Handle<Context> context =
6197       Context::New(v8::Isolate::GetCurrent(), &extensions);
6198   CHECK(context.IsEmpty());
6199 }
6200
6201
6202 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6203   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6204   const char* name = "nativedeclerresc";
6205   // Syntax error in extension code - escape code in "native" means that
6206   // it's not treated as a keyword.
6207   v8::RegisterExtension(new NativeFunctionExtension(
6208       name,
6209       "nativ\\u0065 function foo();"));
6210   const char* extension_names[] = { name };
6211   v8::ExtensionConfiguration extensions(1, extension_names);
6212   v8::Handle<Context> context =
6213       Context::New(v8::Isolate::GetCurrent(), &extensions);
6214   CHECK(context.IsEmpty());
6215 }
6216
6217
6218 static void CheckDependencies(const char* name, const char* expected) {
6219   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6220   v8::ExtensionConfiguration config(1, &name);
6221   LocalContext context(&config);
6222   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
6223 }
6224
6225
6226 /*
6227  * Configuration:
6228  *
6229  *     /-- B <--\
6230  * A <-          -- D <-- E
6231  *     \-- C <--/
6232  */
6233 THREADED_TEST(ExtensionDependency) {
6234   static const char* kEDeps[] = { "D" };
6235   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6236   static const char* kDDeps[] = { "B", "C" };
6237   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6238   static const char* kBCDeps[] = { "A" };
6239   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6240   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6241   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6242   CheckDependencies("A", "undefinedA");
6243   CheckDependencies("B", "undefinedAB");
6244   CheckDependencies("C", "undefinedAC");
6245   CheckDependencies("D", "undefinedABCD");
6246   CheckDependencies("E", "undefinedABCDE");
6247   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6248   static const char* exts[2] = { "C", "E" };
6249   v8::ExtensionConfiguration config(2, exts);
6250   LocalContext context(&config);
6251   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6252 }
6253
6254
6255 static const char* kExtensionTestScript =
6256   "native function A();"
6257   "native function B();"
6258   "native function C();"
6259   "function Foo(i) {"
6260   "  if (i == 0) return A();"
6261   "  if (i == 1) return B();"
6262   "  if (i == 2) return C();"
6263   "}";
6264
6265
6266 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6267   ApiTestFuzzer::Fuzz();
6268   if (args.IsConstructCall()) {
6269     args.This()->Set(v8_str("data"), args.Data());
6270     args.GetReturnValue().SetNull();
6271     return;
6272   }
6273   args.GetReturnValue().Set(args.Data());
6274 }
6275
6276
6277 class FunctionExtension : public Extension {
6278  public:
6279   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6280   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6281       v8::Handle<String> name);
6282 };
6283
6284
6285 static int lookup_count = 0;
6286 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
6287       v8::Handle<String> name) {
6288   lookup_count++;
6289   if (name->Equals(v8_str("A"))) {
6290     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
6291   } else if (name->Equals(v8_str("B"))) {
6292     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
6293   } else if (name->Equals(v8_str("C"))) {
6294     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
6295   } else {
6296     return v8::Handle<v8::FunctionTemplate>();
6297   }
6298 }
6299
6300
6301 THREADED_TEST(FunctionLookup) {
6302   v8::RegisterExtension(new FunctionExtension());
6303   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6304   static const char* exts[1] = { "functiontest" };
6305   v8::ExtensionConfiguration config(1, exts);
6306   LocalContext context(&config);
6307   CHECK_EQ(3, lookup_count);
6308   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
6309   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
6310   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
6311 }
6312
6313
6314 THREADED_TEST(NativeFunctionConstructCall) {
6315   v8::RegisterExtension(new FunctionExtension());
6316   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6317   static const char* exts[1] = { "functiontest" };
6318   v8::ExtensionConfiguration config(1, exts);
6319   LocalContext context(&config);
6320   for (int i = 0; i < 10; i++) {
6321     // Run a few times to ensure that allocation of objects doesn't
6322     // change behavior of a constructor function.
6323     CHECK_EQ(v8::Integer::New(8),
6324              Script::Compile(v8_str("(new A()).data"))->Run());
6325     CHECK_EQ(v8::Integer::New(7),
6326              Script::Compile(v8_str("(new B()).data"))->Run());
6327     CHECK_EQ(v8::Integer::New(6),
6328              Script::Compile(v8_str("(new C()).data"))->Run());
6329   }
6330 }
6331
6332
6333 static const char* last_location;
6334 static const char* last_message;
6335 void StoringErrorCallback(const char* location, const char* message) {
6336   if (last_location == NULL) {
6337     last_location = location;
6338     last_message = message;
6339   }
6340 }
6341
6342
6343 // ErrorReporting creates a circular extensions configuration and
6344 // tests that the fatal error handler gets called.  This renders V8
6345 // unusable and therefore this test cannot be run in parallel.
6346 TEST(ErrorReporting) {
6347   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6348   static const char* aDeps[] = { "B" };
6349   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6350   static const char* bDeps[] = { "A" };
6351   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6352   last_location = NULL;
6353   v8::ExtensionConfiguration config(1, bDeps);
6354   v8::Handle<Context> context =
6355       Context::New(v8::Isolate::GetCurrent(), &config);
6356   CHECK(context.IsEmpty());
6357   CHECK_NE(last_location, NULL);
6358 }
6359
6360
6361 static const char* js_code_causing_huge_string_flattening =
6362     "var str = 'X';"
6363     "for (var i = 0; i < 30; i++) {"
6364     "  str = str + str;"
6365     "}"
6366     "str.match(/X/);";
6367
6368
6369 void OOMCallback(const char* location, const char* message) {
6370   exit(0);
6371 }
6372
6373
6374 TEST(RegexpOutOfMemory) {
6375   // Execute a script that causes out of memory when flattening a string.
6376   v8::HandleScope scope(v8::Isolate::GetCurrent());
6377   v8::V8::SetFatalErrorHandler(OOMCallback);
6378   LocalContext context;
6379   Local<Script> script =
6380       Script::Compile(String::New(js_code_causing_huge_string_flattening));
6381   last_location = NULL;
6382   script->Run();
6383
6384   CHECK(false);  // Should not return.
6385 }
6386
6387
6388 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6389                                              v8::Handle<Value> data) {
6390   CHECK(message->GetScriptResourceName()->IsUndefined());
6391   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
6392   message->GetLineNumber();
6393   message->GetSourceLine();
6394 }
6395
6396
6397 THREADED_TEST(ErrorWithMissingScriptInfo) {
6398   LocalContext context;
6399   v8::HandleScope scope(context->GetIsolate());
6400   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6401   Script::Compile(v8_str("throw Error()"))->Run();
6402   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6403 }
6404
6405
6406 int global_index = 0;
6407
6408 class Snorkel {
6409  public:
6410   Snorkel() { index_ = global_index++; }
6411   int index_;
6412 };
6413
6414 class Whammy {
6415  public:
6416   explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
6417   ~Whammy() { script_.Dispose(isolate_); }
6418   v8::Handle<Script> getScript() {
6419     if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
6420     return Local<Script>::New(isolate_, script_);
6421   }
6422
6423  public:
6424   static const int kObjectCount = 256;
6425   int cursor_;
6426   v8::Isolate* isolate_;
6427   v8::Persistent<v8::Object> objects_[kObjectCount];
6428   v8::Persistent<Script> script_;
6429 };
6430
6431 static void HandleWeakReference(v8::Isolate* isolate,
6432                                 v8::Persistent<v8::Value>* obj,
6433                                 Snorkel* snorkel) {
6434   delete snorkel;
6435   obj->ClearWeak(isolate);
6436 }
6437
6438 void WhammyPropertyGetter(Local<String> name,
6439                           const v8::PropertyCallbackInfo<v8::Value>& info) {
6440   Whammy* whammy =
6441     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
6442
6443   v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
6444
6445   v8::Handle<v8::Object> obj = v8::Object::New();
6446   if (!prev.IsEmpty()) {
6447     v8::Local<v8::Object>::New(info.GetIsolate(), prev)
6448         ->Set(v8_str("next"), obj);
6449     prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference);
6450     whammy->objects_[whammy->cursor_].Clear();
6451   }
6452   whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
6453   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
6454   info.GetReturnValue().Set(whammy->getScript()->Run());
6455 }
6456
6457
6458 THREADED_TEST(WeakReference) {
6459   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6460   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
6461   Whammy* whammy = new Whammy(v8::Isolate::GetCurrent());
6462   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
6463                                  0, 0, 0, 0,
6464                                  v8::External::New(whammy));
6465   const char* extension_list[] = { "v8/gc" };
6466   v8::ExtensionConfiguration extensions(1, extension_list);
6467   v8::Handle<Context> context =
6468       Context::New(v8::Isolate::GetCurrent(), &extensions);
6469   Context::Scope context_scope(context);
6470
6471   v8::Handle<v8::Object> interceptor = templ->NewInstance();
6472   context->Global()->Set(v8_str("whammy"), interceptor);
6473   const char* code =
6474       "var last;"
6475       "for (var i = 0; i < 10000; i++) {"
6476       "  var obj = whammy.length;"
6477       "  if (last) last.next = obj;"
6478       "  last = obj;"
6479       "}"
6480       "gc();"
6481       "4";
6482   v8::Handle<Value> result = CompileRun(code);
6483   CHECK_EQ(4.0, result->NumberValue());
6484   delete whammy;
6485 }
6486
6487
6488 static void DisposeAndSetFlag(v8::Isolate* isolate,
6489                               v8::Persistent<v8::Object>* obj,
6490                               bool* data) {
6491   obj->Dispose(isolate);
6492   *(data) = true;
6493 }
6494
6495
6496 THREADED_TEST(IndependentWeakHandle) {
6497   v8::Isolate* iso = v8::Isolate::GetCurrent();
6498   v8::HandleScope scope(iso);
6499   v8::Handle<Context> context = Context::New(iso);
6500   Context::Scope context_scope(context);
6501
6502   v8::Persistent<v8::Object> object_a, object_b;
6503
6504   {
6505     v8::HandleScope handle_scope(iso);
6506     object_a.Reset(iso, v8::Object::New());
6507     object_b.Reset(iso, v8::Object::New());
6508   }
6509
6510   bool object_a_disposed = false;
6511   bool object_b_disposed = false;
6512   object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
6513   object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
6514   CHECK(!object_b.IsIndependent(iso));
6515   object_a.MarkIndependent(iso);
6516   object_b.MarkIndependent(iso);
6517   CHECK(object_b.IsIndependent(iso));
6518   HEAP->PerformScavenge();
6519   CHECK(object_a_disposed);
6520   CHECK(object_b_disposed);
6521 }
6522
6523
6524 static void InvokeScavenge() {
6525   HEAP->PerformScavenge();
6526 }
6527
6528
6529 static void InvokeMarkSweep() {
6530   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
6531 }
6532
6533
6534 static void ForceScavenge(v8::Isolate* isolate,
6535                           v8::Persistent<v8::Object>* obj,
6536                           bool* data) {
6537   obj->Dispose(isolate);
6538   *(data) = true;
6539   InvokeScavenge();
6540 }
6541
6542
6543 static void ForceMarkSweep(v8::Isolate* isolate,
6544                            v8::Persistent<v8::Object>* obj,
6545                            bool* data) {
6546   obj->Dispose(isolate);
6547   *(data) = true;
6548   InvokeMarkSweep();
6549 }
6550
6551
6552 THREADED_TEST(GCFromWeakCallbacks) {
6553   v8::Isolate* isolate = v8::Isolate::GetCurrent();
6554   v8::HandleScope scope(isolate);
6555   v8::Handle<Context> context = Context::New(isolate);
6556   Context::Scope context_scope(context);
6557
6558   static const int kNumberOfGCTypes = 2;
6559   typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback;
6560   Callback gc_forcing_callback[kNumberOfGCTypes] =
6561       {&ForceScavenge, &ForceMarkSweep};
6562
6563   typedef void (*GCInvoker)();
6564   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6565
6566   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6567     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6568       v8::Persistent<v8::Object> object;
6569       {
6570         v8::HandleScope handle_scope(isolate);
6571         object.Reset(isolate, v8::Object::New());
6572       }
6573       bool disposed = false;
6574       object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
6575       object.MarkIndependent(isolate);
6576       invoke_gc[outer_gc]();
6577       CHECK(disposed);
6578     }
6579   }
6580 }
6581
6582
6583 static void RevivingCallback(v8::Isolate* isolate,
6584                              v8::Persistent<v8::Object>* obj,
6585                              bool* data) {
6586   obj->ClearWeak(isolate);
6587   *(data) = true;
6588 }
6589
6590
6591 THREADED_TEST(IndependentHandleRevival) {
6592   v8::Isolate* isolate = v8::Isolate::GetCurrent();
6593   v8::HandleScope scope(isolate);
6594   v8::Handle<Context> context = Context::New(isolate);
6595   Context::Scope context_scope(context);
6596
6597   v8::Persistent<v8::Object> object;
6598   {
6599     v8::HandleScope handle_scope(isolate);
6600     v8::Local<v8::Object> o = v8::Object::New();
6601     object.Reset(isolate, o);
6602     o->Set(v8_str("x"), v8::Integer::New(1));
6603     v8::Local<String> y_str = v8_str("y");
6604     o->Set(y_str, y_str);
6605   }
6606   bool revived = false;
6607   object.MakeWeak(&revived, &RevivingCallback);
6608   object.MarkIndependent(isolate);
6609   HEAP->PerformScavenge();
6610   CHECK(revived);
6611   HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
6612   {
6613     v8::HandleScope handle_scope(isolate);
6614     v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object);
6615     v8::Local<String> y_str = v8_str("y");
6616     CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x")));
6617     CHECK(o->Get(y_str)->Equals(y_str));
6618   }
6619 }
6620
6621
6622 v8::Handle<Function> args_fun;
6623
6624
6625 static void ArgumentsTestCallback(
6626     const v8::FunctionCallbackInfo<v8::Value>& args) {
6627   ApiTestFuzzer::Fuzz();
6628   CHECK_EQ(args_fun, args.Callee());
6629   CHECK_EQ(3, args.Length());
6630   CHECK_EQ(v8::Integer::New(1), args[0]);
6631   CHECK_EQ(v8::Integer::New(2), args[1]);
6632   CHECK_EQ(v8::Integer::New(3), args[2]);
6633   CHECK_EQ(v8::Undefined(), args[3]);
6634   v8::HandleScope scope(args.GetIsolate());
6635   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
6636 }
6637
6638
6639 THREADED_TEST(Arguments) {
6640   v8::HandleScope scope(v8::Isolate::GetCurrent());
6641   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
6642   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
6643   LocalContext context(NULL, global);
6644   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6645   v8_compile("f(1, 2, 3)")->Run();
6646 }
6647
6648
6649 static void NoBlockGetterX(Local<String> name,
6650                            const v8::PropertyCallbackInfo<v8::Value>&) {
6651 }
6652
6653
6654 static void NoBlockGetterI(uint32_t index,
6655                            const v8::PropertyCallbackInfo<v8::Value>&) {
6656 }
6657
6658
6659 static void PDeleter(Local<String> name,
6660                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
6661   if (!name->Equals(v8_str("foo"))) {
6662     return;  // not intercepted
6663   }
6664
6665   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
6666 }
6667
6668
6669 static void IDeleter(uint32_t index,
6670                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
6671   if (index != 2) {
6672     return;  // not intercepted
6673   }
6674
6675   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
6676 }
6677
6678
6679 THREADED_TEST(Deleter) {
6680   v8::HandleScope scope(v8::Isolate::GetCurrent());
6681   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6682   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
6683   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
6684   LocalContext context;
6685   context->Global()->Set(v8_str("k"), obj->NewInstance());
6686   CompileRun(
6687     "k.foo = 'foo';"
6688     "k.bar = 'bar';"
6689     "k[2] = 2;"
6690     "k[4] = 4;");
6691   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
6692   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
6693
6694   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
6695   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
6696
6697   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
6698   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
6699
6700   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
6701   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
6702 }
6703
6704
6705 static void GetK(Local<String> name,
6706                  const v8::PropertyCallbackInfo<v8::Value>& info) {
6707   ApiTestFuzzer::Fuzz();
6708   if (name->Equals(v8_str("foo")) ||
6709       name->Equals(v8_str("bar")) ||
6710       name->Equals(v8_str("baz"))) {
6711     info.GetReturnValue().SetUndefined();
6712   }
6713 }
6714
6715
6716 static void IndexedGetK(uint32_t index,
6717                         const v8::PropertyCallbackInfo<v8::Value>& info) {
6718   ApiTestFuzzer::Fuzz();
6719   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
6720 }
6721
6722
6723 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
6724   ApiTestFuzzer::Fuzz();
6725   v8::Handle<v8::Array> result = v8::Array::New(3);
6726   result->Set(v8::Integer::New(0), v8_str("foo"));
6727   result->Set(v8::Integer::New(1), v8_str("bar"));
6728   result->Set(v8::Integer::New(2), v8_str("baz"));
6729   info.GetReturnValue().Set(result);
6730 }
6731
6732
6733 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
6734   ApiTestFuzzer::Fuzz();
6735   v8::Handle<v8::Array> result = v8::Array::New(2);
6736   result->Set(v8::Integer::New(0), v8_str("0"));
6737   result->Set(v8::Integer::New(1), v8_str("1"));
6738   info.GetReturnValue().Set(result);
6739 }
6740
6741
6742 THREADED_TEST(Enumerators) {
6743   v8::HandleScope scope(v8::Isolate::GetCurrent());
6744   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6745   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
6746   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
6747   LocalContext context;
6748   context->Global()->Set(v8_str("k"), obj->NewInstance());
6749   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
6750     "k[10] = 0;"
6751     "k.a = 0;"
6752     "k[5] = 0;"
6753     "k.b = 0;"
6754     "k[4294967295] = 0;"
6755     "k.c = 0;"
6756     "k[4294967296] = 0;"
6757     "k.d = 0;"
6758     "k[140000] = 0;"
6759     "k.e = 0;"
6760     "k[30000000000] = 0;"
6761     "k.f = 0;"
6762     "var result = [];"
6763     "for (var prop in k) {"
6764     "  result.push(prop);"
6765     "}"
6766     "result"));
6767   // Check that we get all the property names returned including the
6768   // ones from the enumerators in the right order: indexed properties
6769   // in numerical order, indexed interceptor properties, named
6770   // properties in insertion order, named interceptor properties.
6771   // This order is not mandated by the spec, so this test is just
6772   // documenting our behavior.
6773   CHECK_EQ(17, result->Length());
6774   // Indexed properties in numerical order.
6775   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
6776   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
6777   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
6778   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
6779   // Indexed interceptor properties in the order they are returned
6780   // from the enumerator interceptor.
6781   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
6782   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
6783   // Named properties in insertion order.
6784   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
6785   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
6786   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
6787   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
6788   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
6789   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
6790   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
6791   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
6792   // Named interceptor properties.
6793   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
6794   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
6795   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
6796 }
6797
6798
6799 int p_getter_count;
6800 int p_getter_count2;
6801
6802
6803 static void PGetter(Local<String> name,
6804                     const v8::PropertyCallbackInfo<v8::Value>& info) {
6805   ApiTestFuzzer::Fuzz();
6806   p_getter_count++;
6807   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6808   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
6809   if (name->Equals(v8_str("p1"))) {
6810     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
6811   } else if (name->Equals(v8_str("p2"))) {
6812     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
6813   } else if (name->Equals(v8_str("p3"))) {
6814     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
6815   } else if (name->Equals(v8_str("p4"))) {
6816     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
6817   }
6818 }
6819
6820
6821 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6822   ApiTestFuzzer::Fuzz();
6823   LocalContext context;
6824   context->Global()->Set(v8_str("o1"), obj->NewInstance());
6825   CompileRun(
6826     "o1.__proto__ = { };"
6827     "var o2 = { __proto__: o1 };"
6828     "var o3 = { __proto__: o2 };"
6829     "var o4 = { __proto__: o3 };"
6830     "for (var i = 0; i < 10; i++) o4.p4;"
6831     "for (var i = 0; i < 10; i++) o3.p3;"
6832     "for (var i = 0; i < 10; i++) o2.p2;"
6833     "for (var i = 0; i < 10; i++) o1.p1;");
6834 }
6835
6836
6837 static void PGetter2(Local<String> name,
6838                      const v8::PropertyCallbackInfo<v8::Value>& info) {
6839   ApiTestFuzzer::Fuzz();
6840   p_getter_count2++;
6841   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6842   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
6843   if (name->Equals(v8_str("p1"))) {
6844     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
6845   } else if (name->Equals(v8_str("p2"))) {
6846     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
6847   } else if (name->Equals(v8_str("p3"))) {
6848     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
6849   } else if (name->Equals(v8_str("p4"))) {
6850     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
6851   }
6852 }
6853
6854
6855 THREADED_TEST(GetterHolders) {
6856   v8::HandleScope scope(v8::Isolate::GetCurrent());
6857   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6858   obj->SetAccessor(v8_str("p1"), PGetter);
6859   obj->SetAccessor(v8_str("p2"), PGetter);
6860   obj->SetAccessor(v8_str("p3"), PGetter);
6861   obj->SetAccessor(v8_str("p4"), PGetter);
6862   p_getter_count = 0;
6863   RunHolderTest(obj);
6864   CHECK_EQ(40, p_getter_count);
6865 }
6866
6867
6868 THREADED_TEST(PreInterceptorHolders) {
6869   v8::HandleScope scope(v8::Isolate::GetCurrent());
6870   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6871   obj->SetNamedPropertyHandler(PGetter2);
6872   p_getter_count2 = 0;
6873   RunHolderTest(obj);
6874   CHECK_EQ(40, p_getter_count2);
6875 }
6876
6877
6878 THREADED_TEST(ObjectInstantiation) {
6879   v8::HandleScope scope(v8::Isolate::GetCurrent());
6880   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6881   templ->SetAccessor(v8_str("t"), PGetter2);
6882   LocalContext context;
6883   context->Global()->Set(v8_str("o"), templ->NewInstance());
6884   for (int i = 0; i < 100; i++) {
6885     v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
6886     v8::Handle<v8::Object> obj = templ->NewInstance();
6887     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
6888     context->Global()->Set(v8_str("o2"), obj);
6889     v8::Handle<Value> value =
6890         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
6891     CHECK_EQ(v8::True(), value);
6892     context->Global()->Set(v8_str("o"), obj);
6893   }
6894 }
6895
6896
6897 static int StrCmp16(uint16_t* a, uint16_t* b) {
6898   while (true) {
6899     if (*a == 0 && *b == 0) return 0;
6900     if (*a != *b) return 0 + *a - *b;
6901     a++;
6902     b++;
6903   }
6904 }
6905
6906
6907 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6908   while (true) {
6909     if (n-- == 0) return 0;
6910     if (*a == 0 && *b == 0) return 0;
6911     if (*a != *b) return 0 + *a - *b;
6912     a++;
6913     b++;
6914   }
6915 }
6916
6917
6918 int GetUtf8Length(Handle<String> str) {
6919   int len = str->Utf8Length();
6920   if (len < 0) {
6921     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6922     i::FlattenString(istr);
6923     len = str->Utf8Length();
6924   }
6925   return len;
6926 }
6927
6928
6929 THREADED_TEST(StringWrite) {
6930   LocalContext context;
6931   v8::HandleScope scope(context->GetIsolate());
6932   v8::Handle<String> str = v8_str("abcde");
6933   // abc<Icelandic eth><Unicode snowman>.
6934   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6935   v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
6936   const int kStride = 4;  // Must match stride in for loops in JS below.
6937   CompileRun(
6938       "var left = '';"
6939       "for (var i = 0; i < 0xd800; i += 4) {"
6940       "  left = left + String.fromCharCode(i);"
6941       "}");
6942   CompileRun(
6943       "var right = '';"
6944       "for (var i = 0; i < 0xd800; i += 4) {"
6945       "  right = String.fromCharCode(i) + right;"
6946       "}");
6947   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6948   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
6949   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
6950
6951   CHECK_EQ(5, str2->Length());
6952   CHECK_EQ(0xd800 / kStride, left_tree->Length());
6953   CHECK_EQ(0xd800 / kStride, right_tree->Length());
6954
6955   char buf[100];
6956   char utf8buf[0xd800 * 3];
6957   uint16_t wbuf[100];
6958   int len;
6959   int charlen;
6960
6961   memset(utf8buf, 0x1, 1000);
6962   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
6963   CHECK_EQ(9, len);
6964   CHECK_EQ(5, charlen);
6965   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6966
6967   memset(utf8buf, 0x1, 1000);
6968   len = str2->WriteUtf8(utf8buf, 8, &charlen);
6969   CHECK_EQ(8, len);
6970   CHECK_EQ(5, charlen);
6971   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
6972
6973   memset(utf8buf, 0x1, 1000);
6974   len = str2->WriteUtf8(utf8buf, 7, &charlen);
6975   CHECK_EQ(5, len);
6976   CHECK_EQ(4, charlen);
6977   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6978
6979   memset(utf8buf, 0x1, 1000);
6980   len = str2->WriteUtf8(utf8buf, 6, &charlen);
6981   CHECK_EQ(5, len);
6982   CHECK_EQ(4, charlen);
6983   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6984
6985   memset(utf8buf, 0x1, 1000);
6986   len = str2->WriteUtf8(utf8buf, 5, &charlen);
6987   CHECK_EQ(5, len);
6988   CHECK_EQ(4, charlen);
6989   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6990
6991   memset(utf8buf, 0x1, 1000);
6992   len = str2->WriteUtf8(utf8buf, 4, &charlen);
6993   CHECK_EQ(3, len);
6994   CHECK_EQ(3, charlen);
6995   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
6996
6997   memset(utf8buf, 0x1, 1000);
6998   len = str2->WriteUtf8(utf8buf, 3, &charlen);
6999   CHECK_EQ(3, len);
7000   CHECK_EQ(3, charlen);
7001   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7002
7003   memset(utf8buf, 0x1, 1000);
7004   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7005   CHECK_EQ(2, len);
7006   CHECK_EQ(2, charlen);
7007   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7008
7009   memset(utf8buf, 0x1, sizeof(utf8buf));
7010   len = GetUtf8Length(left_tree);
7011   int utf8_expected =
7012       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7013   CHECK_EQ(utf8_expected, len);
7014   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7015   CHECK_EQ(utf8_expected, len);
7016   CHECK_EQ(0xd800 / kStride, charlen);
7017   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7018   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7019   CHECK_EQ(0xc0 - kStride,
7020            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7021   CHECK_EQ(1, utf8buf[utf8_expected]);
7022
7023   memset(utf8buf, 0x1, sizeof(utf8buf));
7024   len = GetUtf8Length(right_tree);
7025   CHECK_EQ(utf8_expected, len);
7026   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7027   CHECK_EQ(utf8_expected, len);
7028   CHECK_EQ(0xd800 / kStride, charlen);
7029   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7030   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7031   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7032   CHECK_EQ(1, utf8buf[utf8_expected]);
7033
7034   memset(buf, 0x1, sizeof(buf));
7035   memset(wbuf, 0x1, sizeof(wbuf));
7036   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7037   CHECK_EQ(5, len);
7038   len = str->Write(wbuf);
7039   CHECK_EQ(5, len);
7040   CHECK_EQ(0, strcmp("abcde", buf));
7041   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7042   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7043
7044   memset(buf, 0x1, sizeof(buf));
7045   memset(wbuf, 0x1, sizeof(wbuf));
7046   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7047   CHECK_EQ(4, len);
7048   len = str->Write(wbuf, 0, 4);
7049   CHECK_EQ(4, len);
7050   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7051   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7052   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7053
7054   memset(buf, 0x1, sizeof(buf));
7055   memset(wbuf, 0x1, sizeof(wbuf));
7056   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7057   CHECK_EQ(5, len);
7058   len = str->Write(wbuf, 0, 5);
7059   CHECK_EQ(5, len);
7060   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7061   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7062   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7063
7064   memset(buf, 0x1, sizeof(buf));
7065   memset(wbuf, 0x1, sizeof(wbuf));
7066   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7067   CHECK_EQ(5, len);
7068   len = str->Write(wbuf, 0, 6);
7069   CHECK_EQ(5, len);
7070   CHECK_EQ(0, strcmp("abcde", buf));
7071   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7072   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7073
7074   memset(buf, 0x1, sizeof(buf));
7075   memset(wbuf, 0x1, sizeof(wbuf));
7076   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7077   CHECK_EQ(1, len);
7078   len = str->Write(wbuf, 4, -1);
7079   CHECK_EQ(1, len);
7080   CHECK_EQ(0, strcmp("e", buf));
7081   uint16_t answer5[] = {'e', '\0'};
7082   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7083
7084   memset(buf, 0x1, sizeof(buf));
7085   memset(wbuf, 0x1, sizeof(wbuf));
7086   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7087   CHECK_EQ(1, len);
7088   len = str->Write(wbuf, 4, 6);
7089   CHECK_EQ(1, len);
7090   CHECK_EQ(0, strcmp("e", buf));
7091   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7092
7093   memset(buf, 0x1, sizeof(buf));
7094   memset(wbuf, 0x1, sizeof(wbuf));
7095   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7096   CHECK_EQ(1, len);
7097   len = str->Write(wbuf, 4, 1);
7098   CHECK_EQ(1, len);
7099   CHECK_EQ(0, strncmp("e\1", buf, 2));
7100   uint16_t answer6[] = {'e', 0x101};
7101   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7102
7103   memset(buf, 0x1, sizeof(buf));
7104   memset(wbuf, 0x1, sizeof(wbuf));
7105   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7106   CHECK_EQ(1, len);
7107   len = str->Write(wbuf, 3, 1);
7108   CHECK_EQ(1, len);
7109   CHECK_EQ(0, strncmp("d\1", buf, 2));
7110   uint16_t answer7[] = {'d', 0x101};
7111   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7112
7113   memset(wbuf, 0x1, sizeof(wbuf));
7114   wbuf[5] = 'X';
7115   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7116   CHECK_EQ(5, len);
7117   CHECK_EQ('X', wbuf[5]);
7118   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7119   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7120   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7121   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7122   wbuf[5] = '\0';
7123   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7124
7125   memset(buf, 0x1, sizeof(buf));
7126   buf[5] = 'X';
7127   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7128                           0,
7129                           6,
7130                           String::NO_NULL_TERMINATION);
7131   CHECK_EQ(5, len);
7132   CHECK_EQ('X', buf[5]);
7133   CHECK_EQ(0, strncmp("abcde", buf, 5));
7134   CHECK_NE(0, strcmp("abcde", buf));
7135   buf[5] = '\0';
7136   CHECK_EQ(0, strcmp("abcde", buf));
7137
7138   memset(utf8buf, 0x1, sizeof(utf8buf));
7139   utf8buf[8] = 'X';
7140   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7141                         String::NO_NULL_TERMINATION);
7142   CHECK_EQ(8, len);
7143   CHECK_EQ('X', utf8buf[8]);
7144   CHECK_EQ(5, charlen);
7145   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7146   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7147   utf8buf[8] = '\0';
7148   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7149
7150   memset(utf8buf, 0x1, sizeof(utf8buf));
7151   utf8buf[5] = 'X';
7152   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7153                         String::NO_NULL_TERMINATION);
7154   CHECK_EQ(5, len);
7155   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7156   CHECK_EQ(5, charlen);
7157   utf8buf[5] = '\0';
7158   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7159
7160   memset(buf, 0x1, sizeof(buf));
7161   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7162   CHECK_EQ(7, len);
7163   CHECK_EQ(0, strcmp("abc", buf));
7164   CHECK_EQ(0, buf[3]);
7165   CHECK_EQ(0, strcmp("def", buf + 4));
7166
7167   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7168   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7169   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7170 }
7171
7172
7173 static void Utf16Helper(
7174     LocalContext& context,
7175     const char* name,
7176     const char* lengths_name,
7177     int len) {
7178   Local<v8::Array> a =
7179       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7180   Local<v8::Array> alens =
7181       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7182   for (int i = 0; i < len; i++) {
7183     Local<v8::String> string =
7184       Local<v8::String>::Cast(a->Get(i));
7185     Local<v8::Number> expected_len =
7186       Local<v8::Number>::Cast(alens->Get(i));
7187     int length = GetUtf8Length(string);
7188     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7189   }
7190 }
7191
7192
7193 static uint16_t StringGet(Handle<String> str, int index) {
7194   i::Handle<i::String> istring =
7195       v8::Utils::OpenHandle(String::Cast(*str));
7196   return istring->Get(index);
7197 }
7198
7199
7200 static void WriteUtf8Helper(
7201     LocalContext& context,
7202     const char* name,
7203     const char* lengths_name,
7204     int len) {
7205   Local<v8::Array> b =
7206       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7207   Local<v8::Array> alens =
7208       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7209   char buffer[1000];
7210   char buffer2[1000];
7211   for (int i = 0; i < len; i++) {
7212     Local<v8::String> string =
7213       Local<v8::String>::Cast(b->Get(i));
7214     Local<v8::Number> expected_len =
7215       Local<v8::Number>::Cast(alens->Get(i));
7216     int utf8_length = static_cast<int>(expected_len->Value());
7217     for (int j = utf8_length + 1; j >= 0; j--) {
7218       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7219       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7220       int nchars;
7221       int utf8_written =
7222           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7223       int utf8_written2 =
7224           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7225       CHECK_GE(utf8_length + 1, utf8_written);
7226       CHECK_GE(utf8_length, utf8_written2);
7227       for (int k = 0; k < utf8_written2; k++) {
7228         CHECK_EQ(buffer[k], buffer2[k]);
7229       }
7230       CHECK(nchars * 3 >= utf8_written - 1);
7231       CHECK(nchars <= utf8_written);
7232       if (j == utf8_length + 1) {
7233         CHECK_EQ(utf8_written2, utf8_length);
7234         CHECK_EQ(utf8_written2 + 1, utf8_written);
7235       }
7236       CHECK_EQ(buffer[utf8_written], 42);
7237       if (j > utf8_length) {
7238         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7239         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7240         Handle<String> roundtrip = v8_str(buffer);
7241         CHECK(roundtrip->Equals(string));
7242       } else {
7243         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7244       }
7245       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7246       if (nchars >= 2) {
7247         uint16_t trail = StringGet(string, nchars - 1);
7248         uint16_t lead = StringGet(string, nchars - 2);
7249         if (((lead & 0xfc00) == 0xd800) &&
7250             ((trail & 0xfc00) == 0xdc00)) {
7251           unsigned char u1 = buffer2[utf8_written2 - 4];
7252           unsigned char u2 = buffer2[utf8_written2 - 3];
7253           unsigned char u3 = buffer2[utf8_written2 - 2];
7254           unsigned char u4 = buffer2[utf8_written2 - 1];
7255           CHECK_EQ((u1 & 0xf8), 0xf0);
7256           CHECK_EQ((u2 & 0xc0), 0x80);
7257           CHECK_EQ((u3 & 0xc0), 0x80);
7258           CHECK_EQ((u4 & 0xc0), 0x80);
7259           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7260           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7261           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7262           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7263           CHECK_EQ((u1 & 0x3), c >> 18);
7264         }
7265       }
7266     }
7267   }
7268 }
7269
7270
7271 THREADED_TEST(Utf16) {
7272   LocalContext context;
7273   v8::HandleScope scope(context->GetIsolate());
7274   CompileRun(
7275       "var pad = '01234567890123456789';"
7276       "var p = [];"
7277       "var plens = [20, 3, 3];"
7278       "p.push('01234567890123456789');"
7279       "var lead = 0xd800;"
7280       "var trail = 0xdc00;"
7281       "p.push(String.fromCharCode(0xd800));"
7282       "p.push(String.fromCharCode(0xdc00));"
7283       "var a = [];"
7284       "var b = [];"
7285       "var c = [];"
7286       "var alens = [];"
7287       "for (var i = 0; i < 3; i++) {"
7288       "  p[1] = String.fromCharCode(lead++);"
7289       "  for (var j = 0; j < 3; j++) {"
7290       "    p[2] = String.fromCharCode(trail++);"
7291       "    a.push(p[i] + p[j]);"
7292       "    b.push(p[i] + p[j]);"
7293       "    c.push(p[i] + p[j]);"
7294       "    alens.push(plens[i] + plens[j]);"
7295       "  }"
7296       "}"
7297       "alens[5] -= 2;"  // Here the surrogate pairs match up.
7298       "var a2 = [];"
7299       "var b2 = [];"
7300       "var c2 = [];"
7301       "var a2lens = [];"
7302       "for (var m = 0; m < 9; m++) {"
7303       "  for (var n = 0; n < 9; n++) {"
7304       "    a2.push(a[m] + a[n]);"
7305       "    b2.push(b[m] + b[n]);"
7306       "    var newc = 'x' + c[m] + c[n] + 'y';"
7307       "    c2.push(newc.substring(1, newc.length - 1));"
7308       "    var utf = alens[m] + alens[n];"  // And here.
7309            // The 'n's that start with 0xdc.. are 6-8
7310            // The 'm's that end with 0xd8.. are 1, 4 and 7
7311       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
7312       "    a2lens.push(utf);"
7313       "  }"
7314       "}");
7315   Utf16Helper(context, "a", "alens", 9);
7316   Utf16Helper(context, "a2", "a2lens", 81);
7317   WriteUtf8Helper(context, "b", "alens", 9);
7318   WriteUtf8Helper(context, "b2", "a2lens", 81);
7319   WriteUtf8Helper(context, "c2", "a2lens", 81);
7320 }
7321
7322
7323 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7324   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7325   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7326   return *is1 == *is2;
7327 }
7328
7329
7330 static void SameSymbolHelper(const char* a, const char* b) {
7331   Handle<String> symbol1 = v8::String::NewSymbol(a);
7332   Handle<String> symbol2 = v8::String::NewSymbol(b);
7333   CHECK(SameSymbol(symbol1, symbol2));
7334 }
7335
7336
7337 THREADED_TEST(Utf16Symbol) {
7338   LocalContext context;
7339   v8::HandleScope scope(context->GetIsolate());
7340
7341   Handle<String> symbol1 = v8::String::NewSymbol("abc");
7342   Handle<String> symbol2 = v8::String::NewSymbol("abc");
7343   CHECK(SameSymbol(symbol1, symbol2));
7344
7345   SameSymbolHelper("\360\220\220\205",  // 4 byte encoding.
7346                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
7347   SameSymbolHelper("\355\240\201\355\260\206",  // 2 3-byte surrogates.
7348                    "\360\220\220\206");  // 4 byte encoding.
7349   SameSymbolHelper("x\360\220\220\205",  // 4 byte encoding.
7350                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
7351   SameSymbolHelper("x\355\240\201\355\260\206",  // 2 3-byte surrogates.
7352                    "x\360\220\220\206");  // 4 byte encoding.
7353   CompileRun(
7354       "var sym0 = 'benedictus';"
7355       "var sym0b = 'S\303\270ren';"
7356       "var sym1 = '\355\240\201\355\260\207';"
7357       "var sym2 = '\360\220\220\210';"
7358       "var sym3 = 'x\355\240\201\355\260\207';"
7359       "var sym4 = 'x\360\220\220\210';"
7360       "if (sym1.length != 2) throw sym1;"
7361       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7362       "if (sym2.length != 2) throw sym2;"
7363       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7364       "if (sym3.length != 3) throw sym3;"
7365       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7366       "if (sym4.length != 3) throw sym4;"
7367       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7368   Handle<String> sym0 = v8::String::NewSymbol("benedictus");
7369   Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
7370   Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
7371   Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
7372   Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
7373   Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
7374   v8::Local<v8::Object> global = context->Global();
7375   Local<Value> s0 = global->Get(v8_str("sym0"));
7376   Local<Value> s0b = global->Get(v8_str("sym0b"));
7377   Local<Value> s1 = global->Get(v8_str("sym1"));
7378   Local<Value> s2 = global->Get(v8_str("sym2"));
7379   Local<Value> s3 = global->Get(v8_str("sym3"));
7380   Local<Value> s4 = global->Get(v8_str("sym4"));
7381   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7382   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7383   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7384   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7385   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7386   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7387 }
7388
7389
7390 THREADED_TEST(ToArrayIndex) {
7391   LocalContext context;
7392   v8::HandleScope scope(context->GetIsolate());
7393
7394   v8::Handle<String> str = v8_str("42");
7395   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7396   CHECK(!index.IsEmpty());
7397   CHECK_EQ(42.0, index->Uint32Value());
7398   str = v8_str("42asdf");
7399   index = str->ToArrayIndex();
7400   CHECK(index.IsEmpty());
7401   str = v8_str("-42");
7402   index = str->ToArrayIndex();
7403   CHECK(index.IsEmpty());
7404   str = v8_str("4294967295");
7405   index = str->ToArrayIndex();
7406   CHECK(!index.IsEmpty());
7407   CHECK_EQ(4294967295.0, index->Uint32Value());
7408   v8::Handle<v8::Number> num = v8::Number::New(1);
7409   index = num->ToArrayIndex();
7410   CHECK(!index.IsEmpty());
7411   CHECK_EQ(1.0, index->Uint32Value());
7412   num = v8::Number::New(-1);
7413   index = num->ToArrayIndex();
7414   CHECK(index.IsEmpty());
7415   v8::Handle<v8::Object> obj = v8::Object::New();
7416   index = obj->ToArrayIndex();
7417   CHECK(index.IsEmpty());
7418 }
7419
7420
7421 THREADED_TEST(ErrorConstruction) {
7422   LocalContext context;
7423   v8::HandleScope scope(context->GetIsolate());
7424
7425   v8::Handle<String> foo = v8_str("foo");
7426   v8::Handle<String> message = v8_str("message");
7427   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7428   CHECK(range_error->IsObject());
7429   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7430   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7431   CHECK(reference_error->IsObject());
7432   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7433   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7434   CHECK(syntax_error->IsObject());
7435   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7436   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7437   CHECK(type_error->IsObject());
7438   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7439   v8::Handle<Value> error = v8::Exception::Error(foo);
7440   CHECK(error->IsObject());
7441   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7442 }
7443
7444
7445 static void YGetter(Local<String> name,
7446                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7447   ApiTestFuzzer::Fuzz();
7448   info.GetReturnValue().Set(v8_num(10));
7449 }
7450
7451
7452 static void YSetter(Local<String> name,
7453                     Local<Value> value,
7454                     const v8::PropertyCallbackInfo<void>& info) {
7455   if (info.This()->Has(name)) {
7456     info.This()->Delete(name);
7457   }
7458   info.This()->Set(name, value);
7459 }
7460
7461
7462 THREADED_TEST(DeleteAccessor) {
7463   v8::HandleScope scope(v8::Isolate::GetCurrent());
7464   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7465   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7466   LocalContext context;
7467   v8::Handle<v8::Object> holder = obj->NewInstance();
7468   context->Global()->Set(v8_str("holder"), holder);
7469   v8::Handle<Value> result = CompileRun(
7470       "holder.y = 11; holder.y = 12; holder.y");
7471   CHECK_EQ(12, result->Uint32Value());
7472 }
7473
7474
7475 THREADED_TEST(TypeSwitch) {
7476   v8::HandleScope scope(v8::Isolate::GetCurrent());
7477   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
7478   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
7479   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
7480   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7481   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7482   LocalContext context;
7483   v8::Handle<v8::Object> obj0 = v8::Object::New();
7484   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7485   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7486   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7487   for (int i = 0; i < 10; i++) {
7488     CHECK_EQ(0, type_switch->match(obj0));
7489     CHECK_EQ(1, type_switch->match(obj1));
7490     CHECK_EQ(2, type_switch->match(obj2));
7491     CHECK_EQ(3, type_switch->match(obj3));
7492     CHECK_EQ(3, type_switch->match(obj3));
7493     CHECK_EQ(2, type_switch->match(obj2));
7494     CHECK_EQ(1, type_switch->match(obj1));
7495     CHECK_EQ(0, type_switch->match(obj0));
7496   }
7497 }
7498
7499
7500 // For use within the TestSecurityHandler() test.
7501 static bool g_security_callback_result = false;
7502 static bool NamedSecurityTestCallback(Local<v8::Object> global,
7503                                       Local<Value> name,
7504                                       v8::AccessType type,
7505                                       Local<Value> data) {
7506   // Always allow read access.
7507   if (type == v8::ACCESS_GET)
7508     return true;
7509
7510   // Sometimes allow other access.
7511   return g_security_callback_result;
7512 }
7513
7514
7515 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
7516                                         uint32_t key,
7517                                         v8::AccessType type,
7518                                         Local<Value> data) {
7519   // Always allow read access.
7520   if (type == v8::ACCESS_GET)
7521     return true;
7522
7523   // Sometimes allow other access.
7524   return g_security_callback_result;
7525 }
7526
7527
7528 static int trouble_nesting = 0;
7529 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7530   ApiTestFuzzer::Fuzz();
7531   trouble_nesting++;
7532
7533   // Call a JS function that throws an uncaught exception.
7534   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
7535   Local<Value> trouble_callee = (trouble_nesting == 3) ?
7536     arg_this->Get(v8_str("trouble_callee")) :
7537     arg_this->Get(v8_str("trouble_caller"));
7538   CHECK(trouble_callee->IsFunction());
7539   args.GetReturnValue().Set(
7540       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7541 }
7542
7543
7544 static int report_count = 0;
7545 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7546                                              v8::Handle<Value>) {
7547   report_count++;
7548 }
7549
7550
7551 // Counts uncaught exceptions, but other tests running in parallel
7552 // also have uncaught exceptions.
7553 TEST(ApiUncaughtException) {
7554   report_count = 0;
7555   LocalContext env;
7556   v8::HandleScope scope(env->GetIsolate());
7557   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7558
7559   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7560   v8::Local<v8::Object> global = env->Global();
7561   global->Set(v8_str("trouble"), fun->GetFunction());
7562
7563   Script::Compile(v8_str("function trouble_callee() {"
7564                          "  var x = null;"
7565                          "  return x.foo;"
7566                          "};"
7567                          "function trouble_caller() {"
7568                          "  trouble();"
7569                          "};"))->Run();
7570   Local<Value> trouble = global->Get(v8_str("trouble"));
7571   CHECK(trouble->IsFunction());
7572   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7573   CHECK(trouble_callee->IsFunction());
7574   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7575   CHECK(trouble_caller->IsFunction());
7576   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7577   CHECK_EQ(1, report_count);
7578   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7579 }
7580
7581 static const char* script_resource_name = "ExceptionInNativeScript.js";
7582 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7583                                                 v8::Handle<Value>) {
7584   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
7585   CHECK(!name_val.IsEmpty() && name_val->IsString());
7586   v8::String::Utf8Value name(message->GetScriptResourceName());
7587   CHECK_EQ(script_resource_name, *name);
7588   CHECK_EQ(3, message->GetLineNumber());
7589   v8::String::Utf8Value source_line(message->GetSourceLine());
7590   CHECK_EQ("  new o.foo();", *source_line);
7591 }
7592
7593
7594 TEST(ExceptionInNativeScript) {
7595   LocalContext env;
7596   v8::HandleScope scope(env->GetIsolate());
7597   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7598
7599   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7600   v8::Local<v8::Object> global = env->Global();
7601   global->Set(v8_str("trouble"), fun->GetFunction());
7602
7603   Script::Compile(v8_str("function trouble() {\n"
7604                          "  var o = {};\n"
7605                          "  new o.foo();\n"
7606                          "};"), v8::String::New(script_resource_name))->Run();
7607   Local<Value> trouble = global->Get(v8_str("trouble"));
7608   CHECK(trouble->IsFunction());
7609   Function::Cast(*trouble)->Call(global, 0, NULL);
7610   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7611 }
7612
7613
7614 TEST(CompilationErrorUsingTryCatchHandler) {
7615   LocalContext env;
7616   v8::HandleScope scope(env->GetIsolate());
7617   v8::TryCatch try_catch;
7618   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
7619   CHECK_NE(NULL, *try_catch.Exception());
7620   CHECK(try_catch.HasCaught());
7621 }
7622
7623
7624 TEST(TryCatchFinallyUsingTryCatchHandler) {
7625   LocalContext env;
7626   v8::HandleScope scope(env->GetIsolate());
7627   v8::TryCatch try_catch;
7628   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
7629   CHECK(!try_catch.HasCaught());
7630   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
7631   CHECK(try_catch.HasCaught());
7632   try_catch.Reset();
7633   Script::Compile(v8_str("(function() {"
7634                          "try { throw ''; } finally { return; }"
7635                          "})()"))->Run();
7636   CHECK(!try_catch.HasCaught());
7637   Script::Compile(v8_str("(function()"
7638                          "  { try { throw ''; } finally { throw 0; }"
7639                          "})()"))->Run();
7640   CHECK(try_catch.HasCaught());
7641 }
7642
7643
7644 // SecurityHandler can't be run twice
7645 TEST(SecurityHandler) {
7646   v8::HandleScope scope0(v8::Isolate::GetCurrent());
7647   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7648   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
7649                                            IndexedSecurityTestCallback);
7650   // Create an environment
7651   v8::Handle<Context> context0 =
7652     Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
7653   context0->Enter();
7654
7655   v8::Handle<v8::Object> global0 = context0->Global();
7656   v8::Handle<Script> script0 = v8_compile("foo = 111");
7657   script0->Run();
7658   global0->Set(v8_str("0"), v8_num(999));
7659   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7660   CHECK_EQ(111, foo0->Int32Value());
7661   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7662   CHECK_EQ(999, z0->Int32Value());
7663
7664   // Create another environment, should fail security checks.
7665   v8::HandleScope scope1(v8::Isolate::GetCurrent());
7666
7667   v8::Handle<Context> context1 =
7668     Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
7669   context1->Enter();
7670
7671   v8::Handle<v8::Object> global1 = context1->Global();
7672   global1->Set(v8_str("othercontext"), global0);
7673   // This set will fail the security check.
7674   v8::Handle<Script> script1 =
7675     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7676   script1->Run();
7677   // This read will pass the security check.
7678   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7679   CHECK_EQ(111, foo1->Int32Value());
7680   // This read will pass the security check.
7681   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7682   CHECK_EQ(999, z1->Int32Value());
7683
7684   // Create another environment, should pass security checks.
7685   { g_security_callback_result = true;  // allow security handler to pass.
7686     v8::HandleScope scope2(v8::Isolate::GetCurrent());
7687     LocalContext context2;
7688     v8::Handle<v8::Object> global2 = context2->Global();
7689     global2->Set(v8_str("othercontext"), global0);
7690     v8::Handle<Script> script2 =
7691         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7692     script2->Run();
7693     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7694     CHECK_EQ(333, foo2->Int32Value());
7695     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7696     CHECK_EQ(888, z2->Int32Value());
7697   }
7698
7699   context1->Exit();
7700   context0->Exit();
7701 }
7702
7703
7704 THREADED_TEST(SecurityChecks) {
7705   LocalContext env1;
7706   v8::HandleScope handle_scope(env1->GetIsolate());
7707   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7708
7709   Local<Value> foo = v8_str("foo");
7710   Local<Value> bar = v8_str("bar");
7711
7712   // Set to the same domain.
7713   env1->SetSecurityToken(foo);
7714
7715   // Create a function in env1.
7716   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
7717   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7718   CHECK(spy->IsFunction());
7719
7720   // Create another function accessing global objects.
7721   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
7722   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7723   CHECK(spy2->IsFunction());
7724
7725   // Switch to env2 in the same domain and invoke spy on env2.
7726   {
7727     env2->SetSecurityToken(foo);
7728     // Enter env2
7729     Context::Scope scope_env2(env2);
7730     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
7731     CHECK(result->IsFunction());
7732   }
7733
7734   {
7735     env2->SetSecurityToken(bar);
7736     Context::Scope scope_env2(env2);
7737
7738     // Call cross_domain_call, it should throw an exception
7739     v8::TryCatch try_catch;
7740     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
7741     CHECK(try_catch.HasCaught());
7742   }
7743 }
7744
7745
7746 // Regression test case for issue 1183439.
7747 THREADED_TEST(SecurityChecksForPrototypeChain) {
7748   LocalContext current;
7749   v8::HandleScope scope(current->GetIsolate());
7750   v8::Handle<Context> other = Context::New(current->GetIsolate());
7751
7752   // Change context to be able to get to the Object function in the
7753   // other context without hitting the security checks.
7754   v8::Local<Value> other_object;
7755   { Context::Scope scope(other);
7756     other_object = other->Global()->Get(v8_str("Object"));
7757     other->Global()->Set(v8_num(42), v8_num(87));
7758   }
7759
7760   current->Global()->Set(v8_str("other"), other->Global());
7761   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
7762
7763   // Make sure the security check fails here and we get an undefined
7764   // result instead of getting the Object function. Repeat in a loop
7765   // to make sure to exercise the IC code.
7766   v8::Local<Script> access_other0 = v8_compile("other.Object");
7767   v8::Local<Script> access_other1 = v8_compile("other[42]");
7768   for (int i = 0; i < 5; i++) {
7769     CHECK(!access_other0->Run()->Equals(other_object));
7770     CHECK(access_other0->Run()->IsUndefined());
7771     CHECK(!access_other1->Run()->Equals(v8_num(87)));
7772     CHECK(access_other1->Run()->IsUndefined());
7773   }
7774
7775   // Create an object that has 'other' in its prototype chain and make
7776   // sure we cannot access the Object function indirectly through
7777   // that. Repeat in a loop to make sure to exercise the IC code.
7778   v8_compile("function F() { };"
7779              "F.prototype = other;"
7780              "var f = new F();")->Run();
7781   v8::Local<Script> access_f0 = v8_compile("f.Object");
7782   v8::Local<Script> access_f1 = v8_compile("f[42]");
7783   for (int j = 0; j < 5; j++) {
7784     CHECK(!access_f0->Run()->Equals(other_object));
7785     CHECK(access_f0->Run()->IsUndefined());
7786     CHECK(!access_f1->Run()->Equals(v8_num(87)));
7787     CHECK(access_f1->Run()->IsUndefined());
7788   }
7789
7790   // Now it gets hairy: Set the prototype for the other global object
7791   // to be the current global object. The prototype chain for 'f' now
7792   // goes through 'other' but ends up in the current global object.
7793   { Context::Scope scope(other);
7794     other->Global()->Set(v8_str("__proto__"), current->Global());
7795   }
7796   // Set a named and an index property on the current global
7797   // object. To force the lookup to go through the other global object,
7798   // the properties must not exist in the other global object.
7799   current->Global()->Set(v8_str("foo"), v8_num(100));
7800   current->Global()->Set(v8_num(99), v8_num(101));
7801   // Try to read the properties from f and make sure that the access
7802   // gets stopped by the security checks on the other global object.
7803   Local<Script> access_f2 = v8_compile("f.foo");
7804   Local<Script> access_f3 = v8_compile("f[99]");
7805   for (int k = 0; k < 5; k++) {
7806     CHECK(!access_f2->Run()->Equals(v8_num(100)));
7807     CHECK(access_f2->Run()->IsUndefined());
7808     CHECK(!access_f3->Run()->Equals(v8_num(101)));
7809     CHECK(access_f3->Run()->IsUndefined());
7810   }
7811 }
7812
7813
7814 THREADED_TEST(CrossDomainDelete) {
7815   LocalContext env1;
7816   v8::HandleScope handle_scope(env1->GetIsolate());
7817   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7818
7819   Local<Value> foo = v8_str("foo");
7820   Local<Value> bar = v8_str("bar");
7821
7822   // Set to the same domain.
7823   env1->SetSecurityToken(foo);
7824   env2->SetSecurityToken(foo);
7825
7826   env1->Global()->Set(v8_str("prop"), v8_num(3));
7827   env2->Global()->Set(v8_str("env1"), env1->Global());
7828
7829   // Change env2 to a different domain and delete env1.prop.
7830   env2->SetSecurityToken(bar);
7831   {
7832     Context::Scope scope_env2(env2);
7833     Local<Value> result =
7834         Script::Compile(v8_str("delete env1.prop"))->Run();
7835     CHECK(result->IsFalse());
7836   }
7837
7838   // Check that env1.prop still exists.
7839   Local<Value> v = env1->Global()->Get(v8_str("prop"));
7840   CHECK(v->IsNumber());
7841   CHECK_EQ(3, v->Int32Value());
7842 }
7843
7844
7845 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
7846   LocalContext env1;
7847   v8::HandleScope handle_scope(env1->GetIsolate());
7848   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7849
7850   Local<Value> foo = v8_str("foo");
7851   Local<Value> bar = v8_str("bar");
7852
7853   // Set to the same domain.
7854   env1->SetSecurityToken(foo);
7855   env2->SetSecurityToken(foo);
7856
7857   env1->Global()->Set(v8_str("prop"), v8_num(3));
7858   env2->Global()->Set(v8_str("env1"), env1->Global());
7859
7860   // env1.prop is enumerable in env2.
7861   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
7862   {
7863     Context::Scope scope_env2(env2);
7864     Local<Value> result = Script::Compile(test)->Run();
7865     CHECK(result->IsTrue());
7866   }
7867
7868   // Change env2 to a different domain and test again.
7869   env2->SetSecurityToken(bar);
7870   {
7871     Context::Scope scope_env2(env2);
7872     Local<Value> result = Script::Compile(test)->Run();
7873     CHECK(result->IsFalse());
7874   }
7875 }
7876
7877
7878 THREADED_TEST(CrossDomainForIn) {
7879   LocalContext env1;
7880   v8::HandleScope handle_scope(env1->GetIsolate());
7881   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7882
7883   Local<Value> foo = v8_str("foo");
7884   Local<Value> bar = v8_str("bar");
7885
7886   // Set to the same domain.
7887   env1->SetSecurityToken(foo);
7888   env2->SetSecurityToken(foo);
7889
7890   env1->Global()->Set(v8_str("prop"), v8_num(3));
7891   env2->Global()->Set(v8_str("env1"), env1->Global());
7892
7893   // Change env2 to a different domain and set env1's global object
7894   // as the __proto__ of an object in env2 and enumerate properties
7895   // in for-in. It shouldn't enumerate properties on env1's global
7896   // object.
7897   env2->SetSecurityToken(bar);
7898   {
7899     Context::Scope scope_env2(env2);
7900     Local<Value> result =
7901         CompileRun("(function(){var obj = {'__proto__':env1};"
7902                    "for (var p in obj)"
7903                    "   if (p == 'prop') return false;"
7904                    "return true;})()");
7905     CHECK(result->IsTrue());
7906   }
7907 }
7908
7909
7910 TEST(ContextDetachGlobal) {
7911   LocalContext env1;
7912   v8::HandleScope handle_scope(env1->GetIsolate());
7913   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7914
7915   Local<v8::Object> global1 = env1->Global();
7916
7917   Local<Value> foo = v8_str("foo");
7918
7919   // Set to the same domain.
7920   env1->SetSecurityToken(foo);
7921   env2->SetSecurityToken(foo);
7922
7923   // Enter env2
7924   env2->Enter();
7925
7926   // Create a function in env2 and add a reference to it in env1.
7927   Local<v8::Object> global2 = env2->Global();
7928   global2->Set(v8_str("prop"), v8::Integer::New(1));
7929   CompileRun("function getProp() {return prop;}");
7930
7931   env1->Global()->Set(v8_str("getProp"),
7932                       global2->Get(v8_str("getProp")));
7933
7934   // Detach env2's global, and reuse the global object of env2
7935   env2->Exit();
7936   env2->DetachGlobal();
7937   // env2 has a new global object.
7938   CHECK(!env2->Global()->Equals(global2));
7939
7940   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
7941                                           0,
7942                                           v8::Handle<v8::ObjectTemplate>(),
7943                                           global2);
7944   env3->SetSecurityToken(v8_str("bar"));
7945   env3->Enter();
7946
7947   Local<v8::Object> global3 = env3->Global();
7948   CHECK_EQ(global2, global3);
7949   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
7950   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
7951   global3->Set(v8_str("prop"), v8::Integer::New(-1));
7952   global3->Set(v8_str("prop2"), v8::Integer::New(2));
7953   env3->Exit();
7954
7955   // Call getProp in env1, and it should return the value 1
7956   {
7957     Local<Value> get_prop = global1->Get(v8_str("getProp"));
7958     CHECK(get_prop->IsFunction());
7959     v8::TryCatch try_catch;
7960     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
7961     CHECK(!try_catch.HasCaught());
7962     CHECK_EQ(1, r->Int32Value());
7963   }
7964
7965   // Check that env3 is not accessible from env1
7966   {
7967     Local<Value> r = global3->Get(v8_str("prop2"));
7968     CHECK(r->IsUndefined());
7969   }
7970 }
7971
7972
7973 TEST(DetachAndReattachGlobal) {
7974   LocalContext env1;
7975   v8::HandleScope scope(env1->GetIsolate());
7976
7977   // Create second environment.
7978   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7979
7980   Local<Value> foo = v8_str("foo");
7981
7982   // Set same security token for env1 and env2.
7983   env1->SetSecurityToken(foo);
7984   env2->SetSecurityToken(foo);
7985
7986   // Create a property on the global object in env2.
7987   {
7988     v8::Context::Scope scope(env2);
7989     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
7990   }
7991
7992   // Create a reference to env2 global from env1 global.
7993   env1->Global()->Set(v8_str("other"), env2->Global());
7994
7995   // Check that we have access to other.p in env2 from env1.
7996   Local<Value> result = CompileRun("other.p");
7997   CHECK(result->IsInt32());
7998   CHECK_EQ(42, result->Int32Value());
7999
8000   // Hold on to global from env2 and detach global from env2.
8001   Local<v8::Object> global2 = env2->Global();
8002   env2->DetachGlobal();
8003
8004   // Check that the global has been detached. No other.p property can
8005   // be found.
8006   result = CompileRun("other.p");
8007   CHECK(result->IsUndefined());
8008
8009   // Reuse global2 for env3.
8010   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8011                                           0,
8012                                           v8::Handle<v8::ObjectTemplate>(),
8013                                           global2);
8014   CHECK_EQ(global2, env3->Global());
8015
8016   // Start by using the same security token for env3 as for env1 and env2.
8017   env3->SetSecurityToken(foo);
8018
8019   // Create a property on the global object in env3.
8020   {
8021     v8::Context::Scope scope(env3);
8022     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
8023   }
8024
8025   // Check that other.p is now the property in env3 and that we have access.
8026   result = CompileRun("other.p");
8027   CHECK(result->IsInt32());
8028   CHECK_EQ(24, result->Int32Value());
8029
8030   // Change security token for env3 to something different from env1 and env2.
8031   env3->SetSecurityToken(v8_str("bar"));
8032
8033   // Check that we do not have access to other.p in env1. |other| is now
8034   // the global object for env3 which has a different security token,
8035   // so access should be blocked.
8036   result = CompileRun("other.p");
8037   CHECK(result->IsUndefined());
8038
8039   // Detach the global for env3 and reattach it to env2.
8040   env3->DetachGlobal();
8041   env2->ReattachGlobal(global2);
8042
8043   // Check that we have access to other.p again in env1.  |other| is now
8044   // the global object for env2 which has the same security token as env1.
8045   result = CompileRun("other.p");
8046   CHECK(result->IsInt32());
8047   CHECK_EQ(42, result->Int32Value());
8048 }
8049
8050
8051 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8052 static bool NamedAccessBlocker(Local<v8::Object> global,
8053                                Local<Value> name,
8054                                v8::AccessType type,
8055                                Local<Value> data) {
8056   return Context::GetCurrent()->Global()->Equals(global) ||
8057       allowed_access_type[type];
8058 }
8059
8060
8061 static bool IndexedAccessBlocker(Local<v8::Object> global,
8062                                  uint32_t key,
8063                                  v8::AccessType type,
8064                                  Local<Value> data) {
8065   return Context::GetCurrent()->Global()->Equals(global) ||
8066       allowed_access_type[type];
8067 }
8068
8069
8070 static int g_echo_value = -1;
8071 static void EchoGetter(
8072     Local<String> name,
8073     const v8::PropertyCallbackInfo<v8::Value>& info) {
8074   info.GetReturnValue().Set(v8_num(g_echo_value));
8075 }
8076
8077
8078 static void EchoSetter(Local<String> name,
8079                        Local<Value> value,
8080                        const v8::PropertyCallbackInfo<void>&) {
8081   if (value->IsNumber())
8082     g_echo_value = value->Int32Value();
8083 }
8084
8085
8086 static void UnreachableGetter(
8087     Local<String> name,
8088     const v8::PropertyCallbackInfo<v8::Value>& info) {
8089   CHECK(false);  // This function should not be called..
8090 }
8091
8092
8093 static void UnreachableSetter(Local<String>,
8094                               Local<Value>,
8095                               const v8::PropertyCallbackInfo<void>&) {
8096   CHECK(false);  // This function should nto be called.
8097 }
8098
8099
8100 TEST(AccessControl) {
8101   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8102   v8::HandleScope handle_scope(isolate);
8103   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8104
8105   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8106                                            IndexedAccessBlocker);
8107
8108   // Add an accessor accessible by cross-domain JS code.
8109   global_template->SetAccessor(
8110       v8_str("accessible_prop"),
8111       EchoGetter, EchoSetter,
8112       v8::Handle<Value>(),
8113       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8114
8115   // Add an accessor that is not accessible by cross-domain JS code.
8116   global_template->SetAccessor(v8_str("blocked_prop"),
8117                                UnreachableGetter, UnreachableSetter,
8118                                v8::Handle<Value>(),
8119                                v8::DEFAULT);
8120
8121   // Create an environment
8122   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8123   context0->Enter();
8124
8125   v8::Handle<v8::Object> global0 = context0->Global();
8126
8127   // Define a property with JS getter and setter.
8128   CompileRun(
8129       "function getter() { return 'getter'; };\n"
8130       "function setter() { return 'setter'; }\n"
8131       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8132
8133   Local<Value> getter = global0->Get(v8_str("getter"));
8134   Local<Value> setter = global0->Get(v8_str("setter"));
8135
8136   // And define normal element.
8137   global0->Set(239, v8_str("239"));
8138
8139   // Define an element with JS getter and setter.
8140   CompileRun(
8141       "function el_getter() { return 'el_getter'; };\n"
8142       "function el_setter() { return 'el_setter'; };\n"
8143       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8144
8145   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8146   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8147
8148   v8::HandleScope scope1(isolate);
8149
8150   v8::Local<Context> context1 = Context::New(isolate);
8151   context1->Enter();
8152
8153   v8::Handle<v8::Object> global1 = context1->Global();
8154   global1->Set(v8_str("other"), global0);
8155
8156   // Access blocked property.
8157   CompileRun("other.blocked_prop = 1");
8158
8159   ExpectUndefined("other.blocked_prop");
8160   ExpectUndefined(
8161       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8162   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8163
8164   // Enable ACCESS_HAS
8165   allowed_access_type[v8::ACCESS_HAS] = true;
8166   ExpectUndefined("other.blocked_prop");
8167   // ... and now we can get the descriptor...
8168   ExpectUndefined(
8169       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
8170   // ... and enumerate the property.
8171   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
8172   allowed_access_type[v8::ACCESS_HAS] = false;
8173
8174   // Access blocked element.
8175   CompileRun("other[239] = 1");
8176
8177   ExpectUndefined("other[239]");
8178   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
8179   ExpectFalse("propertyIsEnumerable.call(other, '239')");
8180
8181   // Enable ACCESS_HAS
8182   allowed_access_type[v8::ACCESS_HAS] = true;
8183   ExpectUndefined("other[239]");
8184   // ... and now we can get the descriptor...
8185   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
8186   // ... and enumerate the property.
8187   ExpectTrue("propertyIsEnumerable.call(other, '239')");
8188   allowed_access_type[v8::ACCESS_HAS] = false;
8189
8190   // Access a property with JS accessor.
8191   CompileRun("other.js_accessor_p = 2");
8192
8193   ExpectUndefined("other.js_accessor_p");
8194   ExpectUndefined(
8195       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
8196
8197   // Enable ACCESS_HAS.
8198   allowed_access_type[v8::ACCESS_HAS] = true;
8199   ExpectUndefined("other.js_accessor_p");
8200   ExpectUndefined(
8201       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8202   ExpectUndefined(
8203       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8204   ExpectUndefined(
8205       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8206   allowed_access_type[v8::ACCESS_HAS] = false;
8207
8208   // Enable both ACCESS_HAS and ACCESS_GET.
8209   allowed_access_type[v8::ACCESS_HAS] = true;
8210   allowed_access_type[v8::ACCESS_GET] = true;
8211
8212   ExpectString("other.js_accessor_p", "getter");
8213   ExpectObject(
8214       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8215   ExpectUndefined(
8216       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8217   ExpectUndefined(
8218       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8219
8220   allowed_access_type[v8::ACCESS_GET] = false;
8221   allowed_access_type[v8::ACCESS_HAS] = false;
8222
8223   // Enable both ACCESS_HAS and ACCESS_SET.
8224   allowed_access_type[v8::ACCESS_HAS] = true;
8225   allowed_access_type[v8::ACCESS_SET] = true;
8226
8227   ExpectUndefined("other.js_accessor_p");
8228   ExpectUndefined(
8229       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8230   ExpectObject(
8231       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8232   ExpectUndefined(
8233       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8234
8235   allowed_access_type[v8::ACCESS_SET] = false;
8236   allowed_access_type[v8::ACCESS_HAS] = false;
8237
8238   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8239   allowed_access_type[v8::ACCESS_HAS] = true;
8240   allowed_access_type[v8::ACCESS_GET] = true;
8241   allowed_access_type[v8::ACCESS_SET] = true;
8242
8243   ExpectString("other.js_accessor_p", "getter");
8244   ExpectObject(
8245       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8246   ExpectObject(
8247       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8248   ExpectUndefined(
8249       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8250
8251   allowed_access_type[v8::ACCESS_SET] = false;
8252   allowed_access_type[v8::ACCESS_GET] = false;
8253   allowed_access_type[v8::ACCESS_HAS] = false;
8254
8255   // Access an element with JS accessor.
8256   CompileRun("other[42] = 2");
8257
8258   ExpectUndefined("other[42]");
8259   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
8260
8261   // Enable ACCESS_HAS.
8262   allowed_access_type[v8::ACCESS_HAS] = true;
8263   ExpectUndefined("other[42]");
8264   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8265   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8266   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8267   allowed_access_type[v8::ACCESS_HAS] = false;
8268
8269   // Enable both ACCESS_HAS and ACCESS_GET.
8270   allowed_access_type[v8::ACCESS_HAS] = true;
8271   allowed_access_type[v8::ACCESS_GET] = true;
8272
8273   ExpectString("other[42]", "el_getter");
8274   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8275   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8276   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8277
8278   allowed_access_type[v8::ACCESS_GET] = false;
8279   allowed_access_type[v8::ACCESS_HAS] = false;
8280
8281   // Enable both ACCESS_HAS and ACCESS_SET.
8282   allowed_access_type[v8::ACCESS_HAS] = true;
8283   allowed_access_type[v8::ACCESS_SET] = true;
8284
8285   ExpectUndefined("other[42]");
8286   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8287   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8288   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8289
8290   allowed_access_type[v8::ACCESS_SET] = false;
8291   allowed_access_type[v8::ACCESS_HAS] = false;
8292
8293   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8294   allowed_access_type[v8::ACCESS_HAS] = true;
8295   allowed_access_type[v8::ACCESS_GET] = true;
8296   allowed_access_type[v8::ACCESS_SET] = true;
8297
8298   ExpectString("other[42]", "el_getter");
8299   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8300   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8301   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8302
8303   allowed_access_type[v8::ACCESS_SET] = false;
8304   allowed_access_type[v8::ACCESS_GET] = false;
8305   allowed_access_type[v8::ACCESS_HAS] = false;
8306
8307   v8::Handle<Value> value;
8308
8309   // Access accessible property
8310   value = CompileRun("other.accessible_prop = 3");
8311   CHECK(value->IsNumber());
8312   CHECK_EQ(3, value->Int32Value());
8313   CHECK_EQ(3, g_echo_value);
8314
8315   value = CompileRun("other.accessible_prop");
8316   CHECK(value->IsNumber());
8317   CHECK_EQ(3, value->Int32Value());
8318
8319   value = CompileRun(
8320       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8321   CHECK(value->IsNumber());
8322   CHECK_EQ(3, value->Int32Value());
8323
8324   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8325   CHECK(value->IsTrue());
8326
8327   // Enumeration doesn't enumerate accessors from inaccessible objects in
8328   // the prototype chain even if the accessors are in themselves accessible.
8329   value =
8330       CompileRun("(function(){var obj = {'__proto__':other};"
8331                  "for (var p in obj)"
8332                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
8333                  "     return false;"
8334                  "   }"
8335                  "return true;})()");
8336   CHECK(value->IsTrue());
8337
8338   context1->Exit();
8339   context0->Exit();
8340 }
8341
8342
8343 TEST(AccessControlES5) {
8344   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8345   v8::HandleScope handle_scope(isolate);
8346   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8347
8348   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8349                                            IndexedAccessBlocker);
8350
8351   // Add accessible accessor.
8352   global_template->SetAccessor(
8353       v8_str("accessible_prop"),
8354       EchoGetter, EchoSetter,
8355       v8::Handle<Value>(),
8356       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8357
8358
8359   // Add an accessor that is not accessible by cross-domain JS code.
8360   global_template->SetAccessor(v8_str("blocked_prop"),
8361                                UnreachableGetter, UnreachableSetter,
8362                                v8::Handle<Value>(),
8363                                v8::DEFAULT);
8364
8365   // Create an environment
8366   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8367   context0->Enter();
8368
8369   v8::Handle<v8::Object> global0 = context0->Global();
8370
8371   v8::Local<Context> context1 = Context::New(isolate);
8372   context1->Enter();
8373   v8::Handle<v8::Object> global1 = context1->Global();
8374   global1->Set(v8_str("other"), global0);
8375
8376   // Regression test for issue 1154.
8377   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
8378
8379   ExpectUndefined("other.blocked_prop");
8380
8381   // Regression test for issue 1027.
8382   CompileRun("Object.defineProperty(\n"
8383              "  other, 'blocked_prop', {configurable: false})");
8384   ExpectUndefined("other.blocked_prop");
8385   ExpectUndefined(
8386       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8387
8388   // Regression test for issue 1171.
8389   ExpectTrue("Object.isExtensible(other)");
8390   CompileRun("Object.preventExtensions(other)");
8391   ExpectTrue("Object.isExtensible(other)");
8392
8393   // Object.seal and Object.freeze.
8394   CompileRun("Object.freeze(other)");
8395   ExpectTrue("Object.isExtensible(other)");
8396
8397   CompileRun("Object.seal(other)");
8398   ExpectTrue("Object.isExtensible(other)");
8399
8400   // Regression test for issue 1250.
8401   // Make sure that we can set the accessible accessors value using normal
8402   // assignment.
8403   CompileRun("other.accessible_prop = 42");
8404   CHECK_EQ(42, g_echo_value);
8405
8406   v8::Handle<Value> value;
8407   // We follow Safari in ignoring assignments to host object accessors.
8408   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8409   value = CompileRun("other.accessible_prop == 42");
8410   CHECK(value->IsTrue());
8411 }
8412
8413
8414 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
8415                                             Local<Value> name,
8416                                             v8::AccessType type,
8417                                             Local<Value> data) {
8418   return false;
8419 }
8420
8421
8422 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
8423                                               uint32_t key,
8424                                               v8::AccessType type,
8425                                               Local<Value> data) {
8426   return false;
8427 }
8428
8429
8430 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8431   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8432   v8::HandleScope handle_scope(isolate);
8433   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8434
8435   obj_template->Set(v8_str("x"), v8::Integer::New(42));
8436   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
8437                                         GetOwnPropertyNamesIndexedBlocker);
8438
8439   // Create an environment
8440   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8441   context0->Enter();
8442
8443   v8::Handle<v8::Object> global0 = context0->Global();
8444
8445   v8::HandleScope scope1(v8::Isolate::GetCurrent());
8446
8447   v8::Local<Context> context1 = Context::New(isolate);
8448   context1->Enter();
8449
8450   v8::Handle<v8::Object> global1 = context1->Global();
8451   global1->Set(v8_str("other"), global0);
8452   global1->Set(v8_str("object"), obj_template->NewInstance());
8453
8454   v8::Handle<Value> value;
8455
8456   // Attempt to get the property names of the other global object and
8457   // of an object that requires access checks.  Accessing the other
8458   // global object should be blocked by access checks on the global
8459   // proxy object.  Accessing the object that requires access checks
8460   // is blocked by the access checks on the object itself.
8461   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8462   CHECK(value->IsTrue());
8463
8464   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8465   CHECK(value->IsTrue());
8466
8467   context1->Exit();
8468   context0->Exit();
8469 }
8470
8471
8472 static void IndexedPropertyEnumerator(
8473     const v8::PropertyCallbackInfo<v8::Array>& info) {
8474   v8::Handle<v8::Array> result = v8::Array::New(2);
8475   result->Set(0, v8::Integer::New(7));
8476   result->Set(1, v8::Object::New());
8477   info.GetReturnValue().Set(result);
8478 }
8479
8480
8481 static void NamedPropertyEnumerator(
8482     const v8::PropertyCallbackInfo<v8::Array>& info) {
8483   v8::Handle<v8::Array> result = v8::Array::New(2);
8484   result->Set(0, v8_str("x"));
8485   result->Set(1, v8::Object::New());
8486   info.GetReturnValue().Set(result);
8487 }
8488
8489
8490 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
8491   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8492   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8493
8494   obj_template->Set(v8_str("7"), v8::Integer::New(7));
8495   obj_template->Set(v8_str("x"), v8::Integer::New(42));
8496   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
8497                                           IndexedPropertyEnumerator);
8498   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
8499                                         NamedPropertyEnumerator);
8500
8501   LocalContext context;
8502   v8::Handle<v8::Object> global = context->Global();
8503   global->Set(v8_str("object"), obj_template->NewInstance());
8504
8505   v8::Handle<v8::Value> result =
8506       CompileRun("Object.getOwnPropertyNames(object)");
8507   CHECK(result->IsArray());
8508   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
8509   CHECK_EQ(3, result_array->Length());
8510   CHECK(result_array->Get(0)->IsString());
8511   CHECK(result_array->Get(1)->IsString());
8512   CHECK(result_array->Get(2)->IsString());
8513   CHECK_EQ(v8_str("7"), result_array->Get(0));
8514   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
8515   CHECK_EQ(v8_str("x"), result_array->Get(2));
8516 }
8517
8518
8519 static void ConstTenGetter(Local<String> name,
8520                            const v8::PropertyCallbackInfo<v8::Value>& info) {
8521   info.GetReturnValue().Set(v8_num(10));
8522 }
8523
8524
8525 THREADED_TEST(CrossDomainAccessors) {
8526   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8527   v8::HandleScope handle_scope(isolate);
8528
8529   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
8530
8531   v8::Handle<v8::ObjectTemplate> global_template =
8532       func_template->InstanceTemplate();
8533
8534   v8::Handle<v8::ObjectTemplate> proto_template =
8535       func_template->PrototypeTemplate();
8536
8537   // Add an accessor to proto that's accessible by cross-domain JS code.
8538   proto_template->SetAccessor(v8_str("accessible"),
8539                               ConstTenGetter, 0,
8540                               v8::Handle<Value>(),
8541                               v8::ALL_CAN_READ);
8542
8543   // Add an accessor that is not accessible by cross-domain JS code.
8544   global_template->SetAccessor(v8_str("unreachable"),
8545                                UnreachableGetter, 0,
8546                                v8::Handle<Value>(),
8547                                v8::DEFAULT);
8548
8549   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8550   context0->Enter();
8551
8552   Local<v8::Object> global = context0->Global();
8553   // Add a normal property that shadows 'accessible'
8554   global->Set(v8_str("accessible"), v8_num(11));
8555
8556   // Enter a new context.
8557   v8::HandleScope scope1(v8::Isolate::GetCurrent());
8558   v8::Local<Context> context1 = Context::New(isolate);
8559   context1->Enter();
8560
8561   v8::Handle<v8::Object> global1 = context1->Global();
8562   global1->Set(v8_str("other"), global);
8563
8564   // Should return 10, instead of 11
8565   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8566   CHECK(value->IsNumber());
8567   CHECK_EQ(10, value->Int32Value());
8568
8569   value = v8_compile("other.unreachable")->Run();
8570   CHECK(value->IsUndefined());
8571
8572   context1->Exit();
8573   context0->Exit();
8574 }
8575
8576
8577 static int named_access_count = 0;
8578 static int indexed_access_count = 0;
8579
8580 static bool NamedAccessCounter(Local<v8::Object> global,
8581                                Local<Value> name,
8582                                v8::AccessType type,
8583                                Local<Value> data) {
8584   named_access_count++;
8585   return true;
8586 }
8587
8588
8589 static bool IndexedAccessCounter(Local<v8::Object> global,
8590                                  uint32_t key,
8591                                  v8::AccessType type,
8592                                  Local<Value> data) {
8593   indexed_access_count++;
8594   return true;
8595 }
8596
8597
8598 // This one is too easily disturbed by other tests.
8599 TEST(AccessControlIC) {
8600   named_access_count = 0;
8601   indexed_access_count = 0;
8602
8603   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8604   v8::HandleScope handle_scope(isolate);
8605
8606   // Create an environment.
8607   v8::Local<Context> context0 = Context::New(isolate);
8608   context0->Enter();
8609
8610   // Create an object that requires access-check functions to be
8611   // called for cross-domain access.
8612   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8613   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
8614                                            IndexedAccessCounter);
8615   Local<v8::Object> object = object_template->NewInstance();
8616
8617   v8::HandleScope scope1(isolate);
8618
8619   // Create another environment.
8620   v8::Local<Context> context1 = Context::New(isolate);
8621   context1->Enter();
8622
8623   // Make easy access to the object from the other environment.
8624   v8::Handle<v8::Object> global1 = context1->Global();
8625   global1->Set(v8_str("obj"), object);
8626
8627   v8::Handle<Value> value;
8628
8629   // Check that the named access-control function is called every time.
8630   CompileRun("function testProp(obj) {"
8631              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
8632              "  for (var j = 0; j < 10; j++) obj.prop;"
8633              "  return obj.prop"
8634              "}");
8635   value = CompileRun("testProp(obj)");
8636   CHECK(value->IsNumber());
8637   CHECK_EQ(1, value->Int32Value());
8638   CHECK_EQ(21, named_access_count);
8639
8640   // Check that the named access-control function is called every time.
8641   CompileRun("var p = 'prop';"
8642              "function testKeyed(obj) {"
8643              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
8644              "  for (var j = 0; j < 10; j++) obj[p];"
8645              "  return obj[p];"
8646              "}");
8647   // Use obj which requires access checks.  No inline caching is used
8648   // in that case.
8649   value = CompileRun("testKeyed(obj)");
8650   CHECK(value->IsNumber());
8651   CHECK_EQ(1, value->Int32Value());
8652   CHECK_EQ(42, named_access_count);
8653   // Force the inline caches into generic state and try again.
8654   CompileRun("testKeyed({ a: 0 })");
8655   CompileRun("testKeyed({ b: 0 })");
8656   value = CompileRun("testKeyed(obj)");
8657   CHECK(value->IsNumber());
8658   CHECK_EQ(1, value->Int32Value());
8659   CHECK_EQ(63, named_access_count);
8660
8661   // Check that the indexed access-control function is called every time.
8662   CompileRun("function testIndexed(obj) {"
8663              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
8664              "  for (var j = 0; j < 10; j++) obj[0];"
8665              "  return obj[0]"
8666              "}");
8667   value = CompileRun("testIndexed(obj)");
8668   CHECK(value->IsNumber());
8669   CHECK_EQ(1, value->Int32Value());
8670   CHECK_EQ(21, indexed_access_count);
8671   // Force the inline caches into generic state.
8672   CompileRun("testIndexed(new Array(1))");
8673   // Test that the indexed access check is called.
8674   value = CompileRun("testIndexed(obj)");
8675   CHECK(value->IsNumber());
8676   CHECK_EQ(1, value->Int32Value());
8677   CHECK_EQ(42, indexed_access_count);
8678
8679   // Check that the named access check is called when invoking
8680   // functions on an object that requires access checks.
8681   CompileRun("obj.f = function() {}");
8682   CompileRun("function testCallNormal(obj) {"
8683              "  for (var i = 0; i < 10; i++) obj.f();"
8684              "}");
8685   CompileRun("testCallNormal(obj)");
8686   CHECK_EQ(74, named_access_count);
8687
8688   // Force obj into slow case.
8689   value = CompileRun("delete obj.prop");
8690   CHECK(value->BooleanValue());
8691   // Force inline caches into dictionary probing mode.
8692   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
8693   // Test that the named access check is called.
8694   value = CompileRun("testProp(obj);");
8695   CHECK(value->IsNumber());
8696   CHECK_EQ(1, value->Int32Value());
8697   CHECK_EQ(96, named_access_count);
8698
8699   // Force the call inline cache into dictionary probing mode.
8700   CompileRun("o.f = function() {}; testCallNormal(o)");
8701   // Test that the named access check is still called for each
8702   // invocation of the function.
8703   value = CompileRun("testCallNormal(obj)");
8704   CHECK_EQ(106, named_access_count);
8705
8706   context1->Exit();
8707   context0->Exit();
8708 }
8709
8710
8711 static bool NamedAccessFlatten(Local<v8::Object> global,
8712                                Local<Value> name,
8713                                v8::AccessType type,
8714                                Local<Value> data) {
8715   char buf[100];
8716   int len;
8717
8718   CHECK(name->IsString());
8719
8720   memset(buf, 0x1, sizeof(buf));
8721   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8722   CHECK_EQ(4, len);
8723
8724   uint16_t buf2[100];
8725
8726   memset(buf, 0x1, sizeof(buf));
8727   len = name.As<String>()->Write(buf2);
8728   CHECK_EQ(4, len);
8729
8730   return true;
8731 }
8732
8733
8734 static bool IndexedAccessFlatten(Local<v8::Object> global,
8735                                  uint32_t key,
8736                                  v8::AccessType type,
8737                                  Local<Value> data) {
8738   return true;
8739 }
8740
8741
8742 // Regression test.  In access checks, operations that may cause
8743 // garbage collection are not allowed.  It used to be the case that
8744 // using the Write operation on a string could cause a garbage
8745 // collection due to flattening of the string.  This is no longer the
8746 // case.
8747 THREADED_TEST(AccessControlFlatten) {
8748   named_access_count = 0;
8749   indexed_access_count = 0;
8750
8751   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8752   v8::HandleScope handle_scope(isolate);
8753
8754   // Create an environment.
8755   v8::Local<Context> context0 = Context::New(isolate);
8756   context0->Enter();
8757
8758   // Create an object that requires access-check functions to be
8759   // called for cross-domain access.
8760   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8761   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
8762                                            IndexedAccessFlatten);
8763   Local<v8::Object> object = object_template->NewInstance();
8764
8765   v8::HandleScope scope1(isolate);
8766
8767   // Create another environment.
8768   v8::Local<Context> context1 = Context::New(isolate);
8769   context1->Enter();
8770
8771   // Make easy access to the object from the other environment.
8772   v8::Handle<v8::Object> global1 = context1->Global();
8773   global1->Set(v8_str("obj"), object);
8774
8775   v8::Handle<Value> value;
8776
8777   value = v8_compile("var p = 'as' + 'df';")->Run();
8778   value = v8_compile("obj[p];")->Run();
8779
8780   context1->Exit();
8781   context0->Exit();
8782 }
8783
8784
8785 static void AccessControlNamedGetter(
8786     Local<String>,
8787     const v8::PropertyCallbackInfo<v8::Value>& info) {
8788   info.GetReturnValue().Set(42);
8789 }
8790
8791
8792 static void AccessControlNamedSetter(
8793     Local<String>,
8794     Local<Value> value,
8795     const v8::PropertyCallbackInfo<v8::Value>& info) {
8796   info.GetReturnValue().Set(value);
8797 }
8798
8799
8800 static void AccessControlIndexedGetter(
8801       uint32_t index,
8802       const v8::PropertyCallbackInfo<v8::Value>& info) {
8803   info.GetReturnValue().Set(v8_num(42));
8804 }
8805
8806
8807 static void AccessControlIndexedSetter(
8808     uint32_t,
8809     Local<Value> value,
8810     const v8::PropertyCallbackInfo<v8::Value>& info) {
8811   info.GetReturnValue().Set(value);
8812 }
8813
8814
8815 THREADED_TEST(AccessControlInterceptorIC) {
8816   named_access_count = 0;
8817   indexed_access_count = 0;
8818
8819   v8::Isolate* isolate = v8::Isolate::GetCurrent();
8820   v8::HandleScope handle_scope(isolate);
8821
8822   // Create an environment.
8823   v8::Local<Context> context0 = Context::New(isolate);
8824   context0->Enter();
8825
8826   // Create an object that requires access-check functions to be
8827   // called for cross-domain access.  The object also has interceptors
8828   // interceptor.
8829   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8830   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
8831                                            IndexedAccessCounter);
8832   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
8833                                            AccessControlNamedSetter);
8834   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
8835                                              AccessControlIndexedSetter);
8836   Local<v8::Object> object = object_template->NewInstance();
8837
8838   v8::HandleScope scope1(isolate);
8839
8840   // Create another environment.
8841   v8::Local<Context> context1 = Context::New(isolate);
8842   context1->Enter();
8843
8844   // Make easy access to the object from the other environment.
8845   v8::Handle<v8::Object> global1 = context1->Global();
8846   global1->Set(v8_str("obj"), object);
8847
8848   v8::Handle<Value> value;
8849
8850   // Check that the named access-control function is called every time
8851   // eventhough there is an interceptor on the object.
8852   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
8853   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
8854                      "obj.x")->Run();
8855   CHECK(value->IsNumber());
8856   CHECK_EQ(42, value->Int32Value());
8857   CHECK_EQ(21, named_access_count);
8858
8859   value = v8_compile("var p = 'x';")->Run();
8860   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
8861   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
8862                      "obj[p]")->Run();
8863   CHECK(value->IsNumber());
8864   CHECK_EQ(42, value->Int32Value());
8865   CHECK_EQ(42, named_access_count);
8866
8867   // Check that the indexed access-control function is called every
8868   // time eventhough there is an interceptor on the object.
8869   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
8870   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
8871                      "obj[0]")->Run();
8872   CHECK(value->IsNumber());
8873   CHECK_EQ(42, value->Int32Value());
8874   CHECK_EQ(21, indexed_access_count);
8875
8876   context1->Exit();
8877   context0->Exit();
8878 }
8879
8880
8881 THREADED_TEST(Version) {
8882   v8::V8::GetVersion();
8883 }
8884
8885
8886 static void InstanceFunctionCallback(
8887     const v8::FunctionCallbackInfo<v8::Value>& args) {
8888   ApiTestFuzzer::Fuzz();
8889   args.GetReturnValue().Set(v8_num(12));
8890 }
8891
8892
8893 THREADED_TEST(InstanceProperties) {
8894   LocalContext context;
8895   v8::HandleScope handle_scope(context->GetIsolate());
8896
8897   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8898   Local<ObjectTemplate> instance = t->InstanceTemplate();
8899
8900   instance->Set(v8_str("x"), v8_num(42));
8901   instance->Set(v8_str("f"),
8902                 v8::FunctionTemplate::New(InstanceFunctionCallback));
8903
8904   Local<Value> o = t->GetFunction()->NewInstance();
8905
8906   context->Global()->Set(v8_str("i"), o);
8907   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
8908   CHECK_EQ(42, value->Int32Value());
8909
8910   value = Script::Compile(v8_str("i.f()"))->Run();
8911   CHECK_EQ(12, value->Int32Value());
8912 }
8913
8914
8915 static void GlobalObjectInstancePropertiesGet(
8916     Local<String> key,
8917     const v8::PropertyCallbackInfo<v8::Value>&) {
8918   ApiTestFuzzer::Fuzz();
8919 }
8920
8921
8922 THREADED_TEST(GlobalObjectInstanceProperties) {
8923   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8924
8925   Local<Value> global_object;
8926
8927   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8928   t->InstanceTemplate()->SetNamedPropertyHandler(
8929       GlobalObjectInstancePropertiesGet);
8930   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8931   instance_template->Set(v8_str("x"), v8_num(42));
8932   instance_template->Set(v8_str("f"),
8933                          v8::FunctionTemplate::New(InstanceFunctionCallback));
8934
8935   // The script to check how Crankshaft compiles missing global function
8936   // invocations.  function g is not defined and should throw on call.
8937   const char* script =
8938       "function wrapper(call) {"
8939       "  var x = 0, y = 1;"
8940       "  for (var i = 0; i < 1000; i++) {"
8941       "    x += i * 100;"
8942       "    y += i * 100;"
8943       "  }"
8944       "  if (call) g();"
8945       "}"
8946       "for (var i = 0; i < 17; i++) wrapper(false);"
8947       "var thrown = 0;"
8948       "try { wrapper(true); } catch (e) { thrown = 1; };"
8949       "thrown";
8950
8951   {
8952     LocalContext env(NULL, instance_template);
8953     // Hold on to the global object so it can be used again in another
8954     // environment initialization.
8955     global_object = env->Global();
8956
8957     Local<Value> value = Script::Compile(v8_str("x"))->Run();
8958     CHECK_EQ(42, value->Int32Value());
8959     value = Script::Compile(v8_str("f()"))->Run();
8960     CHECK_EQ(12, value->Int32Value());
8961     value = Script::Compile(v8_str(script))->Run();
8962     CHECK_EQ(1, value->Int32Value());
8963   }
8964
8965   {
8966     // Create new environment reusing the global object.
8967     LocalContext env(NULL, instance_template, global_object);
8968     Local<Value> value = Script::Compile(v8_str("x"))->Run();
8969     CHECK_EQ(42, value->Int32Value());
8970     value = Script::Compile(v8_str("f()"))->Run();
8971     CHECK_EQ(12, value->Int32Value());
8972     value = Script::Compile(v8_str(script))->Run();
8973     CHECK_EQ(1, value->Int32Value());
8974   }
8975 }
8976
8977
8978 THREADED_TEST(CallKnownGlobalReceiver) {
8979   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8980
8981   Local<Value> global_object;
8982
8983   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8984   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8985
8986   // The script to check that we leave global object not
8987   // global object proxy on stack when we deoptimize from inside
8988   // arguments evaluation.
8989   // To provoke error we need to both force deoptimization
8990   // from arguments evaluation and to force CallIC to take
8991   // CallIC_Miss code path that can't cope with global proxy.
8992   const char* script =
8993       "function bar(x, y) { try { } finally { } }"
8994       "function baz(x) { try { } finally { } }"
8995       "function bom(x) { try { } finally { } }"
8996       "function foo(x) { bar([x], bom(2)); }"
8997       "for (var i = 0; i < 10000; i++) foo(1);"
8998       "foo";
8999
9000   Local<Value> foo;
9001   {
9002     LocalContext env(NULL, instance_template);
9003     // Hold on to the global object so it can be used again in another
9004     // environment initialization.
9005     global_object = env->Global();
9006     foo = Script::Compile(v8_str(script))->Run();
9007   }
9008
9009   {
9010     // Create new environment reusing the global object.
9011     LocalContext env(NULL, instance_template, global_object);
9012     env->Global()->Set(v8_str("foo"), foo);
9013     Script::Compile(v8_str("foo()"))->Run();
9014   }
9015 }
9016
9017
9018 static void ShadowFunctionCallback(
9019     const v8::FunctionCallbackInfo<v8::Value>& args) {
9020   ApiTestFuzzer::Fuzz();
9021   args.GetReturnValue().Set(v8_num(42));
9022 }
9023
9024
9025 static int shadow_y;
9026 static int shadow_y_setter_call_count;
9027 static int shadow_y_getter_call_count;
9028
9029
9030 static void ShadowYSetter(Local<String>,
9031                           Local<Value>,
9032                           const v8::PropertyCallbackInfo<void>&) {
9033   shadow_y_setter_call_count++;
9034   shadow_y = 42;
9035 }
9036
9037
9038 static void ShadowYGetter(Local<String> name,
9039                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9040   ApiTestFuzzer::Fuzz();
9041   shadow_y_getter_call_count++;
9042   info.GetReturnValue().Set(v8_num(shadow_y));
9043 }
9044
9045
9046 static void ShadowIndexedGet(uint32_t index,
9047                              const v8::PropertyCallbackInfo<v8::Value>&) {
9048 }
9049
9050
9051 static void ShadowNamedGet(Local<String> key,
9052                            const v8::PropertyCallbackInfo<v8::Value>&) {
9053 }
9054
9055
9056 THREADED_TEST(ShadowObject) {
9057   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9058   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
9059
9060   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
9061   LocalContext context(NULL, global_template);
9062
9063   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9064   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9065   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9066   Local<ObjectTemplate> proto = t->PrototypeTemplate();
9067   Local<ObjectTemplate> instance = t->InstanceTemplate();
9068
9069   proto->Set(v8_str("f"),
9070              v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
9071   proto->Set(v8_str("x"), v8_num(12));
9072
9073   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9074
9075   Local<Value> o = t->GetFunction()->NewInstance();
9076   context->Global()->Set(v8_str("__proto__"), o);
9077
9078   Local<Value> value =
9079       Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9080   CHECK(value->IsBoolean());
9081   CHECK(!value->BooleanValue());
9082
9083   value = Script::Compile(v8_str("x"))->Run();
9084   CHECK_EQ(12, value->Int32Value());
9085
9086   value = Script::Compile(v8_str("f()"))->Run();
9087   CHECK_EQ(42, value->Int32Value());
9088
9089   Script::Compile(v8_str("y = 43"))->Run();
9090   CHECK_EQ(1, shadow_y_setter_call_count);
9091   value = Script::Compile(v8_str("y"))->Run();
9092   CHECK_EQ(1, shadow_y_getter_call_count);
9093   CHECK_EQ(42, value->Int32Value());
9094 }
9095
9096
9097 THREADED_TEST(HiddenPrototype) {
9098   LocalContext context;
9099   v8::HandleScope handle_scope(context->GetIsolate());
9100
9101   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9102   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9103   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9104   t1->SetHiddenPrototype(true);
9105   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9106   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9107   t2->SetHiddenPrototype(true);
9108   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9109   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9110   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9111
9112   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9113   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9114   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9115   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9116
9117   // Setting the prototype on an object skips hidden prototypes.
9118   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9119   o0->Set(v8_str("__proto__"), o1);
9120   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9121   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9122   o0->Set(v8_str("__proto__"), o2);
9123   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9124   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9125   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9126   o0->Set(v8_str("__proto__"), o3);
9127   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9128   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9129   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9130   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9131
9132   // Getting the prototype of o0 should get the first visible one
9133   // which is o3.  Therefore, z should not be defined on the prototype
9134   // object.
9135   Local<Value> proto = o0->Get(v8_str("__proto__"));
9136   CHECK(proto->IsObject());
9137   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9138 }
9139
9140
9141 THREADED_TEST(HiddenPrototypeSet) {
9142   LocalContext context;
9143   v8::HandleScope handle_scope(context->GetIsolate());
9144
9145   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
9146   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
9147   ht->SetHiddenPrototype(true);
9148   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
9149   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9150
9151   Local<v8::Object> o = ot->GetFunction()->NewInstance();
9152   Local<v8::Object> h = ht->GetFunction()->NewInstance();
9153   Local<v8::Object> p = pt->GetFunction()->NewInstance();
9154   o->Set(v8_str("__proto__"), h);
9155   h->Set(v8_str("__proto__"), p);
9156
9157   // Setting a property that exists on the hidden prototype goes there.
9158   o->Set(v8_str("x"), v8_num(7));
9159   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9160   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9161   CHECK(p->Get(v8_str("x"))->IsUndefined());
9162
9163   // Setting a new property should not be forwarded to the hidden prototype.
9164   o->Set(v8_str("y"), v8_num(6));
9165   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9166   CHECK(h->Get(v8_str("y"))->IsUndefined());
9167   CHECK(p->Get(v8_str("y"))->IsUndefined());
9168
9169   // Setting a property that only exists on a prototype of the hidden prototype
9170   // is treated normally again.
9171   p->Set(v8_str("z"), v8_num(8));
9172   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9173   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9174   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9175   o->Set(v8_str("z"), v8_num(9));
9176   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9177   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9178   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9179 }
9180
9181
9182 // Regression test for issue 2457.
9183 THREADED_TEST(HiddenPrototypeIdentityHash) {
9184   LocalContext context;
9185   v8::HandleScope handle_scope(context->GetIsolate());
9186
9187   Handle<FunctionTemplate> t = FunctionTemplate::New();
9188   t->SetHiddenPrototype(true);
9189   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9190   Handle<Object> p = t->GetFunction()->NewInstance();
9191   Handle<Object> o = Object::New();
9192   o->SetPrototype(p);
9193
9194   int hash = o->GetIdentityHash();
9195   USE(hash);
9196   o->Set(v8_str("foo"), v8_num(42));
9197   ASSERT_EQ(hash, o->GetIdentityHash());
9198 }
9199
9200
9201 THREADED_TEST(SetPrototype) {
9202   LocalContext context;
9203   v8::HandleScope handle_scope(context->GetIsolate());
9204
9205   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9206   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9207   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9208   t1->SetHiddenPrototype(true);
9209   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9210   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9211   t2->SetHiddenPrototype(true);
9212   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9213   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9214   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9215
9216   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9217   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9218   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9219   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9220
9221   // Setting the prototype on an object does not skip hidden prototypes.
9222   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9223   CHECK(o0->SetPrototype(o1));
9224   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9225   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9226   CHECK(o1->SetPrototype(o2));
9227   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9228   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9229   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9230   CHECK(o2->SetPrototype(o3));
9231   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9232   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9233   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9234   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9235
9236   // Getting the prototype of o0 should get the first visible one
9237   // which is o3.  Therefore, z should not be defined on the prototype
9238   // object.
9239   Local<Value> proto = o0->Get(v8_str("__proto__"));
9240   CHECK(proto->IsObject());
9241   CHECK_EQ(proto.As<v8::Object>(), o3);
9242
9243   // However, Object::GetPrototype ignores hidden prototype.
9244   Local<Value> proto0 = o0->GetPrototype();
9245   CHECK(proto0->IsObject());
9246   CHECK_EQ(proto0.As<v8::Object>(), o1);
9247
9248   Local<Value> proto1 = o1->GetPrototype();
9249   CHECK(proto1->IsObject());
9250   CHECK_EQ(proto1.As<v8::Object>(), o2);
9251
9252   Local<Value> proto2 = o2->GetPrototype();
9253   CHECK(proto2->IsObject());
9254   CHECK_EQ(proto2.As<v8::Object>(), o3);
9255 }
9256
9257
9258 // Getting property names of an object with a prototype chain that
9259 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
9260 // crash the runtime.
9261 THREADED_TEST(Regress91517) {
9262   i::FLAG_allow_natives_syntax = true;
9263   LocalContext context;
9264   v8::HandleScope handle_scope(context->GetIsolate());
9265
9266   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9267   t1->SetHiddenPrototype(true);
9268   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9269   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9270   t2->SetHiddenPrototype(true);
9271   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9272   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
9273   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9274   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9275   t3->SetHiddenPrototype(true);
9276   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9277   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
9278   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9279
9280   // Force dictionary-based properties.
9281   i::ScopedVector<char> name_buf(1024);
9282   for (int i = 1; i <= 1000; i++) {
9283     i::OS::SNPrintF(name_buf, "sdf%d", i);
9284     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9285   }
9286
9287   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9288   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9289   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9290   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9291
9292   // Create prototype chain of hidden prototypes.
9293   CHECK(o4->SetPrototype(o3));
9294   CHECK(o3->SetPrototype(o2));
9295   CHECK(o2->SetPrototype(o1));
9296
9297   // Call the runtime version of GetLocalPropertyNames() on the natively
9298   // created object through JavaScript.
9299   context->Global()->Set(v8_str("obj"), o4);
9300   CompileRun("var names = %GetLocalPropertyNames(obj, true);");
9301
9302   ExpectInt32("names.length", 1006);
9303   ExpectTrue("names.indexOf(\"baz\") >= 0");
9304   ExpectTrue("names.indexOf(\"boo\") >= 0");
9305   ExpectTrue("names.indexOf(\"foo\") >= 0");
9306   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9307   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9308   ExpectFalse("names[1005] == undefined");
9309 }
9310
9311
9312 THREADED_TEST(FunctionReadOnlyPrototype) {
9313   LocalContext context;
9314   v8::HandleScope handle_scope(context->GetIsolate());
9315
9316   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9317   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9318   t1->ReadOnlyPrototype();
9319   context->Global()->Set(v8_str("func1"), t1->GetFunction());
9320   // Configured value of ReadOnly flag.
9321   CHECK(CompileRun(
9322       "(function() {"
9323       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9324       "  return (descriptor['writable'] == false);"
9325       "})()")->BooleanValue());
9326   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9327   CHECK_EQ(42,
9328            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9329
9330   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9331   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9332   context->Global()->Set(v8_str("func2"), t2->GetFunction());
9333   // Default value of ReadOnly flag.
9334   CHECK(CompileRun(
9335       "(function() {"
9336       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9337       "  return (descriptor['writable'] == true);"
9338       "})()")->BooleanValue());
9339   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9340 }
9341
9342
9343 THREADED_TEST(SetPrototypeThrows) {
9344   LocalContext context;
9345   v8::HandleScope handle_scope(context->GetIsolate());
9346
9347   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9348
9349   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9350   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9351
9352   CHECK(o0->SetPrototype(o1));
9353   // If setting the prototype leads to the cycle, SetPrototype should
9354   // return false and keep VM in sane state.
9355   v8::TryCatch try_catch;
9356   CHECK(!o1->SetPrototype(o0));
9357   CHECK(!try_catch.HasCaught());
9358   ASSERT(!i::Isolate::Current()->has_pending_exception());
9359
9360   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9361 }
9362
9363
9364 THREADED_TEST(GetterSetterExceptions) {
9365   LocalContext context;
9366   v8::HandleScope handle_scope(context->GetIsolate());
9367   CompileRun(
9368     "function Foo() { };"
9369     "function Throw() { throw 5; };"
9370     "var x = { };"
9371     "x.__defineSetter__('set', Throw);"
9372     "x.__defineGetter__('get', Throw);");
9373   Local<v8::Object> x =
9374       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9375   v8::TryCatch try_catch;
9376   x->Set(v8_str("set"), v8::Integer::New(8));
9377   x->Get(v8_str("get"));
9378   x->Set(v8_str("set"), v8::Integer::New(8));
9379   x->Get(v8_str("get"));
9380   x->Set(v8_str("set"), v8::Integer::New(8));
9381   x->Get(v8_str("get"));
9382   x->Set(v8_str("set"), v8::Integer::New(8));
9383   x->Get(v8_str("get"));
9384 }
9385
9386
9387 THREADED_TEST(Constructor) {
9388   LocalContext context;
9389   v8::HandleScope handle_scope(context->GetIsolate());
9390   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9391   templ->SetClassName(v8_str("Fun"));
9392   Local<Function> cons = templ->GetFunction();
9393   context->Global()->Set(v8_str("Fun"), cons);
9394   Local<v8::Object> inst = cons->NewInstance();
9395   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9396   CHECK(obj->IsJSObject());
9397   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9398   CHECK(value->BooleanValue());
9399 }
9400
9401
9402 static void ConstructorCallback(
9403     const v8::FunctionCallbackInfo<v8::Value>& args) {
9404   ApiTestFuzzer::Fuzz();
9405   Local<Object> This;
9406
9407   if (args.IsConstructCall()) {
9408     Local<Object> Holder = args.Holder();
9409     This = Object::New();
9410     Local<Value> proto = Holder->GetPrototype();
9411     if (proto->IsObject()) {
9412       This->SetPrototype(proto);
9413     }
9414   } else {
9415     This = args.This();
9416   }
9417
9418   This->Set(v8_str("a"), args[0]);
9419   args.GetReturnValue().Set(This);
9420 }
9421
9422
9423 static void FakeConstructorCallback(
9424     const v8::FunctionCallbackInfo<v8::Value>& args) {
9425   ApiTestFuzzer::Fuzz();
9426   args.GetReturnValue().Set(args[0]);
9427 }
9428
9429
9430 THREADED_TEST(ConstructorForObject) {
9431   LocalContext context;
9432   v8::HandleScope handle_scope(context->GetIsolate());
9433
9434   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9435     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9436     Local<Object> instance = instance_template->NewInstance();
9437     context->Global()->Set(v8_str("obj"), instance);
9438     v8::TryCatch try_catch;
9439     Local<Value> value;
9440     CHECK(!try_catch.HasCaught());
9441
9442     // Call the Object's constructor with a 32-bit signed integer.
9443     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9444     CHECK(!try_catch.HasCaught());
9445     CHECK(value->IsInt32());
9446     CHECK_EQ(28, value->Int32Value());
9447
9448     Local<Value> args1[] = { v8_num(28) };
9449     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9450     CHECK(value_obj1->IsObject());
9451     Local<Object> object1 = Local<Object>::Cast(value_obj1);
9452     value = object1->Get(v8_str("a"));
9453     CHECK(value->IsInt32());
9454     CHECK(!try_catch.HasCaught());
9455     CHECK_EQ(28, value->Int32Value());
9456
9457     // Call the Object's constructor with a String.
9458     value = CompileRun(
9459         "(function() { var o = new obj('tipli'); return o.a; })()");
9460     CHECK(!try_catch.HasCaught());
9461     CHECK(value->IsString());
9462     String::Utf8Value string_value1(value->ToString());
9463     CHECK_EQ("tipli", *string_value1);
9464
9465     Local<Value> args2[] = { v8_str("tipli") };
9466     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9467     CHECK(value_obj2->IsObject());
9468     Local<Object> object2 = Local<Object>::Cast(value_obj2);
9469     value = object2->Get(v8_str("a"));
9470     CHECK(!try_catch.HasCaught());
9471     CHECK(value->IsString());
9472     String::Utf8Value string_value2(value->ToString());
9473     CHECK_EQ("tipli", *string_value2);
9474
9475     // Call the Object's constructor with a Boolean.
9476     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9477     CHECK(!try_catch.HasCaught());
9478     CHECK(value->IsBoolean());
9479     CHECK_EQ(true, value->BooleanValue());
9480
9481     Handle<Value> args3[] = { v8::True() };
9482     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9483     CHECK(value_obj3->IsObject());
9484     Local<Object> object3 = Local<Object>::Cast(value_obj3);
9485     value = object3->Get(v8_str("a"));
9486     CHECK(!try_catch.HasCaught());
9487     CHECK(value->IsBoolean());
9488     CHECK_EQ(true, value->BooleanValue());
9489
9490     // Call the Object's constructor with undefined.
9491     Handle<Value> args4[] = { v8::Undefined() };
9492     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9493     CHECK(value_obj4->IsObject());
9494     Local<Object> object4 = Local<Object>::Cast(value_obj4);
9495     value = object4->Get(v8_str("a"));
9496     CHECK(!try_catch.HasCaught());
9497     CHECK(value->IsUndefined());
9498
9499     // Call the Object's constructor with null.
9500     Handle<Value> args5[] = { v8::Null() };
9501     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9502     CHECK(value_obj5->IsObject());
9503     Local<Object> object5 = Local<Object>::Cast(value_obj5);
9504     value = object5->Get(v8_str("a"));
9505     CHECK(!try_catch.HasCaught());
9506     CHECK(value->IsNull());
9507   }
9508
9509   // Check exception handling when there is no constructor set for the Object.
9510   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9511     Local<Object> instance = instance_template->NewInstance();
9512     context->Global()->Set(v8_str("obj2"), instance);
9513     v8::TryCatch try_catch;
9514     Local<Value> value;
9515     CHECK(!try_catch.HasCaught());
9516
9517     value = CompileRun("new obj2(28)");
9518     CHECK(try_catch.HasCaught());
9519     String::Utf8Value exception_value1(try_catch.Exception());
9520     CHECK_EQ("TypeError: object is not a function", *exception_value1);
9521     try_catch.Reset();
9522
9523     Local<Value> args[] = { v8_num(29) };
9524     value = instance->CallAsConstructor(1, args);
9525     CHECK(try_catch.HasCaught());
9526     String::Utf8Value exception_value2(try_catch.Exception());
9527     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
9528     try_catch.Reset();
9529   }
9530
9531   // Check the case when constructor throws exception.
9532   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9533     instance_template->SetCallAsFunctionHandler(ThrowValue);
9534     Local<Object> instance = instance_template->NewInstance();
9535     context->Global()->Set(v8_str("obj3"), instance);
9536     v8::TryCatch try_catch;
9537     Local<Value> value;
9538     CHECK(!try_catch.HasCaught());
9539
9540     value = CompileRun("new obj3(22)");
9541     CHECK(try_catch.HasCaught());
9542     String::Utf8Value exception_value1(try_catch.Exception());
9543     CHECK_EQ("22", *exception_value1);
9544     try_catch.Reset();
9545
9546     Local<Value> args[] = { v8_num(23) };
9547     value = instance->CallAsConstructor(1, args);
9548     CHECK(try_catch.HasCaught());
9549     String::Utf8Value exception_value2(try_catch.Exception());
9550     CHECK_EQ("23", *exception_value2);
9551     try_catch.Reset();
9552   }
9553
9554   // Check whether constructor returns with an object or non-object.
9555   { Local<FunctionTemplate> function_template =
9556         FunctionTemplate::New(FakeConstructorCallback);
9557     Local<Function> function = function_template->GetFunction();
9558     Local<Object> instance1 = function;
9559     context->Global()->Set(v8_str("obj4"), instance1);
9560     v8::TryCatch try_catch;
9561     Local<Value> value;
9562     CHECK(!try_catch.HasCaught());
9563
9564     CHECK(instance1->IsObject());
9565     CHECK(instance1->IsFunction());
9566
9567     value = CompileRun("new obj4(28)");
9568     CHECK(!try_catch.HasCaught());
9569     CHECK(value->IsObject());
9570
9571     Local<Value> args1[] = { v8_num(28) };
9572     value = instance1->CallAsConstructor(1, args1);
9573     CHECK(!try_catch.HasCaught());
9574     CHECK(value->IsObject());
9575
9576     Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9577     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9578     Local<Object> instance2 = instance_template->NewInstance();
9579     context->Global()->Set(v8_str("obj5"), instance2);
9580     CHECK(!try_catch.HasCaught());
9581
9582     CHECK(instance2->IsObject());
9583     CHECK(!instance2->IsFunction());
9584
9585     value = CompileRun("new obj5(28)");
9586     CHECK(!try_catch.HasCaught());
9587     CHECK(!value->IsObject());
9588
9589     Local<Value> args2[] = { v8_num(28) };
9590     value = instance2->CallAsConstructor(1, args2);
9591     CHECK(!try_catch.HasCaught());
9592     CHECK(!value->IsObject());
9593   }
9594 }
9595
9596
9597 THREADED_TEST(FunctionDescriptorException) {
9598   LocalContext context;
9599   v8::HandleScope handle_scope(context->GetIsolate());
9600   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9601   templ->SetClassName(v8_str("Fun"));
9602   Local<Function> cons = templ->GetFunction();
9603   context->Global()->Set(v8_str("Fun"), cons);
9604   Local<Value> value = CompileRun(
9605     "function test() {"
9606     "  try {"
9607     "    (new Fun()).blah()"
9608     "  } catch (e) {"
9609     "    var str = String(e);"
9610     "    if (str.indexOf('TypeError') == -1) return 1;"
9611     "    if (str.indexOf('[object Fun]') != -1) return 2;"
9612     "    if (str.indexOf('#<Fun>') == -1) return 3;"
9613     "    return 0;"
9614     "  }"
9615     "  return 4;"
9616     "}"
9617     "test();");
9618   CHECK_EQ(0, value->Int32Value());
9619 }
9620
9621
9622 THREADED_TEST(EvalAliasedDynamic) {
9623   LocalContext current;
9624   v8::HandleScope scope(current->GetIsolate());
9625
9626   // Tests where aliased eval can only be resolved dynamically.
9627   Local<Script> script =
9628       Script::Compile(v8_str("function f(x) { "
9629                              "  var foo = 2;"
9630                              "  with (x) { return eval('foo'); }"
9631                              "}"
9632                              "foo = 0;"
9633                              "result1 = f(new Object());"
9634                              "result2 = f(this);"
9635                              "var x = new Object();"
9636                              "x.eval = function(x) { return 1; };"
9637                              "result3 = f(x);"));
9638   script->Run();
9639   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9640   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9641   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9642
9643   v8::TryCatch try_catch;
9644   script =
9645     Script::Compile(v8_str("function f(x) { "
9646                            "  var bar = 2;"
9647                            "  with (x) { return eval('bar'); }"
9648                            "}"
9649                            "result4 = f(this)"));
9650   script->Run();
9651   CHECK(!try_catch.HasCaught());
9652   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9653
9654   try_catch.Reset();
9655 }
9656
9657
9658 THREADED_TEST(CrossEval) {
9659   v8::HandleScope scope(v8::Isolate::GetCurrent());
9660   LocalContext other;
9661   LocalContext current;
9662
9663   Local<String> token = v8_str("<security token>");
9664   other->SetSecurityToken(token);
9665   current->SetSecurityToken(token);
9666
9667   // Set up reference from current to other.
9668   current->Global()->Set(v8_str("other"), other->Global());
9669
9670   // Check that new variables are introduced in other context.
9671   Local<Script> script =
9672       Script::Compile(v8_str("other.eval('var foo = 1234')"));
9673   script->Run();
9674   Local<Value> foo = other->Global()->Get(v8_str("foo"));
9675   CHECK_EQ(1234, foo->Int32Value());
9676   CHECK(!current->Global()->Has(v8_str("foo")));
9677
9678   // Check that writing to non-existing properties introduces them in
9679   // the other context.
9680   script =
9681       Script::Compile(v8_str("other.eval('na = 1234')"));
9682   script->Run();
9683   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9684   CHECK(!current->Global()->Has(v8_str("na")));
9685
9686   // Check that global variables in current context are not visible in other
9687   // context.
9688   v8::TryCatch try_catch;
9689   script =
9690       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
9691   Local<Value> result = script->Run();
9692   CHECK(try_catch.HasCaught());
9693   try_catch.Reset();
9694
9695   // Check that local variables in current context are not visible in other
9696   // context.
9697   script =
9698       Script::Compile(v8_str("(function() { "
9699                              "  var baz = 87;"
9700                              "  return other.eval('baz');"
9701                              "})();"));
9702   result = script->Run();
9703   CHECK(try_catch.HasCaught());
9704   try_catch.Reset();
9705
9706   // Check that global variables in the other environment are visible
9707   // when evaluting code.
9708   other->Global()->Set(v8_str("bis"), v8_num(1234));
9709   script = Script::Compile(v8_str("other.eval('bis')"));
9710   CHECK_EQ(1234, script->Run()->Int32Value());
9711   CHECK(!try_catch.HasCaught());
9712
9713   // Check that the 'this' pointer points to the global object evaluating
9714   // code.
9715   other->Global()->Set(v8_str("t"), other->Global());
9716   script = Script::Compile(v8_str("other.eval('this == t')"));
9717   result = script->Run();
9718   CHECK(result->IsTrue());
9719   CHECK(!try_catch.HasCaught());
9720
9721   // Check that variables introduced in with-statement are not visible in
9722   // other context.
9723   script =
9724       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
9725   result = script->Run();
9726   CHECK(try_catch.HasCaught());
9727   try_catch.Reset();
9728
9729   // Check that you cannot use 'eval.call' with another object than the
9730   // current global object.
9731   script =
9732       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
9733   result = script->Run();
9734   CHECK(try_catch.HasCaught());
9735 }
9736
9737
9738 // Test that calling eval in a context which has been detached from
9739 // its global throws an exception.  This behavior is consistent with
9740 // other JavaScript implementations.
9741 THREADED_TEST(EvalInDetachedGlobal) {
9742   v8::Isolate* isolate = v8::Isolate::GetCurrent();
9743   v8::HandleScope scope(isolate);
9744
9745   v8::Local<Context> context0 = Context::New(isolate);
9746   v8::Local<Context> context1 = Context::New(isolate);
9747
9748   // Set up function in context0 that uses eval from context0.
9749   context0->Enter();
9750   v8::Handle<v8::Value> fun =
9751       CompileRun("var x = 42;"
9752                  "(function() {"
9753                  "  var e = eval;"
9754                  "  return function(s) { return e(s); }"
9755                  "})()");
9756   context0->Exit();
9757
9758   // Put the function into context1 and call it before and after
9759   // detaching the global.  Before detaching, the call succeeds and
9760   // after detaching and exception is thrown.
9761   context1->Enter();
9762   context1->Global()->Set(v8_str("fun"), fun);
9763   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
9764   CHECK_EQ(42, x_value->Int32Value());
9765   context0->DetachGlobal();
9766   v8::TryCatch catcher;
9767   x_value = CompileRun("fun('x')");
9768   CHECK(x_value.IsEmpty());
9769   CHECK(catcher.HasCaught());
9770   context1->Exit();
9771 }
9772
9773
9774 THREADED_TEST(CrossLazyLoad) {
9775   v8::HandleScope scope(v8::Isolate::GetCurrent());
9776   LocalContext other;
9777   LocalContext current;
9778
9779   Local<String> token = v8_str("<security token>");
9780   other->SetSecurityToken(token);
9781   current->SetSecurityToken(token);
9782
9783   // Set up reference from current to other.
9784   current->Global()->Set(v8_str("other"), other->Global());
9785
9786   // Trigger lazy loading in other context.
9787   Local<Script> script =
9788       Script::Compile(v8_str("other.eval('new Date(42)')"));
9789   Local<Value> value = script->Run();
9790   CHECK_EQ(42.0, value->NumberValue());
9791 }
9792
9793
9794 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
9795   ApiTestFuzzer::Fuzz();
9796   if (args.IsConstructCall()) {
9797     if (args[0]->IsInt32()) {
9798       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
9799       return;
9800     }
9801   }
9802
9803   args.GetReturnValue().Set(args[0]);
9804 }
9805
9806
9807 // Test that a call handler can be set for objects which will allow
9808 // non-function objects created through the API to be called as
9809 // functions.
9810 THREADED_TEST(CallAsFunction) {
9811   LocalContext context;
9812   v8::HandleScope scope(context->GetIsolate());
9813
9814   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9815     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9816     instance_template->SetCallAsFunctionHandler(call_as_function);
9817     Local<v8::Object> instance = t->GetFunction()->NewInstance();
9818     context->Global()->Set(v8_str("obj"), instance);
9819     v8::TryCatch try_catch;
9820     Local<Value> value;
9821     CHECK(!try_catch.HasCaught());
9822
9823     value = CompileRun("obj(42)");
9824     CHECK(!try_catch.HasCaught());
9825     CHECK_EQ(42, value->Int32Value());
9826
9827     value = CompileRun("(function(o){return o(49)})(obj)");
9828     CHECK(!try_catch.HasCaught());
9829     CHECK_EQ(49, value->Int32Value());
9830
9831     // test special case of call as function
9832     value = CompileRun("[obj]['0'](45)");
9833     CHECK(!try_catch.HasCaught());
9834     CHECK_EQ(45, value->Int32Value());
9835
9836     value = CompileRun("obj.call = Function.prototype.call;"
9837                        "obj.call(null, 87)");
9838     CHECK(!try_catch.HasCaught());
9839     CHECK_EQ(87, value->Int32Value());
9840
9841     // Regression tests for bug #1116356: Calling call through call/apply
9842     // must work for non-function receivers.
9843     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
9844     value = CompileRun(apply_99);
9845     CHECK(!try_catch.HasCaught());
9846     CHECK_EQ(99, value->Int32Value());
9847
9848     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
9849     value = CompileRun(call_17);
9850     CHECK(!try_catch.HasCaught());
9851     CHECK_EQ(17, value->Int32Value());
9852
9853     // Check that the call-as-function handler can be called through
9854     // new.
9855     value = CompileRun("new obj(43)");
9856     CHECK(!try_catch.HasCaught());
9857     CHECK_EQ(-43, value->Int32Value());
9858
9859     // Check that the call-as-function handler can be called through
9860     // the API.
9861     v8::Handle<Value> args[] = { v8_num(28) };
9862     value = instance->CallAsFunction(instance, 1, args);
9863     CHECK(!try_catch.HasCaught());
9864     CHECK_EQ(28, value->Int32Value());
9865   }
9866
9867   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9868     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
9869     USE(instance_template);
9870     Local<v8::Object> instance = t->GetFunction()->NewInstance();
9871     context->Global()->Set(v8_str("obj2"), instance);
9872     v8::TryCatch try_catch;
9873     Local<Value> value;
9874     CHECK(!try_catch.HasCaught());
9875
9876     // Call an object without call-as-function handler through the JS
9877     value = CompileRun("obj2(28)");
9878     CHECK(value.IsEmpty());
9879     CHECK(try_catch.HasCaught());
9880     String::Utf8Value exception_value1(try_catch.Exception());
9881     CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
9882              *exception_value1);
9883     try_catch.Reset();
9884
9885     // Call an object without call-as-function handler through the API
9886     value = CompileRun("obj2(28)");
9887     v8::Handle<Value> args[] = { v8_num(28) };
9888     value = instance->CallAsFunction(instance, 1, args);
9889     CHECK(value.IsEmpty());
9890     CHECK(try_catch.HasCaught());
9891     String::Utf8Value exception_value2(try_catch.Exception());
9892     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
9893     try_catch.Reset();
9894   }
9895
9896   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9897     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9898     instance_template->SetCallAsFunctionHandler(ThrowValue);
9899     Local<v8::Object> instance = t->GetFunction()->NewInstance();
9900     context->Global()->Set(v8_str("obj3"), instance);
9901     v8::TryCatch try_catch;
9902     Local<Value> value;
9903     CHECK(!try_catch.HasCaught());
9904
9905     // Catch the exception which is thrown by call-as-function handler
9906     value = CompileRun("obj3(22)");
9907     CHECK(try_catch.HasCaught());
9908     String::Utf8Value exception_value1(try_catch.Exception());
9909     CHECK_EQ("22", *exception_value1);
9910     try_catch.Reset();
9911
9912     v8::Handle<Value> args[] = { v8_num(23) };
9913     value = instance->CallAsFunction(instance, 1, args);
9914     CHECK(try_catch.HasCaught());
9915     String::Utf8Value exception_value2(try_catch.Exception());
9916     CHECK_EQ("23", *exception_value2);
9917     try_catch.Reset();
9918   }
9919 }
9920
9921
9922 // Check whether a non-function object is callable.
9923 THREADED_TEST(CallableObject) {
9924   LocalContext context;
9925   v8::HandleScope scope(context->GetIsolate());
9926
9927   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9928     instance_template->SetCallAsFunctionHandler(call_as_function);
9929     Local<Object> instance = instance_template->NewInstance();
9930     v8::TryCatch try_catch;
9931
9932     CHECK(instance->IsCallable());
9933     CHECK(!try_catch.HasCaught());
9934   }
9935
9936   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9937     Local<Object> instance = instance_template->NewInstance();
9938     v8::TryCatch try_catch;
9939
9940     CHECK(!instance->IsCallable());
9941     CHECK(!try_catch.HasCaught());
9942   }
9943
9944   { Local<FunctionTemplate> function_template =
9945         FunctionTemplate::New(call_as_function);
9946     Local<Function> function = function_template->GetFunction();
9947     Local<Object> instance = function;
9948     v8::TryCatch try_catch;
9949
9950     CHECK(instance->IsCallable());
9951     CHECK(!try_catch.HasCaught());
9952   }
9953
9954   { Local<FunctionTemplate> function_template = FunctionTemplate::New();
9955     Local<Function> function = function_template->GetFunction();
9956     Local<Object> instance = function;
9957     v8::TryCatch try_catch;
9958
9959     CHECK(instance->IsCallable());
9960     CHECK(!try_catch.HasCaught());
9961   }
9962 }
9963
9964
9965 static int CountHandles() {
9966   return v8::HandleScope::NumberOfHandles();
9967 }
9968
9969
9970 static int Recurse(int depth, int iterations) {
9971   v8::HandleScope scope(v8::Isolate::GetCurrent());
9972   if (depth == 0) return CountHandles();
9973   for (int i = 0; i < iterations; i++) {
9974     Local<v8::Number> n(v8::Integer::New(42));
9975   }
9976   return Recurse(depth - 1, iterations);
9977 }
9978
9979
9980 THREADED_TEST(HandleIteration) {
9981   static const int kIterations = 500;
9982   static const int kNesting = 200;
9983   CHECK_EQ(0, CountHandles());
9984   {
9985     v8::HandleScope scope1(v8::Isolate::GetCurrent());
9986     CHECK_EQ(0, CountHandles());
9987     for (int i = 0; i < kIterations; i++) {
9988       Local<v8::Number> n(v8::Integer::New(42));
9989       CHECK_EQ(i + 1, CountHandles());
9990     }
9991
9992     CHECK_EQ(kIterations, CountHandles());
9993     {
9994       v8::HandleScope scope2(v8::Isolate::GetCurrent());
9995       for (int j = 0; j < kIterations; j++) {
9996         Local<v8::Number> n(v8::Integer::New(42));
9997         CHECK_EQ(j + 1 + kIterations, CountHandles());
9998       }
9999     }
10000     CHECK_EQ(kIterations, CountHandles());
10001   }
10002   CHECK_EQ(0, CountHandles());
10003   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
10004 }
10005
10006
10007 static void InterceptorHasOwnPropertyGetter(
10008     Local<String> name,
10009     const v8::PropertyCallbackInfo<v8::Value>& info) {
10010   ApiTestFuzzer::Fuzz();
10011 }
10012
10013
10014 THREADED_TEST(InterceptorHasOwnProperty) {
10015   LocalContext context;
10016   v8::HandleScope scope(context->GetIsolate());
10017   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10018   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10019   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
10020   Local<Function> function = fun_templ->GetFunction();
10021   context->Global()->Set(v8_str("constructor"), function);
10022   v8::Handle<Value> value = CompileRun(
10023       "var o = new constructor();"
10024       "o.hasOwnProperty('ostehaps');");
10025   CHECK_EQ(false, value->BooleanValue());
10026   value = CompileRun(
10027       "o.ostehaps = 42;"
10028       "o.hasOwnProperty('ostehaps');");
10029   CHECK_EQ(true, value->BooleanValue());
10030   value = CompileRun(
10031       "var p = new constructor();"
10032       "p.hasOwnProperty('ostehaps');");
10033   CHECK_EQ(false, value->BooleanValue());
10034 }
10035
10036
10037 static void InterceptorHasOwnPropertyGetterGC(
10038     Local<String> name,
10039     const v8::PropertyCallbackInfo<v8::Value>& info) {
10040   ApiTestFuzzer::Fuzz();
10041   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10042 }
10043
10044
10045 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
10046   LocalContext context;
10047   v8::HandleScope scope(context->GetIsolate());
10048   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10049   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10050   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
10051   Local<Function> function = fun_templ->GetFunction();
10052   context->Global()->Set(v8_str("constructor"), function);
10053   // Let's first make some stuff so we can be sure to get a good GC.
10054   CompileRun(
10055       "function makestr(size) {"
10056       "  switch (size) {"
10057       "    case 1: return 'f';"
10058       "    case 2: return 'fo';"
10059       "    case 3: return 'foo';"
10060       "  }"
10061       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
10062       "}"
10063       "var x = makestr(12345);"
10064       "x = makestr(31415);"
10065       "x = makestr(23456);");
10066   v8::Handle<Value> value = CompileRun(
10067       "var o = new constructor();"
10068       "o.__proto__ = new String(x);"
10069       "o.hasOwnProperty('ostehaps');");
10070   CHECK_EQ(false, value->BooleanValue());
10071 }
10072
10073
10074 typedef void (*NamedPropertyGetter)(
10075     Local<String> property,
10076     const v8::PropertyCallbackInfo<v8::Value>& info);
10077
10078
10079 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
10080                                    const char* source,
10081                                    int expected) {
10082   v8::HandleScope scope(v8::Isolate::GetCurrent());
10083   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10084   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
10085   LocalContext context;
10086   context->Global()->Set(v8_str("o"), templ->NewInstance());
10087   v8::Handle<Value> value = CompileRun(source);
10088   CHECK_EQ(expected, value->Int32Value());
10089 }
10090
10091
10092 static void InterceptorLoadICGetter(
10093     Local<String> name,
10094     const v8::PropertyCallbackInfo<v8::Value>& info) {
10095   ApiTestFuzzer::Fuzz();
10096   v8::Isolate* isolate = v8::Isolate::GetCurrent();
10097   CHECK_EQ(isolate, info.GetIsolate());
10098   CHECK_EQ(v8_str("data"), info.Data());
10099   CHECK_EQ(v8_str("x"), name);
10100   info.GetReturnValue().Set(v8::Integer::New(42));
10101 }
10102
10103
10104 // This test should hit the load IC for the interceptor case.
10105 THREADED_TEST(InterceptorLoadIC) {
10106   CheckInterceptorLoadIC(InterceptorLoadICGetter,
10107     "var result = 0;"
10108     "for (var i = 0; i < 1000; i++) {"
10109     "  result = o.x;"
10110     "}",
10111     42);
10112 }
10113
10114
10115 // Below go several tests which verify that JITing for various
10116 // configurations of interceptor and explicit fields works fine
10117 // (those cases are special cased to get better performance).
10118
10119 static void InterceptorLoadXICGetter(
10120     Local<String> name,
10121     const v8::PropertyCallbackInfo<v8::Value>& info) {
10122   ApiTestFuzzer::Fuzz();
10123   info.GetReturnValue().Set(
10124       v8_str("x")->Equals(name) ?
10125           v8::Handle<v8::Value>(v8::Integer::New(42)) :
10126           v8::Handle<v8::Value>());
10127 }
10128
10129
10130 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
10131   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10132     "var result = 0;"
10133     "o.y = 239;"
10134     "for (var i = 0; i < 1000; i++) {"
10135     "  result = o.y;"
10136     "}",
10137     239);
10138 }
10139
10140
10141 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
10142   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10143     "var result = 0;"
10144     "o.__proto__ = { 'y': 239 };"
10145     "for (var i = 0; i < 1000; i++) {"
10146     "  result = o.y + o.x;"
10147     "}",
10148     239 + 42);
10149 }
10150
10151
10152 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
10153   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10154     "var result = 0;"
10155     "o.__proto__.y = 239;"
10156     "for (var i = 0; i < 1000; i++) {"
10157     "  result = o.y + o.x;"
10158     "}",
10159     239 + 42);
10160 }
10161
10162
10163 THREADED_TEST(InterceptorLoadICUndefined) {
10164   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10165     "var result = 0;"
10166     "for (var i = 0; i < 1000; i++) {"
10167     "  result = (o.y == undefined) ? 239 : 42;"
10168     "}",
10169     239);
10170 }
10171
10172
10173 THREADED_TEST(InterceptorLoadICWithOverride) {
10174   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10175     "fst = new Object();  fst.__proto__ = o;"
10176     "snd = new Object();  snd.__proto__ = fst;"
10177     "var result1 = 0;"
10178     "for (var i = 0; i < 1000;  i++) {"
10179     "  result1 = snd.x;"
10180     "}"
10181     "fst.x = 239;"
10182     "var result = 0;"
10183     "for (var i = 0; i < 1000; i++) {"
10184     "  result = snd.x;"
10185     "}"
10186     "result + result1",
10187     239 + 42);
10188 }
10189
10190
10191 // Test the case when we stored field into
10192 // a stub, but interceptor produced value on its own.
10193 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
10194   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10195     "proto = new Object();"
10196     "o.__proto__ = proto;"
10197     "proto.x = 239;"
10198     "for (var i = 0; i < 1000; i++) {"
10199     "  o.x;"
10200     // Now it should be ICed and keep a reference to x defined on proto
10201     "}"
10202     "var result = 0;"
10203     "for (var i = 0; i < 1000; i++) {"
10204     "  result += o.x;"
10205     "}"
10206     "result;",
10207     42 * 1000);
10208 }
10209
10210
10211 // Test the case when we stored field into
10212 // a stub, but it got invalidated later on.
10213 THREADED_TEST(InterceptorLoadICInvalidatedField) {
10214   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10215     "proto1 = new Object();"
10216     "proto2 = new Object();"
10217     "o.__proto__ = proto1;"
10218     "proto1.__proto__ = proto2;"
10219     "proto2.y = 239;"
10220     "for (var i = 0; i < 1000; i++) {"
10221     "  o.y;"
10222     // Now it should be ICed and keep a reference to y defined on proto2
10223     "}"
10224     "proto1.y = 42;"
10225     "var result = 0;"
10226     "for (var i = 0; i < 1000; i++) {"
10227     "  result += o.y;"
10228     "}"
10229     "result;",
10230     42 * 1000);
10231 }
10232
10233
10234 static int interceptor_load_not_handled_calls = 0;
10235 static void InterceptorLoadNotHandled(
10236     Local<String> name,
10237     const v8::PropertyCallbackInfo<v8::Value>& info) {
10238   ++interceptor_load_not_handled_calls;
10239 }
10240
10241
10242 // Test how post-interceptor lookups are done in the non-cacheable
10243 // case: the interceptor should not be invoked during this lookup.
10244 THREADED_TEST(InterceptorLoadICPostInterceptor) {
10245   interceptor_load_not_handled_calls = 0;
10246   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
10247     "receiver = new Object();"
10248     "receiver.__proto__ = o;"
10249     "proto = new Object();"
10250     "/* Make proto a slow-case object. */"
10251     "for (var i = 0; i < 1000; i++) {"
10252     "  proto[\"xxxxxxxx\" + i] = [];"
10253     "}"
10254     "proto.x = 17;"
10255     "o.__proto__ = proto;"
10256     "var result = 0;"
10257     "for (var i = 0; i < 1000; i++) {"
10258     "  result += receiver.x;"
10259     "}"
10260     "result;",
10261     17 * 1000);
10262   CHECK_EQ(1000, interceptor_load_not_handled_calls);
10263 }
10264
10265
10266 // Test the case when we stored field into
10267 // a stub, but it got invalidated later on due to override on
10268 // global object which is between interceptor and fields' holders.
10269 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
10270   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10271     "o.__proto__ = this;"  // set a global to be a proto of o.
10272     "this.__proto__.y = 239;"
10273     "for (var i = 0; i < 10; i++) {"
10274     "  if (o.y != 239) throw 'oops: ' + o.y;"
10275     // Now it should be ICed and keep a reference to y defined on field_holder.
10276     "}"
10277     "this.y = 42;"  // Assign on a global.
10278     "var result = 0;"
10279     "for (var i = 0; i < 10; i++) {"
10280     "  result += o.y;"
10281     "}"
10282     "result;",
10283     42 * 10);
10284 }
10285
10286
10287 static void SetOnThis(Local<String> name,
10288                       Local<Value> value,
10289                       const v8::PropertyCallbackInfo<void>& info) {
10290   info.This()->ForceSet(name, value);
10291 }
10292
10293
10294 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
10295   v8::HandleScope scope(v8::Isolate::GetCurrent());
10296   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10297   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10298   templ->SetAccessor(v8_str("y"), Return239Callback);
10299   LocalContext context;
10300   context->Global()->Set(v8_str("o"), templ->NewInstance());
10301
10302   // Check the case when receiver and interceptor's holder
10303   // are the same objects.
10304   v8::Handle<Value> value = CompileRun(
10305       "var result = 0;"
10306       "for (var i = 0; i < 7; i++) {"
10307       "  result = o.y;"
10308       "}");
10309   CHECK_EQ(239, value->Int32Value());
10310
10311   // Check the case when interceptor's holder is in proto chain
10312   // of receiver.
10313   value = CompileRun(
10314       "r = { __proto__: o };"
10315       "var result = 0;"
10316       "for (var i = 0; i < 7; i++) {"
10317       "  result = r.y;"
10318       "}");
10319   CHECK_EQ(239, value->Int32Value());
10320 }
10321
10322
10323 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
10324   v8::HandleScope scope(v8::Isolate::GetCurrent());
10325   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10326   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10327   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10328   templ_p->SetAccessor(v8_str("y"), Return239Callback);
10329
10330   LocalContext context;
10331   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10332   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10333
10334   // Check the case when receiver and interceptor's holder
10335   // are the same objects.
10336   v8::Handle<Value> value = CompileRun(
10337       "o.__proto__ = p;"
10338       "var result = 0;"
10339       "for (var i = 0; i < 7; i++) {"
10340       "  result = o.x + o.y;"
10341       "}");
10342   CHECK_EQ(239 + 42, value->Int32Value());
10343
10344   // Check the case when interceptor's holder is in proto chain
10345   // of receiver.
10346   value = CompileRun(
10347       "r = { __proto__: o };"
10348       "var result = 0;"
10349       "for (var i = 0; i < 7; i++) {"
10350       "  result = r.x + r.y;"
10351       "}");
10352   CHECK_EQ(239 + 42, value->Int32Value());
10353 }
10354
10355
10356 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
10357   v8::HandleScope scope(v8::Isolate::GetCurrent());
10358   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10359   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10360   templ->SetAccessor(v8_str("y"), Return239Callback);
10361
10362   LocalContext context;
10363   context->Global()->Set(v8_str("o"), templ->NewInstance());
10364
10365   v8::Handle<Value> value = CompileRun(
10366     "fst = new Object();  fst.__proto__ = o;"
10367     "snd = new Object();  snd.__proto__ = fst;"
10368     "var result1 = 0;"
10369     "for (var i = 0; i < 7;  i++) {"
10370     "  result1 = snd.x;"
10371     "}"
10372     "fst.x = 239;"
10373     "var result = 0;"
10374     "for (var i = 0; i < 7; i++) {"
10375     "  result = snd.x;"
10376     "}"
10377     "result + result1");
10378   CHECK_EQ(239 + 42, value->Int32Value());
10379 }
10380
10381
10382 // Test the case when we stored callback into
10383 // a stub, but interceptor produced value on its own.
10384 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
10385   v8::HandleScope scope(v8::Isolate::GetCurrent());
10386   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10387   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10388   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10389   templ_p->SetAccessor(v8_str("y"), Return239Callback);
10390
10391   LocalContext context;
10392   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10393   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10394
10395   v8::Handle<Value> value = CompileRun(
10396     "o.__proto__ = p;"
10397     "for (var i = 0; i < 7; i++) {"
10398     "  o.x;"
10399     // Now it should be ICed and keep a reference to x defined on p
10400     "}"
10401     "var result = 0;"
10402     "for (var i = 0; i < 7; i++) {"
10403     "  result += o.x;"
10404     "}"
10405     "result");
10406   CHECK_EQ(42 * 7, value->Int32Value());
10407 }
10408
10409
10410 // Test the case when we stored callback into
10411 // a stub, but it got invalidated later on.
10412 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
10413   v8::HandleScope scope(v8::Isolate::GetCurrent());
10414   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10415   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10416   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10417   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10418
10419   LocalContext context;
10420   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10421   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10422
10423   v8::Handle<Value> value = CompileRun(
10424     "inbetween = new Object();"
10425     "o.__proto__ = inbetween;"
10426     "inbetween.__proto__ = p;"
10427     "for (var i = 0; i < 10; i++) {"
10428     "  o.y;"
10429     // Now it should be ICed and keep a reference to y defined on p
10430     "}"
10431     "inbetween.y = 42;"
10432     "var result = 0;"
10433     "for (var i = 0; i < 10; i++) {"
10434     "  result += o.y;"
10435     "}"
10436     "result");
10437   CHECK_EQ(42 * 10, value->Int32Value());
10438 }
10439
10440
10441 // Test the case when we stored callback into
10442 // a stub, but it got invalidated later on due to override on
10443 // global object which is between interceptor and callbacks' holders.
10444 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
10445   v8::HandleScope scope(v8::Isolate::GetCurrent());
10446   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10447   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10448   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10449   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10450
10451   LocalContext context;
10452   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10453   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10454
10455   v8::Handle<Value> value = CompileRun(
10456     "o.__proto__ = this;"
10457     "this.__proto__ = p;"
10458     "for (var i = 0; i < 10; i++) {"
10459     "  if (o.y != 239) throw 'oops: ' + o.y;"
10460     // Now it should be ICed and keep a reference to y defined on p
10461     "}"
10462     "this.y = 42;"
10463     "var result = 0;"
10464     "for (var i = 0; i < 10; i++) {"
10465     "  result += o.y;"
10466     "}"
10467     "result");
10468   CHECK_EQ(42 * 10, value->Int32Value());
10469 }
10470
10471
10472 static void InterceptorLoadICGetter0(
10473     Local<String> name,
10474     const v8::PropertyCallbackInfo<v8::Value>& info) {
10475   ApiTestFuzzer::Fuzz();
10476   CHECK(v8_str("x")->Equals(name));
10477   info.GetReturnValue().Set(v8::Integer::New(0));
10478 }
10479
10480
10481 THREADED_TEST(InterceptorReturningZero) {
10482   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
10483      "o.x == undefined ? 1 : 0",
10484      0);
10485 }
10486
10487
10488 static void InterceptorStoreICSetter(
10489     Local<String> key,
10490     Local<Value> value,
10491     const v8::PropertyCallbackInfo<v8::Value>& info) {
10492   CHECK(v8_str("x")->Equals(key));
10493   CHECK_EQ(42, value->Int32Value());
10494   info.GetReturnValue().Set(value);
10495 }
10496
10497
10498 // This test should hit the store IC for the interceptor case.
10499 THREADED_TEST(InterceptorStoreIC) {
10500   v8::HandleScope scope(v8::Isolate::GetCurrent());
10501   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10502   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
10503                                  InterceptorStoreICSetter,
10504                                  0, 0, 0, v8_str("data"));
10505   LocalContext context;
10506   context->Global()->Set(v8_str("o"), templ->NewInstance());
10507   CompileRun(
10508       "for (var i = 0; i < 1000; i++) {"
10509       "  o.x = 42;"
10510       "}");
10511 }
10512
10513
10514 THREADED_TEST(InterceptorStoreICWithNoSetter) {
10515   v8::HandleScope scope(v8::Isolate::GetCurrent());
10516   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10517   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10518   LocalContext context;
10519   context->Global()->Set(v8_str("o"), templ->NewInstance());
10520   v8::Handle<Value> value = CompileRun(
10521     "for (var i = 0; i < 1000; i++) {"
10522     "  o.y = 239;"
10523     "}"
10524     "42 + o.y");
10525   CHECK_EQ(239 + 42, value->Int32Value());
10526 }
10527
10528
10529
10530
10531 v8::Handle<Value> call_ic_function;
10532 v8::Handle<Value> call_ic_function2;
10533 v8::Handle<Value> call_ic_function3;
10534
10535 static void InterceptorCallICGetter(
10536     Local<String> name,
10537     const v8::PropertyCallbackInfo<v8::Value>& info) {
10538   ApiTestFuzzer::Fuzz();
10539   CHECK(v8_str("x")->Equals(name));
10540   info.GetReturnValue().Set(call_ic_function);
10541 }
10542
10543
10544 // This test should hit the call IC for the interceptor case.
10545 THREADED_TEST(InterceptorCallIC) {
10546   v8::HandleScope scope(v8::Isolate::GetCurrent());
10547   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10548   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
10549   LocalContext context;
10550   context->Global()->Set(v8_str("o"), templ->NewInstance());
10551   call_ic_function =
10552       v8_compile("function f(x) { return x + 1; }; f")->Run();
10553   v8::Handle<Value> value = CompileRun(
10554     "var result = 0;"
10555     "for (var i = 0; i < 1000; i++) {"
10556     "  result = o.x(41);"
10557     "}");
10558   CHECK_EQ(42, value->Int32Value());
10559 }
10560
10561
10562 // This test checks that if interceptor doesn't provide
10563 // a value, we can fetch regular value.
10564 THREADED_TEST(InterceptorCallICSeesOthers) {
10565   v8::HandleScope scope(v8::Isolate::GetCurrent());
10566   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10567   templ->SetNamedPropertyHandler(NoBlockGetterX);
10568   LocalContext context;
10569   context->Global()->Set(v8_str("o"), templ->NewInstance());
10570   v8::Handle<Value> value = CompileRun(
10571     "o.x = function f(x) { return x + 1; };"
10572     "var result = 0;"
10573     "for (var i = 0; i < 7; i++) {"
10574     "  result = o.x(41);"
10575     "}");
10576   CHECK_EQ(42, value->Int32Value());
10577 }
10578
10579
10580 static v8::Handle<Value> call_ic_function4;
10581 static void InterceptorCallICGetter4(
10582     Local<String> name,
10583     const v8::PropertyCallbackInfo<v8::Value>& info) {
10584   ApiTestFuzzer::Fuzz();
10585   CHECK(v8_str("x")->Equals(name));
10586   info.GetReturnValue().Set(call_ic_function4);
10587 }
10588
10589
10590 // This test checks that if interceptor provides a function,
10591 // even if we cached shadowed variant, interceptor's function
10592 // is invoked
10593 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
10594   v8::HandleScope scope(v8::Isolate::GetCurrent());
10595   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10596   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
10597   LocalContext context;
10598   context->Global()->Set(v8_str("o"), templ->NewInstance());
10599   call_ic_function4 =
10600       v8_compile("function f(x) { return x - 1; }; f")->Run();
10601   v8::Handle<Value> value = CompileRun(
10602     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
10603     "var result = 0;"
10604     "for (var i = 0; i < 1000; i++) {"
10605     "  result = o.x(42);"
10606     "}");
10607   CHECK_EQ(41, value->Int32Value());
10608 }
10609
10610
10611 // Test the case when we stored cacheable lookup into
10612 // a stub, but it got invalidated later on
10613 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
10614   v8::HandleScope scope(v8::Isolate::GetCurrent());
10615   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10616   templ->SetNamedPropertyHandler(NoBlockGetterX);
10617   LocalContext context;
10618   context->Global()->Set(v8_str("o"), templ->NewInstance());
10619   v8::Handle<Value> value = CompileRun(
10620     "proto1 = new Object();"
10621     "proto2 = new Object();"
10622     "o.__proto__ = proto1;"
10623     "proto1.__proto__ = proto2;"
10624     "proto2.y = function(x) { return x + 1; };"
10625     // Invoke it many times to compile a stub
10626     "for (var i = 0; i < 7; i++) {"
10627     "  o.y(42);"
10628     "}"
10629     "proto1.y = function(x) { return x - 1; };"
10630     "var result = 0;"
10631     "for (var i = 0; i < 7; i++) {"
10632     "  result += o.y(42);"
10633     "}");
10634   CHECK_EQ(41 * 7, value->Int32Value());
10635 }
10636
10637
10638 // This test checks that if interceptor doesn't provide a function,
10639 // cached constant function is used
10640 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
10641   v8::HandleScope scope(v8::Isolate::GetCurrent());
10642   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10643   templ->SetNamedPropertyHandler(NoBlockGetterX);
10644   LocalContext context;
10645   context->Global()->Set(v8_str("o"), templ->NewInstance());
10646   v8::Handle<Value> value = CompileRun(
10647     "function inc(x) { return x + 1; };"
10648     "inc(1);"
10649     "o.x = inc;"
10650     "var result = 0;"
10651     "for (var i = 0; i < 1000; i++) {"
10652     "  result = o.x(42);"
10653     "}");
10654   CHECK_EQ(43, value->Int32Value());
10655 }
10656
10657
10658 static v8::Handle<Value> call_ic_function5;
10659 static void InterceptorCallICGetter5(
10660     Local<String> name,
10661     const v8::PropertyCallbackInfo<v8::Value>& info) {
10662   ApiTestFuzzer::Fuzz();
10663   if (v8_str("x")->Equals(name))
10664     info.GetReturnValue().Set(call_ic_function5);
10665 }
10666
10667
10668 // This test checks that if interceptor provides a function,
10669 // even if we cached constant function, interceptor's function
10670 // is invoked
10671 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
10672   v8::HandleScope scope(v8::Isolate::GetCurrent());
10673   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10674   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
10675   LocalContext context;
10676   context->Global()->Set(v8_str("o"), templ->NewInstance());
10677   call_ic_function5 =
10678       v8_compile("function f(x) { return x - 1; }; f")->Run();
10679   v8::Handle<Value> value = CompileRun(
10680     "function inc(x) { return x + 1; };"
10681     "inc(1);"
10682     "o.x = inc;"
10683     "var result = 0;"
10684     "for (var i = 0; i < 1000; i++) {"
10685     "  result = o.x(42);"
10686     "}");
10687   CHECK_EQ(41, value->Int32Value());
10688 }
10689
10690
10691 static v8::Handle<Value> call_ic_function6;
10692 static void InterceptorCallICGetter6(
10693     Local<String> name,
10694     const v8::PropertyCallbackInfo<v8::Value>& info) {
10695   ApiTestFuzzer::Fuzz();
10696   if (v8_str("x")->Equals(name))
10697     info.GetReturnValue().Set(call_ic_function6);
10698 }
10699
10700
10701 // Same test as above, except the code is wrapped in a function
10702 // to test the optimized compiler.
10703 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
10704   i::FLAG_allow_natives_syntax = true;
10705   v8::HandleScope scope(v8::Isolate::GetCurrent());
10706   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10707   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
10708   LocalContext context;
10709   context->Global()->Set(v8_str("o"), templ->NewInstance());
10710   call_ic_function6 =
10711       v8_compile("function f(x) { return x - 1; }; f")->Run();
10712   v8::Handle<Value> value = CompileRun(
10713     "function inc(x) { return x + 1; };"
10714     "inc(1);"
10715     "o.x = inc;"
10716     "function test() {"
10717     "  var result = 0;"
10718     "  for (var i = 0; i < 1000; i++) {"
10719     "    result = o.x(42);"
10720     "  }"
10721     "  return result;"
10722     "};"
10723     "test();"
10724     "test();"
10725     "test();"
10726     "%OptimizeFunctionOnNextCall(test);"
10727     "test()");
10728   CHECK_EQ(41, value->Int32Value());
10729 }
10730
10731
10732 // Test the case when we stored constant function into
10733 // a stub, but it got invalidated later on
10734 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
10735   v8::HandleScope scope(v8::Isolate::GetCurrent());
10736   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10737   templ->SetNamedPropertyHandler(NoBlockGetterX);
10738   LocalContext context;
10739   context->Global()->Set(v8_str("o"), templ->NewInstance());
10740   v8::Handle<Value> value = CompileRun(
10741     "function inc(x) { return x + 1; };"
10742     "inc(1);"
10743     "proto1 = new Object();"
10744     "proto2 = new Object();"
10745     "o.__proto__ = proto1;"
10746     "proto1.__proto__ = proto2;"
10747     "proto2.y = inc;"
10748     // Invoke it many times to compile a stub
10749     "for (var i = 0; i < 7; i++) {"
10750     "  o.y(42);"
10751     "}"
10752     "proto1.y = function(x) { return x - 1; };"
10753     "var result = 0;"
10754     "for (var i = 0; i < 7; i++) {"
10755     "  result += o.y(42);"
10756     "}");
10757   CHECK_EQ(41 * 7, value->Int32Value());
10758 }
10759
10760
10761 // Test the case when we stored constant function into
10762 // a stub, but it got invalidated later on due to override on
10763 // global object which is between interceptor and constant function' holders.
10764 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
10765   v8::HandleScope scope(v8::Isolate::GetCurrent());
10766   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10767   templ->SetNamedPropertyHandler(NoBlockGetterX);
10768   LocalContext context;
10769   context->Global()->Set(v8_str("o"), templ->NewInstance());
10770   v8::Handle<Value> value = CompileRun(
10771     "function inc(x) { return x + 1; };"
10772     "inc(1);"
10773     "o.__proto__ = this;"
10774     "this.__proto__.y = inc;"
10775     // Invoke it many times to compile a stub
10776     "for (var i = 0; i < 7; i++) {"
10777     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
10778     "}"
10779     "this.y = function(x) { return x - 1; };"
10780     "var result = 0;"
10781     "for (var i = 0; i < 7; i++) {"
10782     "  result += o.y(42);"
10783     "}");
10784   CHECK_EQ(41 * 7, value->Int32Value());
10785 }
10786
10787
10788 // Test the case when actual function to call sits on global object.
10789 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
10790   v8::HandleScope scope(v8::Isolate::GetCurrent());
10791   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10792   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10793
10794   LocalContext context;
10795   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10796
10797   v8::Handle<Value> value = CompileRun(
10798     "try {"
10799     "  o.__proto__ = this;"
10800     "  for (var i = 0; i < 10; i++) {"
10801     "    var v = o.parseFloat('239');"
10802     "    if (v != 239) throw v;"
10803       // Now it should be ICed and keep a reference to parseFloat.
10804     "  }"
10805     "  var result = 0;"
10806     "  for (var i = 0; i < 10; i++) {"
10807     "    result += o.parseFloat('239');"
10808     "  }"
10809     "  result"
10810     "} catch(e) {"
10811     "  e"
10812     "};");
10813   CHECK_EQ(239 * 10, value->Int32Value());
10814 }
10815
10816 static void InterceptorCallICFastApi(
10817     Local<String> name,
10818     const v8::PropertyCallbackInfo<v8::Value>& info) {
10819   ApiTestFuzzer::Fuzz();
10820   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10821   int* call_count =
10822       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10823   ++(*call_count);
10824   if ((*call_count) % 20 == 0) {
10825     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10826   }
10827 }
10828
10829 static void FastApiCallback_TrivialSignature(
10830     const v8::FunctionCallbackInfo<v8::Value>& args) {
10831   ApiTestFuzzer::Fuzz();
10832   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10833   v8::Isolate* isolate = v8::Isolate::GetCurrent();
10834   CHECK_EQ(isolate, args.GetIsolate());
10835   CHECK_EQ(args.This(), args.Holder());
10836   CHECK(args.Data()->Equals(v8_str("method_data")));
10837   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10838 }
10839
10840 static void FastApiCallback_SimpleSignature(
10841     const v8::FunctionCallbackInfo<v8::Value>& args) {
10842   ApiTestFuzzer::Fuzz();
10843   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10844   v8::Isolate* isolate = v8::Isolate::GetCurrent();
10845   CHECK_EQ(isolate, args.GetIsolate());
10846   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
10847   CHECK(args.Data()->Equals(v8_str("method_data")));
10848   // Note, we're using HasRealNamedProperty instead of Has to avoid
10849   // invoking the interceptor again.
10850   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10851   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10852 }
10853
10854
10855 // Helper to maximize the odds of object moving.
10856 static void GenerateSomeGarbage() {
10857   CompileRun(
10858       "var garbage;"
10859       "for (var i = 0; i < 1000; i++) {"
10860       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10861       "}"
10862       "garbage = undefined;");
10863 }
10864
10865
10866 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10867   static int count = 0;
10868   if (count++ % 3 == 0) {
10869     HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10870         // This should move the stub
10871     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
10872   }
10873 }
10874
10875
10876 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10877   LocalContext context;
10878   v8::HandleScope scope(context->GetIsolate());
10879   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
10880   nativeobject_templ->Set("callback",
10881                           v8::FunctionTemplate::New(DirectApiCallback));
10882   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10883   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10884   // call the api function multiple times to ensure direct call stub creation.
10885   CompileRun(
10886         "function f() {"
10887         "  for (var i = 1; i <= 30; i++) {"
10888         "    nativeobject.callback();"
10889         "  }"
10890         "}"
10891         "f();");
10892 }
10893
10894
10895 void ThrowingDirectApiCallback(
10896     const v8::FunctionCallbackInfo<v8::Value>& args) {
10897   v8::ThrowException(v8_str("g"));
10898 }
10899
10900
10901 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10902   LocalContext context;
10903   v8::HandleScope scope(context->GetIsolate());
10904   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
10905   nativeobject_templ->Set("callback",
10906                           v8::FunctionTemplate::New(ThrowingDirectApiCallback));
10907   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10908   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10909   // call the api function multiple times to ensure direct call stub creation.
10910   v8::Handle<Value> result = CompileRun(
10911       "var result = '';"
10912       "function f() {"
10913       "  for (var i = 1; i <= 5; i++) {"
10914       "    try { nativeobject.callback(); } catch (e) { result += e; }"
10915       "  }"
10916       "}"
10917       "f(); result;");
10918   CHECK_EQ(v8_str("ggggg"), result);
10919 }
10920
10921
10922 static Handle<Value> DoDirectGetter() {
10923   if (++p_getter_count % 3 == 0) {
10924     HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10925     GenerateSomeGarbage();
10926   }
10927   return v8_str("Direct Getter Result");
10928 }
10929
10930 static void DirectGetterCallback(
10931     Local<String> name,
10932     const v8::PropertyCallbackInfo<v8::Value>& info) {
10933   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10934   info.GetReturnValue().Set(DoDirectGetter());
10935 }
10936
10937
10938 template<typename Accessor>
10939 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10940   LocalContext context;
10941   v8::HandleScope scope(context->GetIsolate());
10942   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
10943   obj->SetAccessor(v8_str("p1"), accessor);
10944   context->Global()->Set(v8_str("o1"), obj->NewInstance());
10945   p_getter_count = 0;
10946   v8::Handle<v8::Value> result = CompileRun(
10947       "function f() {"
10948       "  for (var i = 0; i < 30; i++) o1.p1;"
10949       "  return o1.p1"
10950       "}"
10951       "f();");
10952   CHECK_EQ(v8_str("Direct Getter Result"), result);
10953   CHECK_EQ(31, p_getter_count);
10954 }
10955
10956
10957 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10958   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10959 }
10960
10961
10962 void ThrowingDirectGetterCallback(
10963     Local<String> name,
10964     const v8::PropertyCallbackInfo<v8::Value>& info) {
10965   v8::ThrowException(v8_str("g"));
10966 }
10967
10968
10969 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10970   LocalContext context;
10971   v8::HandleScope scope(context->GetIsolate());
10972   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
10973   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10974   context->Global()->Set(v8_str("o1"), obj->NewInstance());
10975   v8::Handle<Value> result = CompileRun(
10976       "var result = '';"
10977       "for (var i = 0; i < 5; i++) {"
10978       "    try { o1.p1; } catch (e) { result += e; }"
10979       "}"
10980       "result;");
10981   CHECK_EQ(v8_str("ggggg"), result);
10982 }
10983
10984
10985 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10986   int interceptor_call_count = 0;
10987   v8::HandleScope scope(v8::Isolate::GetCurrent());
10988   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10989   v8::Handle<v8::FunctionTemplate> method_templ =
10990       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10991                                 v8_str("method_data"),
10992                                 v8::Handle<v8::Signature>());
10993   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10994   proto_templ->Set(v8_str("method"), method_templ);
10995   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10996   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10997                                  NULL, NULL, NULL, NULL,
10998                                  v8::External::New(&interceptor_call_count));
10999   LocalContext context;
11000   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11001   GenerateSomeGarbage();
11002   context->Global()->Set(v8_str("o"), fun->NewInstance());
11003   CompileRun(
11004       "var result = 0;"
11005       "for (var i = 0; i < 100; i++) {"
11006       "  result = o.method(41);"
11007       "}");
11008   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11009   CHECK_EQ(100, interceptor_call_count);
11010 }
11011
11012
11013 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
11014   int interceptor_call_count = 0;
11015   v8::HandleScope scope(v8::Isolate::GetCurrent());
11016   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11017   v8::Handle<v8::FunctionTemplate> method_templ =
11018       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11019                                 v8_str("method_data"),
11020                                 v8::Signature::New(fun_templ));
11021   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11022   proto_templ->Set(v8_str("method"), method_templ);
11023   fun_templ->SetHiddenPrototype(true);
11024   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11025   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11026                                  NULL, NULL, NULL, NULL,
11027                                  v8::External::New(&interceptor_call_count));
11028   LocalContext context;
11029   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11030   GenerateSomeGarbage();
11031   context->Global()->Set(v8_str("o"), fun->NewInstance());
11032   CompileRun(
11033       "o.foo = 17;"
11034       "var receiver = {};"
11035       "receiver.__proto__ = o;"
11036       "var result = 0;"
11037       "for (var i = 0; i < 100; i++) {"
11038       "  result = receiver.method(41);"
11039       "}");
11040   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11041   CHECK_EQ(100, interceptor_call_count);
11042 }
11043
11044
11045 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
11046   int interceptor_call_count = 0;
11047   v8::HandleScope scope(v8::Isolate::GetCurrent());
11048   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11049   v8::Handle<v8::FunctionTemplate> method_templ =
11050       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11051                                 v8_str("method_data"),
11052                                 v8::Signature::New(fun_templ));
11053   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11054   proto_templ->Set(v8_str("method"), method_templ);
11055   fun_templ->SetHiddenPrototype(true);
11056   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11057   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11058                                  NULL, NULL, NULL, NULL,
11059                                  v8::External::New(&interceptor_call_count));
11060   LocalContext context;
11061   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11062   GenerateSomeGarbage();
11063   context->Global()->Set(v8_str("o"), fun->NewInstance());
11064   CompileRun(
11065       "o.foo = 17;"
11066       "var receiver = {};"
11067       "receiver.__proto__ = o;"
11068       "var result = 0;"
11069       "var saved_result = 0;"
11070       "for (var i = 0; i < 100; i++) {"
11071       "  result = receiver.method(41);"
11072       "  if (i == 50) {"
11073       "    saved_result = result;"
11074       "    receiver = {method: function(x) { return x - 1 }};"
11075       "  }"
11076       "}");
11077   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11078   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11079   CHECK_GE(interceptor_call_count, 50);
11080 }
11081
11082
11083 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
11084   int interceptor_call_count = 0;
11085   v8::HandleScope scope(v8::Isolate::GetCurrent());
11086   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11087   v8::Handle<v8::FunctionTemplate> method_templ =
11088       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11089                                 v8_str("method_data"),
11090                                 v8::Signature::New(fun_templ));
11091   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11092   proto_templ->Set(v8_str("method"), method_templ);
11093   fun_templ->SetHiddenPrototype(true);
11094   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11095   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11096                                  NULL, NULL, NULL, NULL,
11097                                  v8::External::New(&interceptor_call_count));
11098   LocalContext context;
11099   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11100   GenerateSomeGarbage();
11101   context->Global()->Set(v8_str("o"), fun->NewInstance());
11102   CompileRun(
11103       "o.foo = 17;"
11104       "var receiver = {};"
11105       "receiver.__proto__ = o;"
11106       "var result = 0;"
11107       "var saved_result = 0;"
11108       "for (var i = 0; i < 100; i++) {"
11109       "  result = receiver.method(41);"
11110       "  if (i == 50) {"
11111       "    saved_result = result;"
11112       "    o.method = function(x) { return x - 1 };"
11113       "  }"
11114       "}");
11115   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11116   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11117   CHECK_GE(interceptor_call_count, 50);
11118 }
11119
11120
11121 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
11122   int interceptor_call_count = 0;
11123   v8::HandleScope scope(v8::Isolate::GetCurrent());
11124   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11125   v8::Handle<v8::FunctionTemplate> method_templ =
11126       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11127                                 v8_str("method_data"),
11128                                 v8::Signature::New(fun_templ));
11129   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11130   proto_templ->Set(v8_str("method"), method_templ);
11131   fun_templ->SetHiddenPrototype(true);
11132   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11133   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11134                                  NULL, NULL, NULL, NULL,
11135                                  v8::External::New(&interceptor_call_count));
11136   LocalContext context;
11137   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11138   GenerateSomeGarbage();
11139   context->Global()->Set(v8_str("o"), fun->NewInstance());
11140   v8::TryCatch try_catch;
11141   CompileRun(
11142       "o.foo = 17;"
11143       "var receiver = {};"
11144       "receiver.__proto__ = o;"
11145       "var result = 0;"
11146       "var saved_result = 0;"
11147       "for (var i = 0; i < 100; i++) {"
11148       "  result = receiver.method(41);"
11149       "  if (i == 50) {"
11150       "    saved_result = result;"
11151       "    receiver = 333;"
11152       "  }"
11153       "}");
11154   CHECK(try_catch.HasCaught());
11155   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11156            try_catch.Exception()->ToString());
11157   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11158   CHECK_GE(interceptor_call_count, 50);
11159 }
11160
11161
11162 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
11163   int interceptor_call_count = 0;
11164   v8::HandleScope scope(v8::Isolate::GetCurrent());
11165   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11166   v8::Handle<v8::FunctionTemplate> method_templ =
11167       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11168                                 v8_str("method_data"),
11169                                 v8::Signature::New(fun_templ));
11170   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11171   proto_templ->Set(v8_str("method"), method_templ);
11172   fun_templ->SetHiddenPrototype(true);
11173   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11174   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11175                                  NULL, NULL, NULL, NULL,
11176                                  v8::External::New(&interceptor_call_count));
11177   LocalContext context;
11178   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11179   GenerateSomeGarbage();
11180   context->Global()->Set(v8_str("o"), fun->NewInstance());
11181   v8::TryCatch try_catch;
11182   CompileRun(
11183       "o.foo = 17;"
11184       "var receiver = {};"
11185       "receiver.__proto__ = o;"
11186       "var result = 0;"
11187       "var saved_result = 0;"
11188       "for (var i = 0; i < 100; i++) {"
11189       "  result = receiver.method(41);"
11190       "  if (i == 50) {"
11191       "    saved_result = result;"
11192       "    receiver = {method: receiver.method};"
11193       "  }"
11194       "}");
11195   CHECK(try_catch.HasCaught());
11196   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11197            try_catch.Exception()->ToString());
11198   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11199   CHECK_GE(interceptor_call_count, 50);
11200 }
11201
11202
11203 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
11204   v8::HandleScope scope(v8::Isolate::GetCurrent());
11205   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11206   v8::Handle<v8::FunctionTemplate> method_templ =
11207       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11208                                 v8_str("method_data"),
11209                                 v8::Handle<v8::Signature>());
11210   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11211   proto_templ->Set(v8_str("method"), method_templ);
11212   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11213   USE(templ);
11214   LocalContext context;
11215   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11216   GenerateSomeGarbage();
11217   context->Global()->Set(v8_str("o"), fun->NewInstance());
11218   CompileRun(
11219       "var result = 0;"
11220       "for (var i = 0; i < 100; i++) {"
11221       "  result = o.method(41);"
11222       "}");
11223
11224   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11225 }
11226
11227
11228 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
11229   v8::HandleScope scope(v8::Isolate::GetCurrent());
11230   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11231   v8::Handle<v8::FunctionTemplate> method_templ =
11232       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11233                                 v8_str("method_data"),
11234                                 v8::Signature::New(fun_templ));
11235   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11236   proto_templ->Set(v8_str("method"), method_templ);
11237   fun_templ->SetHiddenPrototype(true);
11238   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11239   CHECK(!templ.IsEmpty());
11240   LocalContext context;
11241   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11242   GenerateSomeGarbage();
11243   context->Global()->Set(v8_str("o"), fun->NewInstance());
11244   CompileRun(
11245       "o.foo = 17;"
11246       "var receiver = {};"
11247       "receiver.__proto__ = o;"
11248       "var result = 0;"
11249       "for (var i = 0; i < 100; i++) {"
11250       "  result = receiver.method(41);"
11251       "}");
11252
11253   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11254 }
11255
11256
11257 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
11258   v8::HandleScope scope(v8::Isolate::GetCurrent());
11259   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11260   v8::Handle<v8::FunctionTemplate> method_templ =
11261       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11262                                 v8_str("method_data"),
11263                                 v8::Signature::New(fun_templ));
11264   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11265   proto_templ->Set(v8_str("method"), method_templ);
11266   fun_templ->SetHiddenPrototype(true);
11267   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11268   CHECK(!templ.IsEmpty());
11269   LocalContext context;
11270   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11271   GenerateSomeGarbage();
11272   context->Global()->Set(v8_str("o"), fun->NewInstance());
11273   CompileRun(
11274       "o.foo = 17;"
11275       "var receiver = {};"
11276       "receiver.__proto__ = o;"
11277       "var result = 0;"
11278       "var saved_result = 0;"
11279       "for (var i = 0; i < 100; i++) {"
11280       "  result = receiver.method(41);"
11281       "  if (i == 50) {"
11282       "    saved_result = result;"
11283       "    receiver = {method: function(x) { return x - 1 }};"
11284       "  }"
11285       "}");
11286   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11287   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11288 }
11289
11290
11291 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
11292   v8::HandleScope scope(v8::Isolate::GetCurrent());
11293   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11294   v8::Handle<v8::FunctionTemplate> method_templ =
11295       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11296                                 v8_str("method_data"),
11297                                 v8::Signature::New(fun_templ));
11298   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11299   proto_templ->Set(v8_str("method"), method_templ);
11300   fun_templ->SetHiddenPrototype(true);
11301   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11302   CHECK(!templ.IsEmpty());
11303   LocalContext context;
11304   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11305   GenerateSomeGarbage();
11306   context->Global()->Set(v8_str("o"), fun->NewInstance());
11307   v8::TryCatch try_catch;
11308   CompileRun(
11309       "o.foo = 17;"
11310       "var receiver = {};"
11311       "receiver.__proto__ = o;"
11312       "var result = 0;"
11313       "var saved_result = 0;"
11314       "for (var i = 0; i < 100; i++) {"
11315       "  result = receiver.method(41);"
11316       "  if (i == 50) {"
11317       "    saved_result = result;"
11318       "    receiver = 333;"
11319       "  }"
11320       "}");
11321   CHECK(try_catch.HasCaught());
11322   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11323            try_catch.Exception()->ToString());
11324   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11325 }
11326
11327
11328 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
11329   v8::HandleScope scope(v8::Isolate::GetCurrent());
11330   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11331   v8::Handle<v8::FunctionTemplate> method_templ =
11332       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11333                                 v8_str("method_data"),
11334                                 v8::Signature::New(fun_templ));
11335   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11336   proto_templ->Set(v8_str("method"), method_templ);
11337   fun_templ->SetHiddenPrototype(true);
11338   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11339   CHECK(!templ.IsEmpty());
11340   LocalContext context;
11341   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11342   GenerateSomeGarbage();
11343   context->Global()->Set(v8_str("o"), fun->NewInstance());
11344   v8::TryCatch try_catch;
11345   CompileRun(
11346       "o.foo = 17;"
11347       "var receiver = {};"
11348       "receiver.__proto__ = o;"
11349       "var result = 0;"
11350       "var saved_result = 0;"
11351       "for (var i = 0; i < 100; i++) {"
11352       "  result = receiver.method(41);"
11353       "  if (i == 50) {"
11354       "    saved_result = result;"
11355       "    receiver = Object.create(receiver);"
11356       "  }"
11357       "}");
11358   CHECK(try_catch.HasCaught());
11359   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11360            try_catch.Exception()->ToString());
11361   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11362 }
11363
11364
11365 v8::Handle<Value> keyed_call_ic_function;
11366
11367 static void InterceptorKeyedCallICGetter(
11368     Local<String> name,
11369     const v8::PropertyCallbackInfo<v8::Value>& info) {
11370   ApiTestFuzzer::Fuzz();
11371   if (v8_str("x")->Equals(name)) {
11372     info.GetReturnValue().Set(keyed_call_ic_function);
11373   }
11374 }
11375
11376
11377 // Test the case when we stored cacheable lookup into
11378 // a stub, but the function name changed (to another cacheable function).
11379 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
11380   v8::HandleScope scope(v8::Isolate::GetCurrent());
11381   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11382   templ->SetNamedPropertyHandler(NoBlockGetterX);
11383   LocalContext context;
11384   context->Global()->Set(v8_str("o"), templ->NewInstance());
11385   CompileRun(
11386     "proto = new Object();"
11387     "proto.y = function(x) { return x + 1; };"
11388     "proto.z = function(x) { return x - 1; };"
11389     "o.__proto__ = proto;"
11390     "var result = 0;"
11391     "var method = 'y';"
11392     "for (var i = 0; i < 10; i++) {"
11393     "  if (i == 5) { method = 'z'; };"
11394     "  result += o[method](41);"
11395     "}");
11396   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11397 }
11398
11399
11400 // Test the case when we stored cacheable lookup into
11401 // a stub, but the function name changed (and the new function is present
11402 // both before and after the interceptor in the prototype chain).
11403 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
11404   v8::HandleScope scope(v8::Isolate::GetCurrent());
11405   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11406   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
11407   LocalContext context;
11408   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
11409   keyed_call_ic_function =
11410       v8_compile("function f(x) { return x - 1; }; f")->Run();
11411   CompileRun(
11412     "o = new Object();"
11413     "proto2 = new Object();"
11414     "o.y = function(x) { return x + 1; };"
11415     "proto2.y = function(x) { return x + 2; };"
11416     "o.__proto__ = proto1;"
11417     "proto1.__proto__ = proto2;"
11418     "var result = 0;"
11419     "var method = 'x';"
11420     "for (var i = 0; i < 10; i++) {"
11421     "  if (i == 5) { method = 'y'; };"
11422     "  result += o[method](41);"
11423     "}");
11424   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11425 }
11426
11427
11428 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
11429 // on the global object.
11430 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
11431   v8::HandleScope scope(v8::Isolate::GetCurrent());
11432   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11433   templ->SetNamedPropertyHandler(NoBlockGetterX);
11434   LocalContext context;
11435   context->Global()->Set(v8_str("o"), templ->NewInstance());
11436   CompileRun(
11437     "function inc(x) { return x + 1; };"
11438     "inc(1);"
11439     "function dec(x) { return x - 1; };"
11440     "dec(1);"
11441     "o.__proto__ = this;"
11442     "this.__proto__.x = inc;"
11443     "this.__proto__.y = dec;"
11444     "var result = 0;"
11445     "var method = 'x';"
11446     "for (var i = 0; i < 10; i++) {"
11447     "  if (i == 5) { method = 'y'; };"
11448     "  result += o[method](41);"
11449     "}");
11450   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11451 }
11452
11453
11454 // Test the case when actual function to call sits on global object.
11455 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
11456   v8::HandleScope scope(v8::Isolate::GetCurrent());
11457   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11458   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11459   LocalContext context;
11460   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11461
11462   CompileRun(
11463     "function len(x) { return x.length; };"
11464     "o.__proto__ = this;"
11465     "var m = 'parseFloat';"
11466     "var result = 0;"
11467     "for (var i = 0; i < 10; i++) {"
11468     "  if (i == 5) {"
11469     "    m = 'len';"
11470     "    saved_result = result;"
11471     "  };"
11472     "  result = o[m]('239');"
11473     "}");
11474   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
11475   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11476 }
11477
11478
11479 // Test the map transition before the interceptor.
11480 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
11481   v8::HandleScope scope(v8::Isolate::GetCurrent());
11482   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11483   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11484   LocalContext context;
11485   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
11486
11487   CompileRun(
11488     "var o = new Object();"
11489     "o.__proto__ = proto;"
11490     "o.method = function(x) { return x + 1; };"
11491     "var m = 'method';"
11492     "var result = 0;"
11493     "for (var i = 0; i < 10; i++) {"
11494     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
11495     "  result += o[m](41);"
11496     "}");
11497   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11498 }
11499
11500
11501 // Test the map transition after the interceptor.
11502 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
11503   v8::HandleScope scope(v8::Isolate::GetCurrent());
11504   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11505   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11506   LocalContext context;
11507   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11508
11509   CompileRun(
11510     "var proto = new Object();"
11511     "o.__proto__ = proto;"
11512     "proto.method = function(x) { return x + 1; };"
11513     "var m = 'method';"
11514     "var result = 0;"
11515     "for (var i = 0; i < 10; i++) {"
11516     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
11517     "  result += o[m](41);"
11518     "}");
11519   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11520 }
11521
11522
11523 static int interceptor_call_count = 0;
11524
11525 static void InterceptorICRefErrorGetter(
11526     Local<String> name,
11527     const v8::PropertyCallbackInfo<v8::Value>& info) {
11528   ApiTestFuzzer::Fuzz();
11529   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
11530     info.GetReturnValue().Set(call_ic_function2);
11531   }
11532 }
11533
11534
11535 // This test should hit load and call ICs for the interceptor case.
11536 // Once in a while, the interceptor will reply that a property was not
11537 // found in which case we should get a reference error.
11538 THREADED_TEST(InterceptorICReferenceErrors) {
11539   v8::HandleScope scope(v8::Isolate::GetCurrent());
11540   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11541   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
11542   LocalContext context(0, templ, v8::Handle<Value>());
11543   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
11544   v8::Handle<Value> value = CompileRun(
11545     "function f() {"
11546     "  for (var i = 0; i < 1000; i++) {"
11547     "    try { x; } catch(e) { return true; }"
11548     "  }"
11549     "  return false;"
11550     "};"
11551     "f();");
11552   CHECK_EQ(true, value->BooleanValue());
11553   interceptor_call_count = 0;
11554   value = CompileRun(
11555     "function g() {"
11556     "  for (var i = 0; i < 1000; i++) {"
11557     "    try { x(42); } catch(e) { return true; }"
11558     "  }"
11559     "  return false;"
11560     "};"
11561     "g();");
11562   CHECK_EQ(true, value->BooleanValue());
11563 }
11564
11565
11566 static int interceptor_ic_exception_get_count = 0;
11567
11568 static void InterceptorICExceptionGetter(
11569     Local<String> name,
11570     const v8::PropertyCallbackInfo<v8::Value>& info) {
11571   ApiTestFuzzer::Fuzz();
11572   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
11573     info.GetReturnValue().Set(call_ic_function3);
11574   }
11575   if (interceptor_ic_exception_get_count == 20) {
11576     v8::ThrowException(v8_num(42));
11577     return;
11578   }
11579 }
11580
11581
11582 // Test interceptor load/call IC where the interceptor throws an
11583 // exception once in a while.
11584 THREADED_TEST(InterceptorICGetterExceptions) {
11585   interceptor_ic_exception_get_count = 0;
11586   v8::HandleScope scope(v8::Isolate::GetCurrent());
11587   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11588   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
11589   LocalContext context(0, templ, v8::Handle<Value>());
11590   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
11591   v8::Handle<Value> value = CompileRun(
11592     "function f() {"
11593     "  for (var i = 0; i < 100; i++) {"
11594     "    try { x; } catch(e) { return true; }"
11595     "  }"
11596     "  return false;"
11597     "};"
11598     "f();");
11599   CHECK_EQ(true, value->BooleanValue());
11600   interceptor_ic_exception_get_count = 0;
11601   value = CompileRun(
11602     "function f() {"
11603     "  for (var i = 0; i < 100; i++) {"
11604     "    try { x(42); } catch(e) { return true; }"
11605     "  }"
11606     "  return false;"
11607     "};"
11608     "f();");
11609   CHECK_EQ(true, value->BooleanValue());
11610 }
11611
11612
11613 static int interceptor_ic_exception_set_count = 0;
11614
11615 static void InterceptorICExceptionSetter(
11616       Local<String> key,
11617       Local<Value> value,
11618       const v8::PropertyCallbackInfo<v8::Value>& info) {
11619   ApiTestFuzzer::Fuzz();
11620   if (++interceptor_ic_exception_set_count > 20) {
11621     v8::ThrowException(v8_num(42));
11622   }
11623 }
11624
11625
11626 // Test interceptor store IC where the interceptor throws an exception
11627 // once in a while.
11628 THREADED_TEST(InterceptorICSetterExceptions) {
11629   interceptor_ic_exception_set_count = 0;
11630   v8::HandleScope scope(v8::Isolate::GetCurrent());
11631   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11632   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
11633   LocalContext context(0, templ, v8::Handle<Value>());
11634   v8::Handle<Value> value = CompileRun(
11635     "function f() {"
11636     "  for (var i = 0; i < 100; i++) {"
11637     "    try { x = 42; } catch(e) { return true; }"
11638     "  }"
11639     "  return false;"
11640     "};"
11641     "f();");
11642   CHECK_EQ(true, value->BooleanValue());
11643 }
11644
11645
11646 // Test that we ignore null interceptors.
11647 THREADED_TEST(NullNamedInterceptor) {
11648   v8::HandleScope scope(v8::Isolate::GetCurrent());
11649   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11650   templ->SetNamedPropertyHandler(
11651       static_cast<v8::NamedPropertyGetterCallback>(0));
11652   LocalContext context;
11653   templ->Set("x", v8_num(42));
11654   v8::Handle<v8::Object> obj = templ->NewInstance();
11655   context->Global()->Set(v8_str("obj"), obj);
11656   v8::Handle<Value> value = CompileRun("obj.x");
11657   CHECK(value->IsInt32());
11658   CHECK_EQ(42, value->Int32Value());
11659 }
11660
11661
11662 // Test that we ignore null interceptors.
11663 THREADED_TEST(NullIndexedInterceptor) {
11664   v8::HandleScope scope(v8::Isolate::GetCurrent());
11665   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11666   templ->SetIndexedPropertyHandler(
11667       static_cast<v8::IndexedPropertyGetterCallback>(0));
11668   LocalContext context;
11669   templ->Set("42", v8_num(42));
11670   v8::Handle<v8::Object> obj = templ->NewInstance();
11671   context->Global()->Set(v8_str("obj"), obj);
11672   v8::Handle<Value> value = CompileRun("obj[42]");
11673   CHECK(value->IsInt32());
11674   CHECK_EQ(42, value->Int32Value());
11675 }
11676
11677
11678 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
11679   v8::HandleScope scope(v8::Isolate::GetCurrent());
11680   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
11681   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11682   LocalContext env;
11683   env->Global()->Set(v8_str("obj"),
11684                      templ->GetFunction()->NewInstance());
11685   ExpectTrue("obj.x === 42");
11686   ExpectTrue("!obj.propertyIsEnumerable('x')");
11687 }
11688
11689
11690 static void ThrowingGetter(Local<String> name,
11691                            const v8::PropertyCallbackInfo<v8::Value>& info) {
11692   ApiTestFuzzer::Fuzz();
11693   ThrowException(Handle<Value>());
11694   info.GetReturnValue().SetUndefined();
11695 }
11696
11697
11698 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
11699   LocalContext context;
11700   HandleScope scope(context->GetIsolate());
11701
11702   Local<FunctionTemplate> templ = FunctionTemplate::New();
11703   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
11704   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
11705
11706   Local<Object> instance = templ->GetFunction()->NewInstance();
11707
11708   Local<Object> another = Object::New();
11709   another->SetPrototype(instance);
11710
11711   Local<Object> with_js_getter = CompileRun(
11712       "o = {};\n"
11713       "o.__defineGetter__('f', function() { throw undefined; });\n"
11714       "o\n").As<Object>();
11715   CHECK(!with_js_getter.IsEmpty());
11716
11717   TryCatch try_catch;
11718
11719   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
11720   CHECK(try_catch.HasCaught());
11721   try_catch.Reset();
11722   CHECK(result.IsEmpty());
11723
11724   result = another->GetRealNamedProperty(v8_str("f"));
11725   CHECK(try_catch.HasCaught());
11726   try_catch.Reset();
11727   CHECK(result.IsEmpty());
11728
11729   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
11730   CHECK(try_catch.HasCaught());
11731   try_catch.Reset();
11732   CHECK(result.IsEmpty());
11733
11734   result = another->Get(v8_str("f"));
11735   CHECK(try_catch.HasCaught());
11736   try_catch.Reset();
11737   CHECK(result.IsEmpty());
11738
11739   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
11740   CHECK(try_catch.HasCaught());
11741   try_catch.Reset();
11742   CHECK(result.IsEmpty());
11743
11744   result = with_js_getter->Get(v8_str("f"));
11745   CHECK(try_catch.HasCaught());
11746   try_catch.Reset();
11747   CHECK(result.IsEmpty());
11748 }
11749
11750
11751 static void ThrowingCallbackWithTryCatch(
11752     const v8::FunctionCallbackInfo<v8::Value>& args) {
11753   TryCatch try_catch;
11754   // Verboseness is important: it triggers message delivery which can call into
11755   // external code.
11756   try_catch.SetVerbose(true);
11757   CompileRun("throw 'from JS';");
11758   CHECK(try_catch.HasCaught());
11759   CHECK(!i::Isolate::Current()->has_pending_exception());
11760   CHECK(!i::Isolate::Current()->has_scheduled_exception());
11761 }
11762
11763
11764 static int call_depth;
11765
11766
11767 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
11768   TryCatch try_catch;
11769 }
11770
11771
11772 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
11773   if (--call_depth) CompileRun("throw 'ThrowInJS';");
11774 }
11775
11776
11777 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
11778   if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
11779 }
11780
11781
11782 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
11783   Handle<String> errorMessageString = message->Get();
11784   CHECK(!errorMessageString.IsEmpty());
11785   message->GetStackTrace();
11786   message->GetScriptResourceName();
11787 }
11788
11789
11790 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
11791   LocalContext context;
11792   HandleScope scope(context->GetIsolate());
11793
11794   Local<Function> func =
11795       FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
11796   context->Global()->Set(v8_str("func"), func);
11797
11798   MessageCallback callbacks[] =
11799       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
11800   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
11801     MessageCallback callback = callbacks[i];
11802     if (callback != NULL) {
11803       V8::AddMessageListener(callback);
11804     }
11805     // Some small number to control number of times message handler should
11806     // throw an exception.
11807     call_depth = 5;
11808     ExpectFalse(
11809         "var thrown = false;\n"
11810         "try { func(); } catch(e) { thrown = true; }\n"
11811         "thrown\n");
11812     if (callback != NULL) {
11813       V8::RemoveMessageListeners(callback);
11814     }
11815   }
11816 }
11817
11818
11819 static void ParentGetter(Local<String> name,
11820                          const v8::PropertyCallbackInfo<v8::Value>& info) {
11821   ApiTestFuzzer::Fuzz();
11822   info.GetReturnValue().Set(v8_num(1));
11823 }
11824
11825
11826 static void ChildGetter(Local<String> name,
11827                         const v8::PropertyCallbackInfo<v8::Value>& info) {
11828   ApiTestFuzzer::Fuzz();
11829   info.GetReturnValue().Set(v8_num(42));
11830 }
11831
11832
11833 THREADED_TEST(Overriding) {
11834   i::FLAG_es5_readonly = true;
11835   LocalContext context;
11836   v8::HandleScope scope(context->GetIsolate());
11837
11838   // Parent template.
11839   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
11840   Local<ObjectTemplate> parent_instance_templ =
11841       parent_templ->InstanceTemplate();
11842   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
11843
11844   // Template that inherits from the parent template.
11845   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
11846   Local<ObjectTemplate> child_instance_templ =
11847       child_templ->InstanceTemplate();
11848   child_templ->Inherit(parent_templ);
11849   // Override 'f'.  The child version of 'f' should get called for child
11850   // instances.
11851   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11852   // Add 'g' twice.  The 'g' added last should get called for instances.
11853   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11854   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11855
11856   // Add 'h' as an accessor to the proto template with ReadOnly attributes
11857   // so 'h' can be shadowed on the instance object.
11858   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11859   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11860       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11861
11862   // Add 'i' as an accessor to the instance template with ReadOnly attributes
11863   // but the attribute does not have effect because it is duplicated with
11864   // NULL setter.
11865   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11866       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11867
11868
11869
11870   // Instantiate the child template.
11871   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11872
11873   // Check that the child function overrides the parent one.
11874   context->Global()->Set(v8_str("o"), instance);
11875   Local<Value> value = v8_compile("o.f")->Run();
11876   // Check that the 'g' that was added last is hit.
11877   CHECK_EQ(42, value->Int32Value());
11878   value = v8_compile("o.g")->Run();
11879   CHECK_EQ(42, value->Int32Value());
11880
11881   // Check that 'h' cannot be shadowed.
11882   value = v8_compile("o.h = 3; o.h")->Run();
11883   CHECK_EQ(1, value->Int32Value());
11884
11885   // Check that 'i' cannot be shadowed or changed.
11886   value = v8_compile("o.i = 3; o.i")->Run();
11887   CHECK_EQ(42, value->Int32Value());
11888 }
11889
11890
11891 static void IsConstructHandler(
11892     const v8::FunctionCallbackInfo<v8::Value>& args) {
11893   ApiTestFuzzer::Fuzz();
11894   args.GetReturnValue().Set(args.IsConstructCall());
11895 }
11896
11897
11898 THREADED_TEST(IsConstructCall) {
11899   v8::HandleScope scope(v8::Isolate::GetCurrent());
11900
11901   // Function template with call handler.
11902   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
11903   templ->SetCallHandler(IsConstructHandler);
11904
11905   LocalContext context;
11906
11907   context->Global()->Set(v8_str("f"), templ->GetFunction());
11908   Local<Value> value = v8_compile("f()")->Run();
11909   CHECK(!value->BooleanValue());
11910   value = v8_compile("new f()")->Run();
11911   CHECK(value->BooleanValue());
11912 }
11913
11914
11915 THREADED_TEST(ObjectProtoToString) {
11916   v8::HandleScope scope(v8::Isolate::GetCurrent());
11917   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
11918   templ->SetClassName(v8_str("MyClass"));
11919
11920   LocalContext context;
11921
11922   Local<String> customized_tostring = v8_str("customized toString");
11923
11924   // Replace Object.prototype.toString
11925   v8_compile("Object.prototype.toString = function() {"
11926                   "  return 'customized toString';"
11927                   "}")->Run();
11928
11929   // Normal ToString call should call replaced Object.prototype.toString
11930   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11931   Local<String> value = instance->ToString();
11932   CHECK(value->IsString() && value->Equals(customized_tostring));
11933
11934   // ObjectProtoToString should not call replace toString function.
11935   value = instance->ObjectProtoToString();
11936   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11937
11938   // Check global
11939   value = context->Global()->ObjectProtoToString();
11940   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11941
11942   // Check ordinary object
11943   Local<Value> object = v8_compile("new Object()")->Run();
11944   value = object.As<v8::Object>()->ObjectProtoToString();
11945   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11946 }
11947
11948
11949 THREADED_TEST(ObjectGetConstructorName) {
11950   LocalContext context;
11951   v8::HandleScope scope(context->GetIsolate());
11952   v8_compile("function Parent() {};"
11953              "function Child() {};"
11954              "Child.prototype = new Parent();"
11955              "var outer = { inner: function() { } };"
11956              "var p = new Parent();"
11957              "var c = new Child();"
11958              "var x = new outer.inner();")->Run();
11959
11960   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11961   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
11962       v8_str("Parent")));
11963
11964   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11965   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
11966       v8_str("Child")));
11967
11968   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11969   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
11970       v8_str("outer.inner")));
11971 }
11972
11973
11974 bool ApiTestFuzzer::fuzzing_ = false;
11975 i::Semaphore* ApiTestFuzzer::all_tests_done_=
11976   i::OS::CreateSemaphore(0);
11977 int ApiTestFuzzer::active_tests_;
11978 int ApiTestFuzzer::tests_being_run_;
11979 int ApiTestFuzzer::current_;
11980
11981
11982 // We are in a callback and want to switch to another thread (if we
11983 // are currently running the thread fuzzing test).
11984 void ApiTestFuzzer::Fuzz() {
11985   if (!fuzzing_) return;
11986   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11987   test->ContextSwitch();
11988 }
11989
11990
11991 // Let the next thread go.  Since it is also waiting on the V8 lock it may
11992 // not start immediately.
11993 bool ApiTestFuzzer::NextThread() {
11994   int test_position = GetNextTestNumber();
11995   const char* test_name = RegisterThreadedTest::nth(current_)->name();
11996   if (test_position == current_) {
11997     if (kLogThreading)
11998       printf("Stay with %s\n", test_name);
11999     return false;
12000   }
12001   if (kLogThreading) {
12002     printf("Switch from %s to %s\n",
12003            test_name,
12004            RegisterThreadedTest::nth(test_position)->name());
12005   }
12006   current_ = test_position;
12007   RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
12008   return true;
12009 }
12010
12011
12012 void ApiTestFuzzer::Run() {
12013   // When it is our turn...
12014   gate_->Wait();
12015   {
12016     // ... get the V8 lock and start running the test.
12017     v8::Locker locker(CcTest::default_isolate());
12018     CallTest();
12019   }
12020   // This test finished.
12021   active_ = false;
12022   active_tests_--;
12023   // If it was the last then signal that fact.
12024   if (active_tests_ == 0) {
12025     all_tests_done_->Signal();
12026   } else {
12027     // Otherwise select a new test and start that.
12028     NextThread();
12029   }
12030 }
12031
12032
12033 static unsigned linear_congruential_generator;
12034
12035
12036 void ApiTestFuzzer::SetUp(PartOfTest part) {
12037   linear_congruential_generator = i::FLAG_testing_prng_seed;
12038   fuzzing_ = true;
12039   int count = RegisterThreadedTest::count();
12040   int start =  count * part / (LAST_PART + 1);
12041   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
12042   active_tests_ = tests_being_run_ = end - start + 1;
12043   for (int i = 0; i < tests_being_run_; i++) {
12044     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
12045   }
12046   for (int i = 0; i < active_tests_; i++) {
12047     RegisterThreadedTest::nth(i)->fuzzer_->Start();
12048   }
12049 }
12050
12051
12052 static void CallTestNumber(int test_number) {
12053   (RegisterThreadedTest::nth(test_number)->callback())();
12054 }
12055
12056
12057 void ApiTestFuzzer::RunAllTests() {
12058   // Set off the first test.
12059   current_ = -1;
12060   NextThread();
12061   // Wait till they are all done.
12062   all_tests_done_->Wait();
12063 }
12064
12065
12066 int ApiTestFuzzer::GetNextTestNumber() {
12067   int next_test;
12068   do {
12069     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
12070     linear_congruential_generator *= 1664525u;
12071     linear_congruential_generator += 1013904223u;
12072   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
12073   return next_test;
12074 }
12075
12076
12077 void ApiTestFuzzer::ContextSwitch() {
12078   // If the new thread is the same as the current thread there is nothing to do.
12079   if (NextThread()) {
12080     // Now it can start.
12081     v8::Unlocker unlocker(CcTest::default_isolate());
12082     // Wait till someone starts us again.
12083     gate_->Wait();
12084     // And we're off.
12085   }
12086 }
12087
12088
12089 void ApiTestFuzzer::TearDown() {
12090   fuzzing_ = false;
12091   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
12092     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
12093     if (fuzzer != NULL) fuzzer->Join();
12094   }
12095 }
12096
12097
12098 // Lets not be needlessly self-referential.
12099 TEST(Threading1) {
12100   // TODO(mstarzinger): Disabled in GC stress mode for now, we should find the
12101   // correct timeout for this an re-enable this test again
12102   if (i::FLAG_stress_compaction) return;
12103   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
12104   ApiTestFuzzer::RunAllTests();
12105   ApiTestFuzzer::TearDown();
12106 }
12107
12108
12109 TEST(Threading2) {
12110   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
12111   ApiTestFuzzer::RunAllTests();
12112   ApiTestFuzzer::TearDown();
12113 }
12114
12115
12116 TEST(Threading3) {
12117   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
12118   ApiTestFuzzer::RunAllTests();
12119   ApiTestFuzzer::TearDown();
12120 }
12121
12122
12123 TEST(Threading4) {
12124   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
12125   ApiTestFuzzer::RunAllTests();
12126   ApiTestFuzzer::TearDown();
12127 }
12128
12129
12130 void ApiTestFuzzer::CallTest() {
12131   if (kLogThreading)
12132     printf("Start test %d\n", test_number_);
12133   CallTestNumber(test_number_);
12134   if (kLogThreading)
12135     printf("End test %d\n", test_number_);
12136 }
12137
12138
12139 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
12140   CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12141   ApiTestFuzzer::Fuzz();
12142   v8::Unlocker unlocker(CcTest::default_isolate());
12143   const char* code = "throw 7;";
12144   {
12145     v8::Locker nested_locker(CcTest::default_isolate());
12146     v8::HandleScope scope(args.GetIsolate());
12147     v8::Handle<Value> exception;
12148     { v8::TryCatch try_catch;
12149       v8::Handle<Value> value = CompileRun(code);
12150       CHECK(value.IsEmpty());
12151       CHECK(try_catch.HasCaught());
12152       // Make sure to wrap the exception in a new handle because
12153       // the handle returned from the TryCatch is destroyed
12154       // when the TryCatch is destroyed.
12155       exception = Local<Value>::New(try_catch.Exception());
12156     }
12157     v8::ThrowException(exception);
12158   }
12159 }
12160
12161
12162 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
12163   CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12164   ApiTestFuzzer::Fuzz();
12165   v8::Unlocker unlocker(CcTest::default_isolate());
12166   const char* code = "throw 7;";
12167   {
12168     v8::Locker nested_locker(CcTest::default_isolate());
12169     v8::HandleScope scope(args.GetIsolate());
12170     v8::Handle<Value> value = CompileRun(code);
12171     CHECK(value.IsEmpty());
12172     args.GetReturnValue().Set(v8_str("foo"));
12173   }
12174 }
12175
12176
12177 // These are locking tests that don't need to be run again
12178 // as part of the locking aggregation tests.
12179 TEST(NestedLockers) {
12180   v8::Locker locker(CcTest::default_isolate());
12181   CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12182   LocalContext env;
12183   v8::HandleScope scope(env->GetIsolate());
12184   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
12185   Local<Function> fun = fun_templ->GetFunction();
12186   env->Global()->Set(v8_str("throw_in_js"), fun);
12187   Local<Script> script = v8_compile("(function () {"
12188                                     "  try {"
12189                                     "    throw_in_js();"
12190                                     "    return 42;"
12191                                     "  } catch (e) {"
12192                                     "    return e * 13;"
12193                                     "  }"
12194                                     "})();");
12195   CHECK_EQ(91, script->Run()->Int32Value());
12196 }
12197
12198
12199 // These are locking tests that don't need to be run again
12200 // as part of the locking aggregation tests.
12201 TEST(NestedLockersNoTryCatch) {
12202   v8::Locker locker(CcTest::default_isolate());
12203   LocalContext env;
12204   v8::HandleScope scope(env->GetIsolate());
12205   Local<v8::FunctionTemplate> fun_templ =
12206       v8::FunctionTemplate::New(ThrowInJSNoCatch);
12207   Local<Function> fun = fun_templ->GetFunction();
12208   env->Global()->Set(v8_str("throw_in_js"), fun);
12209   Local<Script> script = v8_compile("(function () {"
12210                                     "  try {"
12211                                     "    throw_in_js();"
12212                                     "    return 42;"
12213                                     "  } catch (e) {"
12214                                     "    return e * 13;"
12215                                     "  }"
12216                                     "})();");
12217   CHECK_EQ(91, script->Run()->Int32Value());
12218 }
12219
12220
12221 THREADED_TEST(RecursiveLocking) {
12222   v8::Locker locker(CcTest::default_isolate());
12223   {
12224     v8::Locker locker2(CcTest::default_isolate());
12225     CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12226   }
12227 }
12228
12229
12230 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
12231   ApiTestFuzzer::Fuzz();
12232   v8::Unlocker unlocker(CcTest::default_isolate());
12233 }
12234
12235
12236 THREADED_TEST(LockUnlockLock) {
12237   {
12238     v8::Locker locker(CcTest::default_isolate());
12239     v8::HandleScope scope(CcTest::default_isolate());
12240     LocalContext env;
12241     Local<v8::FunctionTemplate> fun_templ =
12242         v8::FunctionTemplate::New(UnlockForAMoment);
12243     Local<Function> fun = fun_templ->GetFunction();
12244     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12245     Local<Script> script = v8_compile("(function () {"
12246                                       "  unlock_for_a_moment();"
12247                                       "  return 42;"
12248                                       "})();");
12249     CHECK_EQ(42, script->Run()->Int32Value());
12250   }
12251   {
12252     v8::Locker locker(CcTest::default_isolate());
12253     v8::HandleScope scope(CcTest::default_isolate());
12254     LocalContext env;
12255     Local<v8::FunctionTemplate> fun_templ =
12256         v8::FunctionTemplate::New(UnlockForAMoment);
12257     Local<Function> fun = fun_templ->GetFunction();
12258     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12259     Local<Script> script = v8_compile("(function () {"
12260                                       "  unlock_for_a_moment();"
12261                                       "  return 42;"
12262                                       "})();");
12263     CHECK_EQ(42, script->Run()->Int32Value());
12264   }
12265 }
12266
12267
12268 static int GetGlobalObjectsCount() {
12269   i::Isolate::Current()->heap()->EnsureHeapIsIterable();
12270   int count = 0;
12271   i::HeapIterator it(HEAP);
12272   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
12273     if (object->IsJSGlobalObject()) count++;
12274   return count;
12275 }
12276
12277
12278 static void CheckSurvivingGlobalObjectsCount(int expected) {
12279   // We need to collect all garbage twice to be sure that everything
12280   // has been collected.  This is because inline caches are cleared in
12281   // the first garbage collection but some of the maps have already
12282   // been marked at that point.  Therefore some of the maps are not
12283   // collected until the second garbage collection.
12284   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12285   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
12286   int count = GetGlobalObjectsCount();
12287 #ifdef DEBUG
12288   if (count != expected) HEAP->TracePathToGlobal();
12289 #endif
12290   CHECK_EQ(expected, count);
12291 }
12292
12293
12294 TEST(DontLeakGlobalObjects) {
12295   // Regression test for issues 1139850 and 1174891.
12296
12297   v8::V8::Initialize();
12298
12299   for (int i = 0; i < 5; i++) {
12300     { v8::HandleScope scope(v8::Isolate::GetCurrent());
12301       LocalContext context;
12302     }
12303     v8::V8::ContextDisposedNotification();
12304     CheckSurvivingGlobalObjectsCount(0);
12305
12306     { v8::HandleScope scope(v8::Isolate::GetCurrent());
12307       LocalContext context;
12308       v8_compile("Date")->Run();
12309     }
12310     v8::V8::ContextDisposedNotification();
12311     CheckSurvivingGlobalObjectsCount(0);
12312
12313     { v8::HandleScope scope(v8::Isolate::GetCurrent());
12314       LocalContext context;
12315       v8_compile("/aaa/")->Run();
12316     }
12317     v8::V8::ContextDisposedNotification();
12318     CheckSurvivingGlobalObjectsCount(0);
12319
12320     { v8::HandleScope scope(v8::Isolate::GetCurrent());
12321       const char* extension_list[] = { "v8/gc" };
12322       v8::ExtensionConfiguration extensions(1, extension_list);
12323       LocalContext context(&extensions);
12324       v8_compile("gc();")->Run();
12325     }
12326     v8::V8::ContextDisposedNotification();
12327     CheckSurvivingGlobalObjectsCount(0);
12328   }
12329 }
12330
12331
12332 v8::Persistent<v8::Object> some_object;
12333 v8::Persistent<v8::Object> bad_handle;
12334
12335 void NewPersistentHandleCallback(v8::Isolate* isolate,
12336                                  v8::Persistent<v8::Value>* handle,
12337                                  void*) {
12338   v8::HandleScope scope(isolate);
12339   bad_handle.Reset(isolate, some_object);
12340   handle->Dispose(isolate);
12341 }
12342
12343
12344 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
12345   LocalContext context;
12346   v8::Isolate* isolate = context->GetIsolate();
12347
12348   v8::Persistent<v8::Object> handle1, handle2;
12349   {
12350     v8::HandleScope scope(isolate);
12351     some_object.Reset(isolate, v8::Object::New());
12352     handle1.Reset(isolate, v8::Object::New());
12353     handle2.Reset(isolate, v8::Object::New());
12354   }
12355   // Note: order is implementation dependent alas: currently
12356   // global handle nodes are processed by PostGarbageCollectionProcessing
12357   // in reverse allocation order, so if second allocated handle is deleted,
12358   // weak callback of the first handle would be able to 'reallocate' it.
12359   handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback);
12360   handle2.Dispose(isolate);
12361   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12362 }
12363
12364
12365 v8::Persistent<v8::Object> to_be_disposed;
12366
12367 void DisposeAndForceGcCallback(v8::Isolate* isolate,
12368                                v8::Persistent<v8::Value>* handle,
12369                                void*) {
12370   to_be_disposed.Dispose(isolate);
12371   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12372   handle->Dispose(isolate);
12373 }
12374
12375
12376 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
12377   LocalContext context;
12378   v8::Isolate* isolate = context->GetIsolate();
12379
12380   v8::Persistent<v8::Object> handle1, handle2;
12381   {
12382     v8::HandleScope scope(isolate);
12383     handle1.Reset(isolate, v8::Object::New());
12384     handle2.Reset(isolate, v8::Object::New());
12385   }
12386   handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback);
12387   to_be_disposed.Reset(isolate, handle2);
12388   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12389 }
12390
12391 void DisposingCallback(v8::Isolate* isolate,
12392                        v8::Persistent<v8::Value>* handle,
12393                        void*) {
12394   handle->Dispose(isolate);
12395 }
12396
12397 void HandleCreatingCallback(v8::Isolate* isolate,
12398                             v8::Persistent<v8::Value>* handle,
12399                             void*) {
12400   v8::HandleScope scope(isolate);
12401   v8::Persistent<v8::Object>(isolate, v8::Object::New());
12402   handle->Dispose(isolate);
12403 }
12404
12405
12406 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
12407   LocalContext context;
12408   v8::Isolate* isolate = context->GetIsolate();
12409
12410   v8::Persistent<v8::Object> handle1, handle2, handle3;
12411   {
12412     v8::HandleScope scope(isolate);
12413     handle3.Reset(isolate, v8::Object::New());
12414     handle2.Reset(isolate, v8::Object::New());
12415     handle1.Reset(isolate, v8::Object::New());
12416   }
12417   handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback);
12418   handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback);
12419   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12420 }
12421
12422
12423 THREADED_TEST(CheckForCrossContextObjectLiterals) {
12424   v8::V8::Initialize();
12425
12426   const int nof = 2;
12427   const char* sources[nof] = {
12428     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
12429     "Object()"
12430   };
12431
12432   for (int i = 0; i < nof; i++) {
12433     const char* source = sources[i];
12434     { v8::HandleScope scope(v8::Isolate::GetCurrent());
12435       LocalContext context;
12436       CompileRun(source);
12437     }
12438     { v8::HandleScope scope(v8::Isolate::GetCurrent());
12439       LocalContext context;
12440       CompileRun(source);
12441     }
12442   }
12443 }
12444
12445
12446 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
12447   v8::HandleScope inner(env->GetIsolate());
12448   env->Enter();
12449   v8::Handle<Value> three = v8_num(3);
12450   v8::Handle<Value> value = inner.Close(three);
12451   env->Exit();
12452   return value;
12453 }
12454
12455
12456 THREADED_TEST(NestedHandleScopeAndContexts) {
12457   v8::Isolate* isolate = v8::Isolate::GetCurrent();
12458   v8::HandleScope outer(isolate);
12459   v8::Local<Context> env = Context::New(isolate);
12460   env->Enter();
12461   v8::Handle<Value> value = NestedScope(env);
12462   v8::Handle<String> str(value->ToString());
12463   CHECK(!str.IsEmpty());
12464   env->Exit();
12465 }
12466
12467
12468 static bool MatchPointers(void* key1, void* key2) {
12469   return key1 == key2;
12470 }
12471
12472
12473 struct SymbolInfo {
12474   size_t id;
12475   size_t size;
12476   std::string name;
12477 };
12478
12479
12480 class SetFunctionEntryHookTest {
12481  public:
12482   SetFunctionEntryHookTest() {
12483     CHECK(instance_ == NULL);
12484     instance_ = this;
12485   }
12486   ~SetFunctionEntryHookTest() {
12487     CHECK(instance_ == this);
12488     instance_ = NULL;
12489   }
12490   void Reset() {
12491     symbols_.clear();
12492     symbol_locations_.clear();
12493     invocations_.clear();
12494   }
12495   void RunTest();
12496   void OnJitEvent(const v8::JitCodeEvent* event);
12497   static void JitEvent(const v8::JitCodeEvent* event) {
12498     CHECK(instance_ != NULL);
12499     instance_->OnJitEvent(event);
12500   }
12501
12502   void OnEntryHook(uintptr_t function,
12503                    uintptr_t return_addr_location);
12504   static void EntryHook(uintptr_t function,
12505                         uintptr_t return_addr_location) {
12506     CHECK(instance_ != NULL);
12507     instance_->OnEntryHook(function, return_addr_location);
12508   }
12509
12510   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12511     CHECK(instance_ != NULL);
12512     args.GetReturnValue().Set(v8_num(42));
12513   }
12514   void RunLoopInNewEnv(v8::Isolate* isolate);
12515
12516   // Records addr as location of symbol.
12517   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
12518
12519   // Finds the symbol containing addr
12520   SymbolInfo* FindSymbolForAddr(i::Address addr);
12521   // Returns the number of invocations where the caller name contains
12522   // \p caller_name and the function name contains \p function_name.
12523   int CountInvocations(const char* caller_name,
12524                        const char* function_name);
12525
12526   i::Handle<i::JSFunction> foo_func_;
12527   i::Handle<i::JSFunction> bar_func_;
12528
12529   typedef std::map<size_t, SymbolInfo> SymbolMap;
12530   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
12531   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
12532   SymbolMap symbols_;
12533   SymbolLocationMap symbol_locations_;
12534   InvocationMap invocations_;
12535
12536   static SetFunctionEntryHookTest* instance_;
12537 };
12538 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12539
12540
12541 // Returns true if addr is in the range [start, start+len).
12542 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12543   if (start <= addr && start + len > addr)
12544     return true;
12545
12546   return false;
12547 }
12548
12549 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12550                                               SymbolInfo* symbol) {
12551   // Insert the symbol at the new location.
12552   SymbolLocationMap::iterator it =
12553       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12554   // Now erase symbols to the left and right that overlap this one.
12555   while (it != symbol_locations_.begin()) {
12556     SymbolLocationMap::iterator left = it;
12557     --left;
12558     if (!Overlaps(left->first, left->second->size, addr))
12559       break;
12560     symbol_locations_.erase(left);
12561   }
12562
12563   // Now erase symbols to the left and right that overlap this one.
12564   while (true) {
12565     SymbolLocationMap::iterator right = it;
12566     ++right;
12567     if (right == symbol_locations_.end())
12568         break;
12569     if (!Overlaps(addr, symbol->size, right->first))
12570       break;
12571     symbol_locations_.erase(right);
12572   }
12573 }
12574
12575
12576 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12577   switch (event->type) {
12578     case v8::JitCodeEvent::CODE_ADDED: {
12579         CHECK(event->code_start != NULL);
12580         CHECK_NE(0, static_cast<int>(event->code_len));
12581         CHECK(event->name.str != NULL);
12582         size_t symbol_id = symbols_.size();
12583
12584         // Record the new symbol.
12585         SymbolInfo& info = symbols_[symbol_id];
12586         info.id = symbol_id;
12587         info.size = event->code_len;
12588         info.name.assign(event->name.str, event->name.str + event->name.len);
12589
12590         // And record it's location.
12591         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
12592       }
12593       break;
12594
12595     case v8::JitCodeEvent::CODE_MOVED: {
12596         // We would like to never see code move that we haven't seen before,
12597         // but the code creation event does not happen until the line endings
12598         // have been calculated (this is so that we can report the line in the
12599         // script at which the function source is found, see
12600         // Compiler::RecordFunctionCompilation) and the line endings
12601         // calculations can cause a GC, which can move the newly created code
12602         // before its existence can be logged.
12603         SymbolLocationMap::iterator it(
12604             symbol_locations_.find(
12605                 reinterpret_cast<i::Address>(event->code_start)));
12606         if (it != symbol_locations_.end()) {
12607           // Found a symbol at this location, move it.
12608           SymbolInfo* info = it->second;
12609           symbol_locations_.erase(it);
12610           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
12611                          info);
12612         }
12613       }
12614     default:
12615       break;
12616   }
12617 }
12618
12619 void SetFunctionEntryHookTest::OnEntryHook(
12620     uintptr_t function, uintptr_t return_addr_location) {
12621   // Get the function's code object.
12622   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
12623       reinterpret_cast<i::Address>(function));
12624   CHECK(function_code != NULL);
12625
12626   // Then try and look up the caller's code object.
12627   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
12628
12629   // Count the invocation.
12630   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
12631   SymbolInfo* function_symbol =
12632       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
12633   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12634
12635   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12636     // Check that we have a symbol for the "bar" function at the right location.
12637     SymbolLocationMap::iterator it(
12638         symbol_locations_.find(function_code->instruction_start()));
12639     CHECK(it != symbol_locations_.end());
12640   }
12641
12642   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12643     // Check that we have a symbol for "foo" at the right location.
12644     SymbolLocationMap::iterator it(
12645         symbol_locations_.find(function_code->instruction_start()));
12646     CHECK(it != symbol_locations_.end());
12647   }
12648 }
12649
12650
12651 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12652   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12653   // Do we have a direct hit on a symbol?
12654   if (it != symbol_locations_.end()) {
12655     if (it->first == addr)
12656       return it->second;
12657   }
12658
12659   // If not a direct hit, it'll have to be the previous symbol.
12660   if (it == symbol_locations_.begin())
12661     return NULL;
12662
12663   --it;
12664   size_t offs = addr - it->first;
12665   if (offs < it->second->size)
12666     return it->second;
12667
12668   return NULL;
12669 }
12670
12671
12672 int SetFunctionEntryHookTest::CountInvocations(
12673     const char* caller_name, const char* function_name) {
12674   InvocationMap::iterator it(invocations_.begin());
12675   int invocations = 0;
12676   for (; it != invocations_.end(); ++it) {
12677     SymbolInfo* caller = it->first.first;
12678     SymbolInfo* function = it->first.second;
12679
12680     // Filter out non-matching functions.
12681     if (function_name != NULL) {
12682       if (function->name.find(function_name) == std::string::npos)
12683         continue;
12684     }
12685
12686     // Filter out non-matching callers.
12687     if (caller_name != NULL) {
12688       if (caller == NULL)
12689         continue;
12690       if (caller->name.find(caller_name) == std::string::npos)
12691         continue;
12692     }
12693
12694     // It matches add the invocation count to the tally.
12695     invocations += it->second;
12696   }
12697
12698   return invocations;
12699 }
12700
12701
12702 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12703   v8::HandleScope outer(isolate);
12704   v8::Local<Context> env = Context::New(isolate);
12705   env->Enter();
12706
12707   Local<ObjectTemplate> t = ObjectTemplate::New();
12708   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback));
12709   env->Global()->Set(v8_str("obj"), t->NewInstance());
12710
12711   const char* script =
12712       "function bar() {\n"
12713       "  var sum = 0;\n"
12714       "  for (i = 0; i < 100; ++i)\n"
12715       "    sum = foo(i);\n"
12716       "  return sum;\n"
12717       "}\n"
12718       "function foo(i) { return i * i; }\n"
12719       "// Invoke on the runtime function.\n"
12720       "obj.asdf()";
12721   CompileRun(script);
12722   bar_func_ = i::Handle<i::JSFunction>::cast(
12723           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12724   ASSERT(!bar_func_.is_null());
12725
12726   foo_func_ =
12727       i::Handle<i::JSFunction>::cast(
12728            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12729   ASSERT(!foo_func_.is_null());
12730
12731   v8::Handle<v8::Value> value = CompileRun("bar();");
12732   CHECK(value->IsNumber());
12733   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12734
12735   // Test the optimized codegen path.
12736   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12737                      "bar();");
12738   CHECK(value->IsNumber());
12739   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12740
12741   env->Exit();
12742 }
12743
12744
12745 void SetFunctionEntryHookTest::RunTest() {
12746   // Work in a new isolate throughout.
12747   v8::Isolate* isolate = v8::Isolate::New();
12748
12749   // Test setting the entry hook on the new isolate.
12750   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
12751
12752   // Replacing the hook, once set should fail.
12753   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
12754
12755   {
12756     v8::Isolate::Scope scope(isolate);
12757
12758     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
12759
12760     RunLoopInNewEnv(isolate);
12761
12762     // Check the exepected invocation counts.
12763     CHECK_EQ(2, CountInvocations(NULL, "bar"));
12764     CHECK_EQ(200, CountInvocations("bar", "foo"));
12765     CHECK_EQ(200, CountInvocations(NULL, "foo"));
12766
12767     // Verify that we have an entry hook on some specific stubs.
12768     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12769     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12770     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12771   }
12772   isolate->Dispose();
12773
12774   Reset();
12775
12776   // Make sure a second isolate is unaffected by the previous entry hook.
12777   isolate = v8::Isolate::New();
12778   {
12779     v8::Isolate::Scope scope(isolate);
12780
12781     // Reset the entry count to zero and set the entry hook.
12782     RunLoopInNewEnv(isolate);
12783
12784     // We should record no invocations in this isolate.
12785     CHECK_EQ(0, static_cast<int>(invocations_.size()));
12786   }
12787   // Since the isolate has been used, we shouldn't be able to set an entry
12788   // hook anymore.
12789   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
12790
12791   isolate->Dispose();
12792 }
12793
12794
12795 TEST(SetFunctionEntryHook) {
12796   // FunctionEntryHook does not work well with experimental natives.
12797   // Experimental natives are compiled during snapshot deserialization.
12798   // This test breaks because InstallGetter (function from snapshot that
12799   // only gets called from experimental natives) is compiled with entry hooks.
12800   i::FLAG_harmony_typed_arrays = false;
12801   i::FLAG_harmony_array_buffer = false;
12802
12803   i::FLAG_allow_natives_syntax = true;
12804   i::FLAG_use_inlining = false;
12805
12806   SetFunctionEntryHookTest test;
12807   test.RunTest();
12808 }
12809
12810
12811 static i::HashMap* code_map = NULL;
12812 static i::HashMap* jitcode_line_info = NULL;
12813 static int saw_bar = 0;
12814 static int move_events = 0;
12815
12816
12817 static bool FunctionNameIs(const char* expected,
12818                            const v8::JitCodeEvent* event) {
12819   // Log lines for functions are of the general form:
12820   // "LazyCompile:<type><function_name>", where the type is one of
12821   // "*", "~" or "".
12822   static const char kPreamble[] = "LazyCompile:";
12823   static size_t kPreambleLen = sizeof(kPreamble) - 1;
12824
12825   if (event->name.len < sizeof(kPreamble) - 1 ||
12826       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12827     return false;
12828   }
12829
12830   const char* tail = event->name.str + kPreambleLen;
12831   size_t tail_len = event->name.len - kPreambleLen;
12832   size_t expected_len = strlen(expected);
12833   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12834     --tail_len;
12835     ++tail;
12836   }
12837
12838   // Check for tails like 'bar :1'.
12839   if (tail_len > expected_len + 2 &&
12840       tail[expected_len] == ' ' &&
12841       tail[expected_len + 1] == ':' &&
12842       tail[expected_len + 2] &&
12843       !strncmp(tail, expected, expected_len)) {
12844     return true;
12845   }
12846
12847   if (tail_len != expected_len)
12848     return false;
12849
12850   return strncmp(tail, expected, expected_len) == 0;
12851 }
12852
12853
12854 static void event_handler(const v8::JitCodeEvent* event) {
12855   CHECK(event != NULL);
12856   CHECK(code_map != NULL);
12857   CHECK(jitcode_line_info != NULL);
12858
12859   class DummyJitCodeLineInfo {
12860   };
12861
12862   switch (event->type) {
12863     case v8::JitCodeEvent::CODE_ADDED: {
12864         CHECK(event->code_start != NULL);
12865         CHECK_NE(0, static_cast<int>(event->code_len));
12866         CHECK(event->name.str != NULL);
12867         i::HashMap::Entry* entry =
12868             code_map->Lookup(event->code_start,
12869                              i::ComputePointerHash(event->code_start),
12870                              true);
12871         entry->value = reinterpret_cast<void*>(event->code_len);
12872
12873         if (FunctionNameIs("bar", event)) {
12874           ++saw_bar;
12875         }
12876       }
12877       break;
12878
12879     case v8::JitCodeEvent::CODE_MOVED: {
12880         uint32_t hash = i::ComputePointerHash(event->code_start);
12881         // We would like to never see code move that we haven't seen before,
12882         // but the code creation event does not happen until the line endings
12883         // have been calculated (this is so that we can report the line in the
12884         // script at which the function source is found, see
12885         // Compiler::RecordFunctionCompilation) and the line endings
12886         // calculations can cause a GC, which can move the newly created code
12887         // before its existence can be logged.
12888         i::HashMap::Entry* entry =
12889             code_map->Lookup(event->code_start, hash, false);
12890         if (entry != NULL) {
12891           ++move_events;
12892
12893           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12894           code_map->Remove(event->code_start, hash);
12895
12896           entry = code_map->Lookup(event->new_code_start,
12897                                    i::ComputePointerHash(event->new_code_start),
12898                                    true);
12899           CHECK(entry != NULL);
12900           entry->value = reinterpret_cast<void*>(event->code_len);
12901         }
12902       }
12903       break;
12904
12905     case v8::JitCodeEvent::CODE_REMOVED:
12906       // Object/code removal events are currently not dispatched from the GC.
12907       CHECK(false);
12908       break;
12909
12910     // For CODE_START_LINE_INFO_RECORDING event, we will create one
12911     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12912     // record it in jitcode_line_info.
12913     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12914         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12915         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12916         temp_event->user_data = line_info;
12917         i::HashMap::Entry* entry =
12918             jitcode_line_info->Lookup(line_info,
12919                                       i::ComputePointerHash(line_info),
12920                                       true);
12921         entry->value = reinterpret_cast<void*>(line_info);
12922       }
12923       break;
12924     // For these two events, we will check whether the event->user_data
12925     // data structure is created before during CODE_START_LINE_INFO_RECORDING
12926     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12927     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12928         CHECK(event->user_data != NULL);
12929         uint32_t hash = i::ComputePointerHash(event->user_data);
12930         i::HashMap::Entry* entry =
12931             jitcode_line_info->Lookup(event->user_data, hash, false);
12932         CHECK(entry != NULL);
12933         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12934       }
12935       break;
12936
12937     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12938         CHECK(event->user_data != NULL);
12939         uint32_t hash = i::ComputePointerHash(event->user_data);
12940         i::HashMap::Entry* entry =
12941             jitcode_line_info->Lookup(event->user_data, hash, false);
12942         CHECK(entry != NULL);
12943       }
12944       break;
12945
12946     default:
12947       // Impossible event.
12948       CHECK(false);
12949       break;
12950   }
12951 }
12952
12953
12954 TEST(SetJitCodeEventHandler) {
12955   i::FLAG_stress_compaction = true;
12956   i::FLAG_incremental_marking = false;
12957   const char* script =
12958     "function bar() {"
12959     "  var sum = 0;"
12960     "  for (i = 0; i < 100; ++i)"
12961     "    sum = foo(i);"
12962     "  return sum;"
12963     "}"
12964     "function foo(i) { return i * i; };"
12965     "bar();";
12966
12967   // Run this test in a new isolate to make sure we don't
12968   // have remnants of state from other code.
12969   v8::Isolate* isolate = v8::Isolate::New();
12970   isolate->Enter();
12971
12972   {
12973     v8::HandleScope scope(isolate);
12974     i::HashMap code(MatchPointers);
12975     code_map = &code;
12976
12977     i::HashMap lineinfo(MatchPointers);
12978     jitcode_line_info = &lineinfo;
12979
12980     saw_bar = 0;
12981     move_events = 0;
12982
12983     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12984
12985     // Generate new code objects sparsely distributed across several
12986     // different fragmented code-space pages.
12987     const int kIterations = 10;
12988     for (int i = 0; i < kIterations; ++i) {
12989       LocalContext env;
12990       i::AlwaysAllocateScope always_allocate;
12991       SimulateFullSpace(HEAP->code_space());
12992       CompileRun(script);
12993
12994       // Keep a strong reference to the code object in the handle scope.
12995       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12996           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12997       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12998           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
12999
13000       // Clear the compilation cache to get more wastage.
13001       ISOLATE->compilation_cache()->Clear();
13002     }
13003
13004     // Force code movement.
13005     HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
13006
13007     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13008
13009     CHECK_LE(kIterations, saw_bar);
13010     CHECK_LT(0, move_events);
13011
13012     code_map = NULL;
13013     jitcode_line_info = NULL;
13014   }
13015
13016   isolate->Exit();
13017   isolate->Dispose();
13018
13019   // Do this in a new isolate.
13020   isolate = v8::Isolate::New();
13021   isolate->Enter();
13022
13023   // Verify that we get callbacks for existing code objects when we
13024   // request enumeration of existing code.
13025   {
13026     v8::HandleScope scope(isolate);
13027     LocalContext env;
13028     CompileRun(script);
13029
13030     // Now get code through initial iteration.
13031     i::HashMap code(MatchPointers);
13032     code_map = &code;
13033
13034     i::HashMap lineinfo(MatchPointers);
13035     jitcode_line_info = &lineinfo;
13036
13037     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
13038     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13039
13040     jitcode_line_info = NULL;
13041     // We expect that we got some events. Note that if we could get code removal
13042     // notifications, we could compare two collections, one created by listening
13043     // from the time of creation of an isolate, and the other by subscribing
13044     // with EnumExisting.
13045     CHECK_LT(0, code.occupancy());
13046
13047     code_map = NULL;
13048   }
13049
13050   isolate->Exit();
13051   isolate->Dispose();
13052 }
13053
13054
13055 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
13056
13057
13058 THREADED_TEST(ExternalAllocatedMemory) {
13059   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13060   v8::HandleScope outer(isolate);
13061   v8::Local<Context> env(Context::New(isolate));
13062   CHECK(!env.IsEmpty());
13063   const intptr_t kSize = 1024*1024;
13064   int64_t baseline = cast(isolate->AdjustAmountOfExternalAllocatedMemory(0));
13065   CHECK_EQ(baseline + cast(kSize),
13066            cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize)));
13067   CHECK_EQ(baseline,
13068            cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)));
13069 }
13070
13071
13072 THREADED_TEST(DisposeEnteredContext) {
13073   LocalContext outer;
13074   v8::Isolate* isolate = outer->GetIsolate();
13075   v8::Persistent<v8::Context> inner;
13076   {
13077     v8::HandleScope scope(isolate);
13078     inner.Reset(isolate, v8::Context::New(isolate));
13079   }
13080   v8::HandleScope scope(isolate);
13081   {
13082     // Don't want a handle here, so do this unsafely
13083     v8::Handle<v8::Context> inner_local =
13084         v8::Utils::Convert<i::Object, v8::Context>(
13085             v8::Utils::OpenPersistent(inner));
13086     inner_local->Enter();
13087     inner.Dispose();
13088     inner.Clear();
13089     inner_local->Exit();
13090   }
13091 }
13092
13093
13094 // Regression test for issue 54, object templates with internal fields
13095 // but no accessors or interceptors did not get their internal field
13096 // count set on instances.
13097 THREADED_TEST(Regress54) {
13098   LocalContext context;
13099   v8::Isolate* isolate = context->GetIsolate();
13100   v8::HandleScope outer(isolate);
13101   static v8::Persistent<v8::ObjectTemplate> templ;
13102   if (templ.IsEmpty()) {
13103     v8::HandleScope inner(isolate);
13104     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
13105     local->SetInternalFieldCount(1);
13106     templ.Reset(isolate, inner.Close(local));
13107   }
13108   v8::Handle<v8::Object> result =
13109       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
13110   CHECK_EQ(1, result->InternalFieldCount());
13111 }
13112
13113
13114 // If part of the threaded tests, this test makes ThreadingTest fail
13115 // on mac.
13116 TEST(CatchStackOverflow) {
13117   LocalContext context;
13118   v8::HandleScope scope(context->GetIsolate());
13119   v8::TryCatch try_catch;
13120   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
13121     "function f() {"
13122     "  return f();"
13123     "}"
13124     ""
13125     "f();"));
13126   v8::Handle<v8::Value> result = script->Run();
13127   CHECK(result.IsEmpty());
13128 }
13129
13130
13131 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
13132                                     const char* resource_name,
13133                                     int line_offset) {
13134   v8::HandleScope scope(v8::Isolate::GetCurrent());
13135   v8::TryCatch try_catch;
13136   v8::Handle<v8::Value> result = script->Run();
13137   CHECK(result.IsEmpty());
13138   CHECK(try_catch.HasCaught());
13139   v8::Handle<v8::Message> message = try_catch.Message();
13140   CHECK(!message.IsEmpty());
13141   CHECK_EQ(10 + line_offset, message->GetLineNumber());
13142   CHECK_EQ(91, message->GetStartPosition());
13143   CHECK_EQ(92, message->GetEndPosition());
13144   CHECK_EQ(2, message->GetStartColumn());
13145   CHECK_EQ(3, message->GetEndColumn());
13146   v8::String::Utf8Value line(message->GetSourceLine());
13147   CHECK_EQ("  throw 'nirk';", *line);
13148   v8::String::Utf8Value name(message->GetScriptResourceName());
13149   CHECK_EQ(resource_name, *name);
13150 }
13151
13152
13153 THREADED_TEST(TryCatchSourceInfo) {
13154   LocalContext context;
13155   v8::HandleScope scope(context->GetIsolate());
13156   v8::Handle<v8::String> source = v8::String::New(
13157       "function Foo() {\n"
13158       "  return Bar();\n"
13159       "}\n"
13160       "\n"
13161       "function Bar() {\n"
13162       "  return Baz();\n"
13163       "}\n"
13164       "\n"
13165       "function Baz() {\n"
13166       "  throw 'nirk';\n"
13167       "}\n"
13168       "\n"
13169       "Foo();\n");
13170
13171   const char* resource_name;
13172   v8::Handle<v8::Script> script;
13173   resource_name = "test.js";
13174   script = v8::Script::Compile(source, v8::String::New(resource_name));
13175   CheckTryCatchSourceInfo(script, resource_name, 0);
13176
13177   resource_name = "test1.js";
13178   v8::ScriptOrigin origin1(v8::String::New(resource_name));
13179   script = v8::Script::Compile(source, &origin1);
13180   CheckTryCatchSourceInfo(script, resource_name, 0);
13181
13182   resource_name = "test2.js";
13183   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
13184   script = v8::Script::Compile(source, &origin2);
13185   CheckTryCatchSourceInfo(script, resource_name, 7);
13186 }
13187
13188
13189 THREADED_TEST(CompilationCache) {
13190   LocalContext context;
13191   v8::HandleScope scope(context->GetIsolate());
13192   v8::Handle<v8::String> source0 = v8::String::New("1234");
13193   v8::Handle<v8::String> source1 = v8::String::New("1234");
13194   v8::Handle<v8::Script> script0 =
13195       v8::Script::Compile(source0, v8::String::New("test.js"));
13196   v8::Handle<v8::Script> script1 =
13197       v8::Script::Compile(source1, v8::String::New("test.js"));
13198   v8::Handle<v8::Script> script2 =
13199       v8::Script::Compile(source0);  // different origin
13200   CHECK_EQ(1234, script0->Run()->Int32Value());
13201   CHECK_EQ(1234, script1->Run()->Int32Value());
13202   CHECK_EQ(1234, script2->Run()->Int32Value());
13203 }
13204
13205
13206 static void FunctionNameCallback(
13207     const v8::FunctionCallbackInfo<v8::Value>& args) {
13208   ApiTestFuzzer::Fuzz();
13209   args.GetReturnValue().Set(v8_num(42));
13210 }
13211
13212
13213 THREADED_TEST(CallbackFunctionName) {
13214   LocalContext context;
13215   v8::HandleScope scope(context->GetIsolate());
13216   Local<ObjectTemplate> t = ObjectTemplate::New();
13217   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
13218   context->Global()->Set(v8_str("obj"), t->NewInstance());
13219   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
13220   CHECK(value->IsString());
13221   v8::String::Utf8Value name(value);
13222   CHECK_EQ("asdf", *name);
13223 }
13224
13225
13226 THREADED_TEST(DateAccess) {
13227   LocalContext context;
13228   v8::HandleScope scope(context->GetIsolate());
13229   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
13230   CHECK(date->IsDate());
13231   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
13232 }
13233
13234
13235 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
13236   v8::Handle<v8::Object> obj = val.As<v8::Object>();
13237   v8::Handle<v8::Array> props = obj->GetPropertyNames();
13238   CHECK_EQ(elmc, props->Length());
13239   for (int i = 0; i < elmc; i++) {
13240     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13241     CHECK_EQ(elmv[i], *elm);
13242   }
13243 }
13244
13245
13246 void CheckOwnProperties(v8::Handle<v8::Value> val,
13247                         int elmc,
13248                         const char* elmv[]) {
13249   v8::Handle<v8::Object> obj = val.As<v8::Object>();
13250   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
13251   CHECK_EQ(elmc, props->Length());
13252   for (int i = 0; i < elmc; i++) {
13253     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13254     CHECK_EQ(elmv[i], *elm);
13255   }
13256 }
13257
13258
13259 THREADED_TEST(PropertyEnumeration) {
13260   LocalContext context;
13261   v8::HandleScope scope(context->GetIsolate());
13262   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13263       "var result = [];"
13264       "result[0] = {};"
13265       "result[1] = {a: 1, b: 2};"
13266       "result[2] = [1, 2, 3];"
13267       "var proto = {x: 1, y: 2, z: 3};"
13268       "var x = { __proto__: proto, w: 0, z: 1 };"
13269       "result[3] = x;"
13270       "result;"))->Run();
13271   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13272   CHECK_EQ(4, elms->Length());
13273   int elmc0 = 0;
13274   const char** elmv0 = NULL;
13275   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13276   CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13277   int elmc1 = 2;
13278   const char* elmv1[] = {"a", "b"};
13279   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13280   CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13281   int elmc2 = 3;
13282   const char* elmv2[] = {"0", "1", "2"};
13283   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13284   CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13285   int elmc3 = 4;
13286   const char* elmv3[] = {"w", "z", "x", "y"};
13287   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
13288   int elmc4 = 2;
13289   const char* elmv4[] = {"w", "z"};
13290   CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
13291 }
13292
13293
13294 THREADED_TEST(PropertyEnumeration2) {
13295   LocalContext context;
13296   v8::HandleScope scope(context->GetIsolate());
13297   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13298       "var result = [];"
13299       "result[0] = {};"
13300       "result[1] = {a: 1, b: 2};"
13301       "result[2] = [1, 2, 3];"
13302       "var proto = {x: 1, y: 2, z: 3};"
13303       "var x = { __proto__: proto, w: 0, z: 1 };"
13304       "result[3] = x;"
13305       "result;"))->Run();
13306   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13307   CHECK_EQ(4, elms->Length());
13308   int elmc0 = 0;
13309   const char** elmv0 = NULL;
13310   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13311
13312   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
13313   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
13314   CHECK_EQ(0, props->Length());
13315   for (uint32_t i = 0; i < props->Length(); i++) {
13316     printf("p[%d]\n", i);
13317   }
13318 }
13319
13320 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
13321                                   Local<Value> name,
13322                                   v8::AccessType type,
13323                                   Local<Value> data) {
13324   return type != v8::ACCESS_SET;
13325 }
13326
13327
13328 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
13329                                     uint32_t key,
13330                                     v8::AccessType type,
13331                                     Local<Value> data) {
13332   return type != v8::ACCESS_SET;
13333 }
13334
13335
13336 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
13337   LocalContext context;
13338   v8::HandleScope scope(context->GetIsolate());
13339   Local<ObjectTemplate> templ = ObjectTemplate::New();
13340   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13341                                  IndexedSetAccessBlocker);
13342   templ->Set(v8_str("x"), v8::True());
13343   Local<v8::Object> instance = templ->NewInstance();
13344   context->Global()->Set(v8_str("obj"), instance);
13345   Local<Value> value = CompileRun("obj.x");
13346   CHECK(value->BooleanValue());
13347 }
13348
13349
13350 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
13351                                   Local<Value> name,
13352                                   v8::AccessType type,
13353                                   Local<Value> data) {
13354   return false;
13355 }
13356
13357
13358 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
13359                                     uint32_t key,
13360                                     v8::AccessType type,
13361                                     Local<Value> data) {
13362   return false;
13363 }
13364
13365
13366
13367 THREADED_TEST(AccessChecksReenabledCorrectly) {
13368   LocalContext context;
13369   v8::HandleScope scope(context->GetIsolate());
13370   Local<ObjectTemplate> templ = ObjectTemplate::New();
13371   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13372                                  IndexedGetAccessBlocker);
13373   templ->Set(v8_str("a"), v8_str("a"));
13374   // Add more than 8 (see kMaxFastProperties) properties
13375   // so that the constructor will force copying map.
13376   // Cannot sprintf, gcc complains unsafety.
13377   char buf[4];
13378   for (char i = '0'; i <= '9' ; i++) {
13379     buf[0] = i;
13380     for (char j = '0'; j <= '9'; j++) {
13381       buf[1] = j;
13382       for (char k = '0'; k <= '9'; k++) {
13383         buf[2] = k;
13384         buf[3] = 0;
13385         templ->Set(v8_str(buf), v8::Number::New(k));
13386       }
13387     }
13388   }
13389
13390   Local<v8::Object> instance_1 = templ->NewInstance();
13391   context->Global()->Set(v8_str("obj_1"), instance_1);
13392
13393   Local<Value> value_1 = CompileRun("obj_1.a");
13394   CHECK(value_1->IsUndefined());
13395
13396   Local<v8::Object> instance_2 = templ->NewInstance();
13397   context->Global()->Set(v8_str("obj_2"), instance_2);
13398
13399   Local<Value> value_2 = CompileRun("obj_2.a");
13400   CHECK(value_2->IsUndefined());
13401 }
13402
13403
13404 // This tests that access check information remains on the global
13405 // object template when creating contexts.
13406 THREADED_TEST(AccessControlRepeatedContextCreation) {
13407   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13408   v8::HandleScope handle_scope(isolate);
13409   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13410   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13411                                            IndexedSetAccessBlocker);
13412   i::Handle<i::ObjectTemplateInfo> internal_template =
13413       v8::Utils::OpenHandle(*global_template);
13414   CHECK(!internal_template->constructor()->IsUndefined());
13415   i::Handle<i::FunctionTemplateInfo> constructor(
13416       i::FunctionTemplateInfo::cast(internal_template->constructor()));
13417   CHECK(!constructor->access_check_info()->IsUndefined());
13418   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
13419   CHECK(!context0.IsEmpty());
13420   CHECK(!constructor->access_check_info()->IsUndefined());
13421 }
13422
13423
13424 THREADED_TEST(TurnOnAccessCheck) {
13425   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13426   v8::HandleScope handle_scope(isolate);
13427
13428   // Create an environment with access check to the global object disabled by
13429   // default.
13430   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13431   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13432                                            IndexedGetAccessBlocker,
13433                                            v8::Handle<v8::Value>(),
13434                                            false);
13435   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
13436   Context::Scope context_scope(context);
13437
13438   // Set up a property and a number of functions.
13439   context->Global()->Set(v8_str("a"), v8_num(1));
13440   CompileRun("function f1() {return a;}"
13441              "function f2() {return a;}"
13442              "function g1() {return h();}"
13443              "function g2() {return h();}"
13444              "function h() {return 1;}");
13445   Local<Function> f1 =
13446       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13447   Local<Function> f2 =
13448       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13449   Local<Function> g1 =
13450       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13451   Local<Function> g2 =
13452       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13453   Local<Function> h =
13454       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
13455
13456   // Get the global object.
13457   v8::Handle<v8::Object> global = context->Global();
13458
13459   // Call f1 one time and f2 a number of times. This will ensure that f1 still
13460   // uses the runtime system to retreive property a whereas f2 uses global load
13461   // inline cache.
13462   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
13463   for (int i = 0; i < 4; i++) {
13464     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
13465   }
13466
13467   // Same for g1 and g2.
13468   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
13469   for (int i = 0; i < 4; i++) {
13470     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
13471   }
13472
13473   // Detach the global and turn on access check.
13474   context->DetachGlobal();
13475   context->Global()->TurnOnAccessCheck();
13476
13477   // Failing access check to property get results in undefined.
13478   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13479   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13480
13481   // Failing access check to function call results in exception.
13482   CHECK(g1->Call(global, 0, NULL).IsEmpty());
13483   CHECK(g2->Call(global, 0, NULL).IsEmpty());
13484
13485   // No failing access check when just returning a constant.
13486   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
13487 }
13488
13489
13490 static const char* kPropertyA = "a";
13491 static const char* kPropertyH = "h";
13492
13493 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
13494                                        Local<Value> name,
13495                                        v8::AccessType type,
13496                                        Local<Value> data) {
13497   if (!name->IsString()) return false;
13498   i::Handle<i::String> name_handle =
13499       v8::Utils::OpenHandle(String::Cast(*name));
13500   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
13501       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
13502 }
13503
13504
13505 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
13506   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13507   v8::HandleScope handle_scope(isolate);
13508
13509   // Create an environment with access check to the global object disabled by
13510   // default. When the registered access checker will block access to properties
13511   // a and h.
13512   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13513   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
13514                                            IndexedGetAccessBlocker,
13515                                            v8::Handle<v8::Value>(),
13516                                            false);
13517   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
13518   Context::Scope context_scope(context);
13519
13520   // Set up a property and a number of functions.
13521   context->Global()->Set(v8_str("a"), v8_num(1));
13522   static const char* source = "function f1() {return a;}"
13523                               "function f2() {return a;}"
13524                               "function g1() {return h();}"
13525                               "function g2() {return h();}"
13526                               "function h() {return 1;}";
13527
13528   CompileRun(source);
13529   Local<Function> f1;
13530   Local<Function> f2;
13531   Local<Function> g1;
13532   Local<Function> g2;
13533   Local<Function> h;
13534   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13535   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13536   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13537   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13538   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
13539
13540   // Get the global object.
13541   v8::Handle<v8::Object> global = context->Global();
13542
13543   // Call f1 one time and f2 a number of times. This will ensure that f1 still
13544   // uses the runtime system to retreive property a whereas f2 uses global load
13545   // inline cache.
13546   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
13547   for (int i = 0; i < 4; i++) {
13548     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
13549   }
13550
13551   // Same for g1 and g2.
13552   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
13553   for (int i = 0; i < 4; i++) {
13554     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
13555   }
13556
13557   // Detach the global and turn on access check now blocking access to property
13558   // a and function h.
13559   context->DetachGlobal();
13560   context->Global()->TurnOnAccessCheck();
13561
13562   // Failing access check to property get results in undefined.
13563   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13564   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13565
13566   // Failing access check to function call results in exception.
13567   CHECK(g1->Call(global, 0, NULL).IsEmpty());
13568   CHECK(g2->Call(global, 0, NULL).IsEmpty());
13569
13570   // No failing access check when just returning a constant.
13571   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
13572
13573   // Now compile the source again. And get the newly compiled functions, except
13574   // for h for which access is blocked.
13575   CompileRun(source);
13576   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13577   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13578   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13579   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13580   CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
13581
13582   // Failing access check to property get results in undefined.
13583   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13584   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13585
13586   // Failing access check to function call results in exception.
13587   CHECK(g1->Call(global, 0, NULL).IsEmpty());
13588   CHECK(g2->Call(global, 0, NULL).IsEmpty());
13589 }
13590
13591
13592 // This test verifies that pre-compilation (aka preparsing) can be called
13593 // without initializing the whole VM. Thus we cannot run this test in a
13594 // multi-threaded setup.
13595 TEST(PreCompile) {
13596   // TODO(155): This test would break without the initialization of V8. This is
13597   // a workaround for now to make this test not fail.
13598   v8::V8::Initialize();
13599   const char* script = "function foo(a) { return a+1; }";
13600   v8::ScriptData* sd =
13601       v8::ScriptData::PreCompile(script, i::StrLength(script));
13602   CHECK_NE(sd->Length(), 0);
13603   CHECK_NE(sd->Data(), NULL);
13604   CHECK(!sd->HasError());
13605   delete sd;
13606 }
13607
13608
13609 TEST(PreCompileWithError) {
13610   v8::V8::Initialize();
13611   const char* script = "function foo(a) { return 1 * * 2; }";
13612   v8::ScriptData* sd =
13613       v8::ScriptData::PreCompile(script, i::StrLength(script));
13614   CHECK(sd->HasError());
13615   delete sd;
13616 }
13617
13618
13619 TEST(Regress31661) {
13620   v8::V8::Initialize();
13621   const char* script = " The Definintive Guide";
13622   v8::ScriptData* sd =
13623       v8::ScriptData::PreCompile(script, i::StrLength(script));
13624   CHECK(sd->HasError());
13625   delete sd;
13626 }
13627
13628
13629 // Tests that ScriptData can be serialized and deserialized.
13630 TEST(PreCompileSerialization) {
13631   v8::V8::Initialize();
13632   const char* script = "function foo(a) { return a+1; }";
13633   v8::ScriptData* sd =
13634       v8::ScriptData::PreCompile(script, i::StrLength(script));
13635
13636   // Serialize.
13637   int serialized_data_length = sd->Length();
13638   char* serialized_data = i::NewArray<char>(serialized_data_length);
13639   i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
13640
13641   // Deserialize.
13642   v8::ScriptData* deserialized_sd =
13643       v8::ScriptData::New(serialized_data, serialized_data_length);
13644
13645   // Verify that the original is the same as the deserialized.
13646   CHECK_EQ(sd->Length(), deserialized_sd->Length());
13647   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
13648   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
13649
13650   delete sd;
13651   delete deserialized_sd;
13652 }
13653
13654
13655 // Attempts to deserialize bad data.
13656 TEST(PreCompileDeserializationError) {
13657   v8::V8::Initialize();
13658   const char* data = "DONT CARE";
13659   int invalid_size = 3;
13660   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
13661
13662   CHECK_EQ(0, sd->Length());
13663
13664   delete sd;
13665 }
13666
13667
13668 // Attempts to deserialize bad data.
13669 TEST(PreCompileInvalidPreparseDataError) {
13670   v8::V8::Initialize();
13671   LocalContext context;
13672   v8::HandleScope scope(context->GetIsolate());
13673
13674   const char* script = "function foo(){ return 5;}\n"
13675       "function bar(){ return 6 + 7;}  foo();";
13676   v8::ScriptData* sd =
13677       v8::ScriptData::PreCompile(script, i::StrLength(script));
13678   CHECK(!sd->HasError());
13679   // ScriptDataImpl private implementation details
13680   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
13681   const int kFunctionEntrySize = i::FunctionEntry::kSize;
13682   const int kFunctionEntryStartOffset = 0;
13683   const int kFunctionEntryEndOffset = 1;
13684   unsigned* sd_data =
13685       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
13686
13687   // Overwrite function bar's end position with 0.
13688   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
13689   v8::TryCatch try_catch;
13690
13691   Local<String> source = String::New(script);
13692   Local<Script> compiled_script = Script::New(source, NULL, sd);
13693   CHECK(try_catch.HasCaught());
13694   String::Utf8Value exception_value(try_catch.Message()->Get());
13695   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
13696            *exception_value);
13697
13698   try_catch.Reset();
13699
13700   // Overwrite function bar's start position with 200.  The function entry
13701   // will not be found when searching for it by position and we should fall
13702   // back on eager compilation.
13703   sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
13704   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
13705   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
13706       200;
13707   compiled_script = Script::New(source, NULL, sd);
13708   CHECK(!try_catch.HasCaught());
13709
13710   delete sd;
13711 }
13712
13713
13714 // Verifies that the Handle<String> and const char* versions of the API produce
13715 // the same results (at least for one trivial case).
13716 TEST(PreCompileAPIVariationsAreSame) {
13717   v8::V8::Initialize();
13718   v8::HandleScope scope(v8::Isolate::GetCurrent());
13719
13720   const char* cstring = "function foo(a) { return a+1; }";
13721
13722   v8::ScriptData* sd_from_cstring =
13723       v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
13724
13725   TestAsciiResource* resource = new TestAsciiResource(cstring);
13726   v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
13727       v8::String::NewExternal(resource));
13728
13729   v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
13730       v8::String::New(cstring));
13731
13732   CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
13733   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
13734                      sd_from_external_string->Data(),
13735                      sd_from_cstring->Length()));
13736
13737   CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
13738   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
13739                      sd_from_string->Data(),
13740                      sd_from_cstring->Length()));
13741
13742
13743   delete sd_from_cstring;
13744   delete sd_from_external_string;
13745   delete sd_from_string;
13746 }
13747
13748
13749 // This tests that we do not allow dictionary load/call inline caches
13750 // to use functions that have not yet been compiled.  The potential
13751 // problem of loading a function that has not yet been compiled can
13752 // arise because we share code between contexts via the compilation
13753 // cache.
13754 THREADED_TEST(DictionaryICLoadedFunction) {
13755   v8::HandleScope scope(v8::Isolate::GetCurrent());
13756   // Test LoadIC.
13757   for (int i = 0; i < 2; i++) {
13758     LocalContext context;
13759     context->Global()->Set(v8_str("tmp"), v8::True());
13760     context->Global()->Delete(v8_str("tmp"));
13761     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
13762   }
13763   // Test CallIC.
13764   for (int i = 0; i < 2; i++) {
13765     LocalContext context;
13766     context->Global()->Set(v8_str("tmp"), v8::True());
13767     context->Global()->Delete(v8_str("tmp"));
13768     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
13769   }
13770 }
13771
13772
13773 // Test that cross-context new calls use the context of the callee to
13774 // create the new JavaScript object.
13775 THREADED_TEST(CrossContextNew) {
13776   v8::Isolate* isolate = v8::Isolate::GetCurrent();
13777   v8::HandleScope scope(isolate);
13778   v8::Local<Context> context0 = Context::New(isolate);
13779   v8::Local<Context> context1 = Context::New(isolate);
13780
13781   // Allow cross-domain access.
13782   Local<String> token = v8_str("<security token>");
13783   context0->SetSecurityToken(token);
13784   context1->SetSecurityToken(token);
13785
13786   // Set an 'x' property on the Object prototype and define a
13787   // constructor function in context0.
13788   context0->Enter();
13789   CompileRun("Object.prototype.x = 42; function C() {};");
13790   context0->Exit();
13791
13792   // Call the constructor function from context0 and check that the
13793   // result has the 'x' property.
13794   context1->Enter();
13795   context1->Global()->Set(v8_str("other"), context0->Global());
13796   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
13797   CHECK(value->IsInt32());
13798   CHECK_EQ(42, value->Int32Value());
13799   context1->Exit();
13800 }
13801
13802
13803 class RegExpInterruptTest {
13804  public:
13805   RegExpInterruptTest() : block_(NULL) {}
13806   ~RegExpInterruptTest() { delete block_; }
13807   void RunTest() {
13808     block_ = i::OS::CreateSemaphore(0);
13809     gc_count_ = 0;
13810     gc_during_regexp_ = 0;
13811     regexp_success_ = false;
13812     gc_success_ = false;
13813     GCThread gc_thread(this);
13814     gc_thread.Start();
13815     v8::Locker::StartPreemption(1);
13816
13817     LongRunningRegExp();
13818     {
13819       v8::Unlocker unlock(CcTest::default_isolate());
13820       gc_thread.Join();
13821     }
13822     v8::Locker::StopPreemption();
13823     CHECK(regexp_success_);
13824     CHECK(gc_success_);
13825   }
13826
13827  private:
13828   // Number of garbage collections required.
13829   static const int kRequiredGCs = 5;
13830
13831   class GCThread : public i::Thread {
13832    public:
13833     explicit GCThread(RegExpInterruptTest* test)
13834         : Thread("GCThread"), test_(test) {}
13835     virtual void Run() {
13836       test_->CollectGarbage();
13837     }
13838    private:
13839      RegExpInterruptTest* test_;
13840   };
13841
13842   void CollectGarbage() {
13843     block_->Wait();
13844     while (gc_during_regexp_ < kRequiredGCs) {
13845       {
13846         v8::Locker lock(CcTest::default_isolate());
13847         // TODO(lrn): Perhaps create some garbage before collecting.
13848         HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13849         gc_count_++;
13850       }
13851       i::OS::Sleep(1);
13852     }
13853     gc_success_ = true;
13854   }
13855
13856   void LongRunningRegExp() {
13857     block_->Signal();  // Enable garbage collection thread on next preemption.
13858     int rounds = 0;
13859     while (gc_during_regexp_ < kRequiredGCs) {
13860       int gc_before = gc_count_;
13861       {
13862         // Match 15-30 "a"'s against 14 and a "b".
13863         const char* c_source =
13864             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
13865             ".exec('aaaaaaaaaaaaaaab') === null";
13866         Local<String> source = String::New(c_source);
13867         Local<Script> script = Script::Compile(source);
13868         Local<Value> result = script->Run();
13869         if (!result->BooleanValue()) {
13870           gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
13871           return;
13872         }
13873       }
13874       {
13875         // Match 15-30 "a"'s against 15 and a "b".
13876         const char* c_source =
13877             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
13878             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
13879         Local<String> source = String::New(c_source);
13880         Local<Script> script = Script::Compile(source);
13881         Local<Value> result = script->Run();
13882         if (!result->BooleanValue()) {
13883           gc_during_regexp_ = kRequiredGCs;
13884           return;
13885         }
13886       }
13887       int gc_after = gc_count_;
13888       gc_during_regexp_ += gc_after - gc_before;
13889       rounds++;
13890       i::OS::Sleep(1);
13891     }
13892     regexp_success_ = true;
13893   }
13894
13895   i::Semaphore* block_;
13896   int gc_count_;
13897   int gc_during_regexp_;
13898   bool regexp_success_;
13899   bool gc_success_;
13900 };
13901
13902
13903 // Test that a regular expression execution can be interrupted and
13904 // survive a garbage collection.
13905 TEST(RegExpInterruption) {
13906   v8::Locker lock(CcTest::default_isolate());
13907   v8::V8::Initialize();
13908   v8::HandleScope scope(CcTest::default_isolate());
13909   Local<Context> local_env;
13910   {
13911     LocalContext env;
13912     local_env = env.local();
13913   }
13914
13915   // Local context should still be live.
13916   CHECK(!local_env.IsEmpty());
13917   local_env->Enter();
13918
13919   // Should complete without problems.
13920   RegExpInterruptTest().RunTest();
13921
13922   local_env->Exit();
13923 }
13924
13925
13926 class ApplyInterruptTest {
13927  public:
13928   ApplyInterruptTest() : block_(NULL) {}
13929   ~ApplyInterruptTest() { delete block_; }
13930   void RunTest() {
13931     block_ = i::OS::CreateSemaphore(0);
13932     gc_count_ = 0;
13933     gc_during_apply_ = 0;
13934     apply_success_ = false;
13935     gc_success_ = false;
13936     GCThread gc_thread(this);
13937     gc_thread.Start();
13938     v8::Locker::StartPreemption(1);
13939
13940     LongRunningApply();
13941     {
13942       v8::Unlocker unlock(CcTest::default_isolate());
13943       gc_thread.Join();
13944     }
13945     v8::Locker::StopPreemption();
13946     CHECK(apply_success_);
13947     CHECK(gc_success_);
13948   }
13949
13950  private:
13951   // Number of garbage collections required.
13952   static const int kRequiredGCs = 2;
13953
13954   class GCThread : public i::Thread {
13955    public:
13956     explicit GCThread(ApplyInterruptTest* test)
13957         : Thread("GCThread"), test_(test) {}
13958     virtual void Run() {
13959       test_->CollectGarbage();
13960     }
13961    private:
13962      ApplyInterruptTest* test_;
13963   };
13964
13965   void CollectGarbage() {
13966     block_->Wait();
13967     while (gc_during_apply_ < kRequiredGCs) {
13968       {
13969         v8::Locker lock(CcTest::default_isolate());
13970         HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13971         gc_count_++;
13972       }
13973       i::OS::Sleep(1);
13974     }
13975     gc_success_ = true;
13976   }
13977
13978   void LongRunningApply() {
13979     block_->Signal();
13980     int rounds = 0;
13981     while (gc_during_apply_ < kRequiredGCs) {
13982       int gc_before = gc_count_;
13983       {
13984         const char* c_source =
13985             "function do_very_little(bar) {"
13986             "  this.foo = bar;"
13987             "}"
13988             "for (var i = 0; i < 100000; i++) {"
13989             "  do_very_little.apply(this, ['bar']);"
13990             "}";
13991         Local<String> source = String::New(c_source);
13992         Local<Script> script = Script::Compile(source);
13993         Local<Value> result = script->Run();
13994         // Check that no exception was thrown.
13995         CHECK(!result.IsEmpty());
13996       }
13997       int gc_after = gc_count_;
13998       gc_during_apply_ += gc_after - gc_before;
13999       rounds++;
14000     }
14001     apply_success_ = true;
14002   }
14003
14004   i::Semaphore* block_;
14005   int gc_count_;
14006   int gc_during_apply_;
14007   bool apply_success_;
14008   bool gc_success_;
14009 };
14010
14011
14012 // Test that nothing bad happens if we get a preemption just when we were
14013 // about to do an apply().
14014 TEST(ApplyInterruption) {
14015   v8::Locker lock(CcTest::default_isolate());
14016   v8::V8::Initialize();
14017   v8::HandleScope scope(CcTest::default_isolate());
14018   Local<Context> local_env;
14019   {
14020     LocalContext env;
14021     local_env = env.local();
14022   }
14023
14024   // Local context should still be live.
14025   CHECK(!local_env.IsEmpty());
14026   local_env->Enter();
14027
14028   // Should complete without problems.
14029   ApplyInterruptTest().RunTest();
14030
14031   local_env->Exit();
14032 }
14033
14034
14035 // Verify that we can clone an object
14036 TEST(ObjectClone) {
14037   LocalContext env;
14038   v8::HandleScope scope(env->GetIsolate());
14039
14040   const char* sample =
14041     "var rv = {};"      \
14042     "rv.alpha = 'hello';" \
14043     "rv.beta = 123;"     \
14044     "rv;";
14045
14046   // Create an object, verify basics.
14047   Local<Value> val = CompileRun(sample);
14048   CHECK(val->IsObject());
14049   Local<v8::Object> obj = val.As<v8::Object>();
14050   obj->Set(v8_str("gamma"), v8_str("cloneme"));
14051
14052   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14053   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14054   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14055
14056   // Clone it.
14057   Local<v8::Object> clone = obj->Clone();
14058   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14059   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
14060   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14061
14062   // Set a property on the clone, verify each object.
14063   clone->Set(v8_str("beta"), v8::Integer::New(456));
14064   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14065   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
14066 }
14067
14068
14069 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14070  public:
14071   explicit AsciiVectorResource(i::Vector<const char> vector)
14072       : data_(vector) {}
14073   virtual ~AsciiVectorResource() {}
14074   virtual size_t length() const { return data_.length(); }
14075   virtual const char* data() const { return data_.start(); }
14076  private:
14077   i::Vector<const char> data_;
14078 };
14079
14080
14081 class UC16VectorResource : public v8::String::ExternalStringResource {
14082  public:
14083   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14084       : data_(vector) {}
14085   virtual ~UC16VectorResource() {}
14086   virtual size_t length() const { return data_.length(); }
14087   virtual const i::uc16* data() const { return data_.start(); }
14088  private:
14089   i::Vector<const i::uc16> data_;
14090 };
14091
14092
14093 static void MorphAString(i::String* string,
14094                          AsciiVectorResource* ascii_resource,
14095                          UC16VectorResource* uc16_resource) {
14096   CHECK(i::StringShape(string).IsExternal());
14097   if (string->IsOneByteRepresentation()) {
14098     // Check old map is not internalized or long.
14099     CHECK(string->map() == HEAP->external_ascii_string_map());
14100     // Morph external string to be TwoByte string.
14101     string->set_map(HEAP->external_string_map());
14102     i::ExternalTwoByteString* morphed =
14103          i::ExternalTwoByteString::cast(string);
14104     morphed->set_resource(uc16_resource);
14105   } else {
14106     // Check old map is not internalized or long.
14107     CHECK(string->map() == HEAP->external_string_map());
14108     // Morph external string to be ASCII string.
14109     string->set_map(HEAP->external_ascii_string_map());
14110     i::ExternalAsciiString* morphed =
14111          i::ExternalAsciiString::cast(string);
14112     morphed->set_resource(ascii_resource);
14113   }
14114 }
14115
14116
14117 // Test that we can still flatten a string if the components it is built up
14118 // from have been turned into 16 bit strings in the mean time.
14119 THREADED_TEST(MorphCompositeStringTest) {
14120   char utf_buffer[129];
14121   const char* c_string = "Now is the time for all good men"
14122                          " to come to the aid of the party";
14123   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14124   {
14125     LocalContext env;
14126     i::Factory* factory = i::Isolate::Current()->factory();
14127     v8::HandleScope scope(env->GetIsolate());
14128     AsciiVectorResource ascii_resource(
14129         i::Vector<const char>(c_string, i::StrLength(c_string)));
14130     UC16VectorResource uc16_resource(
14131         i::Vector<const uint16_t>(two_byte_string,
14132                                   i::StrLength(c_string)));
14133
14134     Local<String> lhs(v8::Utils::ToLocal(
14135         factory->NewExternalStringFromAscii(&ascii_resource)));
14136     Local<String> rhs(v8::Utils::ToLocal(
14137         factory->NewExternalStringFromAscii(&ascii_resource)));
14138
14139     env->Global()->Set(v8_str("lhs"), lhs);
14140     env->Global()->Set(v8_str("rhs"), rhs);
14141
14142     CompileRun(
14143         "var cons = lhs + rhs;"
14144         "var slice = lhs.substring(1, lhs.length - 1);"
14145         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
14146
14147     CHECK(lhs->IsOneByte());
14148     CHECK(rhs->IsOneByte());
14149
14150     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
14151     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
14152
14153     // This should UTF-8 without flattening, since everything is ASCII.
14154     Handle<String> cons = v8_compile("cons")->Run().As<String>();
14155     CHECK_EQ(128, cons->Utf8Length());
14156     int nchars = -1;
14157     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
14158     CHECK_EQ(128, nchars);
14159     CHECK_EQ(0, strcmp(
14160         utf_buffer,
14161         "Now is the time for all good men to come to the aid of the party"
14162         "Now is the time for all good men to come to the aid of the party"));
14163
14164     // Now do some stuff to make sure the strings are flattened, etc.
14165     CompileRun(
14166         "/[^a-z]/.test(cons);"
14167         "/[^a-z]/.test(slice);"
14168         "/[^a-z]/.test(slice_on_cons);");
14169     const char* expected_cons =
14170         "Now is the time for all good men to come to the aid of the party"
14171         "Now is the time for all good men to come to the aid of the party";
14172     const char* expected_slice =
14173         "ow is the time for all good men to come to the aid of the part";
14174     const char* expected_slice_on_cons =
14175         "ow is the time for all good men to come to the aid of the party"
14176         "Now is the time for all good men to come to the aid of the part";
14177     CHECK_EQ(String::New(expected_cons),
14178              env->Global()->Get(v8_str("cons")));
14179     CHECK_EQ(String::New(expected_slice),
14180              env->Global()->Get(v8_str("slice")));
14181     CHECK_EQ(String::New(expected_slice_on_cons),
14182              env->Global()->Get(v8_str("slice_on_cons")));
14183   }
14184   i::DeleteArray(two_byte_string);
14185 }
14186
14187
14188 TEST(CompileExternalTwoByteSource) {
14189   LocalContext context;
14190   v8::HandleScope scope(context->GetIsolate());
14191
14192   // This is a very short list of sources, which currently is to check for a
14193   // regression caused by r2703.
14194   const char* ascii_sources[] = {
14195     "0.5",
14196     "-0.5",   // This mainly testes PushBack in the Scanner.
14197     "--0.5",  // This mainly testes PushBack in the Scanner.
14198     NULL
14199   };
14200
14201   // Compile the sources as external two byte strings.
14202   for (int i = 0; ascii_sources[i] != NULL; i++) {
14203     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
14204     UC16VectorResource uc16_resource(
14205         i::Vector<const uint16_t>(two_byte_string,
14206                                   i::StrLength(ascii_sources[i])));
14207     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
14208     v8::Script::Compile(source);
14209     i::DeleteArray(two_byte_string);
14210   }
14211 }
14212
14213
14214 class RegExpStringModificationTest {
14215  public:
14216   RegExpStringModificationTest()
14217       : block_(i::OS::CreateSemaphore(0)),
14218         morphs_(0),
14219         morphs_during_regexp_(0),
14220         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
14221         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
14222   ~RegExpStringModificationTest() { delete block_; }
14223   void RunTest() {
14224     i::Factory* factory = i::Isolate::Current()->factory();
14225
14226     regexp_success_ = false;
14227     morph_success_ = false;
14228
14229     // Initialize the contents of two_byte_content_ to be a uc16 representation
14230     // of "aaaaaaaaaaaaaab".
14231     for (int i = 0; i < 14; i++) {
14232       two_byte_content_[i] = 'a';
14233     }
14234     two_byte_content_[14] = 'b';
14235
14236     // Create the input string for the regexp - the one we are going to change
14237     // properties of.
14238     input_ = factory->NewExternalStringFromAscii(&ascii_resource_);
14239
14240     // Inject the input as a global variable.
14241     i::Handle<i::String> input_name =
14242         factory->NewStringFromAscii(i::Vector<const char>("input", 5));
14243     i::Isolate::Current()->native_context()->global_object()->SetProperty(
14244         *input_name,
14245         *input_,
14246         NONE,
14247         i::kNonStrictMode)->ToObjectChecked();
14248
14249     MorphThread morph_thread(this);
14250     morph_thread.Start();
14251     v8::Locker::StartPreemption(1);
14252     LongRunningRegExp();
14253     {
14254       v8::Unlocker unlock(CcTest::default_isolate());
14255       morph_thread.Join();
14256     }
14257     v8::Locker::StopPreemption();
14258     CHECK(regexp_success_);
14259     CHECK(morph_success_);
14260   }
14261
14262  private:
14263   // Number of string modifications required.
14264   static const int kRequiredModifications = 5;
14265   static const int kMaxModifications = 100;
14266
14267   class MorphThread : public i::Thread {
14268    public:
14269     explicit MorphThread(RegExpStringModificationTest* test)
14270         : Thread("MorphThread"), test_(test) {}
14271     virtual void Run() {
14272       test_->MorphString();
14273     }
14274    private:
14275      RegExpStringModificationTest* test_;
14276   };
14277
14278   void MorphString() {
14279     block_->Wait();
14280     while (morphs_during_regexp_ < kRequiredModifications &&
14281            morphs_ < kMaxModifications) {
14282       {
14283         v8::Locker lock(CcTest::default_isolate());
14284         // Swap string between ascii and two-byte representation.
14285         i::String* string = *input_;
14286         MorphAString(string, &ascii_resource_, &uc16_resource_);
14287         morphs_++;
14288       }
14289       i::OS::Sleep(1);
14290     }
14291     morph_success_ = true;
14292   }
14293
14294   void LongRunningRegExp() {
14295     block_->Signal();  // Enable morphing thread on next preemption.
14296     while (morphs_during_regexp_ < kRequiredModifications &&
14297            morphs_ < kMaxModifications) {
14298       int morphs_before = morphs_;
14299       {
14300         v8::HandleScope scope(v8::Isolate::GetCurrent());
14301         // Match 15-30 "a"'s against 14 and a "b".
14302         const char* c_source =
14303             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
14304             ".exec(input) === null";
14305         Local<String> source = String::New(c_source);
14306         Local<Script> script = Script::Compile(source);
14307         Local<Value> result = script->Run();
14308         CHECK(result->IsTrue());
14309       }
14310       int morphs_after = morphs_;
14311       morphs_during_regexp_ += morphs_after - morphs_before;
14312     }
14313     regexp_success_ = true;
14314   }
14315
14316   i::uc16 two_byte_content_[15];
14317   i::Semaphore* block_;
14318   int morphs_;
14319   int morphs_during_regexp_;
14320   bool regexp_success_;
14321   bool morph_success_;
14322   i::Handle<i::String> input_;
14323   AsciiVectorResource ascii_resource_;
14324   UC16VectorResource uc16_resource_;
14325 };
14326
14327
14328 // Test that a regular expression execution can be interrupted and
14329 // the string changed without failing.
14330 TEST(RegExpStringModification) {
14331   v8::Locker lock(CcTest::default_isolate());
14332   v8::V8::Initialize();
14333   v8::HandleScope scope(CcTest::default_isolate());
14334   Local<Context> local_env;
14335   {
14336     LocalContext env;
14337     local_env = env.local();
14338   }
14339
14340   // Local context should still be live.
14341   CHECK(!local_env.IsEmpty());
14342   local_env->Enter();
14343
14344   // Should complete without problems.
14345   RegExpStringModificationTest().RunTest();
14346
14347   local_env->Exit();
14348 }
14349
14350
14351 // Test that we cannot set a property on the global object if there
14352 // is a read-only property in the prototype chain.
14353 TEST(ReadOnlyPropertyInGlobalProto) {
14354   i::FLAG_es5_readonly = true;
14355   v8::HandleScope scope(v8::Isolate::GetCurrent());
14356   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14357   LocalContext context(0, templ);
14358   v8::Handle<v8::Object> global = context->Global();
14359   v8::Handle<v8::Object> global_proto =
14360       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
14361   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
14362   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
14363   // Check without 'eval' or 'with'.
14364   v8::Handle<v8::Value> res =
14365       CompileRun("function f() { x = 42; return x; }; f()");
14366   CHECK_EQ(v8::Integer::New(0), res);
14367   // Check with 'eval'.
14368   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
14369   CHECK_EQ(v8::Integer::New(0), res);
14370   // Check with 'with'.
14371   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
14372   CHECK_EQ(v8::Integer::New(0), res);
14373 }
14374
14375 static int force_set_set_count = 0;
14376 static int force_set_get_count = 0;
14377 bool pass_on_get = false;
14378
14379 static void ForceSetGetter(v8::Local<v8::String> name,
14380                            const v8::PropertyCallbackInfo<v8::Value>& info) {
14381   force_set_get_count++;
14382   if (pass_on_get) {
14383     return;
14384   }
14385   info.GetReturnValue().Set(3);
14386 }
14387
14388 static void ForceSetSetter(v8::Local<v8::String> name,
14389                            v8::Local<v8::Value> value,
14390                            const v8::PropertyCallbackInfo<void>& info) {
14391   force_set_set_count++;
14392 }
14393
14394 static void ForceSetInterceptSetter(
14395     v8::Local<v8::String> name,
14396     v8::Local<v8::Value> value,
14397     const v8::PropertyCallbackInfo<v8::Value>& info) {
14398   force_set_set_count++;
14399   info.GetReturnValue().SetUndefined();
14400 }
14401
14402
14403 TEST(ForceSet) {
14404   force_set_get_count = 0;
14405   force_set_set_count = 0;
14406   pass_on_get = false;
14407
14408   v8::HandleScope scope(v8::Isolate::GetCurrent());
14409   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14410   v8::Handle<v8::String> access_property = v8::String::New("a");
14411   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
14412   LocalContext context(NULL, templ);
14413   v8::Handle<v8::Object> global = context->Global();
14414
14415   // Ordinary properties
14416   v8::Handle<v8::String> simple_property = v8::String::New("p");
14417   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
14418   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14419   // This should fail because the property is read-only
14420   global->Set(simple_property, v8::Int32::New(5));
14421   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14422   // This should succeed even though the property is read-only
14423   global->ForceSet(simple_property, v8::Int32::New(6));
14424   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
14425
14426   // Accessors
14427   CHECK_EQ(0, force_set_set_count);
14428   CHECK_EQ(0, force_set_get_count);
14429   CHECK_EQ(3, global->Get(access_property)->Int32Value());
14430   // CHECK_EQ the property shouldn't override it, just call the setter
14431   // which in this case does nothing.
14432   global->Set(access_property, v8::Int32::New(7));
14433   CHECK_EQ(3, global->Get(access_property)->Int32Value());
14434   CHECK_EQ(1, force_set_set_count);
14435   CHECK_EQ(2, force_set_get_count);
14436   // Forcing the property to be set should override the accessor without
14437   // calling it
14438   global->ForceSet(access_property, v8::Int32::New(8));
14439   CHECK_EQ(8, global->Get(access_property)->Int32Value());
14440   CHECK_EQ(1, force_set_set_count);
14441   CHECK_EQ(2, force_set_get_count);
14442 }
14443
14444
14445 TEST(ForceSetWithInterceptor) {
14446   force_set_get_count = 0;
14447   force_set_set_count = 0;
14448   pass_on_get = false;
14449
14450   v8::HandleScope scope(v8::Isolate::GetCurrent());
14451   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14452   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
14453   LocalContext context(NULL, templ);
14454   v8::Handle<v8::Object> global = context->Global();
14455
14456   v8::Handle<v8::String> some_property = v8::String::New("a");
14457   CHECK_EQ(0, force_set_set_count);
14458   CHECK_EQ(0, force_set_get_count);
14459   CHECK_EQ(3, global->Get(some_property)->Int32Value());
14460   // Setting the property shouldn't override it, just call the setter
14461   // which in this case does nothing.
14462   global->Set(some_property, v8::Int32::New(7));
14463   CHECK_EQ(3, global->Get(some_property)->Int32Value());
14464   CHECK_EQ(1, force_set_set_count);
14465   CHECK_EQ(2, force_set_get_count);
14466   // Getting the property when the interceptor returns an empty handle
14467   // should yield undefined, since the property isn't present on the
14468   // object itself yet.
14469   pass_on_get = true;
14470   CHECK(global->Get(some_property)->IsUndefined());
14471   CHECK_EQ(1, force_set_set_count);
14472   CHECK_EQ(3, force_set_get_count);
14473   // Forcing the property to be set should cause the value to be
14474   // set locally without calling the interceptor.
14475   global->ForceSet(some_property, v8::Int32::New(8));
14476   CHECK_EQ(8, global->Get(some_property)->Int32Value());
14477   CHECK_EQ(1, force_set_set_count);
14478   CHECK_EQ(4, force_set_get_count);
14479   // Reenabling the interceptor should cause it to take precedence over
14480   // the property
14481   pass_on_get = false;
14482   CHECK_EQ(3, global->Get(some_property)->Int32Value());
14483   CHECK_EQ(1, force_set_set_count);
14484   CHECK_EQ(5, force_set_get_count);
14485   // The interceptor should also work for other properties
14486   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
14487   CHECK_EQ(1, force_set_set_count);
14488   CHECK_EQ(6, force_set_get_count);
14489 }
14490
14491
14492 THREADED_TEST(ForceDelete) {
14493   v8::HandleScope scope(v8::Isolate::GetCurrent());
14494   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14495   LocalContext context(NULL, templ);
14496   v8::Handle<v8::Object> global = context->Global();
14497
14498   // Ordinary properties
14499   v8::Handle<v8::String> simple_property = v8::String::New("p");
14500   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
14501   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14502   // This should fail because the property is dont-delete.
14503   CHECK(!global->Delete(simple_property));
14504   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14505   // This should succeed even though the property is dont-delete.
14506   CHECK(global->ForceDelete(simple_property));
14507   CHECK(global->Get(simple_property)->IsUndefined());
14508 }
14509
14510
14511 static int force_delete_interceptor_count = 0;
14512 static bool pass_on_delete = false;
14513
14514
14515 static void ForceDeleteDeleter(
14516     v8::Local<v8::String> name,
14517     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
14518   force_delete_interceptor_count++;
14519   if (pass_on_delete) return;
14520   info.GetReturnValue().Set(true);
14521 }
14522
14523
14524 THREADED_TEST(ForceDeleteWithInterceptor) {
14525   force_delete_interceptor_count = 0;
14526   pass_on_delete = false;
14527
14528   v8::HandleScope scope(v8::Isolate::GetCurrent());
14529   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14530   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
14531   LocalContext context(NULL, templ);
14532   v8::Handle<v8::Object> global = context->Global();
14533
14534   v8::Handle<v8::String> some_property = v8::String::New("a");
14535   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
14536
14537   // Deleting a property should get intercepted and nothing should
14538   // happen.
14539   CHECK_EQ(0, force_delete_interceptor_count);
14540   CHECK(global->Delete(some_property));
14541   CHECK_EQ(1, force_delete_interceptor_count);
14542   CHECK_EQ(42, global->Get(some_property)->Int32Value());
14543   // Deleting the property when the interceptor returns an empty
14544   // handle should not delete the property since it is DontDelete.
14545   pass_on_delete = true;
14546   CHECK(!global->Delete(some_property));
14547   CHECK_EQ(2, force_delete_interceptor_count);
14548   CHECK_EQ(42, global->Get(some_property)->Int32Value());
14549   // Forcing the property to be deleted should delete the value
14550   // without calling the interceptor.
14551   CHECK(global->ForceDelete(some_property));
14552   CHECK(global->Get(some_property)->IsUndefined());
14553   CHECK_EQ(2, force_delete_interceptor_count);
14554 }
14555
14556
14557 // Make sure that forcing a delete invalidates any IC stubs, so we
14558 // don't read the hole value.
14559 THREADED_TEST(ForceDeleteIC) {
14560   LocalContext context;
14561   v8::HandleScope scope(context->GetIsolate());
14562   // Create a DontDelete variable on the global object.
14563   CompileRun("this.__proto__ = { foo: 'horse' };"
14564              "var foo = 'fish';"
14565              "function f() { return foo.length; }");
14566   // Initialize the IC for foo in f.
14567   CompileRun("for (var i = 0; i < 4; i++) f();");
14568   // Make sure the value of foo is correct before the deletion.
14569   CHECK_EQ(4, CompileRun("f()")->Int32Value());
14570   // Force the deletion of foo.
14571   CHECK(context->Global()->ForceDelete(v8_str("foo")));
14572   // Make sure the value for foo is read from the prototype, and that
14573   // we don't get in trouble with reading the deleted cell value
14574   // sentinel.
14575   CHECK_EQ(5, CompileRun("f()")->Int32Value());
14576 }
14577
14578
14579 TEST(InlinedFunctionAcrossContexts) {
14580   i::FLAG_allow_natives_syntax = true;
14581   v8::Isolate* isolate = v8::Isolate::GetCurrent();
14582   v8::HandleScope outer_scope(isolate);
14583   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
14584   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
14585   ctx1->Enter();
14586
14587   {
14588     v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
14589     CompileRun("var G = 42; function foo() { return G; }");
14590     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
14591     ctx2->Enter();
14592     ctx2->Global()->Set(v8_str("o"), foo);
14593     v8::Local<v8::Value> res = CompileRun(
14594         "function f() { return o(); }"
14595         "for (var i = 0; i < 10; ++i) f();"
14596         "%OptimizeFunctionOnNextCall(f);"
14597         "f();");
14598     CHECK_EQ(42, res->Int32Value());
14599     ctx2->Exit();
14600     v8::Handle<v8::String> G_property = v8::String::New("G");
14601     CHECK(ctx1->Global()->ForceDelete(G_property));
14602     ctx2->Enter();
14603     ExpectString(
14604         "(function() {"
14605         "  try {"
14606         "    return f();"
14607         "  } catch(e) {"
14608         "    return e.toString();"
14609         "  }"
14610         " })()",
14611         "ReferenceError: G is not defined");
14612     ctx2->Exit();
14613     ctx1->Exit();
14614   }
14615 }
14616
14617
14618 static v8::Local<Context> calling_context0;
14619 static v8::Local<Context> calling_context1;
14620 static v8::Local<Context> calling_context2;
14621
14622
14623 // Check that the call to the callback is initiated in
14624 // calling_context2, the directly calling context is calling_context1
14625 // and the callback itself is in calling_context0.
14626 static void GetCallingContextCallback(
14627     const v8::FunctionCallbackInfo<v8::Value>& args) {
14628   ApiTestFuzzer::Fuzz();
14629   CHECK(Context::GetCurrent() == calling_context0);
14630   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
14631   CHECK(Context::GetCalling() == calling_context1);
14632   CHECK(Context::GetEntered() == calling_context2);
14633   args.GetReturnValue().Set(42);
14634 }
14635
14636
14637 THREADED_TEST(GetCurrentContextWhenNotInContext) {
14638   i::Isolate* isolate = i::Isolate::Current();
14639   CHECK(isolate != NULL);
14640   CHECK(isolate->context() == NULL);
14641   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
14642   v8::HandleScope scope(v8_isolate);
14643   // The following should not crash, but return an empty handle.
14644   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
14645   CHECK(current.IsEmpty());
14646 }
14647
14648
14649 THREADED_TEST(GetCallingContext) {
14650   v8::Isolate* isolate = v8::Isolate::GetCurrent();
14651   v8::HandleScope scope(isolate);
14652
14653   Local<Context> calling_context0(Context::New(isolate));
14654   Local<Context> calling_context1(Context::New(isolate));
14655   Local<Context> calling_context2(Context::New(isolate));
14656   ::calling_context0 = calling_context0;
14657   ::calling_context1 = calling_context1;
14658   ::calling_context2 = calling_context2;
14659
14660   // Allow cross-domain access.
14661   Local<String> token = v8_str("<security token>");
14662   calling_context0->SetSecurityToken(token);
14663   calling_context1->SetSecurityToken(token);
14664   calling_context2->SetSecurityToken(token);
14665
14666   // Create an object with a C++ callback in context0.
14667   calling_context0->Enter();
14668   Local<v8::FunctionTemplate> callback_templ =
14669       v8::FunctionTemplate::New(GetCallingContextCallback);
14670   calling_context0->Global()->Set(v8_str("callback"),
14671                                   callback_templ->GetFunction());
14672   calling_context0->Exit();
14673
14674   // Expose context0 in context1 and set up a function that calls the
14675   // callback function.
14676   calling_context1->Enter();
14677   calling_context1->Global()->Set(v8_str("context0"),
14678                                   calling_context0->Global());
14679   CompileRun("function f() { context0.callback() }");
14680   calling_context1->Exit();
14681
14682   // Expose context1 in context2 and call the callback function in
14683   // context0 indirectly through f in context1.
14684   calling_context2->Enter();
14685   calling_context2->Global()->Set(v8_str("context1"),
14686                                   calling_context1->Global());
14687   CompileRun("context1.f()");
14688   calling_context2->Exit();
14689   ::calling_context0.Clear();
14690   ::calling_context1.Clear();
14691   ::calling_context2.Clear();
14692 }
14693
14694
14695 // Check that a variable declaration with no explicit initialization
14696 // value does shadow an existing property in the prototype chain.
14697 THREADED_TEST(InitGlobalVarInProtoChain) {
14698   i::FLAG_es52_globals = true;
14699   LocalContext context;
14700   v8::HandleScope scope(context->GetIsolate());
14701   // Introduce a variable in the prototype chain.
14702   CompileRun("__proto__.x = 42");
14703   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
14704   CHECK(!result->IsUndefined());
14705   CHECK_EQ(43, result->Int32Value());
14706 }
14707
14708
14709 // Regression test for issue 398.
14710 // If a function is added to an object, creating a constant function
14711 // field, and the result is cloned, replacing the constant function on the
14712 // original should not affect the clone.
14713 // See http://code.google.com/p/v8/issues/detail?id=398
14714 THREADED_TEST(ReplaceConstantFunction) {
14715   LocalContext context;
14716   v8::HandleScope scope(context->GetIsolate());
14717   v8::Handle<v8::Object> obj = v8::Object::New();
14718   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
14719   v8::Handle<v8::String> foo_string = v8::String::New("foo");
14720   obj->Set(foo_string, func_templ->GetFunction());
14721   v8::Handle<v8::Object> obj_clone = obj->Clone();
14722   obj_clone->Set(foo_string, v8::String::New("Hello"));
14723   CHECK(!obj->Get(foo_string)->IsUndefined());
14724 }
14725
14726
14727 // Regression test for http://crbug.com/16276.
14728 THREADED_TEST(Regress16276) {
14729   LocalContext context;
14730   v8::HandleScope scope(context->GetIsolate());
14731   // Force the IC in f to be a dictionary load IC.
14732   CompileRun("function f(obj) { return obj.x; }\n"
14733              "var obj = { x: { foo: 42 }, y: 87 };\n"
14734              "var x = obj.x;\n"
14735              "delete obj.y;\n"
14736              "for (var i = 0; i < 5; i++) f(obj);");
14737   // Detach the global object to make 'this' refer directly to the
14738   // global object (not the proxy), and make sure that the dictionary
14739   // load IC doesn't mess up loading directly from the global object.
14740   context->DetachGlobal();
14741   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
14742 }
14743
14744
14745 THREADED_TEST(PixelArray) {
14746   LocalContext context;
14747   i::Factory* factory = i::Isolate::Current()->factory();
14748   v8::HandleScope scope(context->GetIsolate());
14749   const int kElementCount = 260;
14750   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
14751   i::Handle<i::ExternalPixelArray> pixels =
14752       i::Handle<i::ExternalPixelArray>::cast(
14753           factory->NewExternalArray(kElementCount,
14754                                     v8::kExternalPixelArray,
14755                                     pixel_data));
14756   // Force GC to trigger verification.
14757   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14758   for (int i = 0; i < kElementCount; i++) {
14759     pixels->set(i, i % 256);
14760   }
14761   // Force GC to trigger verification.
14762   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14763   for (int i = 0; i < kElementCount; i++) {
14764     CHECK_EQ(i % 256, pixels->get_scalar(i));
14765     CHECK_EQ(i % 256, pixel_data[i]);
14766   }
14767
14768   v8::Handle<v8::Object> obj = v8::Object::New();
14769   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14770   // Set the elements to be the pixels.
14771   // jsobj->set_elements(*pixels);
14772   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
14773   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14774   obj->Set(v8_str("field"), v8::Int32::New(1503));
14775   context->Global()->Set(v8_str("pixels"), obj);
14776   v8::Handle<v8::Value> result = CompileRun("pixels.field");
14777   CHECK_EQ(1503, result->Int32Value());
14778   result = CompileRun("pixels[1]");
14779   CHECK_EQ(1, result->Int32Value());
14780
14781   result = CompileRun("var sum = 0;"
14782                       "for (var i = 0; i < 8; i++) {"
14783                       "  sum += pixels[i] = pixels[i] = -i;"
14784                       "}"
14785                       "sum;");
14786   CHECK_EQ(-28, result->Int32Value());
14787
14788   result = CompileRun("var sum = 0;"
14789                       "for (var i = 0; i < 8; i++) {"
14790                       "  sum += pixels[i] = pixels[i] = 0;"
14791                       "}"
14792                       "sum;");
14793   CHECK_EQ(0, result->Int32Value());
14794
14795   result = CompileRun("var sum = 0;"
14796                       "for (var i = 0; i < 8; i++) {"
14797                       "  sum += pixels[i] = pixels[i] = 255;"
14798                       "}"
14799                       "sum;");
14800   CHECK_EQ(8 * 255, result->Int32Value());
14801
14802   result = CompileRun("var sum = 0;"
14803                       "for (var i = 0; i < 8; i++) {"
14804                       "  sum += pixels[i] = pixels[i] = 256 + i;"
14805                       "}"
14806                       "sum;");
14807   CHECK_EQ(2076, result->Int32Value());
14808
14809   result = CompileRun("var sum = 0;"
14810                       "for (var i = 0; i < 8; i++) {"
14811                       "  sum += pixels[i] = pixels[i] = i;"
14812                       "}"
14813                       "sum;");
14814   CHECK_EQ(28, result->Int32Value());
14815
14816   result = CompileRun("var sum = 0;"
14817                       "for (var i = 0; i < 8; i++) {"
14818                       "  sum += pixels[i];"
14819                       "}"
14820                       "sum;");
14821   CHECK_EQ(28, result->Int32Value());
14822
14823   i::Handle<i::Smi> value(i::Smi::FromInt(2),
14824                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
14825   i::Handle<i::Object> no_failure;
14826   no_failure =
14827       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
14828   ASSERT(!no_failure.is_null());
14829   i::USE(no_failure);
14830   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14831   *value.location() = i::Smi::FromInt(256);
14832   no_failure =
14833       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
14834   ASSERT(!no_failure.is_null());
14835   i::USE(no_failure);
14836   CHECK_EQ(255,
14837            i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14838   *value.location() = i::Smi::FromInt(-1);
14839   no_failure =
14840       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
14841   ASSERT(!no_failure.is_null());
14842   i::USE(no_failure);
14843   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14844
14845   result = CompileRun("for (var i = 0; i < 8; i++) {"
14846                       "  pixels[i] = (i * 65) - 109;"
14847                       "}"
14848                       "pixels[1] + pixels[6];");
14849   CHECK_EQ(255, result->Int32Value());
14850   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
14851   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14852   CHECK_EQ(21,
14853            i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
14854   CHECK_EQ(86,
14855            i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
14856   CHECK_EQ(151,
14857            i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
14858   CHECK_EQ(216,
14859            i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
14860   CHECK_EQ(255,
14861            i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
14862   CHECK_EQ(255,
14863            i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
14864   result = CompileRun("var sum = 0;"
14865                       "for (var i = 0; i < 8; i++) {"
14866                       "  sum += pixels[i];"
14867                       "}"
14868                       "sum;");
14869   CHECK_EQ(984, result->Int32Value());
14870
14871   result = CompileRun("for (var i = 0; i < 8; i++) {"
14872                       "  pixels[i] = (i * 1.1);"
14873                       "}"
14874                       "pixels[1] + pixels[6];");
14875   CHECK_EQ(8, result->Int32Value());
14876   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
14877   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14878   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
14879   CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
14880   CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
14881   CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
14882   CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
14883   CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
14884
14885   result = CompileRun("for (var i = 0; i < 8; i++) {"
14886                       "  pixels[7] = undefined;"
14887                       "}"
14888                       "pixels[7];");
14889   CHECK_EQ(0, result->Int32Value());
14890   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
14891
14892   result = CompileRun("for (var i = 0; i < 8; i++) {"
14893                       "  pixels[6] = '2.3';"
14894                       "}"
14895                       "pixels[6];");
14896   CHECK_EQ(2, result->Int32Value());
14897   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
14898
14899   result = CompileRun("for (var i = 0; i < 8; i++) {"
14900                       "  pixels[5] = NaN;"
14901                       "}"
14902                       "pixels[5];");
14903   CHECK_EQ(0, result->Int32Value());
14904   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
14905
14906   result = CompileRun("for (var i = 0; i < 8; i++) {"
14907                       "  pixels[8] = Infinity;"
14908                       "}"
14909                       "pixels[8];");
14910   CHECK_EQ(255, result->Int32Value());
14911   CHECK_EQ(255,
14912            i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
14913
14914   result = CompileRun("for (var i = 0; i < 8; i++) {"
14915                       "  pixels[9] = -Infinity;"
14916                       "}"
14917                       "pixels[9];");
14918   CHECK_EQ(0, result->Int32Value());
14919   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
14920
14921   result = CompileRun("pixels[3] = 33;"
14922                       "delete pixels[3];"
14923                       "pixels[3];");
14924   CHECK_EQ(33, result->Int32Value());
14925
14926   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
14927                       "pixels[2] = 12; pixels[3] = 13;"
14928                       "pixels.__defineGetter__('2',"
14929                       "function() { return 120; });"
14930                       "pixels[2];");
14931   CHECK_EQ(12, result->Int32Value());
14932
14933   result = CompileRun("var js_array = new Array(40);"
14934                       "js_array[0] = 77;"
14935                       "js_array;");
14936   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14937
14938   result = CompileRun("pixels[1] = 23;"
14939                       "pixels.__proto__ = [];"
14940                       "js_array.__proto__ = pixels;"
14941                       "js_array.concat(pixels);");
14942   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14943   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14944
14945   result = CompileRun("pixels[1] = 23;");
14946   CHECK_EQ(23, result->Int32Value());
14947
14948   // Test for index greater than 255.  Regression test for:
14949   // http://code.google.com/p/chromium/issues/detail?id=26337.
14950   result = CompileRun("pixels[256] = 255;");
14951   CHECK_EQ(255, result->Int32Value());
14952   result = CompileRun("var i = 0;"
14953                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
14954                       "i");
14955   CHECK_EQ(255, result->Int32Value());
14956
14957   // Make sure that pixel array ICs recognize when a non-pixel array
14958   // is passed to it.
14959   result = CompileRun("function pa_load(p) {"
14960                       "  var sum = 0;"
14961                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
14962                       "  return sum;"
14963                       "}"
14964                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
14965                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
14966                       "just_ints = new Object();"
14967                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
14968                       "for (var i = 0; i < 10; ++i) {"
14969                       "  result = pa_load(just_ints);"
14970                       "}"
14971                       "result");
14972   CHECK_EQ(32640, result->Int32Value());
14973
14974   // Make sure that pixel array ICs recognize out-of-bound accesses.
14975   result = CompileRun("function pa_load(p, start) {"
14976                       "  var sum = 0;"
14977                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
14978                       "  return sum;"
14979                       "}"
14980                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
14981                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
14982                       "for (var i = 0; i < 10; ++i) {"
14983                       "  result = pa_load(pixels,-10);"
14984                       "}"
14985                       "result");
14986   CHECK_EQ(0, result->Int32Value());
14987
14988   // Make sure that generic ICs properly handles a pixel array.
14989   result = CompileRun("function pa_load(p) {"
14990                       "  var sum = 0;"
14991                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
14992                       "  return sum;"
14993                       "}"
14994                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
14995                       "just_ints = new Object();"
14996                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
14997                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
14998                       "for (var i = 0; i < 10; ++i) {"
14999                       "  result = pa_load(pixels);"
15000                       "}"
15001                       "result");
15002   CHECK_EQ(32640, result->Int32Value());
15003
15004   // Make sure that generic load ICs recognize out-of-bound accesses in
15005   // pixel arrays.
15006   result = CompileRun("function pa_load(p, start) {"
15007                       "  var sum = 0;"
15008                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15009                       "  return sum;"
15010                       "}"
15011                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15012                       "just_ints = new Object();"
15013                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15014                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15015                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15016                       "for (var i = 0; i < 10; ++i) {"
15017                       "  result = pa_load(pixels,-10);"
15018                       "}"
15019                       "result");
15020   CHECK_EQ(0, result->Int32Value());
15021
15022   // Make sure that generic ICs properly handles other types than pixel
15023   // arrays (that the inlined fast pixel array test leaves the right information
15024   // in the right registers).
15025   result = CompileRun("function pa_load(p) {"
15026                       "  var sum = 0;"
15027                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15028                       "  return sum;"
15029                       "}"
15030                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15031                       "just_ints = new Object();"
15032                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15033                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15034                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15035                       "sparse_array = new Object();"
15036                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15037                       "sparse_array[1000000] = 3;"
15038                       "for (var i = 0; i < 10; ++i) {"
15039                       "  result = pa_load(sparse_array);"
15040                       "}"
15041                       "result");
15042   CHECK_EQ(32640, result->Int32Value());
15043
15044   // Make sure that pixel array store ICs clamp values correctly.
15045   result = CompileRun("function pa_store(p) {"
15046                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15047                       "}"
15048                       "pa_store(pixels);"
15049                       "var sum = 0;"
15050                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15051                       "sum");
15052   CHECK_EQ(48896, result->Int32Value());
15053
15054   // Make sure that pixel array stores correctly handle accesses outside
15055   // of the pixel array..
15056   result = CompileRun("function pa_store(p,start) {"
15057                       "  for (var j = 0; j < 256; j++) {"
15058                       "    p[j+start] = j * 2;"
15059                       "  }"
15060                       "}"
15061                       "pa_store(pixels,0);"
15062                       "pa_store(pixels,-128);"
15063                       "var sum = 0;"
15064                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15065                       "sum");
15066   CHECK_EQ(65280, result->Int32Value());
15067
15068   // Make sure that the generic store stub correctly handle accesses outside
15069   // of the pixel array..
15070   result = CompileRun("function pa_store(p,start) {"
15071                       "  for (var j = 0; j < 256; j++) {"
15072                       "    p[j+start] = j * 2;"
15073                       "  }"
15074                       "}"
15075                       "pa_store(pixels,0);"
15076                       "just_ints = new Object();"
15077                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15078                       "pa_store(just_ints, 0);"
15079                       "pa_store(pixels,-128);"
15080                       "var sum = 0;"
15081                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15082                       "sum");
15083   CHECK_EQ(65280, result->Int32Value());
15084
15085   // Make sure that the generic keyed store stub clamps pixel array values
15086   // correctly.
15087   result = CompileRun("function pa_store(p) {"
15088                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15089                       "}"
15090                       "pa_store(pixels);"
15091                       "just_ints = new Object();"
15092                       "pa_store(just_ints);"
15093                       "pa_store(pixels);"
15094                       "var sum = 0;"
15095                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15096                       "sum");
15097   CHECK_EQ(48896, result->Int32Value());
15098
15099   // Make sure that pixel array loads are optimized by crankshaft.
15100   result = CompileRun("function pa_load(p) {"
15101                       "  var sum = 0;"
15102                       "  for (var i=0; i<256; ++i) {"
15103                       "    sum += p[i];"
15104                       "  }"
15105                       "  return sum; "
15106                       "}"
15107                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15108                       "for (var i = 0; i < 5000; ++i) {"
15109                       "  result = pa_load(pixels);"
15110                       "}"
15111                       "result");
15112   CHECK_EQ(32640, result->Int32Value());
15113
15114   // Make sure that pixel array stores are optimized by crankshaft.
15115   result = CompileRun("function pa_init(p) {"
15116                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15117                       "}"
15118                       "function pa_load(p) {"
15119                       "  var sum = 0;"
15120                       "  for (var i=0; i<256; ++i) {"
15121                       "    sum += p[i];"
15122                       "  }"
15123                       "  return sum; "
15124                       "}"
15125                       "for (var i = 0; i < 5000; ++i) {"
15126                       "  pa_init(pixels);"
15127                       "}"
15128                       "result = pa_load(pixels);"
15129                       "result");
15130   CHECK_EQ(32640, result->Int32Value());
15131
15132   free(pixel_data);
15133 }
15134
15135
15136 THREADED_TEST(PixelArrayInfo) {
15137   LocalContext context;
15138   v8::HandleScope scope(context->GetIsolate());
15139   for (int size = 0; size < 100; size += 10) {
15140     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15141     v8::Handle<v8::Object> obj = v8::Object::New();
15142     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15143     CHECK(obj->HasIndexedPropertiesInPixelData());
15144     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15145     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15146     free(pixel_data);
15147   }
15148 }
15149
15150
15151 static void NotHandledIndexedPropertyGetter(
15152     uint32_t index,
15153     const v8::PropertyCallbackInfo<v8::Value>& info) {
15154   ApiTestFuzzer::Fuzz();
15155 }
15156
15157
15158 static void NotHandledIndexedPropertySetter(
15159     uint32_t index,
15160     Local<Value> value,
15161     const v8::PropertyCallbackInfo<v8::Value>& info) {
15162   ApiTestFuzzer::Fuzz();
15163 }
15164
15165
15166 THREADED_TEST(PixelArrayWithInterceptor) {
15167   LocalContext context;
15168   i::Factory* factory = i::Isolate::Current()->factory();
15169   v8::HandleScope scope(context->GetIsolate());
15170   const int kElementCount = 260;
15171   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15172   i::Handle<i::ExternalPixelArray> pixels =
15173       i::Handle<i::ExternalPixelArray>::cast(
15174           factory->NewExternalArray(kElementCount,
15175                                     v8::kExternalPixelArray,
15176                                     pixel_data));
15177   for (int i = 0; i < kElementCount; i++) {
15178     pixels->set(i, i % 256);
15179   }
15180   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
15181   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
15182                                    NotHandledIndexedPropertySetter);
15183   v8::Handle<v8::Object> obj = templ->NewInstance();
15184   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15185   context->Global()->Set(v8_str("pixels"), obj);
15186   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
15187   CHECK_EQ(1, result->Int32Value());
15188   result = CompileRun("var sum = 0;"
15189                       "for (var i = 0; i < 8; i++) {"
15190                       "  sum += pixels[i] = pixels[i] = -i;"
15191                       "}"
15192                       "sum;");
15193   CHECK_EQ(-28, result->Int32Value());
15194   result = CompileRun("pixels.hasOwnProperty('1')");
15195   CHECK(result->BooleanValue());
15196   free(pixel_data);
15197 }
15198
15199
15200 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
15201   switch (array_type) {
15202     case v8::kExternalByteArray:
15203     case v8::kExternalUnsignedByteArray:
15204     case v8::kExternalPixelArray:
15205       return 1;
15206       break;
15207     case v8::kExternalShortArray:
15208     case v8::kExternalUnsignedShortArray:
15209       return 2;
15210       break;
15211     case v8::kExternalIntArray:
15212     case v8::kExternalUnsignedIntArray:
15213     case v8::kExternalFloatArray:
15214       return 4;
15215       break;
15216     case v8::kExternalDoubleArray:
15217       return 8;
15218       break;
15219     default:
15220       UNREACHABLE();
15221       return -1;
15222   }
15223   UNREACHABLE();
15224   return -1;
15225 }
15226
15227
15228 template <class ExternalArrayClass, class ElementType>
15229 static void ObjectWithExternalArrayTestHelper(
15230     Handle<Context> context,
15231     v8::Handle<Object> obj,
15232     int element_count,
15233     v8::ExternalArrayType array_type,
15234     int64_t low, int64_t high) {
15235   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15236   obj->Set(v8_str("field"), v8::Int32::New(1503));
15237   context->Global()->Set(v8_str("ext_array"), obj);
15238   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
15239   CHECK_EQ(1503, result->Int32Value());
15240   result = CompileRun("ext_array[1]");
15241   CHECK_EQ(1, result->Int32Value());
15242
15243   // Check pass through of assigned smis
15244   result = CompileRun("var sum = 0;"
15245                       "for (var i = 0; i < 8; i++) {"
15246                       "  sum += ext_array[i] = ext_array[i] = -i;"
15247                       "}"
15248                       "sum;");
15249   CHECK_EQ(-28, result->Int32Value());
15250
15251   // Check assigned smis
15252   result = CompileRun("for (var i = 0; i < 8; i++) {"
15253                       "  ext_array[i] = i;"
15254                       "}"
15255                       "var sum = 0;"
15256                       "for (var i = 0; i < 8; i++) {"
15257                       "  sum += ext_array[i];"
15258                       "}"
15259                       "sum;");
15260   CHECK_EQ(28, result->Int32Value());
15261
15262   // Check assigned smis in reverse order
15263   result = CompileRun("for (var i = 8; --i >= 0; ) {"
15264                       "  ext_array[i] = i;"
15265                       "}"
15266                       "var sum = 0;"
15267                       "for (var i = 0; i < 8; i++) {"
15268                       "  sum += ext_array[i];"
15269                       "}"
15270                       "sum;");
15271   CHECK_EQ(28, result->Int32Value());
15272
15273   // Check pass through of assigned HeapNumbers
15274   result = CompileRun("var sum = 0;"
15275                       "for (var i = 0; i < 16; i+=2) {"
15276                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15277                       "}"
15278                       "sum;");
15279   CHECK_EQ(-28, result->Int32Value());
15280
15281   // Check assigned HeapNumbers
15282   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15283                       "  ext_array[i] = (i * 0.5);"
15284                       "}"
15285                       "var sum = 0;"
15286                       "for (var i = 0; i < 16; i+=2) {"
15287                       "  sum += ext_array[i];"
15288                       "}"
15289                       "sum;");
15290   CHECK_EQ(28, result->Int32Value());
15291
15292   // Check assigned HeapNumbers in reverse order
15293   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15294                       "  ext_array[i] = (i * 0.5);"
15295                       "}"
15296                       "var sum = 0;"
15297                       "for (var i = 0; i < 16; i+=2) {"
15298                       "  sum += ext_array[i];"
15299                       "}"
15300                       "sum;");
15301   CHECK_EQ(28, result->Int32Value());
15302
15303   i::ScopedVector<char> test_buf(1024);
15304
15305   // Check legal boundary conditions.
15306   // The repeated loads and stores ensure the ICs are exercised.
15307   const char* boundary_program =
15308       "var res = 0;"
15309       "for (var i = 0; i < 16; i++) {"
15310       "  ext_array[i] = %lld;"
15311       "  if (i > 8) {"
15312       "    res = ext_array[i];"
15313       "  }"
15314       "}"
15315       "res;";
15316   i::OS::SNPrintF(test_buf,
15317                   boundary_program,
15318                   low);
15319   result = CompileRun(test_buf.start());
15320   CHECK_EQ(low, result->IntegerValue());
15321
15322   i::OS::SNPrintF(test_buf,
15323                   boundary_program,
15324                   high);
15325   result = CompileRun(test_buf.start());
15326   CHECK_EQ(high, result->IntegerValue());
15327
15328   // Check misprediction of type in IC.
15329   result = CompileRun("var tmp_array = ext_array;"
15330                       "var sum = 0;"
15331                       "for (var i = 0; i < 8; i++) {"
15332                       "  tmp_array[i] = i;"
15333                       "  sum += tmp_array[i];"
15334                       "  if (i == 4) {"
15335                       "    tmp_array = {};"
15336                       "  }"
15337                       "}"
15338                       "sum;");
15339   // Force GC to trigger verification.
15340   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15341   CHECK_EQ(28, result->Int32Value());
15342
15343   // Make sure out-of-range loads do not throw.
15344   i::OS::SNPrintF(test_buf,
15345                   "var caught_exception = false;"
15346                   "try {"
15347                   "  ext_array[%d];"
15348                   "} catch (e) {"
15349                   "  caught_exception = true;"
15350                   "}"
15351                   "caught_exception;",
15352                   element_count);
15353   result = CompileRun(test_buf.start());
15354   CHECK_EQ(false, result->BooleanValue());
15355
15356   // Make sure out-of-range stores do not throw.
15357   i::OS::SNPrintF(test_buf,
15358                   "var caught_exception = false;"
15359                   "try {"
15360                   "  ext_array[%d] = 1;"
15361                   "} catch (e) {"
15362                   "  caught_exception = true;"
15363                   "}"
15364                   "caught_exception;",
15365                   element_count);
15366   result = CompileRun(test_buf.start());
15367   CHECK_EQ(false, result->BooleanValue());
15368
15369   // Check other boundary conditions, values and operations.
15370   result = CompileRun("for (var i = 0; i < 8; i++) {"
15371                       "  ext_array[7] = undefined;"
15372                       "}"
15373                       "ext_array[7];");
15374   CHECK_EQ(0, result->Int32Value());
15375   if (array_type == v8::kExternalDoubleArray ||
15376       array_type == v8::kExternalFloatArray) {
15377     CHECK_EQ(
15378         static_cast<int>(i::OS::nan_value()),
15379         static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
15380   } else {
15381     CHECK_EQ(0, static_cast<int>(
15382         jsobj->GetElement(7)->ToObjectChecked()->Number()));
15383   }
15384
15385   result = CompileRun("for (var i = 0; i < 8; i++) {"
15386                       "  ext_array[6] = '2.3';"
15387                       "}"
15388                       "ext_array[6];");
15389   CHECK_EQ(2, result->Int32Value());
15390   CHECK_EQ(
15391       2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
15392
15393   if (array_type != v8::kExternalFloatArray &&
15394       array_type != v8::kExternalDoubleArray) {
15395     // Though the specification doesn't state it, be explicit about
15396     // converting NaNs and +/-Infinity to zero.
15397     result = CompileRun("for (var i = 0; i < 8; i++) {"
15398                         "  ext_array[i] = 5;"
15399                         "}"
15400                         "for (var i = 0; i < 8; i++) {"
15401                         "  ext_array[i] = NaN;"
15402                         "}"
15403                         "ext_array[5];");
15404     CHECK_EQ(0, result->Int32Value());
15405     CHECK_EQ(0,
15406              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
15407
15408     result = CompileRun("for (var i = 0; i < 8; i++) {"
15409                         "  ext_array[i] = 5;"
15410                         "}"
15411                         "for (var i = 0; i < 8; i++) {"
15412                         "  ext_array[i] = Infinity;"
15413                         "}"
15414                         "ext_array[5];");
15415     int expected_value =
15416         (array_type == v8::kExternalPixelArray) ? 255 : 0;
15417     CHECK_EQ(expected_value, result->Int32Value());
15418     CHECK_EQ(expected_value,
15419              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
15420
15421     result = CompileRun("for (var i = 0; i < 8; i++) {"
15422                         "  ext_array[i] = 5;"
15423                         "}"
15424                         "for (var i = 0; i < 8; i++) {"
15425                         "  ext_array[i] = -Infinity;"
15426                         "}"
15427                         "ext_array[5];");
15428     CHECK_EQ(0, result->Int32Value());
15429     CHECK_EQ(0,
15430              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
15431
15432     // Check truncation behavior of integral arrays.
15433     const char* unsigned_data =
15434         "var source_data = [0.6, 10.6];"
15435         "var expected_results = [0, 10];";
15436     const char* signed_data =
15437         "var source_data = [0.6, 10.6, -0.6, -10.6];"
15438         "var expected_results = [0, 10, 0, -10];";
15439     const char* pixel_data =
15440         "var source_data = [0.6, 10.6];"
15441         "var expected_results = [1, 11];";
15442     bool is_unsigned =
15443         (array_type == v8::kExternalUnsignedByteArray ||
15444          array_type == v8::kExternalUnsignedShortArray ||
15445          array_type == v8::kExternalUnsignedIntArray);
15446     bool is_pixel_data = array_type == v8::kExternalPixelArray;
15447
15448     i::OS::SNPrintF(test_buf,
15449                     "%s"
15450                     "var all_passed = true;"
15451                     "for (var i = 0; i < source_data.length; i++) {"
15452                     "  for (var j = 0; j < 8; j++) {"
15453                     "    ext_array[j] = source_data[i];"
15454                     "  }"
15455                     "  all_passed = all_passed &&"
15456                     "               (ext_array[5] == expected_results[i]);"
15457                     "}"
15458                     "all_passed;",
15459                     (is_unsigned ?
15460                          unsigned_data :
15461                          (is_pixel_data ? pixel_data : signed_data)));
15462     result = CompileRun(test_buf.start());
15463     CHECK_EQ(true, result->BooleanValue());
15464   }
15465
15466   i::Handle<ExternalArrayClass> array(
15467       ExternalArrayClass::cast(jsobj->elements()));
15468   for (int i = 0; i < element_count; i++) {
15469     array->set(i, static_cast<ElementType>(i));
15470   }
15471
15472   // Test complex assignments
15473   result = CompileRun("function ee_op_test_complex_func(sum) {"
15474                       " for (var i = 0; i < 40; ++i) {"
15475                       "   sum += (ext_array[i] += 1);"
15476                       "   sum += (ext_array[i] -= 1);"
15477                       " } "
15478                       " return sum;"
15479                       "}"
15480                       "sum=0;"
15481                       "for (var i=0;i<10000;++i) {"
15482                       "  sum=ee_op_test_complex_func(sum);"
15483                       "}"
15484                       "sum;");
15485   CHECK_EQ(16000000, result->Int32Value());
15486
15487   // Test count operations
15488   result = CompileRun("function ee_op_test_count_func(sum) {"
15489                       " for (var i = 0; i < 40; ++i) {"
15490                       "   sum += (++ext_array[i]);"
15491                       "   sum += (--ext_array[i]);"
15492                       " } "
15493                       " return sum;"
15494                       "}"
15495                       "sum=0;"
15496                       "for (var i=0;i<10000;++i) {"
15497                       "  sum=ee_op_test_count_func(sum);"
15498                       "}"
15499                       "sum;");
15500   CHECK_EQ(16000000, result->Int32Value());
15501
15502   result = CompileRun("ext_array[3] = 33;"
15503                       "delete ext_array[3];"
15504                       "ext_array[3];");
15505   CHECK_EQ(33, result->Int32Value());
15506
15507   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
15508                       "ext_array[2] = 12; ext_array[3] = 13;"
15509                       "ext_array.__defineGetter__('2',"
15510                       "function() { return 120; });"
15511                       "ext_array[2];");
15512   CHECK_EQ(12, result->Int32Value());
15513
15514   result = CompileRun("var js_array = new Array(40);"
15515                       "js_array[0] = 77;"
15516                       "js_array;");
15517   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15518
15519   result = CompileRun("ext_array[1] = 23;"
15520                       "ext_array.__proto__ = [];"
15521                       "js_array.__proto__ = ext_array;"
15522                       "js_array.concat(ext_array);");
15523   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15524   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15525
15526   result = CompileRun("ext_array[1] = 23;");
15527   CHECK_EQ(23, result->Int32Value());
15528 }
15529
15530
15531 template <class ExternalArrayClass, class ElementType>
15532 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
15533                                     int64_t low,
15534                                     int64_t high) {
15535   LocalContext context;
15536   i::Factory* factory = i::Isolate::Current()->factory();
15537   v8::HandleScope scope(context->GetIsolate());
15538   const int kElementCount = 40;
15539   int element_size = ExternalArrayElementSize(array_type);
15540   ElementType* array_data =
15541       static_cast<ElementType*>(malloc(kElementCount * element_size));
15542   i::Handle<ExternalArrayClass> array =
15543       i::Handle<ExternalArrayClass>::cast(
15544           factory->NewExternalArray(kElementCount, array_type, array_data));
15545   // Force GC to trigger verification.
15546   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15547   for (int i = 0; i < kElementCount; i++) {
15548     array->set(i, static_cast<ElementType>(i));
15549   }
15550   // Force GC to trigger verification.
15551   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15552   for (int i = 0; i < kElementCount; i++) {
15553     CHECK_EQ(static_cast<int64_t>(i),
15554              static_cast<int64_t>(array->get_scalar(i)));
15555     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
15556   }
15557
15558   v8::Handle<v8::Object> obj = v8::Object::New();
15559   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15560   // Set the elements to be the external array.
15561   obj->SetIndexedPropertiesToExternalArrayData(array_data,
15562                                                array_type,
15563                                                kElementCount);
15564   CHECK_EQ(
15565       1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
15566
15567   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15568       context.local(), obj, kElementCount, array_type, low, high);
15569
15570   v8::Handle<v8::Value> result;
15571
15572   // Test more complex manipulations which cause eax to contain values
15573   // that won't be completely overwritten by loads from the arrays.
15574   // This catches bugs in the instructions used for the KeyedLoadIC
15575   // for byte and word types.
15576   {
15577     const int kXSize = 300;
15578     const int kYSize = 300;
15579     const int kLargeElementCount = kXSize * kYSize * 4;
15580     ElementType* large_array_data =
15581         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
15582     v8::Handle<v8::Object> large_obj = v8::Object::New();
15583     // Set the elements to be the external array.
15584     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
15585                                                        array_type,
15586                                                        kLargeElementCount);
15587     context->Global()->Set(v8_str("large_array"), large_obj);
15588     // Initialize contents of a few rows.
15589     for (int x = 0; x < 300; x++) {
15590       int row = 0;
15591       int offset = row * 300 * 4;
15592       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15593       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15594       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15595       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15596       row = 150;
15597       offset = row * 300 * 4;
15598       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15599       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15600       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15601       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15602       row = 298;
15603       offset = row * 300 * 4;
15604       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15605       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15606       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15607       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15608     }
15609     // The goal of the code below is to make "offset" large enough
15610     // that the computation of the index (which goes into eax) has
15611     // high bits set which will not be overwritten by a byte or short
15612     // load.
15613     result = CompileRun("var failed = false;"
15614                         "var offset = 0;"
15615                         "for (var i = 0; i < 300; i++) {"
15616                         "  if (large_array[4 * i] != 127 ||"
15617                         "      large_array[4 * i + 1] != 0 ||"
15618                         "      large_array[4 * i + 2] != 0 ||"
15619                         "      large_array[4 * i + 3] != 127) {"
15620                         "    failed = true;"
15621                         "  }"
15622                         "}"
15623                         "offset = 150 * 300 * 4;"
15624                         "for (var i = 0; i < 300; i++) {"
15625                         "  if (large_array[offset + 4 * i] != 127 ||"
15626                         "      large_array[offset + 4 * i + 1] != 0 ||"
15627                         "      large_array[offset + 4 * i + 2] != 0 ||"
15628                         "      large_array[offset + 4 * i + 3] != 127) {"
15629                         "    failed = true;"
15630                         "  }"
15631                         "}"
15632                         "offset = 298 * 300 * 4;"
15633                         "for (var i = 0; i < 300; i++) {"
15634                         "  if (large_array[offset + 4 * i] != 127 ||"
15635                         "      large_array[offset + 4 * i + 1] != 0 ||"
15636                         "      large_array[offset + 4 * i + 2] != 0 ||"
15637                         "      large_array[offset + 4 * i + 3] != 127) {"
15638                         "    failed = true;"
15639                         "  }"
15640                         "}"
15641                         "!failed;");
15642     CHECK_EQ(true, result->BooleanValue());
15643     free(large_array_data);
15644   }
15645
15646   // The "" property descriptor is overloaded to store information about
15647   // the external array. Ensure that setting and accessing the "" property
15648   // works (it should overwrite the information cached about the external
15649   // array in the DescriptorArray) in various situations.
15650   result = CompileRun("ext_array[''] = 23; ext_array['']");
15651   CHECK_EQ(23, result->Int32Value());
15652
15653   // Property "" set after the external array is associated with the object.
15654   {
15655     v8::Handle<v8::Object> obj2 = v8::Object::New();
15656     obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
15657     obj2->Set(v8_str(""), v8::Int32::New(1503));
15658     // Set the elements to be the external array.
15659     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
15660                                                   array_type,
15661                                                   kElementCount);
15662     context->Global()->Set(v8_str("ext_array"), obj2);
15663     result = CompileRun("ext_array['']");
15664     CHECK_EQ(1503, result->Int32Value());
15665   }
15666
15667   // Property "" set after the external array is associated with the object.
15668   {
15669     v8::Handle<v8::Object> obj2 = v8::Object::New();
15670     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
15671     // Set the elements to be the external array.
15672     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
15673                                                   array_type,
15674                                                   kElementCount);
15675     obj2->Set(v8_str(""), v8::Int32::New(1503));
15676     context->Global()->Set(v8_str("ext_array"), obj2);
15677     result = CompileRun("ext_array['']");
15678     CHECK_EQ(1503, result->Int32Value());
15679   }
15680
15681   // Should reuse the map from previous test.
15682   {
15683     v8::Handle<v8::Object> obj2 = v8::Object::New();
15684     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
15685     // Set the elements to be the external array. Should re-use the map
15686     // from previous test.
15687     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
15688                                                   array_type,
15689                                                   kElementCount);
15690     context->Global()->Set(v8_str("ext_array"), obj2);
15691     result = CompileRun("ext_array['']");
15692   }
15693
15694   // Property "" is a constant function that shouldn't not be interfered with
15695   // when an external array is set.
15696   {
15697     v8::Handle<v8::Object> obj2 = v8::Object::New();
15698     // Start
15699     obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
15700
15701     // Add a constant function to an object.
15702     context->Global()->Set(v8_str("ext_array"), obj2);
15703     result = CompileRun("ext_array[''] = function() {return 1503;};"
15704                         "ext_array['']();");
15705
15706     // Add an external array transition to the same map that
15707     // has the constant transition.
15708     v8::Handle<v8::Object> obj3 = v8::Object::New();
15709     obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
15710     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
15711                                                   array_type,
15712                                                   kElementCount);
15713     context->Global()->Set(v8_str("ext_array"), obj3);
15714   }
15715
15716   // If a external array transition is in the map, it should get clobbered
15717   // by a constant function.
15718   {
15719     // Add an external array transition.
15720     v8::Handle<v8::Object> obj3 = v8::Object::New();
15721     obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
15722     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
15723                                                   array_type,
15724                                                   kElementCount);
15725
15726     // Add a constant function to the same map that just got an external array
15727     // transition.
15728     v8::Handle<v8::Object> obj2 = v8::Object::New();
15729     obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
15730     context->Global()->Set(v8_str("ext_array"), obj2);
15731     result = CompileRun("ext_array[''] = function() {return 1503;};"
15732                         "ext_array['']();");
15733   }
15734
15735   free(array_data);
15736 }
15737
15738
15739 THREADED_TEST(ExternalByteArray) {
15740   ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
15741       v8::kExternalByteArray,
15742       -128,
15743       127);
15744 }
15745
15746
15747 THREADED_TEST(ExternalUnsignedByteArray) {
15748   ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
15749       v8::kExternalUnsignedByteArray,
15750       0,
15751       255);
15752 }
15753
15754
15755 THREADED_TEST(ExternalPixelArray) {
15756   ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
15757       v8::kExternalPixelArray,
15758       0,
15759       255);
15760 }
15761
15762
15763 THREADED_TEST(ExternalShortArray) {
15764   ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
15765       v8::kExternalShortArray,
15766       -32768,
15767       32767);
15768 }
15769
15770
15771 THREADED_TEST(ExternalUnsignedShortArray) {
15772   ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
15773       v8::kExternalUnsignedShortArray,
15774       0,
15775       65535);
15776 }
15777
15778
15779 THREADED_TEST(ExternalIntArray) {
15780   ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
15781       v8::kExternalIntArray,
15782       INT_MIN,   // -2147483648
15783       INT_MAX);  //  2147483647
15784 }
15785
15786
15787 THREADED_TEST(ExternalUnsignedIntArray) {
15788   ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
15789       v8::kExternalUnsignedIntArray,
15790       0,
15791       UINT_MAX);  // 4294967295
15792 }
15793
15794
15795 THREADED_TEST(ExternalFloatArray) {
15796   ExternalArrayTestHelper<i::ExternalFloatArray, float>(
15797       v8::kExternalFloatArray,
15798       -500,
15799       500);
15800 }
15801
15802
15803 THREADED_TEST(ExternalDoubleArray) {
15804   ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
15805       v8::kExternalDoubleArray,
15806       -500,
15807       500);
15808 }
15809
15810
15811 THREADED_TEST(ExternalArrays) {
15812   TestExternalByteArray();
15813   TestExternalUnsignedByteArray();
15814   TestExternalShortArray();
15815   TestExternalUnsignedShortArray();
15816   TestExternalIntArray();
15817   TestExternalUnsignedIntArray();
15818   TestExternalFloatArray();
15819 }
15820
15821
15822 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
15823   LocalContext context;
15824   v8::HandleScope scope(context->GetIsolate());
15825   for (int size = 0; size < 100; size += 10) {
15826     int element_size = ExternalArrayElementSize(array_type);
15827     void* external_data = malloc(size * element_size);
15828     v8::Handle<v8::Object> obj = v8::Object::New();
15829     obj->SetIndexedPropertiesToExternalArrayData(
15830         external_data, array_type, size);
15831     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
15832     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
15833     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
15834     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
15835     free(external_data);
15836   }
15837 }
15838
15839
15840 THREADED_TEST(ExternalArrayInfo) {
15841   ExternalArrayInfoTestHelper(v8::kExternalByteArray);
15842   ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
15843   ExternalArrayInfoTestHelper(v8::kExternalShortArray);
15844   ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
15845   ExternalArrayInfoTestHelper(v8::kExternalIntArray);
15846   ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
15847   ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
15848   ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
15849   ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
15850 }
15851
15852
15853 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
15854   v8::Handle<v8::Object> obj = v8::Object::New();
15855   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15856   last_location = last_message = NULL;
15857   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
15858   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
15859   CHECK_NE(NULL, last_location);
15860   CHECK_NE(NULL, last_message);
15861 }
15862
15863
15864 TEST(ExternalArrayLimits) {
15865   LocalContext context;
15866   v8::HandleScope scope(context->GetIsolate());
15867   ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
15868   ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
15869   ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
15870   ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
15871   ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
15872   ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
15873   ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
15874   ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
15875   ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
15876   ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
15877   ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
15878   ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
15879   ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
15880   ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
15881   ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
15882   ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
15883   ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
15884   ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
15885 }
15886
15887
15888 template <typename ElementType, typename TypedArray,
15889           class ExternalArrayClass>
15890 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
15891                           int64_t low, int64_t high) {
15892   const int kElementCount = 50;
15893
15894   i::ScopedVector<ElementType> backing_store(kElementCount+2);
15895
15896   LocalContext env;
15897   v8::Isolate* isolate = env->GetIsolate();
15898   v8::HandleScope handle_scope(isolate);
15899
15900   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
15901       backing_store.start(), (kElementCount+2)*sizeof(ElementType));
15902   Local<TypedArray> ta =
15903       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
15904   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
15905   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
15906   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
15907   CHECK_EQ(kElementCount*sizeof(ElementType),
15908            static_cast<int>(ta->ByteLength()));
15909   CHECK_EQ(ab, ta->Buffer());
15910
15911   ElementType* data = backing_store.start() + 2;
15912   for (int i = 0; i < kElementCount; i++) {
15913     data[i] = static_cast<ElementType>(i);
15914   }
15915
15916   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15917       env.local(), ta, kElementCount, array_type, low, high);
15918 }
15919
15920
15921 THREADED_TEST(Uint8Array) {
15922   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>(
15923       v8::kExternalUnsignedByteArray, 0, 0xFF);
15924 }
15925
15926
15927 THREADED_TEST(Int8Array) {
15928   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>(
15929       v8::kExternalByteArray, -0x80, 0x7F);
15930 }
15931
15932
15933 THREADED_TEST(Uint16Array) {
15934   TypedArrayTestHelper<uint16_t,
15935                        v8::Uint16Array,
15936                        i::ExternalUnsignedShortArray>(
15937       v8::kExternalUnsignedShortArray, 0, 0xFFFF);
15938 }
15939
15940
15941 THREADED_TEST(Int16Array) {
15942   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>(
15943       v8::kExternalShortArray, -0x8000, 0x7FFF);
15944 }
15945
15946
15947 THREADED_TEST(Uint32Array) {
15948   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>(
15949       v8::kExternalUnsignedIntArray, 0, UINT_MAX);
15950 }
15951
15952
15953 THREADED_TEST(Int32Array) {
15954   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>(
15955       v8::kExternalIntArray, INT_MIN, INT_MAX);
15956 }
15957
15958
15959 THREADED_TEST(Float32Array) {
15960   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>(
15961       v8::kExternalFloatArray, -500, 500);
15962 }
15963
15964
15965 THREADED_TEST(Float64Array) {
15966   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>(
15967       v8::kExternalDoubleArray, -500, 500);
15968 }
15969
15970
15971 THREADED_TEST(Uint8ClampedArray) {
15972   TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>(
15973       v8::kExternalPixelArray, 0, 0xFF);
15974 }
15975
15976
15977 THREADED_TEST(DataView) {
15978   const int kSize = 50;
15979
15980   i::ScopedVector<uint8_t> backing_store(kSize+2);
15981
15982   LocalContext env;
15983   v8::Isolate* isolate = env->GetIsolate();
15984   v8::HandleScope handle_scope(isolate);
15985
15986   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
15987       backing_store.start(), 2 + kSize);
15988   Local<v8::DataView> dv =
15989       v8::DataView::New(ab, 2, kSize);
15990   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
15991   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
15992   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
15993   CHECK_EQ(ab, dv->Buffer());
15994 }
15995
15996
15997 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
15998   THREADED_TEST(Is##View) {                                                   \
15999     i::FLAG_harmony_array_buffer = true;                                      \
16000     i::FLAG_harmony_typed_arrays = true;                                      \
16001     LocalContext env;                                                         \
16002     v8::Isolate* isolate = env->GetIsolate();                                 \
16003     v8::HandleScope handle_scope(isolate);                                    \
16004                                                                               \
16005     Handle<Value> result = CompileRun(                                        \
16006         "var ab = new ArrayBuffer(128);"                                      \
16007         "new " #View "(ab)");                                                 \
16008     CHECK(result->IsArrayBufferView());                                       \
16009     CHECK(result->Is##View());                                                \
16010     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
16011   }
16012
16013 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16014 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16015 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16016 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16017 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16018 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16019 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16020 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16021 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16022 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16023
16024 #undef IS_ARRAY_BUFFER_VIEW_TEST
16025
16026
16027
16028 THREADED_TEST(ScriptContextDependence) {
16029   LocalContext c1;
16030   v8::HandleScope scope(c1->GetIsolate());
16031   const char *source = "foo";
16032   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
16033   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
16034   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
16035   CHECK_EQ(dep->Run()->Int32Value(), 100);
16036   CHECK_EQ(indep->Run()->Int32Value(), 100);
16037   LocalContext c2;
16038   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
16039   CHECK_EQ(dep->Run()->Int32Value(), 100);
16040   CHECK_EQ(indep->Run()->Int32Value(), 101);
16041 }
16042
16043
16044 THREADED_TEST(StackTrace) {
16045   LocalContext context;
16046   v8::HandleScope scope(context->GetIsolate());
16047   v8::TryCatch try_catch;
16048   const char *source = "function foo() { FAIL.FAIL; }; foo();";
16049   v8::Handle<v8::String> src = v8::String::New(source);
16050   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
16051   v8::Script::New(src, origin)->Run();
16052   CHECK(try_catch.HasCaught());
16053   v8::String::Utf8Value stack(try_catch.StackTrace());
16054   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
16055 }
16056
16057
16058 // Checks that a StackFrame has certain expected values.
16059 void checkStackFrame(const char* expected_script_name,
16060     const char* expected_func_name, int expected_line_number,
16061     int expected_column, bool is_eval, bool is_constructor,
16062     v8::Handle<v8::StackFrame> frame) {
16063   v8::HandleScope scope(v8::Isolate::GetCurrent());
16064   v8::String::Utf8Value func_name(frame->GetFunctionName());
16065   v8::String::Utf8Value script_name(frame->GetScriptName());
16066   if (*script_name == NULL) {
16067     // The situation where there is no associated script, like for evals.
16068     CHECK(expected_script_name == NULL);
16069   } else {
16070     CHECK(strstr(*script_name, expected_script_name) != NULL);
16071   }
16072   CHECK(strstr(*func_name, expected_func_name) != NULL);
16073   CHECK_EQ(expected_line_number, frame->GetLineNumber());
16074   CHECK_EQ(expected_column, frame->GetColumn());
16075   CHECK_EQ(is_eval, frame->IsEval());
16076   CHECK_EQ(is_constructor, frame->IsConstructor());
16077 }
16078
16079
16080 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16081   v8::HandleScope scope(args.GetIsolate());
16082   const char* origin = "capture-stack-trace-test";
16083   const int kOverviewTest = 1;
16084   const int kDetailedTest = 2;
16085
16086   ASSERT(args.Length() == 1);
16087
16088   int testGroup = args[0]->Int32Value();
16089   if (testGroup == kOverviewTest) {
16090     v8::Handle<v8::StackTrace> stackTrace =
16091         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
16092     CHECK_EQ(4, stackTrace->GetFrameCount());
16093     checkStackFrame(origin, "bar", 2, 10, false, false,
16094                     stackTrace->GetFrame(0));
16095     checkStackFrame(origin, "foo", 6, 3, false, false,
16096                     stackTrace->GetFrame(1));
16097     // This is the source string inside the eval which has the call to foo.
16098     checkStackFrame(NULL, "", 1, 5, false, false,
16099                     stackTrace->GetFrame(2));
16100     // The last frame is an anonymous function which has the initial eval call.
16101     checkStackFrame(origin, "", 8, 7, false, false,
16102                     stackTrace->GetFrame(3));
16103
16104     CHECK(stackTrace->AsArray()->IsArray());
16105   } else if (testGroup == kDetailedTest) {
16106     v8::Handle<v8::StackTrace> stackTrace =
16107         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16108     CHECK_EQ(4, stackTrace->GetFrameCount());
16109     checkStackFrame(origin, "bat", 4, 22, false, false,
16110                     stackTrace->GetFrame(0));
16111     checkStackFrame(origin, "baz", 8, 3, false, true,
16112                     stackTrace->GetFrame(1));
16113 #ifdef ENABLE_DEBUGGER_SUPPORT
16114     bool is_eval = true;
16115 #else  // ENABLE_DEBUGGER_SUPPORT
16116     bool is_eval = false;
16117 #endif  // ENABLE_DEBUGGER_SUPPORT
16118
16119     // This is the source string inside the eval which has the call to baz.
16120     checkStackFrame(NULL, "", 1, 5, is_eval, false,
16121                     stackTrace->GetFrame(2));
16122     // The last frame is an anonymous function which has the initial eval call.
16123     checkStackFrame(origin, "", 10, 1, false, false,
16124                     stackTrace->GetFrame(3));
16125
16126     CHECK(stackTrace->AsArray()->IsArray());
16127   }
16128 }
16129
16130
16131 // Tests the C++ StackTrace API.
16132 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16133 // THREADED_TEST(CaptureStackTrace) {
16134 TEST(CaptureStackTrace) {
16135   v8::HandleScope scope(v8::Isolate::GetCurrent());
16136   v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
16137   Local<ObjectTemplate> templ = ObjectTemplate::New();
16138   templ->Set(v8_str("AnalyzeStackInNativeCode"),
16139              v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
16140   LocalContext context(0, templ);
16141
16142   // Test getting OVERVIEW information. Should ignore information that is not
16143   // script name, function name, line number, and column offset.
16144   const char *overview_source =
16145     "function bar() {\n"
16146     "  var y; AnalyzeStackInNativeCode(1);\n"
16147     "}\n"
16148     "function foo() {\n"
16149     "\n"
16150     "  bar();\n"
16151     "}\n"
16152     "var x;eval('new foo();');";
16153   v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
16154   v8::Handle<Value> overview_result(
16155       v8::Script::New(overview_src, origin)->Run());
16156   CHECK(!overview_result.IsEmpty());
16157   CHECK(overview_result->IsObject());
16158
16159   // Test getting DETAILED information.
16160   const char *detailed_source =
16161     "function bat() {AnalyzeStackInNativeCode(2);\n"
16162     "}\n"
16163     "\n"
16164     "function baz() {\n"
16165     "  bat();\n"
16166     "}\n"
16167     "eval('new baz();');";
16168   v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
16169   // Make the script using a non-zero line and column offset.
16170   v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
16171   v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
16172   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16173   v8::Handle<v8::Script> detailed_script(
16174       v8::Script::New(detailed_src, &detailed_origin));
16175   v8::Handle<Value> detailed_result(detailed_script->Run());
16176   CHECK(!detailed_result.IsEmpty());
16177   CHECK(detailed_result->IsObject());
16178 }
16179
16180
16181 static void StackTraceForUncaughtExceptionListener(
16182     v8::Handle<v8::Message> message,
16183     v8::Handle<Value>) {
16184   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16185   CHECK_EQ(2, stack_trace->GetFrameCount());
16186   checkStackFrame("origin", "foo", 2, 3, false, false,
16187                   stack_trace->GetFrame(0));
16188   checkStackFrame("origin", "bar", 5, 3, false, false,
16189                   stack_trace->GetFrame(1));
16190 }
16191
16192
16193 TEST(CaptureStackTraceForUncaughtException) {
16194   report_count = 0;
16195   LocalContext env;
16196   v8::HandleScope scope(env->GetIsolate());
16197   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
16198   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16199
16200   Script::Compile(v8_str("function foo() {\n"
16201                          "  throw 1;\n"
16202                          "};\n"
16203                          "function bar() {\n"
16204                          "  foo();\n"
16205                          "};"),
16206                   v8_str("origin"))->Run();
16207   v8::Local<v8::Object> global = env->Global();
16208   Local<Value> trouble = global->Get(v8_str("bar"));
16209   CHECK(trouble->IsFunction());
16210   Function::Cast(*trouble)->Call(global, 0, NULL);
16211   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16212   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16213 }
16214
16215
16216 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16217   LocalContext env;
16218   v8::HandleScope scope(env->GetIsolate());
16219   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
16220                                                     1024,
16221                                                     v8::StackTrace::kDetailed);
16222
16223   CompileRun(
16224       "var setters = ['column', 'lineNumber', 'scriptName',\n"
16225       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16226       "    'isConstructor'];\n"
16227       "for (var i = 0; i < setters.length; i++) {\n"
16228       "  var prop = setters[i];\n"
16229       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16230       "}\n");
16231   CompileRun("throw 'exception';");
16232   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16233 }
16234
16235
16236 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
16237                                      v8::Handle<v8::Value> data) {
16238   // Use the frame where JavaScript is called from.
16239   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16240   CHECK(!stack_trace.IsEmpty());
16241   int frame_count = stack_trace->GetFrameCount();
16242   CHECK_EQ(3, frame_count);
16243   int line_number[] = {1, 2, 5};
16244   for (int i = 0; i < frame_count; i++) {
16245     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16246   }
16247 }
16248
16249
16250 // Test that we only return the stack trace at the site where the exception
16251 // is first thrown (not where it is rethrown).
16252 TEST(RethrowStackTrace) {
16253   LocalContext env;
16254   v8::HandleScope scope(env->GetIsolate());
16255   // We make sure that
16256   // - the stack trace of the ReferenceError in g() is reported.
16257   // - the stack trace is not overwritten when e1 is rethrown by t().
16258   // - the stack trace of e2 does not overwrite that of e1.
16259   const char* source =
16260       "function g() { error; }          \n"
16261       "function f() { g(); }            \n"
16262       "function t(e) { throw e; }       \n"
16263       "try {                            \n"
16264       "  f();                           \n"
16265       "} catch (e1) {                   \n"
16266       "  try {                          \n"
16267       "    error;                       \n"
16268       "  } catch (e2) {                 \n"
16269       "    t(e1);                       \n"
16270       "  }                              \n"
16271       "}                                \n";
16272   v8::V8::AddMessageListener(RethrowStackTraceHandler);
16273   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16274   CompileRun(source);
16275   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16276   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
16277 }
16278
16279
16280 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
16281                                               v8::Handle<v8::Value> data) {
16282   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16283   CHECK(!stack_trace.IsEmpty());
16284   int frame_count = stack_trace->GetFrameCount();
16285   CHECK_EQ(2, frame_count);
16286   int line_number[] = {3, 7};
16287   for (int i = 0; i < frame_count; i++) {
16288     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16289   }
16290 }
16291
16292
16293 // Test that we do not recognize identity for primitive exceptions.
16294 TEST(RethrowPrimitiveStackTrace) {
16295   LocalContext env;
16296   v8::HandleScope scope(env->GetIsolate());
16297   // We do not capture stack trace for non Error objects on creation time.
16298   // Instead, we capture the stack trace on last throw.
16299   const char* source =
16300       "function g() { throw 404; }      \n"
16301       "function f() { g(); }            \n"
16302       "function t(e) { throw e; }       \n"
16303       "try {                            \n"
16304       "  f();                           \n"
16305       "} catch (e1) {                   \n"
16306       "  t(e1)                          \n"
16307       "}                                \n";
16308   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
16309   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16310   CompileRun(source);
16311   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16312   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16313 }
16314
16315
16316 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
16317                                               v8::Handle<v8::Value> data) {
16318   // Use the frame where JavaScript is called from.
16319   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16320   CHECK(!stack_trace.IsEmpty());
16321   CHECK_EQ(1, stack_trace->GetFrameCount());
16322   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
16323 }
16324
16325
16326 // Test that the stack trace is captured when the error object is created and
16327 // not where it is thrown.
16328 TEST(RethrowExistingStackTrace) {
16329   LocalContext env;
16330   v8::HandleScope scope(env->GetIsolate());
16331   const char* source =
16332       "var e = new Error();           \n"
16333       "throw e;                       \n";
16334   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
16335   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16336   CompileRun(source);
16337   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16338   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
16339 }
16340
16341
16342 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
16343                                                v8::Handle<v8::Value> data) {
16344   // Use the frame where JavaScript is called from.
16345   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16346   CHECK(!stack_trace.IsEmpty());
16347   CHECK_EQ(1, stack_trace->GetFrameCount());
16348   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
16349 }
16350
16351
16352 // Test that the stack trace is captured where the bogus Error object is thrown.
16353 TEST(RethrowBogusErrorStackTrace) {
16354   LocalContext env;
16355   v8::HandleScope scope(env->GetIsolate());
16356   const char* source =
16357       "var e = {__proto__: new Error()} \n"
16358       "throw e;                         \n";
16359   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
16360   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16361   CompileRun(source);
16362   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16363   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16364 }
16365
16366
16367 void AnalyzeStackOfEvalWithSourceURL(
16368     const v8::FunctionCallbackInfo<v8::Value>& args) {
16369   v8::HandleScope scope(args.GetIsolate());
16370   v8::Handle<v8::StackTrace> stackTrace =
16371       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16372   CHECK_EQ(5, stackTrace->GetFrameCount());
16373   v8::Handle<v8::String> url = v8_str("eval_url");
16374   for (int i = 0; i < 3; i++) {
16375     v8::Handle<v8::String> name =
16376         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16377     CHECK(!name.IsEmpty());
16378     CHECK_EQ(url, name);
16379   }
16380 }
16381
16382
16383 TEST(SourceURLInStackTrace) {
16384   v8::HandleScope scope(v8::Isolate::GetCurrent());
16385   Local<ObjectTemplate> templ = ObjectTemplate::New();
16386   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
16387              v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
16388   LocalContext context(0, templ);
16389
16390   const char *source =
16391     "function outer() {\n"
16392     "function bar() {\n"
16393     "  AnalyzeStackOfEvalWithSourceURL();\n"
16394     "}\n"
16395     "function foo() {\n"
16396     "\n"
16397     "  bar();\n"
16398     "}\n"
16399     "foo();\n"
16400     "}\n"
16401     "eval('(' + outer +')()%s');";
16402
16403   i::ScopedVector<char> code(1024);
16404   i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
16405   CHECK(CompileRun(code.start())->IsUndefined());
16406   i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
16407   CHECK(CompileRun(code.start())->IsUndefined());
16408 }
16409
16410
16411 void AnalyzeStackOfInlineScriptWithSourceURL(
16412     const v8::FunctionCallbackInfo<v8::Value>& args) {
16413   v8::HandleScope scope(args.GetIsolate());
16414   v8::Handle<v8::StackTrace> stackTrace =
16415       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16416   CHECK_EQ(4, stackTrace->GetFrameCount());
16417   v8::Handle<v8::String> url = v8_str("url");
16418   for (int i = 0; i < 3; i++) {
16419     v8::Handle<v8::String> name =
16420         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16421     CHECK(!name.IsEmpty());
16422     CHECK_EQ(url, name);
16423   }
16424 }
16425
16426
16427 TEST(InlineScriptWithSourceURLInStackTrace) {
16428   v8::HandleScope scope(v8::Isolate::GetCurrent());
16429   Local<ObjectTemplate> templ = ObjectTemplate::New();
16430   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
16431              v8::FunctionTemplate::New(
16432                  AnalyzeStackOfInlineScriptWithSourceURL));
16433   LocalContext context(0, templ);
16434
16435   const char *source =
16436     "function outer() {\n"
16437     "function bar() {\n"
16438     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
16439     "}\n"
16440     "function foo() {\n"
16441     "\n"
16442     "  bar();\n"
16443     "}\n"
16444     "foo();\n"
16445     "}\n"
16446     "outer()\n%s";
16447
16448   i::ScopedVector<char> code(1024);
16449   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16450   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16451   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16452   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16453 }
16454
16455
16456 void AnalyzeStackOfDynamicScriptWithSourceURL(
16457     const v8::FunctionCallbackInfo<v8::Value>& args) {
16458   v8::HandleScope scope(args.GetIsolate());
16459   v8::Handle<v8::StackTrace> stackTrace =
16460       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16461   CHECK_EQ(4, stackTrace->GetFrameCount());
16462   v8::Handle<v8::String> url = v8_str("source_url");
16463   for (int i = 0; i < 3; i++) {
16464     v8::Handle<v8::String> name =
16465         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16466     CHECK(!name.IsEmpty());
16467     CHECK_EQ(url, name);
16468   }
16469 }
16470
16471
16472 TEST(DynamicWithSourceURLInStackTrace) {
16473   v8::HandleScope scope(v8::Isolate::GetCurrent());
16474   Local<ObjectTemplate> templ = ObjectTemplate::New();
16475   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
16476              v8::FunctionTemplate::New(
16477                  AnalyzeStackOfDynamicScriptWithSourceURL));
16478   LocalContext context(0, templ);
16479
16480   const char *source =
16481     "function outer() {\n"
16482     "function bar() {\n"
16483     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
16484     "}\n"
16485     "function foo() {\n"
16486     "\n"
16487     "  bar();\n"
16488     "}\n"
16489     "foo();\n"
16490     "}\n"
16491     "outer()\n%s";
16492
16493   i::ScopedVector<char> code(1024);
16494   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16495   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16496   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16497   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16498 }
16499
16500
16501 static void CreateGarbageInOldSpace() {
16502   i::Factory* factory = i::Isolate::Current()->factory();
16503   v8::HandleScope scope(v8::Isolate::GetCurrent());
16504   i::AlwaysAllocateScope always_allocate;
16505   for (int i = 0; i < 1000; i++) {
16506     factory->NewFixedArray(1000, i::TENURED);
16507   }
16508 }
16509
16510
16511 // Test that idle notification can be handled and eventually returns true.
16512 TEST(IdleNotification) {
16513   const intptr_t MB = 1024 * 1024;
16514   LocalContext env;
16515   v8::HandleScope scope(env->GetIsolate());
16516   intptr_t initial_size = HEAP->SizeOfObjects();
16517   CreateGarbageInOldSpace();
16518   intptr_t size_with_garbage = HEAP->SizeOfObjects();
16519   CHECK_GT(size_with_garbage, initial_size + MB);
16520   bool finished = false;
16521   for (int i = 0; i < 200 && !finished; i++) {
16522     finished = v8::V8::IdleNotification();
16523   }
16524   intptr_t final_size = HEAP->SizeOfObjects();
16525   CHECK(finished);
16526   CHECK_LT(final_size, initial_size + 1);
16527 }
16528
16529
16530 // Test that idle notification can be handled and eventually collects garbage.
16531 TEST(IdleNotificationWithSmallHint) {
16532   const intptr_t MB = 1024 * 1024;
16533   const int IdlePauseInMs = 900;
16534   LocalContext env;
16535   v8::HandleScope scope(env->GetIsolate());
16536   intptr_t initial_size = HEAP->SizeOfObjects();
16537   CreateGarbageInOldSpace();
16538   intptr_t size_with_garbage = HEAP->SizeOfObjects();
16539   CHECK_GT(size_with_garbage, initial_size + MB);
16540   bool finished = false;
16541   for (int i = 0; i < 200 && !finished; i++) {
16542     finished = v8::V8::IdleNotification(IdlePauseInMs);
16543   }
16544   intptr_t final_size = HEAP->SizeOfObjects();
16545   CHECK(finished);
16546   CHECK_LT(final_size, initial_size + 1);
16547 }
16548
16549
16550 // Test that idle notification can be handled and eventually collects garbage.
16551 TEST(IdleNotificationWithLargeHint) {
16552   const intptr_t MB = 1024 * 1024;
16553   const int IdlePauseInMs = 900;
16554   LocalContext env;
16555   v8::HandleScope scope(env->GetIsolate());
16556   intptr_t initial_size = HEAP->SizeOfObjects();
16557   CreateGarbageInOldSpace();
16558   intptr_t size_with_garbage = HEAP->SizeOfObjects();
16559   CHECK_GT(size_with_garbage, initial_size + MB);
16560   bool finished = false;
16561   for (int i = 0; i < 200 && !finished; i++) {
16562     finished = v8::V8::IdleNotification(IdlePauseInMs);
16563   }
16564   intptr_t final_size = HEAP->SizeOfObjects();
16565   CHECK(finished);
16566   CHECK_LT(final_size, initial_size + 1);
16567 }
16568
16569
16570 TEST(Regress2107) {
16571   const intptr_t MB = 1024 * 1024;
16572   const int kShortIdlePauseInMs = 100;
16573   const int kLongIdlePauseInMs = 1000;
16574   LocalContext env;
16575   v8::Isolate* isolate = env->GetIsolate();
16576   v8::HandleScope scope(env->GetIsolate());
16577   intptr_t initial_size = HEAP->SizeOfObjects();
16578   // Send idle notification to start a round of incremental GCs.
16579   v8::V8::IdleNotification(kShortIdlePauseInMs);
16580   // Emulate 7 page reloads.
16581   for (int i = 0; i < 7; i++) {
16582     {
16583       v8::HandleScope inner_scope(env->GetIsolate());
16584       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
16585       ctx->Enter();
16586       CreateGarbageInOldSpace();
16587       ctx->Exit();
16588     }
16589     v8::V8::ContextDisposedNotification();
16590     v8::V8::IdleNotification(kLongIdlePauseInMs);
16591   }
16592   // Create garbage and check that idle notification still collects it.
16593   CreateGarbageInOldSpace();
16594   intptr_t size_with_garbage = HEAP->SizeOfObjects();
16595   CHECK_GT(size_with_garbage, initial_size + MB);
16596   bool finished = false;
16597   for (int i = 0; i < 200 && !finished; i++) {
16598     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
16599   }
16600   intptr_t final_size = HEAP->SizeOfObjects();
16601   CHECK_LT(final_size, initial_size + 1);
16602 }
16603
16604 static uint32_t* stack_limit;
16605
16606 static void GetStackLimitCallback(
16607     const v8::FunctionCallbackInfo<v8::Value>& args) {
16608   stack_limit = reinterpret_cast<uint32_t*>(
16609       i::Isolate::Current()->stack_guard()->real_climit());
16610 }
16611
16612
16613 // Uses the address of a local variable to determine the stack top now.
16614 // Given a size, returns an address that is that far from the current
16615 // top of stack.
16616 static uint32_t* ComputeStackLimit(uint32_t size) {
16617   uint32_t* answer = &size - (size / sizeof(size));
16618   // If the size is very large and the stack is very near the bottom of
16619   // memory then the calculation above may wrap around and give an address
16620   // that is above the (downwards-growing) stack.  In that case we return
16621   // a very low address.
16622   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
16623   return answer;
16624 }
16625
16626
16627 // We need at least 165kB for an x64 debug build with clang and ASAN.
16628 static const int stack_breathing_room = 256 * i::KB;
16629
16630
16631 TEST(SetResourceConstraints) {
16632   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
16633
16634   // Set stack limit.
16635   v8::ResourceConstraints constraints;
16636   constraints.set_stack_limit(set_limit);
16637   CHECK(v8::SetResourceConstraints(&constraints));
16638
16639   // Execute a script.
16640   LocalContext env;
16641   v8::HandleScope scope(env->GetIsolate());
16642   Local<v8::FunctionTemplate> fun_templ =
16643       v8::FunctionTemplate::New(GetStackLimitCallback);
16644   Local<Function> fun = fun_templ->GetFunction();
16645   env->Global()->Set(v8_str("get_stack_limit"), fun);
16646   CompileRun("get_stack_limit();");
16647
16648   CHECK(stack_limit == set_limit);
16649 }
16650
16651
16652 TEST(SetResourceConstraintsInThread) {
16653   uint32_t* set_limit;
16654   {
16655     v8::Locker locker(CcTest::default_isolate());
16656     set_limit = ComputeStackLimit(stack_breathing_room);
16657
16658     // Set stack limit.
16659     v8::ResourceConstraints constraints;
16660     constraints.set_stack_limit(set_limit);
16661     CHECK(v8::SetResourceConstraints(&constraints));
16662
16663     // Execute a script.
16664     v8::HandleScope scope(CcTest::default_isolate());
16665     LocalContext env;
16666     Local<v8::FunctionTemplate> fun_templ =
16667         v8::FunctionTemplate::New(GetStackLimitCallback);
16668     Local<Function> fun = fun_templ->GetFunction();
16669     env->Global()->Set(v8_str("get_stack_limit"), fun);
16670     CompileRun("get_stack_limit();");
16671
16672     CHECK(stack_limit == set_limit);
16673   }
16674   {
16675     v8::Locker locker(CcTest::default_isolate());
16676     CHECK(stack_limit == set_limit);
16677   }
16678 }
16679
16680
16681 THREADED_TEST(GetHeapStatistics) {
16682   LocalContext c1;
16683   v8::HandleScope scope(c1->GetIsolate());
16684   v8::HeapStatistics heap_statistics;
16685   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
16686   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
16687   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
16688   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
16689   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
16690 }
16691
16692
16693 class VisitorImpl : public v8::ExternalResourceVisitor {
16694  public:
16695   explicit VisitorImpl(TestResource** resource) {
16696     for (int i = 0; i < 4; i++) {
16697       resource_[i] = resource[i];
16698       found_resource_[i] = false;
16699     }
16700   }
16701   virtual ~VisitorImpl() {}
16702   virtual void VisitExternalString(v8::Handle<v8::String> string) {
16703     if (!string->IsExternal()) {
16704       CHECK(string->IsExternalAscii());
16705       return;
16706     }
16707     v8::String::ExternalStringResource* resource =
16708         string->GetExternalStringResource();
16709     CHECK(resource);
16710     for (int i = 0; i < 4; i++) {
16711       if (resource_[i] == resource) {
16712         CHECK(!found_resource_[i]);
16713         found_resource_[i] = true;
16714       }
16715     }
16716   }
16717   void CheckVisitedResources() {
16718     for (int i = 0; i < 4; i++) {
16719       CHECK(found_resource_[i]);
16720     }
16721   }
16722
16723  private:
16724   v8::String::ExternalStringResource* resource_[4];
16725   bool found_resource_[4];
16726 };
16727
16728
16729 TEST(VisitExternalStrings) {
16730   LocalContext env;
16731   v8::HandleScope scope(env->GetIsolate());
16732   const char* string = "Some string";
16733   uint16_t* two_byte_string = AsciiToTwoByteString(string);
16734   TestResource* resource[4];
16735   resource[0] = new TestResource(two_byte_string);
16736   v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
16737   resource[1] = new TestResource(two_byte_string);
16738   v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
16739
16740   // Externalized symbol.
16741   resource[2] = new TestResource(two_byte_string);
16742   v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
16743   CHECK(string2->MakeExternal(resource[2]));
16744
16745   // Symbolized External.
16746   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
16747   v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
16748   HEAP->CollectAllAvailableGarbage();  // Tenure string.
16749   // Turn into a symbol.
16750   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
16751   CHECK(!HEAP->InternalizeString(*string3_i)->IsFailure());
16752   CHECK(string3_i->IsInternalizedString());
16753
16754   // We need to add usages for string* to avoid warnings in GCC 4.7
16755   CHECK(string0->IsExternal());
16756   CHECK(string1->IsExternal());
16757   CHECK(string2->IsExternal());
16758   CHECK(string3->IsExternal());
16759
16760   VisitorImpl visitor(resource);
16761   v8::V8::VisitExternalResources(&visitor);
16762   visitor.CheckVisitedResources();
16763 }
16764
16765
16766 static double DoubleFromBits(uint64_t value) {
16767   double target;
16768   i::OS::MemCopy(&target, &value, sizeof(target));
16769   return target;
16770 }
16771
16772
16773 static uint64_t DoubleToBits(double value) {
16774   uint64_t target;
16775   i::OS::MemCopy(&target, &value, sizeof(target));
16776   return target;
16777 }
16778
16779
16780 static double DoubleToDateTime(double input) {
16781   double date_limit = 864e13;
16782   if (std::isnan(input) || input < -date_limit || input > date_limit) {
16783     return i::OS::nan_value();
16784   }
16785   return (input < 0) ? -(floor(-input)) : floor(input);
16786 }
16787
16788
16789 // We don't have a consistent way to write 64-bit constants syntactically, so we
16790 // split them into two 32-bit constants and combine them programmatically.
16791 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
16792   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
16793 }
16794
16795
16796 THREADED_TEST(QuietSignalingNaNs) {
16797   LocalContext context;
16798   v8::HandleScope scope(context->GetIsolate());
16799   v8::TryCatch try_catch;
16800
16801   // Special double values.
16802   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
16803   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
16804   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
16805   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
16806   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
16807   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
16808   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
16809
16810   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
16811   // on either side of the epoch.
16812   double date_limit = 864e13;
16813
16814   double test_values[] = {
16815       snan,
16816       qnan,
16817       infinity,
16818       max_normal,
16819       date_limit + 1,
16820       date_limit,
16821       min_normal,
16822       max_denormal,
16823       min_denormal,
16824       0,
16825       -0,
16826       -min_denormal,
16827       -max_denormal,
16828       -min_normal,
16829       -date_limit,
16830       -date_limit - 1,
16831       -max_normal,
16832       -infinity,
16833       -qnan,
16834       -snan
16835   };
16836   int num_test_values = 20;
16837
16838   for (int i = 0; i < num_test_values; i++) {
16839     double test_value = test_values[i];
16840
16841     // Check that Number::New preserves non-NaNs and quiets SNaNs.
16842     v8::Handle<v8::Value> number = v8::Number::New(test_value);
16843     double stored_number = number->NumberValue();
16844     if (!std::isnan(test_value)) {
16845       CHECK_EQ(test_value, stored_number);
16846     } else {
16847       uint64_t stored_bits = DoubleToBits(stored_number);
16848       // Check if quiet nan (bits 51..62 all set).
16849 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
16850       // Most significant fraction bit for quiet nan is set to 0
16851       // on MIPS architecture. Allowed by IEEE-754.
16852       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16853 #else
16854       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16855 #endif
16856     }
16857
16858     // Check that Date::New preserves non-NaNs in the date range and
16859     // quiets SNaNs.
16860     v8::Handle<v8::Value> date = v8::Date::New(test_value);
16861     double expected_stored_date = DoubleToDateTime(test_value);
16862     double stored_date = date->NumberValue();
16863     if (!std::isnan(expected_stored_date)) {
16864       CHECK_EQ(expected_stored_date, stored_date);
16865     } else {
16866       uint64_t stored_bits = DoubleToBits(stored_date);
16867       // Check if quiet nan (bits 51..62 all set).
16868 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
16869       // Most significant fraction bit for quiet nan is set to 0
16870       // on MIPS architecture. Allowed by IEEE-754.
16871       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16872 #else
16873       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16874 #endif
16875     }
16876   }
16877 }
16878
16879
16880 static void SpaghettiIncident(
16881     const v8::FunctionCallbackInfo<v8::Value>& args) {
16882   v8::HandleScope scope(args.GetIsolate());
16883   v8::TryCatch tc;
16884   v8::Handle<v8::String> str(args[0]->ToString());
16885   USE(str);
16886   if (tc.HasCaught())
16887     tc.ReThrow();
16888 }
16889
16890
16891 // Test that an exception can be propagated down through a spaghetti
16892 // stack using ReThrow.
16893 THREADED_TEST(SpaghettiStackReThrow) {
16894   v8::HandleScope scope(v8::Isolate::GetCurrent());
16895   LocalContext context;
16896   context->Global()->Set(
16897       v8::String::New("s"),
16898       v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
16899   v8::TryCatch try_catch;
16900   CompileRun(
16901       "var i = 0;"
16902       "var o = {"
16903       "  toString: function () {"
16904       "    if (i == 10) {"
16905       "      throw 'Hey!';"
16906       "    } else {"
16907       "      i++;"
16908       "      return s(o);"
16909       "    }"
16910       "  }"
16911       "};"
16912       "s(o);");
16913   CHECK(try_catch.HasCaught());
16914   v8::String::Utf8Value value(try_catch.Exception());
16915   CHECK_EQ(0, strcmp(*value, "Hey!"));
16916 }
16917
16918
16919 TEST(Regress528) {
16920   v8::V8::Initialize();
16921   v8::Isolate* isolate = v8::Isolate::GetCurrent();
16922   v8::HandleScope scope(isolate);
16923   v8::Local<Context> other_context;
16924   int gc_count;
16925
16926   // Create a context used to keep the code from aging in the compilation
16927   // cache.
16928   other_context = Context::New(isolate);
16929
16930   // Context-dependent context data creates reference from the compilation
16931   // cache to the global object.
16932   const char* source_simple = "1";
16933   {
16934     v8::HandleScope scope(isolate);
16935     v8::Local<Context> context = Context::New(isolate);
16936
16937     context->Enter();
16938     Local<v8::String> obj = v8::String::New("");
16939     context->SetEmbedderData(0, obj);
16940     CompileRun(source_simple);
16941     context->Exit();
16942   }
16943   v8::V8::ContextDisposedNotification();
16944   for (gc_count = 1; gc_count < 10; gc_count++) {
16945     other_context->Enter();
16946     CompileRun(source_simple);
16947     other_context->Exit();
16948     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16949     if (GetGlobalObjectsCount() == 1) break;
16950   }
16951   CHECK_GE(2, gc_count);
16952   CHECK_EQ(1, GetGlobalObjectsCount());
16953
16954   // Eval in a function creates reference from the compilation cache to the
16955   // global object.
16956   const char* source_eval = "function f(){eval('1')}; f()";
16957   {
16958     v8::HandleScope scope(isolate);
16959     v8::Local<Context> context = Context::New(isolate);
16960
16961     context->Enter();
16962     CompileRun(source_eval);
16963     context->Exit();
16964   }
16965   v8::V8::ContextDisposedNotification();
16966   for (gc_count = 1; gc_count < 10; gc_count++) {
16967     other_context->Enter();
16968     CompileRun(source_eval);
16969     other_context->Exit();
16970     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16971     if (GetGlobalObjectsCount() == 1) break;
16972   }
16973   CHECK_GE(2, gc_count);
16974   CHECK_EQ(1, GetGlobalObjectsCount());
16975
16976   // Looking up the line number for an exception creates reference from the
16977   // compilation cache to the global object.
16978   const char* source_exception = "function f(){throw 1;} f()";
16979   {
16980     v8::HandleScope scope(isolate);
16981     v8::Local<Context> context = Context::New(isolate);
16982
16983     context->Enter();
16984     v8::TryCatch try_catch;
16985     CompileRun(source_exception);
16986     CHECK(try_catch.HasCaught());
16987     v8::Handle<v8::Message> message = try_catch.Message();
16988     CHECK(!message.IsEmpty());
16989     CHECK_EQ(1, message->GetLineNumber());
16990     context->Exit();
16991   }
16992   v8::V8::ContextDisposedNotification();
16993   for (gc_count = 1; gc_count < 10; gc_count++) {
16994     other_context->Enter();
16995     CompileRun(source_exception);
16996     other_context->Exit();
16997     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16998     if (GetGlobalObjectsCount() == 1) break;
16999   }
17000   CHECK_GE(2, gc_count);
17001   CHECK_EQ(1, GetGlobalObjectsCount());
17002
17003   v8::V8::ContextDisposedNotification();
17004 }
17005
17006
17007 THREADED_TEST(ScriptOrigin) {
17008   LocalContext env;
17009   v8::HandleScope scope(env->GetIsolate());
17010   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17011   v8::Handle<v8::String> script = v8::String::New(
17012       "function f() {}\n\nfunction g() {}");
17013   v8::Script::Compile(script, &origin)->Run();
17014   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17015       env->Global()->Get(v8::String::New("f")));
17016   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17017       env->Global()->Get(v8::String::New("g")));
17018
17019   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
17020   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
17021   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
17022
17023   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
17024   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
17025   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
17026 }
17027
17028
17029 THREADED_TEST(FunctionGetInferredName) {
17030   LocalContext env;
17031   v8::HandleScope scope(env->GetIsolate());
17032   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17033   v8::Handle<v8::String> script = v8::String::New(
17034       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
17035   v8::Script::Compile(script, &origin)->Run();
17036   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17037       env->Global()->Get(v8::String::New("f")));
17038   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
17039 }
17040
17041
17042 THREADED_TEST(ScriptLineNumber) {
17043   LocalContext env;
17044   v8::HandleScope scope(env->GetIsolate());
17045   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17046   v8::Handle<v8::String> script = v8::String::New(
17047       "function f() {}\n\nfunction g() {}");
17048   v8::Script::Compile(script, &origin)->Run();
17049   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17050       env->Global()->Get(v8::String::New("f")));
17051   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17052       env->Global()->Get(v8::String::New("g")));
17053   CHECK_EQ(0, f->GetScriptLineNumber());
17054   CHECK_EQ(2, g->GetScriptLineNumber());
17055 }
17056
17057
17058 THREADED_TEST(ScriptColumnNumber) {
17059   LocalContext env;
17060   v8::HandleScope scope(env->GetIsolate());
17061   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17062       v8::Integer::New(3), v8::Integer::New(2));
17063   v8::Handle<v8::String> script = v8::String::New(
17064       "function foo() {}\n\n     function bar() {}");
17065   v8::Script::Compile(script, &origin)->Run();
17066   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17067       env->Global()->Get(v8::String::New("foo")));
17068   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17069       env->Global()->Get(v8::String::New("bar")));
17070   CHECK_EQ(14, foo->GetScriptColumnNumber());
17071   CHECK_EQ(17, bar->GetScriptColumnNumber());
17072 }
17073
17074
17075 THREADED_TEST(FunctionGetScriptId) {
17076   LocalContext env;
17077   v8::HandleScope scope(env->GetIsolate());
17078   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17079       v8::Integer::New(3), v8::Integer::New(2));
17080   v8::Handle<v8::String> scriptSource = v8::String::New(
17081       "function foo() {}\n\n     function bar() {}");
17082   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17083   script->Run();
17084   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17085       env->Global()->Get(v8::String::New("foo")));
17086   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17087       env->Global()->Get(v8::String::New("bar")));
17088   CHECK_EQ(script->Id(), foo->GetScriptId());
17089   CHECK_EQ(script->Id(), bar->GetScriptId());
17090 }
17091
17092
17093 static void GetterWhichReturns42(
17094     Local<String> name,
17095     const v8::PropertyCallbackInfo<v8::Value>& info) {
17096   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17097   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17098   info.GetReturnValue().Set(v8_num(42));
17099 }
17100
17101
17102 static void SetterWhichSetsYOnThisTo23(
17103     Local<String> name,
17104     Local<Value> value,
17105     const v8::PropertyCallbackInfo<void>& info) {
17106   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17107   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17108   info.This()->Set(v8_str("y"), v8_num(23));
17109 }
17110
17111
17112 void FooGetInterceptor(Local<String> name,
17113                        const v8::PropertyCallbackInfo<v8::Value>& info) {
17114   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17115   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17116   if (!name->Equals(v8_str("foo"))) return;
17117   info.GetReturnValue().Set(v8_num(42));
17118 }
17119
17120
17121 void FooSetInterceptor(Local<String> name,
17122                        Local<Value> value,
17123                        const v8::PropertyCallbackInfo<v8::Value>& info) {
17124   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17125   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17126   if (!name->Equals(v8_str("foo"))) return;
17127   info.This()->Set(v8_str("y"), v8_num(23));
17128   info.GetReturnValue().Set(v8_num(23));
17129 }
17130
17131
17132 TEST(SetterOnConstructorPrototype) {
17133   v8::HandleScope scope(v8::Isolate::GetCurrent());
17134   Local<ObjectTemplate> templ = ObjectTemplate::New();
17135   templ->SetAccessor(v8_str("x"),
17136                      GetterWhichReturns42,
17137                      SetterWhichSetsYOnThisTo23);
17138   LocalContext context;
17139   context->Global()->Set(v8_str("P"), templ->NewInstance());
17140   CompileRun("function C1() {"
17141              "  this.x = 23;"
17142              "};"
17143              "C1.prototype = P;"
17144              "function C2() {"
17145              "  this.x = 23"
17146              "};"
17147              "C2.prototype = { };"
17148              "C2.prototype.__proto__ = P;");
17149
17150   v8::Local<v8::Script> script;
17151   script = v8::Script::Compile(v8_str("new C1();"));
17152   for (int i = 0; i < 10; i++) {
17153     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17154     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17155     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17156   }
17157
17158   script = v8::Script::Compile(v8_str("new C2();"));
17159   for (int i = 0; i < 10; i++) {
17160     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17161     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
17162     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
17163   }
17164 }
17165
17166
17167 static void NamedPropertyGetterWhichReturns42(
17168     Local<String> name,
17169     const v8::PropertyCallbackInfo<v8::Value>& info) {
17170   info.GetReturnValue().Set(v8_num(42));
17171 }
17172
17173
17174 static void NamedPropertySetterWhichSetsYOnThisTo23(
17175     Local<String> name,
17176     Local<Value> value,
17177     const v8::PropertyCallbackInfo<v8::Value>& info) {
17178   if (name->Equals(v8_str("x"))) {
17179     info.This()->Set(v8_str("y"), v8_num(23));
17180   }
17181 }
17182
17183
17184 THREADED_TEST(InterceptorOnConstructorPrototype) {
17185   v8::HandleScope scope(v8::Isolate::GetCurrent());
17186   Local<ObjectTemplate> templ = ObjectTemplate::New();
17187   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
17188                                  NamedPropertySetterWhichSetsYOnThisTo23);
17189   LocalContext context;
17190   context->Global()->Set(v8_str("P"), templ->NewInstance());
17191   CompileRun("function C1() {"
17192              "  this.x = 23;"
17193              "};"
17194              "C1.prototype = P;"
17195              "function C2() {"
17196              "  this.x = 23"
17197              "};"
17198              "C2.prototype = { };"
17199              "C2.prototype.__proto__ = P;");
17200
17201   v8::Local<v8::Script> script;
17202   script = v8::Script::Compile(v8_str("new C1();"));
17203   for (int i = 0; i < 10; i++) {
17204     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17205     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17206     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17207   }
17208
17209   script = v8::Script::Compile(v8_str("new C2();"));
17210   for (int i = 0; i < 10; i++) {
17211     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17212     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
17213     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
17214   }
17215 }
17216
17217
17218 TEST(Regress618) {
17219   const char* source = "function C1() {"
17220                        "  this.x = 23;"
17221                        "};"
17222                        "C1.prototype = P;";
17223
17224   LocalContext context;
17225   v8::HandleScope scope(context->GetIsolate());
17226   v8::Local<v8::Script> script;
17227
17228   // Use a simple object as prototype.
17229   v8::Local<v8::Object> prototype = v8::Object::New();
17230   prototype->Set(v8_str("y"), v8_num(42));
17231   context->Global()->Set(v8_str("P"), prototype);
17232
17233   // This compile will add the code to the compilation cache.
17234   CompileRun(source);
17235
17236   script = v8::Script::Compile(v8_str("new C1();"));
17237   // Allow enough iterations for the inobject slack tracking logic
17238   // to finalize instance size and install the fast construct stub.
17239   for (int i = 0; i < 256; i++) {
17240     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17241     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17242     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17243   }
17244
17245   // Use an API object with accessors as prototype.
17246   Local<ObjectTemplate> templ = ObjectTemplate::New();
17247   templ->SetAccessor(v8_str("x"),
17248                      GetterWhichReturns42,
17249                      SetterWhichSetsYOnThisTo23);
17250   context->Global()->Set(v8_str("P"), templ->NewInstance());
17251
17252   // This compile will get the code from the compilation cache.
17253   CompileRun(source);
17254
17255   script = v8::Script::Compile(v8_str("new C1();"));
17256   for (int i = 0; i < 10; i++) {
17257     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17258     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17259     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17260   }
17261 }
17262
17263 int prologue_call_count = 0;
17264 int epilogue_call_count = 0;
17265 int prologue_call_count_second = 0;
17266 int epilogue_call_count_second = 0;
17267
17268 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
17269   ++prologue_call_count;
17270 }
17271
17272
17273 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
17274   ++epilogue_call_count;
17275 }
17276
17277
17278 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
17279   ++prologue_call_count_second;
17280 }
17281
17282
17283 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
17284   ++epilogue_call_count_second;
17285 }
17286
17287
17288 TEST(GCCallbacks) {
17289   LocalContext context;
17290
17291   v8::V8::AddGCPrologueCallback(PrologueCallback);
17292   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17293   CHECK_EQ(0, prologue_call_count);
17294   CHECK_EQ(0, epilogue_call_count);
17295   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17296   CHECK_EQ(1, prologue_call_count);
17297   CHECK_EQ(1, epilogue_call_count);
17298   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17299   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17300   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17301   CHECK_EQ(2, prologue_call_count);
17302   CHECK_EQ(2, epilogue_call_count);
17303   CHECK_EQ(1, prologue_call_count_second);
17304   CHECK_EQ(1, epilogue_call_count_second);
17305   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17306   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17307   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17308   CHECK_EQ(2, prologue_call_count);
17309   CHECK_EQ(2, epilogue_call_count);
17310   CHECK_EQ(2, prologue_call_count_second);
17311   CHECK_EQ(2, epilogue_call_count_second);
17312   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17313   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17314   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17315   CHECK_EQ(2, prologue_call_count);
17316   CHECK_EQ(2, epilogue_call_count);
17317   CHECK_EQ(2, prologue_call_count_second);
17318   CHECK_EQ(2, epilogue_call_count_second);
17319 }
17320
17321
17322 THREADED_TEST(AddToJSFunctionResultCache) {
17323   i::FLAG_stress_compaction = false;
17324   i::FLAG_allow_natives_syntax = true;
17325   v8::HandleScope scope(v8::Isolate::GetCurrent());
17326
17327   LocalContext context;
17328
17329   const char* code =
17330       "(function() {"
17331       "  var key0 = 'a';"
17332       "  var key1 = 'b';"
17333       "  var r0 = %_GetFromCache(0, key0);"
17334       "  var r1 = %_GetFromCache(0, key1);"
17335       "  var r0_ = %_GetFromCache(0, key0);"
17336       "  if (r0 !== r0_)"
17337       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17338       "  var r1_ = %_GetFromCache(0, key1);"
17339       "  if (r1 !== r1_)"
17340       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17341       "  return 'PASSED';"
17342       "})()";
17343   HEAP->ClearJSFunctionResultCaches();
17344   ExpectString(code, "PASSED");
17345 }
17346
17347
17348 static const int k0CacheSize = 16;
17349
17350 THREADED_TEST(FillJSFunctionResultCache) {
17351   i::FLAG_allow_natives_syntax = true;
17352   LocalContext context;
17353   v8::HandleScope scope(context->GetIsolate());
17354
17355   const char* code =
17356       "(function() {"
17357       "  var k = 'a';"
17358       "  var r = %_GetFromCache(0, k);"
17359       "  for (var i = 0; i < 16; i++) {"
17360       "    %_GetFromCache(0, 'a' + i);"
17361       "  };"
17362       "  if (r === %_GetFromCache(0, k))"
17363       "    return 'FAILED: k0CacheSize is too small';"
17364       "  return 'PASSED';"
17365       "})()";
17366   HEAP->ClearJSFunctionResultCaches();
17367   ExpectString(code, "PASSED");
17368 }
17369
17370
17371 THREADED_TEST(RoundRobinGetFromCache) {
17372   i::FLAG_allow_natives_syntax = true;
17373   LocalContext context;
17374   v8::HandleScope scope(context->GetIsolate());
17375
17376   const char* code =
17377       "(function() {"
17378       "  var keys = [];"
17379       "  for (var i = 0; i < 16; i++) keys.push(i);"
17380       "  var values = [];"
17381       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17382       "  for (var i = 0; i < 16; i++) {"
17383       "    var v = %_GetFromCache(0, keys[i]);"
17384       "    if (v.toString() !== values[i].toString())"
17385       "      return 'Wrong value for ' + "
17386       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
17387       "  };"
17388       "  return 'PASSED';"
17389       "})()";
17390   HEAP->ClearJSFunctionResultCaches();
17391   ExpectString(code, "PASSED");
17392 }
17393
17394
17395 THREADED_TEST(ReverseGetFromCache) {
17396   i::FLAG_allow_natives_syntax = true;
17397   LocalContext context;
17398   v8::HandleScope scope(context->GetIsolate());
17399
17400   const char* code =
17401       "(function() {"
17402       "  var keys = [];"
17403       "  for (var i = 0; i < 16; i++) keys.push(i);"
17404       "  var values = [];"
17405       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17406       "  for (var i = 15; i >= 16; i--) {"
17407       "    var v = %_GetFromCache(0, keys[i]);"
17408       "    if (v !== values[i])"
17409       "      return 'Wrong value for ' + "
17410       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
17411       "  };"
17412       "  return 'PASSED';"
17413       "})()";
17414   HEAP->ClearJSFunctionResultCaches();
17415   ExpectString(code, "PASSED");
17416 }
17417
17418
17419 THREADED_TEST(TestEviction) {
17420   i::FLAG_allow_natives_syntax = true;
17421   LocalContext context;
17422   v8::HandleScope scope(context->GetIsolate());
17423
17424   const char* code =
17425       "(function() {"
17426       "  for (var i = 0; i < 2*16; i++) {"
17427       "    %_GetFromCache(0, 'a' + i);"
17428       "  };"
17429       "  return 'PASSED';"
17430       "})()";
17431   HEAP->ClearJSFunctionResultCaches();
17432   ExpectString(code, "PASSED");
17433 }
17434
17435
17436 THREADED_TEST(TwoByteStringInAsciiCons) {
17437   // See Chromium issue 47824.
17438   LocalContext context;
17439   v8::HandleScope scope(context->GetIsolate());
17440
17441   const char* init_code =
17442       "var str1 = 'abelspendabel';"
17443       "var str2 = str1 + str1 + str1;"
17444       "str2;";
17445   Local<Value> result = CompileRun(init_code);
17446
17447   Local<Value> indexof = CompileRun("str2.indexOf('els')");
17448   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
17449
17450   CHECK(result->IsString());
17451   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
17452   int length = string->length();
17453   CHECK(string->IsOneByteRepresentation());
17454
17455   FlattenString(string);
17456   i::Handle<i::String> flat_string = FlattenGetString(string);
17457
17458   CHECK(string->IsOneByteRepresentation());
17459   CHECK(flat_string->IsOneByteRepresentation());
17460
17461   // Create external resource.
17462   uint16_t* uc16_buffer = new uint16_t[length + 1];
17463
17464   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
17465   uc16_buffer[length] = 0;
17466
17467   TestResource resource(uc16_buffer);
17468
17469   flat_string->MakeExternal(&resource);
17470
17471   CHECK(flat_string->IsTwoByteRepresentation());
17472
17473   // If the cons string has been short-circuited, skip the following checks.
17474   if (!string.is_identical_to(flat_string)) {
17475     // At this point, we should have a Cons string which is flat and ASCII,
17476     // with a first half that is a two-byte string (although it only contains
17477     // ASCII characters). This is a valid sequence of steps, and it can happen
17478     // in real pages.
17479     CHECK(string->IsOneByteRepresentation());
17480     i::ConsString* cons = i::ConsString::cast(*string);
17481     CHECK_EQ(0, cons->second()->length());
17482     CHECK(cons->first()->IsTwoByteRepresentation());
17483   }
17484
17485   // Check that some string operations work.
17486
17487   // Atom RegExp.
17488   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
17489   CHECK_EQ(6, reresult->Int32Value());
17490
17491   // Nonatom RegExp.
17492   reresult = CompileRun("str2.match(/abe./g).length;");
17493   CHECK_EQ(6, reresult->Int32Value());
17494
17495   reresult = CompileRun("str2.search(/bel/g);");
17496   CHECK_EQ(1, reresult->Int32Value());
17497
17498   reresult = CompileRun("str2.search(/be./g);");
17499   CHECK_EQ(1, reresult->Int32Value());
17500
17501   ExpectTrue("/bel/g.test(str2);");
17502
17503   ExpectTrue("/be./g.test(str2);");
17504
17505   reresult = CompileRun("/bel/g.exec(str2);");
17506   CHECK(!reresult->IsNull());
17507
17508   reresult = CompileRun("/be./g.exec(str2);");
17509   CHECK(!reresult->IsNull());
17510
17511   ExpectString("str2.substring(2, 10);", "elspenda");
17512
17513   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
17514
17515   ExpectString("str2.charAt(2);", "e");
17516
17517   ExpectObject("str2.indexOf('els');", indexof);
17518
17519   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
17520
17521   reresult = CompileRun("str2.charCodeAt(2);");
17522   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
17523 }
17524
17525
17526 TEST(ContainsOnlyOneByte) {
17527   v8::V8::Initialize();
17528   v8::Isolate* isolate = v8::Isolate::GetCurrent();
17529   v8::HandleScope scope(isolate);
17530   // Make a buffer long enough that it won't automatically be converted.
17531   const int length = 512;
17532   // Ensure word aligned assignment.
17533   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
17534   i::SmartArrayPointer<uintptr_t>
17535   aligned_contents(new uintptr_t[aligned_length]);
17536   uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents);
17537   // Set to contain only one byte.
17538   for (int i = 0; i < length-1; i++) {
17539     string_contents[i] = 0x41;
17540   }
17541   string_contents[length-1] = 0;
17542   // Simple case.
17543   Handle<String> string;
17544   string = String::NewExternal(new TestResource(string_contents));
17545   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17546   // Counter example.
17547   string = String::NewFromTwoByte(isolate, string_contents);
17548   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17549   // Test left right and balanced cons strings.
17550   Handle<String> base = String::NewFromUtf8(isolate, "a");
17551   Handle<String> left = base;
17552   Handle<String> right = base;
17553   for (int i = 0; i < 1000; i++) {
17554     left = String::Concat(base, left);
17555     right = String::Concat(right, base);
17556   }
17557   Handle<String> balanced = String::Concat(left, base);
17558   balanced = String::Concat(balanced, right);
17559   Handle<String> cons_strings[] = {left, balanced, right};
17560   Handle<String> two_byte =
17561       String::NewExternal(new TestResource(string_contents));
17562   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
17563     // Base assumptions.
17564     string = cons_strings[i];
17565     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17566     // Test left and right concatentation.
17567     string = String::Concat(two_byte, cons_strings[i]);
17568     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17569     string = String::Concat(cons_strings[i], two_byte);
17570     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17571   }
17572   // Set bits in different positions
17573   // for strings of different lengths and alignments.
17574   for (int alignment = 0; alignment < 7; alignment++) {
17575     for (int size = 2; alignment + size < length; size *= 2) {
17576       int zero_offset = size + alignment;
17577       string_contents[zero_offset] = 0;
17578       for (int i = 0; i < size; i++) {
17579         int shift = 8 + (i % 7);
17580         string_contents[alignment + i] = 1 << shift;
17581         string =
17582             String::NewExternal(new TestResource(string_contents + alignment));
17583         CHECK_EQ(size, string->Length());
17584         CHECK(!string->ContainsOnlyOneByte());
17585         string_contents[alignment + i] = 0x41;
17586       }
17587       string_contents[zero_offset] = 0x41;
17588     }
17589   }
17590 }
17591
17592
17593 // Failed access check callback that performs a GC on each invocation.
17594 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
17595                                  v8::AccessType type,
17596                                  Local<v8::Value> data) {
17597   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17598 }
17599
17600
17601 TEST(GCInFailedAccessCheckCallback) {
17602   // Install a failed access check callback that performs a GC on each
17603   // invocation. Then force the callback to be called from va
17604
17605   v8::V8::Initialize();
17606   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
17607
17608   v8::HandleScope scope(v8::Isolate::GetCurrent());
17609
17610   // Create an ObjectTemplate for global objects and install access
17611   // check callbacks that will block access.
17612   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
17613   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
17614                                            IndexedGetAccessBlocker,
17615                                            v8::Handle<v8::Value>(),
17616                                            false);
17617
17618   // Create a context and set an x property on it's global object.
17619   LocalContext context0(NULL, global_template);
17620   context0->Global()->Set(v8_str("x"), v8_num(42));
17621   v8::Handle<v8::Object> global0 = context0->Global();
17622
17623   // Create a context with a different security token so that the
17624   // failed access check callback will be called on each access.
17625   LocalContext context1(NULL, global_template);
17626   context1->Global()->Set(v8_str("other"), global0);
17627
17628   // Get property with failed access check.
17629   ExpectUndefined("other.x");
17630
17631   // Get element with failed access check.
17632   ExpectUndefined("other[0]");
17633
17634   // Set property with failed access check.
17635   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
17636   CHECK(result->IsObject());
17637
17638   // Set element with failed access check.
17639   result = CompileRun("other[0] = new Object()");
17640   CHECK(result->IsObject());
17641
17642   // Get property attribute with failed access check.
17643   ExpectFalse("\'x\' in other");
17644
17645   // Get property attribute for element with failed access check.
17646   ExpectFalse("0 in other");
17647
17648   // Delete property.
17649   ExpectFalse("delete other.x");
17650
17651   // Delete element.
17652   CHECK_EQ(false, global0->Delete(0));
17653
17654   // DefineAccessor.
17655   CHECK_EQ(false,
17656            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
17657
17658   // Define JavaScript accessor.
17659   ExpectUndefined("Object.prototype.__defineGetter__.call("
17660                   "    other, \'x\', function() { return 42; })");
17661
17662   // LookupAccessor.
17663   ExpectUndefined("Object.prototype.__lookupGetter__.call("
17664                   "    other, \'x\')");
17665
17666   // HasLocalElement.
17667   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
17668
17669   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
17670   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
17671   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
17672
17673   // Reset the failed access check callback so it does not influence
17674   // the other tests.
17675   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
17676 }
17677
17678
17679 TEST(DefaultIsolateGetCurrent) {
17680   CHECK(v8::Isolate::GetCurrent() != NULL);
17681   v8::Isolate* isolate = v8::Isolate::GetCurrent();
17682   CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
17683   printf("*** %s\n", "DefaultIsolateGetCurrent success");
17684 }
17685
17686
17687 TEST(IsolateNewDispose) {
17688   v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
17689   v8::Isolate* isolate = v8::Isolate::New();
17690   CHECK(isolate != NULL);
17691   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
17692   CHECK(current_isolate != isolate);
17693   CHECK(current_isolate == v8::Isolate::GetCurrent());
17694
17695   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17696   last_location = last_message = NULL;
17697   isolate->Dispose();
17698   CHECK_EQ(last_location, NULL);
17699   CHECK_EQ(last_message, NULL);
17700 }
17701
17702
17703 TEST(IsolateEnterExitDefault) {
17704   v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
17705   CHECK(current_isolate != NULL);  // Default isolate.
17706   v8::HandleScope scope(current_isolate);
17707   LocalContext context;
17708   ExpectString("'hello'", "hello");
17709   current_isolate->Enter();
17710   ExpectString("'still working'", "still working");
17711   current_isolate->Exit();
17712   ExpectString("'still working 2'", "still working 2");
17713   current_isolate->Exit();
17714   // Default isolate is always, well, 'default current'.
17715   CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
17716   // Still working since default isolate is auto-entering any thread
17717   // that has no isolate and attempts to execute V8 APIs.
17718   ExpectString("'still working 3'", "still working 3");
17719 }
17720
17721
17722 TEST(DisposeDefaultIsolate) {
17723   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17724
17725   // Run some V8 code to trigger default isolate to become 'current'.
17726   v8::HandleScope scope(v8::Isolate::GetCurrent());
17727   LocalContext context;
17728   ExpectString("'run some V8'", "run some V8");
17729
17730   v8::Isolate* isolate = v8::Isolate::GetCurrent();
17731   CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
17732   last_location = last_message = NULL;
17733   isolate->Dispose();
17734   // It is not possible to dispose default isolate via Isolate API.
17735   CHECK_NE(last_location, NULL);
17736   CHECK_NE(last_message, NULL);
17737 }
17738
17739
17740 TEST(RunDefaultAndAnotherIsolate) {
17741   v8::HandleScope scope(v8::Isolate::GetCurrent());
17742   LocalContext context;
17743
17744   // Enter new isolate.
17745   v8::Isolate* isolate = v8::Isolate::New();
17746   CHECK(isolate);
17747   isolate->Enter();
17748   { // Need this block because subsequent Exit() will deallocate Heap,
17749     // so we need all scope objects to be deconstructed when it happens.
17750     v8::HandleScope scope_new(isolate);
17751     LocalContext context_new;
17752
17753     // Run something in new isolate.
17754     CompileRun("var foo = 153;");
17755     ExpectTrue("function f() { return foo == 153; }; f()");
17756   }
17757   isolate->Exit();
17758
17759   // This runs automatically in default isolate.
17760   // Variables in another isolate should be not available.
17761   ExpectTrue("function f() {"
17762              "  try {"
17763              "    foo;"
17764              "    return false;"
17765              "  } catch(e) {"
17766              "    return true;"
17767              "  }"
17768              "};"
17769              "var bar = 371;"
17770              "f()");
17771
17772   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17773   last_location = last_message = NULL;
17774   isolate->Dispose();
17775   CHECK_EQ(last_location, NULL);
17776   CHECK_EQ(last_message, NULL);
17777
17778   // Check that default isolate still runs.
17779   ExpectTrue("function f() { return bar == 371; }; f()");
17780 }
17781
17782
17783 TEST(DisposeIsolateWhenInUse) {
17784   v8::Isolate* isolate = v8::Isolate::New();
17785   CHECK(isolate);
17786   isolate->Enter();
17787   v8::HandleScope scope(isolate);
17788   LocalContext context;
17789   // Run something in this isolate.
17790   ExpectTrue("true");
17791   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17792   last_location = last_message = NULL;
17793   // Still entered, should fail.
17794   isolate->Dispose();
17795   CHECK_NE(last_location, NULL);
17796   CHECK_NE(last_message, NULL);
17797 }
17798
17799
17800 TEST(RunTwoIsolatesOnSingleThread) {
17801   // Run isolate 1.
17802   v8::Isolate* isolate1 = v8::Isolate::New();
17803   isolate1->Enter();
17804   v8::Persistent<v8::Context> context1;
17805   {
17806     v8::HandleScope scope(isolate1);
17807     context1.Reset(isolate1, Context::New(isolate1));
17808   }
17809
17810   {
17811     v8::HandleScope scope(isolate1);
17812     v8::Local<v8::Context> context =
17813         v8::Local<v8::Context>::New(isolate1, context1);
17814     v8::Context::Scope context_scope(context);
17815     // Run something in new isolate.
17816     CompileRun("var foo = 'isolate 1';");
17817     ExpectString("function f() { return foo; }; f()", "isolate 1");
17818   }
17819
17820   // Run isolate 2.
17821   v8::Isolate* isolate2 = v8::Isolate::New();
17822   v8::Persistent<v8::Context> context2;
17823
17824   {
17825     v8::Isolate::Scope iscope(isolate2);
17826     v8::HandleScope scope(isolate2);
17827     context2.Reset(isolate2, Context::New(isolate2));
17828     v8::Local<v8::Context> context =
17829         v8::Local<v8::Context>::New(isolate2, context2);
17830     v8::Context::Scope context_scope(context);
17831
17832     // Run something in new isolate.
17833     CompileRun("var foo = 'isolate 2';");
17834     ExpectString("function f() { return foo; }; f()", "isolate 2");
17835   }
17836
17837   {
17838     v8::HandleScope scope(isolate1);
17839     v8::Local<v8::Context> context =
17840         v8::Local<v8::Context>::New(isolate1, context1);
17841     v8::Context::Scope context_scope(context);
17842     // Now again in isolate 1
17843     ExpectString("function f() { return foo; }; f()", "isolate 1");
17844   }
17845
17846   isolate1->Exit();
17847
17848   // Run some stuff in default isolate.
17849   v8::Persistent<v8::Context> context_default;
17850   {
17851     v8::Isolate* isolate = v8::Isolate::GetCurrent();
17852     v8::Isolate::Scope iscope(isolate);
17853     v8::HandleScope scope(isolate);
17854     context_default.Reset(isolate, Context::New(isolate));
17855   }
17856
17857   {
17858     v8::HandleScope scope(v8::Isolate::GetCurrent());
17859     v8::Local<v8::Context> context =
17860         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default);
17861     v8::Context::Scope context_scope(context);
17862     // Variables in other isolates should be not available, verify there
17863     // is an exception.
17864     ExpectTrue("function f() {"
17865                "  try {"
17866                "    foo;"
17867                "    return false;"
17868                "  } catch(e) {"
17869                "    return true;"
17870                "  }"
17871                "};"
17872                "var isDefaultIsolate = true;"
17873                "f()");
17874   }
17875
17876   isolate1->Enter();
17877
17878   {
17879     v8::Isolate::Scope iscope(isolate2);
17880     v8::HandleScope scope(v8::Isolate::GetCurrent());
17881     v8::Local<v8::Context> context =
17882         v8::Local<v8::Context>::New(isolate2, context2);
17883     v8::Context::Scope context_scope(context);
17884     ExpectString("function f() { return foo; }; f()", "isolate 2");
17885   }
17886
17887   {
17888     v8::HandleScope scope(v8::Isolate::GetCurrent());
17889     v8::Local<v8::Context> context =
17890         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17891     v8::Context::Scope context_scope(context);
17892     ExpectString("function f() { return foo; }; f()", "isolate 1");
17893   }
17894
17895   {
17896     v8::Isolate::Scope iscope(isolate2);
17897     context2.Dispose();
17898   }
17899
17900   context1.Dispose();
17901   isolate1->Exit();
17902
17903   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17904   last_location = last_message = NULL;
17905
17906   isolate1->Dispose();
17907   CHECK_EQ(last_location, NULL);
17908   CHECK_EQ(last_message, NULL);
17909
17910   isolate2->Dispose();
17911   CHECK_EQ(last_location, NULL);
17912   CHECK_EQ(last_message, NULL);
17913
17914   // Check that default isolate still runs.
17915   {
17916     v8::HandleScope scope(v8::Isolate::GetCurrent());
17917     v8::Local<v8::Context> context =
17918         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default);
17919     v8::Context::Scope context_scope(context);
17920     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17921   }
17922 }
17923
17924
17925 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17926   v8::Isolate::Scope isolate_scope(isolate);
17927   v8::HandleScope scope(isolate);
17928   LocalContext context;
17929   i::ScopedVector<char> code(1024);
17930   i::OS::SNPrintF(code, "function fib(n) {"
17931                         "  if (n <= 2) return 1;"
17932                         "  return fib(n-1) + fib(n-2);"
17933                         "}"
17934                         "fib(%d)", limit);
17935   Local<Value> value = CompileRun(code.start());
17936   CHECK(value->IsNumber());
17937   return static_cast<int>(value->NumberValue());
17938 }
17939
17940 class IsolateThread : public v8::internal::Thread {
17941  public:
17942   IsolateThread(v8::Isolate* isolate, int fib_limit)
17943       : Thread("IsolateThread"),
17944         isolate_(isolate),
17945         fib_limit_(fib_limit),
17946         result_(0) { }
17947
17948   void Run() {
17949     result_ = CalcFibonacci(isolate_, fib_limit_);
17950   }
17951
17952   int result() { return result_; }
17953
17954  private:
17955   v8::Isolate* isolate_;
17956   int fib_limit_;
17957   int result_;
17958 };
17959
17960
17961 TEST(MultipleIsolatesOnIndividualThreads) {
17962   v8::Isolate* isolate1 = v8::Isolate::New();
17963   v8::Isolate* isolate2 = v8::Isolate::New();
17964
17965   IsolateThread thread1(isolate1, 21);
17966   IsolateThread thread2(isolate2, 12);
17967
17968   // Compute some fibonacci numbers on 3 threads in 3 isolates.
17969   thread1.Start();
17970   thread2.Start();
17971
17972   int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
17973   int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
17974
17975   thread1.Join();
17976   thread2.Join();
17977
17978   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17979   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17980   CHECK_EQ(result1, 10946);
17981   CHECK_EQ(result2, 144);
17982   CHECK_EQ(result1, thread1.result());
17983   CHECK_EQ(result2, thread2.result());
17984
17985   isolate1->Dispose();
17986   isolate2->Dispose();
17987 }
17988
17989
17990 TEST(IsolateDifferentContexts) {
17991   v8::Isolate* isolate = v8::Isolate::New();
17992   Local<v8::Context> context;
17993   {
17994     v8::Isolate::Scope isolate_scope(isolate);
17995     v8::HandleScope handle_scope(isolate);
17996     context = v8::Context::New(isolate);
17997     v8::Context::Scope context_scope(context);
17998     Local<Value> v = CompileRun("2");
17999     CHECK(v->IsNumber());
18000     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
18001   }
18002   {
18003     v8::Isolate::Scope isolate_scope(isolate);
18004     v8::HandleScope handle_scope(isolate);
18005     context = v8::Context::New(isolate);
18006     v8::Context::Scope context_scope(context);
18007     Local<Value> v = CompileRun("22");
18008     CHECK(v->IsNumber());
18009     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
18010   }
18011 }
18012
18013 class InitDefaultIsolateThread : public v8::internal::Thread {
18014  public:
18015   enum TestCase {
18016     IgnoreOOM,
18017     SetResourceConstraints,
18018     SetFatalHandler,
18019     SetCounterFunction,
18020     SetCreateHistogramFunction,
18021     SetAddHistogramSampleFunction
18022   };
18023
18024   explicit InitDefaultIsolateThread(TestCase testCase)
18025       : Thread("InitDefaultIsolateThread"),
18026         testCase_(testCase),
18027         result_(false) { }
18028
18029   void Run() {
18030     switch (testCase_) {
18031     case IgnoreOOM:
18032       v8::V8::IgnoreOutOfMemoryException();
18033       break;
18034
18035     case SetResourceConstraints: {
18036       static const int K = 1024;
18037       v8::ResourceConstraints constraints;
18038       constraints.set_max_young_space_size(256 * K);
18039       constraints.set_max_old_space_size(4 * K * K);
18040       v8::SetResourceConstraints(&constraints);
18041       break;
18042     }
18043
18044     case SetFatalHandler:
18045       v8::V8::SetFatalErrorHandler(NULL);
18046       break;
18047
18048     case SetCounterFunction:
18049       v8::V8::SetCounterFunction(NULL);
18050       break;
18051
18052     case SetCreateHistogramFunction:
18053       v8::V8::SetCreateHistogramFunction(NULL);
18054       break;
18055
18056     case SetAddHistogramSampleFunction:
18057       v8::V8::SetAddHistogramSampleFunction(NULL);
18058       break;
18059     }
18060     result_ = true;
18061   }
18062
18063   bool result() { return result_; }
18064
18065  private:
18066   TestCase testCase_;
18067   bool result_;
18068 };
18069
18070
18071 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
18072   InitDefaultIsolateThread thread(testCase);
18073   thread.Start();
18074   thread.Join();
18075   CHECK_EQ(thread.result(), true);
18076 }
18077
18078
18079 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
18080   InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
18081 }
18082
18083
18084 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
18085   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
18086 }
18087
18088
18089 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
18090   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
18091 }
18092
18093
18094 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
18095   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
18096 }
18097
18098
18099 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
18100   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
18101 }
18102
18103
18104 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
18105   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
18106 }
18107
18108
18109 TEST(StringCheckMultipleContexts) {
18110   const char* code =
18111       "(function() { return \"a\".charAt(0); })()";
18112
18113   {
18114     // Run the code twice in the first context to initialize the call IC.
18115     LocalContext context1;
18116     v8::HandleScope scope(context1->GetIsolate());
18117     ExpectString(code, "a");
18118     ExpectString(code, "a");
18119   }
18120
18121   {
18122     // Change the String.prototype in the second context and check
18123     // that the right function gets called.
18124     LocalContext context2;
18125     v8::HandleScope scope(context2->GetIsolate());
18126     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
18127     ExpectString(code, "not a");
18128   }
18129 }
18130
18131
18132 TEST(NumberCheckMultipleContexts) {
18133   const char* code =
18134       "(function() { return (42).toString(); })()";
18135
18136   {
18137     // Run the code twice in the first context to initialize the call IC.
18138     LocalContext context1;
18139     v8::HandleScope scope(context1->GetIsolate());
18140     ExpectString(code, "42");
18141     ExpectString(code, "42");
18142   }
18143
18144   {
18145     // Change the Number.prototype in the second context and check
18146     // that the right function gets called.
18147     LocalContext context2;
18148     v8::HandleScope scope(context2->GetIsolate());
18149     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
18150     ExpectString(code, "not 42");
18151   }
18152 }
18153
18154
18155 TEST(BooleanCheckMultipleContexts) {
18156   const char* code =
18157       "(function() { return true.toString(); })()";
18158
18159   {
18160     // Run the code twice in the first context to initialize the call IC.
18161     LocalContext context1;
18162     v8::HandleScope scope(context1->GetIsolate());
18163     ExpectString(code, "true");
18164     ExpectString(code, "true");
18165   }
18166
18167   {
18168     // Change the Boolean.prototype in the second context and check
18169     // that the right function gets called.
18170     LocalContext context2;
18171     v8::HandleScope scope(context2->GetIsolate());
18172     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
18173     ExpectString(code, "");
18174   }
18175 }
18176
18177
18178 TEST(DontDeleteCellLoadIC) {
18179   const char* function_code =
18180       "function readCell() { while (true) { return cell; } }";
18181
18182   {
18183     // Run the code twice in the first context to initialize the load
18184     // IC for a don't delete cell.
18185     LocalContext context1;
18186     v8::HandleScope scope(context1->GetIsolate());
18187     CompileRun("var cell = \"first\";");
18188     ExpectBoolean("delete cell", false);
18189     CompileRun(function_code);
18190     ExpectString("readCell()", "first");
18191     ExpectString("readCell()", "first");
18192   }
18193
18194   {
18195     // Use a deletable cell in the second context.
18196     LocalContext context2;
18197     v8::HandleScope scope(context2->GetIsolate());
18198     CompileRun("cell = \"second\";");
18199     CompileRun(function_code);
18200     ExpectString("readCell()", "second");
18201     ExpectBoolean("delete cell", true);
18202     ExpectString("(function() {"
18203                  "  try {"
18204                  "    return readCell();"
18205                  "  } catch(e) {"
18206                  "    return e.toString();"
18207                  "  }"
18208                  "})()",
18209                  "ReferenceError: cell is not defined");
18210     CompileRun("cell = \"new_second\";");
18211     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18212     ExpectString("readCell()", "new_second");
18213     ExpectString("readCell()", "new_second");
18214   }
18215 }
18216
18217
18218 TEST(DontDeleteCellLoadICForceDelete) {
18219   const char* function_code =
18220       "function readCell() { while (true) { return cell; } }";
18221
18222   // Run the code twice to initialize the load IC for a don't delete
18223   // cell.
18224   LocalContext context;
18225   v8::HandleScope scope(context->GetIsolate());
18226   CompileRun("var cell = \"value\";");
18227   ExpectBoolean("delete cell", false);
18228   CompileRun(function_code);
18229   ExpectString("readCell()", "value");
18230   ExpectString("readCell()", "value");
18231
18232   // Delete the cell using the API and check the inlined code works
18233   // correctly.
18234   CHECK(context->Global()->ForceDelete(v8_str("cell")));
18235   ExpectString("(function() {"
18236                "  try {"
18237                "    return readCell();"
18238                "  } catch(e) {"
18239                "    return e.toString();"
18240                "  }"
18241                "})()",
18242                "ReferenceError: cell is not defined");
18243 }
18244
18245
18246 TEST(DontDeleteCellLoadICAPI) {
18247   const char* function_code =
18248       "function readCell() { while (true) { return cell; } }";
18249
18250   // Run the code twice to initialize the load IC for a don't delete
18251   // cell created using the API.
18252   LocalContext context;
18253   v8::HandleScope scope(context->GetIsolate());
18254   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
18255   ExpectBoolean("delete cell", false);
18256   CompileRun(function_code);
18257   ExpectString("readCell()", "value");
18258   ExpectString("readCell()", "value");
18259
18260   // Delete the cell using the API and check the inlined code works
18261   // correctly.
18262   CHECK(context->Global()->ForceDelete(v8_str("cell")));
18263   ExpectString("(function() {"
18264                "  try {"
18265                "    return readCell();"
18266                "  } catch(e) {"
18267                "    return e.toString();"
18268                "  }"
18269                "})()",
18270                "ReferenceError: cell is not defined");
18271 }
18272
18273
18274 class Visitor42 : public v8::PersistentHandleVisitor {
18275  public:
18276   explicit Visitor42(v8::Persistent<v8::Object>* object)
18277       : counter_(0), object_(object) { }
18278
18279   virtual void VisitPersistentHandle(Persistent<Value>* value,
18280                                      uint16_t class_id) {
18281     if (class_id != 42) return;
18282     CHECK_EQ(42, value->WrapperClassId());
18283     v8::Isolate* isolate = v8::Isolate::GetCurrent();
18284     v8::HandleScope handle_scope(isolate);
18285     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
18286     v8::Handle<v8::Value> object =
18287         v8::Local<v8::Object>::New(isolate, *object_);
18288     CHECK(handle->IsObject());
18289     CHECK_EQ(Handle<Object>::Cast(handle), object);
18290     ++counter_;
18291   }
18292
18293   int counter_;
18294   v8::Persistent<v8::Object>* object_;
18295 };
18296
18297
18298 TEST(PersistentHandleVisitor) {
18299   LocalContext context;
18300   v8::Isolate* isolate = context->GetIsolate();
18301   v8::HandleScope scope(isolate);
18302   v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18303   CHECK_EQ(0, object.WrapperClassId(isolate));
18304   object.SetWrapperClassId(isolate, 42);
18305   CHECK_EQ(42, object.WrapperClassId(isolate));
18306
18307   Visitor42 visitor(&object);
18308   v8::V8::VisitHandlesWithClassIds(&visitor);
18309   CHECK_EQ(1, visitor.counter_);
18310
18311   object.Dispose(isolate);
18312 }
18313
18314
18315 TEST(WrapperClassId) {
18316   LocalContext context;
18317   v8::Isolate* isolate = context->GetIsolate();
18318   v8::HandleScope scope(isolate);
18319   v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18320   CHECK_EQ(0, object.WrapperClassId(isolate));
18321   object.SetWrapperClassId(isolate, 65535);
18322   CHECK_EQ(65535, object.WrapperClassId(isolate));
18323   object.Dispose(isolate);
18324 }
18325
18326
18327 TEST(PersistentHandleInNewSpaceVisitor) {
18328   LocalContext context;
18329   v8::Isolate* isolate = context->GetIsolate();
18330   v8::HandleScope scope(isolate);
18331   v8::Persistent<v8::Object> object1(isolate, v8::Object::New());
18332   CHECK_EQ(0, object1.WrapperClassId(isolate));
18333   object1.SetWrapperClassId(isolate, 42);
18334   CHECK_EQ(42, object1.WrapperClassId(isolate));
18335
18336   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18337
18338   v8::Persistent<v8::Object> object2(isolate, v8::Object::New());
18339   CHECK_EQ(0, object2.WrapperClassId(isolate));
18340   object2.SetWrapperClassId(isolate, 42);
18341   CHECK_EQ(42, object2.WrapperClassId(isolate));
18342
18343   Visitor42 visitor(&object2);
18344   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18345   CHECK_EQ(1, visitor.counter_);
18346
18347   object1.Dispose(isolate);
18348   object2.Dispose(isolate);
18349 }
18350
18351
18352 TEST(RegExp) {
18353   LocalContext context;
18354   v8::HandleScope scope(context->GetIsolate());
18355
18356   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18357   CHECK(re->IsRegExp());
18358   CHECK(re->GetSource()->Equals(v8_str("foo")));
18359   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18360
18361   re = v8::RegExp::New(v8_str("bar"),
18362                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18363                                                       v8::RegExp::kGlobal));
18364   CHECK(re->IsRegExp());
18365   CHECK(re->GetSource()->Equals(v8_str("bar")));
18366   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18367            static_cast<int>(re->GetFlags()));
18368
18369   re = v8::RegExp::New(v8_str("baz"),
18370                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18371                                                       v8::RegExp::kMultiline));
18372   CHECK(re->IsRegExp());
18373   CHECK(re->GetSource()->Equals(v8_str("baz")));
18374   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18375            static_cast<int>(re->GetFlags()));
18376
18377   re = CompileRun("/quux/").As<v8::RegExp>();
18378   CHECK(re->IsRegExp());
18379   CHECK(re->GetSource()->Equals(v8_str("quux")));
18380   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18381
18382   re = CompileRun("/quux/gm").As<v8::RegExp>();
18383   CHECK(re->IsRegExp());
18384   CHECK(re->GetSource()->Equals(v8_str("quux")));
18385   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18386            static_cast<int>(re->GetFlags()));
18387
18388   // Override the RegExp constructor and check the API constructor
18389   // still works.
18390   CompileRun("RegExp = function() {}");
18391
18392   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18393   CHECK(re->IsRegExp());
18394   CHECK(re->GetSource()->Equals(v8_str("foobar")));
18395   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18396
18397   re = v8::RegExp::New(v8_str("foobarbaz"),
18398                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18399                                                       v8::RegExp::kMultiline));
18400   CHECK(re->IsRegExp());
18401   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18402   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18403            static_cast<int>(re->GetFlags()));
18404
18405   context->Global()->Set(v8_str("re"), re);
18406   ExpectTrue("re.test('FoobarbaZ')");
18407
18408   // RegExps are objects on which you can set properties.
18409   re->Set(v8_str("property"), v8::Integer::New(32));
18410   v8::Handle<v8::Value> value(CompileRun("re.property"));
18411   CHECK_EQ(32, value->Int32Value());
18412
18413   v8::TryCatch try_catch;
18414   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18415   CHECK(re.IsEmpty());
18416   CHECK(try_catch.HasCaught());
18417   context->Global()->Set(v8_str("ex"), try_catch.Exception());
18418   ExpectTrue("ex instanceof SyntaxError");
18419 }
18420
18421
18422 THREADED_TEST(Equals) {
18423   LocalContext localContext;
18424   v8::HandleScope handleScope(localContext->GetIsolate());
18425
18426   v8::Handle<v8::Object> globalProxy = localContext->Global();
18427   v8::Handle<Value> global = globalProxy->GetPrototype();
18428
18429   CHECK(global->StrictEquals(global));
18430   CHECK(!global->StrictEquals(globalProxy));
18431   CHECK(!globalProxy->StrictEquals(global));
18432   CHECK(globalProxy->StrictEquals(globalProxy));
18433
18434   CHECK(global->Equals(global));
18435   CHECK(!global->Equals(globalProxy));
18436   CHECK(!globalProxy->Equals(global));
18437   CHECK(globalProxy->Equals(globalProxy));
18438 }
18439
18440
18441 static void Getter(v8::Local<v8::String> property,
18442                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
18443   info.GetReturnValue().Set(v8_str("42!"));
18444 }
18445
18446
18447 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18448   v8::Handle<v8::Array> result = v8::Array::New();
18449   result->Set(0, v8_str("universalAnswer"));
18450   info.GetReturnValue().Set(result);
18451 }
18452
18453
18454 TEST(NamedEnumeratorAndForIn) {
18455   LocalContext context;
18456   v8::HandleScope handle_scope(context->GetIsolate());
18457   v8::Context::Scope context_scope(context.local());
18458
18459   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
18460   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
18461   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
18462   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
18463         "var result = []; for (var k in o) result.push(k); result"));
18464   CHECK_EQ(1, result->Length());
18465   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
18466 }
18467
18468
18469 TEST(DefinePropertyPostDetach) {
18470   LocalContext context;
18471   v8::HandleScope scope(context->GetIsolate());
18472   v8::Handle<v8::Object> proxy = context->Global();
18473   v8::Handle<v8::Function> define_property =
18474       CompileRun("(function() {"
18475                  "  Object.defineProperty("
18476                  "    this,"
18477                  "    1,"
18478                  "    { configurable: true, enumerable: true, value: 3 });"
18479                  "})").As<Function>();
18480   context->DetachGlobal();
18481   define_property->Call(proxy, 0, NULL);
18482 }
18483
18484
18485 static void InstallContextId(v8::Handle<Context> context, int id) {
18486   Context::Scope scope(context);
18487   CompileRun("Object.prototype").As<Object>()->
18488       Set(v8_str("context_id"), v8::Integer::New(id));
18489 }
18490
18491
18492 static void CheckContextId(v8::Handle<Object> object, int expected) {
18493   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
18494 }
18495
18496
18497 THREADED_TEST(CreationContext) {
18498   HandleScope handle_scope(v8::Isolate::GetCurrent());
18499   Handle<Context> context1 = Context::New(v8::Isolate::GetCurrent());
18500   InstallContextId(context1, 1);
18501   Handle<Context> context2 = Context::New(v8::Isolate::GetCurrent());
18502   InstallContextId(context2, 2);
18503   Handle<Context> context3 = Context::New(v8::Isolate::GetCurrent());
18504   InstallContextId(context3, 3);
18505
18506   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
18507
18508   Local<Object> object1;
18509   Local<Function> func1;
18510   {
18511     Context::Scope scope(context1);
18512     object1 = Object::New();
18513     func1 = tmpl->GetFunction();
18514   }
18515
18516   Local<Object> object2;
18517   Local<Function> func2;
18518   {
18519     Context::Scope scope(context2);
18520     object2 = Object::New();
18521     func2 = tmpl->GetFunction();
18522   }
18523
18524   Local<Object> instance1;
18525   Local<Object> instance2;
18526
18527   {
18528     Context::Scope scope(context3);
18529     instance1 = func1->NewInstance();
18530     instance2 = func2->NewInstance();
18531   }
18532
18533   CHECK(object1->CreationContext() == context1);
18534   CheckContextId(object1, 1);
18535   CHECK(func1->CreationContext() == context1);
18536   CheckContextId(func1, 1);
18537   CHECK(instance1->CreationContext() == context1);
18538   CheckContextId(instance1, 1);
18539   CHECK(object2->CreationContext() == context2);
18540   CheckContextId(object2, 2);
18541   CHECK(func2->CreationContext() == context2);
18542   CheckContextId(func2, 2);
18543   CHECK(instance2->CreationContext() == context2);
18544   CheckContextId(instance2, 2);
18545
18546   {
18547     Context::Scope scope(context1);
18548     CHECK(object1->CreationContext() == context1);
18549     CheckContextId(object1, 1);
18550     CHECK(func1->CreationContext() == context1);
18551     CheckContextId(func1, 1);
18552     CHECK(instance1->CreationContext() == context1);
18553     CheckContextId(instance1, 1);
18554     CHECK(object2->CreationContext() == context2);
18555     CheckContextId(object2, 2);
18556     CHECK(func2->CreationContext() == context2);
18557     CheckContextId(func2, 2);
18558     CHECK(instance2->CreationContext() == context2);
18559     CheckContextId(instance2, 2);
18560   }
18561
18562   {
18563     Context::Scope scope(context2);
18564     CHECK(object1->CreationContext() == context1);
18565     CheckContextId(object1, 1);
18566     CHECK(func1->CreationContext() == context1);
18567     CheckContextId(func1, 1);
18568     CHECK(instance1->CreationContext() == context1);
18569     CheckContextId(instance1, 1);
18570     CHECK(object2->CreationContext() == context2);
18571     CheckContextId(object2, 2);
18572     CHECK(func2->CreationContext() == context2);
18573     CheckContextId(func2, 2);
18574     CHECK(instance2->CreationContext() == context2);
18575     CheckContextId(instance2, 2);
18576   }
18577 }
18578
18579
18580 THREADED_TEST(CreationContextOfJsFunction) {
18581   HandleScope handle_scope(v8::Isolate::GetCurrent());
18582   Handle<Context> context = Context::New(v8::Isolate::GetCurrent());
18583   InstallContextId(context, 1);
18584
18585   Local<Object> function;
18586   {
18587     Context::Scope scope(context);
18588     function = CompileRun("function foo() {}; foo").As<Object>();
18589   }
18590
18591   CHECK(function->CreationContext() == context);
18592   CheckContextId(function, 1);
18593 }
18594
18595
18596 void HasOwnPropertyIndexedPropertyGetter(
18597     uint32_t index,
18598     const v8::PropertyCallbackInfo<v8::Value>& info) {
18599   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
18600 }
18601
18602
18603 void HasOwnPropertyNamedPropertyGetter(
18604     Local<String> property,
18605     const v8::PropertyCallbackInfo<v8::Value>& info) {
18606   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
18607 }
18608
18609
18610 void HasOwnPropertyIndexedPropertyQuery(
18611     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18612   if (index == 42) info.GetReturnValue().Set(1);
18613 }
18614
18615
18616 void HasOwnPropertyNamedPropertyQuery(
18617     Local<String> property,
18618     const v8::PropertyCallbackInfo<v8::Integer>& info) {
18619   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
18620 }
18621
18622
18623 void HasOwnPropertyNamedPropertyQuery2(
18624     Local<String> property,
18625     const v8::PropertyCallbackInfo<v8::Integer>& info) {
18626   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
18627 }
18628
18629
18630 void HasOwnPropertyAccessorGetter(
18631     Local<String> property,
18632     const v8::PropertyCallbackInfo<v8::Value>& info) {
18633   info.GetReturnValue().Set(v8_str("yes"));
18634 }
18635
18636
18637 TEST(HasOwnProperty) {
18638   LocalContext env;
18639   v8::HandleScope scope(env->GetIsolate());
18640   { // Check normal properties and defined getters.
18641     Handle<Value> value = CompileRun(
18642         "function Foo() {"
18643         "    this.foo = 11;"
18644         "    this.__defineGetter__('baz', function() { return 1; });"
18645         "};"
18646         "function Bar() { "
18647         "    this.bar = 13;"
18648         "    this.__defineGetter__('bla', function() { return 2; });"
18649         "};"
18650         "Bar.prototype = new Foo();"
18651         "new Bar();");
18652     CHECK(value->IsObject());
18653     Handle<Object> object = value->ToObject();
18654     CHECK(object->Has(v8_str("foo")));
18655     CHECK(!object->HasOwnProperty(v8_str("foo")));
18656     CHECK(object->HasOwnProperty(v8_str("bar")));
18657     CHECK(object->Has(v8_str("baz")));
18658     CHECK(!object->HasOwnProperty(v8_str("baz")));
18659     CHECK(object->HasOwnProperty(v8_str("bla")));
18660   }
18661   { // Check named getter interceptors.
18662     Handle<ObjectTemplate> templ = ObjectTemplate::New();
18663     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
18664     Handle<Object> instance = templ->NewInstance();
18665     CHECK(!instance->HasOwnProperty(v8_str("42")));
18666     CHECK(instance->HasOwnProperty(v8_str("foo")));
18667     CHECK(!instance->HasOwnProperty(v8_str("bar")));
18668   }
18669   { // Check indexed getter interceptors.
18670     Handle<ObjectTemplate> templ = ObjectTemplate::New();
18671     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
18672     Handle<Object> instance = templ->NewInstance();
18673     CHECK(instance->HasOwnProperty(v8_str("42")));
18674     CHECK(!instance->HasOwnProperty(v8_str("43")));
18675     CHECK(!instance->HasOwnProperty(v8_str("foo")));
18676   }
18677   { // Check named query interceptors.
18678     Handle<ObjectTemplate> templ = ObjectTemplate::New();
18679     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
18680     Handle<Object> instance = templ->NewInstance();
18681     CHECK(instance->HasOwnProperty(v8_str("foo")));
18682     CHECK(!instance->HasOwnProperty(v8_str("bar")));
18683   }
18684   { // Check indexed query interceptors.
18685     Handle<ObjectTemplate> templ = ObjectTemplate::New();
18686     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
18687     Handle<Object> instance = templ->NewInstance();
18688     CHECK(instance->HasOwnProperty(v8_str("42")));
18689     CHECK(!instance->HasOwnProperty(v8_str("41")));
18690   }
18691   { // Check callbacks.
18692     Handle<ObjectTemplate> templ = ObjectTemplate::New();
18693     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
18694     Handle<Object> instance = templ->NewInstance();
18695     CHECK(instance->HasOwnProperty(v8_str("foo")));
18696     CHECK(!instance->HasOwnProperty(v8_str("bar")));
18697   }
18698   { // Check that query wins on disagreement.
18699     Handle<ObjectTemplate> templ = ObjectTemplate::New();
18700     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
18701                                    0,
18702                                    HasOwnPropertyNamedPropertyQuery2);
18703     Handle<Object> instance = templ->NewInstance();
18704     CHECK(!instance->HasOwnProperty(v8_str("foo")));
18705     CHECK(instance->HasOwnProperty(v8_str("bar")));
18706   }
18707 }
18708
18709
18710 TEST(IndexedInterceptorWithStringProto) {
18711   v8::HandleScope scope(v8::Isolate::GetCurrent());
18712   Handle<ObjectTemplate> templ = ObjectTemplate::New();
18713   templ->SetIndexedPropertyHandler(NULL,
18714                                    NULL,
18715                                    HasOwnPropertyIndexedPropertyQuery);
18716   LocalContext context;
18717   context->Global()->Set(v8_str("obj"), templ->NewInstance());
18718   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
18719   // These should be intercepted.
18720   CHECK(CompileRun("42 in obj")->BooleanValue());
18721   CHECK(CompileRun("'42' in obj")->BooleanValue());
18722   // These should fall through to the String prototype.
18723   CHECK(CompileRun("0 in obj")->BooleanValue());
18724   CHECK(CompileRun("'0' in obj")->BooleanValue());
18725   // And these should both fail.
18726   CHECK(!CompileRun("32 in obj")->BooleanValue());
18727   CHECK(!CompileRun("'32' in obj")->BooleanValue());
18728 }
18729
18730
18731 void CheckCodeGenerationAllowed() {
18732   Handle<Value> result = CompileRun("eval('42')");
18733   CHECK_EQ(42, result->Int32Value());
18734   result = CompileRun("(function(e) { return e('42'); })(eval)");
18735   CHECK_EQ(42, result->Int32Value());
18736   result = CompileRun("var f = new Function('return 42'); f()");
18737   CHECK_EQ(42, result->Int32Value());
18738 }
18739
18740
18741 void CheckCodeGenerationDisallowed() {
18742   TryCatch try_catch;
18743
18744   Handle<Value> result = CompileRun("eval('42')");
18745   CHECK(result.IsEmpty());
18746   CHECK(try_catch.HasCaught());
18747   try_catch.Reset();
18748
18749   result = CompileRun("(function(e) { return e('42'); })(eval)");
18750   CHECK(result.IsEmpty());
18751   CHECK(try_catch.HasCaught());
18752   try_catch.Reset();
18753
18754   result = CompileRun("var f = new Function('return 42'); f()");
18755   CHECK(result.IsEmpty());
18756   CHECK(try_catch.HasCaught());
18757 }
18758
18759
18760 bool CodeGenerationAllowed(Local<Context> context) {
18761   ApiTestFuzzer::Fuzz();
18762   return true;
18763 }
18764
18765
18766 bool CodeGenerationDisallowed(Local<Context> context) {
18767   ApiTestFuzzer::Fuzz();
18768   return false;
18769 }
18770
18771
18772 THREADED_TEST(AllowCodeGenFromStrings) {
18773   LocalContext context;
18774   v8::HandleScope scope(context->GetIsolate());
18775
18776   // eval and the Function constructor allowed by default.
18777   CHECK(context->IsCodeGenerationFromStringsAllowed());
18778   CheckCodeGenerationAllowed();
18779
18780   // Disallow eval and the Function constructor.
18781   context->AllowCodeGenerationFromStrings(false);
18782   CHECK(!context->IsCodeGenerationFromStringsAllowed());
18783   CheckCodeGenerationDisallowed();
18784
18785   // Allow again.
18786   context->AllowCodeGenerationFromStrings(true);
18787   CheckCodeGenerationAllowed();
18788
18789   // Disallow but setting a global callback that will allow the calls.
18790   context->AllowCodeGenerationFromStrings(false);
18791   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
18792   CHECK(!context->IsCodeGenerationFromStringsAllowed());
18793   CheckCodeGenerationAllowed();
18794
18795   // Set a callback that disallows the code generation.
18796   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18797   CHECK(!context->IsCodeGenerationFromStringsAllowed());
18798   CheckCodeGenerationDisallowed();
18799 }
18800
18801
18802 TEST(SetErrorMessageForCodeGenFromStrings) {
18803   LocalContext context;
18804   v8::HandleScope scope(context->GetIsolate());
18805   TryCatch try_catch;
18806
18807   Handle<String> message = v8_str("Message") ;
18808   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
18809   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18810   context->AllowCodeGenerationFromStrings(false);
18811   context->SetErrorMessageForCodeGenerationFromStrings(message);
18812   Handle<Value> result = CompileRun("eval('42')");
18813   CHECK(result.IsEmpty());
18814   CHECK(try_catch.HasCaught());
18815   Handle<String> actual_message = try_catch.Message()->Get();
18816   CHECK(expected_message->Equals(actual_message));
18817 }
18818
18819
18820 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
18821 }
18822
18823
18824 THREADED_TEST(CallAPIFunctionOnNonObject) {
18825   LocalContext context;
18826   v8::HandleScope scope(context->GetIsolate());
18827   Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
18828   Handle<Function> function = templ->GetFunction();
18829   context->Global()->Set(v8_str("f"), function);
18830   TryCatch try_catch;
18831   CompileRun("f.call(2)");
18832 }
18833
18834
18835 // Regression test for issue 1470.
18836 THREADED_TEST(ReadOnlyIndexedProperties) {
18837   v8::HandleScope scope(v8::Isolate::GetCurrent());
18838   Local<ObjectTemplate> templ = ObjectTemplate::New();
18839
18840   LocalContext context;
18841   Local<v8::Object> obj = templ->NewInstance();
18842   context->Global()->Set(v8_str("obj"), obj);
18843   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18844   obj->Set(v8_str("1"), v8_str("foobar"));
18845   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
18846   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18847   obj->Set(v8_num(2), v8_str("foobar"));
18848   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
18849
18850   // Test non-smi case.
18851   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18852   obj->Set(v8_str("2000000000"), v8_str("foobar"));
18853   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
18854 }
18855
18856
18857 THREADED_TEST(Regress1516) {
18858   LocalContext context;
18859   v8::HandleScope scope(context->GetIsolate());
18860
18861   { v8::HandleScope temp_scope(context->GetIsolate());
18862     CompileRun("({'a': 0})");
18863   }
18864
18865   int elements;
18866   { i::MapCache* map_cache =
18867         i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
18868     elements = map_cache->NumberOfElements();
18869     CHECK_LE(1, elements);
18870   }
18871
18872   i::Isolate::Current()->heap()->CollectAllGarbage(
18873       i::Heap::kAbortIncrementalMarkingMask);
18874   { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
18875     if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
18876       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
18877       CHECK_GT(elements, map_cache->NumberOfElements());
18878     }
18879   }
18880 }
18881
18882
18883 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
18884                                                 Local<Value> name,
18885                                                 v8::AccessType type,
18886                                                 Local<Value> data) {
18887   // Only block read access to __proto__.
18888   if (type == v8::ACCESS_GET &&
18889       name->IsString() &&
18890       name->ToString()->Length() == 9 &&
18891       name->ToString()->Utf8Length() == 9) {
18892     char buffer[10];
18893     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
18894     return strncmp(buffer, "__proto__", 9) != 0;
18895   }
18896
18897   return true;
18898 }
18899
18900
18901 THREADED_TEST(Regress93759) {
18902   v8::Isolate* isolate = v8::Isolate::GetCurrent();
18903   HandleScope scope(isolate);
18904
18905   // Template for object with security check.
18906   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
18907   // We don't do indexing, so any callback can be used for that.
18908   no_proto_template->SetAccessCheckCallbacks(
18909       BlockProtoNamedSecurityTestCallback,
18910       IndexedSecurityTestCallback);
18911
18912   // Templates for objects with hidden prototypes and possibly security check.
18913   Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
18914   hidden_proto_template->SetHiddenPrototype(true);
18915
18916   Local<FunctionTemplate> protected_hidden_proto_template =
18917       v8::FunctionTemplate::New();
18918   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18919       BlockProtoNamedSecurityTestCallback,
18920       IndexedSecurityTestCallback);
18921   protected_hidden_proto_template->SetHiddenPrototype(true);
18922
18923   // Context for "foreign" objects used in test.
18924   Local<Context> context = v8::Context::New(isolate);
18925   context->Enter();
18926
18927   // Plain object, no security check.
18928   Local<Object> simple_object = Object::New();
18929
18930   // Object with explicit security check.
18931   Local<Object> protected_object =
18932       no_proto_template->NewInstance();
18933
18934   // JSGlobalProxy object, always have security check.
18935   Local<Object> proxy_object =
18936       context->Global();
18937
18938   // Global object, the  prototype of proxy_object. No security checks.
18939   Local<Object> global_object =
18940       proxy_object->GetPrototype()->ToObject();
18941
18942   // Hidden prototype without security check.
18943   Local<Object> hidden_prototype =
18944       hidden_proto_template->GetFunction()->NewInstance();
18945   Local<Object> object_with_hidden =
18946     Object::New();
18947   object_with_hidden->SetPrototype(hidden_prototype);
18948
18949   // Hidden prototype with security check on the hidden prototype.
18950   Local<Object> protected_hidden_prototype =
18951       protected_hidden_proto_template->GetFunction()->NewInstance();
18952   Local<Object> object_with_protected_hidden =
18953     Object::New();
18954   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18955
18956   context->Exit();
18957
18958   // Template for object for second context. Values to test are put on it as
18959   // properties.
18960   Local<ObjectTemplate> global_template = ObjectTemplate::New();
18961   global_template->Set(v8_str("simple"), simple_object);
18962   global_template->Set(v8_str("protected"), protected_object);
18963   global_template->Set(v8_str("global"), global_object);
18964   global_template->Set(v8_str("proxy"), proxy_object);
18965   global_template->Set(v8_str("hidden"), object_with_hidden);
18966   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18967
18968   LocalContext context2(NULL, global_template);
18969
18970   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18971   CHECK(result1->Equals(simple_object->GetPrototype()));
18972
18973   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18974   CHECK(result2->Equals(Undefined()));
18975
18976   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18977   CHECK(result3->Equals(global_object->GetPrototype()));
18978
18979   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18980   CHECK(result4->Equals(Undefined()));
18981
18982   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18983   CHECK(result5->Equals(
18984       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
18985
18986   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18987   CHECK(result6->Equals(Undefined()));
18988 }
18989
18990
18991 THREADED_TEST(Regress125988) {
18992   v8::HandleScope scope(v8::Isolate::GetCurrent());
18993   Handle<FunctionTemplate> intercept = FunctionTemplate::New();
18994   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
18995   LocalContext env;
18996   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
18997   CompileRun("var a = new Object();"
18998              "var b = new Intercept();"
18999              "var c = new Object();"
19000              "c.__proto__ = b;"
19001              "b.__proto__ = a;"
19002              "a.x = 23;"
19003              "for (var i = 0; i < 3; i++) c.x;");
19004   ExpectBoolean("c.hasOwnProperty('x')", false);
19005   ExpectInt32("c.x", 23);
19006   CompileRun("a.y = 42;"
19007              "for (var i = 0; i < 3; i++) c.x;");
19008   ExpectBoolean("c.hasOwnProperty('x')", false);
19009   ExpectInt32("c.x", 23);
19010   ExpectBoolean("c.hasOwnProperty('y')", false);
19011   ExpectInt32("c.y", 42);
19012 }
19013
19014
19015 static void TestReceiver(Local<Value> expected_result,
19016                          Local<Value> expected_receiver,
19017                          const char* code) {
19018   Local<Value> result = CompileRun(code);
19019   CHECK(result->IsObject());
19020   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
19021   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
19022 }
19023
19024
19025 THREADED_TEST(ForeignFunctionReceiver) {
19026   v8::Isolate* isolate = v8::Isolate::GetCurrent();
19027   HandleScope scope(isolate);
19028
19029   // Create two contexts with different "id" properties ('i' and 'o').
19030   // Call a function both from its own context and from a the foreign
19031   // context, and see what "this" is bound to (returning both "this"
19032   // and "this.id" for comparison).
19033
19034   Local<Context> foreign_context = v8::Context::New(isolate);
19035   foreign_context->Enter();
19036   Local<Value> foreign_function =
19037     CompileRun("function func() { return { 0: this.id, "
19038                "                           1: this, "
19039                "                           toString: function() { "
19040                "                               return this[0];"
19041                "                           }"
19042                "                         };"
19043                "}"
19044                "var id = 'i';"
19045                "func;");
19046   CHECK(foreign_function->IsFunction());
19047   foreign_context->Exit();
19048
19049   LocalContext context;
19050
19051   Local<String> password = v8_str("Password");
19052   // Don't get hit by security checks when accessing foreign_context's
19053   // global receiver (aka. global proxy).
19054   context->SetSecurityToken(password);
19055   foreign_context->SetSecurityToken(password);
19056
19057   Local<String> i = v8_str("i");
19058   Local<String> o = v8_str("o");
19059   Local<String> id = v8_str("id");
19060
19061   CompileRun("function ownfunc() { return { 0: this.id, "
19062              "                              1: this, "
19063              "                              toString: function() { "
19064              "                                  return this[0];"
19065              "                              }"
19066              "                             };"
19067              "}"
19068              "var id = 'o';"
19069              "ownfunc");
19070   context->Global()->Set(v8_str("func"), foreign_function);
19071
19072   // Sanity check the contexts.
19073   CHECK(i->Equals(foreign_context->Global()->Get(id)));
19074   CHECK(o->Equals(context->Global()->Get(id)));
19075
19076   // Checking local function's receiver.
19077   // Calling function using its call/apply methods.
19078   TestReceiver(o, context->Global(), "ownfunc.call()");
19079   TestReceiver(o, context->Global(), "ownfunc.apply()");
19080   // Making calls through built-in functions.
19081   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
19082   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
19083   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
19084   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
19085   // Calling with environment record as base.
19086   TestReceiver(o, context->Global(), "ownfunc()");
19087   // Calling with no base.
19088   TestReceiver(o, context->Global(), "(1,ownfunc)()");
19089
19090   // Checking foreign function return value.
19091   // Calling function using its call/apply methods.
19092   TestReceiver(i, foreign_context->Global(), "func.call()");
19093   TestReceiver(i, foreign_context->Global(), "func.apply()");
19094   // Calling function using another context's call/apply methods.
19095   TestReceiver(i, foreign_context->Global(),
19096                "Function.prototype.call.call(func)");
19097   TestReceiver(i, foreign_context->Global(),
19098                "Function.prototype.call.apply(func)");
19099   TestReceiver(i, foreign_context->Global(),
19100                "Function.prototype.apply.call(func)");
19101   TestReceiver(i, foreign_context->Global(),
19102                "Function.prototype.apply.apply(func)");
19103   // Making calls through built-in functions.
19104   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
19105   // ToString(func()) is func()[0], i.e., the returned this.id.
19106   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
19107   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
19108   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
19109
19110   // TODO(1547): Make the following also return "i".
19111   // Calling with environment record as base.
19112   TestReceiver(o, context->Global(), "func()");
19113   // Calling with no base.
19114   TestReceiver(o, context->Global(), "(1,func)()");
19115 }
19116
19117
19118 uint8_t callback_fired = 0;
19119
19120
19121 void CallCompletedCallback1() {
19122   i::OS::Print("Firing callback 1.\n");
19123   callback_fired ^= 1;  // Toggle first bit.
19124 }
19125
19126
19127 void CallCompletedCallback2() {
19128   i::OS::Print("Firing callback 2.\n");
19129   callback_fired ^= 2;  // Toggle second bit.
19130 }
19131
19132
19133 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
19134   int32_t level = args[0]->Int32Value();
19135   if (level < 3) {
19136     level++;
19137     i::OS::Print("Entering recursion level %d.\n", level);
19138     char script[64];
19139     i::Vector<char> script_vector(script, sizeof(script));
19140     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
19141     CompileRun(script_vector.start());
19142     i::OS::Print("Leaving recursion level %d.\n", level);
19143     CHECK_EQ(0, callback_fired);
19144   } else {
19145     i::OS::Print("Recursion ends.\n");
19146     CHECK_EQ(0, callback_fired);
19147   }
19148 }
19149
19150
19151 TEST(CallCompletedCallback) {
19152   LocalContext env;
19153   v8::HandleScope scope(env->GetIsolate());
19154   v8::Handle<v8::FunctionTemplate> recursive_runtime =
19155       v8::FunctionTemplate::New(RecursiveCall);
19156   env->Global()->Set(v8_str("recursion"),
19157                      recursive_runtime->GetFunction());
19158   // Adding the same callback a second time has no effect.
19159   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19160   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19161   v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
19162   i::OS::Print("--- Script (1) ---\n");
19163   Local<Script> script =
19164       v8::Script::Compile(v8::String::New("recursion(0)"));
19165   script->Run();
19166   CHECK_EQ(3, callback_fired);
19167
19168   i::OS::Print("\n--- Script (2) ---\n");
19169   callback_fired = 0;
19170   v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
19171   script->Run();
19172   CHECK_EQ(2, callback_fired);
19173
19174   i::OS::Print("\n--- Function ---\n");
19175   callback_fired = 0;
19176   Local<Function> recursive_function =
19177       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
19178   v8::Handle<Value> args[] = { v8_num(0) };
19179   recursive_function->Call(env->Global(), 1, args);
19180   CHECK_EQ(2, callback_fired);
19181 }
19182
19183
19184 void CallCompletedCallbackNoException() {
19185   v8::HandleScope scope(v8::Isolate::GetCurrent());
19186   CompileRun("1+1;");
19187 }
19188
19189
19190 void CallCompletedCallbackException() {
19191   v8::HandleScope scope(v8::Isolate::GetCurrent());
19192   CompileRun("throw 'second exception';");
19193 }
19194
19195
19196 TEST(CallCompletedCallbackOneException) {
19197   LocalContext env;
19198   v8::HandleScope scope(env->GetIsolate());
19199   v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
19200   CompileRun("throw 'exception';");
19201 }
19202
19203
19204 TEST(CallCompletedCallbackTwoExceptions) {
19205   LocalContext env;
19206   v8::HandleScope scope(env->GetIsolate());
19207   v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
19208   CompileRun("throw 'first exception';");
19209 }
19210
19211
19212 static int probes_counter = 0;
19213 static int misses_counter = 0;
19214 static int updates_counter = 0;
19215
19216
19217 static int* LookupCounter(const char* name) {
19218   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19219     return &probes_counter;
19220   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19221     return &misses_counter;
19222   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19223     return &updates_counter;
19224   }
19225   return NULL;
19226 }
19227
19228
19229 static const char* kMegamorphicTestProgram =
19230     "function ClassA() { };"
19231     "function ClassB() { };"
19232     "ClassA.prototype.foo = function() { };"
19233     "ClassB.prototype.foo = function() { };"
19234     "function fooify(obj) { obj.foo(); };"
19235     "var a = new ClassA();"
19236     "var b = new ClassB();"
19237     "for (var i = 0; i < 10000; i++) {"
19238     "  fooify(a);"
19239     "  fooify(b);"
19240     "}";
19241
19242
19243 static void StubCacheHelper(bool primary) {
19244   V8::SetCounterFunction(LookupCounter);
19245   USE(kMegamorphicTestProgram);
19246 #ifdef DEBUG
19247   i::FLAG_native_code_counters = true;
19248   if (primary) {
19249     i::FLAG_test_primary_stub_cache = true;
19250   } else {
19251     i::FLAG_test_secondary_stub_cache = true;
19252   }
19253   i::FLAG_crankshaft = false;
19254   LocalContext env;
19255   v8::HandleScope scope(env->GetIsolate());
19256   int initial_probes = probes_counter;
19257   int initial_misses = misses_counter;
19258   int initial_updates = updates_counter;
19259   CompileRun(kMegamorphicTestProgram);
19260   int probes = probes_counter - initial_probes;
19261   int misses = misses_counter - initial_misses;
19262   int updates = updates_counter - initial_updates;
19263   CHECK_LT(updates, 10);
19264   CHECK_LT(misses, 10);
19265   CHECK_GE(probes, 10000);
19266 #endif
19267 }
19268
19269
19270 TEST(SecondaryStubCache) {
19271   StubCacheHelper(true);
19272 }
19273
19274
19275 TEST(PrimaryStubCache) {
19276   StubCacheHelper(false);
19277 }
19278
19279
19280 TEST(StaticGetters) {
19281   LocalContext context;
19282   i::Factory* factory = i::Isolate::Current()->factory();
19283   v8::Isolate* isolate = v8::Isolate::GetCurrent();
19284   v8::HandleScope scope(isolate);
19285   i::Handle<i::Object> undefined_value = factory->undefined_value();
19286   CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
19287   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19288   i::Handle<i::Object> null_value = factory->null_value();
19289   CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
19290   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19291   i::Handle<i::Object> true_value = factory->true_value();
19292   CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
19293   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19294   i::Handle<i::Object> false_value = factory->false_value();
19295   CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
19296   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19297 }
19298
19299
19300 TEST(IsolateEmbedderData) {
19301   v8::Isolate* isolate = v8::Isolate::GetCurrent();
19302   CHECK_EQ(NULL, isolate->GetData());
19303   CHECK_EQ(NULL, ISOLATE->GetData());
19304   static void* data1 = reinterpret_cast<void*>(0xacce55ed);
19305   isolate->SetData(data1);
19306   CHECK_EQ(data1, isolate->GetData());
19307   CHECK_EQ(data1, ISOLATE->GetData());
19308   static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
19309   ISOLATE->SetData(data2);
19310   CHECK_EQ(data2, isolate->GetData());
19311   CHECK_EQ(data2, ISOLATE->GetData());
19312   ISOLATE->TearDown();
19313   CHECK_EQ(data2, isolate->GetData());
19314   CHECK_EQ(data2, ISOLATE->GetData());
19315 }
19316
19317
19318 TEST(StringEmpty) {
19319   LocalContext context;
19320   i::Factory* factory = i::Isolate::Current()->factory();
19321   v8::Isolate* isolate = v8::Isolate::GetCurrent();
19322   v8::HandleScope scope(isolate);
19323   i::Handle<i::Object> empty_string = factory->empty_string();
19324   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
19325   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19326 }
19327
19328
19329 static int instance_checked_getter_count = 0;
19330 static void InstanceCheckedGetter(
19331     Local<String> name,
19332     const v8::PropertyCallbackInfo<v8::Value>& info) {
19333   CHECK_EQ(name, v8_str("foo"));
19334   instance_checked_getter_count++;
19335   info.GetReturnValue().Set(v8_num(11));
19336 }
19337
19338
19339 static int instance_checked_setter_count = 0;
19340 static void InstanceCheckedSetter(Local<String> name,
19341                       Local<Value> value,
19342                       const v8::PropertyCallbackInfo<void>& info) {
19343   CHECK_EQ(name, v8_str("foo"));
19344   CHECK_EQ(value, v8_num(23));
19345   instance_checked_setter_count++;
19346 }
19347
19348
19349 static void CheckInstanceCheckedResult(int getters,
19350                                        int setters,
19351                                        bool expects_callbacks,
19352                                        TryCatch* try_catch) {
19353   if (expects_callbacks) {
19354     CHECK(!try_catch->HasCaught());
19355     CHECK_EQ(getters, instance_checked_getter_count);
19356     CHECK_EQ(setters, instance_checked_setter_count);
19357   } else {
19358     CHECK(try_catch->HasCaught());
19359     CHECK_EQ(0, instance_checked_getter_count);
19360     CHECK_EQ(0, instance_checked_setter_count);
19361   }
19362   try_catch->Reset();
19363 }
19364
19365
19366 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19367   instance_checked_getter_count = 0;
19368   instance_checked_setter_count = 0;
19369   TryCatch try_catch;
19370
19371   // Test path through generic runtime code.
19372   CompileRun("obj.foo");
19373   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19374   CompileRun("obj.foo = 23");
19375   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19376
19377   // Test path through generated LoadIC and StoredIC.
19378   CompileRun("function test_get(o) { o.foo; }"
19379              "test_get(obj);");
19380   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19381   CompileRun("test_get(obj);");
19382   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19383   CompileRun("test_get(obj);");
19384   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19385   CompileRun("function test_set(o) { o.foo = 23; }"
19386              "test_set(obj);");
19387   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19388   CompileRun("test_set(obj);");
19389   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19390   CompileRun("test_set(obj);");
19391   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19392
19393   // Test path through optimized code.
19394   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19395              "test_get(obj);");
19396   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19397   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19398              "test_set(obj);");
19399   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19400
19401   // Cleanup so that closures start out fresh in next check.
19402   CompileRun("%DeoptimizeFunction(test_get);"
19403              "%ClearFunctionTypeFeedback(test_get);"
19404              "%DeoptimizeFunction(test_set);"
19405              "%ClearFunctionTypeFeedback(test_set);");
19406 }
19407
19408
19409 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19410   v8::internal::FLAG_allow_natives_syntax = true;
19411   LocalContext context;
19412   v8::HandleScope scope(context->GetIsolate());
19413
19414   Local<FunctionTemplate> templ = FunctionTemplate::New();
19415   Local<ObjectTemplate> inst = templ->InstanceTemplate();
19416   inst->SetAccessor(v8_str("foo"),
19417                     InstanceCheckedGetter, InstanceCheckedSetter,
19418                     Handle<Value>(),
19419                     v8::DEFAULT,
19420                     v8::None,
19421                     v8::AccessorSignature::New(templ));
19422   context->Global()->Set(v8_str("f"), templ->GetFunction());
19423
19424   printf("Testing positive ...\n");
19425   CompileRun("var obj = new f();");
19426   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19427   CheckInstanceCheckedAccessors(true);
19428
19429   printf("Testing negative ...\n");
19430   CompileRun("var obj = {};"
19431              "obj.__proto__ = new f();");
19432   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19433   CheckInstanceCheckedAccessors(false);
19434 }
19435
19436
19437 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19438   v8::internal::FLAG_allow_natives_syntax = true;
19439   LocalContext context;
19440   v8::HandleScope scope(context->GetIsolate());
19441
19442   Local<FunctionTemplate> templ = FunctionTemplate::New();
19443   Local<ObjectTemplate> inst = templ->InstanceTemplate();
19444   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19445   inst->SetAccessor(v8_str("foo"),
19446                     InstanceCheckedGetter, InstanceCheckedSetter,
19447                     Handle<Value>(),
19448                     v8::DEFAULT,
19449                     v8::None,
19450                     v8::AccessorSignature::New(templ));
19451   context->Global()->Set(v8_str("f"), templ->GetFunction());
19452
19453   printf("Testing positive ...\n");
19454   CompileRun("var obj = new f();");
19455   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19456   CheckInstanceCheckedAccessors(true);
19457
19458   printf("Testing negative ...\n");
19459   CompileRun("var obj = {};"
19460              "obj.__proto__ = new f();");
19461   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19462   CheckInstanceCheckedAccessors(false);
19463 }
19464
19465
19466 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
19467   v8::internal::FLAG_allow_natives_syntax = true;
19468   LocalContext context;
19469   v8::HandleScope scope(context->GetIsolate());
19470
19471   Local<FunctionTemplate> templ = FunctionTemplate::New();
19472   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
19473   proto->SetAccessor(v8_str("foo"),
19474                      InstanceCheckedGetter, InstanceCheckedSetter,
19475                      Handle<Value>(),
19476                      v8::DEFAULT,
19477                      v8::None,
19478                      v8::AccessorSignature::New(templ));
19479   context->Global()->Set(v8_str("f"), templ->GetFunction());
19480
19481   printf("Testing positive ...\n");
19482   CompileRun("var obj = new f();");
19483   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19484   CheckInstanceCheckedAccessors(true);
19485
19486   printf("Testing negative ...\n");
19487   CompileRun("var obj = {};"
19488              "obj.__proto__ = new f();");
19489   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19490   CheckInstanceCheckedAccessors(false);
19491
19492   printf("Testing positive with modified prototype chain ...\n");
19493   CompileRun("var obj = new f();"
19494              "var pro = {};"
19495              "pro.__proto__ = obj.__proto__;"
19496              "obj.__proto__ = pro;");
19497   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19498   CheckInstanceCheckedAccessors(true);
19499 }
19500
19501
19502 TEST(TryFinallyMessage) {
19503   LocalContext context;
19504   v8::HandleScope scope(context->GetIsolate());
19505   {
19506     // Test that the original error message is not lost if there is a
19507     // recursive call into Javascript is done in the finally block, e.g. to
19508     // initialize an IC. (crbug.com/129171)
19509     TryCatch try_catch;
19510     const char* trigger_ic =
19511         "try {                      \n"
19512         "  throw new Error('test'); \n"
19513         "} finally {                \n"
19514         "  var x = 0;               \n"
19515         "  x++;                     \n"  // Trigger an IC initialization here.
19516         "}                          \n";
19517     CompileRun(trigger_ic);
19518     CHECK(try_catch.HasCaught());
19519     Local<Message> message = try_catch.Message();
19520     CHECK(!message.IsEmpty());
19521     CHECK_EQ(2, message->GetLineNumber());
19522   }
19523
19524   {
19525     // Test that the original exception message is indeed overwritten if
19526     // a new error is thrown in the finally block.
19527     TryCatch try_catch;
19528     const char* throw_again =
19529         "try {                       \n"
19530         "  throw new Error('test');  \n"
19531         "} finally {                 \n"
19532         "  var x = 0;                \n"
19533         "  x++;                      \n"
19534         "  throw new Error('again'); \n"  // This is the new uncaught error.
19535         "}                           \n";
19536     CompileRun(throw_again);
19537     CHECK(try_catch.HasCaught());
19538     Local<Message> message = try_catch.Message();
19539     CHECK(!message.IsEmpty());
19540     CHECK_EQ(6, message->GetLineNumber());
19541   }
19542 }
19543
19544
19545 static void Helper137002(bool do_store,
19546                          bool polymorphic,
19547                          bool remove_accessor,
19548                          bool interceptor) {
19549   LocalContext context;
19550   Local<ObjectTemplate> templ = ObjectTemplate::New();
19551   if (interceptor) {
19552     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
19553   } else {
19554     templ->SetAccessor(v8_str("foo"),
19555                        GetterWhichReturns42,
19556                        SetterWhichSetsYOnThisTo23);
19557   }
19558   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19559
19560   // Turn monomorphic on slow object with native accessor, then turn
19561   // polymorphic, finally optimize to create negative lookup and fail.
19562   CompileRun(do_store ?
19563              "function f(x) { x.foo = void 0; }" :
19564              "function f(x) { return x.foo; }");
19565   CompileRun("obj.y = void 0;");
19566   if (!interceptor) {
19567     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
19568   }
19569   CompileRun("obj.__proto__ = null;"
19570              "f(obj); f(obj); f(obj);");
19571   if (polymorphic) {
19572     CompileRun("f({});");
19573   }
19574   CompileRun("obj.y = void 0;"
19575              "%OptimizeFunctionOnNextCall(f);");
19576   if (remove_accessor) {
19577     CompileRun("delete obj.foo;");
19578   }
19579   CompileRun("var result = f(obj);");
19580   if (do_store) {
19581     CompileRun("result = obj.y;");
19582   }
19583   if (remove_accessor && !interceptor) {
19584     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
19585   } else {
19586     CHECK_EQ(do_store ? 23 : 42,
19587              context->Global()->Get(v8_str("result"))->Int32Value());
19588   }
19589 }
19590
19591
19592 THREADED_TEST(Regress137002a) {
19593   i::FLAG_allow_natives_syntax = true;
19594   i::FLAG_compilation_cache = false;
19595   v8::HandleScope scope(v8::Isolate::GetCurrent());
19596   for (int i = 0; i < 16; i++) {
19597     Helper137002(i & 8, i & 4, i & 2, i & 1);
19598   }
19599 }
19600
19601
19602 THREADED_TEST(Regress137002b) {
19603   i::FLAG_allow_natives_syntax = true;
19604   LocalContext context;
19605   v8::HandleScope scope(context->GetIsolate());
19606   Local<ObjectTemplate> templ = ObjectTemplate::New();
19607   templ->SetAccessor(v8_str("foo"),
19608                      GetterWhichReturns42,
19609                      SetterWhichSetsYOnThisTo23);
19610   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19611
19612   // Turn monomorphic on slow object with native accessor, then just
19613   // delete the property and fail.
19614   CompileRun("function load(x) { return x.foo; }"
19615              "function store(x) { x.foo = void 0; }"
19616              "function keyed_load(x, key) { return x[key]; }"
19617              // Second version of function has a different source (add void 0)
19618              // so that it does not share code with the first version.  This
19619              // ensures that the ICs are monomorphic.
19620              "function load2(x) { void 0; return x.foo; }"
19621              "function store2(x) { void 0; x.foo = void 0; }"
19622              "function keyed_load2(x, key) { void 0; return x[key]; }"
19623
19624              "obj.y = void 0;"
19625              "obj.__proto__ = null;"
19626              "var subobj = {};"
19627              "subobj.y = void 0;"
19628              "subobj.__proto__ = obj;"
19629              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19630
19631              // Make the ICs monomorphic.
19632              "load(obj); load(obj);"
19633              "load2(subobj); load2(subobj);"
19634              "store(obj); store(obj);"
19635              "store2(subobj); store2(subobj);"
19636              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19637              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19638
19639              // Actually test the shiny new ICs and better not crash. This
19640              // serves as a regression test for issue 142088 as well.
19641              "load(obj);"
19642              "load2(subobj);"
19643              "store(obj);"
19644              "store2(subobj);"
19645              "keyed_load(obj, 'foo');"
19646              "keyed_load2(subobj, 'foo');"
19647
19648              // Delete the accessor.  It better not be called any more now.
19649              "delete obj.foo;"
19650              "obj.y = void 0;"
19651              "subobj.y = void 0;"
19652
19653              "var load_result = load(obj);"
19654              "var load_result2 = load2(subobj);"
19655              "var keyed_load_result = keyed_load(obj, 'foo');"
19656              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19657              "store(obj);"
19658              "store2(subobj);"
19659              "var y_from_obj = obj.y;"
19660              "var y_from_subobj = subobj.y;");
19661   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19662   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19663   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19664   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19665   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19666   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19667 }
19668
19669
19670 THREADED_TEST(Regress142088) {
19671   i::FLAG_allow_natives_syntax = true;
19672   LocalContext context;
19673   v8::HandleScope scope(context->GetIsolate());
19674   Local<ObjectTemplate> templ = ObjectTemplate::New();
19675   templ->SetAccessor(v8_str("foo"),
19676                      GetterWhichReturns42,
19677                      SetterWhichSetsYOnThisTo23);
19678   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19679
19680   CompileRun("function load(x) { return x.foo; }"
19681              "var o = Object.create(obj);"
19682              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19683              "load(o); load(o); load(o); load(o);");
19684 }
19685
19686
19687 THREADED_TEST(Regress137496) {
19688   i::FLAG_expose_gc = true;
19689   LocalContext context;
19690   v8::HandleScope scope(context->GetIsolate());
19691
19692   // Compile a try-finally clause where the finally block causes a GC
19693   // while there still is a message pending for external reporting.
19694   TryCatch try_catch;
19695   try_catch.SetVerbose(true);
19696   CompileRun("try { throw new Error(); } finally { gc(); }");
19697   CHECK(try_catch.HasCaught());
19698 }
19699
19700
19701 THREADED_TEST(Regress149912) {
19702   LocalContext context;
19703   v8::HandleScope scope(context->GetIsolate());
19704   Handle<FunctionTemplate> templ = FunctionTemplate::New();
19705   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19706   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
19707   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
19708 }
19709
19710
19711 THREADED_TEST(Regress157124) {
19712   LocalContext context;
19713   v8::HandleScope scope(context->GetIsolate());
19714   Local<ObjectTemplate> templ = ObjectTemplate::New();
19715   Local<Object> obj = templ->NewInstance();
19716   obj->GetIdentityHash();
19717   obj->DeleteHiddenValue(v8_str("Bug"));
19718 }
19719
19720
19721 THREADED_TEST(Regress2535) {
19722   i::FLAG_harmony_collections = true;
19723   LocalContext context;
19724   v8::HandleScope scope(context->GetIsolate());
19725   Local<Value> set_value = CompileRun("new Set();");
19726   Local<Object> set_object(Local<Object>::Cast(set_value));
19727   CHECK_EQ(0, set_object->InternalFieldCount());
19728   Local<Value> map_value = CompileRun("new Map();");
19729   Local<Object> map_object(Local<Object>::Cast(map_value));
19730   CHECK_EQ(0, map_object->InternalFieldCount());
19731 }
19732
19733
19734 THREADED_TEST(Regress2746) {
19735   LocalContext context;
19736   v8::HandleScope scope(context->GetIsolate());
19737   Local<Object> obj = Object::New();
19738   Local<String> key = String::New("key");
19739   obj->SetHiddenValue(key, v8::Undefined());
19740   Local<Value> value = obj->GetHiddenValue(key);
19741   CHECK(!value.IsEmpty());
19742   CHECK(value->IsUndefined());
19743 }
19744
19745
19746 THREADED_TEST(Regress260106) {
19747   LocalContext context;
19748   v8::HandleScope scope(context->GetIsolate());
19749   Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler);
19750   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19751   Local<Function> function = templ->GetFunction();
19752   CHECK(!function.IsEmpty());
19753   CHECK(function->IsFunction());
19754 }
19755
19756
19757 #ifndef WIN32
19758 class ThreadInterruptTest {
19759  public:
19760   ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
19761   ~ThreadInterruptTest() { delete sem_; }
19762
19763   void RunTest() {
19764     sem_ = i::OS::CreateSemaphore(0);
19765
19766     InterruptThread i_thread(this);
19767     i_thread.Start();
19768
19769     sem_->Wait();
19770     CHECK_EQ(kExpectedValue, sem_value_);
19771   }
19772
19773  private:
19774   static const int kExpectedValue = 1;
19775
19776   class InterruptThread : public i::Thread {
19777    public:
19778     explicit InterruptThread(ThreadInterruptTest* test)
19779         : Thread("InterruptThread"), test_(test) {}
19780
19781     virtual void Run() {
19782       struct sigaction action;
19783
19784       // Ensure that we'll enter waiting condition
19785       i::OS::Sleep(100);
19786
19787       // Setup signal handler
19788       memset(&action, 0, sizeof(action));
19789       action.sa_handler = SignalHandler;
19790       sigaction(SIGCHLD, &action, NULL);
19791
19792       // Send signal
19793       kill(getpid(), SIGCHLD);
19794
19795       // Ensure that if wait has returned because of error
19796       i::OS::Sleep(100);
19797
19798       // Set value and signal semaphore
19799       test_->sem_value_ = 1;
19800       test_->sem_->Signal();
19801     }
19802
19803     static void SignalHandler(int signal) {
19804     }
19805
19806    private:
19807      ThreadInterruptTest* test_;
19808   };
19809
19810   i::Semaphore* sem_;
19811   volatile int sem_value_;
19812 };
19813
19814
19815 THREADED_TEST(SemaphoreInterruption) {
19816   ThreadInterruptTest().RunTest();
19817 }
19818
19819
19820 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
19821                                      Local<Value> name,
19822                                      v8::AccessType type,
19823                                      Local<Value> data) {
19824   i::PrintF("Named access blocked.\n");
19825   return false;
19826 }
19827
19828
19829 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
19830                                      uint32_t key,
19831                                      v8::AccessType type,
19832                                      Local<Value> data) {
19833   i::PrintF("Indexed access blocked.\n");
19834   return false;
19835 }
19836
19837
19838 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19839   CHECK(false);
19840 }
19841
19842
19843 TEST(JSONStringifyAccessCheck) {
19844   v8::V8::Initialize();
19845   v8::HandleScope scope(v8::Isolate::GetCurrent());
19846
19847   // Create an ObjectTemplate for global objects and install access
19848   // check callbacks that will block access.
19849   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
19850   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
19851                                            IndexAccessAlwaysBlocked);
19852
19853   // Create a context and set an x property on it's global object.
19854   LocalContext context0(NULL, global_template);
19855   v8::Handle<v8::Object> global0 = context0->Global();
19856   global0->Set(v8_str("x"), v8_num(42));
19857   ExpectString("JSON.stringify(this)", "{\"x\":42}");
19858
19859   for (int i = 0; i < 2; i++) {
19860     if (i == 1) {
19861       // Install a toJSON function on the second run.
19862       v8::Handle<v8::FunctionTemplate> toJSON =
19863           v8::FunctionTemplate::New(UnreachableCallback);
19864
19865       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19866     }
19867     // Create a context with a different security token so that the
19868     // failed access check callback will be called on each access.
19869     LocalContext context1(NULL, global_template);
19870     context1->Global()->Set(v8_str("other"), global0);
19871
19872     ExpectString("JSON.stringify(other)", "{}");
19873     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
19874                  "{\"a\":{},\"b\":[\"c\"]}");
19875     ExpectString("JSON.stringify([other, 'b', 'c'])",
19876                  "[{},\"b\",\"c\"]");
19877
19878     v8::Handle<v8::Array> array = v8::Array::New(2);
19879     array->Set(0, v8_str("a"));
19880     array->Set(1, v8_str("b"));
19881     context1->Global()->Set(v8_str("array"), array);
19882     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
19883     array->TurnOnAccessCheck();
19884     ExpectString("JSON.stringify(array)", "[]");
19885     ExpectString("JSON.stringify([array])", "[[]]");
19886     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
19887   }
19888 }
19889
19890
19891 bool access_check_fail_thrown = false;
19892 bool catch_callback_called = false;
19893
19894
19895 // Failed access check callback that performs a GC on each invocation.
19896 void FailedAccessCheckThrows(Local<v8::Object> target,
19897                              v8::AccessType type,
19898                              Local<v8::Value> data) {
19899   access_check_fail_thrown = true;
19900   i::PrintF("Access check failed. Error thrown.\n");
19901   v8::ThrowException(v8::Exception::Error(v8_str("cross context")));
19902 }
19903
19904
19905 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19906   for (int i = 0; i < args.Length(); i++) {
19907     i::PrintF("%s\n", *String::Utf8Value(args[i]));
19908   }
19909   catch_callback_called = true;
19910 }
19911
19912
19913 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19914   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
19915 }
19916
19917
19918 void CheckCorrectThrow(const char* script) {
19919   // Test that the script, when wrapped into a try-catch, triggers the catch
19920   // clause due to failed access check throwing an exception.
19921   // The subsequent try-catch should run without any exception.
19922   access_check_fail_thrown = false;
19923   catch_callback_called = false;
19924   i::ScopedVector<char> source(1024);
19925   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19926   CompileRun(source.start());
19927   CHECK(access_check_fail_thrown);
19928   CHECK(catch_callback_called);
19929
19930   access_check_fail_thrown = false;
19931   catch_callback_called = false;
19932   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19933   CHECK(!access_check_fail_thrown);
19934   CHECK(!catch_callback_called);
19935 }
19936
19937
19938 TEST(AccessCheckThrows) {
19939   i::FLAG_allow_natives_syntax = true;
19940   v8::V8::Initialize();
19941   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19942   v8::HandleScope scope(v8::Isolate::GetCurrent());
19943
19944   // Create an ObjectTemplate for global objects and install access
19945   // check callbacks that will block access.
19946   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
19947   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
19948                                            IndexAccessAlwaysBlocked);
19949
19950   // Create a context and set an x property on it's global object.
19951   LocalContext context0(NULL, global_template);
19952   context0->Global()->Set(v8_str("x"), v8_num(42));
19953   v8::Handle<v8::Object> global0 = context0->Global();
19954
19955   // Create a context with a different security token so that the
19956   // failed access check callback will be called on each access.
19957   LocalContext context1(NULL, global_template);
19958   context1->Global()->Set(v8_str("other"), global0);
19959
19960   v8::Handle<v8::FunctionTemplate> catcher_fun =
19961       v8::FunctionTemplate::New(CatcherCallback);
19962   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19963
19964   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19965       v8::FunctionTemplate::New(HasOwnPropertyCallback);
19966   context1->Global()->Set(v8_str("has_own_property"),
19967                           has_own_property_fun->GetFunction());
19968
19969   { v8::TryCatch try_catch;
19970     access_check_fail_thrown = false;
19971     CompileRun("other.x;");
19972     CHECK(access_check_fail_thrown);
19973     CHECK(try_catch.HasCaught());
19974   }
19975
19976   CheckCorrectThrow("other.x");
19977   CheckCorrectThrow("other[1]");
19978   CheckCorrectThrow("JSON.stringify(other)");
19979   CheckCorrectThrow("has_own_property(other, 'x')");
19980   CheckCorrectThrow("%GetProperty(other, 'x')");
19981   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
19982   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
19983   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19984   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19985   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
19986   CheckCorrectThrow("%HasProperty(other, 'x')");
19987   CheckCorrectThrow("%HasElement(other, 1)");
19988   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19989   CheckCorrectThrow("%GetPropertyNames(other)");
19990   CheckCorrectThrow("%GetLocalPropertyNames(other, true)");
19991   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
19992                         "other, 'x', null, null, 1)");
19993 }
19994
19995 #endif  // WIN32