b394e950dd45421f4851e14d8dee926032db1df3
[profile/ivi/qtjsbackend.git] / src / 3rdparty / v8 / test / cctest / test-api.cc
1 // Copyright 2011 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 #include "v8.h"
31
32 #include "api.h"
33 #include "isolate.h"
34 #include "compilation-cache.h"
35 #include "execution.h"
36 #include "snapshot.h"
37 #include "platform.h"
38 #include "utils.h"
39 #include "cctest.h"
40 #include "parser.h"
41 #include "unicode-inl.h"
42
43 static const bool kLogThreading = false;
44
45 static bool IsNaN(double x) {
46 #ifdef WIN32
47   return _isnan(x);
48 #else
49   return isnan(x);
50 #endif
51 }
52
53 using ::v8::AccessorInfo;
54 using ::v8::Arguments;
55 using ::v8::Context;
56 using ::v8::Extension;
57 using ::v8::Function;
58 using ::v8::FunctionTemplate;
59 using ::v8::Handle;
60 using ::v8::HandleScope;
61 using ::v8::Local;
62 using ::v8::Message;
63 using ::v8::MessageCallback;
64 using ::v8::Object;
65 using ::v8::ObjectTemplate;
66 using ::v8::Persistent;
67 using ::v8::Script;
68 using ::v8::StackTrace;
69 using ::v8::String;
70 using ::v8::TryCatch;
71 using ::v8::Undefined;
72 using ::v8::V8;
73 using ::v8::Value;
74
75
76 static void ExpectString(const char* code, const char* expected) {
77   Local<Value> result = CompileRun(code);
78   CHECK(result->IsString());
79   String::AsciiValue ascii(result);
80   CHECK_EQ(expected, *ascii);
81 }
82
83 static void ExpectInt32(const char* code, int expected) {
84   Local<Value> result = CompileRun(code);
85   CHECK(result->IsInt32());
86   CHECK_EQ(expected, result->Int32Value());
87 }
88
89 static void ExpectBoolean(const char* code, bool expected) {
90   Local<Value> result = CompileRun(code);
91   CHECK(result->IsBoolean());
92   CHECK_EQ(expected, result->BooleanValue());
93 }
94
95
96 static void ExpectTrue(const char* code) {
97   ExpectBoolean(code, true);
98 }
99
100
101 static void ExpectFalse(const char* code) {
102   ExpectBoolean(code, false);
103 }
104
105
106 static void ExpectObject(const char* code, Local<Value> expected) {
107   Local<Value> result = CompileRun(code);
108   CHECK(result->Equals(expected));
109 }
110
111
112 static void ExpectUndefined(const char* code) {
113   Local<Value> result = CompileRun(code);
114   CHECK(result->IsUndefined());
115 }
116
117
118 static int signature_callback_count;
119 static v8::Handle<Value> IncrementingSignatureCallback(
120     const v8::Arguments& args) {
121   ApiTestFuzzer::Fuzz();
122   signature_callback_count++;
123   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
124   for (int i = 0; i < args.Length(); i++)
125     result->Set(v8::Integer::New(i), args[i]);
126   return result;
127 }
128
129
130 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
131   ApiTestFuzzer::Fuzz();
132   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
133   for (int i = 0; i < args.Length(); i++) {
134     result->Set(v8::Integer::New(i), args[i]);
135   }
136   return result;
137 }
138
139
140 THREADED_TEST(Handles) {
141   v8::HandleScope scope;
142   Local<Context> local_env;
143   {
144     LocalContext env;
145     local_env = env.local();
146   }
147
148   // Local context should still be live.
149   CHECK(!local_env.IsEmpty());
150   local_env->Enter();
151
152   v8::Handle<v8::Primitive> undef = v8::Undefined();
153   CHECK(!undef.IsEmpty());
154   CHECK(undef->IsUndefined());
155
156   const char* c_source = "1 + 2 + 3";
157   Local<String> source = String::New(c_source);
158   Local<Script> script = Script::Compile(source);
159   CHECK_EQ(6, script->Run()->Int32Value());
160
161   local_env->Exit();
162 }
163
164
165 THREADED_TEST(ReceiverSignature) {
166   v8::HandleScope scope;
167   LocalContext env;
168   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
169   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
170   fun->PrototypeTemplate()->Set(
171       v8_str("m"),
172       v8::FunctionTemplate::New(IncrementingSignatureCallback,
173                                 v8::Handle<Value>(),
174                                 sig));
175   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
176   signature_callback_count = 0;
177   CompileRun(
178       "var o = new Fun();"
179       "o.m();");
180   CHECK_EQ(1, signature_callback_count);
181   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
182   sub_fun->Inherit(fun);
183   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
184   CompileRun(
185       "var o = new SubFun();"
186       "o.m();");
187   CHECK_EQ(2, signature_callback_count);
188
189   v8::TryCatch try_catch;
190   CompileRun(
191       "var o = { };"
192       "o.m = Fun.prototype.m;"
193       "o.m();");
194   CHECK_EQ(2, signature_callback_count);
195   CHECK(try_catch.HasCaught());
196   try_catch.Reset();
197   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
198   sub_fun->Inherit(fun);
199   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
200   CompileRun(
201       "var o = new UnrelFun();"
202       "o.m = Fun.prototype.m;"
203       "o.m();");
204   CHECK_EQ(2, signature_callback_count);
205   CHECK(try_catch.HasCaught());
206 }
207
208
209 THREADED_TEST(ArgumentSignature) {
210   v8::HandleScope scope;
211   LocalContext env;
212   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
213   cons->SetClassName(v8_str("Cons"));
214   v8::Handle<v8::Signature> sig =
215       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
216   v8::Handle<v8::FunctionTemplate> fun =
217       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
218   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
219   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
220
221   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
222   CHECK(value1->IsTrue());
223
224   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
225   CHECK(value2->IsTrue());
226
227   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
228   CHECK(value3->IsTrue());
229
230   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
231   cons1->SetClassName(v8_str("Cons1"));
232   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
233   cons2->SetClassName(v8_str("Cons2"));
234   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
235   cons3->SetClassName(v8_str("Cons3"));
236
237   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
238   v8::Handle<v8::Signature> wsig =
239       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
240   v8::Handle<v8::FunctionTemplate> fun2 =
241       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
242
243   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
244   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
245   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
246   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
247   v8::Handle<Value> value4 = CompileRun(
248       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
249       "'[object Cons1],[object Cons2],[object Cons3]'");
250   CHECK(value4->IsTrue());
251
252   v8::Handle<Value> value5 = CompileRun(
253       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
254   CHECK(value5->IsTrue());
255
256   v8::Handle<Value> value6 = CompileRun(
257       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
258   CHECK(value6->IsTrue());
259
260   v8::Handle<Value> value7 = CompileRun(
261       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
262       "'[object Cons1],[object Cons2],[object Cons3],d';");
263   CHECK(value7->IsTrue());
264
265   v8::Handle<Value> value8 = CompileRun(
266       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
267   CHECK(value8->IsTrue());
268 }
269
270
271 THREADED_TEST(HulIgennem) {
272   v8::HandleScope scope;
273   LocalContext env;
274   v8::Handle<v8::Primitive> undef = v8::Undefined();
275   Local<String> undef_str = undef->ToString();
276   char* value = i::NewArray<char>(undef_str->Length() + 1);
277   undef_str->WriteAscii(value);
278   CHECK_EQ(0, strcmp(value, "undefined"));
279   i::DeleteArray(value);
280 }
281
282
283 THREADED_TEST(Access) {
284   v8::HandleScope scope;
285   LocalContext env;
286   Local<v8::Object> obj = v8::Object::New();
287   Local<Value> foo_before = obj->Get(v8_str("foo"));
288   CHECK(foo_before->IsUndefined());
289   Local<String> bar_str = v8_str("bar");
290   obj->Set(v8_str("foo"), bar_str);
291   Local<Value> foo_after = obj->Get(v8_str("foo"));
292   CHECK(!foo_after->IsUndefined());
293   CHECK(foo_after->IsString());
294   CHECK_EQ(bar_str, foo_after);
295 }
296
297
298 THREADED_TEST(AccessElement) {
299   v8::HandleScope scope;
300   LocalContext env;
301   Local<v8::Object> obj = v8::Object::New();
302   Local<Value> before = obj->Get(1);
303   CHECK(before->IsUndefined());
304   Local<String> bar_str = v8_str("bar");
305   obj->Set(1, bar_str);
306   Local<Value> after = obj->Get(1);
307   CHECK(!after->IsUndefined());
308   CHECK(after->IsString());
309   CHECK_EQ(bar_str, after);
310
311   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
312   CHECK_EQ(v8_str("a"), value->Get(0));
313   CHECK_EQ(v8_str("b"), value->Get(1));
314 }
315
316
317 THREADED_TEST(Script) {
318   v8::HandleScope scope;
319   LocalContext env;
320   const char* c_source = "1 + 2 + 3";
321   Local<String> source = String::New(c_source);
322   Local<Script> script = Script::Compile(source);
323   CHECK_EQ(6, script->Run()->Int32Value());
324 }
325
326
327 static uint16_t* AsciiToTwoByteString(const char* source) {
328   int array_length = i::StrLength(source) + 1;
329   uint16_t* converted = i::NewArray<uint16_t>(array_length);
330   for (int i = 0; i < array_length; i++) converted[i] = source[i];
331   return converted;
332 }
333
334
335 class TestResource: public String::ExternalStringResource {
336  public:
337   explicit TestResource(uint16_t* data, int* counter = NULL)
338     : data_(data), length_(0), counter_(counter) {
339     while (data[length_]) ++length_;
340   }
341
342   ~TestResource() {
343     i::DeleteArray(data_);
344     if (counter_ != NULL) ++*counter_;
345   }
346
347   const uint16_t* data() const {
348     return data_;
349   }
350
351   size_t length() const {
352     return length_;
353   }
354  private:
355   uint16_t* data_;
356   size_t length_;
357   int* counter_;
358 };
359
360
361 class TestAsciiResource: public String::ExternalAsciiStringResource {
362  public:
363   explicit TestAsciiResource(const char* data, int* counter = NULL)
364     : data_(data), length_(strlen(data)), counter_(counter) { }
365
366   ~TestAsciiResource() {
367     i::DeleteArray(data_);
368     if (counter_ != NULL) ++*counter_;
369   }
370
371   const char* data() const {
372     return data_;
373   }
374
375   size_t length() const {
376     return length_;
377   }
378  private:
379   const char* data_;
380   size_t length_;
381   int* counter_;
382 };
383
384
385 THREADED_TEST(ScriptUsingStringResource) {
386   int dispose_count = 0;
387   const char* c_source = "1 + 2 * 3";
388   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
389   {
390     v8::HandleScope scope;
391     LocalContext env;
392     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
393     Local<String> source = String::NewExternal(resource);
394     Local<Script> script = Script::Compile(source);
395     Local<Value> value = script->Run();
396     CHECK(value->IsNumber());
397     CHECK_EQ(7, value->Int32Value());
398     CHECK(source->IsExternal());
399     CHECK_EQ(resource,
400              static_cast<TestResource*>(source->GetExternalStringResource()));
401     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
402     CHECK_EQ(0, dispose_count);
403   }
404   v8::internal::Isolate::Current()->compilation_cache()->Clear();
405   HEAP->CollectAllAvailableGarbage();
406   CHECK_EQ(1, dispose_count);
407 }
408
409
410 THREADED_TEST(ScriptUsingAsciiStringResource) {
411   int dispose_count = 0;
412   const char* c_source = "1 + 2 * 3";
413   {
414     v8::HandleScope scope;
415     LocalContext env;
416     Local<String> source =
417         String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
418                                                   &dispose_count));
419     Local<Script> script = Script::Compile(source);
420     Local<Value> value = script->Run();
421     CHECK(value->IsNumber());
422     CHECK_EQ(7, value->Int32Value());
423     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
424     CHECK_EQ(0, dispose_count);
425   }
426   i::Isolate::Current()->compilation_cache()->Clear();
427   HEAP->CollectAllAvailableGarbage();
428   CHECK_EQ(1, dispose_count);
429 }
430
431
432 THREADED_TEST(ScriptMakingExternalString) {
433   int dispose_count = 0;
434   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
435   {
436     v8::HandleScope scope;
437     LocalContext env;
438     Local<String> source = String::New(two_byte_source);
439     // Trigger GCs so that the newly allocated string moves to old gen.
440     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
441     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
442     bool success = source->MakeExternal(new TestResource(two_byte_source,
443                                                          &dispose_count));
444     CHECK(success);
445     Local<Script> script = Script::Compile(source);
446     Local<Value> value = script->Run();
447     CHECK(value->IsNumber());
448     CHECK_EQ(7, value->Int32Value());
449     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
450     CHECK_EQ(0, dispose_count);
451   }
452   i::Isolate::Current()->compilation_cache()->Clear();
453   // TODO(1608): This should use kAbortIncrementalMarking.
454   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
455   CHECK_EQ(1, dispose_count);
456 }
457
458
459 THREADED_TEST(ScriptMakingExternalAsciiString) {
460   int dispose_count = 0;
461   const char* c_source = "1 + 2 * 3";
462   {
463     v8::HandleScope scope;
464     LocalContext env;
465     Local<String> source = v8_str(c_source);
466     // Trigger GCs so that the newly allocated string moves to old gen.
467     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
468     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
469     bool success = source->MakeExternal(
470         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
471     CHECK(success);
472     Local<Script> script = Script::Compile(source);
473     Local<Value> value = script->Run();
474     CHECK(value->IsNumber());
475     CHECK_EQ(7, value->Int32Value());
476     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
477     CHECK_EQ(0, dispose_count);
478   }
479   i::Isolate::Current()->compilation_cache()->Clear();
480   // TODO(1608): This should use kAbortIncrementalMarking.
481   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
482   CHECK_EQ(1, dispose_count);
483 }
484
485
486 TEST(MakingExternalStringConditions) {
487   v8::HandleScope scope;
488   LocalContext env;
489
490   // Free some space in the new space so that we can check freshness.
491   HEAP->CollectGarbage(i::NEW_SPACE);
492   HEAP->CollectGarbage(i::NEW_SPACE);
493
494   uint16_t* two_byte_string = AsciiToTwoByteString("small");
495   Local<String> small_string = String::New(two_byte_string);
496   i::DeleteArray(two_byte_string);
497
498   // We should refuse to externalize newly created small string.
499   CHECK(!small_string->CanMakeExternal());
500   // Trigger GCs so that the newly allocated string moves to old gen.
501   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
502   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
503   // Old space strings should be accepted.
504   CHECK(small_string->CanMakeExternal());
505
506   two_byte_string = AsciiToTwoByteString("small 2");
507   small_string = String::New(two_byte_string);
508   i::DeleteArray(two_byte_string);
509
510   // We should refuse externalizing newly created small string.
511   CHECK(!small_string->CanMakeExternal());
512   for (int i = 0; i < 100; i++) {
513     String::Value value(small_string);
514   }
515   // Frequently used strings should be accepted.
516   CHECK(small_string->CanMakeExternal());
517
518   const int buf_size = 10 * 1024;
519   char* buf = i::NewArray<char>(buf_size);
520   memset(buf, 'a', buf_size);
521   buf[buf_size - 1] = '\0';
522
523   two_byte_string = AsciiToTwoByteString(buf);
524   Local<String> large_string = String::New(two_byte_string);
525   i::DeleteArray(buf);
526   i::DeleteArray(two_byte_string);
527   // Large strings should be immediately accepted.
528   CHECK(large_string->CanMakeExternal());
529 }
530
531
532 TEST(MakingExternalAsciiStringConditions) {
533   v8::HandleScope scope;
534   LocalContext env;
535
536   // Free some space in the new space so that we can check freshness.
537   HEAP->CollectGarbage(i::NEW_SPACE);
538   HEAP->CollectGarbage(i::NEW_SPACE);
539
540   Local<String> small_string = String::New("small");
541   // We should refuse to externalize newly created small string.
542   CHECK(!small_string->CanMakeExternal());
543   // Trigger GCs so that the newly allocated string moves to old gen.
544   HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
545   HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
546   // Old space strings should be accepted.
547   CHECK(small_string->CanMakeExternal());
548
549   small_string = String::New("small 2");
550   // We should refuse externalizing newly created small string.
551   CHECK(!small_string->CanMakeExternal());
552   for (int i = 0; i < 100; i++) {
553     String::Value value(small_string);
554   }
555   // Frequently used strings should be accepted.
556   CHECK(small_string->CanMakeExternal());
557
558   const int buf_size = 10 * 1024;
559   char* buf = i::NewArray<char>(buf_size);
560   memset(buf, 'a', buf_size);
561   buf[buf_size - 1] = '\0';
562   Local<String> large_string = String::New(buf);
563   i::DeleteArray(buf);
564   // Large strings should be immediately accepted.
565   CHECK(large_string->CanMakeExternal());
566 }
567
568
569 THREADED_TEST(UsingExternalString) {
570   {
571     v8::HandleScope scope;
572     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
573     Local<String> string =
574         String::NewExternal(new TestResource(two_byte_string));
575     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
576     // Trigger GCs so that the newly allocated string moves to old gen.
577     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
578     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
579     i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
580     CHECK(isymbol->IsSymbol());
581   }
582   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
583   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
584 }
585
586
587 THREADED_TEST(UsingExternalAsciiString) {
588   {
589     v8::HandleScope scope;
590     const char* one_byte_string = "test string";
591     Local<String> string = String::NewExternal(
592         new TestAsciiResource(i::StrDup(one_byte_string)));
593     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
594     // Trigger GCs so that the newly allocated string moves to old gen.
595     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
596     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
597     i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring);
598     CHECK(isymbol->IsSymbol());
599   }
600   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
601   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
602 }
603
604
605 THREADED_TEST(ScavengeExternalString) {
606   int dispose_count = 0;
607   bool in_new_space = false;
608   {
609     v8::HandleScope scope;
610     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
611     Local<String> string =
612       String::NewExternal(new TestResource(two_byte_string,
613                                            &dispose_count));
614     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
615     HEAP->CollectGarbage(i::NEW_SPACE);
616     in_new_space = HEAP->InNewSpace(*istring);
617     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
618     CHECK_EQ(0, dispose_count);
619   }
620   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
621   CHECK_EQ(1, dispose_count);
622 }
623
624
625 THREADED_TEST(ScavengeExternalAsciiString) {
626   int dispose_count = 0;
627   bool in_new_space = false;
628   {
629     v8::HandleScope scope;
630     const char* one_byte_string = "test string";
631     Local<String> string = String::NewExternal(
632         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
633     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
634     HEAP->CollectGarbage(i::NEW_SPACE);
635     in_new_space = HEAP->InNewSpace(*istring);
636     CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
637     CHECK_EQ(0, dispose_count);
638   }
639   HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
640   CHECK_EQ(1, dispose_count);
641 }
642
643
644 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
645  public:
646   // Only used by non-threaded tests, so it can use static fields.
647   static int dispose_calls;
648   static int dispose_count;
649
650   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
651       : TestAsciiResource(data, &dispose_count),
652         dispose_(dispose) { }
653
654   void Dispose() {
655     ++dispose_calls;
656     if (dispose_) delete this;
657   }
658  private:
659   bool dispose_;
660 };
661
662
663 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
664 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
665
666
667 TEST(ExternalStringWithDisposeHandling) {
668   const char* c_source = "1 + 2 * 3";
669
670   // Use a stack allocated external string resource allocated object.
671   TestAsciiResourceWithDisposeControl::dispose_count = 0;
672   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
673   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
674   {
675     v8::HandleScope scope;
676     LocalContext env;
677     Local<String> source =  String::NewExternal(&res_stack);
678     Local<Script> script = Script::Compile(source);
679     Local<Value> value = script->Run();
680     CHECK(value->IsNumber());
681     CHECK_EQ(7, value->Int32Value());
682     HEAP->CollectAllAvailableGarbage();
683     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
684   }
685   i::Isolate::Current()->compilation_cache()->Clear();
686   HEAP->CollectAllAvailableGarbage();
687   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
688   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
689
690   // Use a heap allocated external string resource allocated object.
691   TestAsciiResourceWithDisposeControl::dispose_count = 0;
692   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
693   TestAsciiResource* res_heap =
694       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
695   {
696     v8::HandleScope scope;
697     LocalContext env;
698     Local<String> source =  String::NewExternal(res_heap);
699     Local<Script> script = Script::Compile(source);
700     Local<Value> value = script->Run();
701     CHECK(value->IsNumber());
702     CHECK_EQ(7, value->Int32Value());
703     HEAP->CollectAllAvailableGarbage();
704     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
705   }
706   i::Isolate::Current()->compilation_cache()->Clear();
707   HEAP->CollectAllAvailableGarbage();
708   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
709   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
710 }
711
712
713 THREADED_TEST(StringConcat) {
714   {
715     v8::HandleScope scope;
716     LocalContext env;
717     const char* one_byte_string_1 = "function a_times_t";
718     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
719     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
720     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
721     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
722     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
723     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
724     Local<String> left = v8_str(one_byte_string_1);
725
726     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
727     Local<String> right = String::New(two_byte_source);
728     i::DeleteArray(two_byte_source);
729
730     Local<String> source = String::Concat(left, right);
731     right = String::NewExternal(
732         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
733     source = String::Concat(source, right);
734     right = String::NewExternal(
735         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
736     source = String::Concat(source, right);
737     right = v8_str(one_byte_string_2);
738     source = String::Concat(source, right);
739
740     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
741     right = String::New(two_byte_source);
742     i::DeleteArray(two_byte_source);
743
744     source = String::Concat(source, right);
745     right = String::NewExternal(
746         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
747     source = String::Concat(source, right);
748     Local<Script> script = Script::Compile(source);
749     Local<Value> value = script->Run();
750     CHECK(value->IsNumber());
751     CHECK_EQ(68, value->Int32Value());
752   }
753   i::Isolate::Current()->compilation_cache()->Clear();
754   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
755   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
756 }
757
758
759 THREADED_TEST(GlobalProperties) {
760   v8::HandleScope scope;
761   LocalContext env;
762   v8::Handle<v8::Object> global = env->Global();
763   global->Set(v8_str("pi"), v8_num(3.1415926));
764   Local<Value> pi = global->Get(v8_str("pi"));
765   CHECK_EQ(3.1415926, pi->NumberValue());
766 }
767
768
769 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
770   ApiTestFuzzer::Fuzz();
771   return v8_num(102);
772 }
773
774
775 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
776   ApiTestFuzzer::Fuzz();
777   args.This()->Set(v8_str("x"), v8_num(1));
778   args.This()->Set(v8_str("y"), v8_num(2));
779   return args.This();
780 }
781
782 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
783   ApiTestFuzzer::Fuzz();
784   return v8_num(239);
785 }
786
787
788 THREADED_TEST(FunctionTemplate) {
789   v8::HandleScope scope;
790   LocalContext env;
791   {
792     Local<v8::FunctionTemplate> fun_templ =
793         v8::FunctionTemplate::New(handle_call);
794     Local<Function> fun = fun_templ->GetFunction();
795     env->Global()->Set(v8_str("obj"), fun);
796     Local<Script> script = v8_compile("obj()");
797     CHECK_EQ(102, script->Run()->Int32Value());
798   }
799   // Use SetCallHandler to initialize a function template, should work like the
800   // previous one.
801   {
802     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
803     fun_templ->SetCallHandler(handle_call);
804     Local<Function> fun = fun_templ->GetFunction();
805     env->Global()->Set(v8_str("obj"), fun);
806     Local<Script> script = v8_compile("obj()");
807     CHECK_EQ(102, script->Run()->Int32Value());
808   }
809   // Test constructor calls.
810   {
811     Local<v8::FunctionTemplate> fun_templ =
812         v8::FunctionTemplate::New(construct_call);
813     fun_templ->SetClassName(v8_str("funky"));
814     fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239);
815     Local<Function> fun = fun_templ->GetFunction();
816     env->Global()->Set(v8_str("obj"), fun);
817     Local<Script> script = v8_compile("var s = new obj(); s.x");
818     CHECK_EQ(1, script->Run()->Int32Value());
819
820     Local<Value> result = v8_compile("(new obj()).toString()")->Run();
821     CHECK_EQ(v8_str("[object funky]"), result);
822
823     result = v8_compile("(new obj()).m")->Run();
824     CHECK_EQ(239, result->Int32Value());
825   }
826 }
827
828
829 static void* expected_ptr;
830 static v8::Handle<v8::Value> callback(const v8::Arguments& args) {
831   void* ptr = v8::External::Unwrap(args.Data());
832   CHECK_EQ(expected_ptr, ptr);
833   return v8::True();
834 }
835
836
837 static void TestExternalPointerWrapping() {
838   v8::HandleScope scope;
839   LocalContext env;
840
841   v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr);
842
843   v8::Handle<v8::Object> obj = v8::Object::New();
844   obj->Set(v8_str("func"),
845            v8::FunctionTemplate::New(callback, data)->GetFunction());
846   env->Global()->Set(v8_str("obj"), obj);
847
848   CHECK(CompileRun(
849         "function foo() {\n"
850         "  for (var i = 0; i < 13; i++) obj.func();\n"
851         "}\n"
852         "foo(), true")->BooleanValue());
853 }
854
855
856 THREADED_TEST(ExternalWrap) {
857   // Check heap allocated object.
858   int* ptr = new int;
859   expected_ptr = ptr;
860   TestExternalPointerWrapping();
861   delete ptr;
862
863   // Check stack allocated object.
864   int foo;
865   expected_ptr = &foo;
866   TestExternalPointerWrapping();
867
868   // Check not aligned addresses.
869   const int n = 100;
870   char* s = new char[n];
871   for (int i = 0; i < n; i++) {
872     expected_ptr = s + i;
873     TestExternalPointerWrapping();
874   }
875
876   delete[] s;
877
878   // Check several invalid addresses.
879   expected_ptr = reinterpret_cast<void*>(1);
880   TestExternalPointerWrapping();
881
882   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
883   TestExternalPointerWrapping();
884
885   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
886   TestExternalPointerWrapping();
887
888 #if defined(V8_HOST_ARCH_X64)
889   // Check a value with a leading 1 bit in x64 Smi encoding.
890   expected_ptr = reinterpret_cast<void*>(0x400000000);
891   TestExternalPointerWrapping();
892
893   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
894   TestExternalPointerWrapping();
895
896   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
897   TestExternalPointerWrapping();
898 #endif
899 }
900
901
902 THREADED_TEST(FindInstanceInPrototypeChain) {
903   v8::HandleScope scope;
904   LocalContext env;
905
906   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
907   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
908   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
909   derived->Inherit(base);
910
911   Local<v8::Function> base_function = base->GetFunction();
912   Local<v8::Function> derived_function = derived->GetFunction();
913   Local<v8::Function> other_function = other->GetFunction();
914
915   Local<v8::Object> base_instance = base_function->NewInstance();
916   Local<v8::Object> derived_instance = derived_function->NewInstance();
917   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
918   Local<v8::Object> other_instance = other_function->NewInstance();
919   derived_instance2->Set(v8_str("__proto__"), derived_instance);
920   other_instance->Set(v8_str("__proto__"), derived_instance2);
921
922   // base_instance is only an instance of base.
923   CHECK_EQ(base_instance,
924            base_instance->FindInstanceInPrototypeChain(base));
925   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
926   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
927
928   // derived_instance is an instance of base and derived.
929   CHECK_EQ(derived_instance,
930            derived_instance->FindInstanceInPrototypeChain(base));
931   CHECK_EQ(derived_instance,
932            derived_instance->FindInstanceInPrototypeChain(derived));
933   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
934
935   // other_instance is an instance of other and its immediate
936   // prototype derived_instance2 is an instance of base and derived.
937   // Note, derived_instance is an instance of base and derived too,
938   // but it comes after derived_instance2 in the prototype chain of
939   // other_instance.
940   CHECK_EQ(derived_instance2,
941            other_instance->FindInstanceInPrototypeChain(base));
942   CHECK_EQ(derived_instance2,
943            other_instance->FindInstanceInPrototypeChain(derived));
944   CHECK_EQ(other_instance,
945            other_instance->FindInstanceInPrototypeChain(other));
946 }
947
948
949 THREADED_TEST(TinyInteger) {
950   v8::HandleScope scope;
951   LocalContext env;
952   int32_t value = 239;
953   Local<v8::Integer> value_obj = v8::Integer::New(value);
954   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
955 }
956
957
958 THREADED_TEST(BigSmiInteger) {
959   v8::HandleScope scope;
960   LocalContext env;
961   int32_t value = i::Smi::kMaxValue;
962   // We cannot add one to a Smi::kMaxValue without wrapping.
963   if (i::kSmiValueSize < 32) {
964     CHECK(i::Smi::IsValid(value));
965     CHECK(!i::Smi::IsValid(value + 1));
966     Local<v8::Integer> value_obj = v8::Integer::New(value);
967     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
968   }
969 }
970
971
972 THREADED_TEST(BigInteger) {
973   v8::HandleScope scope;
974   LocalContext env;
975   // We cannot add one to a Smi::kMaxValue without wrapping.
976   if (i::kSmiValueSize < 32) {
977     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
978     // The code will not be run in that case, due to the "if" guard.
979     int32_t value =
980         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
981     CHECK(value > i::Smi::kMaxValue);
982     CHECK(!i::Smi::IsValid(value));
983     Local<v8::Integer> value_obj = v8::Integer::New(value);
984     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
985   }
986 }
987
988
989 THREADED_TEST(TinyUnsignedInteger) {
990   v8::HandleScope scope;
991   LocalContext env;
992   uint32_t value = 239;
993   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
994   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
995 }
996
997
998 THREADED_TEST(BigUnsignedSmiInteger) {
999   v8::HandleScope scope;
1000   LocalContext env;
1001   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1002   CHECK(i::Smi::IsValid(value));
1003   CHECK(!i::Smi::IsValid(value + 1));
1004   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1005   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1006 }
1007
1008
1009 THREADED_TEST(BigUnsignedInteger) {
1010   v8::HandleScope scope;
1011   LocalContext env;
1012   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1013   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1014   CHECK(!i::Smi::IsValid(value));
1015   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1016   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1017 }
1018
1019
1020 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1021   v8::HandleScope scope;
1022   LocalContext env;
1023   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1024   uint32_t value = INT32_MAX_AS_UINT + 1;
1025   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1026   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1027   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1028 }
1029
1030
1031 THREADED_TEST(IsNativeError) {
1032   v8::HandleScope scope;
1033   LocalContext env;
1034   v8::Handle<Value> syntax_error = CompileRun(
1035       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1036   CHECK(syntax_error->IsNativeError());
1037   v8::Handle<Value> not_error = CompileRun("{a:42}");
1038   CHECK(!not_error->IsNativeError());
1039   v8::Handle<Value> not_object = CompileRun("42");
1040   CHECK(!not_object->IsNativeError());
1041 }
1042
1043
1044 THREADED_TEST(StringObject) {
1045   v8::HandleScope scope;
1046   LocalContext env;
1047   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1048   CHECK(boxed_string->IsStringObject());
1049   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1050   CHECK(!unboxed_string->IsStringObject());
1051   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1052   CHECK(!boxed_not_string->IsStringObject());
1053   v8::Handle<Value> not_object = CompileRun("0");
1054   CHECK(!not_object->IsStringObject());
1055   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1056   CHECK(!as_boxed.IsEmpty());
1057   Local<v8::String> the_string = as_boxed->StringValue();
1058   CHECK(!the_string.IsEmpty());
1059   ExpectObject("\"test\"", the_string);
1060   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1061   CHECK(new_boxed_string->IsStringObject());
1062   as_boxed = new_boxed_string.As<v8::StringObject>();
1063   the_string = as_boxed->StringValue();
1064   CHECK(!the_string.IsEmpty());
1065   ExpectObject("\"test\"", the_string);
1066 }
1067
1068
1069 THREADED_TEST(NumberObject) {
1070   v8::HandleScope scope;
1071   LocalContext env;
1072   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1073   CHECK(boxed_number->IsNumberObject());
1074   v8::Handle<Value> unboxed_number = CompileRun("42");
1075   CHECK(!unboxed_number->IsNumberObject());
1076   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1077   CHECK(!boxed_not_number->IsNumberObject());
1078   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1079   CHECK(!as_boxed.IsEmpty());
1080   double the_number = as_boxed->NumberValue();
1081   CHECK_EQ(42.0, the_number);
1082   v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1083   CHECK(new_boxed_number->IsNumberObject());
1084   as_boxed = new_boxed_number.As<v8::NumberObject>();
1085   the_number = as_boxed->NumberValue();
1086   CHECK_EQ(43.0, the_number);
1087 }
1088
1089
1090 THREADED_TEST(BooleanObject) {
1091   v8::HandleScope scope;
1092   LocalContext env;
1093   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1094   CHECK(boxed_boolean->IsBooleanObject());
1095   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1096   CHECK(!unboxed_boolean->IsBooleanObject());
1097   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1098   CHECK(!boxed_not_boolean->IsBooleanObject());
1099   v8::Handle<v8::BooleanObject> as_boxed =
1100       boxed_boolean.As<v8::BooleanObject>();
1101   CHECK(!as_boxed.IsEmpty());
1102   bool the_boolean = as_boxed->BooleanValue();
1103   CHECK_EQ(true, the_boolean);
1104   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1105   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1106   CHECK(boxed_true->IsBooleanObject());
1107   CHECK(boxed_false->IsBooleanObject());
1108   as_boxed = boxed_true.As<v8::BooleanObject>();
1109   CHECK_EQ(true, as_boxed->BooleanValue());
1110   as_boxed = boxed_false.As<v8::BooleanObject>();
1111   CHECK_EQ(false, as_boxed->BooleanValue());
1112 }
1113
1114
1115 THREADED_TEST(Number) {
1116   v8::HandleScope scope;
1117   LocalContext env;
1118   double PI = 3.1415926;
1119   Local<v8::Number> pi_obj = v8::Number::New(PI);
1120   CHECK_EQ(PI, pi_obj->NumberValue());
1121 }
1122
1123
1124 THREADED_TEST(ToNumber) {
1125   v8::HandleScope scope;
1126   LocalContext env;
1127   Local<String> str = v8_str("3.1415926");
1128   CHECK_EQ(3.1415926, str->NumberValue());
1129   v8::Handle<v8::Boolean> t = v8::True();
1130   CHECK_EQ(1.0, t->NumberValue());
1131   v8::Handle<v8::Boolean> f = v8::False();
1132   CHECK_EQ(0.0, f->NumberValue());
1133 }
1134
1135
1136 THREADED_TEST(Date) {
1137   v8::HandleScope scope;
1138   LocalContext env;
1139   double PI = 3.1415926;
1140   Local<Value> date = v8::Date::New(PI);
1141   CHECK_EQ(3.0, date->NumberValue());
1142   date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1143   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1144 }
1145
1146
1147 THREADED_TEST(Boolean) {
1148   v8::HandleScope scope;
1149   LocalContext env;
1150   v8::Handle<v8::Boolean> t = v8::True();
1151   CHECK(t->Value());
1152   v8::Handle<v8::Boolean> f = v8::False();
1153   CHECK(!f->Value());
1154   v8::Handle<v8::Primitive> u = v8::Undefined();
1155   CHECK(!u->BooleanValue());
1156   v8::Handle<v8::Primitive> n = v8::Null();
1157   CHECK(!n->BooleanValue());
1158   v8::Handle<String> str1 = v8_str("");
1159   CHECK(!str1->BooleanValue());
1160   v8::Handle<String> str2 = v8_str("x");
1161   CHECK(str2->BooleanValue());
1162   CHECK(!v8::Number::New(0)->BooleanValue());
1163   CHECK(v8::Number::New(-1)->BooleanValue());
1164   CHECK(v8::Number::New(1)->BooleanValue());
1165   CHECK(v8::Number::New(42)->BooleanValue());
1166   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1167 }
1168
1169
1170 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
1171   ApiTestFuzzer::Fuzz();
1172   return v8_num(13.4);
1173 }
1174
1175
1176 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
1177   ApiTestFuzzer::Fuzz();
1178   return v8_num(876);
1179 }
1180
1181
1182 THREADED_TEST(GlobalPrototype) {
1183   v8::HandleScope scope;
1184   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1185   func_templ->PrototypeTemplate()->Set(
1186       "dummy",
1187       v8::FunctionTemplate::New(DummyCallHandler));
1188   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1189   templ->Set("x", v8_num(200));
1190   templ->SetAccessor(v8_str("m"), GetM);
1191   LocalContext env(0, templ);
1192   v8::Handle<v8::Object> obj(env->Global());
1193   v8::Handle<Script> script(v8_compile("dummy()"));
1194   v8::Handle<Value> result(script->Run());
1195   CHECK_EQ(13.4, result->NumberValue());
1196   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1197   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1198 }
1199
1200
1201 THREADED_TEST(ObjectTemplate) {
1202   v8::HandleScope scope;
1203   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1204   templ1->Set("x", v8_num(10));
1205   templ1->Set("y", v8_num(13));
1206   LocalContext env;
1207   Local<v8::Object> instance1 = templ1->NewInstance();
1208   env->Global()->Set(v8_str("p"), instance1);
1209   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1210   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1211   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1212   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1213   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1214   templ2->Set("a", v8_num(12));
1215   templ2->Set("b", templ1);
1216   Local<v8::Object> instance2 = templ2->NewInstance();
1217   env->Global()->Set(v8_str("q"), instance2);
1218   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1219   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1220   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1221   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1222 }
1223
1224
1225 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
1226   ApiTestFuzzer::Fuzz();
1227   return v8_num(17.2);
1228 }
1229
1230
1231 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
1232   ApiTestFuzzer::Fuzz();
1233   return v8_num(15.2);
1234 }
1235
1236
1237 THREADED_TEST(DescriptorInheritance) {
1238   v8::HandleScope scope;
1239   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1240   super->PrototypeTemplate()->Set("flabby",
1241                                   v8::FunctionTemplate::New(GetFlabby));
1242   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1243
1244   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1245
1246   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1247   base1->Inherit(super);
1248   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1249
1250   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1251   base2->Inherit(super);
1252   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1253
1254   LocalContext env;
1255
1256   env->Global()->Set(v8_str("s"), super->GetFunction());
1257   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1258   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1259
1260   // Checks right __proto__ chain.
1261   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1262   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1263
1264   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1265
1266   // Instance accessor should not be visible on function object or its prototype
1267   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1268   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1269   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1270
1271   env->Global()->Set(v8_str("obj"),
1272                      base1->GetFunction()->NewInstance());
1273   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1274   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1275   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1276   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1277   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1278
1279   env->Global()->Set(v8_str("obj2"),
1280                      base2->GetFunction()->NewInstance());
1281   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1282   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1283   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1284   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1285   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1286
1287   // base1 and base2 cannot cross reference to each's prototype
1288   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1289   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1290 }
1291
1292
1293 int echo_named_call_count;
1294
1295
1296 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
1297                                            const AccessorInfo& info) {
1298   ApiTestFuzzer::Fuzz();
1299   CHECK_EQ(v8_str("data"), info.Data());
1300   echo_named_call_count++;
1301   return name;
1302 }
1303
1304 // Helper functions for Interceptor/Accessor interaction tests
1305
1306 Handle<Value> SimpleAccessorGetter(Local<String> name,
1307                                    const AccessorInfo& info) {
1308   Handle<Object> self = info.This();
1309   return self->Get(String::Concat(v8_str("accessor_"), name));
1310 }
1311
1312 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1313                           const AccessorInfo& info) {
1314   Handle<Object> self = info.This();
1315   self->Set(String::Concat(v8_str("accessor_"), name), value);
1316 }
1317
1318 Handle<Value> EmptyInterceptorGetter(Local<String> name,
1319                                      const AccessorInfo& info) {
1320   return Handle<Value>();
1321 }
1322
1323 Handle<Value> EmptyInterceptorSetter(Local<String> name,
1324                                      Local<Value> value,
1325                                      const AccessorInfo& info) {
1326   return Handle<Value>();
1327 }
1328
1329 Handle<Value> InterceptorGetter(Local<String> name,
1330                                 const AccessorInfo& info) {
1331   // Intercept names that start with 'interceptor_'.
1332   String::AsciiValue ascii(name);
1333   char* name_str = *ascii;
1334   char prefix[] = "interceptor_";
1335   int i;
1336   for (i = 0; name_str[i] && prefix[i]; ++i) {
1337     if (name_str[i] != prefix[i]) return Handle<Value>();
1338   }
1339   Handle<Object> self = info.This();
1340   return self->GetHiddenValue(v8_str(name_str + i));
1341 }
1342
1343 Handle<Value> InterceptorSetter(Local<String> name,
1344                                 Local<Value> value,
1345                                 const AccessorInfo& info) {
1346   // Intercept accesses that set certain integer values.
1347   if (value->IsInt32() && value->Int32Value() < 10000) {
1348     Handle<Object> self = info.This();
1349     self->SetHiddenValue(name, value);
1350     return value;
1351   }
1352   return Handle<Value>();
1353 }
1354
1355 void AddAccessor(Handle<FunctionTemplate> templ,
1356                  Handle<String> name,
1357                  v8::AccessorGetter getter,
1358                  v8::AccessorSetter setter) {
1359   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1360 }
1361
1362 void AddInterceptor(Handle<FunctionTemplate> templ,
1363                     v8::NamedPropertyGetter getter,
1364                     v8::NamedPropertySetter setter) {
1365   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1366 }
1367
1368 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1369   v8::HandleScope scope;
1370   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1371   Handle<FunctionTemplate> child = FunctionTemplate::New();
1372   child->Inherit(parent);
1373   AddAccessor(parent, v8_str("age"),
1374               SimpleAccessorGetter, SimpleAccessorSetter);
1375   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1376   LocalContext env;
1377   env->Global()->Set(v8_str("Child"), child->GetFunction());
1378   CompileRun("var child = new Child;"
1379              "child.age = 10;");
1380   ExpectBoolean("child.hasOwnProperty('age')", false);
1381   ExpectInt32("child.age", 10);
1382   ExpectInt32("child.accessor_age", 10);
1383 }
1384
1385 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1386   v8::HandleScope scope;
1387   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1388   Handle<FunctionTemplate> child = FunctionTemplate::New();
1389   child->Inherit(parent);
1390   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1391   LocalContext env;
1392   env->Global()->Set(v8_str("Child"), child->GetFunction());
1393   CompileRun("var child = new Child;"
1394              "var parent = child.__proto__;"
1395              "Object.defineProperty(parent, 'age', "
1396              "  {get: function(){ return this.accessor_age; }, "
1397              "   set: function(v){ this.accessor_age = v; }, "
1398              "   enumerable: true, configurable: true});"
1399              "child.age = 10;");
1400   ExpectBoolean("child.hasOwnProperty('age')", false);
1401   ExpectInt32("child.age", 10);
1402   ExpectInt32("child.accessor_age", 10);
1403 }
1404
1405 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1406   v8::HandleScope scope;
1407   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1408   Handle<FunctionTemplate> child = FunctionTemplate::New();
1409   child->Inherit(parent);
1410   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1411   LocalContext env;
1412   env->Global()->Set(v8_str("Child"), child->GetFunction());
1413   CompileRun("var child = new Child;"
1414              "var parent = child.__proto__;"
1415              "parent.name = 'Alice';");
1416   ExpectBoolean("child.hasOwnProperty('name')", false);
1417   ExpectString("child.name", "Alice");
1418   CompileRun("child.name = 'Bob';");
1419   ExpectString("child.name", "Bob");
1420   ExpectBoolean("child.hasOwnProperty('name')", true);
1421   ExpectString("parent.name", "Alice");
1422 }
1423
1424 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1425   v8::HandleScope scope;
1426   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1427   Handle<FunctionTemplate> child = FunctionTemplate::New();
1428   child->Inherit(parent);
1429   AddAccessor(parent, v8_str("age"),
1430               SimpleAccessorGetter, SimpleAccessorSetter);
1431   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1432   LocalContext env;
1433   env->Global()->Set(v8_str("Child"), child->GetFunction());
1434   CompileRun("var child = new Child;"
1435              "function setAge(i){ child.age = i; };"
1436              "for(var i = 0; i <= 10000; i++) setAge(i);");
1437   // All i < 10000 go to the interceptor.
1438   ExpectInt32("child.interceptor_age", 9999);
1439   // The last i goes to the accessor.
1440   ExpectInt32("child.accessor_age", 10000);
1441 }
1442
1443 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1444   v8::HandleScope scope;
1445   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1446   Handle<FunctionTemplate> child = FunctionTemplate::New();
1447   child->Inherit(parent);
1448   AddAccessor(parent, v8_str("age"),
1449               SimpleAccessorGetter, SimpleAccessorSetter);
1450   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1451   LocalContext env;
1452   env->Global()->Set(v8_str("Child"), child->GetFunction());
1453   CompileRun("var child = new Child;"
1454              "function setAge(i){ child.age = i; };"
1455              "for(var i = 20000; i >= 9999; i--) setAge(i);");
1456   // All i >= 10000 go to the accessor.
1457   ExpectInt32("child.accessor_age", 10000);
1458   // The last i goes to the interceptor.
1459   ExpectInt32("child.interceptor_age", 9999);
1460 }
1461
1462 THREADED_TEST(SwitchFromInterceptorToProperty) {
1463   v8::HandleScope scope;
1464   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1465   Handle<FunctionTemplate> child = FunctionTemplate::New();
1466   child->Inherit(parent);
1467   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1468   LocalContext env;
1469   env->Global()->Set(v8_str("Child"), child->GetFunction());
1470   CompileRun("var child = new Child;"
1471              "function setAge(i){ child.age = i; };"
1472              "for(var i = 0; i <= 10000; i++) setAge(i);");
1473   // All i < 10000 go to the interceptor.
1474   ExpectInt32("child.interceptor_age", 9999);
1475   // The last i goes to child's own property.
1476   ExpectInt32("child.age", 10000);
1477 }
1478
1479 THREADED_TEST(SwitchFromPropertyToInterceptor) {
1480   v8::HandleScope scope;
1481   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1482   Handle<FunctionTemplate> child = FunctionTemplate::New();
1483   child->Inherit(parent);
1484   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1485   LocalContext env;
1486   env->Global()->Set(v8_str("Child"), child->GetFunction());
1487   CompileRun("var child = new Child;"
1488              "function setAge(i){ child.age = i; };"
1489              "for(var i = 20000; i >= 9999; i--) setAge(i);");
1490   // All i >= 10000 go to child's own property.
1491   ExpectInt32("child.age", 10000);
1492   // The last i goes to the interceptor.
1493   ExpectInt32("child.interceptor_age", 9999);
1494 }
1495
1496 THREADED_TEST(NamedPropertyHandlerGetter) {
1497   echo_named_call_count = 0;
1498   v8::HandleScope scope;
1499   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1500   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1501                                                      0, 0, 0, 0,
1502                                                      v8_str("data"));
1503   LocalContext env;
1504   env->Global()->Set(v8_str("obj"),
1505                      templ->GetFunction()->NewInstance());
1506   CHECK_EQ(echo_named_call_count, 0);
1507   v8_compile("obj.x")->Run();
1508   CHECK_EQ(echo_named_call_count, 1);
1509   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1510   v8::Handle<Value> str = CompileRun(code);
1511   String::AsciiValue value(str);
1512   CHECK_EQ(*value, "oddlepoddle");
1513   // Check default behavior
1514   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1515   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1516   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1517 }
1518
1519
1520 int echo_indexed_call_count = 0;
1521
1522
1523 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1524                                              const AccessorInfo& info) {
1525   ApiTestFuzzer::Fuzz();
1526   CHECK_EQ(v8_num(637), info.Data());
1527   echo_indexed_call_count++;
1528   return v8_num(index);
1529 }
1530
1531
1532 THREADED_TEST(IndexedPropertyHandlerGetter) {
1533   v8::HandleScope scope;
1534   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1535   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1536                                                        0, 0, 0, 0,
1537                                                        v8_num(637));
1538   LocalContext env;
1539   env->Global()->Set(v8_str("obj"),
1540                      templ->GetFunction()->NewInstance());
1541   Local<Script> script = v8_compile("obj[900]");
1542   CHECK_EQ(script->Run()->Int32Value(), 900);
1543 }
1544
1545
1546 v8::Handle<v8::Object> bottom;
1547
1548 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1549     uint32_t index,
1550     const AccessorInfo& info) {
1551   ApiTestFuzzer::Fuzz();
1552   CHECK(info.This()->Equals(bottom));
1553   return v8::Handle<Value>();
1554 }
1555
1556 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1557     Local<String> name,
1558     const AccessorInfo& info) {
1559   ApiTestFuzzer::Fuzz();
1560   CHECK(info.This()->Equals(bottom));
1561   return v8::Handle<Value>();
1562 }
1563
1564
1565 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1566                                                  Local<Value> value,
1567                                                  const AccessorInfo& info) {
1568   ApiTestFuzzer::Fuzz();
1569   CHECK(info.This()->Equals(bottom));
1570   return v8::Handle<Value>();
1571 }
1572
1573
1574 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1575                                                Local<Value> value,
1576                                                const AccessorInfo& info) {
1577   ApiTestFuzzer::Fuzz();
1578   CHECK(info.This()->Equals(bottom));
1579   return v8::Handle<Value>();
1580 }
1581
1582 v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery(
1583     uint32_t index,
1584     const AccessorInfo& info) {
1585   ApiTestFuzzer::Fuzz();
1586   CHECK(info.This()->Equals(bottom));
1587   return v8::Handle<v8::Integer>();
1588 }
1589
1590
1591 v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
1592                                                     const AccessorInfo& info) {
1593   ApiTestFuzzer::Fuzz();
1594   CHECK(info.This()->Equals(bottom));
1595   return v8::Handle<v8::Integer>();
1596 }
1597
1598
1599 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1600     uint32_t index,
1601     const AccessorInfo& info) {
1602   ApiTestFuzzer::Fuzz();
1603   CHECK(info.This()->Equals(bottom));
1604   return v8::Handle<v8::Boolean>();
1605 }
1606
1607
1608 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1609     Local<String> property,
1610     const AccessorInfo& info) {
1611   ApiTestFuzzer::Fuzz();
1612   CHECK(info.This()->Equals(bottom));
1613   return v8::Handle<v8::Boolean>();
1614 }
1615
1616
1617 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1618     const AccessorInfo& info) {
1619   ApiTestFuzzer::Fuzz();
1620   CHECK(info.This()->Equals(bottom));
1621   return v8::Handle<v8::Array>();
1622 }
1623
1624
1625 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1626     const AccessorInfo& info) {
1627   ApiTestFuzzer::Fuzz();
1628   CHECK(info.This()->Equals(bottom));
1629   return v8::Handle<v8::Array>();
1630 }
1631
1632
1633 THREADED_TEST(PropertyHandlerInPrototype) {
1634   v8::HandleScope scope;
1635   LocalContext env;
1636
1637   // Set up a prototype chain with three interceptors.
1638   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1639   templ->InstanceTemplate()->SetIndexedPropertyHandler(
1640       CheckThisIndexedPropertyHandler,
1641       CheckThisIndexedPropertySetter,
1642       CheckThisIndexedPropertyQuery,
1643       CheckThisIndexedPropertyDeleter,
1644       CheckThisIndexedPropertyEnumerator);
1645
1646   templ->InstanceTemplate()->SetNamedPropertyHandler(
1647       CheckThisNamedPropertyHandler,
1648       CheckThisNamedPropertySetter,
1649       CheckThisNamedPropertyQuery,
1650       CheckThisNamedPropertyDeleter,
1651       CheckThisNamedPropertyEnumerator);
1652
1653   bottom = templ->GetFunction()->NewInstance();
1654   Local<v8::Object> top = templ->GetFunction()->NewInstance();
1655   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1656
1657   bottom->Set(v8_str("__proto__"), middle);
1658   middle->Set(v8_str("__proto__"), top);
1659   env->Global()->Set(v8_str("obj"), bottom);
1660
1661   // Indexed and named get.
1662   Script::Compile(v8_str("obj[0]"))->Run();
1663   Script::Compile(v8_str("obj.x"))->Run();
1664
1665   // Indexed and named set.
1666   Script::Compile(v8_str("obj[1] = 42"))->Run();
1667   Script::Compile(v8_str("obj.y = 42"))->Run();
1668
1669   // Indexed and named query.
1670   Script::Compile(v8_str("0 in obj"))->Run();
1671   Script::Compile(v8_str("'x' in obj"))->Run();
1672
1673   // Indexed and named deleter.
1674   Script::Compile(v8_str("delete obj[0]"))->Run();
1675   Script::Compile(v8_str("delete obj.x"))->Run();
1676
1677   // Enumerators.
1678   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1679 }
1680
1681
1682 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1683                                                const AccessorInfo& info) {
1684   ApiTestFuzzer::Fuzz();
1685   if (v8_str("pre")->Equals(key)) {
1686     return v8_str("PrePropertyHandler: pre");
1687   }
1688   return v8::Handle<String>();
1689 }
1690
1691
1692 static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
1693                                                        const AccessorInfo&) {
1694   if (v8_str("pre")->Equals(key)) {
1695     return v8::Integer::New(v8::None);
1696   }
1697
1698   return v8::Handle<v8::Integer>();  // do not intercept the call
1699 }
1700
1701
1702 THREADED_TEST(PrePropertyHandler) {
1703   v8::HandleScope scope;
1704   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1705   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1706                                                     0,
1707                                                     PrePropertyHandlerQuery);
1708   LocalContext env(NULL, desc->InstanceTemplate());
1709   Script::Compile(v8_str(
1710       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1711   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1712   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1713   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1714   CHECK_EQ(v8_str("Object: on"), result_on);
1715   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1716   CHECK(result_post.IsEmpty());
1717 }
1718
1719
1720 THREADED_TEST(UndefinedIsNotEnumerable) {
1721   v8::HandleScope scope;
1722   LocalContext env;
1723   v8::Handle<Value> result = Script::Compile(v8_str(
1724       "this.propertyIsEnumerable(undefined)"))->Run();
1725   CHECK(result->IsFalse());
1726 }
1727
1728
1729 v8::Handle<Script> call_recursively_script;
1730 static const int kTargetRecursionDepth = 200;  // near maximum
1731
1732
1733 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1734   ApiTestFuzzer::Fuzz();
1735   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1736   if (depth == kTargetRecursionDepth) return v8::Undefined();
1737   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1738   return call_recursively_script->Run();
1739 }
1740
1741
1742 static v8::Handle<Value> CallFunctionRecursivelyCall(
1743     const v8::Arguments& args) {
1744   ApiTestFuzzer::Fuzz();
1745   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1746   if (depth == kTargetRecursionDepth) {
1747     printf("[depth = %d]\n", depth);
1748     return v8::Undefined();
1749   }
1750   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1751   v8::Handle<Value> function =
1752       args.This()->Get(v8_str("callFunctionRecursively"));
1753   return function.As<Function>()->Call(args.This(), 0, NULL);
1754 }
1755
1756
1757 THREADED_TEST(DeepCrossLanguageRecursion) {
1758   v8::HandleScope scope;
1759   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1760   global->Set(v8_str("callScriptRecursively"),
1761               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1762   global->Set(v8_str("callFunctionRecursively"),
1763               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1764   LocalContext env(NULL, global);
1765
1766   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1767   call_recursively_script = v8_compile("callScriptRecursively()");
1768   v8::Handle<Value> result(call_recursively_script->Run());
1769   call_recursively_script = v8::Handle<Script>();
1770
1771   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1772   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1773 }
1774
1775
1776 static v8::Handle<Value>
1777     ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1778   ApiTestFuzzer::Fuzz();
1779   return v8::ThrowException(key);
1780 }
1781
1782
1783 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1784                                                     Local<Value>,
1785                                                     const AccessorInfo&) {
1786   v8::ThrowException(key);
1787   return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1788 }
1789
1790
1791 THREADED_TEST(CallbackExceptionRegression) {
1792   v8::HandleScope scope;
1793   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1794   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1795                                ThrowingPropertyHandlerSet);
1796   LocalContext env;
1797   env->Global()->Set(v8_str("obj"), obj->NewInstance());
1798   v8::Handle<Value> otto = Script::Compile(v8_str(
1799       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1800   CHECK_EQ(v8_str("otto"), otto);
1801   v8::Handle<Value> netto = Script::Compile(v8_str(
1802       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1803   CHECK_EQ(v8_str("netto"), netto);
1804 }
1805
1806
1807 THREADED_TEST(FunctionPrototype) {
1808   v8::HandleScope scope;
1809   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1810   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1811   LocalContext env;
1812   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1813   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1814   CHECK_EQ(script->Run()->Int32Value(), 321);
1815 }
1816
1817
1818 THREADED_TEST(InternalFields) {
1819   v8::HandleScope scope;
1820   LocalContext env;
1821
1822   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1823   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1824   instance_templ->SetInternalFieldCount(1);
1825   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1826   CHECK_EQ(1, obj->InternalFieldCount());
1827   CHECK(obj->GetInternalField(0)->IsUndefined());
1828   obj->SetInternalField(0, v8_num(17));
1829   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1830 }
1831
1832
1833 THREADED_TEST(GlobalObjectInternalFields) {
1834   v8::HandleScope scope;
1835   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
1836   global_template->SetInternalFieldCount(1);
1837   LocalContext env(NULL, global_template);
1838   v8::Handle<v8::Object> global_proxy = env->Global();
1839   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
1840   CHECK_EQ(1, global->InternalFieldCount());
1841   CHECK(global->GetInternalField(0)->IsUndefined());
1842   global->SetInternalField(0, v8_num(17));
1843   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
1844 }
1845
1846
1847 THREADED_TEST(InternalFieldsNativePointers) {
1848   v8::HandleScope scope;
1849   LocalContext env;
1850
1851   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1852   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1853   instance_templ->SetInternalFieldCount(1);
1854   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1855   CHECK_EQ(1, obj->InternalFieldCount());
1856   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1857
1858   char* data = new char[100];
1859
1860   void* aligned = data;
1861   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1862   void* unaligned = data + 1;
1863   CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1864
1865   // Check reading and writing aligned pointers.
1866   obj->SetPointerInInternalField(0, aligned);
1867   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1868   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1869
1870   // Check reading and writing unaligned pointers.
1871   obj->SetPointerInInternalField(0, unaligned);
1872   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1873   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1874
1875   delete[] data;
1876 }
1877
1878
1879 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1880   v8::HandleScope scope;
1881   LocalContext env;
1882
1883   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1884   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1885   instance_templ->SetInternalFieldCount(1);
1886   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1887   CHECK_EQ(1, obj->InternalFieldCount());
1888   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1889
1890   char* data = new char[100];
1891
1892   void* aligned = data;
1893   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1));
1894   void* unaligned = data + 1;
1895   CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1));
1896
1897   obj->SetPointerInInternalField(0, aligned);
1898   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1899   CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1900
1901   obj->SetPointerInInternalField(0, unaligned);
1902   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1903   CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1904
1905   obj->SetInternalField(0, v8::External::Wrap(aligned));
1906   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1907   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1908
1909   obj->SetInternalField(0, v8::External::Wrap(unaligned));
1910   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1911   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1912
1913   delete[] data;
1914 }
1915
1916
1917 THREADED_TEST(IdentityHash) {
1918   v8::HandleScope scope;
1919   LocalContext env;
1920
1921   // Ensure that the test starts with an fresh heap to test whether the hash
1922   // code is based on the address.
1923   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1924   Local<v8::Object> obj = v8::Object::New();
1925   int hash = obj->GetIdentityHash();
1926   int hash1 = obj->GetIdentityHash();
1927   CHECK_EQ(hash, hash1);
1928   int hash2 = v8::Object::New()->GetIdentityHash();
1929   // Since the identity hash is essentially a random number two consecutive
1930   // objects should not be assigned the same hash code. If the test below fails
1931   // the random number generator should be evaluated.
1932   CHECK_NE(hash, hash2);
1933   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1934   int hash3 = v8::Object::New()->GetIdentityHash();
1935   // Make sure that the identity hash is not based on the initial address of
1936   // the object alone. If the test below fails the random number generator
1937   // should be evaluated.
1938   CHECK_NE(hash, hash3);
1939   int hash4 = obj->GetIdentityHash();
1940   CHECK_EQ(hash, hash4);
1941
1942   // Check identity hashes behaviour in the presence of JS accessors.
1943   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
1944   {
1945     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
1946     Local<v8::Object> o1 = v8::Object::New();
1947     Local<v8::Object> o2 = v8::Object::New();
1948     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1949   }
1950   {
1951     CompileRun(
1952         "function cnst() { return 42; };\n"
1953         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
1954     Local<v8::Object> o1 = v8::Object::New();
1955     Local<v8::Object> o2 = v8::Object::New();
1956     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
1957   }
1958 }
1959
1960
1961 THREADED_TEST(HiddenProperties) {
1962   v8::HandleScope scope;
1963   LocalContext env;
1964
1965   v8::Local<v8::Object> obj = v8::Object::New();
1966   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1967   v8::Local<v8::String> empty = v8_str("");
1968   v8::Local<v8::String> prop_name = v8_str("prop_name");
1969
1970   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1971
1972   // Make sure delete of a non-existent hidden value works
1973   CHECK(obj->DeleteHiddenValue(key));
1974
1975   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1976   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1977   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1978   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1979
1980   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1981
1982   // Make sure we do not find the hidden property.
1983   CHECK(!obj->Has(empty));
1984   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1985   CHECK(obj->Get(empty)->IsUndefined());
1986   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1987   CHECK(obj->Set(empty, v8::Integer::New(2003)));
1988   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1989   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1990
1991   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
1992
1993   // Add another property and delete it afterwards to force the object in
1994   // slow case.
1995   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1996   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1997   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1998   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1999   CHECK(obj->Delete(prop_name));
2000   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2001
2002   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2003
2004   CHECK(obj->DeleteHiddenValue(key));
2005   CHECK(obj->GetHiddenValue(key).IsEmpty());
2006 }
2007
2008
2009 THREADED_TEST(Regress97784) {
2010   // Regression test for crbug.com/97784
2011   // Messing with the Object.prototype should not have effect on
2012   // hidden properties.
2013   v8::HandleScope scope;
2014   LocalContext env;
2015
2016   v8::Local<v8::Object> obj = v8::Object::New();
2017   v8::Local<v8::String> key = v8_str("hidden");
2018
2019   CompileRun(
2020       "set_called = false;"
2021       "Object.defineProperty("
2022       "    Object.prototype,"
2023       "    'hidden',"
2024       "    {get: function() { return 45; },"
2025       "     set: function() { set_called = true; }})");
2026
2027   CHECK(obj->GetHiddenValue(key).IsEmpty());
2028   // Make sure that the getter and setter from Object.prototype is not invoked.
2029   // If it did we would have full access to the hidden properties in
2030   // the accessor.
2031   CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
2032   ExpectFalse("set_called");
2033   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2034 }
2035
2036
2037 static bool interceptor_for_hidden_properties_called;
2038 static v8::Handle<Value> InterceptorForHiddenProperties(
2039     Local<String> name, const AccessorInfo& info) {
2040   interceptor_for_hidden_properties_called = true;
2041   return v8::Handle<Value>();
2042 }
2043
2044
2045 THREADED_TEST(HiddenPropertiesWithInterceptors) {
2046   v8::HandleScope scope;
2047   LocalContext context;
2048
2049   interceptor_for_hidden_properties_called = false;
2050
2051   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2052
2053   // Associate an interceptor with an object and start setting hidden values.
2054   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
2055   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
2056   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
2057   Local<v8::Function> function = fun_templ->GetFunction();
2058   Local<v8::Object> obj = function->NewInstance();
2059   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
2060   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
2061   CHECK(!interceptor_for_hidden_properties_called);
2062 }
2063
2064
2065 THREADED_TEST(External) {
2066   v8::HandleScope scope;
2067   int x = 3;
2068   Local<v8::External> ext = v8::External::New(&x);
2069   LocalContext env;
2070   env->Global()->Set(v8_str("ext"), ext);
2071   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
2072   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2073   int* ptr = static_cast<int*>(reext->Value());
2074   CHECK_EQ(x, 3);
2075   *ptr = 10;
2076   CHECK_EQ(x, 10);
2077
2078   // Make sure unaligned pointers are wrapped properly.
2079   char* data = i::StrDup("0123456789");
2080   Local<v8::Value> zero = v8::External::Wrap(&data[0]);
2081   Local<v8::Value> one = v8::External::Wrap(&data[1]);
2082   Local<v8::Value> two = v8::External::Wrap(&data[2]);
2083   Local<v8::Value> three = v8::External::Wrap(&data[3]);
2084
2085   char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
2086   CHECK_EQ('0', *char_ptr);
2087   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
2088   CHECK_EQ('1', *char_ptr);
2089   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
2090   CHECK_EQ('2', *char_ptr);
2091   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
2092   CHECK_EQ('3', *char_ptr);
2093   i::DeleteArray(data);
2094 }
2095
2096
2097 THREADED_TEST(GlobalHandle) {
2098   v8::Persistent<String> global;
2099   {
2100     v8::HandleScope scope;
2101     Local<String> str = v8_str("str");
2102     global = v8::Persistent<String>::New(str);
2103   }
2104   CHECK_EQ(global->Length(), 3);
2105   global.Dispose();
2106 }
2107
2108
2109 class WeakCallCounter {
2110  public:
2111   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
2112   int id() { return id_; }
2113   void increment() { number_of_weak_calls_++; }
2114   int NumberOfWeakCalls() { return number_of_weak_calls_; }
2115  private:
2116   int id_;
2117   int number_of_weak_calls_;
2118 };
2119
2120
2121 static void WeakPointerCallback(Persistent<Value> handle, void* id) {
2122   WeakCallCounter* counter = reinterpret_cast<WeakCallCounter*>(id);
2123   CHECK_EQ(1234, counter->id());
2124   counter->increment();
2125   handle.Dispose();
2126 }
2127
2128
2129 THREADED_TEST(ApiObjectGroups) {
2130   HandleScope scope;
2131   LocalContext env;
2132
2133   Persistent<Object> g1s1;
2134   Persistent<Object> g1s2;
2135   Persistent<Object> g1c1;
2136   Persistent<Object> g2s1;
2137   Persistent<Object> g2s2;
2138   Persistent<Object> g2c1;
2139
2140   WeakCallCounter counter(1234);
2141
2142   {
2143     HandleScope scope;
2144     g1s1 = Persistent<Object>::New(Object::New());
2145     g1s2 = Persistent<Object>::New(Object::New());
2146     g1c1 = Persistent<Object>::New(Object::New());
2147     g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2148     g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2149     g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2150
2151     g2s1 = Persistent<Object>::New(Object::New());
2152     g2s2 = Persistent<Object>::New(Object::New());
2153     g2c1 = Persistent<Object>::New(Object::New());
2154     g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2155     g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2156     g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2157   }
2158
2159   Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
2160
2161   // Connect group 1 and 2, make a cycle.
2162   CHECK(g1s2->Set(0, g2s2));
2163   CHECK(g2s1->Set(0, g1s1));
2164
2165   {
2166     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2167     Persistent<Value> g1_children[] = { g1c1 };
2168     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2169     Persistent<Value> g2_children[] = { g2c1 };
2170     V8::AddObjectGroup(g1_objects, 2);
2171     V8::AddImplicitReferences(g1s1, g1_children, 1);
2172     V8::AddObjectGroup(g2_objects, 2);
2173     V8::AddImplicitReferences(g2s2, g2_children, 1);
2174   }
2175   // Do a single full GC. Use kMakeHeapIterableMask to ensure that
2176   // incremental garbage collection is stopped.
2177   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2178
2179   // All object should be alive.
2180   CHECK_EQ(0, counter.NumberOfWeakCalls());
2181
2182   // Weaken the root.
2183   root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2184   // But make children strong roots---all the objects (except for children)
2185   // should be collectable now.
2186   g1c1.ClearWeak();
2187   g2c1.ClearWeak();
2188
2189   // Groups are deleted, rebuild groups.
2190   {
2191     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2192     Persistent<Value> g1_children[] = { g1c1 };
2193     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2194     Persistent<Value> g2_children[] = { g2c1 };
2195     V8::AddObjectGroup(g1_objects, 2);
2196     V8::AddImplicitReferences(g1s1, g1_children, 1);
2197     V8::AddObjectGroup(g2_objects, 2);
2198     V8::AddImplicitReferences(g2s2, g2_children, 1);
2199   }
2200
2201   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2202
2203   // All objects should be gone. 5 global handles in total.
2204   CHECK_EQ(5, counter.NumberOfWeakCalls());
2205
2206   // And now make children weak again and collect them.
2207   g1c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2208   g2c1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2209
2210   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2211   CHECK_EQ(7, counter.NumberOfWeakCalls());
2212 }
2213
2214
2215 THREADED_TEST(ApiObjectGroupsCycle) {
2216   HandleScope scope;
2217   LocalContext env;
2218
2219   WeakCallCounter counter(1234);
2220
2221   Persistent<Object> g1s1;
2222   Persistent<Object> g1s2;
2223   Persistent<Object> g2s1;
2224   Persistent<Object> g2s2;
2225   Persistent<Object> g3s1;
2226   Persistent<Object> g3s2;
2227
2228   {
2229     HandleScope scope;
2230     g1s1 = Persistent<Object>::New(Object::New());
2231     g1s2 = Persistent<Object>::New(Object::New());
2232     g1s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2233     g1s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2234
2235     g2s1 = Persistent<Object>::New(Object::New());
2236     g2s2 = Persistent<Object>::New(Object::New());
2237     g2s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2238     g2s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2239
2240     g3s1 = Persistent<Object>::New(Object::New());
2241     g3s2 = Persistent<Object>::New(Object::New());
2242     g3s1.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2243     g3s2.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2244   }
2245
2246   Persistent<Object> root = Persistent<Object>::New(g1s1);  // make a root.
2247
2248   // Connect groups.  We're building the following cycle:
2249   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
2250   // groups.
2251   {
2252     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2253     Persistent<Value> g1_children[] = { g2s1 };
2254     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2255     Persistent<Value> g2_children[] = { g3s1 };
2256     Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2257     Persistent<Value> g3_children[] = { g1s1 };
2258     V8::AddObjectGroup(g1_objects, 2);
2259     V8::AddImplicitReferences(g1s1, g1_children, 1);
2260     V8::AddObjectGroup(g2_objects, 2);
2261     V8::AddImplicitReferences(g2s1, g2_children, 1);
2262     V8::AddObjectGroup(g3_objects, 2);
2263     V8::AddImplicitReferences(g3s1, g3_children, 1);
2264   }
2265   // Do a single full GC
2266   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2267
2268   // All object should be alive.
2269   CHECK_EQ(0, counter.NumberOfWeakCalls());
2270
2271   // Weaken the root.
2272   root.MakeWeak(reinterpret_cast<void*>(&counter), &WeakPointerCallback);
2273
2274   // Groups are deleted, rebuild groups.
2275   {
2276     Persistent<Value> g1_objects[] = { g1s1, g1s2 };
2277     Persistent<Value> g1_children[] = { g2s1 };
2278     Persistent<Value> g2_objects[] = { g2s1, g2s2 };
2279     Persistent<Value> g2_children[] = { g3s1 };
2280     Persistent<Value> g3_objects[] = { g3s1, g3s2 };
2281     Persistent<Value> g3_children[] = { g1s1 };
2282     V8::AddObjectGroup(g1_objects, 2);
2283     V8::AddImplicitReferences(g1s1, g1_children, 1);
2284     V8::AddObjectGroup(g2_objects, 2);
2285     V8::AddImplicitReferences(g2s1, g2_children, 1);
2286     V8::AddObjectGroup(g3_objects, 2);
2287     V8::AddImplicitReferences(g3s1, g3_children, 1);
2288   }
2289
2290   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
2291
2292   // All objects should be gone. 7 global handles in total.
2293   CHECK_EQ(7, counter.NumberOfWeakCalls());
2294 }
2295
2296
2297 THREADED_TEST(ScriptException) {
2298   v8::HandleScope scope;
2299   LocalContext env;
2300   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
2301   v8::TryCatch try_catch;
2302   Local<Value> result = script->Run();
2303   CHECK(result.IsEmpty());
2304   CHECK(try_catch.HasCaught());
2305   String::AsciiValue exception_value(try_catch.Exception());
2306   CHECK_EQ(*exception_value, "panama!");
2307 }
2308
2309
2310 bool message_received;
2311
2312
2313 static void check_message(v8::Handle<v8::Message> message,
2314                           v8::Handle<Value> data) {
2315   CHECK_EQ(5.76, data->NumberValue());
2316   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
2317   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
2318   message_received = true;
2319 }
2320
2321
2322 THREADED_TEST(MessageHandlerData) {
2323   message_received = false;
2324   v8::HandleScope scope;
2325   CHECK(!message_received);
2326   v8::V8::AddMessageListener(check_message, v8_num(5.76));
2327   LocalContext context;
2328   v8::ScriptOrigin origin =
2329       v8::ScriptOrigin(v8_str("6.75"));
2330   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
2331                                                   &origin);
2332   script->SetData(v8_str("7.56"));
2333   script->Run();
2334   CHECK(message_received);
2335   // clear out the message listener
2336   v8::V8::RemoveMessageListeners(check_message);
2337 }
2338
2339
2340 THREADED_TEST(GetSetProperty) {
2341   v8::HandleScope scope;
2342   LocalContext context;
2343   context->Global()->Set(v8_str("foo"), v8_num(14));
2344   context->Global()->Set(v8_str("12"), v8_num(92));
2345   context->Global()->Set(v8::Integer::New(16), v8_num(32));
2346   context->Global()->Set(v8_num(13), v8_num(56));
2347   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
2348   CHECK_EQ(14, foo->Int32Value());
2349   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
2350   CHECK_EQ(92, twelve->Int32Value());
2351   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
2352   CHECK_EQ(32, sixteen->Int32Value());
2353   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
2354   CHECK_EQ(56, thirteen->Int32Value());
2355   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
2356   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
2357   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
2358   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
2359   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
2360   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
2361   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
2362   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
2363   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
2364 }
2365
2366
2367 THREADED_TEST(PropertyAttributes) {
2368   v8::HandleScope scope;
2369   LocalContext context;
2370   // none
2371   Local<String> prop = v8_str("none");
2372   context->Global()->Set(prop, v8_num(7));
2373   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2374   // read-only
2375   prop = v8_str("read_only");
2376   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
2377   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2378   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
2379   Script::Compile(v8_str("read_only = 9"))->Run();
2380   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2381   context->Global()->Set(prop, v8_num(10));
2382   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
2383   // dont-delete
2384   prop = v8_str("dont_delete");
2385   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
2386   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2387   Script::Compile(v8_str("delete dont_delete"))->Run();
2388   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
2389   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
2390   // dont-enum
2391   prop = v8_str("dont_enum");
2392   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
2393   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
2394   // absent
2395   prop = v8_str("absent");
2396   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
2397   Local<Value> fake_prop = v8_num(1);
2398   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
2399   // exception
2400   TryCatch try_catch;
2401   Local<Value> exception =
2402       CompileRun("({ toString: function() { throw 'exception';} })");
2403   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
2404   CHECK(try_catch.HasCaught());
2405   String::AsciiValue exception_value(try_catch.Exception());
2406   CHECK_EQ("exception", *exception_value);
2407   try_catch.Reset();
2408 }
2409
2410
2411 THREADED_TEST(Array) {
2412   v8::HandleScope scope;
2413   LocalContext context;
2414   Local<v8::Array> array = v8::Array::New();
2415   CHECK_EQ(0, array->Length());
2416   CHECK(array->Get(0)->IsUndefined());
2417   CHECK(!array->Has(0));
2418   CHECK(array->Get(100)->IsUndefined());
2419   CHECK(!array->Has(100));
2420   array->Set(2, v8_num(7));
2421   CHECK_EQ(3, array->Length());
2422   CHECK(!array->Has(0));
2423   CHECK(!array->Has(1));
2424   CHECK(array->Has(2));
2425   CHECK_EQ(7, array->Get(2)->Int32Value());
2426   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
2427   Local<v8::Array> arr = obj.As<v8::Array>();
2428   CHECK_EQ(3, arr->Length());
2429   CHECK_EQ(1, arr->Get(0)->Int32Value());
2430   CHECK_EQ(2, arr->Get(1)->Int32Value());
2431   CHECK_EQ(3, arr->Get(2)->Int32Value());
2432   array = v8::Array::New(27);
2433   CHECK_EQ(27, array->Length());
2434   array = v8::Array::New(-27);
2435   CHECK_EQ(0, array->Length());
2436 }
2437
2438
2439 v8::Handle<Value> HandleF(const v8::Arguments& args) {
2440   v8::HandleScope scope;
2441   ApiTestFuzzer::Fuzz();
2442   Local<v8::Array> result = v8::Array::New(args.Length());
2443   for (int i = 0; i < args.Length(); i++)
2444     result->Set(i, args[i]);
2445   return scope.Close(result);
2446 }
2447
2448
2449 THREADED_TEST(Vector) {
2450   v8::HandleScope scope;
2451   Local<ObjectTemplate> global = ObjectTemplate::New();
2452   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
2453   LocalContext context(0, global);
2454
2455   const char* fun = "f()";
2456   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
2457   CHECK_EQ(0, a0->Length());
2458
2459   const char* fun2 = "f(11)";
2460   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
2461   CHECK_EQ(1, a1->Length());
2462   CHECK_EQ(11, a1->Get(0)->Int32Value());
2463
2464   const char* fun3 = "f(12, 13)";
2465   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
2466   CHECK_EQ(2, a2->Length());
2467   CHECK_EQ(12, a2->Get(0)->Int32Value());
2468   CHECK_EQ(13, a2->Get(1)->Int32Value());
2469
2470   const char* fun4 = "f(14, 15, 16)";
2471   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
2472   CHECK_EQ(3, a3->Length());
2473   CHECK_EQ(14, a3->Get(0)->Int32Value());
2474   CHECK_EQ(15, a3->Get(1)->Int32Value());
2475   CHECK_EQ(16, a3->Get(2)->Int32Value());
2476
2477   const char* fun5 = "f(17, 18, 19, 20)";
2478   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
2479   CHECK_EQ(4, a4->Length());
2480   CHECK_EQ(17, a4->Get(0)->Int32Value());
2481   CHECK_EQ(18, a4->Get(1)->Int32Value());
2482   CHECK_EQ(19, a4->Get(2)->Int32Value());
2483   CHECK_EQ(20, a4->Get(3)->Int32Value());
2484 }
2485
2486
2487 THREADED_TEST(FunctionCall) {
2488   v8::HandleScope scope;
2489   LocalContext context;
2490   CompileRun(
2491     "function Foo() {"
2492     "  var result = [];"
2493     "  for (var i = 0; i < arguments.length; i++) {"
2494     "    result.push(arguments[i]);"
2495     "  }"
2496     "  return result;"
2497     "}");
2498   Local<Function> Foo =
2499       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2500
2501   v8::Handle<Value>* args0 = NULL;
2502   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
2503   CHECK_EQ(0, a0->Length());
2504
2505   v8::Handle<Value> args1[] = { v8_num(1.1) };
2506   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
2507   CHECK_EQ(1, a1->Length());
2508   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2509
2510   v8::Handle<Value> args2[] = { v8_num(2.2),
2511                                 v8_num(3.3) };
2512   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
2513   CHECK_EQ(2, a2->Length());
2514   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2515   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2516
2517   v8::Handle<Value> args3[] = { v8_num(4.4),
2518                                 v8_num(5.5),
2519                                 v8_num(6.6) };
2520   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
2521   CHECK_EQ(3, a3->Length());
2522   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2523   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2524   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2525
2526   v8::Handle<Value> args4[] = { v8_num(7.7),
2527                                 v8_num(8.8),
2528                                 v8_num(9.9),
2529                                 v8_num(10.11) };
2530   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
2531   CHECK_EQ(4, a4->Length());
2532   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2533   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2534   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2535   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2536 }
2537
2538
2539 static const char* js_code_causing_out_of_memory =
2540     "var a = new Array(); while(true) a.push(a);";
2541
2542
2543 // These tests run for a long time and prevent us from running tests
2544 // that come after them so they cannot run in parallel.
2545 TEST(OutOfMemory) {
2546   // It's not possible to read a snapshot into a heap with different dimensions.
2547   if (i::Snapshot::IsEnabled()) return;
2548   // Set heap limits.
2549   static const int K = 1024;
2550   v8::ResourceConstraints constraints;
2551   constraints.set_max_young_space_size(256 * K);
2552   constraints.set_max_old_space_size(4 * K * K);
2553   v8::SetResourceConstraints(&constraints);
2554
2555   // Execute a script that causes out of memory.
2556   v8::HandleScope scope;
2557   LocalContext context;
2558   v8::V8::IgnoreOutOfMemoryException();
2559   Local<Script> script =
2560       Script::Compile(String::New(js_code_causing_out_of_memory));
2561   Local<Value> result = script->Run();
2562
2563   // Check for out of memory state.
2564   CHECK(result.IsEmpty());
2565   CHECK(context->HasOutOfMemoryException());
2566 }
2567
2568
2569 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
2570   ApiTestFuzzer::Fuzz();
2571
2572   v8::HandleScope scope;
2573   LocalContext context;
2574   Local<Script> script =
2575       Script::Compile(String::New(js_code_causing_out_of_memory));
2576   Local<Value> result = script->Run();
2577
2578   // Check for out of memory state.
2579   CHECK(result.IsEmpty());
2580   CHECK(context->HasOutOfMemoryException());
2581
2582   return result;
2583 }
2584
2585
2586 TEST(OutOfMemoryNested) {
2587   // It's not possible to read a snapshot into a heap with different dimensions.
2588   if (i::Snapshot::IsEnabled()) return;
2589   // Set heap limits.
2590   static const int K = 1024;
2591   v8::ResourceConstraints constraints;
2592   constraints.set_max_young_space_size(256 * K);
2593   constraints.set_max_old_space_size(4 * K * K);
2594   v8::SetResourceConstraints(&constraints);
2595
2596   v8::HandleScope scope;
2597   Local<ObjectTemplate> templ = ObjectTemplate::New();
2598   templ->Set(v8_str("ProvokeOutOfMemory"),
2599              v8::FunctionTemplate::New(ProvokeOutOfMemory));
2600   LocalContext context(0, templ);
2601   v8::V8::IgnoreOutOfMemoryException();
2602   Local<Value> result = CompileRun(
2603     "var thrown = false;"
2604     "try {"
2605     "  ProvokeOutOfMemory();"
2606     "} catch (e) {"
2607     "  thrown = true;"
2608     "}");
2609   // Check for out of memory state.
2610   CHECK(result.IsEmpty());
2611   CHECK(context->HasOutOfMemoryException());
2612 }
2613
2614
2615 TEST(HugeConsStringOutOfMemory) {
2616   // It's not possible to read a snapshot into a heap with different dimensions.
2617   if (i::Snapshot::IsEnabled()) return;
2618   // Set heap limits.
2619   static const int K = 1024;
2620   v8::ResourceConstraints constraints;
2621   constraints.set_max_young_space_size(256 * K);
2622   constraints.set_max_old_space_size(2 * K * K);
2623   v8::SetResourceConstraints(&constraints);
2624
2625   // Execute a script that causes out of memory.
2626   v8::V8::IgnoreOutOfMemoryException();
2627
2628   v8::HandleScope scope;
2629   LocalContext context;
2630
2631   // Build huge string. This should fail with out of memory exception.
2632   Local<Value> result = CompileRun(
2633     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
2634     "for (var i = 0; i < 22; i++) { str = str + str; }");
2635
2636   // Check for out of memory state.
2637   CHECK(result.IsEmpty());
2638   CHECK(context->HasOutOfMemoryException());
2639 }
2640
2641
2642 THREADED_TEST(ConstructCall) {
2643   v8::HandleScope scope;
2644   LocalContext context;
2645   CompileRun(
2646     "function Foo() {"
2647     "  var result = [];"
2648     "  for (var i = 0; i < arguments.length; i++) {"
2649     "    result.push(arguments[i]);"
2650     "  }"
2651     "  return result;"
2652     "}");
2653   Local<Function> Foo =
2654       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
2655
2656   v8::Handle<Value>* args0 = NULL;
2657   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
2658   CHECK_EQ(0, a0->Length());
2659
2660   v8::Handle<Value> args1[] = { v8_num(1.1) };
2661   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
2662   CHECK_EQ(1, a1->Length());
2663   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
2664
2665   v8::Handle<Value> args2[] = { v8_num(2.2),
2666                                 v8_num(3.3) };
2667   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
2668   CHECK_EQ(2, a2->Length());
2669   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
2670   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
2671
2672   v8::Handle<Value> args3[] = { v8_num(4.4),
2673                                 v8_num(5.5),
2674                                 v8_num(6.6) };
2675   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
2676   CHECK_EQ(3, a3->Length());
2677   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
2678   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
2679   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
2680
2681   v8::Handle<Value> args4[] = { v8_num(7.7),
2682                                 v8_num(8.8),
2683                                 v8_num(9.9),
2684                                 v8_num(10.11) };
2685   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
2686   CHECK_EQ(4, a4->Length());
2687   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
2688   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
2689   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
2690   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
2691 }
2692
2693
2694 static void CheckUncle(v8::TryCatch* try_catch) {
2695   CHECK(try_catch->HasCaught());
2696   String::AsciiValue str_value(try_catch->Exception());
2697   CHECK_EQ(*str_value, "uncle?");
2698   try_catch->Reset();
2699 }
2700
2701
2702 THREADED_TEST(ConversionNumber) {
2703   v8::HandleScope scope;
2704   LocalContext env;
2705   // Very large number.
2706   CompileRun("var obj = Math.pow(2,32) * 1237;");
2707   Local<Value> obj = env->Global()->Get(v8_str("obj"));
2708   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
2709   CHECK_EQ(0, obj->ToInt32()->Value());
2710   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
2711   // Large number.
2712   CompileRun("var obj = -1234567890123;");
2713   obj = env->Global()->Get(v8_str("obj"));
2714   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
2715   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
2716   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
2717   // Small positive integer.
2718   CompileRun("var obj = 42;");
2719   obj = env->Global()->Get(v8_str("obj"));
2720   CHECK_EQ(42.0, obj->ToNumber()->Value());
2721   CHECK_EQ(42, obj->ToInt32()->Value());
2722   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2723   // Negative integer.
2724   CompileRun("var obj = -37;");
2725   obj = env->Global()->Get(v8_str("obj"));
2726   CHECK_EQ(-37.0, obj->ToNumber()->Value());
2727   CHECK_EQ(-37, obj->ToInt32()->Value());
2728   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
2729   // Positive non-int32 integer.
2730   CompileRun("var obj = 0x81234567;");
2731   obj = env->Global()->Get(v8_str("obj"));
2732   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
2733   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
2734   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
2735   // Fraction.
2736   CompileRun("var obj = 42.3;");
2737   obj = env->Global()->Get(v8_str("obj"));
2738   CHECK_EQ(42.3, obj->ToNumber()->Value());
2739   CHECK_EQ(42, obj->ToInt32()->Value());
2740   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
2741   // Large negative fraction.
2742   CompileRun("var obj = -5726623061.75;");
2743   obj = env->Global()->Get(v8_str("obj"));
2744   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
2745   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
2746   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
2747 }
2748
2749
2750 THREADED_TEST(isNumberType) {
2751   v8::HandleScope scope;
2752   LocalContext env;
2753   // Very large number.
2754   CompileRun("var obj = Math.pow(2,32) * 1237;");
2755   Local<Value> obj = env->Global()->Get(v8_str("obj"));
2756   CHECK(!obj->IsInt32());
2757   CHECK(!obj->IsUint32());
2758   // Large negative number.
2759   CompileRun("var obj = -1234567890123;");
2760   obj = env->Global()->Get(v8_str("obj"));
2761   CHECK(!obj->IsInt32());
2762   CHECK(!obj->IsUint32());
2763   // Small positive integer.
2764   CompileRun("var obj = 42;");
2765   obj = env->Global()->Get(v8_str("obj"));
2766   CHECK(obj->IsInt32());
2767   CHECK(obj->IsUint32());
2768   // Negative integer.
2769   CompileRun("var obj = -37;");
2770   obj = env->Global()->Get(v8_str("obj"));
2771   CHECK(obj->IsInt32());
2772   CHECK(!obj->IsUint32());
2773   // Positive non-int32 integer.
2774   CompileRun("var obj = 0x81234567;");
2775   obj = env->Global()->Get(v8_str("obj"));
2776   CHECK(!obj->IsInt32());
2777   CHECK(obj->IsUint32());
2778   // Fraction.
2779   CompileRun("var obj = 42.3;");
2780   obj = env->Global()->Get(v8_str("obj"));
2781   CHECK(!obj->IsInt32());
2782   CHECK(!obj->IsUint32());
2783   // Large negative fraction.
2784   CompileRun("var obj = -5726623061.75;");
2785   obj = env->Global()->Get(v8_str("obj"));
2786   CHECK(!obj->IsInt32());
2787   CHECK(!obj->IsUint32());
2788 }
2789
2790
2791 THREADED_TEST(ConversionException) {
2792   v8::HandleScope scope;
2793   LocalContext env;
2794   CompileRun(
2795     "function TestClass() { };"
2796     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
2797     "var obj = new TestClass();");
2798   Local<Value> obj = env->Global()->Get(v8_str("obj"));
2799
2800   v8::TryCatch try_catch;
2801
2802   Local<Value> to_string_result = obj->ToString();
2803   CHECK(to_string_result.IsEmpty());
2804   CheckUncle(&try_catch);
2805
2806   Local<Value> to_number_result = obj->ToNumber();
2807   CHECK(to_number_result.IsEmpty());
2808   CheckUncle(&try_catch);
2809
2810   Local<Value> to_integer_result = obj->ToInteger();
2811   CHECK(to_integer_result.IsEmpty());
2812   CheckUncle(&try_catch);
2813
2814   Local<Value> to_uint32_result = obj->ToUint32();
2815   CHECK(to_uint32_result.IsEmpty());
2816   CheckUncle(&try_catch);
2817
2818   Local<Value> to_int32_result = obj->ToInt32();
2819   CHECK(to_int32_result.IsEmpty());
2820   CheckUncle(&try_catch);
2821
2822   Local<Value> to_object_result = v8::Undefined()->ToObject();
2823   CHECK(to_object_result.IsEmpty());
2824   CHECK(try_catch.HasCaught());
2825   try_catch.Reset();
2826
2827   int32_t int32_value = obj->Int32Value();
2828   CHECK_EQ(0, int32_value);
2829   CheckUncle(&try_catch);
2830
2831   uint32_t uint32_value = obj->Uint32Value();
2832   CHECK_EQ(0, uint32_value);
2833   CheckUncle(&try_catch);
2834
2835   double number_value = obj->NumberValue();
2836   CHECK_NE(0, IsNaN(number_value));
2837   CheckUncle(&try_catch);
2838
2839   int64_t integer_value = obj->IntegerValue();
2840   CHECK_EQ(0.0, static_cast<double>(integer_value));
2841   CheckUncle(&try_catch);
2842 }
2843
2844
2845 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
2846   ApiTestFuzzer::Fuzz();
2847   return v8::ThrowException(v8_str("konto"));
2848 }
2849
2850
2851 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
2852   if (args.Length() < 1) return v8::False();
2853   v8::HandleScope scope;
2854   v8::TryCatch try_catch;
2855   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2856   CHECK(!try_catch.HasCaught() || result.IsEmpty());
2857   return v8::Boolean::New(try_catch.HasCaught());
2858 }
2859
2860
2861 THREADED_TEST(APICatch) {
2862   v8::HandleScope scope;
2863   Local<ObjectTemplate> templ = ObjectTemplate::New();
2864   templ->Set(v8_str("ThrowFromC"),
2865              v8::FunctionTemplate::New(ThrowFromC));
2866   LocalContext context(0, templ);
2867   CompileRun(
2868     "var thrown = false;"
2869     "try {"
2870     "  ThrowFromC();"
2871     "} catch (e) {"
2872     "  thrown = true;"
2873     "}");
2874   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2875   CHECK(thrown->BooleanValue());
2876 }
2877
2878
2879 THREADED_TEST(APIThrowTryCatch) {
2880   v8::HandleScope scope;
2881   Local<ObjectTemplate> templ = ObjectTemplate::New();
2882   templ->Set(v8_str("ThrowFromC"),
2883              v8::FunctionTemplate::New(ThrowFromC));
2884   LocalContext context(0, templ);
2885   v8::TryCatch try_catch;
2886   CompileRun("ThrowFromC();");
2887   CHECK(try_catch.HasCaught());
2888 }
2889
2890
2891 // Test that a try-finally block doesn't shadow a try-catch block
2892 // when setting up an external handler.
2893 //
2894 // BUG(271): Some of the exception propagation does not work on the
2895 // ARM simulator because the simulator separates the C++ stack and the
2896 // JS stack.  This test therefore fails on the simulator.  The test is
2897 // not threaded to allow the threading tests to run on the simulator.
2898 TEST(TryCatchInTryFinally) {
2899   v8::HandleScope scope;
2900   Local<ObjectTemplate> templ = ObjectTemplate::New();
2901   templ->Set(v8_str("CCatcher"),
2902              v8::FunctionTemplate::New(CCatcher));
2903   LocalContext context(0, templ);
2904   Local<Value> result = CompileRun("try {"
2905                                    "  try {"
2906                                    "    CCatcher('throw 7;');"
2907                                    "  } finally {"
2908                                    "  }"
2909                                    "} catch (e) {"
2910                                    "}");
2911   CHECK(result->IsTrue());
2912 }
2913
2914
2915 static void check_reference_error_message(
2916     v8::Handle<v8::Message> message,
2917     v8::Handle<v8::Value> data) {
2918   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
2919   CHECK(message->Get()->Equals(v8_str(reference_error)));
2920 }
2921
2922
2923 static v8::Handle<Value> Fail(const v8::Arguments& args) {
2924   ApiTestFuzzer::Fuzz();
2925   CHECK(false);
2926   return v8::Undefined();
2927 }
2928
2929
2930 // Test that overwritten methods are not invoked on uncaught exception
2931 // formatting. However, they are invoked when performing normal error
2932 // string conversions.
2933 TEST(APIThrowMessageOverwrittenToString) {
2934   v8::HandleScope scope;
2935   v8::V8::AddMessageListener(check_reference_error_message);
2936   Local<ObjectTemplate> templ = ObjectTemplate::New();
2937   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
2938   LocalContext context(NULL, templ);
2939   CompileRun("asdf;");
2940   CompileRun("var limit = {};"
2941              "limit.valueOf = fail;"
2942              "Error.stackTraceLimit = limit;");
2943   CompileRun("asdf");
2944   CompileRun("Array.prototype.pop = fail;");
2945   CompileRun("Object.prototype.hasOwnProperty = fail;");
2946   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
2947   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
2948   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
2949   CompileRun("ReferenceError.prototype.toString ="
2950              "  function() { return 'Whoops' }");
2951   CompileRun("asdf;");
2952   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
2953   CompileRun("asdf;");
2954   CompileRun("ReferenceError.prototype.constructor = void 0;");
2955   CompileRun("asdf;");
2956   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
2957   CompileRun("asdf;");
2958   CompileRun("ReferenceError.prototype = new Object();");
2959   CompileRun("asdf;");
2960   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
2961   CHECK(string->Equals(v8_str("Whoops")));
2962   CompileRun("ReferenceError.prototype.constructor = new Object();"
2963              "ReferenceError.prototype.constructor.name = 1;"
2964              "Number.prototype.toString = function() { return 'Whoops'; };"
2965              "ReferenceError.prototype.toString = Object.prototype.toString;");
2966   CompileRun("asdf;");
2967   v8::V8::RemoveMessageListeners(check_message);
2968 }
2969
2970
2971 static void receive_message(v8::Handle<v8::Message> message,
2972                             v8::Handle<v8::Value> data) {
2973   message->Get();
2974   message_received = true;
2975 }
2976
2977
2978 TEST(APIThrowMessage) {
2979   message_received = false;
2980   v8::HandleScope scope;
2981   v8::V8::AddMessageListener(receive_message);
2982   Local<ObjectTemplate> templ = ObjectTemplate::New();
2983   templ->Set(v8_str("ThrowFromC"),
2984              v8::FunctionTemplate::New(ThrowFromC));
2985   LocalContext context(0, templ);
2986   CompileRun("ThrowFromC();");
2987   CHECK(message_received);
2988   v8::V8::RemoveMessageListeners(check_message);
2989 }
2990
2991
2992 TEST(APIThrowMessageAndVerboseTryCatch) {
2993   message_received = false;
2994   v8::HandleScope scope;
2995   v8::V8::AddMessageListener(receive_message);
2996   Local<ObjectTemplate> templ = ObjectTemplate::New();
2997   templ->Set(v8_str("ThrowFromC"),
2998              v8::FunctionTemplate::New(ThrowFromC));
2999   LocalContext context(0, templ);
3000   v8::TryCatch try_catch;
3001   try_catch.SetVerbose(true);
3002   Local<Value> result = CompileRun("ThrowFromC();");
3003   CHECK(try_catch.HasCaught());
3004   CHECK(result.IsEmpty());
3005   CHECK(message_received);
3006   v8::V8::RemoveMessageListeners(check_message);
3007 }
3008
3009
3010 TEST(APIStackOverflowAndVerboseTryCatch) {
3011   message_received = false;
3012   v8::HandleScope scope;
3013   v8::V8::AddMessageListener(receive_message);
3014   LocalContext context;
3015   v8::TryCatch try_catch;
3016   try_catch.SetVerbose(true);
3017   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
3018   CHECK(try_catch.HasCaught());
3019   CHECK(result.IsEmpty());
3020   CHECK(message_received);
3021   v8::V8::RemoveMessageListeners(receive_message);
3022 }
3023
3024
3025 THREADED_TEST(ExternalScriptException) {
3026   v8::HandleScope scope;
3027   Local<ObjectTemplate> templ = ObjectTemplate::New();
3028   templ->Set(v8_str("ThrowFromC"),
3029              v8::FunctionTemplate::New(ThrowFromC));
3030   LocalContext context(0, templ);
3031
3032   v8::TryCatch try_catch;
3033   Local<Script> script
3034       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
3035   Local<Value> result = script->Run();
3036   CHECK(result.IsEmpty());
3037   CHECK(try_catch.HasCaught());
3038   String::AsciiValue exception_value(try_catch.Exception());
3039   CHECK_EQ("konto", *exception_value);
3040 }
3041
3042
3043
3044 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
3045   ApiTestFuzzer::Fuzz();
3046   CHECK_EQ(4, args.Length());
3047   int count = args[0]->Int32Value();
3048   int cInterval = args[2]->Int32Value();
3049   if (count == 0) {
3050     return v8::ThrowException(v8_str("FromC"));
3051   } else {
3052     Local<v8::Object> global = Context::GetCurrent()->Global();
3053     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
3054     v8::Handle<Value> argv[] = { v8_num(count - 1),
3055                                  args[1],
3056                                  args[2],
3057                                  args[3] };
3058     if (count % cInterval == 0) {
3059       v8::TryCatch try_catch;
3060       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
3061       int expected = args[3]->Int32Value();
3062       if (try_catch.HasCaught()) {
3063         CHECK_EQ(expected, count);
3064         CHECK(result.IsEmpty());
3065         CHECK(!i::Isolate::Current()->has_scheduled_exception());
3066       } else {
3067         CHECK_NE(expected, count);
3068       }
3069       return result;
3070     } else {
3071       return fun.As<Function>()->Call(global, 4, argv);
3072     }
3073   }
3074 }
3075
3076
3077 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
3078   ApiTestFuzzer::Fuzz();
3079   CHECK_EQ(3, args.Length());
3080   bool equality = args[0]->BooleanValue();
3081   int count = args[1]->Int32Value();
3082   int expected = args[2]->Int32Value();
3083   if (equality) {
3084     CHECK_EQ(count, expected);
3085   } else {
3086     CHECK_NE(count, expected);
3087   }
3088   return v8::Undefined();
3089 }
3090
3091
3092 THREADED_TEST(EvalInTryFinally) {
3093   v8::HandleScope scope;
3094   LocalContext context;
3095   v8::TryCatch try_catch;
3096   CompileRun("(function() {"
3097              "  try {"
3098              "    eval('asldkf (*&^&*^');"
3099              "  } finally {"
3100              "    return;"
3101              "  }"
3102              "})()");
3103   CHECK(!try_catch.HasCaught());
3104 }
3105
3106
3107 // This test works by making a stack of alternating JavaScript and C
3108 // activations.  These activations set up exception handlers with regular
3109 // intervals, one interval for C activations and another for JavaScript
3110 // activations.  When enough activations have been created an exception is
3111 // thrown and we check that the right activation catches the exception and that
3112 // no other activations do.  The right activation is always the topmost one with
3113 // a handler, regardless of whether it is in JavaScript or C.
3114 //
3115 // The notation used to describe a test case looks like this:
3116 //
3117 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
3118 //
3119 // Each entry is an activation, either JS or C.  The index is the count at that
3120 // level.  Stars identify activations with exception handlers, the @ identifies
3121 // the exception handler that should catch the exception.
3122 //
3123 // BUG(271): Some of the exception propagation does not work on the
3124 // ARM simulator because the simulator separates the C++ stack and the
3125 // JS stack.  This test therefore fails on the simulator.  The test is
3126 // not threaded to allow the threading tests to run on the simulator.
3127 TEST(ExceptionOrder) {
3128   v8::HandleScope scope;
3129   Local<ObjectTemplate> templ = ObjectTemplate::New();
3130   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
3131   templ->Set(v8_str("CThrowCountDown"),
3132              v8::FunctionTemplate::New(CThrowCountDown));
3133   LocalContext context(0, templ);
3134   CompileRun(
3135     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
3136     "  if (count == 0) throw 'FromJS';"
3137     "  if (count % jsInterval == 0) {"
3138     "    try {"
3139     "      var value = CThrowCountDown(count - 1,"
3140     "                                  jsInterval,"
3141     "                                  cInterval,"
3142     "                                  expected);"
3143     "      check(false, count, expected);"
3144     "      return value;"
3145     "    } catch (e) {"
3146     "      check(true, count, expected);"
3147     "    }"
3148     "  } else {"
3149     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
3150     "  }"
3151     "}");
3152   Local<Function> fun =
3153       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
3154
3155   const int argc = 4;
3156   //                             count      jsInterval cInterval  expected
3157
3158   // *JS[4] *C[3] @JS[2] C[1] JS[0]
3159   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
3160   fun->Call(fun, argc, a0);
3161
3162   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
3163   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
3164   fun->Call(fun, argc, a1);
3165
3166   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
3167   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
3168   fun->Call(fun, argc, a2);
3169
3170   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
3171   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
3172   fun->Call(fun, argc, a3);
3173
3174   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
3175   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
3176   fun->Call(fun, argc, a4);
3177
3178   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
3179   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
3180   fun->Call(fun, argc, a5);
3181 }
3182
3183
3184 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
3185   ApiTestFuzzer::Fuzz();
3186   CHECK_EQ(1, args.Length());
3187   return v8::ThrowException(args[0]);
3188 }
3189
3190
3191 THREADED_TEST(ThrowValues) {
3192   v8::HandleScope scope;
3193   Local<ObjectTemplate> templ = ObjectTemplate::New();
3194   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
3195   LocalContext context(0, templ);
3196   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3197     "function Run(obj) {"
3198     "  try {"
3199     "    Throw(obj);"
3200     "  } catch (e) {"
3201     "    return e;"
3202     "  }"
3203     "  return 'no exception';"
3204     "}"
3205     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
3206   CHECK_EQ(5, result->Length());
3207   CHECK(result->Get(v8::Integer::New(0))->IsString());
3208   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
3209   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
3210   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
3211   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
3212   CHECK(result->Get(v8::Integer::New(3))->IsNull());
3213   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
3214 }
3215
3216
3217 THREADED_TEST(CatchZero) {
3218   v8::HandleScope scope;
3219   LocalContext context;
3220   v8::TryCatch try_catch;
3221   CHECK(!try_catch.HasCaught());
3222   Script::Compile(v8_str("throw 10"))->Run();
3223   CHECK(try_catch.HasCaught());
3224   CHECK_EQ(10, try_catch.Exception()->Int32Value());
3225   try_catch.Reset();
3226   CHECK(!try_catch.HasCaught());
3227   Script::Compile(v8_str("throw 0"))->Run();
3228   CHECK(try_catch.HasCaught());
3229   CHECK_EQ(0, try_catch.Exception()->Int32Value());
3230 }
3231
3232
3233 THREADED_TEST(CatchExceptionFromWith) {
3234   v8::HandleScope scope;
3235   LocalContext context;
3236   v8::TryCatch try_catch;
3237   CHECK(!try_catch.HasCaught());
3238   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
3239   CHECK(try_catch.HasCaught());
3240 }
3241
3242
3243 THREADED_TEST(TryCatchAndFinallyHidingException) {
3244   v8::HandleScope scope;
3245   LocalContext context;
3246   v8::TryCatch try_catch;
3247   CHECK(!try_catch.HasCaught());
3248   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
3249   CompileRun("f({toString: function() { throw 42; }});");
3250   CHECK(!try_catch.HasCaught());
3251 }
3252
3253
3254 v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) {
3255   v8::TryCatch try_catch;
3256   return v8::Undefined();
3257 }
3258
3259
3260 THREADED_TEST(TryCatchAndFinally) {
3261   v8::HandleScope scope;
3262   LocalContext context;
3263   context->Global()->Set(
3264       v8_str("native_with_try_catch"),
3265       v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
3266   v8::TryCatch try_catch;
3267   CHECK(!try_catch.HasCaught());
3268   CompileRun(
3269       "try {\n"
3270       "  throw new Error('a');\n"
3271       "} finally {\n"
3272       "  native_with_try_catch();\n"
3273       "}\n");
3274   CHECK(try_catch.HasCaught());
3275 }
3276
3277
3278 THREADED_TEST(Equality) {
3279   v8::HandleScope scope;
3280   LocalContext context;
3281   // Check that equality works at all before relying on CHECK_EQ
3282   CHECK(v8_str("a")->Equals(v8_str("a")));
3283   CHECK(!v8_str("a")->Equals(v8_str("b")));
3284
3285   CHECK_EQ(v8_str("a"), v8_str("a"));
3286   CHECK_NE(v8_str("a"), v8_str("b"));
3287   CHECK_EQ(v8_num(1), v8_num(1));
3288   CHECK_EQ(v8_num(1.00), v8_num(1));
3289   CHECK_NE(v8_num(1), v8_num(2));
3290
3291   // Assume String is not symbol.
3292   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
3293   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
3294   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
3295   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
3296   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
3297   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
3298   Local<Value> not_a_number = v8_num(i::OS::nan_value());
3299   CHECK(!not_a_number->StrictEquals(not_a_number));
3300   CHECK(v8::False()->StrictEquals(v8::False()));
3301   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
3302
3303   v8::Handle<v8::Object> obj = v8::Object::New();
3304   v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
3305   CHECK(alias->StrictEquals(obj));
3306   alias.Dispose();
3307 }
3308
3309
3310 THREADED_TEST(MultiRun) {
3311   v8::HandleScope scope;
3312   LocalContext context;
3313   Local<Script> script = Script::Compile(v8_str("x"));
3314   for (int i = 0; i < 10; i++)
3315     script->Run();
3316 }
3317
3318
3319 static v8::Handle<Value> GetXValue(Local<String> name,
3320                                    const AccessorInfo& info) {
3321   ApiTestFuzzer::Fuzz();
3322   CHECK_EQ(info.Data(), v8_str("donut"));
3323   CHECK_EQ(name, v8_str("x"));
3324   return name;
3325 }
3326
3327
3328 THREADED_TEST(SimplePropertyRead) {
3329   v8::HandleScope scope;
3330   Local<ObjectTemplate> templ = ObjectTemplate::New();
3331   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3332   LocalContext context;
3333   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3334   Local<Script> script = Script::Compile(v8_str("obj.x"));
3335   for (int i = 0; i < 10; i++) {
3336     Local<Value> result = script->Run();
3337     CHECK_EQ(result, v8_str("x"));
3338   }
3339 }
3340
3341 THREADED_TEST(DefinePropertyOnAPIAccessor) {
3342   v8::HandleScope scope;
3343   Local<ObjectTemplate> templ = ObjectTemplate::New();
3344   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3345   LocalContext context;
3346   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3347
3348   // Uses getOwnPropertyDescriptor to check the configurable status
3349   Local<Script> script_desc
3350     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
3351                              "obj, 'x');"
3352                              "prop.configurable;"));
3353   Local<Value> result = script_desc->Run();
3354   CHECK_EQ(result->BooleanValue(), true);
3355
3356   // Redefine get - but still configurable
3357   Local<Script> script_define
3358     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
3359                              "            configurable: true };"
3360                              "Object.defineProperty(obj, 'x', desc);"
3361                              "obj.x"));
3362   result = script_define->Run();
3363   CHECK_EQ(result, v8_num(42));
3364
3365   // Check that the accessor is still configurable
3366   result = script_desc->Run();
3367   CHECK_EQ(result->BooleanValue(), true);
3368
3369   // Redefine to a non-configurable
3370   script_define
3371     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
3372                              "             configurable: false };"
3373                              "Object.defineProperty(obj, 'x', desc);"
3374                              "obj.x"));
3375   result = script_define->Run();
3376   CHECK_EQ(result, v8_num(43));
3377   result = script_desc->Run();
3378   CHECK_EQ(result->BooleanValue(), false);
3379
3380   // Make sure that it is not possible to redefine again
3381   v8::TryCatch try_catch;
3382   result = script_define->Run();
3383   CHECK(try_catch.HasCaught());
3384   String::AsciiValue exception_value(try_catch.Exception());
3385   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3386 }
3387
3388 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
3389   v8::HandleScope scope;
3390   Local<ObjectTemplate> templ = ObjectTemplate::New();
3391   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
3392   LocalContext context;
3393   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3394
3395   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
3396                                     "Object.getOwnPropertyDescriptor( "
3397                                     "obj, 'x');"
3398                                     "prop.configurable;"));
3399   Local<Value> result = script_desc->Run();
3400   CHECK_EQ(result->BooleanValue(), true);
3401
3402   Local<Script> script_define =
3403     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
3404                            "            configurable: true };"
3405                            "Object.defineProperty(obj, 'x', desc);"
3406                            "obj.x"));
3407   result = script_define->Run();
3408   CHECK_EQ(result, v8_num(42));
3409
3410
3411   result = script_desc->Run();
3412   CHECK_EQ(result->BooleanValue(), true);
3413
3414
3415   script_define =
3416     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
3417                            "            configurable: false };"
3418                            "Object.defineProperty(obj, 'x', desc);"
3419                            "obj.x"));
3420   result = script_define->Run();
3421   CHECK_EQ(result, v8_num(43));
3422   result = script_desc->Run();
3423
3424   CHECK_EQ(result->BooleanValue(), false);
3425
3426   v8::TryCatch try_catch;
3427   result = script_define->Run();
3428   CHECK(try_catch.HasCaught());
3429   String::AsciiValue exception_value(try_catch.Exception());
3430   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3431 }
3432
3433
3434 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
3435                                                 char const* name) {
3436   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
3437 }
3438
3439
3440 THREADED_TEST(DefineAPIAccessorOnObject) {
3441   v8::HandleScope scope;
3442   Local<ObjectTemplate> templ = ObjectTemplate::New();
3443   LocalContext context;
3444
3445   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3446   CompileRun("var obj2 = {};");
3447
3448   CHECK(CompileRun("obj1.x")->IsUndefined());
3449   CHECK(CompileRun("obj2.x")->IsUndefined());
3450
3451   CHECK(GetGlobalProperty(&context, "obj1")->
3452       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3453
3454   ExpectString("obj1.x", "x");
3455   CHECK(CompileRun("obj2.x")->IsUndefined());
3456
3457   CHECK(GetGlobalProperty(&context, "obj2")->
3458       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3459
3460   ExpectString("obj1.x", "x");
3461   ExpectString("obj2.x", "x");
3462
3463   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3464   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3465
3466   CompileRun("Object.defineProperty(obj1, 'x',"
3467              "{ get: function() { return 'y'; }, configurable: true })");
3468
3469   ExpectString("obj1.x", "y");
3470   ExpectString("obj2.x", "x");
3471
3472   CompileRun("Object.defineProperty(obj2, 'x',"
3473              "{ get: function() { return 'y'; }, configurable: true })");
3474
3475   ExpectString("obj1.x", "y");
3476   ExpectString("obj2.x", "y");
3477
3478   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3479   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3480
3481   CHECK(GetGlobalProperty(&context, "obj1")->
3482       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3483   CHECK(GetGlobalProperty(&context, "obj2")->
3484       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3485
3486   ExpectString("obj1.x", "x");
3487   ExpectString("obj2.x", "x");
3488
3489   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3490   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3491
3492   // Define getters/setters, but now make them not configurable.
3493   CompileRun("Object.defineProperty(obj1, 'x',"
3494              "{ get: function() { return 'z'; }, configurable: false })");
3495   CompileRun("Object.defineProperty(obj2, 'x',"
3496              "{ get: function() { return 'z'; }, configurable: false })");
3497
3498   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3499   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3500
3501   ExpectString("obj1.x", "z");
3502   ExpectString("obj2.x", "z");
3503
3504   CHECK(!GetGlobalProperty(&context, "obj1")->
3505       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3506   CHECK(!GetGlobalProperty(&context, "obj2")->
3507       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3508
3509   ExpectString("obj1.x", "z");
3510   ExpectString("obj2.x", "z");
3511 }
3512
3513
3514 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
3515   v8::HandleScope scope;
3516   Local<ObjectTemplate> templ = ObjectTemplate::New();
3517   LocalContext context;
3518
3519   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3520   CompileRun("var obj2 = {};");
3521
3522   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3523         v8_str("x"),
3524         GetXValue, NULL,
3525         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3526   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3527         v8_str("x"),
3528         GetXValue, NULL,
3529         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
3530
3531   ExpectString("obj1.x", "x");
3532   ExpectString("obj2.x", "x");
3533
3534   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
3535   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
3536
3537   CHECK(!GetGlobalProperty(&context, "obj1")->
3538       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3539   CHECK(!GetGlobalProperty(&context, "obj2")->
3540       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
3541
3542   {
3543     v8::TryCatch try_catch;
3544     CompileRun("Object.defineProperty(obj1, 'x',"
3545         "{get: function() { return 'func'; }})");
3546     CHECK(try_catch.HasCaught());
3547     String::AsciiValue exception_value(try_catch.Exception());
3548     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3549   }
3550   {
3551     v8::TryCatch try_catch;
3552     CompileRun("Object.defineProperty(obj2, 'x',"
3553         "{get: function() { return 'func'; }})");
3554     CHECK(try_catch.HasCaught());
3555     String::AsciiValue exception_value(try_catch.Exception());
3556     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
3557   }
3558 }
3559
3560
3561 static v8::Handle<Value> Get239Value(Local<String> name,
3562                                      const AccessorInfo& info) {
3563   ApiTestFuzzer::Fuzz();
3564   CHECK_EQ(info.Data(), v8_str("donut"));
3565   CHECK_EQ(name, v8_str("239"));
3566   return name;
3567 }
3568
3569
3570 THREADED_TEST(ElementAPIAccessor) {
3571   v8::HandleScope scope;
3572   Local<ObjectTemplate> templ = ObjectTemplate::New();
3573   LocalContext context;
3574
3575   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
3576   CompileRun("var obj2 = {};");
3577
3578   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
3579         v8_str("239"),
3580         Get239Value, NULL,
3581         v8_str("donut")));
3582   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
3583         v8_str("239"),
3584         Get239Value, NULL,
3585         v8_str("donut")));
3586
3587   ExpectString("obj1[239]", "239");
3588   ExpectString("obj2[239]", "239");
3589   ExpectString("obj1['239']", "239");
3590   ExpectString("obj2['239']", "239");
3591 }
3592
3593
3594 v8::Persistent<Value> xValue;
3595
3596
3597 static void SetXValue(Local<String> name,
3598                       Local<Value> value,
3599                       const AccessorInfo& info) {
3600   CHECK_EQ(value, v8_num(4));
3601   CHECK_EQ(info.Data(), v8_str("donut"));
3602   CHECK_EQ(name, v8_str("x"));
3603   CHECK(xValue.IsEmpty());
3604   xValue = v8::Persistent<Value>::New(value);
3605 }
3606
3607
3608 THREADED_TEST(SimplePropertyWrite) {
3609   v8::HandleScope scope;
3610   Local<ObjectTemplate> templ = ObjectTemplate::New();
3611   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
3612   LocalContext context;
3613   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3614   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
3615   for (int i = 0; i < 10; i++) {
3616     CHECK(xValue.IsEmpty());
3617     script->Run();
3618     CHECK_EQ(v8_num(4), xValue);
3619     xValue.Dispose();
3620     xValue = v8::Persistent<Value>();
3621   }
3622 }
3623
3624
3625 static v8::Handle<Value> XPropertyGetter(Local<String> property,
3626                                          const AccessorInfo& info) {
3627   ApiTestFuzzer::Fuzz();
3628   CHECK(info.Data()->IsUndefined());
3629   return property;
3630 }
3631
3632
3633 THREADED_TEST(NamedInterceptorPropertyRead) {
3634   v8::HandleScope scope;
3635   Local<ObjectTemplate> templ = ObjectTemplate::New();
3636   templ->SetNamedPropertyHandler(XPropertyGetter);
3637   LocalContext context;
3638   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3639   Local<Script> script = Script::Compile(v8_str("obj.x"));
3640   for (int i = 0; i < 10; i++) {
3641     Local<Value> result = script->Run();
3642     CHECK_EQ(result, v8_str("x"));
3643   }
3644 }
3645
3646
3647 THREADED_TEST(NamedInterceptorDictionaryIC) {
3648   v8::HandleScope scope;
3649   Local<ObjectTemplate> templ = ObjectTemplate::New();
3650   templ->SetNamedPropertyHandler(XPropertyGetter);
3651   LocalContext context;
3652   // Create an object with a named interceptor.
3653   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
3654   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
3655   for (int i = 0; i < 10; i++) {
3656     Local<Value> result = script->Run();
3657     CHECK_EQ(result, v8_str("x"));
3658   }
3659   // Create a slow case object and a function accessing a property in
3660   // that slow case object (with dictionary probing in generated
3661   // code). Then force object with a named interceptor into slow-case,
3662   // pass it to the function, and check that the interceptor is called
3663   // instead of accessing the local property.
3664   Local<Value> result =
3665       CompileRun("function get_x(o) { return o.x; };"
3666                  "var obj = { x : 42, y : 0 };"
3667                  "delete obj.y;"
3668                  "for (var i = 0; i < 10; i++) get_x(obj);"
3669                  "interceptor_obj.x = 42;"
3670                  "interceptor_obj.y = 10;"
3671                  "delete interceptor_obj.y;"
3672                  "get_x(interceptor_obj)");
3673   CHECK_EQ(result, v8_str("x"));
3674 }
3675
3676
3677 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
3678   v8::HandleScope scope;
3679
3680   v8::Persistent<Context> context1 = Context::New();
3681
3682   context1->Enter();
3683   Local<ObjectTemplate> templ = ObjectTemplate::New();
3684   templ->SetNamedPropertyHandler(XPropertyGetter);
3685   // Create an object with a named interceptor.
3686   v8::Local<v8::Object> object = templ->NewInstance();
3687   context1->Global()->Set(v8_str("interceptor_obj"), object);
3688
3689   // Force the object into the slow case.
3690   CompileRun("interceptor_obj.y = 0;"
3691              "delete interceptor_obj.y;");
3692   context1->Exit();
3693
3694   {
3695     // Introduce the object into a different context.
3696     // Repeat named loads to exercise ICs.
3697     LocalContext context2;
3698     context2->Global()->Set(v8_str("interceptor_obj"), object);
3699     Local<Value> result =
3700       CompileRun("function get_x(o) { return o.x; }"
3701                  "interceptor_obj.x = 42;"
3702                  "for (var i=0; i != 10; i++) {"
3703                  "  get_x(interceptor_obj);"
3704                  "}"
3705                  "get_x(interceptor_obj)");
3706     // Check that the interceptor was actually invoked.
3707     CHECK_EQ(result, v8_str("x"));
3708   }
3709
3710   // Return to the original context and force some object to the slow case
3711   // to cause the NormalizedMapCache to verify.
3712   context1->Enter();
3713   CompileRun("var obj = { x : 0 }; delete obj.x;");
3714   context1->Exit();
3715
3716   context1.Dispose();
3717 }
3718
3719
3720 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
3721                                                const AccessorInfo& info) {
3722   // Set x on the prototype object and do not handle the get request.
3723   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
3724   proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
3725   return v8::Handle<Value>();
3726 }
3727
3728
3729 // This is a regression test for http://crbug.com/20104. Map
3730 // transitions should not interfere with post interceptor lookup.
3731 THREADED_TEST(NamedInterceptorMapTransitionRead) {
3732   v8::HandleScope scope;
3733   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
3734   Local<v8::ObjectTemplate> instance_template
3735       = function_template->InstanceTemplate();
3736   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
3737   LocalContext context;
3738   context->Global()->Set(v8_str("F"), function_template->GetFunction());
3739   // Create an instance of F and introduce a map transition for x.
3740   CompileRun("var o = new F(); o.x = 23;");
3741   // Create an instance of F and invoke the getter. The result should be 23.
3742   Local<Value> result = CompileRun("o = new F(); o.x");
3743   CHECK_EQ(result->Int32Value(), 23);
3744 }
3745
3746
3747 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
3748                                                const AccessorInfo& info) {
3749   ApiTestFuzzer::Fuzz();
3750   if (index == 37) {
3751     return v8::Handle<Value>(v8_num(625));
3752   }
3753   return v8::Handle<Value>();
3754 }
3755
3756
3757 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
3758                                                Local<Value> value,
3759                                                const AccessorInfo& info) {
3760   ApiTestFuzzer::Fuzz();
3761   if (index == 39) {
3762     return value;
3763   }
3764   return v8::Handle<Value>();
3765 }
3766
3767
3768 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
3769   v8::HandleScope scope;
3770   Local<ObjectTemplate> templ = ObjectTemplate::New();
3771   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
3772                                    IndexedPropertySetter);
3773   LocalContext context;
3774   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3775   Local<Script> getter_script = Script::Compile(v8_str(
3776       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
3777   Local<Script> setter_script = Script::Compile(v8_str(
3778       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
3779       "obj[17] = 23;"
3780       "obj.foo;"));
3781   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
3782       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
3783       "obj[39] = 47;"
3784       "obj.foo;"));  // This setter should not run, due to the interceptor.
3785   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
3786       "obj[37];"));
3787   Local<Value> result = getter_script->Run();
3788   CHECK_EQ(v8_num(5), result);
3789   result = setter_script->Run();
3790   CHECK_EQ(v8_num(23), result);
3791   result = interceptor_setter_script->Run();
3792   CHECK_EQ(v8_num(23), result);
3793   result = interceptor_getter_script->Run();
3794   CHECK_EQ(v8_num(625), result);
3795 }
3796
3797
3798 static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
3799     uint32_t index,
3800     const AccessorInfo& info) {
3801   ApiTestFuzzer::Fuzz();
3802   if (index < 25) {
3803     return v8::Handle<Value>(v8_num(index));
3804   }
3805   return v8::Handle<Value>();
3806 }
3807
3808
3809 static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
3810     uint32_t index,
3811     Local<Value> value,
3812     const AccessorInfo& info) {
3813   ApiTestFuzzer::Fuzz();
3814   if (index < 25) {
3815     return v8::Handle<Value>(v8_num(index));
3816   }
3817   return v8::Handle<Value>();
3818 }
3819
3820
3821 Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
3822     const AccessorInfo& info) {
3823   // Force the list of returned keys to be stored in a FastDoubleArray.
3824   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3825       "keys = new Array(); keys[125000] = 1;"
3826       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
3827       "keys.length = 25; keys;"));
3828   Local<Value> result = indexed_property_names_script->Run();
3829   return Local<v8::Array>(::v8::Array::Cast(*result));
3830 }
3831
3832
3833 // Make sure that the the interceptor code in the runtime properly handles
3834 // merging property name lists for double-array-backed arrays.
3835 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
3836   v8::HandleScope scope;
3837   Local<ObjectTemplate> templ = ObjectTemplate::New();
3838   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
3839                                    UnboxedDoubleIndexedPropertySetter,
3840                                    0,
3841                                    0,
3842                                    UnboxedDoubleIndexedPropertyEnumerator);
3843   LocalContext context;
3844   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3845   // When obj is created, force it to be Stored in a FastDoubleArray.
3846   Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
3847       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
3848       "key_count = 0; "
3849       "for (x in obj) {key_count++;};"
3850       "obj;"));
3851   Local<Value> result = create_unboxed_double_script->Run();
3852   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
3853   Local<Script> key_count_check = Script::Compile(v8_str(
3854       "key_count;"));
3855   result = key_count_check->Run();
3856   CHECK_EQ(v8_num(40013), result);
3857 }
3858
3859
3860 Handle<v8::Array> NonStrictArgsIndexedPropertyEnumerator(
3861     const AccessorInfo& info) {
3862   // Force the list of returned keys to be stored in a Arguments object.
3863   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
3864       "function f(w,x) {"
3865       " return arguments;"
3866       "}"
3867       "keys = f(0, 1, 2, 3);"
3868       "keys;"));
3869   Local<Value> result = indexed_property_names_script->Run();
3870   return Local<v8::Array>(static_cast<v8::Array*>(::v8::Object::Cast(*result)));
3871 }
3872
3873
3874 static v8::Handle<Value> NonStrictIndexedPropertyGetter(
3875     uint32_t index,
3876     const AccessorInfo& info) {
3877   ApiTestFuzzer::Fuzz();
3878   if (index < 4) {
3879     return v8::Handle<Value>(v8_num(index));
3880   }
3881   return v8::Handle<Value>();
3882 }
3883
3884
3885 // Make sure that the the interceptor code in the runtime properly handles
3886 // merging property name lists for non-string arguments arrays.
3887 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
3888   v8::HandleScope scope;
3889   Local<ObjectTemplate> templ = ObjectTemplate::New();
3890   templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
3891                                    0,
3892                                    0,
3893                                    0,
3894                                    NonStrictArgsIndexedPropertyEnumerator);
3895   LocalContext context;
3896   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3897   Local<Script> create_args_script =
3898       Script::Compile(v8_str(
3899           "var key_count = 0;"
3900           "for (x in obj) {key_count++;} key_count;"));
3901   Local<Value> result = create_args_script->Run();
3902   CHECK_EQ(v8_num(4), result);
3903 }
3904
3905
3906 static v8::Handle<Value> IdentityIndexedPropertyGetter(
3907     uint32_t index,
3908     const AccessorInfo& info) {
3909   return v8::Integer::NewFromUnsigned(index);
3910 }
3911
3912
3913 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
3914   v8::HandleScope scope;
3915   Local<ObjectTemplate> templ = ObjectTemplate::New();
3916   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3917
3918   LocalContext context;
3919   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3920
3921   // Check fast object case.
3922   const char* fast_case_code =
3923       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
3924   ExpectString(fast_case_code, "0");
3925
3926   // Check slow case.
3927   const char* slow_case_code =
3928       "obj.x = 1; delete obj.x;"
3929       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
3930   ExpectString(slow_case_code, "1");
3931 }
3932
3933
3934 THREADED_TEST(IndexedInterceptorWithNoSetter) {
3935   v8::HandleScope scope;
3936   Local<ObjectTemplate> templ = ObjectTemplate::New();
3937   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3938
3939   LocalContext context;
3940   context->Global()->Set(v8_str("obj"), templ->NewInstance());
3941
3942   const char* code =
3943       "try {"
3944       "  obj[0] = 239;"
3945       "  for (var i = 0; i < 100; i++) {"
3946       "    var v = obj[0];"
3947       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
3948       "  }"
3949       "  'PASSED'"
3950       "} catch(e) {"
3951       "  e"
3952       "}";
3953   ExpectString(code, "PASSED");
3954 }
3955
3956
3957 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
3958   v8::HandleScope scope;
3959   Local<ObjectTemplate> templ = ObjectTemplate::New();
3960   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3961
3962   LocalContext context;
3963   Local<v8::Object> obj = templ->NewInstance();
3964   obj->TurnOnAccessCheck();
3965   context->Global()->Set(v8_str("obj"), obj);
3966
3967   const char* code =
3968       "try {"
3969       "  for (var i = 0; i < 100; i++) {"
3970       "    var v = obj[0];"
3971       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
3972       "  }"
3973       "  'PASSED'"
3974       "} catch(e) {"
3975       "  e"
3976       "}";
3977   ExpectString(code, "PASSED");
3978 }
3979
3980
3981 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
3982   i::FLAG_allow_natives_syntax = true;
3983   v8::HandleScope scope;
3984   Local<ObjectTemplate> templ = ObjectTemplate::New();
3985   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
3986
3987   LocalContext context;
3988   Local<v8::Object> obj = templ->NewInstance();
3989   context->Global()->Set(v8_str("obj"), obj);
3990
3991   const char* code =
3992       "try {"
3993       "  for (var i = 0; i < 100; i++) {"
3994       "    var expected = i;"
3995       "    if (i == 5) {"
3996       "      %EnableAccessChecks(obj);"
3997       "      expected = undefined;"
3998       "    }"
3999       "    var v = obj[i];"
4000       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4001       "    if (i == 5) %DisableAccessChecks(obj);"
4002       "  }"
4003       "  'PASSED'"
4004       "} catch(e) {"
4005       "  e"
4006       "}";
4007   ExpectString(code, "PASSED");
4008 }
4009
4010
4011 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
4012   v8::HandleScope scope;
4013   Local<ObjectTemplate> templ = ObjectTemplate::New();
4014   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4015
4016   LocalContext context;
4017   Local<v8::Object> obj = templ->NewInstance();
4018   context->Global()->Set(v8_str("obj"), obj);
4019
4020   const char* code =
4021       "try {"
4022       "  for (var i = 0; i < 100; i++) {"
4023       "    var v = obj[i];"
4024       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4025       "  }"
4026       "  'PASSED'"
4027       "} catch(e) {"
4028       "  e"
4029       "}";
4030   ExpectString(code, "PASSED");
4031 }
4032
4033
4034 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
4035   v8::HandleScope scope;
4036   Local<ObjectTemplate> templ = ObjectTemplate::New();
4037   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4038
4039   LocalContext context;
4040   Local<v8::Object> obj = templ->NewInstance();
4041   context->Global()->Set(v8_str("obj"), obj);
4042
4043   const char* code =
4044       "try {"
4045       "  for (var i = 0; i < 100; i++) {"
4046       "    var expected = i;"
4047       "    var key = i;"
4048       "    if (i == 25) {"
4049       "       key = -1;"
4050       "       expected = undefined;"
4051       "    }"
4052       "    if (i == 50) {"
4053       "       /* probe minimal Smi number on 32-bit platforms */"
4054       "       key = -(1 << 30);"
4055       "       expected = undefined;"
4056       "    }"
4057       "    if (i == 75) {"
4058       "       /* probe minimal Smi number on 64-bit platforms */"
4059       "       key = 1 << 31;"
4060       "       expected = undefined;"
4061       "    }"
4062       "    var v = obj[key];"
4063       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4064       "  }"
4065       "  'PASSED'"
4066       "} catch(e) {"
4067       "  e"
4068       "}";
4069   ExpectString(code, "PASSED");
4070 }
4071
4072
4073 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
4074   v8::HandleScope scope;
4075   Local<ObjectTemplate> templ = ObjectTemplate::New();
4076   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4077
4078   LocalContext context;
4079   Local<v8::Object> obj = templ->NewInstance();
4080   context->Global()->Set(v8_str("obj"), obj);
4081
4082   const char* code =
4083       "try {"
4084       "  for (var i = 0; i < 100; i++) {"
4085       "    var expected = i;"
4086       "    var key = i;"
4087       "    if (i == 50) {"
4088       "       key = 'foobar';"
4089       "       expected = undefined;"
4090       "    }"
4091       "    var v = obj[key];"
4092       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4093       "  }"
4094       "  'PASSED'"
4095       "} catch(e) {"
4096       "  e"
4097       "}";
4098   ExpectString(code, "PASSED");
4099 }
4100
4101
4102 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
4103   v8::HandleScope scope;
4104   Local<ObjectTemplate> templ = ObjectTemplate::New();
4105   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4106
4107   LocalContext context;
4108   Local<v8::Object> obj = templ->NewInstance();
4109   context->Global()->Set(v8_str("obj"), obj);
4110
4111   const char* code =
4112       "var original = obj;"
4113       "try {"
4114       "  for (var i = 0; i < 100; i++) {"
4115       "    var expected = i;"
4116       "    if (i == 50) {"
4117       "       obj = {50: 'foobar'};"
4118       "       expected = 'foobar';"
4119       "    }"
4120       "    var v = obj[i];"
4121       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4122       "    if (i == 50) obj = original;"
4123       "  }"
4124       "  'PASSED'"
4125       "} catch(e) {"
4126       "  e"
4127       "}";
4128   ExpectString(code, "PASSED");
4129 }
4130
4131
4132 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
4133   v8::HandleScope scope;
4134   Local<ObjectTemplate> templ = ObjectTemplate::New();
4135   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4136
4137   LocalContext context;
4138   Local<v8::Object> obj = templ->NewInstance();
4139   context->Global()->Set(v8_str("obj"), obj);
4140
4141   const char* code =
4142       "var original = obj;"
4143       "try {"
4144       "  for (var i = 0; i < 100; i++) {"
4145       "    var expected = i;"
4146       "    if (i == 5) {"
4147       "       obj = 239;"
4148       "       expected = undefined;"
4149       "    }"
4150       "    var v = obj[i];"
4151       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
4152       "    if (i == 5) obj = original;"
4153       "  }"
4154       "  'PASSED'"
4155       "} catch(e) {"
4156       "  e"
4157       "}";
4158   ExpectString(code, "PASSED");
4159 }
4160
4161
4162 THREADED_TEST(IndexedInterceptorOnProto) {
4163   v8::HandleScope scope;
4164   Local<ObjectTemplate> templ = ObjectTemplate::New();
4165   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
4166
4167   LocalContext context;
4168   Local<v8::Object> obj = templ->NewInstance();
4169   context->Global()->Set(v8_str("obj"), obj);
4170
4171   const char* code =
4172       "var o = {__proto__: obj};"
4173       "try {"
4174       "  for (var i = 0; i < 100; i++) {"
4175       "    var v = o[i];"
4176       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
4177       "  }"
4178       "  'PASSED'"
4179       "} catch(e) {"
4180       "  e"
4181       "}";
4182   ExpectString(code, "PASSED");
4183 }
4184
4185
4186 THREADED_TEST(MultiContexts) {
4187   v8::HandleScope scope;
4188   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
4189   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
4190
4191   Local<String> password = v8_str("Password");
4192
4193   // Create an environment
4194   LocalContext context0(0, templ);
4195   context0->SetSecurityToken(password);
4196   v8::Handle<v8::Object> global0 = context0->Global();
4197   global0->Set(v8_str("custom"), v8_num(1234));
4198   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4199
4200   // Create an independent environment
4201   LocalContext context1(0, templ);
4202   context1->SetSecurityToken(password);
4203   v8::Handle<v8::Object> global1 = context1->Global();
4204   global1->Set(v8_str("custom"), v8_num(1234));
4205   CHECK_NE(global0, global1);
4206   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
4207   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
4208
4209   // Now create a new context with the old global
4210   LocalContext context2(0, templ, global1);
4211   context2->SetSecurityToken(password);
4212   v8::Handle<v8::Object> global2 = context2->Global();
4213   CHECK_EQ(global1, global2);
4214   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
4215   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
4216 }
4217
4218
4219 THREADED_TEST(FunctionPrototypeAcrossContexts) {
4220   // Make sure that functions created by cloning boilerplates cannot
4221   // communicate through their __proto__ field.
4222
4223   v8::HandleScope scope;
4224
4225   LocalContext env0;
4226   v8::Handle<v8::Object> global0 =
4227       env0->Global();
4228   v8::Handle<v8::Object> object0 =
4229       global0->Get(v8_str("Object")).As<v8::Object>();
4230   v8::Handle<v8::Object> tostring0 =
4231       object0->Get(v8_str("toString")).As<v8::Object>();
4232   v8::Handle<v8::Object> proto0 =
4233       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
4234   proto0->Set(v8_str("custom"), v8_num(1234));
4235
4236   LocalContext env1;
4237   v8::Handle<v8::Object> global1 =
4238       env1->Global();
4239   v8::Handle<v8::Object> object1 =
4240       global1->Get(v8_str("Object")).As<v8::Object>();
4241   v8::Handle<v8::Object> tostring1 =
4242       object1->Get(v8_str("toString")).As<v8::Object>();
4243   v8::Handle<v8::Object> proto1 =
4244       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
4245   CHECK(!proto1->Has(v8_str("custom")));
4246 }
4247
4248
4249 THREADED_TEST(Regress892105) {
4250   // Make sure that object and array literals created by cloning
4251   // boilerplates cannot communicate through their __proto__
4252   // field. This is rather difficult to check, but we try to add stuff
4253   // to Object.prototype and Array.prototype and create a new
4254   // environment. This should succeed.
4255
4256   v8::HandleScope scope;
4257
4258   Local<String> source = v8_str("Object.prototype.obj = 1234;"
4259                                 "Array.prototype.arr = 4567;"
4260                                 "8901");
4261
4262   LocalContext env0;
4263   Local<Script> script0 = Script::Compile(source);
4264   CHECK_EQ(8901.0, script0->Run()->NumberValue());
4265
4266   LocalContext env1;
4267   Local<Script> script1 = Script::Compile(source);
4268   CHECK_EQ(8901.0, script1->Run()->NumberValue());
4269 }
4270
4271
4272 THREADED_TEST(UndetectableObject) {
4273   v8::HandleScope scope;
4274   LocalContext env;
4275
4276   Local<v8::FunctionTemplate> desc =
4277       v8::FunctionTemplate::New(0, v8::Handle<Value>());
4278   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4279
4280   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4281   env->Global()->Set(v8_str("undetectable"), obj);
4282
4283   ExpectString("undetectable.toString()", "[object Object]");
4284   ExpectString("typeof undetectable", "undefined");
4285   ExpectString("typeof(undetectable)", "undefined");
4286   ExpectBoolean("typeof undetectable == 'undefined'", true);
4287   ExpectBoolean("typeof undetectable == 'object'", false);
4288   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4289   ExpectBoolean("!undetectable", true);
4290
4291   ExpectObject("true&&undetectable", obj);
4292   ExpectBoolean("false&&undetectable", false);
4293   ExpectBoolean("true||undetectable", true);
4294   ExpectObject("false||undetectable", obj);
4295
4296   ExpectObject("undetectable&&true", obj);
4297   ExpectObject("undetectable&&false", obj);
4298   ExpectBoolean("undetectable||true", true);
4299   ExpectBoolean("undetectable||false", false);
4300
4301   ExpectBoolean("undetectable==null", true);
4302   ExpectBoolean("null==undetectable", true);
4303   ExpectBoolean("undetectable==undefined", true);
4304   ExpectBoolean("undefined==undetectable", true);
4305   ExpectBoolean("undetectable==undetectable", true);
4306
4307
4308   ExpectBoolean("undetectable===null", false);
4309   ExpectBoolean("null===undetectable", false);
4310   ExpectBoolean("undetectable===undefined", false);
4311   ExpectBoolean("undefined===undetectable", false);
4312   ExpectBoolean("undetectable===undetectable", true);
4313 }
4314
4315
4316 THREADED_TEST(VoidLiteral) {
4317   v8::HandleScope scope;
4318   LocalContext env;
4319
4320   Local<v8::FunctionTemplate> desc =
4321       v8::FunctionTemplate::New(0, v8::Handle<Value>());
4322   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4323
4324   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4325   env->Global()->Set(v8_str("undetectable"), obj);
4326
4327   ExpectBoolean("undefined == void 0", true);
4328   ExpectBoolean("undetectable == void 0", true);
4329   ExpectBoolean("null == void 0", true);
4330   ExpectBoolean("undefined === void 0", true);
4331   ExpectBoolean("undetectable === void 0", false);
4332   ExpectBoolean("null === void 0", false);
4333
4334   ExpectBoolean("void 0 == undefined", true);
4335   ExpectBoolean("void 0 == undetectable", true);
4336   ExpectBoolean("void 0 == null", true);
4337   ExpectBoolean("void 0 === undefined", true);
4338   ExpectBoolean("void 0 === undetectable", false);
4339   ExpectBoolean("void 0 === null", false);
4340
4341   ExpectString("(function() {"
4342                "  try {"
4343                "    return x === void 0;"
4344                "  } catch(e) {"
4345                "    return e.toString();"
4346                "  }"
4347                "})()",
4348                "ReferenceError: x is not defined");
4349   ExpectString("(function() {"
4350                "  try {"
4351                "    return void 0 === x;"
4352                "  } catch(e) {"
4353                "    return e.toString();"
4354                "  }"
4355                "})()",
4356                "ReferenceError: x is not defined");
4357 }
4358
4359
4360 THREADED_TEST(ExtensibleOnUndetectable) {
4361   v8::HandleScope scope;
4362   LocalContext env;
4363
4364   Local<v8::FunctionTemplate> desc =
4365       v8::FunctionTemplate::New(0, v8::Handle<Value>());
4366   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
4367
4368   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
4369   env->Global()->Set(v8_str("undetectable"), obj);
4370
4371   Local<String> source = v8_str("undetectable.x = 42;"
4372                                 "undetectable.x");
4373
4374   Local<Script> script = Script::Compile(source);
4375
4376   CHECK_EQ(v8::Integer::New(42), script->Run());
4377
4378   ExpectBoolean("Object.isExtensible(undetectable)", true);
4379
4380   source = v8_str("Object.preventExtensions(undetectable);");
4381   script = Script::Compile(source);
4382   script->Run();
4383   ExpectBoolean("Object.isExtensible(undetectable)", false);
4384
4385   source = v8_str("undetectable.y = 2000;");
4386   script = Script::Compile(source);
4387   Local<Value> result(script->Run());
4388   ExpectBoolean("undetectable.y == undefined", true);
4389 }
4390
4391
4392
4393 THREADED_TEST(UndetectableString) {
4394   v8::HandleScope scope;
4395   LocalContext env;
4396
4397   Local<String> obj = String::NewUndetectable("foo");
4398   env->Global()->Set(v8_str("undetectable"), obj);
4399
4400   ExpectString("undetectable", "foo");
4401   ExpectString("typeof undetectable", "undefined");
4402   ExpectString("typeof(undetectable)", "undefined");
4403   ExpectBoolean("typeof undetectable == 'undefined'", true);
4404   ExpectBoolean("typeof undetectable == 'string'", false);
4405   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
4406   ExpectBoolean("!undetectable", true);
4407
4408   ExpectObject("true&&undetectable", obj);
4409   ExpectBoolean("false&&undetectable", false);
4410   ExpectBoolean("true||undetectable", true);
4411   ExpectObject("false||undetectable", obj);
4412
4413   ExpectObject("undetectable&&true", obj);
4414   ExpectObject("undetectable&&false", obj);
4415   ExpectBoolean("undetectable||true", true);
4416   ExpectBoolean("undetectable||false", false);
4417
4418   ExpectBoolean("undetectable==null", true);
4419   ExpectBoolean("null==undetectable", true);
4420   ExpectBoolean("undetectable==undefined", true);
4421   ExpectBoolean("undefined==undetectable", true);
4422   ExpectBoolean("undetectable==undetectable", true);
4423
4424
4425   ExpectBoolean("undetectable===null", false);
4426   ExpectBoolean("null===undetectable", false);
4427   ExpectBoolean("undetectable===undefined", false);
4428   ExpectBoolean("undefined===undetectable", false);
4429   ExpectBoolean("undetectable===undetectable", true);
4430 }
4431
4432
4433 TEST(UndetectableOptimized) {
4434   i::FLAG_allow_natives_syntax = true;
4435   v8::HandleScope scope;
4436   LocalContext env;
4437
4438   Local<String> obj = String::NewUndetectable("foo");
4439   env->Global()->Set(v8_str("undetectable"), obj);
4440   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
4441
4442   ExpectString(
4443       "function testBranch() {"
4444       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
4445       "  if (%_IsUndetectableObject(detectable)) throw 2;"
4446       "}\n"
4447       "function testBool() {"
4448       "  var b1 = !%_IsUndetectableObject(undetectable);"
4449       "  var b2 = %_IsUndetectableObject(detectable);"
4450       "  if (b1) throw 3;"
4451       "  if (b2) throw 4;"
4452       "  return b1 == b2;"
4453       "}\n"
4454       "%OptimizeFunctionOnNextCall(testBranch);"
4455       "%OptimizeFunctionOnNextCall(testBool);"
4456       "for (var i = 0; i < 10; i++) {"
4457       "  testBranch();"
4458       "  testBool();"
4459       "}\n"
4460       "\"PASS\"",
4461       "PASS");
4462 }
4463
4464
4465 template <typename T> static void USE(T) { }
4466
4467
4468 // This test is not intended to be run, just type checked.
4469 static inline void PersistentHandles() {
4470   USE(PersistentHandles);
4471   Local<String> str = v8_str("foo");
4472   v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
4473   USE(p_str);
4474   Local<Script> scr = Script::Compile(v8_str(""));
4475   v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
4476   USE(p_scr);
4477   Local<ObjectTemplate> templ = ObjectTemplate::New();
4478   v8::Persistent<ObjectTemplate> p_templ =
4479     v8::Persistent<ObjectTemplate>::New(templ);
4480   USE(p_templ);
4481 }
4482
4483
4484 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
4485   ApiTestFuzzer::Fuzz();
4486   return v8::Undefined();
4487 }
4488
4489
4490 THREADED_TEST(GlobalObjectTemplate) {
4491   v8::HandleScope handle_scope;
4492   Local<ObjectTemplate> global_template = ObjectTemplate::New();
4493   global_template->Set(v8_str("JSNI_Log"),
4494                        v8::FunctionTemplate::New(HandleLogDelegator));
4495   v8::Persistent<Context> context = Context::New(0, global_template);
4496   Context::Scope context_scope(context);
4497   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
4498   context.Dispose();
4499 }
4500
4501
4502 static const char* kSimpleExtensionSource =
4503   "function Foo() {"
4504   "  return 4;"
4505   "}";
4506
4507
4508 THREADED_TEST(SimpleExtensions) {
4509   v8::HandleScope handle_scope;
4510   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
4511   const char* extension_names[] = { "simpletest" };
4512   v8::ExtensionConfiguration extensions(1, extension_names);
4513   v8::Handle<Context> context = Context::New(&extensions);
4514   Context::Scope lock(context);
4515   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4516   CHECK_EQ(result, v8::Integer::New(4));
4517 }
4518
4519
4520 static const char* kEmbeddedExtensionSource =
4521     "function Ret54321(){return 54321;}~~@@$"
4522     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
4523 static const int kEmbeddedExtensionSourceValidLen = 34;
4524
4525
4526 THREADED_TEST(ExtensionMissingSourceLength) {
4527   v8::HandleScope handle_scope;
4528   v8::RegisterExtension(new Extension("srclentest_fail",
4529                                       kEmbeddedExtensionSource));
4530   const char* extension_names[] = { "srclentest_fail" };
4531   v8::ExtensionConfiguration extensions(1, extension_names);
4532   v8::Handle<Context> context = Context::New(&extensions);
4533   CHECK_EQ(0, *context);
4534 }
4535
4536
4537 THREADED_TEST(ExtensionWithSourceLength) {
4538   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
4539        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
4540     v8::HandleScope handle_scope;
4541     i::ScopedVector<char> extension_name(32);
4542     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
4543     v8::RegisterExtension(new Extension(extension_name.start(),
4544                                         kEmbeddedExtensionSource, 0, 0,
4545                                         source_len));
4546     const char* extension_names[1] = { extension_name.start() };
4547     v8::ExtensionConfiguration extensions(1, extension_names);
4548     v8::Handle<Context> context = Context::New(&extensions);
4549     if (source_len == kEmbeddedExtensionSourceValidLen) {
4550       Context::Scope lock(context);
4551       v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
4552       CHECK_EQ(v8::Integer::New(54321), result);
4553     } else {
4554       // Anything but exactly the right length should fail to compile.
4555       CHECK_EQ(0, *context);
4556     }
4557   }
4558 }
4559
4560
4561 static const char* kEvalExtensionSource1 =
4562   "function UseEval1() {"
4563   "  var x = 42;"
4564   "  return eval('x');"
4565   "}";
4566
4567
4568 static const char* kEvalExtensionSource2 =
4569   "(function() {"
4570   "  var x = 42;"
4571   "  function e() {"
4572   "    return eval('x');"
4573   "  }"
4574   "  this.UseEval2 = e;"
4575   "})()";
4576
4577
4578 THREADED_TEST(UseEvalFromExtension) {
4579   v8::HandleScope handle_scope;
4580   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
4581   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
4582   const char* extension_names[] = { "evaltest1", "evaltest2" };
4583   v8::ExtensionConfiguration extensions(2, extension_names);
4584   v8::Handle<Context> context = Context::New(&extensions);
4585   Context::Scope lock(context);
4586   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
4587   CHECK_EQ(result, v8::Integer::New(42));
4588   result = Script::Compile(v8_str("UseEval2()"))->Run();
4589   CHECK_EQ(result, v8::Integer::New(42));
4590 }
4591
4592
4593 static const char* kWithExtensionSource1 =
4594   "function UseWith1() {"
4595   "  var x = 42;"
4596   "  with({x:87}) { return x; }"
4597   "}";
4598
4599
4600
4601 static const char* kWithExtensionSource2 =
4602   "(function() {"
4603   "  var x = 42;"
4604   "  function e() {"
4605   "    with ({x:87}) { return x; }"
4606   "  }"
4607   "  this.UseWith2 = e;"
4608   "})()";
4609
4610
4611 THREADED_TEST(UseWithFromExtension) {
4612   v8::HandleScope handle_scope;
4613   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
4614   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
4615   const char* extension_names[] = { "withtest1", "withtest2" };
4616   v8::ExtensionConfiguration extensions(2, extension_names);
4617   v8::Handle<Context> context = Context::New(&extensions);
4618   Context::Scope lock(context);
4619   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
4620   CHECK_EQ(result, v8::Integer::New(87));
4621   result = Script::Compile(v8_str("UseWith2()"))->Run();
4622   CHECK_EQ(result, v8::Integer::New(87));
4623 }
4624
4625
4626 THREADED_TEST(AutoExtensions) {
4627   v8::HandleScope handle_scope;
4628   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
4629   extension->set_auto_enable(true);
4630   v8::RegisterExtension(extension);
4631   v8::Handle<Context> context = Context::New();
4632   Context::Scope lock(context);
4633   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
4634   CHECK_EQ(result, v8::Integer::New(4));
4635 }
4636
4637
4638 static const char* kSyntaxErrorInExtensionSource =
4639     "[";
4640
4641
4642 // Test that a syntax error in an extension does not cause a fatal
4643 // error but results in an empty context.
4644 THREADED_TEST(SyntaxErrorExtensions) {
4645   v8::HandleScope handle_scope;
4646   v8::RegisterExtension(new Extension("syntaxerror",
4647                                       kSyntaxErrorInExtensionSource));
4648   const char* extension_names[] = { "syntaxerror" };
4649   v8::ExtensionConfiguration extensions(1, extension_names);
4650   v8::Handle<Context> context = Context::New(&extensions);
4651   CHECK(context.IsEmpty());
4652 }
4653
4654
4655 static const char* kExceptionInExtensionSource =
4656     "throw 42";
4657
4658
4659 // Test that an exception when installing an extension does not cause
4660 // a fatal error but results in an empty context.
4661 THREADED_TEST(ExceptionExtensions) {
4662   v8::HandleScope handle_scope;
4663   v8::RegisterExtension(new Extension("exception",
4664                                       kExceptionInExtensionSource));
4665   const char* extension_names[] = { "exception" };
4666   v8::ExtensionConfiguration extensions(1, extension_names);
4667   v8::Handle<Context> context = Context::New(&extensions);
4668   CHECK(context.IsEmpty());
4669 }
4670
4671
4672 static const char* kNativeCallInExtensionSource =
4673     "function call_runtime_last_index_of(x) {"
4674     "  return %StringLastIndexOf(x, 'bob', 10);"
4675     "}";
4676
4677
4678 static const char* kNativeCallTest =
4679     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
4680
4681 // Test that a native runtime calls are supported in extensions.
4682 THREADED_TEST(NativeCallInExtensions) {
4683   v8::HandleScope handle_scope;
4684   v8::RegisterExtension(new Extension("nativecall",
4685                                       kNativeCallInExtensionSource));
4686   const char* extension_names[] = { "nativecall" };
4687   v8::ExtensionConfiguration extensions(1, extension_names);
4688   v8::Handle<Context> context = Context::New(&extensions);
4689   Context::Scope lock(context);
4690   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
4691   CHECK_EQ(result, v8::Integer::New(3));
4692 }
4693
4694
4695 class NativeFunctionExtension : public Extension {
4696  public:
4697   NativeFunctionExtension(const char* name,
4698                           const char* source,
4699                           v8::InvocationCallback fun = &Echo)
4700       : Extension(name, source),
4701         function_(fun) { }
4702
4703   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4704       v8::Handle<v8::String> name) {
4705     return v8::FunctionTemplate::New(function_);
4706   }
4707
4708   static v8::Handle<v8::Value> Echo(const v8::Arguments& args) {
4709     if (args.Length() >= 1) return (args[0]);
4710     return v8::Undefined();
4711   }
4712  private:
4713   v8::InvocationCallback function_;
4714 };
4715
4716
4717 THREADED_TEST(NativeFunctionDeclaration) {
4718   v8::HandleScope handle_scope;
4719   const char* name = "nativedecl";
4720   v8::RegisterExtension(new NativeFunctionExtension(name,
4721                                                     "native function foo();"));
4722   const char* extension_names[] = { name };
4723   v8::ExtensionConfiguration extensions(1, extension_names);
4724   v8::Handle<Context> context = Context::New(&extensions);
4725   Context::Scope lock(context);
4726   v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
4727   CHECK_EQ(result, v8::Integer::New(42));
4728 }
4729
4730
4731 THREADED_TEST(NativeFunctionDeclarationError) {
4732   v8::HandleScope handle_scope;
4733   const char* name = "nativedeclerr";
4734   // Syntax error in extension code.
4735   v8::RegisterExtension(new NativeFunctionExtension(name,
4736                                                     "native\nfunction foo();"));
4737   const char* extension_names[] = { name };
4738   v8::ExtensionConfiguration extensions(1, extension_names);
4739   v8::Handle<Context> context(Context::New(&extensions));
4740   ASSERT(context.IsEmpty());
4741 }
4742
4743 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
4744   v8::HandleScope handle_scope;
4745   const char* name = "nativedeclerresc";
4746   // Syntax error in extension code - escape code in "native" means that
4747   // it's not treated as a keyword.
4748   v8::RegisterExtension(new NativeFunctionExtension(
4749       name,
4750       "nativ\\u0065 function foo();"));
4751   const char* extension_names[] = { name };
4752   v8::ExtensionConfiguration extensions(1, extension_names);
4753   v8::Handle<Context> context(Context::New(&extensions));
4754   ASSERT(context.IsEmpty());
4755 }
4756
4757
4758 static void CheckDependencies(const char* name, const char* expected) {
4759   v8::HandleScope handle_scope;
4760   v8::ExtensionConfiguration config(1, &name);
4761   LocalContext context(&config);
4762   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
4763 }
4764
4765
4766 /*
4767  * Configuration:
4768  *
4769  *     /-- B <--\
4770  * A <-          -- D <-- E
4771  *     \-- C <--/
4772  */
4773 THREADED_TEST(ExtensionDependency) {
4774   static const char* kEDeps[] = { "D" };
4775   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
4776   static const char* kDDeps[] = { "B", "C" };
4777   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
4778   static const char* kBCDeps[] = { "A" };
4779   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
4780   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
4781   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
4782   CheckDependencies("A", "undefinedA");
4783   CheckDependencies("B", "undefinedAB");
4784   CheckDependencies("C", "undefinedAC");
4785   CheckDependencies("D", "undefinedABCD");
4786   CheckDependencies("E", "undefinedABCDE");
4787   v8::HandleScope handle_scope;
4788   static const char* exts[2] = { "C", "E" };
4789   v8::ExtensionConfiguration config(2, exts);
4790   LocalContext context(&config);
4791   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
4792 }
4793
4794
4795 static const char* kExtensionTestScript =
4796   "native function A();"
4797   "native function B();"
4798   "native function C();"
4799   "function Foo(i) {"
4800   "  if (i == 0) return A();"
4801   "  if (i == 1) return B();"
4802   "  if (i == 2) return C();"
4803   "}";
4804
4805
4806 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
4807   ApiTestFuzzer::Fuzz();
4808   if (args.IsConstructCall()) {
4809     args.This()->Set(v8_str("data"), args.Data());
4810     return v8::Null();
4811   }
4812   return args.Data();
4813 }
4814
4815
4816 class FunctionExtension : public Extension {
4817  public:
4818   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
4819   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
4820       v8::Handle<String> name);
4821 };
4822
4823
4824 static int lookup_count = 0;
4825 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
4826       v8::Handle<String> name) {
4827   lookup_count++;
4828   if (name->Equals(v8_str("A"))) {
4829     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
4830   } else if (name->Equals(v8_str("B"))) {
4831     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
4832   } else if (name->Equals(v8_str("C"))) {
4833     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
4834   } else {
4835     return v8::Handle<v8::FunctionTemplate>();
4836   }
4837 }
4838
4839
4840 THREADED_TEST(FunctionLookup) {
4841   v8::RegisterExtension(new FunctionExtension());
4842   v8::HandleScope handle_scope;
4843   static const char* exts[1] = { "functiontest" };
4844   v8::ExtensionConfiguration config(1, exts);
4845   LocalContext context(&config);
4846   CHECK_EQ(3, lookup_count);
4847   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
4848   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
4849   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
4850 }
4851
4852
4853 THREADED_TEST(NativeFunctionConstructCall) {
4854   v8::RegisterExtension(new FunctionExtension());
4855   v8::HandleScope handle_scope;
4856   static const char* exts[1] = { "functiontest" };
4857   v8::ExtensionConfiguration config(1, exts);
4858   LocalContext context(&config);
4859   for (int i = 0; i < 10; i++) {
4860     // Run a few times to ensure that allocation of objects doesn't
4861     // change behavior of a constructor function.
4862     CHECK_EQ(v8::Integer::New(8),
4863              Script::Compile(v8_str("(new A()).data"))->Run());
4864     CHECK_EQ(v8::Integer::New(7),
4865              Script::Compile(v8_str("(new B()).data"))->Run());
4866     CHECK_EQ(v8::Integer::New(6),
4867              Script::Compile(v8_str("(new C()).data"))->Run());
4868   }
4869 }
4870
4871
4872 static const char* last_location;
4873 static const char* last_message;
4874 void StoringErrorCallback(const char* location, const char* message) {
4875   if (last_location == NULL) {
4876     last_location = location;
4877     last_message = message;
4878   }
4879 }
4880
4881
4882 // ErrorReporting creates a circular extensions configuration and
4883 // tests that the fatal error handler gets called.  This renders V8
4884 // unusable and therefore this test cannot be run in parallel.
4885 TEST(ErrorReporting) {
4886   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
4887   static const char* aDeps[] = { "B" };
4888   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
4889   static const char* bDeps[] = { "A" };
4890   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
4891   last_location = NULL;
4892   v8::ExtensionConfiguration config(1, bDeps);
4893   v8::Handle<Context> context = Context::New(&config);
4894   CHECK(context.IsEmpty());
4895   CHECK_NE(last_location, NULL);
4896 }
4897
4898
4899 static const char* js_code_causing_huge_string_flattening =
4900     "var str = 'X';"
4901     "for (var i = 0; i < 30; i++) {"
4902     "  str = str + str;"
4903     "}"
4904     "str.match(/X/);";
4905
4906
4907 void OOMCallback(const char* location, const char* message) {
4908   exit(0);
4909 }
4910
4911
4912 TEST(RegexpOutOfMemory) {
4913   // Execute a script that causes out of memory when flattening a string.
4914   v8::HandleScope scope;
4915   v8::V8::SetFatalErrorHandler(OOMCallback);
4916   LocalContext context;
4917   Local<Script> script =
4918       Script::Compile(String::New(js_code_causing_huge_string_flattening));
4919   last_location = NULL;
4920   Local<Value> result(script->Run());
4921
4922   CHECK(false);  // Should not return.
4923 }
4924
4925
4926 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
4927                                              v8::Handle<Value> data) {
4928   CHECK_EQ(v8::Undefined(), data);
4929   CHECK(message->GetScriptResourceName()->IsUndefined());
4930   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
4931   message->GetLineNumber();
4932   message->GetSourceLine();
4933 }
4934
4935
4936 THREADED_TEST(ErrorWithMissingScriptInfo) {
4937   v8::HandleScope scope;
4938   LocalContext context;
4939   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
4940   Script::Compile(v8_str("throw Error()"))->Run();
4941   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
4942 }
4943
4944
4945 int global_index = 0;
4946
4947 class Snorkel {
4948  public:
4949   Snorkel() { index_ = global_index++; }
4950   int index_;
4951 };
4952
4953 class Whammy {
4954  public:
4955   Whammy() {
4956     cursor_ = 0;
4957   }
4958   ~Whammy() {
4959     script_.Dispose();
4960   }
4961   v8::Handle<Script> getScript() {
4962     if (script_.IsEmpty())
4963       script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
4964     return Local<Script>(*script_);
4965   }
4966
4967  public:
4968   static const int kObjectCount = 256;
4969   int cursor_;
4970   v8::Persistent<v8::Object> objects_[kObjectCount];
4971   v8::Persistent<Script> script_;
4972 };
4973
4974 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
4975   Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
4976   delete snorkel;
4977   obj.ClearWeak();
4978 }
4979
4980 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
4981                                        const AccessorInfo& info) {
4982   Whammy* whammy =
4983     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
4984
4985   v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
4986
4987   v8::Handle<v8::Object> obj = v8::Object::New();
4988   v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
4989   if (!prev.IsEmpty()) {
4990     prev->Set(v8_str("next"), obj);
4991     prev.MakeWeak(new Snorkel(), &HandleWeakReference);
4992     whammy->objects_[whammy->cursor_].Clear();
4993   }
4994   whammy->objects_[whammy->cursor_] = global;
4995   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
4996   return whammy->getScript()->Run();
4997 }
4998
4999 THREADED_TEST(WeakReference) {
5000   v8::HandleScope handle_scope;
5001   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
5002   Whammy* whammy = new Whammy();
5003   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
5004                                  0, 0, 0, 0,
5005                                  v8::External::New(whammy));
5006   const char* extension_list[] = { "v8/gc" };
5007   v8::ExtensionConfiguration extensions(1, extension_list);
5008   v8::Persistent<Context> context = Context::New(&extensions);
5009   Context::Scope context_scope(context);
5010
5011   v8::Handle<v8::Object> interceptor = templ->NewInstance();
5012   context->Global()->Set(v8_str("whammy"), interceptor);
5013   const char* code =
5014       "var last;"
5015       "for (var i = 0; i < 10000; i++) {"
5016       "  var obj = whammy.length;"
5017       "  if (last) last.next = obj;"
5018       "  last = obj;"
5019       "}"
5020       "gc();"
5021       "4";
5022   v8::Handle<Value> result = CompileRun(code);
5023   CHECK_EQ(4.0, result->NumberValue());
5024   delete whammy;
5025   context.Dispose();
5026 }
5027
5028
5029 static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) {
5030   obj.Dispose();
5031   obj.Clear();
5032   *(reinterpret_cast<bool*>(data)) = true;
5033 }
5034
5035
5036 THREADED_TEST(IndependentWeakHandle) {
5037   v8::Persistent<Context> context = Context::New();
5038   Context::Scope context_scope(context);
5039
5040   v8::Persistent<v8::Object> object_a;
5041
5042   {
5043     v8::HandleScope handle_scope;
5044     object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
5045   }
5046
5047   bool object_a_disposed = false;
5048   object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
5049   object_a.MarkIndependent();
5050   HEAP->PerformScavenge();
5051   CHECK(object_a_disposed);
5052 }
5053
5054
5055 static void InvokeScavenge() {
5056   HEAP->PerformScavenge();
5057 }
5058
5059
5060 static void InvokeMarkSweep() {
5061   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5062 }
5063
5064
5065 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
5066   obj.Dispose();
5067   obj.Clear();
5068   *(reinterpret_cast<bool*>(data)) = true;
5069   InvokeScavenge();
5070 }
5071
5072
5073 static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) {
5074   obj.Dispose();
5075   obj.Clear();
5076   *(reinterpret_cast<bool*>(data)) = true;
5077   InvokeMarkSweep();
5078 }
5079
5080
5081 THREADED_TEST(GCFromWeakCallbacks) {
5082   v8::Persistent<Context> context = Context::New();
5083   Context::Scope context_scope(context);
5084
5085   static const int kNumberOfGCTypes = 2;
5086   v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] =
5087       {&ForceScavenge, &ForceMarkSweep};
5088
5089   typedef void (*GCInvoker)();
5090   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
5091
5092   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
5093     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
5094       v8::Persistent<v8::Object> object;
5095       {
5096         v8::HandleScope handle_scope;
5097         object = v8::Persistent<v8::Object>::New(v8::Object::New());
5098       }
5099       bool disposed = false;
5100       object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
5101       object.MarkIndependent();
5102       invoke_gc[outer_gc]();
5103       CHECK(disposed);
5104     }
5105   }
5106 }
5107
5108
5109 static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) {
5110   obj.ClearWeak();
5111   *(reinterpret_cast<bool*>(data)) = true;
5112 }
5113
5114
5115 THREADED_TEST(IndependentHandleRevival) {
5116   v8::Persistent<Context> context = Context::New();
5117   Context::Scope context_scope(context);
5118
5119   v8::Persistent<v8::Object> object;
5120   {
5121     v8::HandleScope handle_scope;
5122     object = v8::Persistent<v8::Object>::New(v8::Object::New());
5123     object->Set(v8_str("x"), v8::Integer::New(1));
5124     v8::Local<String> y_str = v8_str("y");
5125     object->Set(y_str, y_str);
5126   }
5127   bool revived = false;
5128   object.MakeWeak(&revived, &RevivingCallback);
5129   object.MarkIndependent();
5130   HEAP->PerformScavenge();
5131   CHECK(revived);
5132   HEAP->CollectAllGarbage(true);
5133   {
5134     v8::HandleScope handle_scope;
5135     v8::Local<String> y_str = v8_str("y");
5136     CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x")));
5137     CHECK(object->Get(y_str)->Equals(y_str));
5138   }
5139 }
5140
5141
5142 v8::Handle<Function> args_fun;
5143
5144
5145 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
5146   ApiTestFuzzer::Fuzz();
5147   CHECK_EQ(args_fun, args.Callee());
5148   CHECK_EQ(3, args.Length());
5149   CHECK_EQ(v8::Integer::New(1), args[0]);
5150   CHECK_EQ(v8::Integer::New(2), args[1]);
5151   CHECK_EQ(v8::Integer::New(3), args[2]);
5152   CHECK_EQ(v8::Undefined(), args[3]);
5153   v8::HandleScope scope;
5154   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
5155   return v8::Undefined();
5156 }
5157
5158
5159 THREADED_TEST(Arguments) {
5160   v8::HandleScope scope;
5161   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
5162   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
5163   LocalContext context(NULL, global);
5164   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
5165   v8_compile("f(1, 2, 3)")->Run();
5166 }
5167
5168
5169 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
5170                                         const AccessorInfo&) {
5171   return v8::Handle<Value>();
5172 }
5173
5174
5175 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
5176                                         const AccessorInfo&) {
5177   return v8::Handle<Value>();
5178 }
5179
5180
5181 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
5182                                         const AccessorInfo&) {
5183   if (!name->Equals(v8_str("foo"))) {
5184     return v8::Handle<v8::Boolean>();  // not intercepted
5185   }
5186
5187   return v8::False();  // intercepted, and don't delete the property
5188 }
5189
5190
5191 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
5192   if (index != 2) {
5193     return v8::Handle<v8::Boolean>();  // not intercepted
5194   }
5195
5196   return v8::False();  // intercepted, and don't delete the property
5197 }
5198
5199
5200 THREADED_TEST(Deleter) {
5201   v8::HandleScope scope;
5202   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5203   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
5204   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
5205   LocalContext context;
5206   context->Global()->Set(v8_str("k"), obj->NewInstance());
5207   CompileRun(
5208     "k.foo = 'foo';"
5209     "k.bar = 'bar';"
5210     "k[2] = 2;"
5211     "k[4] = 4;");
5212   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
5213   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
5214
5215   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
5216   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
5217
5218   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
5219   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
5220
5221   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
5222   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
5223 }
5224
5225
5226 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
5227   ApiTestFuzzer::Fuzz();
5228   if (name->Equals(v8_str("foo")) ||
5229       name->Equals(v8_str("bar")) ||
5230       name->Equals(v8_str("baz"))) {
5231     return v8::Undefined();
5232   }
5233   return v8::Handle<Value>();
5234 }
5235
5236
5237 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
5238   ApiTestFuzzer::Fuzz();
5239   if (index == 0 || index == 1) return v8::Undefined();
5240   return v8::Handle<Value>();
5241 }
5242
5243
5244 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
5245   ApiTestFuzzer::Fuzz();
5246   v8::Handle<v8::Array> result = v8::Array::New(3);
5247   result->Set(v8::Integer::New(0), v8_str("foo"));
5248   result->Set(v8::Integer::New(1), v8_str("bar"));
5249   result->Set(v8::Integer::New(2), v8_str("baz"));
5250   return result;
5251 }
5252
5253
5254 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
5255   ApiTestFuzzer::Fuzz();
5256   v8::Handle<v8::Array> result = v8::Array::New(2);
5257   result->Set(v8::Integer::New(0), v8_str("0"));
5258   result->Set(v8::Integer::New(1), v8_str("1"));
5259   return result;
5260 }
5261
5262
5263 THREADED_TEST(Enumerators) {
5264   v8::HandleScope scope;
5265   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5266   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
5267   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
5268   LocalContext context;
5269   context->Global()->Set(v8_str("k"), obj->NewInstance());
5270   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5271     "k[10] = 0;"
5272     "k.a = 0;"
5273     "k[5] = 0;"
5274     "k.b = 0;"
5275     "k[4294967295] = 0;"
5276     "k.c = 0;"
5277     "k[4294967296] = 0;"
5278     "k.d = 0;"
5279     "k[140000] = 0;"
5280     "k.e = 0;"
5281     "k[30000000000] = 0;"
5282     "k.f = 0;"
5283     "var result = [];"
5284     "for (var prop in k) {"
5285     "  result.push(prop);"
5286     "}"
5287     "result"));
5288   // Check that we get all the property names returned including the
5289   // ones from the enumerators in the right order: indexed properties
5290   // in numerical order, indexed interceptor properties, named
5291   // properties in insertion order, named interceptor properties.
5292   // This order is not mandated by the spec, so this test is just
5293   // documenting our behavior.
5294   CHECK_EQ(17, result->Length());
5295   // Indexed properties in numerical order.
5296   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
5297   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
5298   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
5299   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
5300   // Indexed interceptor properties in the order they are returned
5301   // from the enumerator interceptor.
5302   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
5303   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
5304   // Named properties in insertion order.
5305   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
5306   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
5307   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
5308   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
5309   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
5310   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
5311   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
5312   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
5313   // Named interceptor properties.
5314   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
5315   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
5316   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
5317 }
5318
5319
5320 int p_getter_count;
5321 int p_getter_count2;
5322
5323
5324 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
5325   ApiTestFuzzer::Fuzz();
5326   p_getter_count++;
5327   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5328   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5329   if (name->Equals(v8_str("p1"))) {
5330     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5331   } else if (name->Equals(v8_str("p2"))) {
5332     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5333   } else if (name->Equals(v8_str("p3"))) {
5334     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5335   } else if (name->Equals(v8_str("p4"))) {
5336     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5337   }
5338   return v8::Undefined();
5339 }
5340
5341
5342 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
5343   ApiTestFuzzer::Fuzz();
5344   LocalContext context;
5345   context->Global()->Set(v8_str("o1"), obj->NewInstance());
5346   CompileRun(
5347     "o1.__proto__ = { };"
5348     "var o2 = { __proto__: o1 };"
5349     "var o3 = { __proto__: o2 };"
5350     "var o4 = { __proto__: o3 };"
5351     "for (var i = 0; i < 10; i++) o4.p4;"
5352     "for (var i = 0; i < 10; i++) o3.p3;"
5353     "for (var i = 0; i < 10; i++) o2.p2;"
5354     "for (var i = 0; i < 10; i++) o1.p1;");
5355 }
5356
5357
5358 static v8::Handle<Value> PGetter2(Local<String> name,
5359                                   const AccessorInfo& info) {
5360   ApiTestFuzzer::Fuzz();
5361   p_getter_count2++;
5362   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5363   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
5364   if (name->Equals(v8_str("p1"))) {
5365     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
5366   } else if (name->Equals(v8_str("p2"))) {
5367     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
5368   } else if (name->Equals(v8_str("p3"))) {
5369     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
5370   } else if (name->Equals(v8_str("p4"))) {
5371     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
5372   }
5373   return v8::Undefined();
5374 }
5375
5376
5377 THREADED_TEST(GetterHolders) {
5378   v8::HandleScope scope;
5379   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5380   obj->SetAccessor(v8_str("p1"), PGetter);
5381   obj->SetAccessor(v8_str("p2"), PGetter);
5382   obj->SetAccessor(v8_str("p3"), PGetter);
5383   obj->SetAccessor(v8_str("p4"), PGetter);
5384   p_getter_count = 0;
5385   RunHolderTest(obj);
5386   CHECK_EQ(40, p_getter_count);
5387 }
5388
5389
5390 THREADED_TEST(PreInterceptorHolders) {
5391   v8::HandleScope scope;
5392   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5393   obj->SetNamedPropertyHandler(PGetter2);
5394   p_getter_count2 = 0;
5395   RunHolderTest(obj);
5396   CHECK_EQ(40, p_getter_count2);
5397 }
5398
5399
5400 THREADED_TEST(ObjectInstantiation) {
5401   v8::HandleScope scope;
5402   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5403   templ->SetAccessor(v8_str("t"), PGetter2);
5404   LocalContext context;
5405   context->Global()->Set(v8_str("o"), templ->NewInstance());
5406   for (int i = 0; i < 100; i++) {
5407     v8::HandleScope inner_scope;
5408     v8::Handle<v8::Object> obj = templ->NewInstance();
5409     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
5410     context->Global()->Set(v8_str("o2"), obj);
5411     v8::Handle<Value> value =
5412         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
5413     CHECK_EQ(v8::True(), value);
5414     context->Global()->Set(v8_str("o"), obj);
5415   }
5416 }
5417
5418
5419 static int StrCmp16(uint16_t* a, uint16_t* b) {
5420   while (true) {
5421     if (*a == 0 && *b == 0) return 0;
5422     if (*a != *b) return 0 + *a - *b;
5423     a++;
5424     b++;
5425   }
5426 }
5427
5428
5429 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
5430   while (true) {
5431     if (n-- == 0) return 0;
5432     if (*a == 0 && *b == 0) return 0;
5433     if (*a != *b) return 0 + *a - *b;
5434     a++;
5435     b++;
5436   }
5437 }
5438
5439
5440 THREADED_TEST(StringWrite) {
5441   LocalContext context;
5442   v8::HandleScope scope;
5443   v8::Handle<String> str = v8_str("abcde");
5444   // abc<Icelandic eth><Unicode snowman>.
5445   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
5446   const int kStride = 4;  // Must match stride in for loops in JS below.
5447   CompileRun(
5448       "var left = '';"
5449       "for (var i = 0; i < 0xd800; i += 4) {"
5450       "  left = left + String.fromCharCode(i);"
5451       "}");
5452   CompileRun(
5453       "var right = '';"
5454       "for (var i = 0; i < 0xd800; i += 4) {"
5455       "  right = String.fromCharCode(i) + right;"
5456       "}");
5457   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
5458   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
5459   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
5460
5461   CHECK_EQ(5, str2->Length());
5462   CHECK_EQ(0xd800 / kStride, left_tree->Length());
5463   CHECK_EQ(0xd800 / kStride, right_tree->Length());
5464
5465   char buf[100];
5466   char utf8buf[0xd800 * 3];
5467   uint16_t wbuf[100];
5468   int len;
5469   int charlen;
5470
5471   memset(utf8buf, 0x1, 1000);
5472   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
5473   CHECK_EQ(9, len);
5474   CHECK_EQ(5, charlen);
5475   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5476
5477   memset(utf8buf, 0x1, 1000);
5478   len = str2->WriteUtf8(utf8buf, 8, &charlen);
5479   CHECK_EQ(8, len);
5480   CHECK_EQ(5, charlen);
5481   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
5482
5483   memset(utf8buf, 0x1, 1000);
5484   len = str2->WriteUtf8(utf8buf, 7, &charlen);
5485   CHECK_EQ(5, len);
5486   CHECK_EQ(4, charlen);
5487   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5488
5489   memset(utf8buf, 0x1, 1000);
5490   len = str2->WriteUtf8(utf8buf, 6, &charlen);
5491   CHECK_EQ(5, len);
5492   CHECK_EQ(4, charlen);
5493   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5494
5495   memset(utf8buf, 0x1, 1000);
5496   len = str2->WriteUtf8(utf8buf, 5, &charlen);
5497   CHECK_EQ(5, len);
5498   CHECK_EQ(4, charlen);
5499   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
5500
5501   memset(utf8buf, 0x1, 1000);
5502   len = str2->WriteUtf8(utf8buf, 4, &charlen);
5503   CHECK_EQ(3, len);
5504   CHECK_EQ(3, charlen);
5505   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5506
5507   memset(utf8buf, 0x1, 1000);
5508   len = str2->WriteUtf8(utf8buf, 3, &charlen);
5509   CHECK_EQ(3, len);
5510   CHECK_EQ(3, charlen);
5511   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
5512
5513   memset(utf8buf, 0x1, 1000);
5514   len = str2->WriteUtf8(utf8buf, 2, &charlen);
5515   CHECK_EQ(2, len);
5516   CHECK_EQ(2, charlen);
5517   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
5518
5519   memset(utf8buf, 0x1, sizeof(utf8buf));
5520   len = left_tree->Utf8Length();
5521   int utf8_expected =
5522       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
5523   CHECK_EQ(utf8_expected, len);
5524   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5525   CHECK_EQ(utf8_expected, len);
5526   CHECK_EQ(0xd800 / kStride, charlen);
5527   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
5528   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
5529   CHECK_EQ(0xc0 - kStride,
5530            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
5531   CHECK_EQ(1, utf8buf[utf8_expected]);
5532
5533   memset(utf8buf, 0x1, sizeof(utf8buf));
5534   len = right_tree->Utf8Length();
5535   CHECK_EQ(utf8_expected, len);
5536   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
5537   CHECK_EQ(utf8_expected, len);
5538   CHECK_EQ(0xd800 / kStride, charlen);
5539   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
5540   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
5541   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
5542   CHECK_EQ(1, utf8buf[utf8_expected]);
5543
5544   memset(buf, 0x1, sizeof(buf));
5545   memset(wbuf, 0x1, sizeof(wbuf));
5546   len = str->WriteAscii(buf);
5547   CHECK_EQ(5, len);
5548   len = str->Write(wbuf);
5549   CHECK_EQ(5, len);
5550   CHECK_EQ(0, strcmp("abcde", buf));
5551   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5552   CHECK_EQ(0, StrCmp16(answer1, wbuf));
5553
5554   memset(buf, 0x1, sizeof(buf));
5555   memset(wbuf, 0x1, sizeof(wbuf));
5556   len = str->WriteAscii(buf, 0, 4);
5557   CHECK_EQ(4, len);
5558   len = str->Write(wbuf, 0, 4);
5559   CHECK_EQ(4, len);
5560   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
5561   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
5562   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
5563
5564   memset(buf, 0x1, sizeof(buf));
5565   memset(wbuf, 0x1, sizeof(wbuf));
5566   len = str->WriteAscii(buf, 0, 5);
5567   CHECK_EQ(5, len);
5568   len = str->Write(wbuf, 0, 5);
5569   CHECK_EQ(5, len);
5570   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
5571   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
5572   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
5573
5574   memset(buf, 0x1, sizeof(buf));
5575   memset(wbuf, 0x1, sizeof(wbuf));
5576   len = str->WriteAscii(buf, 0, 6);
5577   CHECK_EQ(5, len);
5578   len = str->Write(wbuf, 0, 6);
5579   CHECK_EQ(5, len);
5580   CHECK_EQ(0, strcmp("abcde", buf));
5581   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5582   CHECK_EQ(0, StrCmp16(answer4, wbuf));
5583
5584   memset(buf, 0x1, sizeof(buf));
5585   memset(wbuf, 0x1, sizeof(wbuf));
5586   len = str->WriteAscii(buf, 4, -1);
5587   CHECK_EQ(1, len);
5588   len = str->Write(wbuf, 4, -1);
5589   CHECK_EQ(1, len);
5590   CHECK_EQ(0, strcmp("e", buf));
5591   uint16_t answer5[] = {'e', '\0'};
5592   CHECK_EQ(0, StrCmp16(answer5, wbuf));
5593
5594   memset(buf, 0x1, sizeof(buf));
5595   memset(wbuf, 0x1, sizeof(wbuf));
5596   len = str->WriteAscii(buf, 4, 6);
5597   CHECK_EQ(1, len);
5598   len = str->Write(wbuf, 4, 6);
5599   CHECK_EQ(1, len);
5600   CHECK_EQ(0, strcmp("e", buf));
5601   CHECK_EQ(0, StrCmp16(answer5, wbuf));
5602
5603   memset(buf, 0x1, sizeof(buf));
5604   memset(wbuf, 0x1, sizeof(wbuf));
5605   len = str->WriteAscii(buf, 4, 1);
5606   CHECK_EQ(1, len);
5607   len = str->Write(wbuf, 4, 1);
5608   CHECK_EQ(1, len);
5609   CHECK_EQ(0, strncmp("e\1", buf, 2));
5610   uint16_t answer6[] = {'e', 0x101};
5611   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
5612
5613   memset(buf, 0x1, sizeof(buf));
5614   memset(wbuf, 0x1, sizeof(wbuf));
5615   len = str->WriteAscii(buf, 3, 1);
5616   CHECK_EQ(1, len);
5617   len = str->Write(wbuf, 3, 1);
5618   CHECK_EQ(1, len);
5619   CHECK_EQ(0, strncmp("d\1", buf, 2));
5620   uint16_t answer7[] = {'d', 0x101};
5621   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
5622
5623   memset(wbuf, 0x1, sizeof(wbuf));
5624   wbuf[5] = 'X';
5625   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
5626   CHECK_EQ(5, len);
5627   CHECK_EQ('X', wbuf[5]);
5628   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
5629   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
5630   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
5631   CHECK_NE(0, StrCmp16(answer8b, wbuf));
5632   wbuf[5] = '\0';
5633   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
5634
5635   memset(buf, 0x1, sizeof(buf));
5636   buf[5] = 'X';
5637   len = str->WriteAscii(buf, 0, 6, String::NO_NULL_TERMINATION);
5638   CHECK_EQ(5, len);
5639   CHECK_EQ('X', buf[5]);
5640   CHECK_EQ(0, strncmp("abcde", buf, 5));
5641   CHECK_NE(0, strcmp("abcde", buf));
5642   buf[5] = '\0';
5643   CHECK_EQ(0, strcmp("abcde", buf));
5644
5645   memset(utf8buf, 0x1, sizeof(utf8buf));
5646   utf8buf[8] = 'X';
5647   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
5648                         String::NO_NULL_TERMINATION);
5649   CHECK_EQ(8, len);
5650   CHECK_EQ('X', utf8buf[8]);
5651   CHECK_EQ(5, charlen);
5652   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
5653   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5654   utf8buf[8] = '\0';
5655   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
5656 }
5657
5658
5659 THREADED_TEST(ToArrayIndex) {
5660   v8::HandleScope scope;
5661   LocalContext context;
5662
5663   v8::Handle<String> str = v8_str("42");
5664   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
5665   CHECK(!index.IsEmpty());
5666   CHECK_EQ(42.0, index->Uint32Value());
5667   str = v8_str("42asdf");
5668   index = str->ToArrayIndex();
5669   CHECK(index.IsEmpty());
5670   str = v8_str("-42");
5671   index = str->ToArrayIndex();
5672   CHECK(index.IsEmpty());
5673   str = v8_str("4294967295");
5674   index = str->ToArrayIndex();
5675   CHECK(!index.IsEmpty());
5676   CHECK_EQ(4294967295.0, index->Uint32Value());
5677   v8::Handle<v8::Number> num = v8::Number::New(1);
5678   index = num->ToArrayIndex();
5679   CHECK(!index.IsEmpty());
5680   CHECK_EQ(1.0, index->Uint32Value());
5681   num = v8::Number::New(-1);
5682   index = num->ToArrayIndex();
5683   CHECK(index.IsEmpty());
5684   v8::Handle<v8::Object> obj = v8::Object::New();
5685   index = obj->ToArrayIndex();
5686   CHECK(index.IsEmpty());
5687 }
5688
5689
5690 THREADED_TEST(ErrorConstruction) {
5691   v8::HandleScope scope;
5692   LocalContext context;
5693
5694   v8::Handle<String> foo = v8_str("foo");
5695   v8::Handle<String> message = v8_str("message");
5696   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
5697   CHECK(range_error->IsObject());
5698   v8::Handle<v8::Object> range_obj(range_error.As<v8::Object>());
5699   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
5700   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
5701   CHECK(reference_error->IsObject());
5702   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
5703   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
5704   CHECK(syntax_error->IsObject());
5705   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
5706   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
5707   CHECK(type_error->IsObject());
5708   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
5709   v8::Handle<Value> error = v8::Exception::Error(foo);
5710   CHECK(error->IsObject());
5711   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
5712 }
5713
5714
5715 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
5716   ApiTestFuzzer::Fuzz();
5717   return v8_num(10);
5718 }
5719
5720
5721 static void YSetter(Local<String> name,
5722                     Local<Value> value,
5723                     const AccessorInfo& info) {
5724   if (info.This()->Has(name)) {
5725     info.This()->Delete(name);
5726   }
5727   info.This()->Set(name, value);
5728 }
5729
5730
5731 THREADED_TEST(DeleteAccessor) {
5732   v8::HandleScope scope;
5733   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
5734   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
5735   LocalContext context;
5736   v8::Handle<v8::Object> holder = obj->NewInstance();
5737   context->Global()->Set(v8_str("holder"), holder);
5738   v8::Handle<Value> result = CompileRun(
5739       "holder.y = 11; holder.y = 12; holder.y");
5740   CHECK_EQ(12, result->Uint32Value());
5741 }
5742
5743
5744 THREADED_TEST(TypeSwitch) {
5745   v8::HandleScope scope;
5746   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
5747   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
5748   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
5749   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
5750   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
5751   LocalContext context;
5752   v8::Handle<v8::Object> obj0 = v8::Object::New();
5753   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
5754   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
5755   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
5756   for (int i = 0; i < 10; i++) {
5757     CHECK_EQ(0, type_switch->match(obj0));
5758     CHECK_EQ(1, type_switch->match(obj1));
5759     CHECK_EQ(2, type_switch->match(obj2));
5760     CHECK_EQ(3, type_switch->match(obj3));
5761     CHECK_EQ(3, type_switch->match(obj3));
5762     CHECK_EQ(2, type_switch->match(obj2));
5763     CHECK_EQ(1, type_switch->match(obj1));
5764     CHECK_EQ(0, type_switch->match(obj0));
5765   }
5766 }
5767
5768
5769 // For use within the TestSecurityHandler() test.
5770 static bool g_security_callback_result = false;
5771 static bool NamedSecurityTestCallback(Local<v8::Object> global,
5772                                       Local<Value> name,
5773                                       v8::AccessType type,
5774                                       Local<Value> data) {
5775   // Always allow read access.
5776   if (type == v8::ACCESS_GET)
5777     return true;
5778
5779   // Sometimes allow other access.
5780   return g_security_callback_result;
5781 }
5782
5783
5784 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
5785                                         uint32_t key,
5786                                         v8::AccessType type,
5787                                         Local<Value> data) {
5788   // Always allow read access.
5789   if (type == v8::ACCESS_GET)
5790     return true;
5791
5792   // Sometimes allow other access.
5793   return g_security_callback_result;
5794 }
5795
5796
5797 static int trouble_nesting = 0;
5798 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
5799   ApiTestFuzzer::Fuzz();
5800   trouble_nesting++;
5801
5802   // Call a JS function that throws an uncaught exception.
5803   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
5804   Local<Value> trouble_callee = (trouble_nesting == 3) ?
5805     arg_this->Get(v8_str("trouble_callee")) :
5806     arg_this->Get(v8_str("trouble_caller"));
5807   CHECK(trouble_callee->IsFunction());
5808   return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
5809 }
5810
5811
5812 static int report_count = 0;
5813 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
5814                                              v8::Handle<Value>) {
5815   report_count++;
5816 }
5817
5818
5819 // Counts uncaught exceptions, but other tests running in parallel
5820 // also have uncaught exceptions.
5821 TEST(ApiUncaughtException) {
5822   report_count = 0;
5823   v8::HandleScope scope;
5824   LocalContext env;
5825   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
5826
5827   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5828   v8::Local<v8::Object> global = env->Global();
5829   global->Set(v8_str("trouble"), fun->GetFunction());
5830
5831   Script::Compile(v8_str("function trouble_callee() {"
5832                          "  var x = null;"
5833                          "  return x.foo;"
5834                          "};"
5835                          "function trouble_caller() {"
5836                          "  trouble();"
5837                          "};"))->Run();
5838   Local<Value> trouble = global->Get(v8_str("trouble"));
5839   CHECK(trouble->IsFunction());
5840   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
5841   CHECK(trouble_callee->IsFunction());
5842   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
5843   CHECK(trouble_caller->IsFunction());
5844   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
5845   CHECK_EQ(1, report_count);
5846   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
5847 }
5848
5849 static const char* script_resource_name = "ExceptionInNativeScript.js";
5850 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
5851                                                 v8::Handle<Value>) {
5852   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
5853   CHECK(!name_val.IsEmpty() && name_val->IsString());
5854   v8::String::AsciiValue name(message->GetScriptResourceName());
5855   CHECK_EQ(script_resource_name, *name);
5856   CHECK_EQ(3, message->GetLineNumber());
5857   v8::String::AsciiValue source_line(message->GetSourceLine());
5858   CHECK_EQ("  new o.foo();", *source_line);
5859 }
5860
5861 TEST(ExceptionInNativeScript) {
5862   v8::HandleScope scope;
5863   LocalContext env;
5864   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
5865
5866   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
5867   v8::Local<v8::Object> global = env->Global();
5868   global->Set(v8_str("trouble"), fun->GetFunction());
5869
5870   Script::Compile(v8_str("function trouble() {\n"
5871                          "  var o = {};\n"
5872                          "  new o.foo();\n"
5873                          "};"), v8::String::New(script_resource_name))->Run();
5874   Local<Value> trouble = global->Get(v8_str("trouble"));
5875   CHECK(trouble->IsFunction());
5876   Function::Cast(*trouble)->Call(global, 0, NULL);
5877   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
5878 }
5879
5880
5881 TEST(CompilationErrorUsingTryCatchHandler) {
5882   v8::HandleScope scope;
5883   LocalContext env;
5884   v8::TryCatch try_catch;
5885   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
5886   CHECK_NE(NULL, *try_catch.Exception());
5887   CHECK(try_catch.HasCaught());
5888 }
5889
5890
5891 TEST(TryCatchFinallyUsingTryCatchHandler) {
5892   v8::HandleScope scope;
5893   LocalContext env;
5894   v8::TryCatch try_catch;
5895   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
5896   CHECK(!try_catch.HasCaught());
5897   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
5898   CHECK(try_catch.HasCaught());
5899   try_catch.Reset();
5900   Script::Compile(v8_str("(function() {"
5901                          "try { throw ''; } finally { return; }"
5902                          "})()"))->Run();
5903   CHECK(!try_catch.HasCaught());
5904   Script::Compile(v8_str("(function()"
5905                          "  { try { throw ''; } finally { throw 0; }"
5906                          "})()"))->Run();
5907   CHECK(try_catch.HasCaught());
5908 }
5909
5910
5911 // SecurityHandler can't be run twice
5912 TEST(SecurityHandler) {
5913   v8::HandleScope scope0;
5914   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5915   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
5916                                            IndexedSecurityTestCallback);
5917   // Create an environment
5918   v8::Persistent<Context> context0 =
5919     Context::New(NULL, global_template);
5920   context0->Enter();
5921
5922   v8::Handle<v8::Object> global0 = context0->Global();
5923   v8::Handle<Script> script0 = v8_compile("foo = 111");
5924   script0->Run();
5925   global0->Set(v8_str("0"), v8_num(999));
5926   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
5927   CHECK_EQ(111, foo0->Int32Value());
5928   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
5929   CHECK_EQ(999, z0->Int32Value());
5930
5931   // Create another environment, should fail security checks.
5932   v8::HandleScope scope1;
5933
5934   v8::Persistent<Context> context1 =
5935     Context::New(NULL, global_template);
5936   context1->Enter();
5937
5938   v8::Handle<v8::Object> global1 = context1->Global();
5939   global1->Set(v8_str("othercontext"), global0);
5940   // This set will fail the security check.
5941   v8::Handle<Script> script1 =
5942     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
5943   script1->Run();
5944   // This read will pass the security check.
5945   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
5946   CHECK_EQ(111, foo1->Int32Value());
5947   // This read will pass the security check.
5948   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
5949   CHECK_EQ(999, z1->Int32Value());
5950
5951   // Create another environment, should pass security checks.
5952   { g_security_callback_result = true;  // allow security handler to pass.
5953     v8::HandleScope scope2;
5954     LocalContext context2;
5955     v8::Handle<v8::Object> global2 = context2->Global();
5956     global2->Set(v8_str("othercontext"), global0);
5957     v8::Handle<Script> script2 =
5958         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
5959     script2->Run();
5960     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
5961     CHECK_EQ(333, foo2->Int32Value());
5962     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
5963     CHECK_EQ(888, z2->Int32Value());
5964   }
5965
5966   context1->Exit();
5967   context1.Dispose();
5968
5969   context0->Exit();
5970   context0.Dispose();
5971 }
5972
5973
5974 THREADED_TEST(SecurityChecks) {
5975   v8::HandleScope handle_scope;
5976   LocalContext env1;
5977   v8::Persistent<Context> env2 = Context::New();
5978
5979   Local<Value> foo = v8_str("foo");
5980   Local<Value> bar = v8_str("bar");
5981
5982   // Set to the same domain.
5983   env1->SetSecurityToken(foo);
5984
5985   // Create a function in env1.
5986   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
5987   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
5988   CHECK(spy->IsFunction());
5989
5990   // Create another function accessing global objects.
5991   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
5992   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
5993   CHECK(spy2->IsFunction());
5994
5995   // Switch to env2 in the same domain and invoke spy on env2.
5996   {
5997     env2->SetSecurityToken(foo);
5998     // Enter env2
5999     Context::Scope scope_env2(env2);
6000     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
6001     CHECK(result->IsFunction());
6002   }
6003
6004   {
6005     env2->SetSecurityToken(bar);
6006     Context::Scope scope_env2(env2);
6007
6008     // Call cross_domain_call, it should throw an exception
6009     v8::TryCatch try_catch;
6010     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
6011     CHECK(try_catch.HasCaught());
6012   }
6013
6014   env2.Dispose();
6015 }
6016
6017
6018 // Regression test case for issue 1183439.
6019 THREADED_TEST(SecurityChecksForPrototypeChain) {
6020   v8::HandleScope scope;
6021   LocalContext current;
6022   v8::Persistent<Context> other = Context::New();
6023
6024   // Change context to be able to get to the Object function in the
6025   // other context without hitting the security checks.
6026   v8::Local<Value> other_object;
6027   { Context::Scope scope(other);
6028     other_object = other->Global()->Get(v8_str("Object"));
6029     other->Global()->Set(v8_num(42), v8_num(87));
6030   }
6031
6032   current->Global()->Set(v8_str("other"), other->Global());
6033   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
6034
6035   // Make sure the security check fails here and we get an undefined
6036   // result instead of getting the Object function. Repeat in a loop
6037   // to make sure to exercise the IC code.
6038   v8::Local<Script> access_other0 = v8_compile("other.Object");
6039   v8::Local<Script> access_other1 = v8_compile("other[42]");
6040   for (int i = 0; i < 5; i++) {
6041     CHECK(!access_other0->Run()->Equals(other_object));
6042     CHECK(access_other0->Run()->IsUndefined());
6043     CHECK(!access_other1->Run()->Equals(v8_num(87)));
6044     CHECK(access_other1->Run()->IsUndefined());
6045   }
6046
6047   // Create an object that has 'other' in its prototype chain and make
6048   // sure we cannot access the Object function indirectly through
6049   // that. Repeat in a loop to make sure to exercise the IC code.
6050   v8_compile("function F() { };"
6051              "F.prototype = other;"
6052              "var f = new F();")->Run();
6053   v8::Local<Script> access_f0 = v8_compile("f.Object");
6054   v8::Local<Script> access_f1 = v8_compile("f[42]");
6055   for (int j = 0; j < 5; j++) {
6056     CHECK(!access_f0->Run()->Equals(other_object));
6057     CHECK(access_f0->Run()->IsUndefined());
6058     CHECK(!access_f1->Run()->Equals(v8_num(87)));
6059     CHECK(access_f1->Run()->IsUndefined());
6060   }
6061
6062   // Now it gets hairy: Set the prototype for the other global object
6063   // to be the current global object. The prototype chain for 'f' now
6064   // goes through 'other' but ends up in the current global object.
6065   { Context::Scope scope(other);
6066     other->Global()->Set(v8_str("__proto__"), current->Global());
6067   }
6068   // Set a named and an index property on the current global
6069   // object. To force the lookup to go through the other global object,
6070   // the properties must not exist in the other global object.
6071   current->Global()->Set(v8_str("foo"), v8_num(100));
6072   current->Global()->Set(v8_num(99), v8_num(101));
6073   // Try to read the properties from f and make sure that the access
6074   // gets stopped by the security checks on the other global object.
6075   Local<Script> access_f2 = v8_compile("f.foo");
6076   Local<Script> access_f3 = v8_compile("f[99]");
6077   for (int k = 0; k < 5; k++) {
6078     CHECK(!access_f2->Run()->Equals(v8_num(100)));
6079     CHECK(access_f2->Run()->IsUndefined());
6080     CHECK(!access_f3->Run()->Equals(v8_num(101)));
6081     CHECK(access_f3->Run()->IsUndefined());
6082   }
6083   other.Dispose();
6084 }
6085
6086
6087 THREADED_TEST(CrossDomainDelete) {
6088   v8::HandleScope handle_scope;
6089   LocalContext env1;
6090   v8::Persistent<Context> env2 = Context::New();
6091
6092   Local<Value> foo = v8_str("foo");
6093   Local<Value> bar = v8_str("bar");
6094
6095   // Set to the same domain.
6096   env1->SetSecurityToken(foo);
6097   env2->SetSecurityToken(foo);
6098
6099   env1->Global()->Set(v8_str("prop"), v8_num(3));
6100   env2->Global()->Set(v8_str("env1"), env1->Global());
6101
6102   // Change env2 to a different domain and delete env1.prop.
6103   env2->SetSecurityToken(bar);
6104   {
6105     Context::Scope scope_env2(env2);
6106     Local<Value> result =
6107         Script::Compile(v8_str("delete env1.prop"))->Run();
6108     CHECK(result->IsFalse());
6109   }
6110
6111   // Check that env1.prop still exists.
6112   Local<Value> v = env1->Global()->Get(v8_str("prop"));
6113   CHECK(v->IsNumber());
6114   CHECK_EQ(3, v->Int32Value());
6115
6116   env2.Dispose();
6117 }
6118
6119
6120 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
6121   v8::HandleScope handle_scope;
6122   LocalContext env1;
6123   v8::Persistent<Context> env2 = Context::New();
6124
6125   Local<Value> foo = v8_str("foo");
6126   Local<Value> bar = v8_str("bar");
6127
6128   // Set to the same domain.
6129   env1->SetSecurityToken(foo);
6130   env2->SetSecurityToken(foo);
6131
6132   env1->Global()->Set(v8_str("prop"), v8_num(3));
6133   env2->Global()->Set(v8_str("env1"), env1->Global());
6134
6135   // env1.prop is enumerable in env2.
6136   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
6137   {
6138     Context::Scope scope_env2(env2);
6139     Local<Value> result = Script::Compile(test)->Run();
6140     CHECK(result->IsTrue());
6141   }
6142
6143   // Change env2 to a different domain and test again.
6144   env2->SetSecurityToken(bar);
6145   {
6146     Context::Scope scope_env2(env2);
6147     Local<Value> result = Script::Compile(test)->Run();
6148     CHECK(result->IsFalse());
6149   }
6150
6151   env2.Dispose();
6152 }
6153
6154
6155 THREADED_TEST(CrossDomainForIn) {
6156   v8::HandleScope handle_scope;
6157   LocalContext env1;
6158   v8::Persistent<Context> env2 = Context::New();
6159
6160   Local<Value> foo = v8_str("foo");
6161   Local<Value> bar = v8_str("bar");
6162
6163   // Set to the same domain.
6164   env1->SetSecurityToken(foo);
6165   env2->SetSecurityToken(foo);
6166
6167   env1->Global()->Set(v8_str("prop"), v8_num(3));
6168   env2->Global()->Set(v8_str("env1"), env1->Global());
6169
6170   // Change env2 to a different domain and set env1's global object
6171   // as the __proto__ of an object in env2 and enumerate properties
6172   // in for-in. It shouldn't enumerate properties on env1's global
6173   // object.
6174   env2->SetSecurityToken(bar);
6175   {
6176     Context::Scope scope_env2(env2);
6177     Local<Value> result =
6178         CompileRun("(function(){var obj = {'__proto__':env1};"
6179                    "for (var p in obj)"
6180                    "   if (p == 'prop') return false;"
6181                    "return true;})()");
6182     CHECK(result->IsTrue());
6183   }
6184   env2.Dispose();
6185 }
6186
6187
6188 TEST(ContextDetachGlobal) {
6189   v8::HandleScope handle_scope;
6190   LocalContext env1;
6191   v8::Persistent<Context> env2 = Context::New();
6192
6193   Local<v8::Object> global1 = env1->Global();
6194
6195   Local<Value> foo = v8_str("foo");
6196
6197   // Set to the same domain.
6198   env1->SetSecurityToken(foo);
6199   env2->SetSecurityToken(foo);
6200
6201   // Enter env2
6202   env2->Enter();
6203
6204   // Create a function in env2 and add a reference to it in env1.
6205   Local<v8::Object> global2 = env2->Global();
6206   global2->Set(v8_str("prop"), v8::Integer::New(1));
6207   CompileRun("function getProp() {return prop;}");
6208
6209   env1->Global()->Set(v8_str("getProp"),
6210                       global2->Get(v8_str("getProp")));
6211
6212   // Detach env2's global, and reuse the global object of env2
6213   env2->Exit();
6214   env2->DetachGlobal();
6215   // env2 has a new global object.
6216   CHECK(!env2->Global()->Equals(global2));
6217
6218   v8::Persistent<Context> env3 =
6219       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6220   env3->SetSecurityToken(v8_str("bar"));
6221   env3->Enter();
6222
6223   Local<v8::Object> global3 = env3->Global();
6224   CHECK_EQ(global2, global3);
6225   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
6226   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
6227   global3->Set(v8_str("prop"), v8::Integer::New(-1));
6228   global3->Set(v8_str("prop2"), v8::Integer::New(2));
6229   env3->Exit();
6230
6231   // Call getProp in env1, and it should return the value 1
6232   {
6233     Local<Value> get_prop = global1->Get(v8_str("getProp"));
6234     CHECK(get_prop->IsFunction());
6235     v8::TryCatch try_catch;
6236     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
6237     CHECK(!try_catch.HasCaught());
6238     CHECK_EQ(1, r->Int32Value());
6239   }
6240
6241   // Check that env3 is not accessible from env1
6242   {
6243     Local<Value> r = global3->Get(v8_str("prop2"));
6244     CHECK(r->IsUndefined());
6245   }
6246
6247   env2.Dispose();
6248   env3.Dispose();
6249 }
6250
6251
6252 TEST(DetachAndReattachGlobal) {
6253   v8::HandleScope scope;
6254   LocalContext env1;
6255
6256   // Create second environment.
6257   v8::Persistent<Context> env2 = Context::New();
6258
6259   Local<Value> foo = v8_str("foo");
6260
6261   // Set same security token for env1 and env2.
6262   env1->SetSecurityToken(foo);
6263   env2->SetSecurityToken(foo);
6264
6265   // Create a property on the global object in env2.
6266   {
6267     v8::Context::Scope scope(env2);
6268     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
6269   }
6270
6271   // Create a reference to env2 global from env1 global.
6272   env1->Global()->Set(v8_str("other"), env2->Global());
6273
6274   // Check that we have access to other.p in env2 from env1.
6275   Local<Value> result = CompileRun("other.p");
6276   CHECK(result->IsInt32());
6277   CHECK_EQ(42, result->Int32Value());
6278
6279   // Hold on to global from env2 and detach global from env2.
6280   Local<v8::Object> global2 = env2->Global();
6281   env2->DetachGlobal();
6282
6283   // Check that the global has been detached. No other.p property can
6284   // be found.
6285   result = CompileRun("other.p");
6286   CHECK(result->IsUndefined());
6287
6288   // Reuse global2 for env3.
6289   v8::Persistent<Context> env3 =
6290       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
6291   CHECK_EQ(global2, env3->Global());
6292
6293   // Start by using the same security token for env3 as for env1 and env2.
6294   env3->SetSecurityToken(foo);
6295
6296   // Create a property on the global object in env3.
6297   {
6298     v8::Context::Scope scope(env3);
6299     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
6300   }
6301
6302   // Check that other.p is now the property in env3 and that we have access.
6303   result = CompileRun("other.p");
6304   CHECK(result->IsInt32());
6305   CHECK_EQ(24, result->Int32Value());
6306
6307   // Change security token for env3 to something different from env1 and env2.
6308   env3->SetSecurityToken(v8_str("bar"));
6309
6310   // Check that we do not have access to other.p in env1. |other| is now
6311   // the global object for env3 which has a different security token,
6312   // so access should be blocked.
6313   result = CompileRun("other.p");
6314   CHECK(result->IsUndefined());
6315
6316   // Detach the global for env3 and reattach it to env2.
6317   env3->DetachGlobal();
6318   env2->ReattachGlobal(global2);
6319
6320   // Check that we have access to other.p again in env1.  |other| is now
6321   // the global object for env2 which has the same security token as env1.
6322   result = CompileRun("other.p");
6323   CHECK(result->IsInt32());
6324   CHECK_EQ(42, result->Int32Value());
6325
6326   env2.Dispose();
6327   env3.Dispose();
6328 }
6329
6330
6331 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
6332 static bool NamedAccessBlocker(Local<v8::Object> global,
6333                                Local<Value> name,
6334                                v8::AccessType type,
6335                                Local<Value> data) {
6336   return Context::GetCurrent()->Global()->Equals(global) ||
6337       allowed_access_type[type];
6338 }
6339
6340
6341 static bool IndexedAccessBlocker(Local<v8::Object> global,
6342                                  uint32_t key,
6343                                  v8::AccessType type,
6344                                  Local<Value> data) {
6345   return Context::GetCurrent()->Global()->Equals(global) ||
6346       allowed_access_type[type];
6347 }
6348
6349
6350 static int g_echo_value = -1;
6351 static v8::Handle<Value> EchoGetter(Local<String> name,
6352                                     const AccessorInfo& info) {
6353   return v8_num(g_echo_value);
6354 }
6355
6356
6357 static void EchoSetter(Local<String> name,
6358                        Local<Value> value,
6359                        const AccessorInfo&) {
6360   if (value->IsNumber())
6361     g_echo_value = value->Int32Value();
6362 }
6363
6364
6365 static v8::Handle<Value> UnreachableGetter(Local<String> name,
6366                                            const AccessorInfo& info) {
6367   CHECK(false);  // This function should not be called..
6368   return v8::Undefined();
6369 }
6370
6371
6372 static void UnreachableSetter(Local<String>, Local<Value>,
6373                               const AccessorInfo&) {
6374   CHECK(false);  // This function should nto be called.
6375 }
6376
6377
6378 TEST(AccessControl) {
6379   v8::HandleScope handle_scope;
6380   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6381
6382   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6383                                            IndexedAccessBlocker);
6384
6385   // Add an accessor accessible by cross-domain JS code.
6386   global_template->SetAccessor(
6387       v8_str("accessible_prop"),
6388       EchoGetter, EchoSetter,
6389       v8::Handle<Value>(),
6390       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6391
6392   // Add an accessor that is not accessible by cross-domain JS code.
6393   global_template->SetAccessor(v8_str("blocked_prop"),
6394                                UnreachableGetter, UnreachableSetter,
6395                                v8::Handle<Value>(),
6396                                v8::DEFAULT);
6397
6398   // Create an environment
6399   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6400   context0->Enter();
6401
6402   v8::Handle<v8::Object> global0 = context0->Global();
6403
6404   // Define a property with JS getter and setter.
6405   CompileRun(
6406       "function getter() { return 'getter'; };\n"
6407       "function setter() { return 'setter'; }\n"
6408       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
6409
6410   Local<Value> getter = global0->Get(v8_str("getter"));
6411   Local<Value> setter = global0->Get(v8_str("setter"));
6412
6413   // And define normal element.
6414   global0->Set(239, v8_str("239"));
6415
6416   // Define an element with JS getter and setter.
6417   CompileRun(
6418       "function el_getter() { return 'el_getter'; };\n"
6419       "function el_setter() { return 'el_setter'; };\n"
6420       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
6421
6422   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
6423   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
6424
6425   v8::HandleScope scope1;
6426
6427   v8::Persistent<Context> context1 = Context::New();
6428   context1->Enter();
6429
6430   v8::Handle<v8::Object> global1 = context1->Global();
6431   global1->Set(v8_str("other"), global0);
6432
6433   // Access blocked property.
6434   CompileRun("other.blocked_prop = 1");
6435
6436   ExpectUndefined("other.blocked_prop");
6437   ExpectUndefined(
6438       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6439   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
6440
6441   // Enable ACCESS_HAS
6442   allowed_access_type[v8::ACCESS_HAS] = true;
6443   ExpectUndefined("other.blocked_prop");
6444   // ... and now we can get the descriptor...
6445   ExpectUndefined(
6446       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
6447   // ... and enumerate the property.
6448   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
6449   allowed_access_type[v8::ACCESS_HAS] = false;
6450
6451   // Access blocked element.
6452   CompileRun("other[239] = 1");
6453
6454   ExpectUndefined("other[239]");
6455   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
6456   ExpectFalse("propertyIsEnumerable.call(other, '239')");
6457
6458   // Enable ACCESS_HAS
6459   allowed_access_type[v8::ACCESS_HAS] = true;
6460   ExpectUndefined("other[239]");
6461   // ... and now we can get the descriptor...
6462   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
6463   // ... and enumerate the property.
6464   ExpectTrue("propertyIsEnumerable.call(other, '239')");
6465   allowed_access_type[v8::ACCESS_HAS] = false;
6466
6467   // Access a property with JS accessor.
6468   CompileRun("other.js_accessor_p = 2");
6469
6470   ExpectUndefined("other.js_accessor_p");
6471   ExpectUndefined(
6472       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
6473
6474   // Enable ACCESS_HAS.
6475   allowed_access_type[v8::ACCESS_HAS] = true;
6476   ExpectUndefined("other.js_accessor_p");
6477   ExpectUndefined(
6478       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6479   ExpectUndefined(
6480       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6481   ExpectUndefined(
6482       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6483   allowed_access_type[v8::ACCESS_HAS] = false;
6484
6485   // Enable both ACCESS_HAS and ACCESS_GET.
6486   allowed_access_type[v8::ACCESS_HAS] = true;
6487   allowed_access_type[v8::ACCESS_GET] = true;
6488
6489   ExpectString("other.js_accessor_p", "getter");
6490   ExpectObject(
6491       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6492   ExpectUndefined(
6493       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
6494   ExpectUndefined(
6495       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6496
6497   allowed_access_type[v8::ACCESS_GET] = false;
6498   allowed_access_type[v8::ACCESS_HAS] = false;
6499
6500   // Enable both ACCESS_HAS and ACCESS_SET.
6501   allowed_access_type[v8::ACCESS_HAS] = true;
6502   allowed_access_type[v8::ACCESS_SET] = true;
6503
6504   ExpectUndefined("other.js_accessor_p");
6505   ExpectUndefined(
6506       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
6507   ExpectObject(
6508       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6509   ExpectUndefined(
6510       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6511
6512   allowed_access_type[v8::ACCESS_SET] = false;
6513   allowed_access_type[v8::ACCESS_HAS] = false;
6514
6515   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6516   allowed_access_type[v8::ACCESS_HAS] = true;
6517   allowed_access_type[v8::ACCESS_GET] = true;
6518   allowed_access_type[v8::ACCESS_SET] = true;
6519
6520   ExpectString("other.js_accessor_p", "getter");
6521   ExpectObject(
6522       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
6523   ExpectObject(
6524       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
6525   ExpectUndefined(
6526       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
6527
6528   allowed_access_type[v8::ACCESS_SET] = false;
6529   allowed_access_type[v8::ACCESS_GET] = false;
6530   allowed_access_type[v8::ACCESS_HAS] = false;
6531
6532   // Access an element with JS accessor.
6533   CompileRun("other[42] = 2");
6534
6535   ExpectUndefined("other[42]");
6536   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
6537
6538   // Enable ACCESS_HAS.
6539   allowed_access_type[v8::ACCESS_HAS] = true;
6540   ExpectUndefined("other[42]");
6541   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6542   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6543   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6544   allowed_access_type[v8::ACCESS_HAS] = false;
6545
6546   // Enable both ACCESS_HAS and ACCESS_GET.
6547   allowed_access_type[v8::ACCESS_HAS] = true;
6548   allowed_access_type[v8::ACCESS_GET] = true;
6549
6550   ExpectString("other[42]", "el_getter");
6551   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6552   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
6553   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6554
6555   allowed_access_type[v8::ACCESS_GET] = false;
6556   allowed_access_type[v8::ACCESS_HAS] = false;
6557
6558   // Enable both ACCESS_HAS and ACCESS_SET.
6559   allowed_access_type[v8::ACCESS_HAS] = true;
6560   allowed_access_type[v8::ACCESS_SET] = true;
6561
6562   ExpectUndefined("other[42]");
6563   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
6564   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6565   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6566
6567   allowed_access_type[v8::ACCESS_SET] = false;
6568   allowed_access_type[v8::ACCESS_HAS] = false;
6569
6570   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
6571   allowed_access_type[v8::ACCESS_HAS] = true;
6572   allowed_access_type[v8::ACCESS_GET] = true;
6573   allowed_access_type[v8::ACCESS_SET] = true;
6574
6575   ExpectString("other[42]", "el_getter");
6576   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
6577   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
6578   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
6579
6580   allowed_access_type[v8::ACCESS_SET] = false;
6581   allowed_access_type[v8::ACCESS_GET] = false;
6582   allowed_access_type[v8::ACCESS_HAS] = false;
6583
6584   v8::Handle<Value> value;
6585
6586   // Access accessible property
6587   value = CompileRun("other.accessible_prop = 3");
6588   CHECK(value->IsNumber());
6589   CHECK_EQ(3, value->Int32Value());
6590   CHECK_EQ(3, g_echo_value);
6591
6592   value = CompileRun("other.accessible_prop");
6593   CHECK(value->IsNumber());
6594   CHECK_EQ(3, value->Int32Value());
6595
6596   value = CompileRun(
6597       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
6598   CHECK(value->IsNumber());
6599   CHECK_EQ(3, value->Int32Value());
6600
6601   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
6602   CHECK(value->IsTrue());
6603
6604   // Enumeration doesn't enumerate accessors from inaccessible objects in
6605   // the prototype chain even if the accessors are in themselves accessible.
6606   value =
6607       CompileRun("(function(){var obj = {'__proto__':other};"
6608                  "for (var p in obj)"
6609                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
6610                  "     return false;"
6611                  "   }"
6612                  "return true;})()");
6613   CHECK(value->IsTrue());
6614
6615   context1->Exit();
6616   context0->Exit();
6617   context1.Dispose();
6618   context0.Dispose();
6619 }
6620
6621
6622 TEST(AccessControlES5) {
6623   v8::HandleScope handle_scope;
6624   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6625
6626   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
6627                                            IndexedAccessBlocker);
6628
6629   // Add accessible accessor.
6630   global_template->SetAccessor(
6631       v8_str("accessible_prop"),
6632       EchoGetter, EchoSetter,
6633       v8::Handle<Value>(),
6634       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
6635
6636
6637   // Add an accessor that is not accessible by cross-domain JS code.
6638   global_template->SetAccessor(v8_str("blocked_prop"),
6639                                UnreachableGetter, UnreachableSetter,
6640                                v8::Handle<Value>(),
6641                                v8::DEFAULT);
6642
6643   // Create an environment
6644   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6645   context0->Enter();
6646
6647   v8::Handle<v8::Object> global0 = context0->Global();
6648
6649   v8::Persistent<Context> context1 = Context::New();
6650   context1->Enter();
6651   v8::Handle<v8::Object> global1 = context1->Global();
6652   global1->Set(v8_str("other"), global0);
6653
6654   // Regression test for issue 1154.
6655   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
6656
6657   ExpectUndefined("other.blocked_prop");
6658
6659   // Regression test for issue 1027.
6660   CompileRun("Object.defineProperty(\n"
6661              "  other, 'blocked_prop', {configurable: false})");
6662   ExpectUndefined("other.blocked_prop");
6663   ExpectUndefined(
6664       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
6665
6666   // Regression test for issue 1171.
6667   ExpectTrue("Object.isExtensible(other)");
6668   CompileRun("Object.preventExtensions(other)");
6669   ExpectTrue("Object.isExtensible(other)");
6670
6671   // Object.seal and Object.freeze.
6672   CompileRun("Object.freeze(other)");
6673   ExpectTrue("Object.isExtensible(other)");
6674
6675   CompileRun("Object.seal(other)");
6676   ExpectTrue("Object.isExtensible(other)");
6677
6678   // Regression test for issue 1250.
6679   // Make sure that we can set the accessible accessors value using normal
6680   // assignment.
6681   CompileRun("other.accessible_prop = 42");
6682   CHECK_EQ(42, g_echo_value);
6683
6684   v8::Handle<Value> value;
6685   // We follow Safari in ignoring assignments to host object accessors.
6686   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
6687   value = CompileRun("other.accessible_prop == 42");
6688   CHECK(value->IsTrue());
6689 }
6690
6691
6692 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
6693                                             Local<Value> name,
6694                                             v8::AccessType type,
6695                                             Local<Value> data) {
6696   return false;
6697 }
6698
6699
6700 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
6701                                               uint32_t key,
6702                                               v8::AccessType type,
6703                                               Local<Value> data) {
6704   return false;
6705 }
6706
6707
6708 THREADED_TEST(AccessControlGetOwnPropertyNames) {
6709   v8::HandleScope handle_scope;
6710   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6711
6712   obj_template->Set(v8_str("x"), v8::Integer::New(42));
6713   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
6714                                         GetOwnPropertyNamesIndexedBlocker);
6715
6716   // Create an environment
6717   v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
6718   context0->Enter();
6719
6720   v8::Handle<v8::Object> global0 = context0->Global();
6721
6722   v8::HandleScope scope1;
6723
6724   v8::Persistent<Context> context1 = Context::New();
6725   context1->Enter();
6726
6727   v8::Handle<v8::Object> global1 = context1->Global();
6728   global1->Set(v8_str("other"), global0);
6729   global1->Set(v8_str("object"), obj_template->NewInstance());
6730
6731   v8::Handle<Value> value;
6732
6733   // Attempt to get the property names of the other global object and
6734   // of an object that requires access checks.  Accessing the other
6735   // global object should be blocked by access checks on the global
6736   // proxy object.  Accessing the object that requires access checks
6737   // is blocked by the access checks on the object itself.
6738   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
6739   CHECK(value->IsTrue());
6740
6741   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
6742   CHECK(value->IsTrue());
6743
6744   context1->Exit();
6745   context0->Exit();
6746   context1.Dispose();
6747   context0.Dispose();
6748 }
6749
6750
6751 static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) {
6752   v8::Handle<v8::Array> result = v8::Array::New(1);
6753   result->Set(0, v8_str("x"));
6754   return result;
6755 }
6756
6757
6758 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
6759   v8::HandleScope handle_scope;
6760   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
6761
6762   obj_template->Set(v8_str("x"), v8::Integer::New(42));
6763   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
6764                                         NamedPropertyEnumerator);
6765
6766   LocalContext context;
6767   v8::Handle<v8::Object> global = context->Global();
6768   global->Set(v8_str("object"), obj_template->NewInstance());
6769
6770   v8::Handle<Value> value =
6771       CompileRun("Object.getOwnPropertyNames(object).join(',')");
6772   CHECK_EQ(v8_str("x"), value);
6773 }
6774
6775
6776 static v8::Handle<Value> ConstTenGetter(Local<String> name,
6777                                         const AccessorInfo& info) {
6778   return v8_num(10);
6779 }
6780
6781
6782 THREADED_TEST(CrossDomainAccessors) {
6783   v8::HandleScope handle_scope;
6784
6785   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
6786
6787   v8::Handle<v8::ObjectTemplate> global_template =
6788       func_template->InstanceTemplate();
6789
6790   v8::Handle<v8::ObjectTemplate> proto_template =
6791       func_template->PrototypeTemplate();
6792
6793   // Add an accessor to proto that's accessible by cross-domain JS code.
6794   proto_template->SetAccessor(v8_str("accessible"),
6795                               ConstTenGetter, 0,
6796                               v8::Handle<Value>(),
6797                               v8::ALL_CAN_READ);
6798
6799   // Add an accessor that is not accessible by cross-domain JS code.
6800   global_template->SetAccessor(v8_str("unreachable"),
6801                                UnreachableGetter, 0,
6802                                v8::Handle<Value>(),
6803                                v8::DEFAULT);
6804
6805   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6806   context0->Enter();
6807
6808   Local<v8::Object> global = context0->Global();
6809   // Add a normal property that shadows 'accessible'
6810   global->Set(v8_str("accessible"), v8_num(11));
6811
6812   // Enter a new context.
6813   v8::HandleScope scope1;
6814   v8::Persistent<Context> context1 = Context::New();
6815   context1->Enter();
6816
6817   v8::Handle<v8::Object> global1 = context1->Global();
6818   global1->Set(v8_str("other"), global);
6819
6820   // Should return 10, instead of 11
6821   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
6822   CHECK(value->IsNumber());
6823   CHECK_EQ(10, value->Int32Value());
6824
6825   value = v8_compile("other.unreachable")->Run();
6826   CHECK(value->IsUndefined());
6827
6828   context1->Exit();
6829   context0->Exit();
6830   context1.Dispose();
6831   context0.Dispose();
6832 }
6833
6834
6835 static int named_access_count = 0;
6836 static int indexed_access_count = 0;
6837
6838 static bool NamedAccessCounter(Local<v8::Object> global,
6839                                Local<Value> name,
6840                                v8::AccessType type,
6841                                Local<Value> data) {
6842   named_access_count++;
6843   return true;
6844 }
6845
6846
6847 static bool IndexedAccessCounter(Local<v8::Object> global,
6848                                  uint32_t key,
6849                                  v8::AccessType type,
6850                                  Local<Value> data) {
6851   indexed_access_count++;
6852   return true;
6853 }
6854
6855
6856 // This one is too easily disturbed by other tests.
6857 TEST(AccessControlIC) {
6858   named_access_count = 0;
6859   indexed_access_count = 0;
6860
6861   v8::HandleScope handle_scope;
6862
6863   // Create an environment.
6864   v8::Persistent<Context> context0 = Context::New();
6865   context0->Enter();
6866
6867   // Create an object that requires access-check functions to be
6868   // called for cross-domain access.
6869   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
6870   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
6871                                            IndexedAccessCounter);
6872   Local<v8::Object> object = object_template->NewInstance();
6873
6874   v8::HandleScope scope1;
6875
6876   // Create another environment.
6877   v8::Persistent<Context> context1 = Context::New();
6878   context1->Enter();
6879
6880   // Make easy access to the object from the other environment.
6881   v8::Handle<v8::Object> global1 = context1->Global();
6882   global1->Set(v8_str("obj"), object);
6883
6884   v8::Handle<Value> value;
6885
6886   // Check that the named access-control function is called every time.
6887   CompileRun("function testProp(obj) {"
6888              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
6889              "  for (var j = 0; j < 10; j++) obj.prop;"
6890              "  return obj.prop"
6891              "}");
6892   value = CompileRun("testProp(obj)");
6893   CHECK(value->IsNumber());
6894   CHECK_EQ(1, value->Int32Value());
6895   CHECK_EQ(21, named_access_count);
6896
6897   // Check that the named access-control function is called every time.
6898   CompileRun("var p = 'prop';"
6899              "function testKeyed(obj) {"
6900              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
6901              "  for (var j = 0; j < 10; j++) obj[p];"
6902              "  return obj[p];"
6903              "}");
6904   // Use obj which requires access checks.  No inline caching is used
6905   // in that case.
6906   value = CompileRun("testKeyed(obj)");
6907   CHECK(value->IsNumber());
6908   CHECK_EQ(1, value->Int32Value());
6909   CHECK_EQ(42, named_access_count);
6910   // Force the inline caches into generic state and try again.
6911   CompileRun("testKeyed({ a: 0 })");
6912   CompileRun("testKeyed({ b: 0 })");
6913   value = CompileRun("testKeyed(obj)");
6914   CHECK(value->IsNumber());
6915   CHECK_EQ(1, value->Int32Value());
6916   CHECK_EQ(63, named_access_count);
6917
6918   // Check that the indexed access-control function is called every time.
6919   CompileRun("function testIndexed(obj) {"
6920              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
6921              "  for (var j = 0; j < 10; j++) obj[0];"
6922              "  return obj[0]"
6923              "}");
6924   value = CompileRun("testIndexed(obj)");
6925   CHECK(value->IsNumber());
6926   CHECK_EQ(1, value->Int32Value());
6927   CHECK_EQ(21, indexed_access_count);
6928   // Force the inline caches into generic state.
6929   CompileRun("testIndexed(new Array(1))");
6930   // Test that the indexed access check is called.
6931   value = CompileRun("testIndexed(obj)");
6932   CHECK(value->IsNumber());
6933   CHECK_EQ(1, value->Int32Value());
6934   CHECK_EQ(42, indexed_access_count);
6935
6936   // Check that the named access check is called when invoking
6937   // functions on an object that requires access checks.
6938   CompileRun("obj.f = function() {}");
6939   CompileRun("function testCallNormal(obj) {"
6940              "  for (var i = 0; i < 10; i++) obj.f();"
6941              "}");
6942   CompileRun("testCallNormal(obj)");
6943   CHECK_EQ(74, named_access_count);
6944
6945   // Force obj into slow case.
6946   value = CompileRun("delete obj.prop");
6947   CHECK(value->BooleanValue());
6948   // Force inline caches into dictionary probing mode.
6949   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
6950   // Test that the named access check is called.
6951   value = CompileRun("testProp(obj);");
6952   CHECK(value->IsNumber());
6953   CHECK_EQ(1, value->Int32Value());
6954   CHECK_EQ(96, named_access_count);
6955
6956   // Force the call inline cache into dictionary probing mode.
6957   CompileRun("o.f = function() {}; testCallNormal(o)");
6958   // Test that the named access check is still called for each
6959   // invocation of the function.
6960   value = CompileRun("testCallNormal(obj)");
6961   CHECK_EQ(106, named_access_count);
6962
6963   context1->Exit();
6964   context0->Exit();
6965   context1.Dispose();
6966   context0.Dispose();
6967 }
6968
6969
6970 static bool NamedAccessFlatten(Local<v8::Object> global,
6971                                Local<Value> name,
6972                                v8::AccessType type,
6973                                Local<Value> data) {
6974   char buf[100];
6975   int len;
6976
6977   CHECK(name->IsString());
6978
6979   memset(buf, 0x1, sizeof(buf));
6980   len = name.As<String>()->WriteAscii(buf);
6981   CHECK_EQ(4, len);
6982
6983   uint16_t buf2[100];
6984
6985   memset(buf, 0x1, sizeof(buf));
6986   len = name.As<String>()->Write(buf2);
6987   CHECK_EQ(4, len);
6988
6989   return true;
6990 }
6991
6992
6993 static bool IndexedAccessFlatten(Local<v8::Object> global,
6994                                  uint32_t key,
6995                                  v8::AccessType type,
6996                                  Local<Value> data) {
6997   return true;
6998 }
6999
7000
7001 // Regression test.  In access checks, operations that may cause
7002 // garbage collection are not allowed.  It used to be the case that
7003 // using the Write operation on a string could cause a garbage
7004 // collection due to flattening of the string.  This is no longer the
7005 // case.
7006 THREADED_TEST(AccessControlFlatten) {
7007   named_access_count = 0;
7008   indexed_access_count = 0;
7009
7010   v8::HandleScope handle_scope;
7011
7012   // Create an environment.
7013   v8::Persistent<Context> context0 = Context::New();
7014   context0->Enter();
7015
7016   // Create an object that requires access-check functions to be
7017   // called for cross-domain access.
7018   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7019   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
7020                                            IndexedAccessFlatten);
7021   Local<v8::Object> object = object_template->NewInstance();
7022
7023   v8::HandleScope scope1;
7024
7025   // Create another environment.
7026   v8::Persistent<Context> context1 = Context::New();
7027   context1->Enter();
7028
7029   // Make easy access to the object from the other environment.
7030   v8::Handle<v8::Object> global1 = context1->Global();
7031   global1->Set(v8_str("obj"), object);
7032
7033   v8::Handle<Value> value;
7034
7035   value = v8_compile("var p = 'as' + 'df';")->Run();
7036   value = v8_compile("obj[p];")->Run();
7037
7038   context1->Exit();
7039   context0->Exit();
7040   context1.Dispose();
7041   context0.Dispose();
7042 }
7043
7044
7045 static v8::Handle<Value> AccessControlNamedGetter(
7046     Local<String>, const AccessorInfo&) {
7047   return v8::Integer::New(42);
7048 }
7049
7050
7051 static v8::Handle<Value> AccessControlNamedSetter(
7052     Local<String>, Local<Value> value, const AccessorInfo&) {
7053   return value;
7054 }
7055
7056
7057 static v8::Handle<Value> AccessControlIndexedGetter(
7058       uint32_t index,
7059       const AccessorInfo& info) {
7060   return v8_num(42);
7061 }
7062
7063
7064 static v8::Handle<Value> AccessControlIndexedSetter(
7065     uint32_t, Local<Value> value, const AccessorInfo&) {
7066   return value;
7067 }
7068
7069
7070 THREADED_TEST(AccessControlInterceptorIC) {
7071   named_access_count = 0;
7072   indexed_access_count = 0;
7073
7074   v8::HandleScope handle_scope;
7075
7076   // Create an environment.
7077   v8::Persistent<Context> context0 = Context::New();
7078   context0->Enter();
7079
7080   // Create an object that requires access-check functions to be
7081   // called for cross-domain access.  The object also has interceptors
7082   // interceptor.
7083   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
7084   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
7085                                            IndexedAccessCounter);
7086   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
7087                                            AccessControlNamedSetter);
7088   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
7089                                              AccessControlIndexedSetter);
7090   Local<v8::Object> object = object_template->NewInstance();
7091
7092   v8::HandleScope scope1;
7093
7094   // Create another environment.
7095   v8::Persistent<Context> context1 = Context::New();
7096   context1->Enter();
7097
7098   // Make easy access to the object from the other environment.
7099   v8::Handle<v8::Object> global1 = context1->Global();
7100   global1->Set(v8_str("obj"), object);
7101
7102   v8::Handle<Value> value;
7103
7104   // Check that the named access-control function is called every time
7105   // eventhough there is an interceptor on the object.
7106   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
7107   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
7108                      "obj.x")->Run();
7109   CHECK(value->IsNumber());
7110   CHECK_EQ(42, value->Int32Value());
7111   CHECK_EQ(21, named_access_count);
7112
7113   value = v8_compile("var p = 'x';")->Run();
7114   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
7115   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
7116                      "obj[p]")->Run();
7117   CHECK(value->IsNumber());
7118   CHECK_EQ(42, value->Int32Value());
7119   CHECK_EQ(42, named_access_count);
7120
7121   // Check that the indexed access-control function is called every
7122   // time eventhough there is an interceptor on the object.
7123   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
7124   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
7125                      "obj[0]")->Run();
7126   CHECK(value->IsNumber());
7127   CHECK_EQ(42, value->Int32Value());
7128   CHECK_EQ(21, indexed_access_count);
7129
7130   context1->Exit();
7131   context0->Exit();
7132   context1.Dispose();
7133   context0.Dispose();
7134 }
7135
7136
7137 THREADED_TEST(Version) {
7138   v8::V8::GetVersion();
7139 }
7140
7141
7142 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
7143   ApiTestFuzzer::Fuzz();
7144   return v8_num(12);
7145 }
7146
7147
7148 THREADED_TEST(InstanceProperties) {
7149   v8::HandleScope handle_scope;
7150   LocalContext context;
7151
7152   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7153   Local<ObjectTemplate> instance = t->InstanceTemplate();
7154
7155   instance->Set(v8_str("x"), v8_num(42));
7156   instance->Set(v8_str("f"),
7157                 v8::FunctionTemplate::New(InstanceFunctionCallback));
7158
7159   Local<Value> o = t->GetFunction()->NewInstance();
7160
7161   context->Global()->Set(v8_str("i"), o);
7162   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
7163   CHECK_EQ(42, value->Int32Value());
7164
7165   value = Script::Compile(v8_str("i.f()"))->Run();
7166   CHECK_EQ(12, value->Int32Value());
7167 }
7168
7169
7170 static v8::Handle<Value>
7171 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
7172   ApiTestFuzzer::Fuzz();
7173   return v8::Handle<Value>();
7174 }
7175
7176
7177 THREADED_TEST(GlobalObjectInstanceProperties) {
7178   v8::HandleScope handle_scope;
7179
7180   Local<Value> global_object;
7181
7182   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7183   t->InstanceTemplate()->SetNamedPropertyHandler(
7184       GlobalObjectInstancePropertiesGet);
7185   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7186   instance_template->Set(v8_str("x"), v8_num(42));
7187   instance_template->Set(v8_str("f"),
7188                          v8::FunctionTemplate::New(InstanceFunctionCallback));
7189
7190   // The script to check how Crankshaft compiles missing global function
7191   // invocations.  function g is not defined and should throw on call.
7192   const char* script =
7193       "function wrapper(call) {"
7194       "  var x = 0, y = 1;"
7195       "  for (var i = 0; i < 1000; i++) {"
7196       "    x += i * 100;"
7197       "    y += i * 100;"
7198       "  }"
7199       "  if (call) g();"
7200       "}"
7201       "for (var i = 0; i < 17; i++) wrapper(false);"
7202       "var thrown = 0;"
7203       "try { wrapper(true); } catch (e) { thrown = 1; };"
7204       "thrown";
7205
7206   {
7207     LocalContext env(NULL, instance_template);
7208     // Hold on to the global object so it can be used again in another
7209     // environment initialization.
7210     global_object = env->Global();
7211
7212     Local<Value> value = Script::Compile(v8_str("x"))->Run();
7213     CHECK_EQ(42, value->Int32Value());
7214     value = Script::Compile(v8_str("f()"))->Run();
7215     CHECK_EQ(12, value->Int32Value());
7216     value = Script::Compile(v8_str(script))->Run();
7217     CHECK_EQ(1, value->Int32Value());
7218   }
7219
7220   {
7221     // Create new environment reusing the global object.
7222     LocalContext env(NULL, instance_template, global_object);
7223     Local<Value> value = Script::Compile(v8_str("x"))->Run();
7224     CHECK_EQ(42, value->Int32Value());
7225     value = Script::Compile(v8_str("f()"))->Run();
7226     CHECK_EQ(12, value->Int32Value());
7227     value = Script::Compile(v8_str(script))->Run();
7228     CHECK_EQ(1, value->Int32Value());
7229   }
7230 }
7231
7232
7233 THREADED_TEST(CallKnownGlobalReceiver) {
7234   v8::HandleScope handle_scope;
7235
7236   Local<Value> global_object;
7237
7238   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7239   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7240
7241   // The script to check that we leave global object not
7242   // global object proxy on stack when we deoptimize from inside
7243   // arguments evaluation.
7244   // To provoke error we need to both force deoptimization
7245   // from arguments evaluation and to force CallIC to take
7246   // CallIC_Miss code path that can't cope with global proxy.
7247   const char* script =
7248       "function bar(x, y) { try { } finally { } }"
7249       "function baz(x) { try { } finally { } }"
7250       "function bom(x) { try { } finally { } }"
7251       "function foo(x) { bar([x], bom(2)); }"
7252       "for (var i = 0; i < 10000; i++) foo(1);"
7253       "foo";
7254
7255   Local<Value> foo;
7256   {
7257     LocalContext env(NULL, instance_template);
7258     // Hold on to the global object so it can be used again in another
7259     // environment initialization.
7260     global_object = env->Global();
7261     foo = Script::Compile(v8_str(script))->Run();
7262   }
7263
7264   {
7265     // Create new environment reusing the global object.
7266     LocalContext env(NULL, instance_template, global_object);
7267     env->Global()->Set(v8_str("foo"), foo);
7268     Local<Value> value(Script::Compile(v8_str("foo()"))->Run());
7269   }
7270 }
7271
7272
7273 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
7274   ApiTestFuzzer::Fuzz();
7275   return v8_num(42);
7276 }
7277
7278
7279 static int shadow_y;
7280 static int shadow_y_setter_call_count;
7281 static int shadow_y_getter_call_count;
7282
7283
7284 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
7285   shadow_y_setter_call_count++;
7286   shadow_y = 42;
7287 }
7288
7289
7290 static v8::Handle<Value> ShadowYGetter(Local<String> name,
7291                                        const AccessorInfo& info) {
7292   ApiTestFuzzer::Fuzz();
7293   shadow_y_getter_call_count++;
7294   return v8_num(shadow_y);
7295 }
7296
7297
7298 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
7299                                           const AccessorInfo& info) {
7300   return v8::Handle<Value>();
7301 }
7302
7303
7304 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
7305                                         const AccessorInfo&) {
7306   return v8::Handle<Value>();
7307 }
7308
7309
7310 THREADED_TEST(ShadowObject) {
7311   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
7312   v8::HandleScope handle_scope;
7313
7314   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
7315   LocalContext context(NULL, global_template);
7316
7317   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7318   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
7319   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
7320   Local<ObjectTemplate> proto = t->PrototypeTemplate();
7321   Local<ObjectTemplate> instance = t->InstanceTemplate();
7322
7323   // Only allow calls of f on instances of t.
7324   Local<v8::Signature> signature = v8::Signature::New(t);
7325   proto->Set(v8_str("f"),
7326              v8::FunctionTemplate::New(ShadowFunctionCallback,
7327                                        Local<Value>(),
7328                                        signature));
7329   proto->Set(v8_str("x"), v8_num(12));
7330
7331   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
7332
7333   Local<Value> o = t->GetFunction()->NewInstance();
7334   context->Global()->Set(v8_str("__proto__"), o);
7335
7336   Local<Value> value =
7337       Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
7338   CHECK(value->IsBoolean());
7339   CHECK(!value->BooleanValue());
7340
7341   value = Script::Compile(v8_str("x"))->Run();
7342   CHECK_EQ(12, value->Int32Value());
7343
7344   value = Script::Compile(v8_str("f()"))->Run();
7345   CHECK_EQ(42, value->Int32Value());
7346
7347   Script::Compile(v8_str("y = 42"))->Run();
7348   CHECK_EQ(1, shadow_y_setter_call_count);
7349   value = Script::Compile(v8_str("y"))->Run();
7350   CHECK_EQ(1, shadow_y_getter_call_count);
7351   CHECK_EQ(42, value->Int32Value());
7352 }
7353
7354
7355 THREADED_TEST(HiddenPrototype) {
7356   v8::HandleScope handle_scope;
7357   LocalContext context;
7358
7359   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7360   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7361   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7362   t1->SetHiddenPrototype(true);
7363   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7364   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7365   t2->SetHiddenPrototype(true);
7366   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7367   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7368   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7369
7370   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7371   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7372   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7373   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7374
7375   // Setting the prototype on an object skips hidden prototypes.
7376   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7377   o0->Set(v8_str("__proto__"), o1);
7378   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7379   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7380   o0->Set(v8_str("__proto__"), o2);
7381   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7382   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7383   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7384   o0->Set(v8_str("__proto__"), o3);
7385   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7386   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7387   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7388   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7389
7390   // Getting the prototype of o0 should get the first visible one
7391   // which is o3.  Therefore, z should not be defined on the prototype
7392   // object.
7393   Local<Value> proto = o0->Get(v8_str("__proto__"));
7394   CHECK(proto->IsObject());
7395   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
7396 }
7397
7398
7399 THREADED_TEST(SetPrototype) {
7400   v8::HandleScope handle_scope;
7401   LocalContext context;
7402
7403   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
7404   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
7405   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7406   t1->SetHiddenPrototype(true);
7407   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
7408   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7409   t2->SetHiddenPrototype(true);
7410   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
7411   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
7412   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
7413
7414   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
7415   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
7416   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
7417   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
7418
7419   // Setting the prototype on an object does not skip hidden prototypes.
7420   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7421   CHECK(o0->SetPrototype(o1));
7422   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7423   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7424   CHECK(o1->SetPrototype(o2));
7425   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7426   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7427   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7428   CHECK(o2->SetPrototype(o3));
7429   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
7430   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
7431   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
7432   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
7433
7434   // Getting the prototype of o0 should get the first visible one
7435   // which is o3.  Therefore, z should not be defined on the prototype
7436   // object.
7437   Local<Value> proto = o0->Get(v8_str("__proto__"));
7438   CHECK(proto->IsObject());
7439   CHECK_EQ(proto.As<v8::Object>(), o3);
7440
7441   // However, Object::GetPrototype ignores hidden prototype.
7442   Local<Value> proto0 = o0->GetPrototype();
7443   CHECK(proto0->IsObject());
7444   CHECK_EQ(proto0.As<v8::Object>(), o1);
7445
7446   Local<Value> proto1 = o1->GetPrototype();
7447   CHECK(proto1->IsObject());
7448   CHECK_EQ(proto1.As<v8::Object>(), o2);
7449
7450   Local<Value> proto2 = o2->GetPrototype();
7451   CHECK(proto2->IsObject());
7452   CHECK_EQ(proto2.As<v8::Object>(), o3);
7453 }
7454
7455
7456 THREADED_TEST(FunctionReadOnlyPrototype) {
7457   v8::HandleScope handle_scope;
7458   LocalContext context;
7459
7460   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
7461   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7462   t1->ReadOnlyPrototype();
7463   context->Global()->Set(v8_str("func1"), t1->GetFunction());
7464   // Configured value of ReadOnly flag.
7465   CHECK(CompileRun(
7466       "(function() {"
7467       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
7468       "  return (descriptor['writable'] == false);"
7469       "})()")->BooleanValue());
7470   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
7471   CHECK_EQ(42,
7472            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
7473
7474   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
7475   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
7476   context->Global()->Set(v8_str("func2"), t2->GetFunction());
7477   // Default value of ReadOnly flag.
7478   CHECK(CompileRun(
7479       "(function() {"
7480       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
7481       "  return (descriptor['writable'] == true);"
7482       "})()")->BooleanValue());
7483   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
7484 }
7485
7486
7487 THREADED_TEST(SetPrototypeThrows) {
7488   v8::HandleScope handle_scope;
7489   LocalContext context;
7490
7491   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7492
7493   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
7494   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
7495
7496   CHECK(o0->SetPrototype(o1));
7497   // If setting the prototype leads to the cycle, SetPrototype should
7498   // return false and keep VM in sane state.
7499   v8::TryCatch try_catch;
7500   CHECK(!o1->SetPrototype(o0));
7501   CHECK(!try_catch.HasCaught());
7502   ASSERT(!i::Isolate::Current()->has_pending_exception());
7503
7504   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
7505 }
7506
7507
7508 THREADED_TEST(GetterSetterExceptions) {
7509   v8::HandleScope handle_scope;
7510   LocalContext context;
7511   CompileRun(
7512     "function Foo() { };"
7513     "function Throw() { throw 5; };"
7514     "var x = { };"
7515     "x.__defineSetter__('set', Throw);"
7516     "x.__defineGetter__('get', Throw);");
7517   Local<v8::Object> x =
7518       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
7519   v8::TryCatch try_catch;
7520   x->Set(v8_str("set"), v8::Integer::New(8));
7521   x->Get(v8_str("get"));
7522   x->Set(v8_str("set"), v8::Integer::New(8));
7523   x->Get(v8_str("get"));
7524   x->Set(v8_str("set"), v8::Integer::New(8));
7525   x->Get(v8_str("get"));
7526   x->Set(v8_str("set"), v8::Integer::New(8));
7527   x->Get(v8_str("get"));
7528 }
7529
7530
7531 THREADED_TEST(Constructor) {
7532   v8::HandleScope handle_scope;
7533   LocalContext context;
7534   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7535   templ->SetClassName(v8_str("Fun"));
7536   Local<Function> cons = templ->GetFunction();
7537   context->Global()->Set(v8_str("Fun"), cons);
7538   Local<v8::Object> inst = cons->NewInstance();
7539   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
7540   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
7541   CHECK(value->BooleanValue());
7542 }
7543
7544
7545 static Handle<Value> ConstructorCallback(const Arguments& args) {
7546   ApiTestFuzzer::Fuzz();
7547   Local<Object> This;
7548
7549   if (args.IsConstructCall()) {
7550     Local<Object> Holder = args.Holder();
7551     This = Object::New();
7552     Local<Value> proto = Holder->GetPrototype();
7553     if (proto->IsObject()) {
7554       This->SetPrototype(proto);
7555     }
7556   } else {
7557     This = args.This();
7558   }
7559
7560   This->Set(v8_str("a"), args[0]);
7561   return This;
7562 }
7563
7564
7565 static Handle<Value> FakeConstructorCallback(const Arguments& args) {
7566   ApiTestFuzzer::Fuzz();
7567   return args[0];
7568 }
7569
7570
7571 THREADED_TEST(ConstructorForObject) {
7572   v8::HandleScope handle_scope;
7573   LocalContext context;
7574
7575   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7576     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
7577     Local<Object> instance = instance_template->NewInstance();
7578     context->Global()->Set(v8_str("obj"), instance);
7579     v8::TryCatch try_catch;
7580     Local<Value> value;
7581     CHECK(!try_catch.HasCaught());
7582
7583     // Call the Object's constructor with a 32-bit signed integer.
7584     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
7585     CHECK(!try_catch.HasCaught());
7586     CHECK(value->IsInt32());
7587     CHECK_EQ(28, value->Int32Value());
7588
7589     Local<Value> args1[] = { v8_num(28) };
7590     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
7591     CHECK(value_obj1->IsObject());
7592     Local<Object> object1 = Local<Object>::Cast(value_obj1);
7593     value = object1->Get(v8_str("a"));
7594     CHECK(value->IsInt32());
7595     CHECK(!try_catch.HasCaught());
7596     CHECK_EQ(28, value->Int32Value());
7597
7598     // Call the Object's constructor with a String.
7599     value = CompileRun(
7600         "(function() { var o = new obj('tipli'); return o.a; })()");
7601     CHECK(!try_catch.HasCaught());
7602     CHECK(value->IsString());
7603     String::AsciiValue string_value1(value->ToString());
7604     CHECK_EQ("tipli", *string_value1);
7605
7606     Local<Value> args2[] = { v8_str("tipli") };
7607     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
7608     CHECK(value_obj2->IsObject());
7609     Local<Object> object2 = Local<Object>::Cast(value_obj2);
7610     value = object2->Get(v8_str("a"));
7611     CHECK(!try_catch.HasCaught());
7612     CHECK(value->IsString());
7613     String::AsciiValue string_value2(value->ToString());
7614     CHECK_EQ("tipli", *string_value2);
7615
7616     // Call the Object's constructor with a Boolean.
7617     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
7618     CHECK(!try_catch.HasCaught());
7619     CHECK(value->IsBoolean());
7620     CHECK_EQ(true, value->BooleanValue());
7621
7622     Handle<Value> args3[] = { v8::True() };
7623     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
7624     CHECK(value_obj3->IsObject());
7625     Local<Object> object3 = Local<Object>::Cast(value_obj3);
7626     value = object3->Get(v8_str("a"));
7627     CHECK(!try_catch.HasCaught());
7628     CHECK(value->IsBoolean());
7629     CHECK_EQ(true, value->BooleanValue());
7630
7631     // Call the Object's constructor with undefined.
7632     Handle<Value> args4[] = { v8::Undefined() };
7633     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
7634     CHECK(value_obj4->IsObject());
7635     Local<Object> object4 = Local<Object>::Cast(value_obj4);
7636     value = object4->Get(v8_str("a"));
7637     CHECK(!try_catch.HasCaught());
7638     CHECK(value->IsUndefined());
7639
7640     // Call the Object's constructor with null.
7641     Handle<Value> args5[] = { v8::Null() };
7642     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
7643     CHECK(value_obj5->IsObject());
7644     Local<Object> object5 = Local<Object>::Cast(value_obj5);
7645     value = object5->Get(v8_str("a"));
7646     CHECK(!try_catch.HasCaught());
7647     CHECK(value->IsNull());
7648   }
7649
7650   // Check exception handling when there is no constructor set for the Object.
7651   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7652     Local<Object> instance = instance_template->NewInstance();
7653     context->Global()->Set(v8_str("obj2"), instance);
7654     v8::TryCatch try_catch;
7655     Local<Value> value;
7656     CHECK(!try_catch.HasCaught());
7657
7658     value = CompileRun("new obj2(28)");
7659     CHECK(try_catch.HasCaught());
7660     String::AsciiValue exception_value1(try_catch.Exception());
7661     CHECK_EQ("TypeError: object is not a function", *exception_value1);
7662     try_catch.Reset();
7663
7664     Local<Value> args[] = { v8_num(29) };
7665     value = instance->CallAsConstructor(1, args);
7666     CHECK(try_catch.HasCaught());
7667     String::AsciiValue exception_value2(try_catch.Exception());
7668     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
7669     try_catch.Reset();
7670   }
7671
7672   // Check the case when constructor throws exception.
7673   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7674     instance_template->SetCallAsFunctionHandler(ThrowValue);
7675     Local<Object> instance = instance_template->NewInstance();
7676     context->Global()->Set(v8_str("obj3"), instance);
7677     v8::TryCatch try_catch;
7678     Local<Value> value;
7679     CHECK(!try_catch.HasCaught());
7680
7681     value = CompileRun("new obj3(22)");
7682     CHECK(try_catch.HasCaught());
7683     String::AsciiValue exception_value1(try_catch.Exception());
7684     CHECK_EQ("22", *exception_value1);
7685     try_catch.Reset();
7686
7687     Local<Value> args[] = { v8_num(23) };
7688     value = instance->CallAsConstructor(1, args);
7689     CHECK(try_catch.HasCaught());
7690     String::AsciiValue exception_value2(try_catch.Exception());
7691     CHECK_EQ("23", *exception_value2);
7692     try_catch.Reset();
7693   }
7694
7695   // Check whether constructor returns with an object or non-object.
7696   { Local<FunctionTemplate> function_template =
7697         FunctionTemplate::New(FakeConstructorCallback);
7698     Local<Function> function = function_template->GetFunction();
7699     Local<Object> instance1 = function;
7700     context->Global()->Set(v8_str("obj4"), instance1);
7701     v8::TryCatch try_catch;
7702     Local<Value> value;
7703     CHECK(!try_catch.HasCaught());
7704
7705     CHECK(instance1->IsObject());
7706     CHECK(instance1->IsFunction());
7707
7708     value = CompileRun("new obj4(28)");
7709     CHECK(!try_catch.HasCaught());
7710     CHECK(value->IsObject());
7711
7712     Local<Value> args1[] = { v8_num(28) };
7713     value = instance1->CallAsConstructor(1, args1);
7714     CHECK(!try_catch.HasCaught());
7715     CHECK(value->IsObject());
7716
7717     Local<ObjectTemplate> instance_template = ObjectTemplate::New();
7718     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
7719     Local<Object> instance2 = instance_template->NewInstance();
7720     context->Global()->Set(v8_str("obj5"), instance2);
7721     CHECK(!try_catch.HasCaught());
7722
7723     CHECK(instance2->IsObject());
7724     CHECK(!instance2->IsFunction());
7725
7726     value = CompileRun("new obj5(28)");
7727     CHECK(!try_catch.HasCaught());
7728     CHECK(!value->IsObject());
7729
7730     Local<Value> args2[] = { v8_num(28) };
7731     value = instance2->CallAsConstructor(1, args2);
7732     CHECK(!try_catch.HasCaught());
7733     CHECK(!value->IsObject());
7734   }
7735 }
7736
7737
7738 THREADED_TEST(FunctionDescriptorException) {
7739   v8::HandleScope handle_scope;
7740   LocalContext context;
7741   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
7742   templ->SetClassName(v8_str("Fun"));
7743   Local<Function> cons = templ->GetFunction();
7744   context->Global()->Set(v8_str("Fun"), cons);
7745   Local<Value> value = CompileRun(
7746     "function test() {"
7747     "  try {"
7748     "    (new Fun()).blah()"
7749     "  } catch (e) {"
7750     "    var str = String(e);"
7751     "    if (str.indexOf('TypeError') == -1) return 1;"
7752     "    if (str.indexOf('[object Fun]') != -1) return 2;"
7753     "    if (str.indexOf('#<Fun>') == -1) return 3;"
7754     "    return 0;"
7755     "  }"
7756     "  return 4;"
7757     "}"
7758     "test();");
7759   CHECK_EQ(0, value->Int32Value());
7760 }
7761
7762
7763 THREADED_TEST(EvalAliasedDynamic) {
7764   v8::HandleScope scope;
7765   LocalContext current;
7766
7767   // Tests where aliased eval can only be resolved dynamically.
7768   Local<Script> script =
7769       Script::Compile(v8_str("function f(x) { "
7770                              "  var foo = 2;"
7771                              "  with (x) { return eval('foo'); }"
7772                              "}"
7773                              "foo = 0;"
7774                              "result1 = f(new Object());"
7775                              "result2 = f(this);"
7776                              "var x = new Object();"
7777                              "x.eval = function(x) { return 1; };"
7778                              "result3 = f(x);"));
7779   script->Run();
7780   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
7781   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
7782   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
7783
7784   v8::TryCatch try_catch;
7785   script =
7786     Script::Compile(v8_str("function f(x) { "
7787                            "  var bar = 2;"
7788                            "  with (x) { return eval('bar'); }"
7789                            "}"
7790                            "result4 = f(this)"));
7791   script->Run();
7792   CHECK(!try_catch.HasCaught());
7793   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
7794
7795   try_catch.Reset();
7796 }
7797
7798
7799 THREADED_TEST(CrossEval) {
7800   v8::HandleScope scope;
7801   LocalContext other;
7802   LocalContext current;
7803
7804   Local<String> token = v8_str("<security token>");
7805   other->SetSecurityToken(token);
7806   current->SetSecurityToken(token);
7807
7808   // Setup reference from current to other.
7809   current->Global()->Set(v8_str("other"), other->Global());
7810
7811   // Check that new variables are introduced in other context.
7812   Local<Script> script =
7813       Script::Compile(v8_str("other.eval('var foo = 1234')"));
7814   script->Run();
7815   Local<Value> foo = other->Global()->Get(v8_str("foo"));
7816   CHECK_EQ(1234, foo->Int32Value());
7817   CHECK(!current->Global()->Has(v8_str("foo")));
7818
7819   // Check that writing to non-existing properties introduces them in
7820   // the other context.
7821   script =
7822       Script::Compile(v8_str("other.eval('na = 1234')"));
7823   script->Run();
7824   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
7825   CHECK(!current->Global()->Has(v8_str("na")));
7826
7827   // Check that global variables in current context are not visible in other
7828   // context.
7829   v8::TryCatch try_catch;
7830   script =
7831       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
7832   Local<Value> result = script->Run();
7833   CHECK(try_catch.HasCaught());
7834   try_catch.Reset();
7835
7836   // Check that local variables in current context are not visible in other
7837   // context.
7838   script =
7839       Script::Compile(v8_str("(function() { "
7840                              "  var baz = 87;"
7841                              "  return other.eval('baz');"
7842                              "})();"));
7843   result = script->Run();
7844   CHECK(try_catch.HasCaught());
7845   try_catch.Reset();
7846
7847   // Check that global variables in the other environment are visible
7848   // when evaluting code.
7849   other->Global()->Set(v8_str("bis"), v8_num(1234));
7850   script = Script::Compile(v8_str("other.eval('bis')"));
7851   CHECK_EQ(1234, script->Run()->Int32Value());
7852   CHECK(!try_catch.HasCaught());
7853
7854   // Check that the 'this' pointer points to the global object evaluating
7855   // code.
7856   other->Global()->Set(v8_str("t"), other->Global());
7857   script = Script::Compile(v8_str("other.eval('this == t')"));
7858   result = script->Run();
7859   CHECK(result->IsTrue());
7860   CHECK(!try_catch.HasCaught());
7861
7862   // Check that variables introduced in with-statement are not visible in
7863   // other context.
7864   script =
7865       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
7866   result = script->Run();
7867   CHECK(try_catch.HasCaught());
7868   try_catch.Reset();
7869
7870   // Check that you cannot use 'eval.call' with another object than the
7871   // current global object.
7872   script =
7873       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
7874   result = script->Run();
7875   CHECK(try_catch.HasCaught());
7876 }
7877
7878
7879 // Test that calling eval in a context which has been detached from
7880 // its global throws an exception.  This behavior is consistent with
7881 // other JavaScript implementations.
7882 THREADED_TEST(EvalInDetachedGlobal) {
7883   v8::HandleScope scope;
7884
7885   v8::Persistent<Context> context0 = Context::New();
7886   v8::Persistent<Context> context1 = Context::New();
7887
7888   // Setup function in context0 that uses eval from context0.
7889   context0->Enter();
7890   v8::Handle<v8::Value> fun =
7891       CompileRun("var x = 42;"
7892                  "(function() {"
7893                  "  var e = eval;"
7894                  "  return function(s) { return e(s); }"
7895                  "})()");
7896   context0->Exit();
7897
7898   // Put the function into context1 and call it before and after
7899   // detaching the global.  Before detaching, the call succeeds and
7900   // after detaching and exception is thrown.
7901   context1->Enter();
7902   context1->Global()->Set(v8_str("fun"), fun);
7903   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
7904   CHECK_EQ(42, x_value->Int32Value());
7905   context0->DetachGlobal();
7906   v8::TryCatch catcher;
7907   x_value = CompileRun("fun('x')");
7908   CHECK(x_value.IsEmpty());
7909   CHECK(catcher.HasCaught());
7910   context1->Exit();
7911
7912   context1.Dispose();
7913   context0.Dispose();
7914 }
7915
7916
7917 THREADED_TEST(CrossLazyLoad) {
7918   v8::HandleScope scope;
7919   LocalContext other;
7920   LocalContext current;
7921
7922   Local<String> token = v8_str("<security token>");
7923   other->SetSecurityToken(token);
7924   current->SetSecurityToken(token);
7925
7926   // Setup reference from current to other.
7927   current->Global()->Set(v8_str("other"), other->Global());
7928
7929   // Trigger lazy loading in other context.
7930   Local<Script> script =
7931       Script::Compile(v8_str("other.eval('new Date(42)')"));
7932   Local<Value> value = script->Run();
7933   CHECK_EQ(42.0, value->NumberValue());
7934 }
7935
7936
7937 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
7938   ApiTestFuzzer::Fuzz();
7939   if (args.IsConstructCall()) {
7940     if (args[0]->IsInt32()) {
7941        return v8_num(-args[0]->Int32Value());
7942     }
7943   }
7944
7945   return args[0];
7946 }
7947
7948
7949 // Test that a call handler can be set for objects which will allow
7950 // non-function objects created through the API to be called as
7951 // functions.
7952 THREADED_TEST(CallAsFunction) {
7953   v8::HandleScope scope;
7954   LocalContext context;
7955
7956   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
7957     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
7958     instance_template->SetCallAsFunctionHandler(call_as_function);
7959     Local<v8::Object> instance = t->GetFunction()->NewInstance();
7960     context->Global()->Set(v8_str("obj"), instance);
7961     v8::TryCatch try_catch;
7962     Local<Value> value;
7963     CHECK(!try_catch.HasCaught());
7964
7965     value = CompileRun("obj(42)");
7966     CHECK(!try_catch.HasCaught());
7967     CHECK_EQ(42, value->Int32Value());
7968
7969     value = CompileRun("(function(o){return o(49)})(obj)");
7970     CHECK(!try_catch.HasCaught());
7971     CHECK_EQ(49, value->Int32Value());
7972
7973     // test special case of call as function
7974     value = CompileRun("[obj]['0'](45)");
7975     CHECK(!try_catch.HasCaught());
7976     CHECK_EQ(45, value->Int32Value());
7977
7978     value = CompileRun("obj.call = Function.prototype.call;"
7979                        "obj.call(null, 87)");
7980     CHECK(!try_catch.HasCaught());
7981     CHECK_EQ(87, value->Int32Value());
7982
7983     // Regression tests for bug #1116356: Calling call through call/apply
7984     // must work for non-function receivers.
7985     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
7986     value = CompileRun(apply_99);
7987     CHECK(!try_catch.HasCaught());
7988     CHECK_EQ(99, value->Int32Value());
7989
7990     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
7991     value = CompileRun(call_17);
7992     CHECK(!try_catch.HasCaught());
7993     CHECK_EQ(17, value->Int32Value());
7994
7995     // Check that the call-as-function handler can be called through
7996     // new.
7997     value = CompileRun("new obj(43)");
7998     CHECK(!try_catch.HasCaught());
7999     CHECK_EQ(-43, value->Int32Value());
8000
8001     // Check that the call-as-function handler can be called through
8002     // the API.
8003     v8::Handle<Value> args[] = { v8_num(28) };
8004     value = instance->CallAsFunction(instance, 1, args);
8005     CHECK(!try_catch.HasCaught());
8006     CHECK_EQ(28, value->Int32Value());
8007   }
8008
8009   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8010     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
8011     Local<v8::Object> instance = t->GetFunction()->NewInstance();
8012     context->Global()->Set(v8_str("obj2"), instance);
8013     v8::TryCatch try_catch;
8014     Local<Value> value;
8015     CHECK(!try_catch.HasCaught());
8016
8017     // Call an object without call-as-function handler through the JS
8018     value = CompileRun("obj2(28)");
8019     CHECK(value.IsEmpty());
8020     CHECK(try_catch.HasCaught());
8021     String::AsciiValue exception_value1(try_catch.Exception());
8022     CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
8023              *exception_value1);
8024     try_catch.Reset();
8025
8026     // Call an object without call-as-function handler through the API
8027     value = CompileRun("obj2(28)");
8028     v8::Handle<Value> args[] = { v8_num(28) };
8029     value = instance->CallAsFunction(instance, 1, args);
8030     CHECK(value.IsEmpty());
8031     CHECK(try_catch.HasCaught());
8032     String::AsciiValue exception_value2(try_catch.Exception());
8033     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
8034     try_catch.Reset();
8035   }
8036
8037   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8038     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8039     instance_template->SetCallAsFunctionHandler(ThrowValue);
8040     Local<v8::Object> instance = t->GetFunction()->NewInstance();
8041     context->Global()->Set(v8_str("obj3"), instance);
8042     v8::TryCatch try_catch;
8043     Local<Value> value;
8044     CHECK(!try_catch.HasCaught());
8045
8046     // Catch the exception which is thrown by call-as-function handler
8047     value = CompileRun("obj3(22)");
8048     CHECK(try_catch.HasCaught());
8049     String::AsciiValue exception_value1(try_catch.Exception());
8050     CHECK_EQ("22", *exception_value1);
8051     try_catch.Reset();
8052
8053     v8::Handle<Value> args[] = { v8_num(23) };
8054     value = instance->CallAsFunction(instance, 1, args);
8055     CHECK(try_catch.HasCaught());
8056     String::AsciiValue exception_value2(try_catch.Exception());
8057     CHECK_EQ("23", *exception_value2);
8058     try_catch.Reset();
8059   }
8060 }
8061
8062
8063 // Check whether a non-function object is callable.
8064 THREADED_TEST(CallableObject) {
8065   v8::HandleScope scope;
8066   LocalContext context;
8067
8068   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8069     instance_template->SetCallAsFunctionHandler(call_as_function);
8070     Local<Object> instance = instance_template->NewInstance();
8071     v8::TryCatch try_catch;
8072
8073     CHECK(instance->IsCallable());
8074     CHECK(!try_catch.HasCaught());
8075   }
8076
8077   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
8078     Local<Object> instance = instance_template->NewInstance();
8079     v8::TryCatch try_catch;
8080
8081     CHECK(!instance->IsCallable());
8082     CHECK(!try_catch.HasCaught());
8083   }
8084
8085   { Local<FunctionTemplate> function_template =
8086         FunctionTemplate::New(call_as_function);
8087     Local<Function> function = function_template->GetFunction();
8088     Local<Object> instance = function;
8089     v8::TryCatch try_catch;
8090
8091     CHECK(instance->IsCallable());
8092     CHECK(!try_catch.HasCaught());
8093   }
8094
8095   { Local<FunctionTemplate> function_template = FunctionTemplate::New();
8096     Local<Function> function = function_template->GetFunction();
8097     Local<Object> instance = function;
8098     v8::TryCatch try_catch;
8099
8100     CHECK(instance->IsCallable());
8101     CHECK(!try_catch.HasCaught());
8102   }
8103 }
8104
8105
8106 static int CountHandles() {
8107   return v8::HandleScope::NumberOfHandles();
8108 }
8109
8110
8111 static int Recurse(int depth, int iterations) {
8112   v8::HandleScope scope;
8113   if (depth == 0) return CountHandles();
8114   for (int i = 0; i < iterations; i++) {
8115     Local<v8::Number> n(v8::Integer::New(42));
8116   }
8117   return Recurse(depth - 1, iterations);
8118 }
8119
8120
8121 THREADED_TEST(HandleIteration) {
8122   static const int kIterations = 500;
8123   static const int kNesting = 200;
8124   CHECK_EQ(0, CountHandles());
8125   {
8126     v8::HandleScope scope1;
8127     CHECK_EQ(0, CountHandles());
8128     for (int i = 0; i < kIterations; i++) {
8129       Local<v8::Number> n(v8::Integer::New(42));
8130       CHECK_EQ(i + 1, CountHandles());
8131     }
8132
8133     CHECK_EQ(kIterations, CountHandles());
8134     {
8135       v8::HandleScope scope2;
8136       for (int j = 0; j < kIterations; j++) {
8137         Local<v8::Number> n(v8::Integer::New(42));
8138         CHECK_EQ(j + 1 + kIterations, CountHandles());
8139       }
8140     }
8141     CHECK_EQ(kIterations, CountHandles());
8142   }
8143   CHECK_EQ(0, CountHandles());
8144   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
8145 }
8146
8147
8148 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
8149     Local<String> name,
8150     const AccessorInfo& info) {
8151   ApiTestFuzzer::Fuzz();
8152   return v8::Handle<Value>();
8153 }
8154
8155
8156 THREADED_TEST(InterceptorHasOwnProperty) {
8157   v8::HandleScope scope;
8158   LocalContext context;
8159   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8160   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8161   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
8162   Local<Function> function = fun_templ->GetFunction();
8163   context->Global()->Set(v8_str("constructor"), function);
8164   v8::Handle<Value> value = CompileRun(
8165       "var o = new constructor();"
8166       "o.hasOwnProperty('ostehaps');");
8167   CHECK_EQ(false, value->BooleanValue());
8168   value = CompileRun(
8169       "o.ostehaps = 42;"
8170       "o.hasOwnProperty('ostehaps');");
8171   CHECK_EQ(true, value->BooleanValue());
8172   value = CompileRun(
8173       "var p = new constructor();"
8174       "p.hasOwnProperty('ostehaps');");
8175   CHECK_EQ(false, value->BooleanValue());
8176 }
8177
8178
8179 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
8180     Local<String> name,
8181     const AccessorInfo& info) {
8182   ApiTestFuzzer::Fuzz();
8183   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8184   return v8::Handle<Value>();
8185 }
8186
8187
8188 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
8189   v8::HandleScope scope;
8190   LocalContext context;
8191   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
8192   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
8193   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
8194   Local<Function> function = fun_templ->GetFunction();
8195   context->Global()->Set(v8_str("constructor"), function);
8196   // Let's first make some stuff so we can be sure to get a good GC.
8197   CompileRun(
8198       "function makestr(size) {"
8199       "  switch (size) {"
8200       "    case 1: return 'f';"
8201       "    case 2: return 'fo';"
8202       "    case 3: return 'foo';"
8203       "  }"
8204       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
8205       "}"
8206       "var x = makestr(12345);"
8207       "x = makestr(31415);"
8208       "x = makestr(23456);");
8209   v8::Handle<Value> value = CompileRun(
8210       "var o = new constructor();"
8211       "o.__proto__ = new String(x);"
8212       "o.hasOwnProperty('ostehaps');");
8213   CHECK_EQ(false, value->BooleanValue());
8214 }
8215
8216
8217 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
8218                                                  const AccessorInfo& info);
8219
8220
8221 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
8222                                    const char* source,
8223                                    int expected) {
8224   v8::HandleScope scope;
8225   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8226   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
8227   LocalContext context;
8228   context->Global()->Set(v8_str("o"), templ->NewInstance());
8229   v8::Handle<Value> value = CompileRun(source);
8230   CHECK_EQ(expected, value->Int32Value());
8231 }
8232
8233
8234 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
8235                                                  const AccessorInfo& info) {
8236   ApiTestFuzzer::Fuzz();
8237   CHECK_EQ(v8_str("data"), info.Data());
8238   CHECK_EQ(v8_str("x"), name);
8239   return v8::Integer::New(42);
8240 }
8241
8242
8243 // This test should hit the load IC for the interceptor case.
8244 THREADED_TEST(InterceptorLoadIC) {
8245   CheckInterceptorLoadIC(InterceptorLoadICGetter,
8246     "var result = 0;"
8247     "for (var i = 0; i < 1000; i++) {"
8248     "  result = o.x;"
8249     "}",
8250     42);
8251 }
8252
8253
8254 // Below go several tests which verify that JITing for various
8255 // configurations of interceptor and explicit fields works fine
8256 // (those cases are special cased to get better performance).
8257
8258 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
8259                                                  const AccessorInfo& info) {
8260   ApiTestFuzzer::Fuzz();
8261   return v8_str("x")->Equals(name)
8262       ? v8::Integer::New(42) : v8::Handle<v8::Value>();
8263 }
8264
8265
8266 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
8267   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8268     "var result = 0;"
8269     "o.y = 239;"
8270     "for (var i = 0; i < 1000; i++) {"
8271     "  result = o.y;"
8272     "}",
8273     239);
8274 }
8275
8276
8277 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
8278   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8279     "var result = 0;"
8280     "o.__proto__ = { 'y': 239 };"
8281     "for (var i = 0; i < 1000; i++) {"
8282     "  result = o.y + o.x;"
8283     "}",
8284     239 + 42);
8285 }
8286
8287
8288 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
8289   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8290     "var result = 0;"
8291     "o.__proto__.y = 239;"
8292     "for (var i = 0; i < 1000; i++) {"
8293     "  result = o.y + o.x;"
8294     "}",
8295     239 + 42);
8296 }
8297
8298
8299 THREADED_TEST(InterceptorLoadICUndefined) {
8300   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8301     "var result = 0;"
8302     "for (var i = 0; i < 1000; i++) {"
8303     "  result = (o.y == undefined) ? 239 : 42;"
8304     "}",
8305     239);
8306 }
8307
8308
8309 THREADED_TEST(InterceptorLoadICWithOverride) {
8310   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8311     "fst = new Object();  fst.__proto__ = o;"
8312     "snd = new Object();  snd.__proto__ = fst;"
8313     "var result1 = 0;"
8314     "for (var i = 0; i < 1000;  i++) {"
8315     "  result1 = snd.x;"
8316     "}"
8317     "fst.x = 239;"
8318     "var result = 0;"
8319     "for (var i = 0; i < 1000; i++) {"
8320     "  result = snd.x;"
8321     "}"
8322     "result + result1",
8323     239 + 42);
8324 }
8325
8326
8327 // Test the case when we stored field into
8328 // a stub, but interceptor produced value on its own.
8329 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
8330   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8331     "proto = new Object();"
8332     "o.__proto__ = proto;"
8333     "proto.x = 239;"
8334     "for (var i = 0; i < 1000; i++) {"
8335     "  o.x;"
8336     // Now it should be ICed and keep a reference to x defined on proto
8337     "}"
8338     "var result = 0;"
8339     "for (var i = 0; i < 1000; i++) {"
8340     "  result += o.x;"
8341     "}"
8342     "result;",
8343     42 * 1000);
8344 }
8345
8346
8347 // Test the case when we stored field into
8348 // a stub, but it got invalidated later on.
8349 THREADED_TEST(InterceptorLoadICInvalidatedField) {
8350   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8351     "proto1 = new Object();"
8352     "proto2 = new Object();"
8353     "o.__proto__ = proto1;"
8354     "proto1.__proto__ = proto2;"
8355     "proto2.y = 239;"
8356     "for (var i = 0; i < 1000; i++) {"
8357     "  o.y;"
8358     // Now it should be ICed and keep a reference to y defined on proto2
8359     "}"
8360     "proto1.y = 42;"
8361     "var result = 0;"
8362     "for (var i = 0; i < 1000; i++) {"
8363     "  result += o.y;"
8364     "}"
8365     "result;",
8366     42 * 1000);
8367 }
8368
8369
8370 static int interceptor_load_not_handled_calls = 0;
8371 static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name,
8372                                                    const AccessorInfo& info) {
8373   ++interceptor_load_not_handled_calls;
8374   return v8::Handle<v8::Value>();
8375 }
8376
8377
8378 // Test how post-interceptor lookups are done in the non-cacheable
8379 // case: the interceptor should not be invoked during this lookup.
8380 THREADED_TEST(InterceptorLoadICPostInterceptor) {
8381   interceptor_load_not_handled_calls = 0;
8382   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
8383     "receiver = new Object();"
8384     "receiver.__proto__ = o;"
8385     "proto = new Object();"
8386     "/* Make proto a slow-case object. */"
8387     "for (var i = 0; i < 1000; i++) {"
8388     "  proto[\"xxxxxxxx\" + i] = [];"
8389     "}"
8390     "proto.x = 17;"
8391     "o.__proto__ = proto;"
8392     "var result = 0;"
8393     "for (var i = 0; i < 1000; i++) {"
8394     "  result += receiver.x;"
8395     "}"
8396     "result;",
8397     17 * 1000);
8398   CHECK_EQ(1000, interceptor_load_not_handled_calls);
8399 }
8400
8401
8402 // Test the case when we stored field into
8403 // a stub, but it got invalidated later on due to override on
8404 // global object which is between interceptor and fields' holders.
8405 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
8406   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
8407     "o.__proto__ = this;"  // set a global to be a proto of o.
8408     "this.__proto__.y = 239;"
8409     "for (var i = 0; i < 10; i++) {"
8410     "  if (o.y != 239) throw 'oops: ' + o.y;"
8411     // Now it should be ICed and keep a reference to y defined on field_holder.
8412     "}"
8413     "this.y = 42;"  // Assign on a global.
8414     "var result = 0;"
8415     "for (var i = 0; i < 10; i++) {"
8416     "  result += o.y;"
8417     "}"
8418     "result;",
8419     42 * 10);
8420 }
8421
8422
8423 static void SetOnThis(Local<String> name,
8424                       Local<Value> value,
8425                       const AccessorInfo& info) {
8426   info.This()->ForceSet(name, value);
8427 }
8428
8429
8430 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
8431   v8::HandleScope scope;
8432   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8433   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8434   templ->SetAccessor(v8_str("y"), Return239);
8435   LocalContext context;
8436   context->Global()->Set(v8_str("o"), templ->NewInstance());
8437
8438   // Check the case when receiver and interceptor's holder
8439   // are the same objects.
8440   v8::Handle<Value> value = CompileRun(
8441       "var result = 0;"
8442       "for (var i = 0; i < 7; i++) {"
8443       "  result = o.y;"
8444       "}");
8445   CHECK_EQ(239, value->Int32Value());
8446
8447   // Check the case when interceptor's holder is in proto chain
8448   // of receiver.
8449   value = CompileRun(
8450       "r = { __proto__: o };"
8451       "var result = 0;"
8452       "for (var i = 0; i < 7; i++) {"
8453       "  result = r.y;"
8454       "}");
8455   CHECK_EQ(239, value->Int32Value());
8456 }
8457
8458
8459 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
8460   v8::HandleScope scope;
8461   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8462   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8463   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8464   templ_p->SetAccessor(v8_str("y"), Return239);
8465
8466   LocalContext context;
8467   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8468   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8469
8470   // Check the case when receiver and interceptor's holder
8471   // are the same objects.
8472   v8::Handle<Value> value = CompileRun(
8473       "o.__proto__ = p;"
8474       "var result = 0;"
8475       "for (var i = 0; i < 7; i++) {"
8476       "  result = o.x + o.y;"
8477       "}");
8478   CHECK_EQ(239 + 42, value->Int32Value());
8479
8480   // Check the case when interceptor's holder is in proto chain
8481   // of receiver.
8482   value = CompileRun(
8483       "r = { __proto__: o };"
8484       "var result = 0;"
8485       "for (var i = 0; i < 7; i++) {"
8486       "  result = r.x + r.y;"
8487       "}");
8488   CHECK_EQ(239 + 42, value->Int32Value());
8489 }
8490
8491
8492 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
8493   v8::HandleScope scope;
8494   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8495   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8496   templ->SetAccessor(v8_str("y"), Return239);
8497
8498   LocalContext context;
8499   context->Global()->Set(v8_str("o"), templ->NewInstance());
8500
8501   v8::Handle<Value> value = CompileRun(
8502     "fst = new Object();  fst.__proto__ = o;"
8503     "snd = new Object();  snd.__proto__ = fst;"
8504     "var result1 = 0;"
8505     "for (var i = 0; i < 7;  i++) {"
8506     "  result1 = snd.x;"
8507     "}"
8508     "fst.x = 239;"
8509     "var result = 0;"
8510     "for (var i = 0; i < 7; i++) {"
8511     "  result = snd.x;"
8512     "}"
8513     "result + result1");
8514   CHECK_EQ(239 + 42, value->Int32Value());
8515 }
8516
8517
8518 // Test the case when we stored callback into
8519 // a stub, but interceptor produced value on its own.
8520 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
8521   v8::HandleScope scope;
8522   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8523   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8524   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8525   templ_p->SetAccessor(v8_str("y"), Return239);
8526
8527   LocalContext context;
8528   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8529   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8530
8531   v8::Handle<Value> value = CompileRun(
8532     "o.__proto__ = p;"
8533     "for (var i = 0; i < 7; i++) {"
8534     "  o.x;"
8535     // Now it should be ICed and keep a reference to x defined on p
8536     "}"
8537     "var result = 0;"
8538     "for (var i = 0; i < 7; i++) {"
8539     "  result += o.x;"
8540     "}"
8541     "result");
8542   CHECK_EQ(42 * 7, value->Int32Value());
8543 }
8544
8545
8546 // Test the case when we stored callback into
8547 // a stub, but it got invalidated later on.
8548 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
8549   v8::HandleScope scope;
8550   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8551   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8552   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8553   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8554
8555   LocalContext context;
8556   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8557   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8558
8559   v8::Handle<Value> value = CompileRun(
8560     "inbetween = new Object();"
8561     "o.__proto__ = inbetween;"
8562     "inbetween.__proto__ = p;"
8563     "for (var i = 0; i < 10; i++) {"
8564     "  o.y;"
8565     // Now it should be ICed and keep a reference to y defined on p
8566     "}"
8567     "inbetween.y = 42;"
8568     "var result = 0;"
8569     "for (var i = 0; i < 10; i++) {"
8570     "  result += o.y;"
8571     "}"
8572     "result");
8573   CHECK_EQ(42 * 10, value->Int32Value());
8574 }
8575
8576
8577 // Test the case when we stored callback into
8578 // a stub, but it got invalidated later on due to override on
8579 // global object which is between interceptor and callbacks' holders.
8580 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
8581   v8::HandleScope scope;
8582   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8583   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8584   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
8585   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
8586
8587   LocalContext context;
8588   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8589   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
8590
8591   v8::Handle<Value> value = CompileRun(
8592     "o.__proto__ = this;"
8593     "this.__proto__ = p;"
8594     "for (var i = 0; i < 10; i++) {"
8595     "  if (o.y != 239) throw 'oops: ' + o.y;"
8596     // Now it should be ICed and keep a reference to y defined on p
8597     "}"
8598     "this.y = 42;"
8599     "var result = 0;"
8600     "for (var i = 0; i < 10; i++) {"
8601     "  result += o.y;"
8602     "}"
8603     "result");
8604   CHECK_EQ(42 * 10, value->Int32Value());
8605 }
8606
8607
8608 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
8609                                                   const AccessorInfo& info) {
8610   ApiTestFuzzer::Fuzz();
8611   CHECK(v8_str("x")->Equals(name));
8612   return v8::Integer::New(0);
8613 }
8614
8615
8616 THREADED_TEST(InterceptorReturningZero) {
8617   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
8618      "o.x == undefined ? 1 : 0",
8619      0);
8620 }
8621
8622
8623 static v8::Handle<Value> InterceptorStoreICSetter(
8624     Local<String> key, Local<Value> value, const AccessorInfo&) {
8625   CHECK(v8_str("x")->Equals(key));
8626   CHECK_EQ(42, value->Int32Value());
8627   return value;
8628 }
8629
8630
8631 // This test should hit the store IC for the interceptor case.
8632 THREADED_TEST(InterceptorStoreIC) {
8633   v8::HandleScope scope;
8634   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8635   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
8636                                  InterceptorStoreICSetter,
8637                                  0, 0, 0, v8_str("data"));
8638   LocalContext context;
8639   context->Global()->Set(v8_str("o"), templ->NewInstance());
8640   v8::Handle<Value> value(CompileRun(
8641     "for (var i = 0; i < 1000; i++) {"
8642     "  o.x = 42;"
8643     "}"));
8644 }
8645
8646
8647 THREADED_TEST(InterceptorStoreICWithNoSetter) {
8648   v8::HandleScope scope;
8649   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8650   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
8651   LocalContext context;
8652   context->Global()->Set(v8_str("o"), templ->NewInstance());
8653   v8::Handle<Value> value = CompileRun(
8654     "for (var i = 0; i < 1000; i++) {"
8655     "  o.y = 239;"
8656     "}"
8657     "42 + o.y");
8658   CHECK_EQ(239 + 42, value->Int32Value());
8659 }
8660
8661
8662
8663
8664 v8::Handle<Value> call_ic_function;
8665 v8::Handle<Value> call_ic_function2;
8666 v8::Handle<Value> call_ic_function3;
8667
8668 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
8669                                                  const AccessorInfo& info) {
8670   ApiTestFuzzer::Fuzz();
8671   CHECK(v8_str("x")->Equals(name));
8672   return call_ic_function;
8673 }
8674
8675
8676 // This test should hit the call IC for the interceptor case.
8677 THREADED_TEST(InterceptorCallIC) {
8678   v8::HandleScope scope;
8679   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8680   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
8681   LocalContext context;
8682   context->Global()->Set(v8_str("o"), templ->NewInstance());
8683   call_ic_function =
8684       v8_compile("function f(x) { return x + 1; }; f")->Run();
8685   v8::Handle<Value> value = CompileRun(
8686     "var result = 0;"
8687     "for (var i = 0; i < 1000; i++) {"
8688     "  result = o.x(41);"
8689     "}");
8690   CHECK_EQ(42, value->Int32Value());
8691 }
8692
8693
8694 // This test checks that if interceptor doesn't provide
8695 // a value, we can fetch regular value.
8696 THREADED_TEST(InterceptorCallICSeesOthers) {
8697   v8::HandleScope scope;
8698   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8699   templ->SetNamedPropertyHandler(NoBlockGetterX);
8700   LocalContext context;
8701   context->Global()->Set(v8_str("o"), templ->NewInstance());
8702   v8::Handle<Value> value = CompileRun(
8703     "o.x = function f(x) { return x + 1; };"
8704     "var result = 0;"
8705     "for (var i = 0; i < 7; i++) {"
8706     "  result = o.x(41);"
8707     "}");
8708   CHECK_EQ(42, value->Int32Value());
8709 }
8710
8711
8712 static v8::Handle<Value> call_ic_function4;
8713 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
8714                                                   const AccessorInfo& info) {
8715   ApiTestFuzzer::Fuzz();
8716   CHECK(v8_str("x")->Equals(name));
8717   return call_ic_function4;
8718 }
8719
8720
8721 // This test checks that if interceptor provides a function,
8722 // even if we cached shadowed variant, interceptor's function
8723 // is invoked
8724 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
8725   v8::HandleScope scope;
8726   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8727   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
8728   LocalContext context;
8729   context->Global()->Set(v8_str("o"), templ->NewInstance());
8730   call_ic_function4 =
8731       v8_compile("function f(x) { return x - 1; }; f")->Run();
8732   v8::Handle<Value> value = CompileRun(
8733     "o.__proto__.x = function(x) { return x + 1; };"
8734     "var result = 0;"
8735     "for (var i = 0; i < 1000; i++) {"
8736     "  result = o.x(42);"
8737     "}");
8738   CHECK_EQ(41, value->Int32Value());
8739 }
8740
8741
8742 // Test the case when we stored cacheable lookup into
8743 // a stub, but it got invalidated later on
8744 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
8745   v8::HandleScope scope;
8746   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8747   templ->SetNamedPropertyHandler(NoBlockGetterX);
8748   LocalContext context;
8749   context->Global()->Set(v8_str("o"), templ->NewInstance());
8750   v8::Handle<Value> value = CompileRun(
8751     "proto1 = new Object();"
8752     "proto2 = new Object();"
8753     "o.__proto__ = proto1;"
8754     "proto1.__proto__ = proto2;"
8755     "proto2.y = function(x) { return x + 1; };"
8756     // Invoke it many times to compile a stub
8757     "for (var i = 0; i < 7; i++) {"
8758     "  o.y(42);"
8759     "}"
8760     "proto1.y = function(x) { return x - 1; };"
8761     "var result = 0;"
8762     "for (var i = 0; i < 7; i++) {"
8763     "  result += o.y(42);"
8764     "}");
8765   CHECK_EQ(41 * 7, value->Int32Value());
8766 }
8767
8768
8769 static v8::Handle<Value> call_ic_function5;
8770 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
8771                                                   const AccessorInfo& info) {
8772   ApiTestFuzzer::Fuzz();
8773   if (v8_str("x")->Equals(name))
8774     return call_ic_function5;
8775   else
8776     return Local<Value>();
8777 }
8778
8779
8780 // This test checks that if interceptor doesn't provide a function,
8781 // cached constant function is used
8782 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
8783   v8::HandleScope scope;
8784   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8785   templ->SetNamedPropertyHandler(NoBlockGetterX);
8786   LocalContext context;
8787   context->Global()->Set(v8_str("o"), templ->NewInstance());
8788   v8::Handle<Value> value = CompileRun(
8789     "function inc(x) { return x + 1; };"
8790     "inc(1);"
8791     "o.x = inc;"
8792     "var result = 0;"
8793     "for (var i = 0; i < 1000; i++) {"
8794     "  result = o.x(42);"
8795     "}");
8796   CHECK_EQ(43, value->Int32Value());
8797 }
8798
8799
8800 // This test checks that if interceptor provides a function,
8801 // even if we cached constant function, interceptor's function
8802 // is invoked
8803 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
8804   v8::HandleScope scope;
8805   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8806   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
8807   LocalContext context;
8808   context->Global()->Set(v8_str("o"), templ->NewInstance());
8809   call_ic_function5 =
8810       v8_compile("function f(x) { return x - 1; }; f")->Run();
8811   v8::Handle<Value> value = CompileRun(
8812     "function inc(x) { return x + 1; };"
8813     "inc(1);"
8814     "o.x = inc;"
8815     "var result = 0;"
8816     "for (var i = 0; i < 1000; i++) {"
8817     "  result = o.x(42);"
8818     "}");
8819   CHECK_EQ(41, value->Int32Value());
8820 }
8821
8822
8823 // Test the case when we stored constant function into
8824 // a stub, but it got invalidated later on
8825 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
8826   v8::HandleScope scope;
8827   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8828   templ->SetNamedPropertyHandler(NoBlockGetterX);
8829   LocalContext context;
8830   context->Global()->Set(v8_str("o"), templ->NewInstance());
8831   v8::Handle<Value> value = CompileRun(
8832     "function inc(x) { return x + 1; };"
8833     "inc(1);"
8834     "proto1 = new Object();"
8835     "proto2 = new Object();"
8836     "o.__proto__ = proto1;"
8837     "proto1.__proto__ = proto2;"
8838     "proto2.y = inc;"
8839     // Invoke it many times to compile a stub
8840     "for (var i = 0; i < 7; i++) {"
8841     "  o.y(42);"
8842     "}"
8843     "proto1.y = function(x) { return x - 1; };"
8844     "var result = 0;"
8845     "for (var i = 0; i < 7; i++) {"
8846     "  result += o.y(42);"
8847     "}");
8848   CHECK_EQ(41 * 7, value->Int32Value());
8849 }
8850
8851
8852 // Test the case when we stored constant function into
8853 // a stub, but it got invalidated later on due to override on
8854 // global object which is between interceptor and constant function' holders.
8855 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
8856   v8::HandleScope scope;
8857   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
8858   templ->SetNamedPropertyHandler(NoBlockGetterX);
8859   LocalContext context;
8860   context->Global()->Set(v8_str("o"), templ->NewInstance());
8861   v8::Handle<Value> value = CompileRun(
8862     "function inc(x) { return x + 1; };"
8863     "inc(1);"
8864     "o.__proto__ = this;"
8865     "this.__proto__.y = inc;"
8866     // Invoke it many times to compile a stub
8867     "for (var i = 0; i < 7; i++) {"
8868     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
8869     "}"
8870     "this.y = function(x) { return x - 1; };"
8871     "var result = 0;"
8872     "for (var i = 0; i < 7; i++) {"
8873     "  result += o.y(42);"
8874     "}");
8875   CHECK_EQ(41 * 7, value->Int32Value());
8876 }
8877
8878
8879 // Test the case when actual function to call sits on global object.
8880 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
8881   v8::HandleScope scope;
8882   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
8883   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
8884
8885   LocalContext context;
8886   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
8887
8888   v8::Handle<Value> value = CompileRun(
8889     "try {"
8890     "  o.__proto__ = this;"
8891     "  for (var i = 0; i < 10; i++) {"
8892     "    var v = o.parseFloat('239');"
8893     "    if (v != 239) throw v;"
8894       // Now it should be ICed and keep a reference to parseFloat.
8895     "  }"
8896     "  var result = 0;"
8897     "  for (var i = 0; i < 10; i++) {"
8898     "    result += o.parseFloat('239');"
8899     "  }"
8900     "  result"
8901     "} catch(e) {"
8902     "  e"
8903     "};");
8904   CHECK_EQ(239 * 10, value->Int32Value());
8905 }
8906
8907 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
8908                                                   const AccessorInfo& info) {
8909   ApiTestFuzzer::Fuzz();
8910   int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
8911   ++(*call_count);
8912   if ((*call_count) % 20 == 0) {
8913     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
8914   }
8915   return v8::Handle<Value>();
8916 }
8917
8918 static v8::Handle<Value> FastApiCallback_TrivialSignature(
8919     const v8::Arguments& args) {
8920   ApiTestFuzzer::Fuzz();
8921   CHECK_EQ(args.This(), args.Holder());
8922   CHECK(args.Data()->Equals(v8_str("method_data")));
8923   return v8::Integer::New(args[0]->Int32Value() + 1);
8924 }
8925
8926 static v8::Handle<Value> FastApiCallback_SimpleSignature(
8927     const v8::Arguments& args) {
8928   ApiTestFuzzer::Fuzz();
8929   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
8930   CHECK(args.Data()->Equals(v8_str("method_data")));
8931   // Note, we're using HasRealNamedProperty instead of Has to avoid
8932   // invoking the interceptor again.
8933   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
8934   return v8::Integer::New(args[0]->Int32Value() + 1);
8935 }
8936
8937 // Helper to maximize the odds of object moving.
8938 static void GenerateSomeGarbage() {
8939   CompileRun(
8940       "var garbage;"
8941       "for (var i = 0; i < 1000; i++) {"
8942       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
8943       "}"
8944       "garbage = undefined;");
8945 }
8946
8947
8948 v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) {
8949   static int count = 0;
8950   if (count++ % 3 == 0) {
8951     HEAP->  CollectAllGarbage(true);  // This should move the stub
8952     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
8953   }
8954   return v8::Handle<v8::Value>();
8955 }
8956
8957
8958 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
8959   v8::HandleScope scope;
8960   LocalContext context;
8961   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8962   nativeobject_templ->Set("callback",
8963                           v8::FunctionTemplate::New(DirectApiCallback));
8964   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8965   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8966   // call the api function multiple times to ensure direct call stub creation.
8967   CompileRun(
8968         "function f() {"
8969         "  for (var i = 1; i <= 30; i++) {"
8970         "    nativeobject.callback();"
8971         "  }"
8972         "}"
8973         "f();");
8974 }
8975
8976
8977 v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) {
8978   return v8::ThrowException(v8_str("g"));
8979 }
8980
8981
8982 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
8983   v8::HandleScope scope;
8984   LocalContext context;
8985   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
8986   nativeobject_templ->Set("callback",
8987                           v8::FunctionTemplate::New(ThrowingDirectApiCallback));
8988   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
8989   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
8990   // call the api function multiple times to ensure direct call stub creation.
8991   v8::Handle<Value> result = CompileRun(
8992       "var result = '';"
8993       "function f() {"
8994       "  for (var i = 1; i <= 5; i++) {"
8995       "    try { nativeobject.callback(); } catch (e) { result += e; }"
8996       "  }"
8997       "}"
8998       "f(); result;");
8999   CHECK_EQ(v8_str("ggggg"), result);
9000 }
9001
9002
9003 v8::Handle<v8::Value> DirectGetterCallback(Local<String> name,
9004                                            const v8::AccessorInfo& info) {
9005   if (++p_getter_count % 3 == 0) {
9006     HEAP->CollectAllGarbage(true);
9007     GenerateSomeGarbage();
9008   }
9009   return v8::Handle<v8::Value>();
9010 }
9011
9012
9013 THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
9014   v8::HandleScope scope;
9015   LocalContext context;
9016   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9017   obj->SetAccessor(v8_str("p1"), DirectGetterCallback);
9018   context->Global()->Set(v8_str("o1"), obj->NewInstance());
9019   p_getter_count = 0;
9020   CompileRun(
9021       "function f() {"
9022       "  for (var i = 0; i < 30; i++) o1.p1;"
9023       "}"
9024       "f();");
9025   CHECK_EQ(30, p_getter_count);
9026 }
9027
9028
9029 v8::Handle<v8::Value> ThrowingDirectGetterCallback(
9030     Local<String> name, const v8::AccessorInfo& info) {
9031   return v8::ThrowException(v8_str("g"));
9032 }
9033
9034
9035 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
9036   v8::HandleScope scope;
9037   LocalContext context;
9038   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
9039   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
9040   context->Global()->Set(v8_str("o1"), obj->NewInstance());
9041   v8::Handle<Value> result = CompileRun(
9042       "var result = '';"
9043       "for (var i = 0; i < 5; i++) {"
9044       "    try { o1.p1; } catch (e) { result += e; }"
9045       "}"
9046       "result;");
9047   CHECK_EQ(v8_str("ggggg"), result);
9048 }
9049
9050
9051 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
9052   int interceptor_call_count = 0;
9053   v8::HandleScope scope;
9054   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9055   v8::Handle<v8::FunctionTemplate> method_templ =
9056       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9057                                 v8_str("method_data"),
9058                                 v8::Handle<v8::Signature>());
9059   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9060   proto_templ->Set(v8_str("method"), method_templ);
9061   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9062   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9063                                  NULL, NULL, NULL, NULL,
9064                                  v8::External::Wrap(&interceptor_call_count));
9065   LocalContext context;
9066   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9067   GenerateSomeGarbage();
9068   context->Global()->Set(v8_str("o"), fun->NewInstance());
9069   v8::Handle<Value> value(CompileRun(
9070       "var result = 0;"
9071       "for (var i = 0; i < 100; i++) {"
9072       "  result = o.method(41);"
9073       "}"));
9074   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9075   CHECK_EQ(100, interceptor_call_count);
9076 }
9077
9078 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
9079   int interceptor_call_count = 0;
9080   v8::HandleScope scope;
9081   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9082   v8::Handle<v8::FunctionTemplate> method_templ =
9083       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9084                                 v8_str("method_data"),
9085                                 v8::Signature::New(fun_templ));
9086   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9087   proto_templ->Set(v8_str("method"), method_templ);
9088   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9089   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9090                                  NULL, NULL, NULL, NULL,
9091                                  v8::External::Wrap(&interceptor_call_count));
9092   LocalContext context;
9093   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9094   GenerateSomeGarbage();
9095   context->Global()->Set(v8_str("o"), fun->NewInstance());
9096   v8::Handle<Value> value(CompileRun(
9097       "o.foo = 17;"
9098       "var receiver = {};"
9099       "receiver.__proto__ = o;"
9100       "var result = 0;"
9101       "for (var i = 0; i < 100; i++) {"
9102       "  result = receiver.method(41);"
9103       "}"));
9104   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9105   CHECK_EQ(100, interceptor_call_count);
9106 }
9107
9108 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
9109   int interceptor_call_count = 0;
9110   v8::HandleScope scope;
9111   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9112   v8::Handle<v8::FunctionTemplate> method_templ =
9113       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9114                                 v8_str("method_data"),
9115                                 v8::Signature::New(fun_templ));
9116   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9117   proto_templ->Set(v8_str("method"), method_templ);
9118   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9119   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9120                                  NULL, NULL, NULL, NULL,
9121                                  v8::External::Wrap(&interceptor_call_count));
9122   LocalContext context;
9123   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9124   GenerateSomeGarbage();
9125   context->Global()->Set(v8_str("o"), fun->NewInstance());
9126   v8::Handle<Value> value(CompileRun(
9127       "o.foo = 17;"
9128       "var receiver = {};"
9129       "receiver.__proto__ = o;"
9130       "var result = 0;"
9131       "var saved_result = 0;"
9132       "for (var i = 0; i < 100; i++) {"
9133       "  result = receiver.method(41);"
9134       "  if (i == 50) {"
9135       "    saved_result = result;"
9136       "    receiver = {method: function(x) { return x - 1 }};"
9137       "  }"
9138       "}"));
9139   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9140   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9141   CHECK_GE(interceptor_call_count, 50);
9142 }
9143
9144 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
9145   int interceptor_call_count = 0;
9146   v8::HandleScope scope;
9147   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9148   v8::Handle<v8::FunctionTemplate> method_templ =
9149       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9150                                 v8_str("method_data"),
9151                                 v8::Signature::New(fun_templ));
9152   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9153   proto_templ->Set(v8_str("method"), method_templ);
9154   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9155   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9156                                  NULL, NULL, NULL, NULL,
9157                                  v8::External::Wrap(&interceptor_call_count));
9158   LocalContext context;
9159   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9160   GenerateSomeGarbage();
9161   context->Global()->Set(v8_str("o"), fun->NewInstance());
9162   v8::Handle<Value> value(CompileRun(
9163       "o.foo = 17;"
9164       "var receiver = {};"
9165       "receiver.__proto__ = o;"
9166       "var result = 0;"
9167       "var saved_result = 0;"
9168       "for (var i = 0; i < 100; i++) {"
9169       "  result = receiver.method(41);"
9170       "  if (i == 50) {"
9171       "    saved_result = result;"
9172       "    o.method = function(x) { return x - 1 };"
9173       "  }"
9174       "}"));
9175   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9176   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9177   CHECK_GE(interceptor_call_count, 50);
9178 }
9179
9180 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
9181   int interceptor_call_count = 0;
9182   v8::HandleScope scope;
9183   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9184   v8::Handle<v8::FunctionTemplate> method_templ =
9185       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9186                                 v8_str("method_data"),
9187                                 v8::Signature::New(fun_templ));
9188   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9189   proto_templ->Set(v8_str("method"), method_templ);
9190   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9191   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9192                                  NULL, NULL, NULL, NULL,
9193                                  v8::External::Wrap(&interceptor_call_count));
9194   LocalContext context;
9195   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9196   GenerateSomeGarbage();
9197   context->Global()->Set(v8_str("o"), fun->NewInstance());
9198   v8::TryCatch try_catch;
9199   v8::Handle<Value> value(CompileRun(
9200       "o.foo = 17;"
9201       "var receiver = {};"
9202       "receiver.__proto__ = o;"
9203       "var result = 0;"
9204       "var saved_result = 0;"
9205       "for (var i = 0; i < 100; i++) {"
9206       "  result = receiver.method(41);"
9207       "  if (i == 50) {"
9208       "    saved_result = result;"
9209       "    receiver = 333;"
9210       "  }"
9211       "}"));
9212   CHECK(try_catch.HasCaught());
9213   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9214            try_catch.Exception()->ToString());
9215   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9216   CHECK_GE(interceptor_call_count, 50);
9217 }
9218
9219 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
9220   int interceptor_call_count = 0;
9221   v8::HandleScope scope;
9222   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9223   v8::Handle<v8::FunctionTemplate> method_templ =
9224       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9225                                 v8_str("method_data"),
9226                                 v8::Signature::New(fun_templ));
9227   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9228   proto_templ->Set(v8_str("method"), method_templ);
9229   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
9230   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
9231                                  NULL, NULL, NULL, NULL,
9232                                  v8::External::Wrap(&interceptor_call_count));
9233   LocalContext context;
9234   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9235   GenerateSomeGarbage();
9236   context->Global()->Set(v8_str("o"), fun->NewInstance());
9237   v8::TryCatch try_catch;
9238   v8::Handle<Value> value(CompileRun(
9239       "o.foo = 17;"
9240       "var receiver = {};"
9241       "receiver.__proto__ = o;"
9242       "var result = 0;"
9243       "var saved_result = 0;"
9244       "for (var i = 0; i < 100; i++) {"
9245       "  result = receiver.method(41);"
9246       "  if (i == 50) {"
9247       "    saved_result = result;"
9248       "    receiver = {method: receiver.method};"
9249       "  }"
9250       "}"));
9251   CHECK(try_catch.HasCaught());
9252   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
9253            try_catch.Exception()->ToString());
9254   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9255   CHECK_GE(interceptor_call_count, 50);
9256 }
9257
9258 THREADED_TEST(CallICFastApi_TrivialSignature) {
9259   v8::HandleScope scope;
9260   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9261   v8::Handle<v8::FunctionTemplate> method_templ =
9262       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
9263                                 v8_str("method_data"),
9264                                 v8::Handle<v8::Signature>());
9265   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9266   proto_templ->Set(v8_str("method"), method_templ);
9267   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9268   LocalContext context;
9269   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9270   GenerateSomeGarbage();
9271   context->Global()->Set(v8_str("o"), fun->NewInstance());
9272   v8::Handle<Value> value(CompileRun(
9273       "var result = 0;"
9274       "for (var i = 0; i < 100; i++) {"
9275       "  result = o.method(41);"
9276       "}"));
9277
9278   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9279 }
9280
9281 THREADED_TEST(CallICFastApi_SimpleSignature) {
9282   v8::HandleScope scope;
9283   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9284   v8::Handle<v8::FunctionTemplate> method_templ =
9285       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9286                                 v8_str("method_data"),
9287                                 v8::Signature::New(fun_templ));
9288   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9289   proto_templ->Set(v8_str("method"), method_templ);
9290   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9291   LocalContext context;
9292   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9293   GenerateSomeGarbage();
9294   context->Global()->Set(v8_str("o"), fun->NewInstance());
9295   v8::Handle<Value> value(CompileRun(
9296       "o.foo = 17;"
9297       "var receiver = {};"
9298       "receiver.__proto__ = o;"
9299       "var result = 0;"
9300       "for (var i = 0; i < 100; i++) {"
9301       "  result = receiver.method(41);"
9302       "}"));
9303
9304   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
9305 }
9306
9307 THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
9308   v8::HandleScope scope;
9309   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9310   v8::Handle<v8::FunctionTemplate> method_templ =
9311       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9312                                 v8_str("method_data"),
9313                                 v8::Signature::New(fun_templ));
9314   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9315   proto_templ->Set(v8_str("method"), method_templ);
9316   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9317   LocalContext context;
9318   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9319   GenerateSomeGarbage();
9320   context->Global()->Set(v8_str("o"), fun->NewInstance());
9321   v8::Handle<Value> value(CompileRun(
9322       "o.foo = 17;"
9323       "var receiver = {};"
9324       "receiver.__proto__ = o;"
9325       "var result = 0;"
9326       "var saved_result = 0;"
9327       "for (var i = 0; i < 100; i++) {"
9328       "  result = receiver.method(41);"
9329       "  if (i == 50) {"
9330       "    saved_result = result;"
9331       "    receiver = {method: function(x) { return x - 1 }};"
9332       "  }"
9333       "}"));
9334   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
9335   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9336 }
9337
9338 THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
9339   v8::HandleScope scope;
9340   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
9341   v8::Handle<v8::FunctionTemplate> method_templ =
9342       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
9343                                 v8_str("method_data"),
9344                                 v8::Signature::New(fun_templ));
9345   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
9346   proto_templ->Set(v8_str("method"), method_templ);
9347   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
9348   LocalContext context;
9349   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
9350   GenerateSomeGarbage();
9351   context->Global()->Set(v8_str("o"), fun->NewInstance());
9352   v8::TryCatch try_catch;
9353   v8::Handle<Value> value(CompileRun(
9354       "o.foo = 17;"
9355       "var receiver = {};"
9356       "receiver.__proto__ = o;"
9357       "var result = 0;"
9358       "var saved_result = 0;"
9359       "for (var i = 0; i < 100; i++) {"
9360       "  result = receiver.method(41);"
9361       "  if (i == 50) {"
9362       "    saved_result = result;"
9363       "    receiver = 333;"
9364       "  }"
9365       "}"));
9366   CHECK(try_catch.HasCaught());
9367   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
9368            try_catch.Exception()->ToString());
9369   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9370 }
9371
9372
9373 v8::Handle<Value> keyed_call_ic_function;
9374
9375 static v8::Handle<Value> InterceptorKeyedCallICGetter(
9376     Local<String> name, const AccessorInfo& info) {
9377   ApiTestFuzzer::Fuzz();
9378   if (v8_str("x")->Equals(name)) {
9379     return keyed_call_ic_function;
9380   }
9381   return v8::Handle<Value>();
9382 }
9383
9384
9385 // Test the case when we stored cacheable lookup into
9386 // a stub, but the function name changed (to another cacheable function).
9387 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
9388   v8::HandleScope scope;
9389   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9390   templ->SetNamedPropertyHandler(NoBlockGetterX);
9391   LocalContext context;
9392   context->Global()->Set(v8_str("o"), templ->NewInstance());
9393   v8::Handle<Value> value(CompileRun(
9394     "proto = new Object();"
9395     "proto.y = function(x) { return x + 1; };"
9396     "proto.z = function(x) { return x - 1; };"
9397     "o.__proto__ = proto;"
9398     "var result = 0;"
9399     "var method = 'y';"
9400     "for (var i = 0; i < 10; i++) {"
9401     "  if (i == 5) { method = 'z'; };"
9402     "  result += o[method](41);"
9403     "}"));
9404   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9405 }
9406
9407
9408 // Test the case when we stored cacheable lookup into
9409 // a stub, but the function name changed (and the new function is present
9410 // both before and after the interceptor in the prototype chain).
9411 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
9412   v8::HandleScope scope;
9413   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9414   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
9415   LocalContext context;
9416   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
9417   keyed_call_ic_function =
9418       v8_compile("function f(x) { return x - 1; }; f")->Run();
9419   v8::Handle<Value> value(CompileRun(
9420     "o = new Object();"
9421     "proto2 = new Object();"
9422     "o.y = function(x) { return x + 1; };"
9423     "proto2.y = function(x) { return x + 2; };"
9424     "o.__proto__ = proto1;"
9425     "proto1.__proto__ = proto2;"
9426     "var result = 0;"
9427     "var method = 'x';"
9428     "for (var i = 0; i < 10; i++) {"
9429     "  if (i == 5) { method = 'y'; };"
9430     "  result += o[method](41);"
9431     "}"));
9432   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9433 }
9434
9435
9436 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
9437 // on the global object.
9438 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
9439   v8::HandleScope scope;
9440   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9441   templ->SetNamedPropertyHandler(NoBlockGetterX);
9442   LocalContext context;
9443   context->Global()->Set(v8_str("o"), templ->NewInstance());
9444   v8::Handle<Value> value(CompileRun(
9445     "function inc(x) { return x + 1; };"
9446     "inc(1);"
9447     "function dec(x) { return x - 1; };"
9448     "dec(1);"
9449     "o.__proto__ = this;"
9450     "this.__proto__.x = inc;"
9451     "this.__proto__.y = dec;"
9452     "var result = 0;"
9453     "var method = 'x';"
9454     "for (var i = 0; i < 10; i++) {"
9455     "  if (i == 5) { method = 'y'; };"
9456     "  result += o[method](41);"
9457     "}"));
9458   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9459 }
9460
9461
9462 // Test the case when actual function to call sits on global object.
9463 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
9464   v8::HandleScope scope;
9465   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9466   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9467   LocalContext context;
9468   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9469
9470   v8::Handle<Value> value(CompileRun(
9471     "function len(x) { return x.length; };"
9472     "o.__proto__ = this;"
9473     "var m = 'parseFloat';"
9474     "var result = 0;"
9475     "for (var i = 0; i < 10; i++) {"
9476     "  if (i == 5) {"
9477     "    m = 'len';"
9478     "    saved_result = result;"
9479     "  };"
9480     "  result = o[m]('239');"
9481     "}"));
9482   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
9483   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
9484 }
9485
9486 // Test the map transition before the interceptor.
9487 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
9488   v8::HandleScope scope;
9489   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9490   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9491   LocalContext context;
9492   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
9493
9494   v8::Handle<Value> value(CompileRun(
9495     "var o = new Object();"
9496     "o.__proto__ = proto;"
9497     "o.method = function(x) { return x + 1; };"
9498     "var m = 'method';"
9499     "var result = 0;"
9500     "for (var i = 0; i < 10; i++) {"
9501     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
9502     "  result += o[m](41);"
9503     "}"));
9504   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9505 }
9506
9507
9508 // Test the map transition after the interceptor.
9509 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
9510   v8::HandleScope scope;
9511   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
9512   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
9513   LocalContext context;
9514   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
9515
9516   v8::Handle<Value> value(CompileRun(
9517     "var proto = new Object();"
9518     "o.__proto__ = proto;"
9519     "proto.method = function(x) { return x + 1; };"
9520     "var m = 'method';"
9521     "var result = 0;"
9522     "for (var i = 0; i < 10; i++) {"
9523     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
9524     "  result += o[m](41);"
9525     "}"));
9526   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
9527 }
9528
9529
9530 static int interceptor_call_count = 0;
9531
9532 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
9533                                                      const AccessorInfo& info) {
9534   ApiTestFuzzer::Fuzz();
9535   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
9536     return call_ic_function2;
9537   }
9538   return v8::Handle<Value>();
9539 }
9540
9541
9542 // This test should hit load and call ICs for the interceptor case.
9543 // Once in a while, the interceptor will reply that a property was not
9544 // found in which case we should get a reference error.
9545 THREADED_TEST(InterceptorICReferenceErrors) {
9546   v8::HandleScope scope;
9547   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9548   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
9549   LocalContext context(0, templ, v8::Handle<Value>());
9550   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
9551   v8::Handle<Value> value = CompileRun(
9552     "function f() {"
9553     "  for (var i = 0; i < 1000; i++) {"
9554     "    try { x; } catch(e) { return true; }"
9555     "  }"
9556     "  return false;"
9557     "};"
9558     "f();");
9559   CHECK_EQ(true, value->BooleanValue());
9560   interceptor_call_count = 0;
9561   value = CompileRun(
9562     "function g() {"
9563     "  for (var i = 0; i < 1000; i++) {"
9564     "    try { x(42); } catch(e) { return true; }"
9565     "  }"
9566     "  return false;"
9567     "};"
9568     "g();");
9569   CHECK_EQ(true, value->BooleanValue());
9570 }
9571
9572
9573 static int interceptor_ic_exception_get_count = 0;
9574
9575 static v8::Handle<Value> InterceptorICExceptionGetter(
9576     Local<String> name,
9577     const AccessorInfo& info) {
9578   ApiTestFuzzer::Fuzz();
9579   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
9580     return call_ic_function3;
9581   }
9582   if (interceptor_ic_exception_get_count == 20) {
9583     return v8::ThrowException(v8_num(42));
9584   }
9585   // Do not handle get for properties other than x.
9586   return v8::Handle<Value>();
9587 }
9588
9589 // Test interceptor load/call IC where the interceptor throws an
9590 // exception once in a while.
9591 THREADED_TEST(InterceptorICGetterExceptions) {
9592   interceptor_ic_exception_get_count = 0;
9593   v8::HandleScope scope;
9594   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9595   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
9596   LocalContext context(0, templ, v8::Handle<Value>());
9597   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
9598   v8::Handle<Value> value = CompileRun(
9599     "function f() {"
9600     "  for (var i = 0; i < 100; i++) {"
9601     "    try { x; } catch(e) { return true; }"
9602     "  }"
9603     "  return false;"
9604     "};"
9605     "f();");
9606   CHECK_EQ(true, value->BooleanValue());
9607   interceptor_ic_exception_get_count = 0;
9608   value = CompileRun(
9609     "function f() {"
9610     "  for (var i = 0; i < 100; i++) {"
9611     "    try { x(42); } catch(e) { return true; }"
9612     "  }"
9613     "  return false;"
9614     "};"
9615     "f();");
9616   CHECK_EQ(true, value->BooleanValue());
9617 }
9618
9619
9620 static int interceptor_ic_exception_set_count = 0;
9621
9622 static v8::Handle<Value> InterceptorICExceptionSetter(
9623       Local<String> key, Local<Value> value, const AccessorInfo&) {
9624   ApiTestFuzzer::Fuzz();
9625   if (++interceptor_ic_exception_set_count > 20) {
9626     return v8::ThrowException(v8_num(42));
9627   }
9628   // Do not actually handle setting.
9629   return v8::Handle<Value>();
9630 }
9631
9632 // Test interceptor store IC where the interceptor throws an exception
9633 // once in a while.
9634 THREADED_TEST(InterceptorICSetterExceptions) {
9635   interceptor_ic_exception_set_count = 0;
9636   v8::HandleScope scope;
9637   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9638   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
9639   LocalContext context(0, templ, v8::Handle<Value>());
9640   v8::Handle<Value> value = CompileRun(
9641     "function f() {"
9642     "  for (var i = 0; i < 100; i++) {"
9643     "    try { x = 42; } catch(e) { return true; }"
9644     "  }"
9645     "  return false;"
9646     "};"
9647     "f();");
9648   CHECK_EQ(true, value->BooleanValue());
9649 }
9650
9651
9652 // Test that we ignore null interceptors.
9653 THREADED_TEST(NullNamedInterceptor) {
9654   v8::HandleScope scope;
9655   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9656   templ->SetNamedPropertyHandler(0);
9657   LocalContext context;
9658   templ->Set("x", v8_num(42));
9659   v8::Handle<v8::Object> obj = templ->NewInstance();
9660   context->Global()->Set(v8_str("obj"), obj);
9661   v8::Handle<Value> value = CompileRun("obj.x");
9662   CHECK(value->IsInt32());
9663   CHECK_EQ(42, value->Int32Value());
9664 }
9665
9666
9667 // Test that we ignore null interceptors.
9668 THREADED_TEST(NullIndexedInterceptor) {
9669   v8::HandleScope scope;
9670   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
9671   templ->SetIndexedPropertyHandler(0);
9672   LocalContext context;
9673   templ->Set("42", v8_num(42));
9674   v8::Handle<v8::Object> obj = templ->NewInstance();
9675   context->Global()->Set(v8_str("obj"), obj);
9676   v8::Handle<Value> value = CompileRun("obj[42]");
9677   CHECK(value->IsInt32());
9678   CHECK_EQ(42, value->Int32Value());
9679 }
9680
9681
9682 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
9683   v8::HandleScope scope;
9684   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9685   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
9686   LocalContext env;
9687   env->Global()->Set(v8_str("obj"),
9688                      templ->GetFunction()->NewInstance());
9689   ExpectTrue("obj.x === 42");
9690   ExpectTrue("!obj.propertyIsEnumerable('x')");
9691 }
9692
9693
9694 static Handle<Value> ThrowingGetter(Local<String> name,
9695                                     const AccessorInfo& info) {
9696   ApiTestFuzzer::Fuzz();
9697   ThrowException(Handle<Value>());
9698   return Undefined();
9699 }
9700
9701
9702 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
9703   HandleScope scope;
9704   LocalContext context;
9705
9706   Local<FunctionTemplate> templ = FunctionTemplate::New();
9707   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
9708   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
9709
9710   Local<Object> instance = templ->GetFunction()->NewInstance();
9711
9712   Local<Object> another = Object::New();
9713   another->SetPrototype(instance);
9714
9715   Local<Object> with_js_getter = CompileRun(
9716       "o = {};\n"
9717       "o.__defineGetter__('f', function() { throw undefined; });\n"
9718       "o\n").As<Object>();
9719   CHECK(!with_js_getter.IsEmpty());
9720
9721   TryCatch try_catch;
9722
9723   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
9724   CHECK(try_catch.HasCaught());
9725   try_catch.Reset();
9726   CHECK(result.IsEmpty());
9727
9728   result = another->GetRealNamedProperty(v8_str("f"));
9729   CHECK(try_catch.HasCaught());
9730   try_catch.Reset();
9731   CHECK(result.IsEmpty());
9732
9733   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
9734   CHECK(try_catch.HasCaught());
9735   try_catch.Reset();
9736   CHECK(result.IsEmpty());
9737
9738   result = another->Get(v8_str("f"));
9739   CHECK(try_catch.HasCaught());
9740   try_catch.Reset();
9741   CHECK(result.IsEmpty());
9742
9743   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
9744   CHECK(try_catch.HasCaught());
9745   try_catch.Reset();
9746   CHECK(result.IsEmpty());
9747
9748   result = with_js_getter->Get(v8_str("f"));
9749   CHECK(try_catch.HasCaught());
9750   try_catch.Reset();
9751   CHECK(result.IsEmpty());
9752 }
9753
9754
9755 static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) {
9756   TryCatch try_catch;
9757   // Verboseness is important: it triggers message delivery which can call into
9758   // external code.
9759   try_catch.SetVerbose(true);
9760   CompileRun("throw 'from JS';");
9761   CHECK(try_catch.HasCaught());
9762   CHECK(!i::Isolate::Current()->has_pending_exception());
9763   CHECK(!i::Isolate::Current()->has_scheduled_exception());
9764   return Undefined();
9765 }
9766
9767
9768 static int call_depth;
9769
9770
9771 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
9772   TryCatch try_catch;
9773 }
9774
9775
9776 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
9777   if (--call_depth) CompileRun("throw 'ThrowInJS';");
9778 }
9779
9780
9781 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
9782   if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
9783 }
9784
9785
9786 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
9787   Handle<String> errorMessageString = message->Get();
9788   CHECK(!errorMessageString.IsEmpty());
9789   message->GetStackTrace();
9790   message->GetScriptResourceName();
9791 }
9792
9793 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
9794   HandleScope scope;
9795   LocalContext context;
9796
9797   Local<Function> func =
9798       FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
9799   context->Global()->Set(v8_str("func"), func);
9800
9801   MessageCallback callbacks[] =
9802       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
9803   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
9804     MessageCallback callback = callbacks[i];
9805     if (callback != NULL) {
9806       V8::AddMessageListener(callback);
9807     }
9808     // Some small number to control number of times message handler should
9809     // throw an exception.
9810     call_depth = 5;
9811     ExpectFalse(
9812         "var thrown = false;\n"
9813         "try { func(); } catch(e) { thrown = true; }\n"
9814         "thrown\n");
9815     if (callback != NULL) {
9816       V8::RemoveMessageListeners(callback);
9817     }
9818   }
9819 }
9820
9821
9822 static v8::Handle<Value> ParentGetter(Local<String> name,
9823                                       const AccessorInfo& info) {
9824   ApiTestFuzzer::Fuzz();
9825   return v8_num(1);
9826 }
9827
9828
9829 static v8::Handle<Value> ChildGetter(Local<String> name,
9830                                      const AccessorInfo& info) {
9831   ApiTestFuzzer::Fuzz();
9832   return v8_num(42);
9833 }
9834
9835
9836 THREADED_TEST(Overriding) {
9837   v8::HandleScope scope;
9838   LocalContext context;
9839
9840   // Parent template.
9841   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
9842   Local<ObjectTemplate> parent_instance_templ =
9843       parent_templ->InstanceTemplate();
9844   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
9845
9846   // Template that inherits from the parent template.
9847   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
9848   Local<ObjectTemplate> child_instance_templ =
9849       child_templ->InstanceTemplate();
9850   child_templ->Inherit(parent_templ);
9851   // Override 'f'.  The child version of 'f' should get called for child
9852   // instances.
9853   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
9854   // Add 'g' twice.  The 'g' added last should get called for instances.
9855   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
9856   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
9857
9858   // Add 'h' as an accessor to the proto template with ReadOnly attributes
9859   // so 'h' can be shadowed on the instance object.
9860   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
9861   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
9862       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9863
9864   // Add 'i' as an accessor to the instance template with ReadOnly attributes
9865   // but the attribute does not have effect because it is duplicated with
9866   // NULL setter.
9867   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
9868       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
9869
9870
9871
9872   // Instantiate the child template.
9873   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
9874
9875   // Check that the child function overrides the parent one.
9876   context->Global()->Set(v8_str("o"), instance);
9877   Local<Value> value = v8_compile("o.f")->Run();
9878   // Check that the 'g' that was added last is hit.
9879   CHECK_EQ(42, value->Int32Value());
9880   value = v8_compile("o.g")->Run();
9881   CHECK_EQ(42, value->Int32Value());
9882
9883   // Check 'h' can be shadowed.
9884   value = v8_compile("o.h = 3; o.h")->Run();
9885   CHECK_EQ(3, value->Int32Value());
9886
9887   // Check 'i' is cannot be shadowed or changed.
9888   value = v8_compile("o.i = 3; o.i")->Run();
9889   CHECK_EQ(42, value->Int32Value());
9890 }
9891
9892
9893 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
9894   ApiTestFuzzer::Fuzz();
9895   return v8::Boolean::New(args.IsConstructCall());
9896 }
9897
9898
9899 THREADED_TEST(IsConstructCall) {
9900   v8::HandleScope scope;
9901
9902   // Function template with call handler.
9903   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9904   templ->SetCallHandler(IsConstructHandler);
9905
9906   LocalContext context;
9907
9908   context->Global()->Set(v8_str("f"), templ->GetFunction());
9909   Local<Value> value = v8_compile("f()")->Run();
9910   CHECK(!value->BooleanValue());
9911   value = v8_compile("new f()")->Run();
9912   CHECK(value->BooleanValue());
9913 }
9914
9915
9916 THREADED_TEST(ObjectProtoToString) {
9917   v8::HandleScope scope;
9918   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9919   templ->SetClassName(v8_str("MyClass"));
9920
9921   LocalContext context;
9922
9923   Local<String> customized_tostring = v8_str("customized toString");
9924
9925   // Replace Object.prototype.toString
9926   v8_compile("Object.prototype.toString = function() {"
9927                   "  return 'customized toString';"
9928                   "}")->Run();
9929
9930   // Normal ToString call should call replaced Object.prototype.toString
9931   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
9932   Local<String> value = instance->ToString();
9933   CHECK(value->IsString() && value->Equals(customized_tostring));
9934
9935   // ObjectProtoToString should not call replace toString function.
9936   value = instance->ObjectProtoToString();
9937   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
9938
9939   // Check global
9940   value = context->Global()->ObjectProtoToString();
9941   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
9942
9943   // Check ordinary object
9944   Local<Value> object = v8_compile("new Object()")->Run();
9945   value = object.As<v8::Object>()->ObjectProtoToString();
9946   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
9947 }
9948
9949
9950 THREADED_TEST(ObjectGetConstructorName) {
9951   v8::HandleScope scope;
9952   LocalContext context;
9953   v8_compile("function Parent() {};"
9954              "function Child() {};"
9955              "Child.prototype = new Parent();"
9956              "var outer = { inner: function() { } };"
9957              "var p = new Parent();"
9958              "var c = new Child();"
9959              "var x = new outer.inner();")->Run();
9960
9961   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
9962   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
9963       v8_str("Parent")));
9964
9965   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
9966   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
9967       v8_str("Child")));
9968
9969   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
9970   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
9971       v8_str("outer.inner")));
9972 }
9973
9974
9975 bool ApiTestFuzzer::fuzzing_ = false;
9976 i::Semaphore* ApiTestFuzzer::all_tests_done_=
9977   i::OS::CreateSemaphore(0);
9978 int ApiTestFuzzer::active_tests_;
9979 int ApiTestFuzzer::tests_being_run_;
9980 int ApiTestFuzzer::current_;
9981
9982
9983 // We are in a callback and want to switch to another thread (if we
9984 // are currently running the thread fuzzing test).
9985 void ApiTestFuzzer::Fuzz() {
9986   if (!fuzzing_) return;
9987   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
9988   test->ContextSwitch();
9989 }
9990
9991
9992 // Let the next thread go.  Since it is also waiting on the V8 lock it may
9993 // not start immediately.
9994 bool ApiTestFuzzer::NextThread() {
9995   int test_position = GetNextTestNumber();
9996   const char* test_name = RegisterThreadedTest::nth(current_)->name();
9997   if (test_position == current_) {
9998     if (kLogThreading)
9999       printf("Stay with %s\n", test_name);
10000     return false;
10001   }
10002   if (kLogThreading) {
10003     printf("Switch from %s to %s\n",
10004            test_name,
10005            RegisterThreadedTest::nth(test_position)->name());
10006   }
10007   current_ = test_position;
10008   RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
10009   return true;
10010 }
10011
10012
10013 void ApiTestFuzzer::Run() {
10014   // When it is our turn...
10015   gate_->Wait();
10016   {
10017     // ... get the V8 lock and start running the test.
10018     v8::Locker locker;
10019     CallTest();
10020   }
10021   // This test finished.
10022   active_ = false;
10023   active_tests_--;
10024   // If it was the last then signal that fact.
10025   if (active_tests_ == 0) {
10026     all_tests_done_->Signal();
10027   } else {
10028     // Otherwise select a new test and start that.
10029     NextThread();
10030   }
10031 }
10032
10033
10034 static unsigned linear_congruential_generator;
10035
10036
10037 void ApiTestFuzzer::Setup(PartOfTest part) {
10038   linear_congruential_generator = i::FLAG_testing_prng_seed;
10039   fuzzing_ = true;
10040   int count = RegisterThreadedTest::count();
10041   int start =  count * part / (LAST_PART + 1);
10042   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
10043   active_tests_ = tests_being_run_ = end - start + 1;
10044   for (int i = 0; i < tests_being_run_; i++) {
10045     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
10046   }
10047   for (int i = 0; i < active_tests_; i++) {
10048     RegisterThreadedTest::nth(i)->fuzzer_->Start();
10049   }
10050 }
10051
10052
10053 static void CallTestNumber(int test_number) {
10054   (RegisterThreadedTest::nth(test_number)->callback())();
10055 }
10056
10057
10058 void ApiTestFuzzer::RunAllTests() {
10059   // Set off the first test.
10060   current_ = -1;
10061   NextThread();
10062   // Wait till they are all done.
10063   all_tests_done_->Wait();
10064 }
10065
10066
10067 int ApiTestFuzzer::GetNextTestNumber() {
10068   int next_test;
10069   do {
10070     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
10071     linear_congruential_generator *= 1664525u;
10072     linear_congruential_generator += 1013904223u;
10073   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
10074   return next_test;
10075 }
10076
10077
10078 void ApiTestFuzzer::ContextSwitch() {
10079   // If the new thread is the same as the current thread there is nothing to do.
10080   if (NextThread()) {
10081     // Now it can start.
10082     v8::Unlocker unlocker;
10083     // Wait till someone starts us again.
10084     gate_->Wait();
10085     // And we're off.
10086   }
10087 }
10088
10089
10090 void ApiTestFuzzer::TearDown() {
10091   fuzzing_ = false;
10092   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
10093     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
10094     if (fuzzer != NULL) fuzzer->Join();
10095   }
10096 }
10097
10098
10099 // Lets not be needlessly self-referential.
10100 TEST(Threading) {
10101   ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
10102   ApiTestFuzzer::RunAllTests();
10103   ApiTestFuzzer::TearDown();
10104 }
10105
10106 TEST(Threading2) {
10107   ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
10108   ApiTestFuzzer::RunAllTests();
10109   ApiTestFuzzer::TearDown();
10110 }
10111
10112 TEST(Threading3) {
10113   ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART);
10114   ApiTestFuzzer::RunAllTests();
10115   ApiTestFuzzer::TearDown();
10116 }
10117
10118 TEST(Threading4) {
10119   ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART);
10120   ApiTestFuzzer::RunAllTests();
10121   ApiTestFuzzer::TearDown();
10122 }
10123
10124 void ApiTestFuzzer::CallTest() {
10125   if (kLogThreading)
10126     printf("Start test %d\n", test_number_);
10127   CallTestNumber(test_number_);
10128   if (kLogThreading)
10129     printf("End test %d\n", test_number_);
10130 }
10131
10132
10133 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
10134   CHECK(v8::Locker::IsLocked());
10135   ApiTestFuzzer::Fuzz();
10136   v8::Unlocker unlocker;
10137   const char* code = "throw 7;";
10138   {
10139     v8::Locker nested_locker;
10140     v8::HandleScope scope;
10141     v8::Handle<Value> exception;
10142     { v8::TryCatch try_catch;
10143       v8::Handle<Value> value = CompileRun(code);
10144       CHECK(value.IsEmpty());
10145       CHECK(try_catch.HasCaught());
10146       // Make sure to wrap the exception in a new handle because
10147       // the handle returned from the TryCatch is destroyed
10148       // when the TryCatch is destroyed.
10149       exception = Local<Value>::New(try_catch.Exception());
10150     }
10151     return v8::ThrowException(exception);
10152   }
10153 }
10154
10155
10156 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
10157   CHECK(v8::Locker::IsLocked());
10158   ApiTestFuzzer::Fuzz();
10159   v8::Unlocker unlocker;
10160   const char* code = "throw 7;";
10161   {
10162     v8::Locker nested_locker;
10163     v8::HandleScope scope;
10164     v8::Handle<Value> value = CompileRun(code);
10165     CHECK(value.IsEmpty());
10166     return v8_str("foo");
10167   }
10168 }
10169
10170
10171 // These are locking tests that don't need to be run again
10172 // as part of the locking aggregation tests.
10173 TEST(NestedLockers) {
10174   v8::Locker locker;
10175   CHECK(v8::Locker::IsLocked());
10176   v8::HandleScope scope;
10177   LocalContext env;
10178   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
10179   Local<Function> fun = fun_templ->GetFunction();
10180   env->Global()->Set(v8_str("throw_in_js"), fun);
10181   Local<Script> script = v8_compile("(function () {"
10182                                     "  try {"
10183                                     "    throw_in_js();"
10184                                     "    return 42;"
10185                                     "  } catch (e) {"
10186                                     "    return e * 13;"
10187                                     "  }"
10188                                     "})();");
10189   CHECK_EQ(91, script->Run()->Int32Value());
10190 }
10191
10192
10193 // These are locking tests that don't need to be run again
10194 // as part of the locking aggregation tests.
10195 TEST(NestedLockersNoTryCatch) {
10196   v8::Locker locker;
10197   v8::HandleScope scope;
10198   LocalContext env;
10199   Local<v8::FunctionTemplate> fun_templ =
10200       v8::FunctionTemplate::New(ThrowInJSNoCatch);
10201   Local<Function> fun = fun_templ->GetFunction();
10202   env->Global()->Set(v8_str("throw_in_js"), fun);
10203   Local<Script> script = v8_compile("(function () {"
10204                                     "  try {"
10205                                     "    throw_in_js();"
10206                                     "    return 42;"
10207                                     "  } catch (e) {"
10208                                     "    return e * 13;"
10209                                     "  }"
10210                                     "})();");
10211   CHECK_EQ(91, script->Run()->Int32Value());
10212 }
10213
10214
10215 THREADED_TEST(RecursiveLocking) {
10216   v8::Locker locker;
10217   {
10218     v8::Locker locker2;
10219     CHECK(v8::Locker::IsLocked());
10220   }
10221 }
10222
10223
10224 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
10225   ApiTestFuzzer::Fuzz();
10226   v8::Unlocker unlocker;
10227   return v8::Undefined();
10228 }
10229
10230
10231 THREADED_TEST(LockUnlockLock) {
10232   {
10233     v8::Locker locker;
10234     v8::HandleScope scope;
10235     LocalContext env;
10236     Local<v8::FunctionTemplate> fun_templ =
10237         v8::FunctionTemplate::New(UnlockForAMoment);
10238     Local<Function> fun = fun_templ->GetFunction();
10239     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10240     Local<Script> script = v8_compile("(function () {"
10241                                       "  unlock_for_a_moment();"
10242                                       "  return 42;"
10243                                       "})();");
10244     CHECK_EQ(42, script->Run()->Int32Value());
10245   }
10246   {
10247     v8::Locker locker;
10248     v8::HandleScope scope;
10249     LocalContext env;
10250     Local<v8::FunctionTemplate> fun_templ =
10251         v8::FunctionTemplate::New(UnlockForAMoment);
10252     Local<Function> fun = fun_templ->GetFunction();
10253     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
10254     Local<Script> script = v8_compile("(function () {"
10255                                       "  unlock_for_a_moment();"
10256                                       "  return 42;"
10257                                       "})();");
10258     CHECK_EQ(42, script->Run()->Int32Value());
10259   }
10260 }
10261
10262
10263 static int GetGlobalObjectsCount() {
10264   i::Isolate::Current()->heap()->EnsureHeapIsIterable();
10265   int count = 0;
10266   i::HeapIterator it;
10267   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
10268     if (object->IsJSGlobalObject()) count++;
10269   return count;
10270 }
10271
10272
10273 static void CheckSurvivingGlobalObjectsCount(int expected) {
10274   // We need to collect all garbage twice to be sure that everything
10275   // has been collected.  This is because inline caches are cleared in
10276   // the first garbage collection but some of the maps have already
10277   // been marked at that point.  Therefore some of the maps are not
10278   // collected until the second garbage collection.
10279   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10280   HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
10281   int count = GetGlobalObjectsCount();
10282 #ifdef DEBUG
10283   if (count != expected) HEAP->TracePathToGlobal();
10284 #endif
10285   CHECK_EQ(expected, count);
10286 }
10287
10288
10289 TEST(DontLeakGlobalObjects) {
10290   // Regression test for issues 1139850 and 1174891.
10291
10292   v8::V8::Initialize();
10293
10294   for (int i = 0; i < 5; i++) {
10295     { v8::HandleScope scope;
10296       LocalContext context;
10297     }
10298     CheckSurvivingGlobalObjectsCount(0);
10299
10300     { v8::HandleScope scope;
10301       LocalContext context;
10302       v8_compile("Date")->Run();
10303     }
10304     CheckSurvivingGlobalObjectsCount(0);
10305
10306     { v8::HandleScope scope;
10307       LocalContext context;
10308       v8_compile("/aaa/")->Run();
10309     }
10310     CheckSurvivingGlobalObjectsCount(0);
10311
10312     { v8::HandleScope scope;
10313       const char* extension_list[] = { "v8/gc" };
10314       v8::ExtensionConfiguration extensions(1, extension_list);
10315       LocalContext context(&extensions);
10316       v8_compile("gc();")->Run();
10317     }
10318     CheckSurvivingGlobalObjectsCount(0);
10319   }
10320 }
10321
10322
10323 v8::Persistent<v8::Object> some_object;
10324 v8::Persistent<v8::Object> bad_handle;
10325
10326 void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
10327   v8::HandleScope scope;
10328   bad_handle = v8::Persistent<v8::Object>::New(some_object);
10329   handle.Dispose();
10330 }
10331
10332
10333 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
10334   LocalContext context;
10335
10336   v8::Persistent<v8::Object> handle1, handle2;
10337   {
10338     v8::HandleScope scope;
10339     some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
10340     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10341     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10342   }
10343   // Note: order is implementation dependent alas: currently
10344   // global handle nodes are processed by PostGarbageCollectionProcessing
10345   // in reverse allocation order, so if second allocated handle is deleted,
10346   // weak callback of the first handle would be able to 'reallocate' it.
10347   handle1.MakeWeak(NULL, NewPersistentHandleCallback);
10348   handle2.Dispose();
10349   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10350 }
10351
10352
10353 v8::Persistent<v8::Object> to_be_disposed;
10354
10355 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
10356   to_be_disposed.Dispose();
10357   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10358   handle.Dispose();
10359 }
10360
10361
10362 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
10363   LocalContext context;
10364
10365   v8::Persistent<v8::Object> handle1, handle2;
10366   {
10367     v8::HandleScope scope;
10368     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10369     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10370   }
10371   handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
10372   to_be_disposed = handle2;
10373   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10374 }
10375
10376 void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
10377   handle.Dispose();
10378 }
10379
10380 void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
10381   v8::HandleScope scope;
10382   v8::Persistent<v8::Object>::New(v8::Object::New());
10383   handle.Dispose();
10384 }
10385
10386
10387 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
10388   LocalContext context;
10389
10390   v8::Persistent<v8::Object> handle1, handle2, handle3;
10391   {
10392     v8::HandleScope scope;
10393     handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
10394     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
10395     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
10396   }
10397   handle2.MakeWeak(NULL, DisposingCallback);
10398   handle3.MakeWeak(NULL, HandleCreatingCallback);
10399   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10400 }
10401
10402
10403 THREADED_TEST(CheckForCrossContextObjectLiterals) {
10404   v8::V8::Initialize();
10405
10406   const int nof = 2;
10407   const char* sources[nof] = {
10408     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
10409     "Object()"
10410   };
10411
10412   for (int i = 0; i < nof; i++) {
10413     const char* source = sources[i];
10414     { v8::HandleScope scope;
10415       LocalContext context;
10416       CompileRun(source);
10417     }
10418     { v8::HandleScope scope;
10419       LocalContext context;
10420       CompileRun(source);
10421     }
10422   }
10423 }
10424
10425
10426 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
10427   v8::HandleScope inner;
10428   env->Enter();
10429   v8::Handle<Value> three = v8_num(3);
10430   v8::Handle<Value> value = inner.Close(three);
10431   env->Exit();
10432   return value;
10433 }
10434
10435
10436 THREADED_TEST(NestedHandleScopeAndContexts) {
10437   v8::HandleScope outer;
10438   v8::Persistent<Context> env = Context::New();
10439   env->Enter();
10440   v8::Handle<Value> value = NestedScope(env);
10441   v8::Handle<String> str(value->ToString());
10442   env->Exit();
10443   env.Dispose();
10444 }
10445
10446
10447 THREADED_TEST(ExternalAllocatedMemory) {
10448   v8::HandleScope outer;
10449   v8::Persistent<Context> env(Context::New());
10450   const int kSize = 1024*1024;
10451   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
10452   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
10453 }
10454
10455
10456 THREADED_TEST(DisposeEnteredContext) {
10457   v8::HandleScope scope;
10458   LocalContext outer;
10459   { v8::Persistent<v8::Context> inner = v8::Context::New();
10460     inner->Enter();
10461     inner.Dispose();
10462     inner.Clear();
10463     inner->Exit();
10464   }
10465 }
10466
10467
10468 // Regression test for issue 54, object templates with internal fields
10469 // but no accessors or interceptors did not get their internal field
10470 // count set on instances.
10471 THREADED_TEST(Regress54) {
10472   v8::HandleScope outer;
10473   LocalContext context;
10474   static v8::Persistent<v8::ObjectTemplate> templ;
10475   if (templ.IsEmpty()) {
10476     v8::HandleScope inner;
10477     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
10478     local->SetInternalFieldCount(1);
10479     templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
10480   }
10481   v8::Handle<v8::Object> result = templ->NewInstance();
10482   CHECK_EQ(1, result->InternalFieldCount());
10483 }
10484
10485
10486 // If part of the threaded tests, this test makes ThreadingTest fail
10487 // on mac.
10488 TEST(CatchStackOverflow) {
10489   v8::HandleScope scope;
10490   LocalContext context;
10491   v8::TryCatch try_catch;
10492   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
10493     "function f() {"
10494     "  return f();"
10495     "}"
10496     ""
10497     "f();"));
10498   v8::Handle<v8::Value> result = script->Run();
10499   CHECK(result.IsEmpty());
10500 }
10501
10502
10503 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
10504                                     const char* resource_name,
10505                                     int line_offset) {
10506   v8::HandleScope scope;
10507   v8::TryCatch try_catch;
10508   v8::Handle<v8::Value> result = script->Run();
10509   CHECK(result.IsEmpty());
10510   CHECK(try_catch.HasCaught());
10511   v8::Handle<v8::Message> message = try_catch.Message();
10512   CHECK(!message.IsEmpty());
10513   CHECK_EQ(10 + line_offset, message->GetLineNumber());
10514   CHECK_EQ(91, message->GetStartPosition());
10515   CHECK_EQ(92, message->GetEndPosition());
10516   CHECK_EQ(2, message->GetStartColumn());
10517   CHECK_EQ(3, message->GetEndColumn());
10518   v8::String::AsciiValue line(message->GetSourceLine());
10519   CHECK_EQ("  throw 'nirk';", *line);
10520   v8::String::AsciiValue name(message->GetScriptResourceName());
10521   CHECK_EQ(resource_name, *name);
10522 }
10523
10524
10525 THREADED_TEST(TryCatchSourceInfo) {
10526   v8::HandleScope scope;
10527   LocalContext context;
10528   v8::Handle<v8::String> source = v8::String::New(
10529       "function Foo() {\n"
10530       "  return Bar();\n"
10531       "}\n"
10532       "\n"
10533       "function Bar() {\n"
10534       "  return Baz();\n"
10535       "}\n"
10536       "\n"
10537       "function Baz() {\n"
10538       "  throw 'nirk';\n"
10539       "}\n"
10540       "\n"
10541       "Foo();\n");
10542
10543   const char* resource_name;
10544   v8::Handle<v8::Script> script;
10545   resource_name = "test.js";
10546   script = v8::Script::Compile(source, v8::String::New(resource_name));
10547   CheckTryCatchSourceInfo(script, resource_name, 0);
10548
10549   resource_name = "test1.js";
10550   v8::ScriptOrigin origin1(v8::String::New(resource_name));
10551   script = v8::Script::Compile(source, &origin1);
10552   CheckTryCatchSourceInfo(script, resource_name, 0);
10553
10554   resource_name = "test2.js";
10555   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
10556   script = v8::Script::Compile(source, &origin2);
10557   CheckTryCatchSourceInfo(script, resource_name, 7);
10558 }
10559
10560
10561 THREADED_TEST(CompilationCache) {
10562   v8::HandleScope scope;
10563   LocalContext context;
10564   v8::Handle<v8::String> source0 = v8::String::New("1234");
10565   v8::Handle<v8::String> source1 = v8::String::New("1234");
10566   v8::Handle<v8::Script> script0 =
10567       v8::Script::Compile(source0, v8::String::New("test.js"));
10568   v8::Handle<v8::Script> script1 =
10569       v8::Script::Compile(source1, v8::String::New("test.js"));
10570   v8::Handle<v8::Script> script2 =
10571       v8::Script::Compile(source0);  // different origin
10572   CHECK_EQ(1234, script0->Run()->Int32Value());
10573   CHECK_EQ(1234, script1->Run()->Int32Value());
10574   CHECK_EQ(1234, script2->Run()->Int32Value());
10575 }
10576
10577
10578 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
10579   ApiTestFuzzer::Fuzz();
10580   return v8_num(42);
10581 }
10582
10583
10584 THREADED_TEST(CallbackFunctionName) {
10585   v8::HandleScope scope;
10586   LocalContext context;
10587   Local<ObjectTemplate> t = ObjectTemplate::New();
10588   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
10589   context->Global()->Set(v8_str("obj"), t->NewInstance());
10590   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
10591   CHECK(value->IsString());
10592   v8::String::AsciiValue name(value);
10593   CHECK_EQ("asdf", *name);
10594 }
10595
10596
10597 THREADED_TEST(DateAccess) {
10598   v8::HandleScope scope;
10599   LocalContext context;
10600   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
10601   CHECK(date->IsDate());
10602   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue());
10603 }
10604
10605
10606 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
10607   v8::Handle<v8::Object> obj = val.As<v8::Object>();
10608   v8::Handle<v8::Array> props = obj->GetPropertyNames();
10609   CHECK_EQ(elmc, props->Length());
10610   for (int i = 0; i < elmc; i++) {
10611     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10612     CHECK_EQ(elmv[i], *elm);
10613   }
10614 }
10615
10616
10617 void CheckOwnProperties(v8::Handle<v8::Value> val,
10618                         int elmc,
10619                         const char* elmv[]) {
10620   v8::Handle<v8::Object> obj = val.As<v8::Object>();
10621   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
10622   CHECK_EQ(elmc, props->Length());
10623   for (int i = 0; i < elmc; i++) {
10624     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
10625     CHECK_EQ(elmv[i], *elm);
10626   }
10627 }
10628
10629
10630 THREADED_TEST(PropertyEnumeration) {
10631   v8::HandleScope scope;
10632   LocalContext context;
10633   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10634       "var result = [];"
10635       "result[0] = {};"
10636       "result[1] = {a: 1, b: 2};"
10637       "result[2] = [1, 2, 3];"
10638       "var proto = {x: 1, y: 2, z: 3};"
10639       "var x = { __proto__: proto, w: 0, z: 1 };"
10640       "result[3] = x;"
10641       "result;"))->Run();
10642   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10643   CHECK_EQ(4, elms->Length());
10644   int elmc0 = 0;
10645   const char** elmv0 = NULL;
10646   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10647   CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10648   int elmc1 = 2;
10649   const char* elmv1[] = {"a", "b"};
10650   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10651   CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
10652   int elmc2 = 3;
10653   const char* elmv2[] = {"0", "1", "2"};
10654   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10655   CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
10656   int elmc3 = 4;
10657   const char* elmv3[] = {"w", "z", "x", "y"};
10658   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
10659   int elmc4 = 2;
10660   const char* elmv4[] = {"w", "z"};
10661   CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
10662 }
10663
10664 THREADED_TEST(PropertyEnumeration2) {
10665   v8::HandleScope scope;
10666   LocalContext context;
10667   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
10668       "var result = [];"
10669       "result[0] = {};"
10670       "result[1] = {a: 1, b: 2};"
10671       "result[2] = [1, 2, 3];"
10672       "var proto = {x: 1, y: 2, z: 3};"
10673       "var x = { __proto__: proto, w: 0, z: 1 };"
10674       "result[3] = x;"
10675       "result;"))->Run();
10676   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
10677   CHECK_EQ(4, elms->Length());
10678   int elmc0 = 0;
10679   const char** elmv0 = NULL;
10680   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
10681
10682   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
10683   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
10684   CHECK_EQ(0, props->Length());
10685   for (uint32_t i = 0; i < props->Length(); i++) {
10686     printf("p[%d]\n", i);
10687   }
10688 }
10689
10690 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
10691                                   Local<Value> name,
10692                                   v8::AccessType type,
10693                                   Local<Value> data) {
10694   return type != v8::ACCESS_SET;
10695 }
10696
10697
10698 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
10699                                     uint32_t key,
10700                                     v8::AccessType type,
10701                                     Local<Value> data) {
10702   return type != v8::ACCESS_SET;
10703 }
10704
10705
10706 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
10707   v8::HandleScope scope;
10708   LocalContext context;
10709   Local<ObjectTemplate> templ = ObjectTemplate::New();
10710   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10711                                  IndexedSetAccessBlocker);
10712   templ->Set(v8_str("x"), v8::True());
10713   Local<v8::Object> instance = templ->NewInstance();
10714   context->Global()->Set(v8_str("obj"), instance);
10715   Local<Value> value = CompileRun("obj.x");
10716   CHECK(value->BooleanValue());
10717 }
10718
10719
10720 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
10721                                   Local<Value> name,
10722                                   v8::AccessType type,
10723                                   Local<Value> data) {
10724   return false;
10725 }
10726
10727
10728 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
10729                                     uint32_t key,
10730                                     v8::AccessType type,
10731                                     Local<Value> data) {
10732   return false;
10733 }
10734
10735
10736
10737 THREADED_TEST(AccessChecksReenabledCorrectly) {
10738   v8::HandleScope scope;
10739   LocalContext context;
10740   Local<ObjectTemplate> templ = ObjectTemplate::New();
10741   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10742                                  IndexedGetAccessBlocker);
10743   templ->Set(v8_str("a"), v8_str("a"));
10744   // Add more than 8 (see kMaxFastProperties) properties
10745   // so that the constructor will force copying map.
10746   // Cannot sprintf, gcc complains unsafety.
10747   char buf[4];
10748   for (char i = '0'; i <= '9' ; i++) {
10749     buf[0] = i;
10750     for (char j = '0'; j <= '9'; j++) {
10751       buf[1] = j;
10752       for (char k = '0'; k <= '9'; k++) {
10753         buf[2] = k;
10754         buf[3] = 0;
10755         templ->Set(v8_str(buf), v8::Number::New(k));
10756       }
10757     }
10758   }
10759
10760   Local<v8::Object> instance_1 = templ->NewInstance();
10761   context->Global()->Set(v8_str("obj_1"), instance_1);
10762
10763   Local<Value> value_1 = CompileRun("obj_1.a");
10764   CHECK(value_1->IsUndefined());
10765
10766   Local<v8::Object> instance_2 = templ->NewInstance();
10767   context->Global()->Set(v8_str("obj_2"), instance_2);
10768
10769   Local<Value> value_2 = CompileRun("obj_2.a");
10770   CHECK(value_2->IsUndefined());
10771 }
10772
10773
10774 // This tests that access check information remains on the global
10775 // object template when creating contexts.
10776 THREADED_TEST(AccessControlRepeatedContextCreation) {
10777   v8::HandleScope handle_scope;
10778   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10779   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
10780                                            IndexedSetAccessBlocker);
10781   i::Handle<i::ObjectTemplateInfo> internal_template =
10782       v8::Utils::OpenHandle(*global_template);
10783   CHECK(!internal_template->constructor()->IsUndefined());
10784   i::Handle<i::FunctionTemplateInfo> constructor(
10785       i::FunctionTemplateInfo::cast(internal_template->constructor()));
10786   CHECK(!constructor->access_check_info()->IsUndefined());
10787   v8::Persistent<Context> context0(Context::New(NULL, global_template));
10788   CHECK(!constructor->access_check_info()->IsUndefined());
10789 }
10790
10791
10792 THREADED_TEST(TurnOnAccessCheck) {
10793   v8::HandleScope handle_scope;
10794
10795   // Create an environment with access check to the global object disabled by
10796   // default.
10797   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10798   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
10799                                            IndexedGetAccessBlocker,
10800                                            v8::Handle<v8::Value>(),
10801                                            false);
10802   v8::Persistent<Context> context = Context::New(NULL, global_template);
10803   Context::Scope context_scope(context);
10804
10805   // Set up a property and a number of functions.
10806   context->Global()->Set(v8_str("a"), v8_num(1));
10807   CompileRun("function f1() {return a;}"
10808              "function f2() {return a;}"
10809              "function g1() {return h();}"
10810              "function g2() {return h();}"
10811              "function h() {return 1;}");
10812   Local<Function> f1 =
10813       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10814   Local<Function> f2 =
10815       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10816   Local<Function> g1 =
10817       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10818   Local<Function> g2 =
10819       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10820   Local<Function> h =
10821       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10822
10823   // Get the global object.
10824   v8::Handle<v8::Object> global = context->Global();
10825
10826   // Call f1 one time and f2 a number of times. This will ensure that f1 still
10827   // uses the runtime system to retreive property a whereas f2 uses global load
10828   // inline cache.
10829   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10830   for (int i = 0; i < 4; i++) {
10831     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10832   }
10833
10834   // Same for g1 and g2.
10835   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10836   for (int i = 0; i < 4; i++) {
10837     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10838   }
10839
10840   // Detach the global and turn on access check.
10841   context->DetachGlobal();
10842   context->Global()->TurnOnAccessCheck();
10843
10844   // Failing access check to property get results in undefined.
10845   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10846   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10847
10848   // Failing access check to function call results in exception.
10849   CHECK(g1->Call(global, 0, NULL).IsEmpty());
10850   CHECK(g2->Call(global, 0, NULL).IsEmpty());
10851
10852   // No failing access check when just returning a constant.
10853   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10854 }
10855
10856
10857 v8::Handle<v8::String> a;
10858 v8::Handle<v8::String> h;
10859
10860 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
10861                                        Local<Value> name,
10862                                        v8::AccessType type,
10863                                        Local<Value> data) {
10864   return !(name->Equals(a) || name->Equals(h));
10865 }
10866
10867
10868 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
10869   v8::HandleScope handle_scope;
10870
10871   // Create an environment with access check to the global object disabled by
10872   // default. When the registered access checker will block access to properties
10873   // a and h
10874   a = v8_str("a");
10875   h = v8_str("h");
10876   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
10877   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
10878                                            IndexedGetAccessBlocker,
10879                                            v8::Handle<v8::Value>(),
10880                                            false);
10881   v8::Persistent<Context> context = Context::New(NULL, global_template);
10882   Context::Scope context_scope(context);
10883
10884   // Set up a property and a number of functions.
10885   context->Global()->Set(v8_str("a"), v8_num(1));
10886   static const char* source = "function f1() {return a;}"
10887                               "function f2() {return a;}"
10888                               "function g1() {return h();}"
10889                               "function g2() {return h();}"
10890                               "function h() {return 1;}";
10891
10892   CompileRun(source);
10893   Local<Function> f1;
10894   Local<Function> f2;
10895   Local<Function> g1;
10896   Local<Function> g2;
10897   Local<Function> h;
10898   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10899   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10900   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10901   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10902   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
10903
10904   // Get the global object.
10905   v8::Handle<v8::Object> global = context->Global();
10906
10907   // Call f1 one time and f2 a number of times. This will ensure that f1 still
10908   // uses the runtime system to retreive property a whereas f2 uses global load
10909   // inline cache.
10910   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
10911   for (int i = 0; i < 4; i++) {
10912     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
10913   }
10914
10915   // Same for g1 and g2.
10916   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
10917   for (int i = 0; i < 4; i++) {
10918     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
10919   }
10920
10921   // Detach the global and turn on access check now blocking access to property
10922   // a and function h.
10923   context->DetachGlobal();
10924   context->Global()->TurnOnAccessCheck();
10925
10926   // Failing access check to property get results in undefined.
10927   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10928   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10929
10930   // Failing access check to function call results in exception.
10931   CHECK(g1->Call(global, 0, NULL).IsEmpty());
10932   CHECK(g2->Call(global, 0, NULL).IsEmpty());
10933
10934   // No failing access check when just returning a constant.
10935   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
10936
10937   // Now compile the source again. And get the newly compiled functions, except
10938   // for h for which access is blocked.
10939   CompileRun(source);
10940   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
10941   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
10942   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
10943   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
10944   CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
10945
10946   // Failing access check to property get results in undefined.
10947   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
10948   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
10949
10950   // Failing access check to function call results in exception.
10951   CHECK(g1->Call(global, 0, NULL).IsEmpty());
10952   CHECK(g2->Call(global, 0, NULL).IsEmpty());
10953 }
10954
10955
10956 // This test verifies that pre-compilation (aka preparsing) can be called
10957 // without initializing the whole VM. Thus we cannot run this test in a
10958 // multi-threaded setup.
10959 TEST(PreCompile) {
10960   // TODO(155): This test would break without the initialization of V8. This is
10961   // a workaround for now to make this test not fail.
10962   v8::V8::Initialize();
10963   const char* script = "function foo(a) { return a+1; }";
10964   v8::ScriptData* sd =
10965       v8::ScriptData::PreCompile(script, i::StrLength(script));
10966   CHECK_NE(sd->Length(), 0);
10967   CHECK_NE(sd->Data(), NULL);
10968   CHECK(!sd->HasError());
10969   delete sd;
10970 }
10971
10972
10973 TEST(PreCompileWithError) {
10974   v8::V8::Initialize();
10975   const char* script = "function foo(a) { return 1 * * 2; }";
10976   v8::ScriptData* sd =
10977       v8::ScriptData::PreCompile(script, i::StrLength(script));
10978   CHECK(sd->HasError());
10979   delete sd;
10980 }
10981
10982
10983 TEST(Regress31661) {
10984   v8::V8::Initialize();
10985   const char* script = " The Definintive Guide";
10986   v8::ScriptData* sd =
10987       v8::ScriptData::PreCompile(script, i::StrLength(script));
10988   CHECK(sd->HasError());
10989   delete sd;
10990 }
10991
10992
10993 // Tests that ScriptData can be serialized and deserialized.
10994 TEST(PreCompileSerialization) {
10995   v8::V8::Initialize();
10996   const char* script = "function foo(a) { return a+1; }";
10997   v8::ScriptData* sd =
10998       v8::ScriptData::PreCompile(script, i::StrLength(script));
10999
11000   // Serialize.
11001   int serialized_data_length = sd->Length();
11002   char* serialized_data = i::NewArray<char>(serialized_data_length);
11003   memcpy(serialized_data, sd->Data(), serialized_data_length);
11004
11005   // Deserialize.
11006   v8::ScriptData* deserialized_sd =
11007       v8::ScriptData::New(serialized_data, serialized_data_length);
11008
11009   // Verify that the original is the same as the deserialized.
11010   CHECK_EQ(sd->Length(), deserialized_sd->Length());
11011   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
11012   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
11013
11014   delete sd;
11015   delete deserialized_sd;
11016 }
11017
11018
11019 // Attempts to deserialize bad data.
11020 TEST(PreCompileDeserializationError) {
11021   v8::V8::Initialize();
11022   const char* data = "DONT CARE";
11023   int invalid_size = 3;
11024   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
11025
11026   CHECK_EQ(0, sd->Length());
11027
11028   delete sd;
11029 }
11030
11031
11032 // Attempts to deserialize bad data.
11033 TEST(PreCompileInvalidPreparseDataError) {
11034   v8::V8::Initialize();
11035   v8::HandleScope scope;
11036   LocalContext context;
11037
11038   const char* script = "function foo(){ return 5;}\n"
11039       "function bar(){ return 6 + 7;}  foo();";
11040   v8::ScriptData* sd =
11041       v8::ScriptData::PreCompile(script, i::StrLength(script));
11042   CHECK(!sd->HasError());
11043   // ScriptDataImpl private implementation details
11044   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
11045   const int kFunctionEntrySize = i::FunctionEntry::kSize;
11046   const int kFunctionEntryStartOffset = 0;
11047   const int kFunctionEntryEndOffset = 1;
11048   unsigned* sd_data =
11049       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11050
11051   // Overwrite function bar's end position with 0.
11052   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
11053   v8::TryCatch try_catch;
11054
11055   Local<String> source = String::New(script);
11056   Local<Script> compiled_script = Script::New(source, NULL, sd);
11057   CHECK(try_catch.HasCaught());
11058   String::AsciiValue exception_value(try_catch.Message()->Get());
11059   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
11060            *exception_value);
11061
11062   try_catch.Reset();
11063
11064   // Overwrite function bar's start position with 200.  The function entry
11065   // will not be found when searching for it by position and we should fall
11066   // back on eager compilation.
11067   sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
11068   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
11069   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
11070       200;
11071   compiled_script = Script::New(source, NULL, sd);
11072   CHECK(!try_catch.HasCaught());
11073
11074   delete sd;
11075 }
11076
11077
11078 // Verifies that the Handle<String> and const char* versions of the API produce
11079 // the same results (at least for one trivial case).
11080 TEST(PreCompileAPIVariationsAreSame) {
11081   v8::V8::Initialize();
11082   v8::HandleScope scope;
11083
11084   const char* cstring = "function foo(a) { return a+1; }";
11085
11086   v8::ScriptData* sd_from_cstring =
11087       v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
11088
11089   TestAsciiResource* resource = new TestAsciiResource(cstring);
11090   v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
11091       v8::String::NewExternal(resource));
11092
11093   v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
11094       v8::String::New(cstring));
11095
11096   CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
11097   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11098                      sd_from_external_string->Data(),
11099                      sd_from_cstring->Length()));
11100
11101   CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
11102   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
11103                      sd_from_string->Data(),
11104                      sd_from_cstring->Length()));
11105
11106
11107   delete sd_from_cstring;
11108   delete sd_from_external_string;
11109   delete sd_from_string;
11110 }
11111
11112
11113 // This tests that we do not allow dictionary load/call inline caches
11114 // to use functions that have not yet been compiled.  The potential
11115 // problem of loading a function that has not yet been compiled can
11116 // arise because we share code between contexts via the compilation
11117 // cache.
11118 THREADED_TEST(DictionaryICLoadedFunction) {
11119   v8::HandleScope scope;
11120   // Test LoadIC.
11121   for (int i = 0; i < 2; i++) {
11122     LocalContext context;
11123     context->Global()->Set(v8_str("tmp"), v8::True());
11124     context->Global()->Delete(v8_str("tmp"));
11125     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
11126   }
11127   // Test CallIC.
11128   for (int i = 0; i < 2; i++) {
11129     LocalContext context;
11130     context->Global()->Set(v8_str("tmp"), v8::True());
11131     context->Global()->Delete(v8_str("tmp"));
11132     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
11133   }
11134 }
11135
11136
11137 // Test that cross-context new calls use the context of the callee to
11138 // create the new JavaScript object.
11139 THREADED_TEST(CrossContextNew) {
11140   v8::HandleScope scope;
11141   v8::Persistent<Context> context0 = Context::New();
11142   v8::Persistent<Context> context1 = Context::New();
11143
11144   // Allow cross-domain access.
11145   Local<String> token = v8_str("<security token>");
11146   context0->SetSecurityToken(token);
11147   context1->SetSecurityToken(token);
11148
11149   // Set an 'x' property on the Object prototype and define a
11150   // constructor function in context0.
11151   context0->Enter();
11152   CompileRun("Object.prototype.x = 42; function C() {};");
11153   context0->Exit();
11154
11155   // Call the constructor function from context0 and check that the
11156   // result has the 'x' property.
11157   context1->Enter();
11158   context1->Global()->Set(v8_str("other"), context0->Global());
11159   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
11160   CHECK(value->IsInt32());
11161   CHECK_EQ(42, value->Int32Value());
11162   context1->Exit();
11163
11164   // Dispose the contexts to allow them to be garbage collected.
11165   context0.Dispose();
11166   context1.Dispose();
11167 }
11168
11169
11170 class RegExpInterruptTest {
11171  public:
11172   RegExpInterruptTest() : block_(NULL) {}
11173   ~RegExpInterruptTest() { delete block_; }
11174   void RunTest() {
11175     block_ = i::OS::CreateSemaphore(0);
11176     gc_count_ = 0;
11177     gc_during_regexp_ = 0;
11178     regexp_success_ = false;
11179     gc_success_ = false;
11180     GCThread gc_thread(this);
11181     gc_thread.Start();
11182     v8::Locker::StartPreemption(1);
11183
11184     LongRunningRegExp();
11185     {
11186       v8::Unlocker unlock;
11187       gc_thread.Join();
11188     }
11189     v8::Locker::StopPreemption();
11190     CHECK(regexp_success_);
11191     CHECK(gc_success_);
11192   }
11193
11194  private:
11195   // Number of garbage collections required.
11196   static const int kRequiredGCs = 5;
11197
11198   class GCThread : public i::Thread {
11199    public:
11200     explicit GCThread(RegExpInterruptTest* test)
11201         : Thread("GCThread"), test_(test) {}
11202     virtual void Run() {
11203       test_->CollectGarbage();
11204     }
11205    private:
11206      RegExpInterruptTest* test_;
11207   };
11208
11209   void CollectGarbage() {
11210     block_->Wait();
11211     while (gc_during_regexp_ < kRequiredGCs) {
11212       {
11213         v8::Locker lock;
11214         // TODO(lrn): Perhaps create some garbage before collecting.
11215         HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11216         gc_count_++;
11217       }
11218       i::OS::Sleep(1);
11219     }
11220     gc_success_ = true;
11221   }
11222
11223   void LongRunningRegExp() {
11224     block_->Signal();  // Enable garbage collection thread on next preemption.
11225     int rounds = 0;
11226     while (gc_during_regexp_ < kRequiredGCs) {
11227       int gc_before = gc_count_;
11228       {
11229         // Match 15-30 "a"'s against 14 and a "b".
11230         const char* c_source =
11231             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11232             ".exec('aaaaaaaaaaaaaaab') === null";
11233         Local<String> source = String::New(c_source);
11234         Local<Script> script = Script::Compile(source);
11235         Local<Value> result = script->Run();
11236         if (!result->BooleanValue()) {
11237           gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
11238           return;
11239         }
11240       }
11241       {
11242         // Match 15-30 "a"'s against 15 and a "b".
11243         const char* c_source =
11244             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11245             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
11246         Local<String> source = String::New(c_source);
11247         Local<Script> script = Script::Compile(source);
11248         Local<Value> result = script->Run();
11249         if (!result->BooleanValue()) {
11250           gc_during_regexp_ = kRequiredGCs;
11251           return;
11252         }
11253       }
11254       int gc_after = gc_count_;
11255       gc_during_regexp_ += gc_after - gc_before;
11256       rounds++;
11257       i::OS::Sleep(1);
11258     }
11259     regexp_success_ = true;
11260   }
11261
11262   i::Semaphore* block_;
11263   int gc_count_;
11264   int gc_during_regexp_;
11265   bool regexp_success_;
11266   bool gc_success_;
11267 };
11268
11269
11270 // Test that a regular expression execution can be interrupted and
11271 // survive a garbage collection.
11272 TEST(RegExpInterruption) {
11273   v8::Locker lock;
11274   v8::V8::Initialize();
11275   v8::HandleScope scope;
11276   Local<Context> local_env;
11277   {
11278     LocalContext env;
11279     local_env = env.local();
11280   }
11281
11282   // Local context should still be live.
11283   CHECK(!local_env.IsEmpty());
11284   local_env->Enter();
11285
11286   // Should complete without problems.
11287   RegExpInterruptTest().RunTest();
11288
11289   local_env->Exit();
11290 }
11291
11292
11293 class ApplyInterruptTest {
11294  public:
11295   ApplyInterruptTest() : block_(NULL) {}
11296   ~ApplyInterruptTest() { delete block_; }
11297   void RunTest() {
11298     block_ = i::OS::CreateSemaphore(0);
11299     gc_count_ = 0;
11300     gc_during_apply_ = 0;
11301     apply_success_ = false;
11302     gc_success_ = false;
11303     GCThread gc_thread(this);
11304     gc_thread.Start();
11305     v8::Locker::StartPreemption(1);
11306
11307     LongRunningApply();
11308     {
11309       v8::Unlocker unlock;
11310       gc_thread.Join();
11311     }
11312     v8::Locker::StopPreemption();
11313     CHECK(apply_success_);
11314     CHECK(gc_success_);
11315   }
11316
11317  private:
11318   // Number of garbage collections required.
11319   static const int kRequiredGCs = 2;
11320
11321   class GCThread : public i::Thread {
11322    public:
11323     explicit GCThread(ApplyInterruptTest* test)
11324         : Thread("GCThread"), test_(test) {}
11325     virtual void Run() {
11326       test_->CollectGarbage();
11327     }
11328    private:
11329      ApplyInterruptTest* test_;
11330   };
11331
11332   void CollectGarbage() {
11333     block_->Wait();
11334     while (gc_during_apply_ < kRequiredGCs) {
11335       {
11336         v8::Locker lock;
11337         HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
11338         gc_count_++;
11339       }
11340       i::OS::Sleep(1);
11341     }
11342     gc_success_ = true;
11343   }
11344
11345   void LongRunningApply() {
11346     block_->Signal();
11347     int rounds = 0;
11348     while (gc_during_apply_ < kRequiredGCs) {
11349       int gc_before = gc_count_;
11350       {
11351         const char* c_source =
11352             "function do_very_little(bar) {"
11353             "  this.foo = bar;"
11354             "}"
11355             "for (var i = 0; i < 100000; i++) {"
11356             "  do_very_little.apply(this, ['bar']);"
11357             "}";
11358         Local<String> source = String::New(c_source);
11359         Local<Script> script = Script::Compile(source);
11360         Local<Value> result = script->Run();
11361         // Check that no exception was thrown.
11362         CHECK(!result.IsEmpty());
11363       }
11364       int gc_after = gc_count_;
11365       gc_during_apply_ += gc_after - gc_before;
11366       rounds++;
11367     }
11368     apply_success_ = true;
11369   }
11370
11371   i::Semaphore* block_;
11372   int gc_count_;
11373   int gc_during_apply_;
11374   bool apply_success_;
11375   bool gc_success_;
11376 };
11377
11378
11379 // Test that nothing bad happens if we get a preemption just when we were
11380 // about to do an apply().
11381 TEST(ApplyInterruption) {
11382   v8::Locker lock;
11383   v8::V8::Initialize();
11384   v8::HandleScope scope;
11385   Local<Context> local_env;
11386   {
11387     LocalContext env;
11388     local_env = env.local();
11389   }
11390
11391   // Local context should still be live.
11392   CHECK(!local_env.IsEmpty());
11393   local_env->Enter();
11394
11395   // Should complete without problems.
11396   ApplyInterruptTest().RunTest();
11397
11398   local_env->Exit();
11399 }
11400
11401
11402 // Verify that we can clone an object
11403 TEST(ObjectClone) {
11404   v8::HandleScope scope;
11405   LocalContext env;
11406
11407   const char* sample =
11408     "var rv = {};"      \
11409     "rv.alpha = 'hello';" \
11410     "rv.beta = 123;"     \
11411     "rv;";
11412
11413   // Create an object, verify basics.
11414   Local<Value> val = CompileRun(sample);
11415   CHECK(val->IsObject());
11416   Local<v8::Object> obj = val.As<v8::Object>();
11417   obj->Set(v8_str("gamma"), v8_str("cloneme"));
11418
11419   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
11420   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11421   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
11422
11423   // Clone it.
11424   Local<v8::Object> clone = obj->Clone();
11425   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
11426   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
11427   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
11428
11429   // Set a property on the clone, verify each object.
11430   clone->Set(v8_str("beta"), v8::Integer::New(456));
11431   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
11432   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
11433 }
11434
11435
11436 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
11437  public:
11438   explicit AsciiVectorResource(i::Vector<const char> vector)
11439       : data_(vector) {}
11440   virtual ~AsciiVectorResource() {}
11441   virtual size_t length() const { return data_.length(); }
11442   virtual const char* data() const { return data_.start(); }
11443  private:
11444   i::Vector<const char> data_;
11445 };
11446
11447
11448 class UC16VectorResource : public v8::String::ExternalStringResource {
11449  public:
11450   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
11451       : data_(vector) {}
11452   virtual ~UC16VectorResource() {}
11453   virtual size_t length() const { return data_.length(); }
11454   virtual const i::uc16* data() const { return data_.start(); }
11455  private:
11456   i::Vector<const i::uc16> data_;
11457 };
11458
11459
11460 static void MorphAString(i::String* string,
11461                          AsciiVectorResource* ascii_resource,
11462                          UC16VectorResource* uc16_resource) {
11463   CHECK(i::StringShape(string).IsExternal());
11464   if (string->IsAsciiRepresentation()) {
11465     // Check old map is not symbol or long.
11466     CHECK(string->map() == HEAP->external_ascii_string_map());
11467     // Morph external string to be TwoByte string.
11468     string->set_map(HEAP->external_string_map());
11469     i::ExternalTwoByteString* morphed =
11470          i::ExternalTwoByteString::cast(string);
11471     morphed->set_resource(uc16_resource);
11472   } else {
11473     // Check old map is not symbol or long.
11474     CHECK(string->map() == HEAP->external_string_map());
11475     // Morph external string to be ASCII string.
11476     string->set_map(HEAP->external_ascii_string_map());
11477     i::ExternalAsciiString* morphed =
11478          i::ExternalAsciiString::cast(string);
11479     morphed->set_resource(ascii_resource);
11480   }
11481 }
11482
11483
11484 // Test that we can still flatten a string if the components it is built up
11485 // from have been turned into 16 bit strings in the mean time.
11486 THREADED_TEST(MorphCompositeStringTest) {
11487   char utf_buffer[129];
11488   const char* c_string = "Now is the time for all good men"
11489                          " to come to the aid of the party";
11490   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
11491   {
11492     v8::HandleScope scope;
11493     LocalContext env;
11494     AsciiVectorResource ascii_resource(
11495         i::Vector<const char>(c_string, i::StrLength(c_string)));
11496     UC16VectorResource uc16_resource(
11497         i::Vector<const uint16_t>(two_byte_string,
11498                                   i::StrLength(c_string)));
11499
11500     Local<String> lhs(v8::Utils::ToLocal(
11501         FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11502     Local<String> rhs(v8::Utils::ToLocal(
11503         FACTORY->NewExternalStringFromAscii(&ascii_resource)));
11504
11505     env->Global()->Set(v8_str("lhs"), lhs);
11506     env->Global()->Set(v8_str("rhs"), rhs);
11507
11508     CompileRun(
11509         "var cons = lhs + rhs;"
11510         "var slice = lhs.substring(1, lhs.length - 1);"
11511         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
11512
11513     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
11514     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
11515
11516     // This should UTF-8 without flattening, since everything is ASCII.
11517     Handle<String> cons = v8_compile("cons")->Run().As<String>();
11518     CHECK_EQ(128, cons->Utf8Length());
11519     int nchars = -1;
11520     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
11521     CHECK_EQ(128, nchars);
11522     CHECK_EQ(0, strcmp(
11523         utf_buffer,
11524         "Now is the time for all good men to come to the aid of the party"
11525         "Now is the time for all good men to come to the aid of the party"));
11526
11527     // Now do some stuff to make sure the strings are flattened, etc.
11528     CompileRun(
11529         "/[^a-z]/.test(cons);"
11530         "/[^a-z]/.test(slice);"
11531         "/[^a-z]/.test(slice_on_cons);");
11532     const char* expected_cons =
11533         "Now is the time for all good men to come to the aid of the party"
11534         "Now is the time for all good men to come to the aid of the party";
11535     const char* expected_slice =
11536         "ow is the time for all good men to come to the aid of the part";
11537     const char* expected_slice_on_cons =
11538         "ow is the time for all good men to come to the aid of the party"
11539         "Now is the time for all good men to come to the aid of the part";
11540     CHECK_EQ(String::New(expected_cons),
11541              env->Global()->Get(v8_str("cons")));
11542     CHECK_EQ(String::New(expected_slice),
11543              env->Global()->Get(v8_str("slice")));
11544     CHECK_EQ(String::New(expected_slice_on_cons),
11545              env->Global()->Get(v8_str("slice_on_cons")));
11546   }
11547   i::DeleteArray(two_byte_string);
11548 }
11549
11550
11551 TEST(CompileExternalTwoByteSource) {
11552   v8::HandleScope scope;
11553   LocalContext context;
11554
11555   // This is a very short list of sources, which currently is to check for a
11556   // regression caused by r2703.
11557   const char* ascii_sources[] = {
11558     "0.5",
11559     "-0.5",   // This mainly testes PushBack in the Scanner.
11560     "--0.5",  // This mainly testes PushBack in the Scanner.
11561     NULL
11562   };
11563
11564   // Compile the sources as external two byte strings.
11565   for (int i = 0; ascii_sources[i] != NULL; i++) {
11566     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
11567     UC16VectorResource uc16_resource(
11568         i::Vector<const uint16_t>(two_byte_string,
11569                                   i::StrLength(ascii_sources[i])));
11570     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
11571     v8::Script::Compile(source);
11572     i::DeleteArray(two_byte_string);
11573   }
11574 }
11575
11576
11577 class RegExpStringModificationTest {
11578  public:
11579   RegExpStringModificationTest()
11580       : block_(i::OS::CreateSemaphore(0)),
11581         morphs_(0),
11582         morphs_during_regexp_(0),
11583         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
11584         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
11585   ~RegExpStringModificationTest() { delete block_; }
11586   void RunTest() {
11587     regexp_success_ = false;
11588     morph_success_ = false;
11589
11590     // Initialize the contents of two_byte_content_ to be a uc16 representation
11591     // of "aaaaaaaaaaaaaab".
11592     for (int i = 0; i < 14; i++) {
11593       two_byte_content_[i] = 'a';
11594     }
11595     two_byte_content_[14] = 'b';
11596
11597     // Create the input string for the regexp - the one we are going to change
11598     // properties of.
11599     input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_);
11600
11601     // Inject the input as a global variable.
11602     i::Handle<i::String> input_name =
11603         FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5));
11604     i::Isolate::Current()->global_context()->global()->SetProperty(
11605         *input_name,
11606         *input_,
11607         NONE,
11608         i::kNonStrictMode)->ToObjectChecked();
11609
11610     MorphThread morph_thread(this);
11611     morph_thread.Start();
11612     v8::Locker::StartPreemption(1);
11613     LongRunningRegExp();
11614     {
11615       v8::Unlocker unlock;
11616       morph_thread.Join();
11617     }
11618     v8::Locker::StopPreemption();
11619     CHECK(regexp_success_);
11620     CHECK(morph_success_);
11621   }
11622
11623  private:
11624   // Number of string modifications required.
11625   static const int kRequiredModifications = 5;
11626   static const int kMaxModifications = 100;
11627
11628   class MorphThread : public i::Thread {
11629    public:
11630     explicit MorphThread(RegExpStringModificationTest* test)
11631         : Thread("MorphThread"), test_(test) {}
11632     virtual void Run() {
11633       test_->MorphString();
11634     }
11635    private:
11636      RegExpStringModificationTest* test_;
11637   };
11638
11639   void MorphString() {
11640     block_->Wait();
11641     while (morphs_during_regexp_ < kRequiredModifications &&
11642            morphs_ < kMaxModifications) {
11643       {
11644         v8::Locker lock;
11645         // Swap string between ascii and two-byte representation.
11646         i::String* string = *input_;
11647         MorphAString(string, &ascii_resource_, &uc16_resource_);
11648         morphs_++;
11649       }
11650       i::OS::Sleep(1);
11651     }
11652     morph_success_ = true;
11653   }
11654
11655   void LongRunningRegExp() {
11656     block_->Signal();  // Enable morphing thread on next preemption.
11657     while (morphs_during_regexp_ < kRequiredModifications &&
11658            morphs_ < kMaxModifications) {
11659       int morphs_before = morphs_;
11660       {
11661         v8::HandleScope scope;
11662         // Match 15-30 "a"'s against 14 and a "b".
11663         const char* c_source =
11664             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
11665             ".exec(input) === null";
11666         Local<String> source = String::New(c_source);
11667         Local<Script> script = Script::Compile(source);
11668         Local<Value> result = script->Run();
11669         CHECK(result->IsTrue());
11670       }
11671       int morphs_after = morphs_;
11672       morphs_during_regexp_ += morphs_after - morphs_before;
11673     }
11674     regexp_success_ = true;
11675   }
11676
11677   i::uc16 two_byte_content_[15];
11678   i::Semaphore* block_;
11679   int morphs_;
11680   int morphs_during_regexp_;
11681   bool regexp_success_;
11682   bool morph_success_;
11683   i::Handle<i::String> input_;
11684   AsciiVectorResource ascii_resource_;
11685   UC16VectorResource uc16_resource_;
11686 };
11687
11688
11689 // Test that a regular expression execution can be interrupted and
11690 // the string changed without failing.
11691 TEST(RegExpStringModification) {
11692   v8::Locker lock;
11693   v8::V8::Initialize();
11694   v8::HandleScope scope;
11695   Local<Context> local_env;
11696   {
11697     LocalContext env;
11698     local_env = env.local();
11699   }
11700
11701   // Local context should still be live.
11702   CHECK(!local_env.IsEmpty());
11703   local_env->Enter();
11704
11705   // Should complete without problems.
11706   RegExpStringModificationTest().RunTest();
11707
11708   local_env->Exit();
11709 }
11710
11711
11712 // Test that we can set a property on the global object even if there
11713 // is a read-only property in the prototype chain.
11714 TEST(ReadOnlyPropertyInGlobalProto) {
11715   v8::HandleScope scope;
11716   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11717   LocalContext context(0, templ);
11718   v8::Handle<v8::Object> global = context->Global();
11719   v8::Handle<v8::Object> global_proto =
11720       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
11721   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
11722   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
11723   // Check without 'eval' or 'with'.
11724   v8::Handle<v8::Value> res =
11725       CompileRun("function f() { x = 42; return x; }; f()");
11726   // Check with 'eval'.
11727   res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
11728   CHECK_EQ(v8::Integer::New(42), res);
11729   // Check with 'with'.
11730   res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
11731   CHECK_EQ(v8::Integer::New(42), res);
11732 }
11733
11734 static int force_set_set_count = 0;
11735 static int force_set_get_count = 0;
11736 bool pass_on_get = false;
11737
11738 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
11739                                             const v8::AccessorInfo& info) {
11740   force_set_get_count++;
11741   if (pass_on_get) {
11742     return v8::Handle<v8::Value>();
11743   } else {
11744     return v8::Int32::New(3);
11745   }
11746 }
11747
11748 static void ForceSetSetter(v8::Local<v8::String> name,
11749                            v8::Local<v8::Value> value,
11750                            const v8::AccessorInfo& info) {
11751   force_set_set_count++;
11752 }
11753
11754 static v8::Handle<v8::Value> ForceSetInterceptSetter(
11755     v8::Local<v8::String> name,
11756     v8::Local<v8::Value> value,
11757     const v8::AccessorInfo& info) {
11758   force_set_set_count++;
11759   return v8::Undefined();
11760 }
11761
11762 TEST(ForceSet) {
11763   force_set_get_count = 0;
11764   force_set_set_count = 0;
11765   pass_on_get = false;
11766
11767   v8::HandleScope scope;
11768   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11769   v8::Handle<v8::String> access_property = v8::String::New("a");
11770   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
11771   LocalContext context(NULL, templ);
11772   v8::Handle<v8::Object> global = context->Global();
11773
11774   // Ordinary properties
11775   v8::Handle<v8::String> simple_property = v8::String::New("p");
11776   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
11777   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11778   // This should fail because the property is read-only
11779   global->Set(simple_property, v8::Int32::New(5));
11780   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11781   // This should succeed even though the property is read-only
11782   global->ForceSet(simple_property, v8::Int32::New(6));
11783   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
11784
11785   // Accessors
11786   CHECK_EQ(0, force_set_set_count);
11787   CHECK_EQ(0, force_set_get_count);
11788   CHECK_EQ(3, global->Get(access_property)->Int32Value());
11789   // CHECK_EQ the property shouldn't override it, just call the setter
11790   // which in this case does nothing.
11791   global->Set(access_property, v8::Int32::New(7));
11792   CHECK_EQ(3, global->Get(access_property)->Int32Value());
11793   CHECK_EQ(1, force_set_set_count);
11794   CHECK_EQ(2, force_set_get_count);
11795   // Forcing the property to be set should override the accessor without
11796   // calling it
11797   global->ForceSet(access_property, v8::Int32::New(8));
11798   CHECK_EQ(8, global->Get(access_property)->Int32Value());
11799   CHECK_EQ(1, force_set_set_count);
11800   CHECK_EQ(2, force_set_get_count);
11801 }
11802
11803 TEST(ForceSetWithInterceptor) {
11804   force_set_get_count = 0;
11805   force_set_set_count = 0;
11806   pass_on_get = false;
11807
11808   v8::HandleScope scope;
11809   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11810   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
11811   LocalContext context(NULL, templ);
11812   v8::Handle<v8::Object> global = context->Global();
11813
11814   v8::Handle<v8::String> some_property = v8::String::New("a");
11815   CHECK_EQ(0, force_set_set_count);
11816   CHECK_EQ(0, force_set_get_count);
11817   CHECK_EQ(3, global->Get(some_property)->Int32Value());
11818   // Setting the property shouldn't override it, just call the setter
11819   // which in this case does nothing.
11820   global->Set(some_property, v8::Int32::New(7));
11821   CHECK_EQ(3, global->Get(some_property)->Int32Value());
11822   CHECK_EQ(1, force_set_set_count);
11823   CHECK_EQ(2, force_set_get_count);
11824   // Getting the property when the interceptor returns an empty handle
11825   // should yield undefined, since the property isn't present on the
11826   // object itself yet.
11827   pass_on_get = true;
11828   CHECK(global->Get(some_property)->IsUndefined());
11829   CHECK_EQ(1, force_set_set_count);
11830   CHECK_EQ(3, force_set_get_count);
11831   // Forcing the property to be set should cause the value to be
11832   // set locally without calling the interceptor.
11833   global->ForceSet(some_property, v8::Int32::New(8));
11834   CHECK_EQ(8, global->Get(some_property)->Int32Value());
11835   CHECK_EQ(1, force_set_set_count);
11836   CHECK_EQ(4, force_set_get_count);
11837   // Reenabling the interceptor should cause it to take precedence over
11838   // the property
11839   pass_on_get = false;
11840   CHECK_EQ(3, global->Get(some_property)->Int32Value());
11841   CHECK_EQ(1, force_set_set_count);
11842   CHECK_EQ(5, force_set_get_count);
11843   // The interceptor should also work for other properties
11844   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
11845   CHECK_EQ(1, force_set_set_count);
11846   CHECK_EQ(6, force_set_get_count);
11847 }
11848
11849
11850 THREADED_TEST(ForceDelete) {
11851   v8::HandleScope scope;
11852   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11853   LocalContext context(NULL, templ);
11854   v8::Handle<v8::Object> global = context->Global();
11855
11856   // Ordinary properties
11857   v8::Handle<v8::String> simple_property = v8::String::New("p");
11858   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
11859   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11860   // This should fail because the property is dont-delete.
11861   CHECK(!global->Delete(simple_property));
11862   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
11863   // This should succeed even though the property is dont-delete.
11864   CHECK(global->ForceDelete(simple_property));
11865   CHECK(global->Get(simple_property)->IsUndefined());
11866 }
11867
11868
11869 static int force_delete_interceptor_count = 0;
11870 static bool pass_on_delete = false;
11871
11872
11873 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
11874     v8::Local<v8::String> name,
11875     const v8::AccessorInfo& info) {
11876   force_delete_interceptor_count++;
11877   if (pass_on_delete) {
11878     return v8::Handle<v8::Boolean>();
11879   } else {
11880     return v8::True();
11881   }
11882 }
11883
11884
11885 THREADED_TEST(ForceDeleteWithInterceptor) {
11886   force_delete_interceptor_count = 0;
11887   pass_on_delete = false;
11888
11889   v8::HandleScope scope;
11890   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
11891   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
11892   LocalContext context(NULL, templ);
11893   v8::Handle<v8::Object> global = context->Global();
11894
11895   v8::Handle<v8::String> some_property = v8::String::New("a");
11896   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
11897
11898   // Deleting a property should get intercepted and nothing should
11899   // happen.
11900   CHECK_EQ(0, force_delete_interceptor_count);
11901   CHECK(global->Delete(some_property));
11902   CHECK_EQ(1, force_delete_interceptor_count);
11903   CHECK_EQ(42, global->Get(some_property)->Int32Value());
11904   // Deleting the property when the interceptor returns an empty
11905   // handle should not delete the property since it is DontDelete.
11906   pass_on_delete = true;
11907   CHECK(!global->Delete(some_property));
11908   CHECK_EQ(2, force_delete_interceptor_count);
11909   CHECK_EQ(42, global->Get(some_property)->Int32Value());
11910   // Forcing the property to be deleted should delete the value
11911   // without calling the interceptor.
11912   CHECK(global->ForceDelete(some_property));
11913   CHECK(global->Get(some_property)->IsUndefined());
11914   CHECK_EQ(2, force_delete_interceptor_count);
11915 }
11916
11917
11918 // Make sure that forcing a delete invalidates any IC stubs, so we
11919 // don't read the hole value.
11920 THREADED_TEST(ForceDeleteIC) {
11921   v8::HandleScope scope;
11922   LocalContext context;
11923   // Create a DontDelete variable on the global object.
11924   CompileRun("this.__proto__ = { foo: 'horse' };"
11925              "var foo = 'fish';"
11926              "function f() { return foo.length; }");
11927   // Initialize the IC for foo in f.
11928   CompileRun("for (var i = 0; i < 4; i++) f();");
11929   // Make sure the value of foo is correct before the deletion.
11930   CHECK_EQ(4, CompileRun("f()")->Int32Value());
11931   // Force the deletion of foo.
11932   CHECK(context->Global()->ForceDelete(v8_str("foo")));
11933   // Make sure the value for foo is read from the prototype, and that
11934   // we don't get in trouble with reading the deleted cell value
11935   // sentinel.
11936   CHECK_EQ(5, CompileRun("f()")->Int32Value());
11937 }
11938
11939
11940 v8::Persistent<Context> calling_context0;
11941 v8::Persistent<Context> calling_context1;
11942 v8::Persistent<Context> calling_context2;
11943
11944
11945 // Check that the call to the callback is initiated in
11946 // calling_context2, the directly calling context is calling_context1
11947 // and the callback itself is in calling_context0.
11948 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
11949   ApiTestFuzzer::Fuzz();
11950   CHECK(Context::GetCurrent() == calling_context0);
11951   CHECK(Context::GetCalling() == calling_context1);
11952   CHECK(Context::GetEntered() == calling_context2);
11953   return v8::Integer::New(42);
11954 }
11955
11956
11957 THREADED_TEST(GetCallingContext) {
11958   v8::HandleScope scope;
11959
11960   calling_context0 = Context::New();
11961   calling_context1 = Context::New();
11962   calling_context2 = Context::New();
11963
11964   // Allow cross-domain access.
11965   Local<String> token = v8_str("<security token>");
11966   calling_context0->SetSecurityToken(token);
11967   calling_context1->SetSecurityToken(token);
11968   calling_context2->SetSecurityToken(token);
11969
11970   // Create an object with a C++ callback in context0.
11971   calling_context0->Enter();
11972   Local<v8::FunctionTemplate> callback_templ =
11973       v8::FunctionTemplate::New(GetCallingContextCallback);
11974   calling_context0->Global()->Set(v8_str("callback"),
11975                                   callback_templ->GetFunction());
11976   calling_context0->Exit();
11977
11978   // Expose context0 in context1 and setup a function that calls the
11979   // callback function.
11980   calling_context1->Enter();
11981   calling_context1->Global()->Set(v8_str("context0"),
11982                                   calling_context0->Global());
11983   CompileRun("function f() { context0.callback() }");
11984   calling_context1->Exit();
11985
11986   // Expose context1 in context2 and call the callback function in
11987   // context0 indirectly through f in context1.
11988   calling_context2->Enter();
11989   calling_context2->Global()->Set(v8_str("context1"),
11990                                   calling_context1->Global());
11991   CompileRun("context1.f()");
11992   calling_context2->Exit();
11993
11994   // Dispose the contexts to allow them to be garbage collected.
11995   calling_context0.Dispose();
11996   calling_context1.Dispose();
11997   calling_context2.Dispose();
11998   calling_context0.Clear();
11999   calling_context1.Clear();
12000   calling_context2.Clear();
12001 }
12002
12003
12004 // Check that a variable declaration with no explicit initialization
12005 // value does not shadow an existing property in the prototype chain.
12006 //
12007 // This is consistent with Firefox and Safari.
12008 //
12009 // See http://crbug.com/12548.
12010 THREADED_TEST(InitGlobalVarInProtoChain) {
12011   v8::HandleScope scope;
12012   LocalContext context;
12013   // Introduce a variable in the prototype chain.
12014   CompileRun("__proto__.x = 42");
12015   v8::Handle<v8::Value> result = CompileRun("var x; x");
12016   CHECK(!result->IsUndefined());
12017   CHECK_EQ(42, result->Int32Value());
12018 }
12019
12020
12021 // Regression test for issue 398.
12022 // If a function is added to an object, creating a constant function
12023 // field, and the result is cloned, replacing the constant function on the
12024 // original should not affect the clone.
12025 // See http://code.google.com/p/v8/issues/detail?id=398
12026 THREADED_TEST(ReplaceConstantFunction) {
12027   v8::HandleScope scope;
12028   LocalContext context;
12029   v8::Handle<v8::Object> obj = v8::Object::New();
12030   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
12031   v8::Handle<v8::String> foo_string = v8::String::New("foo");
12032   obj->Set(foo_string, func_templ->GetFunction());
12033   v8::Handle<v8::Object> obj_clone = obj->Clone();
12034   obj_clone->Set(foo_string, v8::String::New("Hello"));
12035   CHECK(!obj->Get(foo_string)->IsUndefined());
12036 }
12037
12038
12039 // Regression test for http://crbug.com/16276.
12040 THREADED_TEST(Regress16276) {
12041   v8::HandleScope scope;
12042   LocalContext context;
12043   // Force the IC in f to be a dictionary load IC.
12044   CompileRun("function f(obj) { return obj.x; }\n"
12045              "var obj = { x: { foo: 42 }, y: 87 };\n"
12046              "var x = obj.x;\n"
12047              "delete obj.y;\n"
12048              "for (var i = 0; i < 5; i++) f(obj);");
12049   // Detach the global object to make 'this' refer directly to the
12050   // global object (not the proxy), and make sure that the dictionary
12051   // load IC doesn't mess up loading directly from the global object.
12052   context->DetachGlobal();
12053   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
12054 }
12055
12056
12057 THREADED_TEST(PixelArray) {
12058   v8::HandleScope scope;
12059   LocalContext context;
12060   const int kElementCount = 260;
12061   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12062   i::Handle<i::ExternalPixelArray> pixels =
12063       i::Handle<i::ExternalPixelArray>::cast(
12064           FACTORY->NewExternalArray(kElementCount,
12065                                     v8::kExternalPixelArray,
12066                                     pixel_data));
12067   // Force GC to trigger verification.
12068   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12069   for (int i = 0; i < kElementCount; i++) {
12070     pixels->set(i, i % 256);
12071   }
12072   // Force GC to trigger verification.
12073   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12074   for (int i = 0; i < kElementCount; i++) {
12075     CHECK_EQ(i % 256, pixels->get_scalar(i));
12076     CHECK_EQ(i % 256, pixel_data[i]);
12077   }
12078
12079   v8::Handle<v8::Object> obj = v8::Object::New();
12080   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12081   // Set the elements to be the pixels.
12082   // jsobj->set_elements(*pixels);
12083   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12084   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12085   obj->Set(v8_str("field"), v8::Int32::New(1503));
12086   context->Global()->Set(v8_str("pixels"), obj);
12087   v8::Handle<v8::Value> result = CompileRun("pixels.field");
12088   CHECK_EQ(1503, result->Int32Value());
12089   result = CompileRun("pixels[1]");
12090   CHECK_EQ(1, result->Int32Value());
12091
12092   result = CompileRun("var sum = 0;"
12093                       "for (var i = 0; i < 8; i++) {"
12094                       "  sum += pixels[i] = pixels[i] = -i;"
12095                       "}"
12096                       "sum;");
12097   CHECK_EQ(-28, result->Int32Value());
12098
12099   result = CompileRun("var sum = 0;"
12100                       "for (var i = 0; i < 8; i++) {"
12101                       "  sum += pixels[i] = pixels[i] = 0;"
12102                       "}"
12103                       "sum;");
12104   CHECK_EQ(0, result->Int32Value());
12105
12106   result = CompileRun("var sum = 0;"
12107                       "for (var i = 0; i < 8; i++) {"
12108                       "  sum += pixels[i] = pixels[i] = 255;"
12109                       "}"
12110                       "sum;");
12111   CHECK_EQ(8 * 255, result->Int32Value());
12112
12113   result = CompileRun("var sum = 0;"
12114                       "for (var i = 0; i < 8; i++) {"
12115                       "  sum += pixels[i] = pixels[i] = 256 + i;"
12116                       "}"
12117                       "sum;");
12118   CHECK_EQ(2076, result->Int32Value());
12119
12120   result = CompileRun("var sum = 0;"
12121                       "for (var i = 0; i < 8; i++) {"
12122                       "  sum += pixels[i] = pixels[i] = i;"
12123                       "}"
12124                       "sum;");
12125   CHECK_EQ(28, result->Int32Value());
12126
12127   result = CompileRun("var sum = 0;"
12128                       "for (var i = 0; i < 8; i++) {"
12129                       "  sum += pixels[i];"
12130                       "}"
12131                       "sum;");
12132   CHECK_EQ(28, result->Int32Value());
12133
12134   i::Handle<i::Smi> value(i::Smi::FromInt(2));
12135   i::Handle<i::Object> no_failure;
12136   no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12137   ASSERT(!no_failure.is_null());
12138   i::USE(no_failure);
12139   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12140   *value.location() = i::Smi::FromInt(256);
12141   no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12142   ASSERT(!no_failure.is_null());
12143   i::USE(no_failure);
12144   CHECK_EQ(255,
12145            i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12146   *value.location() = i::Smi::FromInt(-1);
12147   no_failure = i::SetElement(jsobj, 1, value, i::kNonStrictMode);
12148   ASSERT(!no_failure.is_null());
12149   i::USE(no_failure);
12150   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12151
12152   result = CompileRun("for (var i = 0; i < 8; i++) {"
12153                       "  pixels[i] = (i * 65) - 109;"
12154                       "}"
12155                       "pixels[1] + pixels[6];");
12156   CHECK_EQ(255, result->Int32Value());
12157   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12158   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12159   CHECK_EQ(21,
12160            i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12161   CHECK_EQ(86,
12162            i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12163   CHECK_EQ(151,
12164            i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12165   CHECK_EQ(216,
12166            i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12167   CHECK_EQ(255,
12168            i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12169   CHECK_EQ(255,
12170            i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12171   result = CompileRun("var sum = 0;"
12172                       "for (var i = 0; i < 8; i++) {"
12173                       "  sum += pixels[i];"
12174                       "}"
12175                       "sum;");
12176   CHECK_EQ(984, result->Int32Value());
12177
12178   result = CompileRun("for (var i = 0; i < 8; i++) {"
12179                       "  pixels[i] = (i * 1.1);"
12180                       "}"
12181                       "pixels[1] + pixels[6];");
12182   CHECK_EQ(8, result->Int32Value());
12183   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
12184   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
12185   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
12186   CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
12187   CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
12188   CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12189   CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12190   CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12191
12192   result = CompileRun("for (var i = 0; i < 8; i++) {"
12193                       "  pixels[7] = undefined;"
12194                       "}"
12195                       "pixels[7];");
12196   CHECK_EQ(0, result->Int32Value());
12197   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
12198
12199   result = CompileRun("for (var i = 0; i < 8; i++) {"
12200                       "  pixels[6] = '2.3';"
12201                       "}"
12202                       "pixels[6];");
12203   CHECK_EQ(2, result->Int32Value());
12204   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
12205
12206   result = CompileRun("for (var i = 0; i < 8; i++) {"
12207                       "  pixels[5] = NaN;"
12208                       "}"
12209                       "pixels[5];");
12210   CHECK_EQ(0, result->Int32Value());
12211   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12212
12213   result = CompileRun("for (var i = 0; i < 8; i++) {"
12214                       "  pixels[8] = Infinity;"
12215                       "}"
12216                       "pixels[8];");
12217   CHECK_EQ(255, result->Int32Value());
12218   CHECK_EQ(255,
12219            i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
12220
12221   result = CompileRun("for (var i = 0; i < 8; i++) {"
12222                       "  pixels[9] = -Infinity;"
12223                       "}"
12224                       "pixels[9];");
12225   CHECK_EQ(0, result->Int32Value());
12226   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
12227
12228   result = CompileRun("pixels[3] = 33;"
12229                       "delete pixels[3];"
12230                       "pixels[3];");
12231   CHECK_EQ(33, result->Int32Value());
12232
12233   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
12234                       "pixels[2] = 12; pixels[3] = 13;"
12235                       "pixels.__defineGetter__('2',"
12236                       "function() { return 120; });"
12237                       "pixels[2];");
12238   CHECK_EQ(12, result->Int32Value());
12239
12240   result = CompileRun("var js_array = new Array(40);"
12241                       "js_array[0] = 77;"
12242                       "js_array;");
12243   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12244
12245   result = CompileRun("pixels[1] = 23;"
12246                       "pixels.__proto__ = [];"
12247                       "js_array.__proto__ = pixels;"
12248                       "js_array.concat(pixels);");
12249   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12250   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12251
12252   result = CompileRun("pixels[1] = 23;");
12253   CHECK_EQ(23, result->Int32Value());
12254
12255   // Test for index greater than 255.  Regression test for:
12256   // http://code.google.com/p/chromium/issues/detail?id=26337.
12257   result = CompileRun("pixels[256] = 255;");
12258   CHECK_EQ(255, result->Int32Value());
12259   result = CompileRun("var i = 0;"
12260                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
12261                       "i");
12262   CHECK_EQ(255, result->Int32Value());
12263
12264   // Make sure that pixel array ICs recognize when a non-pixel array
12265   // is passed to it.
12266   result = CompileRun("function pa_load(p) {"
12267                       "  var sum = 0;"
12268                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12269                       "  return sum;"
12270                       "}"
12271                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12272                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12273                       "just_ints = new Object();"
12274                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12275                       "for (var i = 0; i < 10; ++i) {"
12276                       "  result = pa_load(just_ints);"
12277                       "}"
12278                       "result");
12279   CHECK_EQ(32640, result->Int32Value());
12280
12281   // Make sure that pixel array ICs recognize out-of-bound accesses.
12282   result = CompileRun("function pa_load(p, start) {"
12283                       "  var sum = 0;"
12284                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
12285                       "  return sum;"
12286                       "}"
12287                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12288                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12289                       "for (var i = 0; i < 10; ++i) {"
12290                       "  result = pa_load(pixels,-10);"
12291                       "}"
12292                       "result");
12293   CHECK_EQ(0, result->Int32Value());
12294
12295   // Make sure that generic ICs properly handles a pixel array.
12296   result = CompileRun("function pa_load(p) {"
12297                       "  var sum = 0;"
12298                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12299                       "  return sum;"
12300                       "}"
12301                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12302                       "just_ints = new Object();"
12303                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12304                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12305                       "for (var i = 0; i < 10; ++i) {"
12306                       "  result = pa_load(pixels);"
12307                       "}"
12308                       "result");
12309   CHECK_EQ(32640, result->Int32Value());
12310
12311   // Make sure that generic load ICs recognize out-of-bound accesses in
12312   // pixel arrays.
12313   result = CompileRun("function pa_load(p, start) {"
12314                       "  var sum = 0;"
12315                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
12316                       "  return sum;"
12317                       "}"
12318                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12319                       "just_ints = new Object();"
12320                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12321                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
12322                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
12323                       "for (var i = 0; i < 10; ++i) {"
12324                       "  result = pa_load(pixels,-10);"
12325                       "}"
12326                       "result");
12327   CHECK_EQ(0, result->Int32Value());
12328
12329   // Make sure that generic ICs properly handles other types than pixel
12330   // arrays (that the inlined fast pixel array test leaves the right information
12331   // in the right registers).
12332   result = CompileRun("function pa_load(p) {"
12333                       "  var sum = 0;"
12334                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
12335                       "  return sum;"
12336                       "}"
12337                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12338                       "just_ints = new Object();"
12339                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12340                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
12341                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
12342                       "sparse_array = new Object();"
12343                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
12344                       "sparse_array[1000000] = 3;"
12345                       "for (var i = 0; i < 10; ++i) {"
12346                       "  result = pa_load(sparse_array);"
12347                       "}"
12348                       "result");
12349   CHECK_EQ(32640, result->Int32Value());
12350
12351   // Make sure that pixel array store ICs clamp values correctly.
12352   result = CompileRun("function pa_store(p) {"
12353                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12354                       "}"
12355                       "pa_store(pixels);"
12356                       "var sum = 0;"
12357                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12358                       "sum");
12359   CHECK_EQ(48896, result->Int32Value());
12360
12361   // Make sure that pixel array stores correctly handle accesses outside
12362   // of the pixel array..
12363   result = CompileRun("function pa_store(p,start) {"
12364                       "  for (var j = 0; j < 256; j++) {"
12365                       "    p[j+start] = j * 2;"
12366                       "  }"
12367                       "}"
12368                       "pa_store(pixels,0);"
12369                       "pa_store(pixels,-128);"
12370                       "var sum = 0;"
12371                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12372                       "sum");
12373   CHECK_EQ(65280, result->Int32Value());
12374
12375   // Make sure that the generic store stub correctly handle accesses outside
12376   // of the pixel array..
12377   result = CompileRun("function pa_store(p,start) {"
12378                       "  for (var j = 0; j < 256; j++) {"
12379                       "    p[j+start] = j * 2;"
12380                       "  }"
12381                       "}"
12382                       "pa_store(pixels,0);"
12383                       "just_ints = new Object();"
12384                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
12385                       "pa_store(just_ints, 0);"
12386                       "pa_store(pixels,-128);"
12387                       "var sum = 0;"
12388                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12389                       "sum");
12390   CHECK_EQ(65280, result->Int32Value());
12391
12392   // Make sure that the generic keyed store stub clamps pixel array values
12393   // correctly.
12394   result = CompileRun("function pa_store(p) {"
12395                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
12396                       "}"
12397                       "pa_store(pixels);"
12398                       "just_ints = new Object();"
12399                       "pa_store(just_ints);"
12400                       "pa_store(pixels);"
12401                       "var sum = 0;"
12402                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
12403                       "sum");
12404   CHECK_EQ(48896, result->Int32Value());
12405
12406   // Make sure that pixel array loads are optimized by crankshaft.
12407   result = CompileRun("function pa_load(p) {"
12408                       "  var sum = 0;"
12409                       "  for (var i=0; i<256; ++i) {"
12410                       "    sum += p[i];"
12411                       "  }"
12412                       "  return sum; "
12413                       "}"
12414                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
12415                       "for (var i = 0; i < 5000; ++i) {"
12416                       "  result = pa_load(pixels);"
12417                       "}"
12418                       "result");
12419   CHECK_EQ(32640, result->Int32Value());
12420
12421   // Make sure that pixel array stores are optimized by crankshaft.
12422   result = CompileRun("function pa_init(p) {"
12423                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
12424                       "}"
12425                       "function pa_load(p) {"
12426                       "  var sum = 0;"
12427                       "  for (var i=0; i<256; ++i) {"
12428                       "    sum += p[i];"
12429                       "  }"
12430                       "  return sum; "
12431                       "}"
12432                       "for (var i = 0; i < 5000; ++i) {"
12433                       "  pa_init(pixels);"
12434                       "}"
12435                       "result = pa_load(pixels);"
12436                       "result");
12437   CHECK_EQ(32640, result->Int32Value());
12438
12439   free(pixel_data);
12440 }
12441
12442
12443 THREADED_TEST(PixelArrayInfo) {
12444   v8::HandleScope scope;
12445   LocalContext context;
12446   for (int size = 0; size < 100; size += 10) {
12447     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
12448     v8::Handle<v8::Object> obj = v8::Object::New();
12449     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
12450     CHECK(obj->HasIndexedPropertiesInPixelData());
12451     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
12452     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
12453     free(pixel_data);
12454   }
12455 }
12456
12457
12458 static v8::Handle<Value> NotHandledIndexedPropertyGetter(
12459     uint32_t index,
12460     const AccessorInfo& info) {
12461   ApiTestFuzzer::Fuzz();
12462   return v8::Handle<Value>();
12463 }
12464
12465
12466 static v8::Handle<Value> NotHandledIndexedPropertySetter(
12467     uint32_t index,
12468     Local<Value> value,
12469     const AccessorInfo& info) {
12470   ApiTestFuzzer::Fuzz();
12471   return v8::Handle<Value>();
12472 }
12473
12474
12475 THREADED_TEST(PixelArrayWithInterceptor) {
12476   v8::HandleScope scope;
12477   LocalContext context;
12478   const int kElementCount = 260;
12479   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
12480   i::Handle<i::ExternalPixelArray> pixels =
12481       i::Handle<i::ExternalPixelArray>::cast(
12482           FACTORY->NewExternalArray(kElementCount,
12483                                     v8::kExternalPixelArray,
12484                                     pixel_data));
12485   for (int i = 0; i < kElementCount; i++) {
12486     pixels->set(i, i % 256);
12487   }
12488   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
12489   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
12490                                    NotHandledIndexedPropertySetter);
12491   v8::Handle<v8::Object> obj = templ->NewInstance();
12492   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
12493   context->Global()->Set(v8_str("pixels"), obj);
12494   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
12495   CHECK_EQ(1, result->Int32Value());
12496   result = CompileRun("var sum = 0;"
12497                       "for (var i = 0; i < 8; i++) {"
12498                       "  sum += pixels[i] = pixels[i] = -i;"
12499                       "}"
12500                       "sum;");
12501   CHECK_EQ(-28, result->Int32Value());
12502   result = CompileRun("pixels.hasOwnProperty('1')");
12503   CHECK(result->BooleanValue());
12504   free(pixel_data);
12505 }
12506
12507
12508 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
12509   switch (array_type) {
12510     case v8::kExternalByteArray:
12511     case v8::kExternalUnsignedByteArray:
12512     case v8::kExternalPixelArray:
12513       return 1;
12514       break;
12515     case v8::kExternalShortArray:
12516     case v8::kExternalUnsignedShortArray:
12517       return 2;
12518       break;
12519     case v8::kExternalIntArray:
12520     case v8::kExternalUnsignedIntArray:
12521     case v8::kExternalFloatArray:
12522       return 4;
12523       break;
12524     case v8::kExternalDoubleArray:
12525       return 8;
12526       break;
12527     default:
12528       UNREACHABLE();
12529       return -1;
12530   }
12531   UNREACHABLE();
12532   return -1;
12533 }
12534
12535
12536 template <class ExternalArrayClass, class ElementType>
12537 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
12538                                     int64_t low,
12539                                     int64_t high) {
12540   v8::HandleScope scope;
12541   LocalContext context;
12542   const int kElementCount = 40;
12543   int element_size = ExternalArrayElementSize(array_type);
12544   ElementType* array_data =
12545       static_cast<ElementType*>(malloc(kElementCount * element_size));
12546   i::Handle<ExternalArrayClass> array =
12547       i::Handle<ExternalArrayClass>::cast(
12548           FACTORY->NewExternalArray(kElementCount, array_type, array_data));
12549   // Force GC to trigger verification.
12550   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12551   for (int i = 0; i < kElementCount; i++) {
12552     array->set(i, static_cast<ElementType>(i));
12553   }
12554   // Force GC to trigger verification.
12555   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12556   for (int i = 0; i < kElementCount; i++) {
12557     CHECK_EQ(static_cast<int64_t>(i),
12558              static_cast<int64_t>(array->get_scalar(i)));
12559     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
12560   }
12561
12562   v8::Handle<v8::Object> obj = v8::Object::New();
12563   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
12564   // Set the elements to be the external array.
12565   obj->SetIndexedPropertiesToExternalArrayData(array_data,
12566                                                array_type,
12567                                                kElementCount);
12568   CHECK_EQ(
12569       1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
12570   obj->Set(v8_str("field"), v8::Int32::New(1503));
12571   context->Global()->Set(v8_str("ext_array"), obj);
12572   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
12573   CHECK_EQ(1503, result->Int32Value());
12574   result = CompileRun("ext_array[1]");
12575   CHECK_EQ(1, result->Int32Value());
12576
12577   // Check pass through of assigned smis
12578   result = CompileRun("var sum = 0;"
12579                       "for (var i = 0; i < 8; i++) {"
12580                       "  sum += ext_array[i] = ext_array[i] = -i;"
12581                       "}"
12582                       "sum;");
12583   CHECK_EQ(-28, result->Int32Value());
12584
12585   // Check assigned smis
12586   result = CompileRun("for (var i = 0; i < 8; i++) {"
12587                       "  ext_array[i] = i;"
12588                       "}"
12589                       "var sum = 0;"
12590                       "for (var i = 0; i < 8; i++) {"
12591                       "  sum += ext_array[i];"
12592                       "}"
12593                       "sum;");
12594   CHECK_EQ(28, result->Int32Value());
12595
12596   // Check assigned smis in reverse order
12597   result = CompileRun("for (var i = 8; --i >= 0; ) {"
12598                       "  ext_array[i] = i;"
12599                       "}"
12600                       "var sum = 0;"
12601                       "for (var i = 0; i < 8; i++) {"
12602                       "  sum += ext_array[i];"
12603                       "}"
12604                       "sum;");
12605   CHECK_EQ(28, result->Int32Value());
12606
12607   // Check pass through of assigned HeapNumbers
12608   result = CompileRun("var sum = 0;"
12609                       "for (var i = 0; i < 16; i+=2) {"
12610                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
12611                       "}"
12612                       "sum;");
12613   CHECK_EQ(-28, result->Int32Value());
12614
12615   // Check assigned HeapNumbers
12616   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
12617                       "  ext_array[i] = (i * 0.5);"
12618                       "}"
12619                       "var sum = 0;"
12620                       "for (var i = 0; i < 16; i+=2) {"
12621                       "  sum += ext_array[i];"
12622                       "}"
12623                       "sum;");
12624   CHECK_EQ(28, result->Int32Value());
12625
12626   // Check assigned HeapNumbers in reverse order
12627   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
12628                       "  ext_array[i] = (i * 0.5);"
12629                       "}"
12630                       "var sum = 0;"
12631                       "for (var i = 0; i < 16; i+=2) {"
12632                       "  sum += ext_array[i];"
12633                       "}"
12634                       "sum;");
12635   CHECK_EQ(28, result->Int32Value());
12636
12637   i::ScopedVector<char> test_buf(1024);
12638
12639   // Check legal boundary conditions.
12640   // The repeated loads and stores ensure the ICs are exercised.
12641   const char* boundary_program =
12642       "var res = 0;"
12643       "for (var i = 0; i < 16; i++) {"
12644       "  ext_array[i] = %lld;"
12645       "  if (i > 8) {"
12646       "    res = ext_array[i];"
12647       "  }"
12648       "}"
12649       "res;";
12650   i::OS::SNPrintF(test_buf,
12651                   boundary_program,
12652                   low);
12653   result = CompileRun(test_buf.start());
12654   CHECK_EQ(low, result->IntegerValue());
12655
12656   i::OS::SNPrintF(test_buf,
12657                   boundary_program,
12658                   high);
12659   result = CompileRun(test_buf.start());
12660   CHECK_EQ(high, result->IntegerValue());
12661
12662   // Check misprediction of type in IC.
12663   result = CompileRun("var tmp_array = ext_array;"
12664                       "var sum = 0;"
12665                       "for (var i = 0; i < 8; i++) {"
12666                       "  tmp_array[i] = i;"
12667                       "  sum += tmp_array[i];"
12668                       "  if (i == 4) {"
12669                       "    tmp_array = {};"
12670                       "  }"
12671                       "}"
12672                       "sum;");
12673   // Force GC to trigger verification.
12674   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12675   CHECK_EQ(28, result->Int32Value());
12676
12677   // Make sure out-of-range loads do not throw.
12678   i::OS::SNPrintF(test_buf,
12679                   "var caught_exception = false;"
12680                   "try {"
12681                   "  ext_array[%d];"
12682                   "} catch (e) {"
12683                   "  caught_exception = true;"
12684                   "}"
12685                   "caught_exception;",
12686                   kElementCount);
12687   result = CompileRun(test_buf.start());
12688   CHECK_EQ(false, result->BooleanValue());
12689
12690   // Make sure out-of-range stores do not throw.
12691   i::OS::SNPrintF(test_buf,
12692                   "var caught_exception = false;"
12693                   "try {"
12694                   "  ext_array[%d] = 1;"
12695                   "} catch (e) {"
12696                   "  caught_exception = true;"
12697                   "}"
12698                   "caught_exception;",
12699                   kElementCount);
12700   result = CompileRun(test_buf.start());
12701   CHECK_EQ(false, result->BooleanValue());
12702
12703   // Check other boundary conditions, values and operations.
12704   result = CompileRun("for (var i = 0; i < 8; i++) {"
12705                       "  ext_array[7] = undefined;"
12706                       "}"
12707                       "ext_array[7];");
12708   CHECK_EQ(0, result->Int32Value());
12709   CHECK_EQ(
12710       0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
12711
12712   result = CompileRun("for (var i = 0; i < 8; i++) {"
12713                       "  ext_array[6] = '2.3';"
12714                       "}"
12715                       "ext_array[6];");
12716   CHECK_EQ(2, result->Int32Value());
12717   CHECK_EQ(
12718       2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
12719
12720   if (array_type != v8::kExternalFloatArray &&
12721       array_type != v8::kExternalDoubleArray) {
12722     // Though the specification doesn't state it, be explicit about
12723     // converting NaNs and +/-Infinity to zero.
12724     result = CompileRun("for (var i = 0; i < 8; i++) {"
12725                         "  ext_array[i] = 5;"
12726                         "}"
12727                         "for (var i = 0; i < 8; i++) {"
12728                         "  ext_array[i] = NaN;"
12729                         "}"
12730                         "ext_array[5];");
12731     CHECK_EQ(0, result->Int32Value());
12732     CHECK_EQ(0,
12733              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12734
12735     result = CompileRun("for (var i = 0; i < 8; i++) {"
12736                         "  ext_array[i] = 5;"
12737                         "}"
12738                         "for (var i = 0; i < 8; i++) {"
12739                         "  ext_array[i] = Infinity;"
12740                         "}"
12741                         "ext_array[5];");
12742     int expected_value =
12743         (array_type == v8::kExternalPixelArray) ? 255 : 0;
12744     CHECK_EQ(expected_value, result->Int32Value());
12745     CHECK_EQ(expected_value,
12746              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12747
12748     result = CompileRun("for (var i = 0; i < 8; i++) {"
12749                         "  ext_array[i] = 5;"
12750                         "}"
12751                         "for (var i = 0; i < 8; i++) {"
12752                         "  ext_array[i] = -Infinity;"
12753                         "}"
12754                         "ext_array[5];");
12755     CHECK_EQ(0, result->Int32Value());
12756     CHECK_EQ(0,
12757              i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
12758
12759     // Check truncation behavior of integral arrays.
12760     const char* unsigned_data =
12761         "var source_data = [0.6, 10.6];"
12762         "var expected_results = [0, 10];";
12763     const char* signed_data =
12764         "var source_data = [0.6, 10.6, -0.6, -10.6];"
12765         "var expected_results = [0, 10, 0, -10];";
12766     const char* pixel_data =
12767         "var source_data = [0.6, 10.6];"
12768         "var expected_results = [1, 11];";
12769     bool is_unsigned =
12770         (array_type == v8::kExternalUnsignedByteArray ||
12771          array_type == v8::kExternalUnsignedShortArray ||
12772          array_type == v8::kExternalUnsignedIntArray);
12773     bool is_pixel_data = array_type == v8::kExternalPixelArray;
12774
12775     i::OS::SNPrintF(test_buf,
12776                     "%s"
12777                     "var all_passed = true;"
12778                     "for (var i = 0; i < source_data.length; i++) {"
12779                     "  for (var j = 0; j < 8; j++) {"
12780                     "    ext_array[j] = source_data[i];"
12781                     "  }"
12782                     "  all_passed = all_passed &&"
12783                     "               (ext_array[5] == expected_results[i]);"
12784                     "}"
12785                     "all_passed;",
12786                     (is_unsigned ?
12787                          unsigned_data :
12788                          (is_pixel_data ? pixel_data : signed_data)));
12789     result = CompileRun(test_buf.start());
12790     CHECK_EQ(true, result->BooleanValue());
12791   }
12792
12793   for (int i = 0; i < kElementCount; i++) {
12794     array->set(i, static_cast<ElementType>(i));
12795   }
12796   // Test complex assignments
12797   result = CompileRun("function ee_op_test_complex_func(sum) {"
12798                       " for (var i = 0; i < 40; ++i) {"
12799                       "   sum += (ext_array[i] += 1);"
12800                       "   sum += (ext_array[i] -= 1);"
12801                       " } "
12802                       " return sum;"
12803                       "}"
12804                       "sum=0;"
12805                       "for (var i=0;i<10000;++i) {"
12806                       "  sum=ee_op_test_complex_func(sum);"
12807                       "}"
12808                       "sum;");
12809   CHECK_EQ(16000000, result->Int32Value());
12810
12811   // Test count operations
12812   result = CompileRun("function ee_op_test_count_func(sum) {"
12813                       " for (var i = 0; i < 40; ++i) {"
12814                       "   sum += (++ext_array[i]);"
12815                       "   sum += (--ext_array[i]);"
12816                       " } "
12817                       " return sum;"
12818                       "}"
12819                       "sum=0;"
12820                       "for (var i=0;i<10000;++i) {"
12821                       "  sum=ee_op_test_count_func(sum);"
12822                       "}"
12823                       "sum;");
12824   CHECK_EQ(16000000, result->Int32Value());
12825
12826   result = CompileRun("ext_array[3] = 33;"
12827                       "delete ext_array[3];"
12828                       "ext_array[3];");
12829   CHECK_EQ(33, result->Int32Value());
12830
12831   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
12832                       "ext_array[2] = 12; ext_array[3] = 13;"
12833                       "ext_array.__defineGetter__('2',"
12834                       "function() { return 120; });"
12835                       "ext_array[2];");
12836   CHECK_EQ(12, result->Int32Value());
12837
12838   result = CompileRun("var js_array = new Array(40);"
12839                       "js_array[0] = 77;"
12840                       "js_array;");
12841   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12842
12843   result = CompileRun("ext_array[1] = 23;"
12844                       "ext_array.__proto__ = [];"
12845                       "js_array.__proto__ = ext_array;"
12846                       "js_array.concat(ext_array);");
12847   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
12848   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
12849
12850   result = CompileRun("ext_array[1] = 23;");
12851   CHECK_EQ(23, result->Int32Value());
12852
12853   // Test more complex manipulations which cause eax to contain values
12854   // that won't be completely overwritten by loads from the arrays.
12855   // This catches bugs in the instructions used for the KeyedLoadIC
12856   // for byte and word types.
12857   {
12858     const int kXSize = 300;
12859     const int kYSize = 300;
12860     const int kLargeElementCount = kXSize * kYSize * 4;
12861     ElementType* large_array_data =
12862         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
12863     i::Handle<ExternalArrayClass> large_array(
12864         i::Handle<ExternalArrayClass>::cast(
12865             FACTORY->NewExternalArray(kLargeElementCount,
12866                                       array_type,
12867                                       array_data)));
12868     v8::Handle<v8::Object> large_obj = v8::Object::New();
12869     // Set the elements to be the external array.
12870     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
12871                                                        array_type,
12872                                                        kLargeElementCount);
12873     context->Global()->Set(v8_str("large_array"), large_obj);
12874     // Initialize contents of a few rows.
12875     for (int x = 0; x < 300; x++) {
12876       int row = 0;
12877       int offset = row * 300 * 4;
12878       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12879       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12880       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12881       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12882       row = 150;
12883       offset = row * 300 * 4;
12884       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12885       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12886       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12887       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12888       row = 298;
12889       offset = row * 300 * 4;
12890       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
12891       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
12892       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
12893       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
12894     }
12895     // The goal of the code below is to make "offset" large enough
12896     // that the computation of the index (which goes into eax) has
12897     // high bits set which will not be overwritten by a byte or short
12898     // load.
12899     result = CompileRun("var failed = false;"
12900                         "var offset = 0;"
12901                         "for (var i = 0; i < 300; i++) {"
12902                         "  if (large_array[4 * i] != 127 ||"
12903                         "      large_array[4 * i + 1] != 0 ||"
12904                         "      large_array[4 * i + 2] != 0 ||"
12905                         "      large_array[4 * i + 3] != 127) {"
12906                         "    failed = true;"
12907                         "  }"
12908                         "}"
12909                         "offset = 150 * 300 * 4;"
12910                         "for (var i = 0; i < 300; i++) {"
12911                         "  if (large_array[offset + 4 * i] != 127 ||"
12912                         "      large_array[offset + 4 * i + 1] != 0 ||"
12913                         "      large_array[offset + 4 * i + 2] != 0 ||"
12914                         "      large_array[offset + 4 * i + 3] != 127) {"
12915                         "    failed = true;"
12916                         "  }"
12917                         "}"
12918                         "offset = 298 * 300 * 4;"
12919                         "for (var i = 0; i < 300; i++) {"
12920                         "  if (large_array[offset + 4 * i] != 127 ||"
12921                         "      large_array[offset + 4 * i + 1] != 0 ||"
12922                         "      large_array[offset + 4 * i + 2] != 0 ||"
12923                         "      large_array[offset + 4 * i + 3] != 127) {"
12924                         "    failed = true;"
12925                         "  }"
12926                         "}"
12927                         "!failed;");
12928     CHECK_EQ(true, result->BooleanValue());
12929     free(large_array_data);
12930   }
12931
12932   // The "" property descriptor is overloaded to store information about
12933   // the external array. Ensure that setting and accessing the "" property
12934   // works (it should overwrite the information cached about the external
12935   // array in the DescriptorArray) in various situations.
12936   result = CompileRun("ext_array[''] = 23; ext_array['']");
12937   CHECK_EQ(23, result->Int32Value());
12938
12939   // Property "" set after the external array is associated with the object.
12940   {
12941     v8::Handle<v8::Object> obj2 = v8::Object::New();
12942     obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
12943     obj2->Set(v8_str(""), v8::Int32::New(1503));
12944     // Set the elements to be the external array.
12945     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12946                                                   array_type,
12947                                                   kElementCount);
12948     context->Global()->Set(v8_str("ext_array"), obj2);
12949     result = CompileRun("ext_array['']");
12950     CHECK_EQ(1503, result->Int32Value());
12951   }
12952
12953   // Property "" set after the external array is associated with the object.
12954   {
12955     v8::Handle<v8::Object> obj2 = v8::Object::New();
12956     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12957     // Set the elements to be the external array.
12958     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12959                                                   array_type,
12960                                                   kElementCount);
12961     obj2->Set(v8_str(""), v8::Int32::New(1503));
12962     context->Global()->Set(v8_str("ext_array"), obj2);
12963     result = CompileRun("ext_array['']");
12964     CHECK_EQ(1503, result->Int32Value());
12965   }
12966
12967   // Should reuse the map from previous test.
12968   {
12969     v8::Handle<v8::Object> obj2 = v8::Object::New();
12970     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
12971     // Set the elements to be the external array. Should re-use the map
12972     // from previous test.
12973     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
12974                                                   array_type,
12975                                                   kElementCount);
12976     context->Global()->Set(v8_str("ext_array"), obj2);
12977     result = CompileRun("ext_array['']");
12978   }
12979
12980   // Property "" is a constant function that shouldn't not be interfered with
12981   // when an external array is set.
12982   {
12983     v8::Handle<v8::Object> obj2 = v8::Object::New();
12984     // Start
12985     obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12986
12987     // Add a constant function to an object.
12988     context->Global()->Set(v8_str("ext_array"), obj2);
12989     result = CompileRun("ext_array[''] = function() {return 1503;};"
12990                         "ext_array['']();");
12991
12992     // Add an external array transition to the same map that
12993     // has the constant transition.
12994     v8::Handle<v8::Object> obj3 = v8::Object::New();
12995     obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
12996     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
12997                                                   array_type,
12998                                                   kElementCount);
12999     context->Global()->Set(v8_str("ext_array"), obj3);
13000   }
13001
13002   // If a external array transition is in the map, it should get clobbered
13003   // by a constant function.
13004   {
13005     // Add an external array transition.
13006     v8::Handle<v8::Object> obj3 = v8::Object::New();
13007     obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13008     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
13009                                                   array_type,
13010                                                   kElementCount);
13011
13012     // Add a constant function to the same map that just got an external array
13013     // transition.
13014     v8::Handle<v8::Object> obj2 = v8::Object::New();
13015     obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
13016     context->Global()->Set(v8_str("ext_array"), obj2);
13017     result = CompileRun("ext_array[''] = function() {return 1503;};"
13018                         "ext_array['']();");
13019   }
13020
13021   free(array_data);
13022 }
13023
13024
13025 THREADED_TEST(ExternalByteArray) {
13026   ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
13027       v8::kExternalByteArray,
13028       -128,
13029       127);
13030 }
13031
13032
13033 THREADED_TEST(ExternalUnsignedByteArray) {
13034   ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
13035       v8::kExternalUnsignedByteArray,
13036       0,
13037       255);
13038 }
13039
13040
13041 THREADED_TEST(ExternalPixelArray) {
13042   ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
13043       v8::kExternalPixelArray,
13044       0,
13045       255);
13046 }
13047
13048
13049 THREADED_TEST(ExternalShortArray) {
13050   ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
13051       v8::kExternalShortArray,
13052       -32768,
13053       32767);
13054 }
13055
13056
13057 THREADED_TEST(ExternalUnsignedShortArray) {
13058   ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
13059       v8::kExternalUnsignedShortArray,
13060       0,
13061       65535);
13062 }
13063
13064
13065 THREADED_TEST(ExternalIntArray) {
13066   ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
13067       v8::kExternalIntArray,
13068       INT_MIN,   // -2147483648
13069       INT_MAX);  //  2147483647
13070 }
13071
13072
13073 THREADED_TEST(ExternalUnsignedIntArray) {
13074   ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
13075       v8::kExternalUnsignedIntArray,
13076       0,
13077       UINT_MAX);  // 4294967295
13078 }
13079
13080
13081 THREADED_TEST(ExternalFloatArray) {
13082   ExternalArrayTestHelper<i::ExternalFloatArray, float>(
13083       v8::kExternalFloatArray,
13084       -500,
13085       500);
13086 }
13087
13088
13089 THREADED_TEST(ExternalDoubleArray) {
13090   ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
13091       v8::kExternalDoubleArray,
13092       -500,
13093       500);
13094 }
13095
13096
13097 THREADED_TEST(ExternalArrays) {
13098   TestExternalByteArray();
13099   TestExternalUnsignedByteArray();
13100   TestExternalShortArray();
13101   TestExternalUnsignedShortArray();
13102   TestExternalIntArray();
13103   TestExternalUnsignedIntArray();
13104   TestExternalFloatArray();
13105 }
13106
13107
13108 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
13109   v8::HandleScope scope;
13110   LocalContext context;
13111   for (int size = 0; size < 100; size += 10) {
13112     int element_size = ExternalArrayElementSize(array_type);
13113     void* external_data = malloc(size * element_size);
13114     v8::Handle<v8::Object> obj = v8::Object::New();
13115     obj->SetIndexedPropertiesToExternalArrayData(
13116         external_data, array_type, size);
13117     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
13118     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
13119     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
13120     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
13121     free(external_data);
13122   }
13123 }
13124
13125
13126 THREADED_TEST(ExternalArrayInfo) {
13127   ExternalArrayInfoTestHelper(v8::kExternalByteArray);
13128   ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
13129   ExternalArrayInfoTestHelper(v8::kExternalShortArray);
13130   ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
13131   ExternalArrayInfoTestHelper(v8::kExternalIntArray);
13132   ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
13133   ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
13134   ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
13135   ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
13136 }
13137
13138
13139 THREADED_TEST(ScriptContextDependence) {
13140   v8::HandleScope scope;
13141   LocalContext c1;
13142   const char *source = "foo";
13143   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
13144   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
13145   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
13146   CHECK_EQ(dep->Run()->Int32Value(), 100);
13147   CHECK_EQ(indep->Run()->Int32Value(), 100);
13148   LocalContext c2;
13149   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
13150   CHECK_EQ(dep->Run()->Int32Value(), 100);
13151   CHECK_EQ(indep->Run()->Int32Value(), 101);
13152 }
13153
13154
13155 THREADED_TEST(StackTrace) {
13156   v8::HandleScope scope;
13157   LocalContext context;
13158   v8::TryCatch try_catch;
13159   const char *source = "function foo() { FAIL.FAIL; }; foo();";
13160   v8::Handle<v8::String> src = v8::String::New(source);
13161   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
13162   v8::Script::New(src, origin)->Run();
13163   CHECK(try_catch.HasCaught());
13164   v8::String::Utf8Value stack(try_catch.StackTrace());
13165   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
13166 }
13167
13168
13169 // Checks that a StackFrame has certain expected values.
13170 void checkStackFrame(const char* expected_script_name,
13171     const char* expected_func_name, int expected_line_number,
13172     int expected_column, bool is_eval, bool is_constructor,
13173     v8::Handle<v8::StackFrame> frame) {
13174   v8::HandleScope scope;
13175   v8::String::Utf8Value func_name(frame->GetFunctionName());
13176   v8::String::Utf8Value script_name(frame->GetScriptName());
13177   if (*script_name == NULL) {
13178     // The situation where there is no associated script, like for evals.
13179     CHECK(expected_script_name == NULL);
13180   } else {
13181     CHECK(strstr(*script_name, expected_script_name) != NULL);
13182   }
13183   CHECK(strstr(*func_name, expected_func_name) != NULL);
13184   CHECK_EQ(expected_line_number, frame->GetLineNumber());
13185   CHECK_EQ(expected_column, frame->GetColumn());
13186   CHECK_EQ(is_eval, frame->IsEval());
13187   CHECK_EQ(is_constructor, frame->IsConstructor());
13188 }
13189
13190
13191 v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
13192   v8::HandleScope scope;
13193   const char* origin = "capture-stack-trace-test";
13194   const int kOverviewTest = 1;
13195   const int kDetailedTest = 2;
13196
13197   ASSERT(args.Length() == 1);
13198
13199   int testGroup = args[0]->Int32Value();
13200   if (testGroup == kOverviewTest) {
13201     v8::Handle<v8::StackTrace> stackTrace =
13202         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
13203     CHECK_EQ(4, stackTrace->GetFrameCount());
13204     checkStackFrame(origin, "bar", 2, 10, false, false,
13205                     stackTrace->GetFrame(0));
13206     checkStackFrame(origin, "foo", 6, 3, false, false,
13207                     stackTrace->GetFrame(1));
13208     // This is the source string inside the eval which has the call to foo.
13209     checkStackFrame(NULL, "", 1, 5, false, false,
13210                     stackTrace->GetFrame(2));
13211     // The last frame is an anonymous function which has the initial eval call.
13212     checkStackFrame(origin, "", 8, 7, false, false,
13213                     stackTrace->GetFrame(3));
13214
13215     CHECK(stackTrace->AsArray()->IsArray());
13216   } else if (testGroup == kDetailedTest) {
13217     v8::Handle<v8::StackTrace> stackTrace =
13218         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13219     CHECK_EQ(4, stackTrace->GetFrameCount());
13220     checkStackFrame(origin, "bat", 4, 22, false, false,
13221                     stackTrace->GetFrame(0));
13222     checkStackFrame(origin, "baz", 8, 3, false, true,
13223                     stackTrace->GetFrame(1));
13224 #ifdef ENABLE_DEBUGGER_SUPPORT
13225     bool is_eval = true;
13226 #else  // ENABLE_DEBUGGER_SUPPORT
13227     bool is_eval = false;
13228 #endif  // ENABLE_DEBUGGER_SUPPORT
13229
13230     // This is the source string inside the eval which has the call to baz.
13231     checkStackFrame(NULL, "", 1, 5, is_eval, false,
13232                     stackTrace->GetFrame(2));
13233     // The last frame is an anonymous function which has the initial eval call.
13234     checkStackFrame(origin, "", 10, 1, false, false,
13235                     stackTrace->GetFrame(3));
13236
13237     CHECK(stackTrace->AsArray()->IsArray());
13238   }
13239   return v8::Undefined();
13240 }
13241
13242
13243 // Tests the C++ StackTrace API.
13244 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
13245 // THREADED_TEST(CaptureStackTrace) {
13246 TEST(CaptureStackTrace) {
13247   v8::HandleScope scope;
13248   v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
13249   Local<ObjectTemplate> templ = ObjectTemplate::New();
13250   templ->Set(v8_str("AnalyzeStackInNativeCode"),
13251              v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
13252   LocalContext context(0, templ);
13253
13254   // Test getting OVERVIEW information. Should ignore information that is not
13255   // script name, function name, line number, and column offset.
13256   const char *overview_source =
13257     "function bar() {\n"
13258     "  var y; AnalyzeStackInNativeCode(1);\n"
13259     "}\n"
13260     "function foo() {\n"
13261     "\n"
13262     "  bar();\n"
13263     "}\n"
13264     "var x;eval('new foo();');";
13265   v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
13266   v8::Handle<Value> overview_result(
13267       v8::Script::New(overview_src, origin)->Run());
13268   ASSERT(!overview_result.IsEmpty());
13269   ASSERT(overview_result->IsObject());
13270
13271   // Test getting DETAILED information.
13272   const char *detailed_source =
13273     "function bat() {AnalyzeStackInNativeCode(2);\n"
13274     "}\n"
13275     "\n"
13276     "function baz() {\n"
13277     "  bat();\n"
13278     "}\n"
13279     "eval('new baz();');";
13280   v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
13281   // Make the script using a non-zero line and column offset.
13282   v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
13283   v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
13284   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
13285   v8::Handle<v8::Script> detailed_script(
13286       v8::Script::New(detailed_src, &detailed_origin));
13287   v8::Handle<Value> detailed_result(detailed_script->Run());
13288   ASSERT(!detailed_result.IsEmpty());
13289   ASSERT(detailed_result->IsObject());
13290 }
13291
13292
13293 static void StackTraceForUncaughtExceptionListener(
13294     v8::Handle<v8::Message> message,
13295     v8::Handle<Value>) {
13296   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
13297   CHECK_EQ(2, stack_trace->GetFrameCount());
13298   checkStackFrame("origin", "foo", 2, 3, false, false,
13299                   stack_trace->GetFrame(0));
13300   checkStackFrame("origin", "bar", 5, 3, false, false,
13301                   stack_trace->GetFrame(1));
13302 }
13303
13304 TEST(CaptureStackTraceForUncaughtException) {
13305   report_count = 0;
13306   v8::HandleScope scope;
13307   LocalContext env;
13308   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
13309   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
13310
13311   Script::Compile(v8_str("function foo() {\n"
13312                          "  throw 1;\n"
13313                          "};\n"
13314                          "function bar() {\n"
13315                          "  foo();\n"
13316                          "};"),
13317                   v8_str("origin"))->Run();
13318   v8::Local<v8::Object> global = env->Global();
13319   Local<Value> trouble = global->Get(v8_str("bar"));
13320   CHECK(trouble->IsFunction());
13321   Function::Cast(*trouble)->Call(global, 0, NULL);
13322   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13323   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
13324 }
13325
13326
13327 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
13328   v8::HandleScope scope;
13329   LocalContext env;
13330   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
13331                                                     1024,
13332                                                     v8::StackTrace::kDetailed);
13333
13334   CompileRun(
13335       "var setters = ['column', 'lineNumber', 'scriptName',\n"
13336       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
13337       "    'isConstructor'];\n"
13338       "for (var i = 0; i < setters.length; i++) {\n"
13339       "  var prop = setters[i];\n"
13340       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
13341       "}\n");
13342   CompileRun("throw 'exception';");
13343   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
13344 }
13345
13346
13347 v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) {
13348   v8::HandleScope scope;
13349   v8::Handle<v8::StackTrace> stackTrace =
13350       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
13351   CHECK_EQ(5, stackTrace->GetFrameCount());
13352   v8::Handle<v8::String> url = v8_str("eval_url");
13353   for (int i = 0; i < 3; i++) {
13354     v8::Handle<v8::String> name =
13355         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
13356     CHECK(!name.IsEmpty());
13357     CHECK_EQ(url, name);
13358   }
13359   return v8::Undefined();
13360 }
13361
13362
13363 TEST(SourceURLInStackTrace) {
13364   v8::HandleScope scope;
13365   Local<ObjectTemplate> templ = ObjectTemplate::New();
13366   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
13367              v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
13368   LocalContext context(0, templ);
13369
13370   const char *source =
13371     "function outer() {\n"
13372     "function bar() {\n"
13373     "  AnalyzeStackOfEvalWithSourceURL();\n"
13374     "}\n"
13375     "function foo() {\n"
13376     "\n"
13377     "  bar();\n"
13378     "}\n"
13379     "foo();\n"
13380     "}\n"
13381     "eval('(' + outer +')()//@ sourceURL=eval_url');";
13382   CHECK(CompileRun(source)->IsUndefined());
13383 }
13384
13385
13386 // Test that idle notification can be handled and eventually returns true.
13387 THREADED_TEST(IdleNotification) {
13388   bool rv = false;
13389   for (int i = 0; i < 100; i++) {
13390     rv = v8::V8::IdleNotification();
13391     if (rv)
13392       break;
13393   }
13394   CHECK(rv == true);
13395 }
13396
13397
13398 static uint32_t* stack_limit;
13399
13400 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
13401   stack_limit = reinterpret_cast<uint32_t*>(
13402       i::Isolate::Current()->stack_guard()->real_climit());
13403   return v8::Undefined();
13404 }
13405
13406
13407 // Uses the address of a local variable to determine the stack top now.
13408 // Given a size, returns an address that is that far from the current
13409 // top of stack.
13410 static uint32_t* ComputeStackLimit(uint32_t size) {
13411   uint32_t* answer = &size - (size / sizeof(size));
13412   // If the size is very large and the stack is very near the bottom of
13413   // memory then the calculation above may wrap around and give an address
13414   // that is above the (downwards-growing) stack.  In that case we return
13415   // a very low address.
13416   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
13417   return answer;
13418 }
13419
13420
13421 TEST(SetResourceConstraints) {
13422   static const int K = 1024;
13423   uint32_t* set_limit = ComputeStackLimit(128 * K);
13424
13425   // Set stack limit.
13426   v8::ResourceConstraints constraints;
13427   constraints.set_stack_limit(set_limit);
13428   CHECK(v8::SetResourceConstraints(&constraints));
13429
13430   // Execute a script.
13431   v8::HandleScope scope;
13432   LocalContext env;
13433   Local<v8::FunctionTemplate> fun_templ =
13434       v8::FunctionTemplate::New(GetStackLimitCallback);
13435   Local<Function> fun = fun_templ->GetFunction();
13436   env->Global()->Set(v8_str("get_stack_limit"), fun);
13437   CompileRun("get_stack_limit();");
13438
13439   CHECK(stack_limit == set_limit);
13440 }
13441
13442
13443 TEST(SetResourceConstraintsInThread) {
13444   uint32_t* set_limit;
13445   {
13446     v8::Locker locker;
13447     static const int K = 1024;
13448     set_limit = ComputeStackLimit(128 * K);
13449
13450     // Set stack limit.
13451     v8::ResourceConstraints constraints;
13452     constraints.set_stack_limit(set_limit);
13453     CHECK(v8::SetResourceConstraints(&constraints));
13454
13455     // Execute a script.
13456     v8::HandleScope scope;
13457     LocalContext env;
13458     Local<v8::FunctionTemplate> fun_templ =
13459         v8::FunctionTemplate::New(GetStackLimitCallback);
13460     Local<Function> fun = fun_templ->GetFunction();
13461     env->Global()->Set(v8_str("get_stack_limit"), fun);
13462     CompileRun("get_stack_limit();");
13463
13464     CHECK(stack_limit == set_limit);
13465   }
13466   {
13467     v8::Locker locker;
13468     CHECK(stack_limit == set_limit);
13469   }
13470 }
13471
13472
13473 THREADED_TEST(GetHeapStatistics) {
13474   v8::HandleScope scope;
13475   LocalContext c1;
13476   v8::HeapStatistics heap_statistics;
13477   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
13478   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
13479   v8::V8::GetHeapStatistics(&heap_statistics);
13480   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
13481   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
13482 }
13483
13484
13485 static double DoubleFromBits(uint64_t value) {
13486   double target;
13487   memcpy(&target, &value, sizeof(target));
13488   return target;
13489 }
13490
13491
13492 static uint64_t DoubleToBits(double value) {
13493   uint64_t target;
13494   memcpy(&target, &value, sizeof(target));
13495   return target;
13496 }
13497
13498
13499 static double DoubleToDateTime(double input) {
13500   double date_limit = 864e13;
13501   if (IsNaN(input) || input < -date_limit || input > date_limit) {
13502     return i::OS::nan_value();
13503   }
13504   return (input < 0) ? -(floor(-input)) : floor(input);
13505 }
13506
13507 // We don't have a consistent way to write 64-bit constants syntactically, so we
13508 // split them into two 32-bit constants and combine them programmatically.
13509 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
13510   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
13511 }
13512
13513
13514 THREADED_TEST(QuietSignalingNaNs) {
13515   v8::HandleScope scope;
13516   LocalContext context;
13517   v8::TryCatch try_catch;
13518
13519   // Special double values.
13520   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
13521   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
13522   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
13523   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
13524   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
13525   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
13526   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
13527
13528   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
13529   // on either side of the epoch.
13530   double date_limit = 864e13;
13531
13532   double test_values[] = {
13533       snan,
13534       qnan,
13535       infinity,
13536       max_normal,
13537       date_limit + 1,
13538       date_limit,
13539       min_normal,
13540       max_denormal,
13541       min_denormal,
13542       0,
13543       -0,
13544       -min_denormal,
13545       -max_denormal,
13546       -min_normal,
13547       -date_limit,
13548       -date_limit - 1,
13549       -max_normal,
13550       -infinity,
13551       -qnan,
13552       -snan
13553   };
13554   int num_test_values = 20;
13555
13556   for (int i = 0; i < num_test_values; i++) {
13557     double test_value = test_values[i];
13558
13559     // Check that Number::New preserves non-NaNs and quiets SNaNs.
13560     v8::Handle<v8::Value> number = v8::Number::New(test_value);
13561     double stored_number = number->NumberValue();
13562     if (!IsNaN(test_value)) {
13563       CHECK_EQ(test_value, stored_number);
13564     } else {
13565       uint64_t stored_bits = DoubleToBits(stored_number);
13566       // Check if quiet nan (bits 51..62 all set).
13567       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13568     }
13569
13570     // Check that Date::New preserves non-NaNs in the date range and
13571     // quiets SNaNs.
13572     v8::Handle<v8::Value> date = v8::Date::New(test_value);
13573     double expected_stored_date = DoubleToDateTime(test_value);
13574     double stored_date = date->NumberValue();
13575     if (!IsNaN(expected_stored_date)) {
13576       CHECK_EQ(expected_stored_date, stored_date);
13577     } else {
13578       uint64_t stored_bits = DoubleToBits(stored_date);
13579       // Check if quiet nan (bits 51..62 all set).
13580       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
13581     }
13582   }
13583 }
13584
13585
13586 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
13587   v8::HandleScope scope;
13588   v8::TryCatch tc;
13589   v8::Handle<v8::String> str(args[0]->ToString());
13590   if (tc.HasCaught())
13591     return tc.ReThrow();
13592   return v8::Undefined();
13593 }
13594
13595
13596 // Test that an exception can be propagated down through a spaghetti
13597 // stack using ReThrow.
13598 THREADED_TEST(SpaghettiStackReThrow) {
13599   v8::HandleScope scope;
13600   LocalContext context;
13601   context->Global()->Set(
13602       v8::String::New("s"),
13603       v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
13604   v8::TryCatch try_catch;
13605   CompileRun(
13606       "var i = 0;"
13607       "var o = {"
13608       "  toString: function () {"
13609       "    if (i == 10) {"
13610       "      throw 'Hey!';"
13611       "    } else {"
13612       "      i++;"
13613       "      return s(o);"
13614       "    }"
13615       "  }"
13616       "};"
13617       "s(o);");
13618   CHECK(try_catch.HasCaught());
13619   v8::String::Utf8Value value(try_catch.Exception());
13620   CHECK_EQ(0, strcmp(*value, "Hey!"));
13621 }
13622
13623
13624 TEST(Regress528) {
13625   v8::V8::Initialize();
13626
13627   v8::HandleScope scope;
13628   v8::Persistent<Context> context;
13629   v8::Persistent<Context> other_context;
13630   int gc_count;
13631
13632   // Create a context used to keep the code from aging in the compilation
13633   // cache.
13634   other_context = Context::New();
13635
13636   // Context-dependent context data creates reference from the compilation
13637   // cache to the global object.
13638   const char* source_simple = "1";
13639   context = Context::New();
13640   {
13641     v8::HandleScope scope;
13642
13643     context->Enter();
13644     Local<v8::String> obj = v8::String::New("");
13645     context->SetData(obj);
13646     CompileRun(source_simple);
13647     context->Exit();
13648   }
13649   context.Dispose();
13650   for (gc_count = 1; gc_count < 10; gc_count++) {
13651     other_context->Enter();
13652     CompileRun(source_simple);
13653     other_context->Exit();
13654     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13655     if (GetGlobalObjectsCount() == 1) break;
13656   }
13657   CHECK_GE(2, gc_count);
13658   CHECK_EQ(1, GetGlobalObjectsCount());
13659
13660   // Eval in a function creates reference from the compilation cache to the
13661   // global object.
13662   const char* source_eval = "function f(){eval('1')}; f()";
13663   context = Context::New();
13664   {
13665     v8::HandleScope scope;
13666
13667     context->Enter();
13668     CompileRun(source_eval);
13669     context->Exit();
13670   }
13671   context.Dispose();
13672   for (gc_count = 1; gc_count < 10; gc_count++) {
13673     other_context->Enter();
13674     CompileRun(source_eval);
13675     other_context->Exit();
13676     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13677     if (GetGlobalObjectsCount() == 1) break;
13678   }
13679   CHECK_GE(2, gc_count);
13680   CHECK_EQ(1, GetGlobalObjectsCount());
13681
13682   // Looking up the line number for an exception creates reference from the
13683   // compilation cache to the global object.
13684   const char* source_exception = "function f(){throw 1;} f()";
13685   context = Context::New();
13686   {
13687     v8::HandleScope scope;
13688
13689     context->Enter();
13690     v8::TryCatch try_catch;
13691     CompileRun(source_exception);
13692     CHECK(try_catch.HasCaught());
13693     v8::Handle<v8::Message> message = try_catch.Message();
13694     CHECK(!message.IsEmpty());
13695     CHECK_EQ(1, message->GetLineNumber());
13696     context->Exit();
13697   }
13698   context.Dispose();
13699   for (gc_count = 1; gc_count < 10; gc_count++) {
13700     other_context->Enter();
13701     CompileRun(source_exception);
13702     other_context->Exit();
13703     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13704     if (GetGlobalObjectsCount() == 1) break;
13705   }
13706   CHECK_GE(2, gc_count);
13707   CHECK_EQ(1, GetGlobalObjectsCount());
13708
13709   other_context.Dispose();
13710 }
13711
13712
13713 THREADED_TEST(ScriptOrigin) {
13714   v8::HandleScope scope;
13715   LocalContext env;
13716   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13717   v8::Handle<v8::String> script = v8::String::New(
13718       "function f() {}\n\nfunction g() {}");
13719   v8::Script::Compile(script, &origin)->Run();
13720   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13721       env->Global()->Get(v8::String::New("f")));
13722   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13723       env->Global()->Get(v8::String::New("g")));
13724
13725   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
13726   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
13727   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
13728
13729   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
13730   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
13731   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
13732 }
13733
13734
13735 THREADED_TEST(ScriptLineNumber) {
13736   v8::HandleScope scope;
13737   LocalContext env;
13738   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
13739   v8::Handle<v8::String> script = v8::String::New(
13740       "function f() {}\n\nfunction g() {}");
13741   v8::Script::Compile(script, &origin)->Run();
13742   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
13743       env->Global()->Get(v8::String::New("f")));
13744   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
13745       env->Global()->Get(v8::String::New("g")));
13746   CHECK_EQ(0, f->GetScriptLineNumber());
13747   CHECK_EQ(2, g->GetScriptLineNumber());
13748 }
13749
13750
13751 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
13752                                               const AccessorInfo& info) {
13753   return v8_num(42);
13754 }
13755
13756
13757 static void SetterWhichSetsYOnThisTo23(Local<String> name,
13758                                        Local<Value> value,
13759                                        const AccessorInfo& info) {
13760   info.This()->Set(v8_str("y"), v8_num(23));
13761 }
13762
13763
13764 TEST(SetterOnConstructorPrototype) {
13765   v8::HandleScope scope;
13766   Local<ObjectTemplate> templ = ObjectTemplate::New();
13767   templ->SetAccessor(v8_str("x"),
13768                      GetterWhichReturns42,
13769                      SetterWhichSetsYOnThisTo23);
13770   LocalContext context;
13771   context->Global()->Set(v8_str("P"), templ->NewInstance());
13772   CompileRun("function C1() {"
13773              "  this.x = 23;"
13774              "};"
13775              "C1.prototype = P;"
13776              "function C2() {"
13777              "  this.x = 23"
13778              "};"
13779              "C2.prototype = { };"
13780              "C2.prototype.__proto__ = P;");
13781
13782   v8::Local<v8::Script> script;
13783   script = v8::Script::Compile(v8_str("new C1();"));
13784   for (int i = 0; i < 10; i++) {
13785     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13786     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13787     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13788   }
13789
13790   script = v8::Script::Compile(v8_str("new C2();"));
13791   for (int i = 0; i < 10; i++) {
13792     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13793     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
13794     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
13795   }
13796 }
13797
13798
13799 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
13800     Local<String> name, const AccessorInfo& info) {
13801   return v8_num(42);
13802 }
13803
13804
13805 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
13806     Local<String> name, Local<Value> value, const AccessorInfo& info) {
13807   if (name->Equals(v8_str("x"))) {
13808     info.This()->Set(v8_str("y"), v8_num(23));
13809   }
13810   return v8::Handle<Value>();
13811 }
13812
13813
13814 THREADED_TEST(InterceptorOnConstructorPrototype) {
13815   v8::HandleScope scope;
13816   Local<ObjectTemplate> templ = ObjectTemplate::New();
13817   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
13818                                  NamedPropertySetterWhichSetsYOnThisTo23);
13819   LocalContext context;
13820   context->Global()->Set(v8_str("P"), templ->NewInstance());
13821   CompileRun("function C1() {"
13822              "  this.x = 23;"
13823              "};"
13824              "C1.prototype = P;"
13825              "function C2() {"
13826              "  this.x = 23"
13827              "};"
13828              "C2.prototype = { };"
13829              "C2.prototype.__proto__ = P;");
13830
13831   v8::Local<v8::Script> script;
13832   script = v8::Script::Compile(v8_str("new C1();"));
13833   for (int i = 0; i < 10; i++) {
13834     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13835     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13836     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13837   }
13838
13839   script = v8::Script::Compile(v8_str("new C2();"));
13840   for (int i = 0; i < 10; i++) {
13841     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
13842     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
13843     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
13844   }
13845 }
13846
13847
13848 TEST(Bug618) {
13849   const char* source = "function C1() {"
13850                        "  this.x = 23;"
13851                        "};"
13852                        "C1.prototype = P;";
13853
13854   v8::HandleScope scope;
13855   LocalContext context;
13856   v8::Local<v8::Script> script;
13857
13858   // Use a simple object as prototype.
13859   v8::Local<v8::Object> prototype = v8::Object::New();
13860   prototype->Set(v8_str("y"), v8_num(42));
13861   context->Global()->Set(v8_str("P"), prototype);
13862
13863   // This compile will add the code to the compilation cache.
13864   CompileRun(source);
13865
13866   script = v8::Script::Compile(v8_str("new C1();"));
13867   // Allow enough iterations for the inobject slack tracking logic
13868   // to finalize instance size and install the fast construct stub.
13869   for (int i = 0; i < 256; i++) {
13870     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13871     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
13872     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
13873   }
13874
13875   // Use an API object with accessors as prototype.
13876   Local<ObjectTemplate> templ = ObjectTemplate::New();
13877   templ->SetAccessor(v8_str("x"),
13878                      GetterWhichReturns42,
13879                      SetterWhichSetsYOnThisTo23);
13880   context->Global()->Set(v8_str("P"), templ->NewInstance());
13881
13882   // This compile will get the code from the compilation cache.
13883   CompileRun(source);
13884
13885   script = v8::Script::Compile(v8_str("new C1();"));
13886   for (int i = 0; i < 10; i++) {
13887     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
13888     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
13889     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
13890   }
13891 }
13892
13893 int prologue_call_count = 0;
13894 int epilogue_call_count = 0;
13895 int prologue_call_count_second = 0;
13896 int epilogue_call_count_second = 0;
13897
13898 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
13899   ++prologue_call_count;
13900 }
13901
13902 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
13903   ++epilogue_call_count;
13904 }
13905
13906 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13907   ++prologue_call_count_second;
13908 }
13909
13910 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
13911   ++epilogue_call_count_second;
13912 }
13913
13914 TEST(GCCallbacks) {
13915   LocalContext context;
13916
13917   v8::V8::AddGCPrologueCallback(PrologueCallback);
13918   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
13919   CHECK_EQ(0, prologue_call_count);
13920   CHECK_EQ(0, epilogue_call_count);
13921   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13922   CHECK_EQ(1, prologue_call_count);
13923   CHECK_EQ(1, epilogue_call_count);
13924   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
13925   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
13926   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13927   CHECK_EQ(2, prologue_call_count);
13928   CHECK_EQ(2, epilogue_call_count);
13929   CHECK_EQ(1, prologue_call_count_second);
13930   CHECK_EQ(1, epilogue_call_count_second);
13931   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
13932   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
13933   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13934   CHECK_EQ(2, prologue_call_count);
13935   CHECK_EQ(2, epilogue_call_count);
13936   CHECK_EQ(2, prologue_call_count_second);
13937   CHECK_EQ(2, epilogue_call_count_second);
13938   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
13939   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
13940   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13941   CHECK_EQ(2, prologue_call_count);
13942   CHECK_EQ(2, epilogue_call_count);
13943   CHECK_EQ(2, prologue_call_count_second);
13944   CHECK_EQ(2, epilogue_call_count_second);
13945 }
13946
13947
13948 THREADED_TEST(AddToJSFunctionResultCache) {
13949   i::FLAG_allow_natives_syntax = true;
13950   v8::HandleScope scope;
13951
13952   LocalContext context;
13953
13954   const char* code =
13955       "(function() {"
13956       "  var key0 = 'a';"
13957       "  var key1 = 'b';"
13958       "  var r0 = %_GetFromCache(0, key0);"
13959       "  var r1 = %_GetFromCache(0, key1);"
13960       "  var r0_ = %_GetFromCache(0, key0);"
13961       "  if (r0 !== r0_)"
13962       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
13963       "  var r1_ = %_GetFromCache(0, key1);"
13964       "  if (r1 !== r1_)"
13965       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
13966       "  return 'PASSED';"
13967       "})()";
13968   HEAP->ClearJSFunctionResultCaches();
13969   ExpectString(code, "PASSED");
13970 }
13971
13972
13973 static const int k0CacheSize = 16;
13974
13975 THREADED_TEST(FillJSFunctionResultCache) {
13976   i::FLAG_allow_natives_syntax = true;
13977   v8::HandleScope scope;
13978
13979   LocalContext context;
13980
13981   const char* code =
13982       "(function() {"
13983       "  var k = 'a';"
13984       "  var r = %_GetFromCache(0, k);"
13985       "  for (var i = 0; i < 16; i++) {"
13986       "    %_GetFromCache(0, 'a' + i);"
13987       "  };"
13988       "  if (r === %_GetFromCache(0, k))"
13989       "    return 'FAILED: k0CacheSize is too small';"
13990       "  return 'PASSED';"
13991       "})()";
13992   HEAP->ClearJSFunctionResultCaches();
13993   ExpectString(code, "PASSED");
13994 }
13995
13996
13997 THREADED_TEST(RoundRobinGetFromCache) {
13998   i::FLAG_allow_natives_syntax = true;
13999   v8::HandleScope scope;
14000
14001   LocalContext context;
14002
14003   const char* code =
14004       "(function() {"
14005       "  var keys = [];"
14006       "  for (var i = 0; i < 16; i++) keys.push(i);"
14007       "  var values = [];"
14008       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14009       "  for (var i = 0; i < 16; i++) {"
14010       "    var v = %_GetFromCache(0, keys[i]);"
14011       "    if (v !== values[i])"
14012       "      return 'Wrong value for ' + "
14013       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
14014       "  };"
14015       "  return 'PASSED';"
14016       "})()";
14017   HEAP->ClearJSFunctionResultCaches();
14018   ExpectString(code, "PASSED");
14019 }
14020
14021
14022 THREADED_TEST(ReverseGetFromCache) {
14023   i::FLAG_allow_natives_syntax = true;
14024   v8::HandleScope scope;
14025
14026   LocalContext context;
14027
14028   const char* code =
14029       "(function() {"
14030       "  var keys = [];"
14031       "  for (var i = 0; i < 16; i++) keys.push(i);"
14032       "  var values = [];"
14033       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
14034       "  for (var i = 15; i >= 16; i--) {"
14035       "    var v = %_GetFromCache(0, keys[i]);"
14036       "    if (v !== values[i])"
14037       "      return 'Wrong value for ' + "
14038       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
14039       "  };"
14040       "  return 'PASSED';"
14041       "})()";
14042   HEAP->ClearJSFunctionResultCaches();
14043   ExpectString(code, "PASSED");
14044 }
14045
14046
14047 THREADED_TEST(TestEviction) {
14048   i::FLAG_allow_natives_syntax = true;
14049   v8::HandleScope scope;
14050
14051   LocalContext context;
14052
14053   const char* code =
14054       "(function() {"
14055       "  for (var i = 0; i < 2*16; i++) {"
14056       "    %_GetFromCache(0, 'a' + i);"
14057       "  };"
14058       "  return 'PASSED';"
14059       "})()";
14060   HEAP->ClearJSFunctionResultCaches();
14061   ExpectString(code, "PASSED");
14062 }
14063
14064
14065 THREADED_TEST(TwoByteStringInAsciiCons) {
14066   // See Chromium issue 47824.
14067   v8::HandleScope scope;
14068
14069   LocalContext context;
14070   const char* init_code =
14071       "var str1 = 'abelspendabel';"
14072       "var str2 = str1 + str1 + str1;"
14073       "str2;";
14074   Local<Value> result = CompileRun(init_code);
14075
14076   Local<Value> indexof = CompileRun("str2.indexOf('els')");
14077   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
14078
14079   CHECK(result->IsString());
14080   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
14081   int length = string->length();
14082   CHECK(string->IsAsciiRepresentation());
14083
14084   FlattenString(string);
14085   i::Handle<i::String> flat_string = FlattenGetString(string);
14086
14087   CHECK(string->IsAsciiRepresentation());
14088   CHECK(flat_string->IsAsciiRepresentation());
14089
14090   // Create external resource.
14091   uint16_t* uc16_buffer = new uint16_t[length + 1];
14092
14093   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
14094   uc16_buffer[length] = 0;
14095
14096   TestResource resource(uc16_buffer);
14097
14098   flat_string->MakeExternal(&resource);
14099
14100   CHECK(flat_string->IsTwoByteRepresentation());
14101
14102   // At this point, we should have a Cons string which is flat and ASCII,
14103   // with a first half that is a two-byte string (although it only contains
14104   // ASCII characters). This is a valid sequence of steps, and it can happen
14105   // in real pages.
14106
14107   CHECK(string->IsAsciiRepresentation());
14108   i::ConsString* cons = i::ConsString::cast(*string);
14109   CHECK_EQ(0, cons->second()->length());
14110   CHECK(cons->first()->IsTwoByteRepresentation());
14111
14112   // Check that some string operations work.
14113
14114   // Atom RegExp.
14115   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
14116   CHECK_EQ(6, reresult->Int32Value());
14117
14118   // Nonatom RegExp.
14119   reresult = CompileRun("str2.match(/abe./g).length;");
14120   CHECK_EQ(6, reresult->Int32Value());
14121
14122   reresult = CompileRun("str2.search(/bel/g);");
14123   CHECK_EQ(1, reresult->Int32Value());
14124
14125   reresult = CompileRun("str2.search(/be./g);");
14126   CHECK_EQ(1, reresult->Int32Value());
14127
14128   ExpectTrue("/bel/g.test(str2);");
14129
14130   ExpectTrue("/be./g.test(str2);");
14131
14132   reresult = CompileRun("/bel/g.exec(str2);");
14133   CHECK(!reresult->IsNull());
14134
14135   reresult = CompileRun("/be./g.exec(str2);");
14136   CHECK(!reresult->IsNull());
14137
14138   ExpectString("str2.substring(2, 10);", "elspenda");
14139
14140   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
14141
14142   ExpectString("str2.charAt(2);", "e");
14143
14144   ExpectObject("str2.indexOf('els');", indexof);
14145
14146   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
14147
14148   reresult = CompileRun("str2.charCodeAt(2);");
14149   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
14150 }
14151
14152
14153 // Failed access check callback that performs a GC on each invocation.
14154 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
14155                                  v8::AccessType type,
14156                                  Local<v8::Value> data) {
14157   HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14158 }
14159
14160
14161 TEST(GCInFailedAccessCheckCallback) {
14162   // Install a failed access check callback that performs a GC on each
14163   // invocation. Then force the callback to be called from va
14164
14165   v8::V8::Initialize();
14166   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
14167
14168   v8::HandleScope scope;
14169
14170   // Create an ObjectTemplate for global objects and install access
14171   // check callbacks that will block access.
14172   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14173   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14174                                            IndexedGetAccessBlocker,
14175                                            v8::Handle<v8::Value>(),
14176                                            false);
14177
14178   // Create a context and set an x property on it's global object.
14179   LocalContext context0(NULL, global_template);
14180   context0->Global()->Set(v8_str("x"), v8_num(42));
14181   v8::Handle<v8::Object> global0 = context0->Global();
14182
14183   // Create a context with a different security token so that the
14184   // failed access check callback will be called on each access.
14185   LocalContext context1(NULL, global_template);
14186   context1->Global()->Set(v8_str("other"), global0);
14187
14188   // Get property with failed access check.
14189   ExpectUndefined("other.x");
14190
14191   // Get element with failed access check.
14192   ExpectUndefined("other[0]");
14193
14194   // Set property with failed access check.
14195   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
14196   CHECK(result->IsObject());
14197
14198   // Set element with failed access check.
14199   result = CompileRun("other[0] = new Object()");
14200   CHECK(result->IsObject());
14201
14202   // Get property attribute with failed access check.
14203   ExpectFalse("\'x\' in other");
14204
14205   // Get property attribute for element with failed access check.
14206   ExpectFalse("0 in other");
14207
14208   // Delete property.
14209   ExpectFalse("delete other.x");
14210
14211   // Delete element.
14212   CHECK_EQ(false, global0->Delete(0));
14213
14214   // DefineAccessor.
14215   CHECK_EQ(false,
14216            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
14217
14218   // Define JavaScript accessor.
14219   ExpectUndefined("Object.prototype.__defineGetter__.call("
14220                   "    other, \'x\', function() { return 42; })");
14221
14222   // LookupAccessor.
14223   ExpectUndefined("Object.prototype.__lookupGetter__.call("
14224                   "    other, \'x\')");
14225
14226   // HasLocalElement.
14227   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
14228
14229   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
14230   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
14231   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
14232
14233   // Reset the failed access check callback so it does not influence
14234   // the other tests.
14235   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
14236 }
14237
14238 TEST(DefaultIsolateGetCurrent) {
14239   CHECK(v8::Isolate::GetCurrent() != NULL);
14240   v8::Isolate* isolate = v8::Isolate::GetCurrent();
14241   CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14242   printf("*** %s\n", "DefaultIsolateGetCurrent success");
14243 }
14244
14245 TEST(IsolateNewDispose) {
14246   v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14247   v8::Isolate* isolate = v8::Isolate::New();
14248   CHECK(isolate != NULL);
14249   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14250   CHECK(current_isolate != isolate);
14251   CHECK(current_isolate == v8::Isolate::GetCurrent());
14252
14253   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14254   last_location = last_message = NULL;
14255   isolate->Dispose();
14256   CHECK_EQ(last_location, NULL);
14257   CHECK_EQ(last_message, NULL);
14258 }
14259
14260 TEST(IsolateEnterExitDefault) {
14261   v8::HandleScope scope;
14262   LocalContext context;
14263   v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
14264   CHECK(current_isolate != NULL);  // Default isolate.
14265   ExpectString("'hello'", "hello");
14266   current_isolate->Enter();
14267   ExpectString("'still working'", "still working");
14268   current_isolate->Exit();
14269   ExpectString("'still working 2'", "still working 2");
14270   current_isolate->Exit();
14271   // Default isolate is always, well, 'default current'.
14272   CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
14273   // Still working since default isolate is auto-entering any thread
14274   // that has no isolate and attempts to execute V8 APIs.
14275   ExpectString("'still working 3'", "still working 3");
14276 }
14277
14278 TEST(DisposeDefaultIsolate) {
14279   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14280
14281   // Run some V8 code to trigger default isolate to become 'current'.
14282   v8::HandleScope scope;
14283   LocalContext context;
14284   ExpectString("'run some V8'", "run some V8");
14285
14286   v8::Isolate* isolate = v8::Isolate::GetCurrent();
14287   CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
14288   last_location = last_message = NULL;
14289   isolate->Dispose();
14290   // It is not possible to dispose default isolate via Isolate API.
14291   CHECK_NE(last_location, NULL);
14292   CHECK_NE(last_message, NULL);
14293 }
14294
14295 TEST(RunDefaultAndAnotherIsolate) {
14296   v8::HandleScope scope;
14297   LocalContext context;
14298
14299   // Enter new isolate.
14300   v8::Isolate* isolate = v8::Isolate::New();
14301   CHECK(isolate);
14302   isolate->Enter();
14303   { // Need this block because subsequent Exit() will deallocate Heap,
14304     // so we need all scope objects to be deconstructed when it happens.
14305     v8::HandleScope scope_new;
14306     LocalContext context_new;
14307
14308     // Run something in new isolate.
14309     CompileRun("var foo = 153;");
14310     ExpectTrue("function f() { return foo == 153; }; f()");
14311   }
14312   isolate->Exit();
14313
14314   // This runs automatically in default isolate.
14315   // Variables in another isolate should be not available.
14316   ExpectTrue("function f() {"
14317              "  try {"
14318              "    foo;"
14319              "    return false;"
14320              "  } catch(e) {"
14321              "    return true;"
14322              "  }"
14323              "};"
14324              "var bar = 371;"
14325              "f()");
14326
14327   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14328   last_location = last_message = NULL;
14329   isolate->Dispose();
14330   CHECK_EQ(last_location, NULL);
14331   CHECK_EQ(last_message, NULL);
14332
14333   // Check that default isolate still runs.
14334   ExpectTrue("function f() { return bar == 371; }; f()");
14335 }
14336
14337 TEST(DisposeIsolateWhenInUse) {
14338   v8::Isolate* isolate = v8::Isolate::New();
14339   CHECK(isolate);
14340   isolate->Enter();
14341   v8::HandleScope scope;
14342   LocalContext context;
14343   // Run something in this isolate.
14344   ExpectTrue("true");
14345   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14346   last_location = last_message = NULL;
14347   // Still entered, should fail.
14348   isolate->Dispose();
14349   CHECK_NE(last_location, NULL);
14350   CHECK_NE(last_message, NULL);
14351 }
14352
14353 TEST(RunTwoIsolatesOnSingleThread) {
14354   // Run isolate 1.
14355   v8::Isolate* isolate1 = v8::Isolate::New();
14356   isolate1->Enter();
14357   v8::Persistent<v8::Context> context1 = v8::Context::New();
14358
14359   {
14360     v8::Context::Scope cscope(context1);
14361     v8::HandleScope scope;
14362     // Run something in new isolate.
14363     CompileRun("var foo = 'isolate 1';");
14364     ExpectString("function f() { return foo; }; f()", "isolate 1");
14365   }
14366
14367   // Run isolate 2.
14368   v8::Isolate* isolate2 = v8::Isolate::New();
14369   v8::Persistent<v8::Context> context2;
14370
14371   {
14372     v8::Isolate::Scope iscope(isolate2);
14373     context2 = v8::Context::New();
14374     v8::Context::Scope cscope(context2);
14375     v8::HandleScope scope;
14376
14377     // Run something in new isolate.
14378     CompileRun("var foo = 'isolate 2';");
14379     ExpectString("function f() { return foo; }; f()", "isolate 2");
14380   }
14381
14382   {
14383     v8::Context::Scope cscope(context1);
14384     v8::HandleScope scope;
14385     // Now again in isolate 1
14386     ExpectString("function f() { return foo; }; f()", "isolate 1");
14387   }
14388
14389   isolate1->Exit();
14390
14391   // Run some stuff in default isolate.
14392   v8::Persistent<v8::Context> context_default = v8::Context::New();
14393
14394   {
14395     v8::Context::Scope cscope(context_default);
14396     v8::HandleScope scope;
14397     // Variables in other isolates should be not available, verify there
14398     // is an exception.
14399     ExpectTrue("function f() {"
14400                "  try {"
14401                "    foo;"
14402                "    return false;"
14403                "  } catch(e) {"
14404                "    return true;"
14405                "  }"
14406                "};"
14407                "var isDefaultIsolate = true;"
14408                "f()");
14409   }
14410
14411   isolate1->Enter();
14412
14413   {
14414     v8::Isolate::Scope iscope(isolate2);
14415     v8::Context::Scope cscope(context2);
14416     v8::HandleScope scope;
14417     ExpectString("function f() { return foo; }; f()", "isolate 2");
14418   }
14419
14420   {
14421     v8::Context::Scope cscope(context1);
14422     v8::HandleScope scope;
14423     ExpectString("function f() { return foo; }; f()", "isolate 1");
14424   }
14425
14426   {
14427     v8::Isolate::Scope iscope(isolate2);
14428     context2.Dispose();
14429   }
14430
14431   context1.Dispose();
14432   isolate1->Exit();
14433
14434   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14435   last_location = last_message = NULL;
14436
14437   isolate1->Dispose();
14438   CHECK_EQ(last_location, NULL);
14439   CHECK_EQ(last_message, NULL);
14440
14441   isolate2->Dispose();
14442   CHECK_EQ(last_location, NULL);
14443   CHECK_EQ(last_message, NULL);
14444
14445   // Check that default isolate still runs.
14446   {
14447     v8::Context::Scope cscope(context_default);
14448     v8::HandleScope scope;
14449     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
14450   }
14451 }
14452
14453 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
14454   v8::Isolate::Scope isolate_scope(isolate);
14455   v8::HandleScope scope;
14456   LocalContext context;
14457   i::ScopedVector<char> code(1024);
14458   i::OS::SNPrintF(code, "function fib(n) {"
14459                         "  if (n <= 2) return 1;"
14460                         "  return fib(n-1) + fib(n-2);"
14461                         "}"
14462                         "fib(%d)", limit);
14463   Local<Value> value = CompileRun(code.start());
14464   CHECK(value->IsNumber());
14465   return static_cast<int>(value->NumberValue());
14466 }
14467
14468 class IsolateThread : public v8::internal::Thread {
14469  public:
14470   IsolateThread(v8::Isolate* isolate, int fib_limit)
14471       : Thread("IsolateThread"),
14472         isolate_(isolate),
14473         fib_limit_(fib_limit),
14474         result_(0) { }
14475
14476   void Run() {
14477     result_ = CalcFibonacci(isolate_, fib_limit_);
14478   }
14479
14480   int result() { return result_; }
14481
14482  private:
14483   v8::Isolate* isolate_;
14484   int fib_limit_;
14485   int result_;
14486 };
14487
14488 TEST(MultipleIsolatesOnIndividualThreads) {
14489   v8::Isolate* isolate1 = v8::Isolate::New();
14490   v8::Isolate* isolate2 = v8::Isolate::New();
14491
14492   IsolateThread thread1(isolate1, 21);
14493   IsolateThread thread2(isolate2, 12);
14494
14495   // Compute some fibonacci numbers on 3 threads in 3 isolates.
14496   thread1.Start();
14497   thread2.Start();
14498
14499   int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
14500   int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
14501
14502   thread1.Join();
14503   thread2.Join();
14504
14505   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
14506   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
14507   CHECK_EQ(result1, 10946);
14508   CHECK_EQ(result2, 144);
14509   CHECK_EQ(result1, thread1.result());
14510   CHECK_EQ(result2, thread2.result());
14511
14512   isolate1->Dispose();
14513   isolate2->Dispose();
14514 }
14515
14516 TEST(IsolateDifferentContexts) {
14517   v8::Isolate* isolate = v8::Isolate::New();
14518   Persistent<v8::Context> context;
14519   {
14520     v8::Isolate::Scope isolate_scope(isolate);
14521     v8::HandleScope handle_scope;
14522     context = v8::Context::New();
14523     v8::Context::Scope context_scope(context);
14524     Local<Value> v = CompileRun("2");
14525     CHECK(v->IsNumber());
14526     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
14527   }
14528   {
14529     v8::Isolate::Scope isolate_scope(isolate);
14530     v8::HandleScope handle_scope;
14531     context = v8::Context::New();
14532     v8::Context::Scope context_scope(context);
14533     Local<Value> v = CompileRun("22");
14534     CHECK(v->IsNumber());
14535     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
14536   }
14537 }
14538
14539 class InitDefaultIsolateThread : public v8::internal::Thread {
14540  public:
14541   enum TestCase {
14542     IgnoreOOM,
14543     SetResourceConstraints,
14544     SetFatalHandler,
14545     SetCounterFunction,
14546     SetCreateHistogramFunction,
14547     SetAddHistogramSampleFunction
14548   };
14549
14550   explicit InitDefaultIsolateThread(TestCase testCase)
14551       : Thread("InitDefaultIsolateThread"),
14552         testCase_(testCase),
14553         result_(false) { }
14554
14555   void Run() {
14556     switch (testCase_) {
14557     case IgnoreOOM:
14558       v8::V8::IgnoreOutOfMemoryException();
14559       break;
14560
14561     case SetResourceConstraints: {
14562       static const int K = 1024;
14563       v8::ResourceConstraints constraints;
14564       constraints.set_max_young_space_size(256 * K);
14565       constraints.set_max_old_space_size(4 * K * K);
14566       v8::SetResourceConstraints(&constraints);
14567       break;
14568     }
14569
14570     case SetFatalHandler:
14571       v8::V8::SetFatalErrorHandler(NULL);
14572       break;
14573
14574     case SetCounterFunction:
14575       v8::V8::SetCounterFunction(NULL);
14576       break;
14577
14578     case SetCreateHistogramFunction:
14579       v8::V8::SetCreateHistogramFunction(NULL);
14580       break;
14581
14582     case SetAddHistogramSampleFunction:
14583       v8::V8::SetAddHistogramSampleFunction(NULL);
14584       break;
14585     }
14586     result_ = true;
14587   }
14588
14589   bool result() { return result_; }
14590
14591  private:
14592   TestCase testCase_;
14593   bool result_;
14594 };
14595
14596
14597 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
14598   InitDefaultIsolateThread thread(testCase);
14599   thread.Start();
14600   thread.Join();
14601   CHECK_EQ(thread.result(), true);
14602 }
14603
14604 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
14605   InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
14606 }
14607
14608 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
14609   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
14610 }
14611
14612 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
14613   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
14614 }
14615
14616 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
14617   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
14618 }
14619
14620 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
14621   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
14622 }
14623
14624 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
14625   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
14626 }
14627
14628
14629 TEST(StringCheckMultipleContexts) {
14630   const char* code =
14631       "(function() { return \"a\".charAt(0); })()";
14632
14633   {
14634     // Run the code twice in the first context to initialize the call IC.
14635     v8::HandleScope scope;
14636     LocalContext context1;
14637     ExpectString(code, "a");
14638     ExpectString(code, "a");
14639   }
14640
14641   {
14642     // Change the String.prototype in the second context and check
14643     // that the right function gets called.
14644     v8::HandleScope scope;
14645     LocalContext context2;
14646     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
14647     ExpectString(code, "not a");
14648   }
14649 }
14650
14651
14652 TEST(NumberCheckMultipleContexts) {
14653   const char* code =
14654       "(function() { return (42).toString(); })()";
14655
14656   {
14657     // Run the code twice in the first context to initialize the call IC.
14658     v8::HandleScope scope;
14659     LocalContext context1;
14660     ExpectString(code, "42");
14661     ExpectString(code, "42");
14662   }
14663
14664   {
14665     // Change the Number.prototype in the second context and check
14666     // that the right function gets called.
14667     v8::HandleScope scope;
14668     LocalContext context2;
14669     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
14670     ExpectString(code, "not 42");
14671   }
14672 }
14673
14674
14675 TEST(BooleanCheckMultipleContexts) {
14676   const char* code =
14677       "(function() { return true.toString(); })()";
14678
14679   {
14680     // Run the code twice in the first context to initialize the call IC.
14681     v8::HandleScope scope;
14682     LocalContext context1;
14683     ExpectString(code, "true");
14684     ExpectString(code, "true");
14685   }
14686
14687   {
14688     // Change the Boolean.prototype in the second context and check
14689     // that the right function gets called.
14690     v8::HandleScope scope;
14691     LocalContext context2;
14692     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
14693     ExpectString(code, "");
14694   }
14695 }
14696
14697
14698 TEST(DontDeleteCellLoadIC) {
14699   const char* function_code =
14700       "function readCell() { while (true) { return cell; } }";
14701
14702   {
14703     // Run the code twice in the first context to initialize the load
14704     // IC for a don't delete cell.
14705     v8::HandleScope scope;
14706     LocalContext context1;
14707     CompileRun("var cell = \"first\";");
14708     ExpectBoolean("delete cell", false);
14709     CompileRun(function_code);
14710     ExpectString("readCell()", "first");
14711     ExpectString("readCell()", "first");
14712   }
14713
14714   {
14715     // Use a deletable cell in the second context.
14716     v8::HandleScope scope;
14717     LocalContext context2;
14718     CompileRun("cell = \"second\";");
14719     CompileRun(function_code);
14720     ExpectString("readCell()", "second");
14721     ExpectBoolean("delete cell", true);
14722     ExpectString("(function() {"
14723                  "  try {"
14724                  "    return readCell();"
14725                  "  } catch(e) {"
14726                  "    return e.toString();"
14727                  "  }"
14728                  "})()",
14729                  "ReferenceError: cell is not defined");
14730     CompileRun("cell = \"new_second\";");
14731     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14732     ExpectString("readCell()", "new_second");
14733     ExpectString("readCell()", "new_second");
14734   }
14735 }
14736
14737
14738 TEST(DontDeleteCellLoadICForceDelete) {
14739   const char* function_code =
14740       "function readCell() { while (true) { return cell; } }";
14741
14742   // Run the code twice to initialize the load IC for a don't delete
14743   // cell.
14744   v8::HandleScope scope;
14745   LocalContext context;
14746   CompileRun("var cell = \"value\";");
14747   ExpectBoolean("delete cell", false);
14748   CompileRun(function_code);
14749   ExpectString("readCell()", "value");
14750   ExpectString("readCell()", "value");
14751
14752   // Delete the cell using the API and check the inlined code works
14753   // correctly.
14754   CHECK(context->Global()->ForceDelete(v8_str("cell")));
14755   ExpectString("(function() {"
14756                "  try {"
14757                "    return readCell();"
14758                "  } catch(e) {"
14759                "    return e.toString();"
14760                "  }"
14761                "})()",
14762                "ReferenceError: cell is not defined");
14763 }
14764
14765
14766 TEST(DontDeleteCellLoadICAPI) {
14767   const char* function_code =
14768       "function readCell() { while (true) { return cell; } }";
14769
14770   // Run the code twice to initialize the load IC for a don't delete
14771   // cell created using the API.
14772   v8::HandleScope scope;
14773   LocalContext context;
14774   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
14775   ExpectBoolean("delete cell", false);
14776   CompileRun(function_code);
14777   ExpectString("readCell()", "value");
14778   ExpectString("readCell()", "value");
14779
14780   // Delete the cell using the API and check the inlined code works
14781   // correctly.
14782   CHECK(context->Global()->ForceDelete(v8_str("cell")));
14783   ExpectString("(function() {"
14784                "  try {"
14785                "    return readCell();"
14786                "  } catch(e) {"
14787                "    return e.toString();"
14788                "  }"
14789                "})()",
14790                "ReferenceError: cell is not defined");
14791 }
14792
14793
14794 TEST(RegExp) {
14795   v8::HandleScope scope;
14796   LocalContext context;
14797
14798   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
14799   CHECK(re->IsRegExp());
14800   CHECK(re->GetSource()->Equals(v8_str("foo")));
14801   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14802
14803   re = v8::RegExp::New(v8_str("bar"),
14804                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14805                                                       v8::RegExp::kGlobal));
14806   CHECK(re->IsRegExp());
14807   CHECK(re->GetSource()->Equals(v8_str("bar")));
14808   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
14809            static_cast<int>(re->GetFlags()));
14810
14811   re = v8::RegExp::New(v8_str("baz"),
14812                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14813                                                       v8::RegExp::kMultiline));
14814   CHECK(re->IsRegExp());
14815   CHECK(re->GetSource()->Equals(v8_str("baz")));
14816   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14817            static_cast<int>(re->GetFlags()));
14818
14819   re = CompileRun("/quux/").As<v8::RegExp>();
14820   CHECK(re->IsRegExp());
14821   CHECK(re->GetSource()->Equals(v8_str("quux")));
14822   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14823
14824   re = CompileRun("/quux/gm").As<v8::RegExp>();
14825   CHECK(re->IsRegExp());
14826   CHECK(re->GetSource()->Equals(v8_str("quux")));
14827   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
14828            static_cast<int>(re->GetFlags()));
14829
14830   // Override the RegExp constructor and check the API constructor
14831   // still works.
14832   CompileRun("RegExp = function() {}");
14833
14834   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
14835   CHECK(re->IsRegExp());
14836   CHECK(re->GetSource()->Equals(v8_str("foobar")));
14837   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
14838
14839   re = v8::RegExp::New(v8_str("foobarbaz"),
14840                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
14841                                                       v8::RegExp::kMultiline));
14842   CHECK(re->IsRegExp());
14843   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
14844   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
14845            static_cast<int>(re->GetFlags()));
14846
14847   context->Global()->Set(v8_str("re"), re);
14848   ExpectTrue("re.test('FoobarbaZ')");
14849
14850   // RegExps are objects on which you can set properties.
14851   re->Set(v8_str("property"), v8::Integer::New(32));
14852   v8::Handle<v8::Value> value(CompileRun("re.property"));
14853   ASSERT_EQ(32, value->Int32Value());
14854
14855   v8::TryCatch try_catch;
14856   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
14857   CHECK(re.IsEmpty());
14858   CHECK(try_catch.HasCaught());
14859   context->Global()->Set(v8_str("ex"), try_catch.Exception());
14860   ExpectTrue("ex instanceof SyntaxError");
14861 }
14862
14863
14864 THREADED_TEST(Equals) {
14865   v8::HandleScope handleScope;
14866   LocalContext localContext;
14867
14868   v8::Handle<v8::Object> globalProxy = localContext->Global();
14869   v8::Handle<Value> global = globalProxy->GetPrototype();
14870
14871   CHECK(global->StrictEquals(global));
14872   CHECK(!global->StrictEquals(globalProxy));
14873   CHECK(!globalProxy->StrictEquals(global));
14874   CHECK(globalProxy->StrictEquals(globalProxy));
14875
14876   CHECK(global->Equals(global));
14877   CHECK(!global->Equals(globalProxy));
14878   CHECK(!globalProxy->Equals(global));
14879   CHECK(globalProxy->Equals(globalProxy));
14880 }
14881
14882
14883 static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
14884                                     const v8::AccessorInfo& info ) {
14885   return v8_str("42!");
14886 }
14887
14888
14889 static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) {
14890   v8::Handle<v8::Array> result = v8::Array::New();
14891   result->Set(0, v8_str("universalAnswer"));
14892   return result;
14893 }
14894
14895
14896 TEST(NamedEnumeratorAndForIn) {
14897   v8::HandleScope handle_scope;
14898   LocalContext context;
14899   v8::Context::Scope context_scope(context.local());
14900
14901   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
14902   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
14903   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
14904   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
14905         "var result = []; for (var k in o) result.push(k); result"));
14906   CHECK_EQ(1, result->Length());
14907   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
14908 }
14909
14910
14911 TEST(DefinePropertyPostDetach) {
14912   v8::HandleScope scope;
14913   LocalContext context;
14914   v8::Handle<v8::Object> proxy = context->Global();
14915   v8::Handle<v8::Function> define_property =
14916       CompileRun("(function() {"
14917                  "  Object.defineProperty("
14918                  "    this,"
14919                  "    1,"
14920                  "    { configurable: true, enumerable: true, value: 3 });"
14921                  "})").As<Function>();
14922   context->DetachGlobal();
14923   define_property->Call(proxy, 0, NULL);
14924 }
14925
14926
14927 static void InstallContextId(v8::Handle<Context> context, int id) {
14928   Context::Scope scope(context);
14929   CompileRun("Object.prototype").As<Object>()->
14930       Set(v8_str("context_id"), v8::Integer::New(id));
14931 }
14932
14933
14934 static void CheckContextId(v8::Handle<Object> object, int expected) {
14935   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
14936 }
14937
14938
14939 THREADED_TEST(CreationContext) {
14940   HandleScope handle_scope;
14941   Persistent<Context> context1 = Context::New();
14942   InstallContextId(context1, 1);
14943   Persistent<Context> context2 = Context::New();
14944   InstallContextId(context2, 2);
14945   Persistent<Context> context3 = Context::New();
14946   InstallContextId(context3, 3);
14947
14948   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
14949
14950   Local<Object> object1;
14951   Local<Function> func1;
14952   {
14953     Context::Scope scope(context1);
14954     object1 = Object::New();
14955     func1 = tmpl->GetFunction();
14956   }
14957
14958   Local<Object> object2;
14959   Local<Function> func2;
14960   {
14961     Context::Scope scope(context2);
14962     object2 = Object::New();
14963     func2 = tmpl->GetFunction();
14964   }
14965
14966   Local<Object> instance1;
14967   Local<Object> instance2;
14968
14969   {
14970     Context::Scope scope(context3);
14971     instance1 = func1->NewInstance();
14972     instance2 = func2->NewInstance();
14973   }
14974
14975   CHECK(object1->CreationContext() == context1);
14976   CheckContextId(object1, 1);
14977   CHECK(func1->CreationContext() == context1);
14978   CheckContextId(func1, 1);
14979   CHECK(instance1->CreationContext() == context1);
14980   CheckContextId(instance1, 1);
14981   CHECK(object2->CreationContext() == context2);
14982   CheckContextId(object2, 2);
14983   CHECK(func2->CreationContext() == context2);
14984   CheckContextId(func2, 2);
14985   CHECK(instance2->CreationContext() == context2);
14986   CheckContextId(instance2, 2);
14987
14988   {
14989     Context::Scope scope(context1);
14990     CHECK(object1->CreationContext() == context1);
14991     CheckContextId(object1, 1);
14992     CHECK(func1->CreationContext() == context1);
14993     CheckContextId(func1, 1);
14994     CHECK(instance1->CreationContext() == context1);
14995     CheckContextId(instance1, 1);
14996     CHECK(object2->CreationContext() == context2);
14997     CheckContextId(object2, 2);
14998     CHECK(func2->CreationContext() == context2);
14999     CheckContextId(func2, 2);
15000     CHECK(instance2->CreationContext() == context2);
15001     CheckContextId(instance2, 2);
15002   }
15003
15004   {
15005     Context::Scope scope(context2);
15006     CHECK(object1->CreationContext() == context1);
15007     CheckContextId(object1, 1);
15008     CHECK(func1->CreationContext() == context1);
15009     CheckContextId(func1, 1);
15010     CHECK(instance1->CreationContext() == context1);
15011     CheckContextId(instance1, 1);
15012     CHECK(object2->CreationContext() == context2);
15013     CheckContextId(object2, 2);
15014     CHECK(func2->CreationContext() == context2);
15015     CheckContextId(func2, 2);
15016     CHECK(instance2->CreationContext() == context2);
15017     CheckContextId(instance2, 2);
15018   }
15019
15020   context1.Dispose();
15021   context2.Dispose();
15022   context3.Dispose();
15023 }
15024
15025
15026 THREADED_TEST(CreationContextOfJsFunction) {
15027   HandleScope handle_scope;
15028   Persistent<Context> context = Context::New();
15029   InstallContextId(context, 1);
15030
15031   Local<Object> function;
15032   {
15033     Context::Scope scope(context);
15034     function = CompileRun("function foo() {}; foo").As<Object>();
15035   }
15036
15037   CHECK(function->CreationContext() == context);
15038   CheckContextId(function, 1);
15039
15040   context.Dispose();
15041 }
15042
15043
15044 Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index,
15045                                                   const AccessorInfo& info) {
15046   if (index == 42) return v8_str("yes");
15047   return Handle<v8::Integer>();
15048 }
15049
15050
15051 Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property,
15052                                                 const AccessorInfo& info) {
15053   if (property->Equals(v8_str("foo"))) return v8_str("yes");
15054   return Handle<Value>();
15055 }
15056
15057
15058 Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery(
15059     uint32_t index, const AccessorInfo& info) {
15060   if (index == 42) return v8_num(1).As<v8::Integer>();
15061   return Handle<v8::Integer>();
15062 }
15063
15064
15065 Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery(
15066     Local<String> property, const AccessorInfo& info) {
15067   if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>();
15068   return Handle<v8::Integer>();
15069 }
15070
15071
15072 Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2(
15073     Local<String> property, const AccessorInfo& info) {
15074   if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>();
15075   return Handle<v8::Integer>();
15076 }
15077
15078
15079 Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property,
15080                                            const AccessorInfo& info) {
15081   return v8_str("yes");
15082 }
15083
15084
15085 TEST(HasOwnProperty) {
15086   v8::HandleScope scope;
15087   LocalContext env;
15088   { // Check normal properties and defined getters.
15089     Handle<Value> value = CompileRun(
15090         "function Foo() {"
15091         "    this.foo = 11;"
15092         "    this.__defineGetter__('baz', function() { return 1; });"
15093         "};"
15094         "function Bar() { "
15095         "    this.bar = 13;"
15096         "    this.__defineGetter__('bla', function() { return 2; });"
15097         "};"
15098         "Bar.prototype = new Foo();"
15099         "new Bar();");
15100     CHECK(value->IsObject());
15101     Handle<Object> object = value->ToObject();
15102     CHECK(object->Has(v8_str("foo")));
15103     CHECK(!object->HasOwnProperty(v8_str("foo")));
15104     CHECK(object->HasOwnProperty(v8_str("bar")));
15105     CHECK(object->Has(v8_str("baz")));
15106     CHECK(!object->HasOwnProperty(v8_str("baz")));
15107     CHECK(object->HasOwnProperty(v8_str("bla")));
15108   }
15109   { // Check named getter interceptors.
15110     Handle<ObjectTemplate> templ = ObjectTemplate::New();
15111     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
15112     Handle<Object> instance = templ->NewInstance();
15113     CHECK(!instance->HasOwnProperty(v8_str("42")));
15114     CHECK(instance->HasOwnProperty(v8_str("foo")));
15115     CHECK(!instance->HasOwnProperty(v8_str("bar")));
15116   }
15117   { // Check indexed getter interceptors.
15118     Handle<ObjectTemplate> templ = ObjectTemplate::New();
15119     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
15120     Handle<Object> instance = templ->NewInstance();
15121     CHECK(instance->HasOwnProperty(v8_str("42")));
15122     CHECK(!instance->HasOwnProperty(v8_str("43")));
15123     CHECK(!instance->HasOwnProperty(v8_str("foo")));
15124   }
15125   { // Check named query interceptors.
15126     Handle<ObjectTemplate> templ = ObjectTemplate::New();
15127     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
15128     Handle<Object> instance = templ->NewInstance();
15129     CHECK(instance->HasOwnProperty(v8_str("foo")));
15130     CHECK(!instance->HasOwnProperty(v8_str("bar")));
15131   }
15132   { // Check indexed query interceptors.
15133     Handle<ObjectTemplate> templ = ObjectTemplate::New();
15134     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
15135     Handle<Object> instance = templ->NewInstance();
15136     CHECK(instance->HasOwnProperty(v8_str("42")));
15137     CHECK(!instance->HasOwnProperty(v8_str("41")));
15138   }
15139   { // Check callbacks.
15140     Handle<ObjectTemplate> templ = ObjectTemplate::New();
15141     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
15142     Handle<Object> instance = templ->NewInstance();
15143     CHECK(instance->HasOwnProperty(v8_str("foo")));
15144     CHECK(!instance->HasOwnProperty(v8_str("bar")));
15145   }
15146   { // Check that query wins on disagreement.
15147     Handle<ObjectTemplate> templ = ObjectTemplate::New();
15148     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
15149                                    0,
15150                                    HasOwnPropertyNamedPropertyQuery2);
15151     Handle<Object> instance = templ->NewInstance();
15152     CHECK(!instance->HasOwnProperty(v8_str("foo")));
15153     CHECK(instance->HasOwnProperty(v8_str("bar")));
15154   }
15155 }
15156
15157
15158 void CheckCodeGenerationAllowed() {
15159   Handle<Value> result = CompileRun("eval('42')");
15160   CHECK_EQ(42, result->Int32Value());
15161   result = CompileRun("(function(e) { return e('42'); })(eval)");
15162   CHECK_EQ(42, result->Int32Value());
15163   result = CompileRun("var f = new Function('return 42'); f()");
15164   CHECK_EQ(42, result->Int32Value());
15165 }
15166
15167
15168 void CheckCodeGenerationDisallowed() {
15169   TryCatch try_catch;
15170
15171   Handle<Value> result = CompileRun("eval('42')");
15172   CHECK(result.IsEmpty());
15173   CHECK(try_catch.HasCaught());
15174   try_catch.Reset();
15175
15176   result = CompileRun("(function(e) { return e('42'); })(eval)");
15177   CHECK(result.IsEmpty());
15178   CHECK(try_catch.HasCaught());
15179   try_catch.Reset();
15180
15181   result = CompileRun("var f = new Function('return 42'); f()");
15182   CHECK(result.IsEmpty());
15183   CHECK(try_catch.HasCaught());
15184 }
15185
15186
15187 bool CodeGenerationAllowed(Local<Context> context) {
15188   ApiTestFuzzer::Fuzz();
15189   return true;
15190 }
15191
15192
15193 bool CodeGenerationDisallowed(Local<Context> context) {
15194   ApiTestFuzzer::Fuzz();
15195   return false;
15196 }
15197
15198
15199 THREADED_TEST(AllowCodeGenFromStrings) {
15200   v8::HandleScope scope;
15201   LocalContext context;
15202
15203   // eval and the Function constructor allowed by default.
15204   CheckCodeGenerationAllowed();
15205
15206   // Disallow eval and the Function constructor.
15207   context->AllowCodeGenerationFromStrings(false);
15208   CheckCodeGenerationDisallowed();
15209
15210   // Allow again.
15211   context->AllowCodeGenerationFromStrings(true);
15212   CheckCodeGenerationAllowed();
15213
15214   // Disallow but setting a global callback that will allow the calls.
15215   context->AllowCodeGenerationFromStrings(false);
15216   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
15217   CheckCodeGenerationAllowed();
15218
15219   // Set a callback that disallows the code generation.
15220   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
15221   CheckCodeGenerationDisallowed();
15222 }
15223
15224
15225 static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) {
15226   return v8::Undefined();
15227 }
15228
15229
15230 THREADED_TEST(CallAPIFunctionOnNonObject) {
15231   v8::HandleScope scope;
15232   LocalContext context;
15233   Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
15234   Handle<Function> function = templ->GetFunction();
15235   context->Global()->Set(v8_str("f"), function);
15236   TryCatch try_catch;
15237   CompileRun("f.call(2)");
15238 }
15239
15240
15241 // Regression test for issue 1470.
15242 THREADED_TEST(ReadOnlyIndexedProperties) {
15243   v8::HandleScope scope;
15244   Local<ObjectTemplate> templ = ObjectTemplate::New();
15245
15246   LocalContext context;
15247   Local<v8::Object> obj = templ->NewInstance();
15248   context->Global()->Set(v8_str("obj"), obj);
15249   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15250   obj->Set(v8_str("1"), v8_str("foobar"));
15251   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
15252   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
15253   obj->Set(v8_num(2), v8_str("foobar"));
15254   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
15255
15256   // Test non-smi case.
15257   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
15258   obj->Set(v8_str("2000000000"), v8_str("foobar"));
15259   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
15260 }
15261
15262
15263 THREADED_TEST(Regress1516) {
15264   v8::HandleScope scope;
15265
15266   LocalContext context;
15267   { v8::HandleScope temp_scope;
15268     CompileRun("({'a': 0})");
15269   }
15270
15271   int elements;
15272   { i::MapCache* map_cache =
15273         i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
15274     elements = map_cache->NumberOfElements();
15275     CHECK_LE(1, elements);
15276   }
15277
15278   i::Isolate::Current()->heap()->CollectAllGarbage(true);
15279   { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
15280     if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
15281       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
15282       CHECK_GT(elements, map_cache->NumberOfElements());
15283     }
15284   }
15285 }
15286
15287
15288 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
15289                                                 Local<Value> name,
15290                                                 v8::AccessType type,
15291                                                 Local<Value> data) {
15292   // Only block read access to __proto__.
15293   if (type == v8::ACCESS_GET &&
15294       name->IsString() &&
15295       name->ToString()->Length() == 9 &&
15296       name->ToString()->Utf8Length() == 9) {
15297     char buffer[10];
15298     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
15299     return strncmp(buffer, "__proto__", 9) != 0;
15300   }
15301
15302   return true;
15303 }
15304
15305
15306 THREADED_TEST(Regress93759) {
15307   HandleScope scope;
15308
15309   // Template for object with security check.
15310   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
15311   // We don't do indexing, so any callback can be used for that.
15312   no_proto_template->SetAccessCheckCallbacks(
15313       BlockProtoNamedSecurityTestCallback,
15314       IndexedSecurityTestCallback);
15315
15316   // Templates for objects with hidden prototypes and possibly security check.
15317   Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
15318   hidden_proto_template->SetHiddenPrototype(true);
15319
15320   Local<FunctionTemplate> protected_hidden_proto_template =
15321       v8::FunctionTemplate::New();
15322   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
15323       BlockProtoNamedSecurityTestCallback,
15324       IndexedSecurityTestCallback);
15325   protected_hidden_proto_template->SetHiddenPrototype(true);
15326
15327   // Context for "foreign" objects used in test.
15328   Persistent<Context> context = v8::Context::New();
15329   context->Enter();
15330
15331   // Plain object, no security check.
15332   Local<Object> simple_object = Object::New();
15333
15334   // Object with explicit security check.
15335   Local<Object> protected_object =
15336       no_proto_template->NewInstance();
15337
15338   // JSGlobalProxy object, always have security check.
15339   Local<Object> proxy_object =
15340       context->Global();
15341
15342   // Global object, the  prototype of proxy_object. No security checks.
15343   Local<Object> global_object =
15344       proxy_object->GetPrototype()->ToObject();
15345
15346   // Hidden prototype without security check.
15347   Local<Object> hidden_prototype =
15348       hidden_proto_template->GetFunction()->NewInstance();
15349   Local<Object> object_with_hidden =
15350     Object::New();
15351   object_with_hidden->SetPrototype(hidden_prototype);
15352
15353   // Hidden prototype with security check on the hidden prototype.
15354   Local<Object> protected_hidden_prototype =
15355       protected_hidden_proto_template->GetFunction()->NewInstance();
15356   Local<Object> object_with_protected_hidden =
15357     Object::New();
15358   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
15359
15360   context->Exit();
15361
15362   // Template for object for second context. Values to test are put on it as
15363   // properties.
15364   Local<ObjectTemplate> global_template = ObjectTemplate::New();
15365   global_template->Set(v8_str("simple"), simple_object);
15366   global_template->Set(v8_str("protected"), protected_object);
15367   global_template->Set(v8_str("global"), global_object);
15368   global_template->Set(v8_str("proxy"), proxy_object);
15369   global_template->Set(v8_str("hidden"), object_with_hidden);
15370   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
15371
15372   LocalContext context2(NULL, global_template);
15373
15374   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
15375   CHECK(result1->Equals(simple_object->GetPrototype()));
15376
15377   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
15378   CHECK(result2->Equals(Undefined()));
15379
15380   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
15381   CHECK(result3->Equals(global_object->GetPrototype()));
15382
15383   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
15384   CHECK(result4->Equals(Undefined()));
15385
15386   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
15387   CHECK(result5->Equals(
15388       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
15389
15390   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
15391   CHECK(result6->Equals(Undefined()));
15392
15393   context.Dispose();
15394 }
15395
15396
15397 static void TestReceiver(Local<Value> expected_result,
15398                          Local<Value> expected_receiver,
15399                          const char* code) {
15400   Local<Value> result = CompileRun(code);
15401   CHECK(result->IsObject());
15402   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
15403   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
15404 }
15405
15406
15407 THREADED_TEST(ForeignFunctionReceiver) {
15408   HandleScope scope;
15409
15410   // Create two contexts with different "id" properties ('i' and 'o').
15411   // Call a function both from its own context and from a the foreign
15412   // context, and see what "this" is bound to (returning both "this"
15413   // and "this.id" for comparison).
15414
15415   Persistent<Context> foreign_context = v8::Context::New();
15416   foreign_context->Enter();
15417   Local<Value> foreign_function =
15418     CompileRun("function func() { return { 0: this.id, "
15419                "                           1: this, "
15420                "                           toString: function() { "
15421                "                               return this[0];"
15422                "                           }"
15423                "                         };"
15424                "}"
15425                "var id = 'i';"
15426                "func;");
15427   CHECK(foreign_function->IsFunction());
15428   foreign_context->Exit();
15429
15430   LocalContext context;
15431
15432   Local<String> password = v8_str("Password");
15433   // Don't get hit by security checks when accessing foreign_context's
15434   // global receiver (aka. global proxy).
15435   context->SetSecurityToken(password);
15436   foreign_context->SetSecurityToken(password);
15437
15438   Local<String> i = v8_str("i");
15439   Local<String> o = v8_str("o");
15440   Local<String> id = v8_str("id");
15441
15442   CompileRun("function ownfunc() { return { 0: this.id, "
15443              "                              1: this, "
15444              "                              toString: function() { "
15445              "                                  return this[0];"
15446              "                              }"
15447              "                             };"
15448              "}"
15449              "var id = 'o';"
15450              "ownfunc");
15451   context->Global()->Set(v8_str("func"), foreign_function);
15452
15453   // Sanity check the contexts.
15454   CHECK(i->Equals(foreign_context->Global()->Get(id)));
15455   CHECK(o->Equals(context->Global()->Get(id)));
15456
15457   // Checking local function's receiver.
15458   // Calling function using its call/apply methods.
15459   TestReceiver(o, context->Global(), "ownfunc.call()");
15460   TestReceiver(o, context->Global(), "ownfunc.apply()");
15461   // Making calls through built-in functions.
15462   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
15463   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
15464   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
15465   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
15466   // Calling with environment record as base.
15467   TestReceiver(o, context->Global(), "ownfunc()");
15468   // Calling with no base.
15469   TestReceiver(o, context->Global(), "(1,ownfunc)()");
15470
15471   // Checking foreign function return value.
15472   // Calling function using its call/apply methods.
15473   TestReceiver(i, foreign_context->Global(), "func.call()");
15474   TestReceiver(i, foreign_context->Global(), "func.apply()");
15475   // Calling function using another context's call/apply methods.
15476   TestReceiver(i, foreign_context->Global(),
15477                "Function.prototype.call.call(func)");
15478   TestReceiver(i, foreign_context->Global(),
15479                "Function.prototype.call.apply(func)");
15480   TestReceiver(i, foreign_context->Global(),
15481                "Function.prototype.apply.call(func)");
15482   TestReceiver(i, foreign_context->Global(),
15483                "Function.prototype.apply.apply(func)");
15484   // Making calls through built-in functions.
15485   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
15486   // ToString(func()) is func()[0], i.e., the returned this.id.
15487   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
15488   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
15489   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
15490
15491   // TODO(1547): Make the following also return "i".
15492   // Calling with environment record as base.
15493   TestReceiver(o, context->Global(), "func()");
15494   // Calling with no base.
15495   TestReceiver(o, context->Global(), "(1,func)()");
15496
15497   foreign_context.Dispose();
15498 }