• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2007-2009 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 "compilation-cache.h"
34 #include "execution.h"
35 #include "snapshot.h"
36 #include "platform.h"
37 #include "top.h"
38 #include "utils.h"
39 #include "cctest.h"
40 
41 static const bool kLogThreading = true;
42 
IsNaN(double x)43 static bool IsNaN(double x) {
44 #ifdef WIN32
45   return _isnan(x);
46 #else
47   return isnan(x);
48 #endif
49 }
50 
51 using ::v8::ObjectTemplate;
52 using ::v8::Value;
53 using ::v8::Context;
54 using ::v8::Local;
55 using ::v8::String;
56 using ::v8::Script;
57 using ::v8::Function;
58 using ::v8::AccessorInfo;
59 using ::v8::Extension;
60 
61 namespace i = ::v8::internal;
62 
63 
ExpectString(const char * code,const char * expected)64 static void ExpectString(const char* code, const char* expected) {
65   Local<Value> result = CompileRun(code);
66   CHECK(result->IsString());
67   String::AsciiValue ascii(result);
68   CHECK_EQ(expected, *ascii);
69 }
70 
71 
ExpectBoolean(const char * code,bool expected)72 static void ExpectBoolean(const char* code, bool expected) {
73   Local<Value> result = CompileRun(code);
74   CHECK(result->IsBoolean());
75   CHECK_EQ(expected, result->BooleanValue());
76 }
77 
78 
ExpectObject(const char * code,Local<Value> expected)79 static void ExpectObject(const char* code, Local<Value> expected) {
80   Local<Value> result = CompileRun(code);
81   CHECK(result->Equals(expected));
82 }
83 
84 
85 static int signature_callback_count;
IncrementingSignatureCallback(const v8::Arguments & args)86 static v8::Handle<Value> IncrementingSignatureCallback(
87     const v8::Arguments& args) {
88   ApiTestFuzzer::Fuzz();
89   signature_callback_count++;
90   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
91   for (int i = 0; i < args.Length(); i++)
92     result->Set(v8::Integer::New(i), args[i]);
93   return result;
94 }
95 
96 
SignatureCallback(const v8::Arguments & args)97 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
98   ApiTestFuzzer::Fuzz();
99   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
100   for (int i = 0; i < args.Length(); i++) {
101     result->Set(v8::Integer::New(i), args[i]);
102   }
103   return result;
104 }
105 
106 
THREADED_TEST(Handles)107 THREADED_TEST(Handles) {
108   v8::HandleScope scope;
109   Local<Context> local_env;
110   {
111     LocalContext env;
112     local_env = env.local();
113   }
114 
115   // Local context should still be live.
116   CHECK(!local_env.IsEmpty());
117   local_env->Enter();
118 
119   v8::Handle<v8::Primitive> undef = v8::Undefined();
120   CHECK(!undef.IsEmpty());
121   CHECK(undef->IsUndefined());
122 
123   const char* c_source = "1 + 2 + 3";
124   Local<String> source = String::New(c_source);
125   Local<Script> script = Script::Compile(source);
126   CHECK_EQ(6, script->Run()->Int32Value());
127 
128   local_env->Exit();
129 }
130 
131 
THREADED_TEST(ReceiverSignature)132 THREADED_TEST(ReceiverSignature) {
133   v8::HandleScope scope;
134   LocalContext env;
135   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
136   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
137   fun->PrototypeTemplate()->Set(
138       v8_str("m"),
139       v8::FunctionTemplate::New(IncrementingSignatureCallback,
140                                 v8::Handle<Value>(),
141                                 sig));
142   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
143   signature_callback_count = 0;
144   CompileRun(
145       "var o = new Fun();"
146       "o.m();");
147   CHECK_EQ(1, signature_callback_count);
148   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
149   sub_fun->Inherit(fun);
150   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
151   CompileRun(
152       "var o = new SubFun();"
153       "o.m();");
154   CHECK_EQ(2, signature_callback_count);
155 
156   v8::TryCatch try_catch;
157   CompileRun(
158       "var o = { };"
159       "o.m = Fun.prototype.m;"
160       "o.m();");
161   CHECK_EQ(2, signature_callback_count);
162   CHECK(try_catch.HasCaught());
163   try_catch.Reset();
164   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
165   sub_fun->Inherit(fun);
166   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
167   CompileRun(
168       "var o = new UnrelFun();"
169       "o.m = Fun.prototype.m;"
170       "o.m();");
171   CHECK_EQ(2, signature_callback_count);
172   CHECK(try_catch.HasCaught());
173 }
174 
175 
176 
177 
THREADED_TEST(ArgumentSignature)178 THREADED_TEST(ArgumentSignature) {
179   v8::HandleScope scope;
180   LocalContext env;
181   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
182   cons->SetClassName(v8_str("Cons"));
183   v8::Handle<v8::Signature> sig =
184       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
185   v8::Handle<v8::FunctionTemplate> fun =
186       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
187   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
188   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
189 
190   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
191   CHECK(value1->IsTrue());
192 
193   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
194   CHECK(value2->IsTrue());
195 
196   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
197   CHECK(value3->IsTrue());
198 
199   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
200   cons1->SetClassName(v8_str("Cons1"));
201   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
202   cons2->SetClassName(v8_str("Cons2"));
203   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
204   cons3->SetClassName(v8_str("Cons3"));
205 
206   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
207   v8::Handle<v8::Signature> wsig =
208       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
209   v8::Handle<v8::FunctionTemplate> fun2 =
210       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
211 
212   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
213   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
214   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
215   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
216   v8::Handle<Value> value4 = CompileRun(
217       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
218       "'[object Cons1],[object Cons2],[object Cons3]'");
219   CHECK(value4->IsTrue());
220 
221   v8::Handle<Value> value5 = CompileRun(
222       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
223   CHECK(value5->IsTrue());
224 
225   v8::Handle<Value> value6 = CompileRun(
226       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
227   CHECK(value6->IsTrue());
228 
229   v8::Handle<Value> value7 = CompileRun(
230       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
231       "'[object Cons1],[object Cons2],[object Cons3],d';");
232   CHECK(value7->IsTrue());
233 
234   v8::Handle<Value> value8 = CompileRun(
235       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
236   CHECK(value8->IsTrue());
237 }
238 
239 
THREADED_TEST(HulIgennem)240 THREADED_TEST(HulIgennem) {
241   v8::HandleScope scope;
242   LocalContext env;
243   v8::Handle<v8::Primitive> undef = v8::Undefined();
244   Local<String> undef_str = undef->ToString();
245   char* value = i::NewArray<char>(undef_str->Length() + 1);
246   undef_str->WriteAscii(value);
247   CHECK_EQ(0, strcmp(value, "undefined"));
248   i::DeleteArray(value);
249 }
250 
251 
THREADED_TEST(Access)252 THREADED_TEST(Access) {
253   v8::HandleScope scope;
254   LocalContext env;
255   Local<v8::Object> obj = v8::Object::New();
256   Local<Value> foo_before = obj->Get(v8_str("foo"));
257   CHECK(foo_before->IsUndefined());
258   Local<String> bar_str = v8_str("bar");
259   obj->Set(v8_str("foo"), bar_str);
260   Local<Value> foo_after = obj->Get(v8_str("foo"));
261   CHECK(!foo_after->IsUndefined());
262   CHECK(foo_after->IsString());
263   CHECK_EQ(bar_str, foo_after);
264 }
265 
266 
THREADED_TEST(Script)267 THREADED_TEST(Script) {
268   v8::HandleScope scope;
269   LocalContext env;
270   const char* c_source = "1 + 2 + 3";
271   Local<String> source = String::New(c_source);
272   Local<Script> script = Script::Compile(source);
273   CHECK_EQ(6, script->Run()->Int32Value());
274 }
275 
276 
AsciiToTwoByteString(const char * source)277 static uint16_t* AsciiToTwoByteString(const char* source) {
278   int array_length = i::StrLength(source) + 1;
279   uint16_t* converted = i::NewArray<uint16_t>(array_length);
280   for (int i = 0; i < array_length; i++) converted[i] = source[i];
281   return converted;
282 }
283 
284 
285 class TestResource: public String::ExternalStringResource {
286  public:
287   static int dispose_count;
288 
TestResource(uint16_t * data)289   explicit TestResource(uint16_t* data)
290       : data_(data), length_(0) {
291     while (data[length_]) ++length_;
292   }
293 
~TestResource()294   ~TestResource() {
295     i::DeleteArray(data_);
296     ++dispose_count;
297   }
298 
data() const299   const uint16_t* data() const {
300     return data_;
301   }
302 
length() const303   size_t length() const {
304     return length_;
305   }
306  private:
307   uint16_t* data_;
308   size_t length_;
309 };
310 
311 
312 int TestResource::dispose_count = 0;
313 
314 
315 class TestAsciiResource: public String::ExternalAsciiStringResource {
316  public:
317   static int dispose_count;
318 
TestAsciiResource(const char * data)319   explicit TestAsciiResource(const char* data)
320       : data_(data),
321         length_(strlen(data)) { }
322 
~TestAsciiResource()323   ~TestAsciiResource() {
324     i::DeleteArray(data_);
325     ++dispose_count;
326   }
327 
data() const328   const char* data() const {
329     return data_;
330   }
331 
length() const332   size_t length() const {
333     return length_;
334   }
335  private:
336   const char* data_;
337   size_t length_;
338 };
339 
340 
341 int TestAsciiResource::dispose_count = 0;
342 
343 
THREADED_TEST(ScriptUsingStringResource)344 THREADED_TEST(ScriptUsingStringResource) {
345   TestResource::dispose_count = 0;
346   const char* c_source = "1 + 2 * 3";
347   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
348   {
349     v8::HandleScope scope;
350     LocalContext env;
351     TestResource* resource = new TestResource(two_byte_source);
352     Local<String> source = String::NewExternal(resource);
353     Local<Script> script = Script::Compile(source);
354     Local<Value> value = script->Run();
355     CHECK(value->IsNumber());
356     CHECK_EQ(7, value->Int32Value());
357     CHECK(source->IsExternal());
358     CHECK_EQ(resource,
359              static_cast<TestResource*>(source->GetExternalStringResource()));
360     v8::internal::Heap::CollectAllGarbage(false);
361     CHECK_EQ(0, TestResource::dispose_count);
362   }
363   v8::internal::CompilationCache::Clear();
364   v8::internal::Heap::CollectAllGarbage(false);
365   CHECK_EQ(1, TestResource::dispose_count);
366 }
367 
368 
THREADED_TEST(ScriptUsingAsciiStringResource)369 THREADED_TEST(ScriptUsingAsciiStringResource) {
370   TestAsciiResource::dispose_count = 0;
371   const char* c_source = "1 + 2 * 3";
372   {
373     v8::HandleScope scope;
374     LocalContext env;
375     Local<String> source =
376         String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
377     Local<Script> script = Script::Compile(source);
378     Local<Value> value = script->Run();
379     CHECK(value->IsNumber());
380     CHECK_EQ(7, value->Int32Value());
381     v8::internal::Heap::CollectAllGarbage(false);
382     CHECK_EQ(0, TestAsciiResource::dispose_count);
383   }
384   v8::internal::CompilationCache::Clear();
385   v8::internal::Heap::CollectAllGarbage(false);
386   CHECK_EQ(1, TestAsciiResource::dispose_count);
387 }
388 
389 
THREADED_TEST(ScriptMakingExternalString)390 THREADED_TEST(ScriptMakingExternalString) {
391   TestResource::dispose_count = 0;
392   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
393   {
394     v8::HandleScope scope;
395     LocalContext env;
396     Local<String> source = String::New(two_byte_source);
397     // Trigger GCs so that the newly allocated string moves to old gen.
398     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
399     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
400     bool success = source->MakeExternal(new TestResource(two_byte_source));
401     CHECK(success);
402     Local<Script> script = Script::Compile(source);
403     Local<Value> value = script->Run();
404     CHECK(value->IsNumber());
405     CHECK_EQ(7, value->Int32Value());
406     v8::internal::Heap::CollectAllGarbage(false);
407     CHECK_EQ(0, TestResource::dispose_count);
408   }
409   v8::internal::CompilationCache::Clear();
410   v8::internal::Heap::CollectAllGarbage(false);
411   CHECK_EQ(1, TestResource::dispose_count);
412 }
413 
414 
THREADED_TEST(ScriptMakingExternalAsciiString)415 THREADED_TEST(ScriptMakingExternalAsciiString) {
416   TestAsciiResource::dispose_count = 0;
417   const char* c_source = "1 + 2 * 3";
418   {
419     v8::HandleScope scope;
420     LocalContext env;
421     Local<String> source = v8_str(c_source);
422     // Trigger GCs so that the newly allocated string moves to old gen.
423     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
424     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
425     bool success = source->MakeExternal(
426         new TestAsciiResource(i::StrDup(c_source)));
427     CHECK(success);
428     Local<Script> script = Script::Compile(source);
429     Local<Value> value = script->Run();
430     CHECK(value->IsNumber());
431     CHECK_EQ(7, value->Int32Value());
432     v8::internal::Heap::CollectAllGarbage(false);
433     CHECK_EQ(0, TestAsciiResource::dispose_count);
434   }
435   v8::internal::CompilationCache::Clear();
436   v8::internal::Heap::CollectAllGarbage(false);
437   CHECK_EQ(1, TestAsciiResource::dispose_count);
438 }
439 
440 
TEST(MakingExternalStringConditions)441 TEST(MakingExternalStringConditions) {
442   v8::HandleScope scope;
443   LocalContext env;
444 
445   // Free some space in the new space so that we can check freshness.
446   i::Heap::CollectGarbage(0, i::NEW_SPACE);
447   i::Heap::CollectGarbage(0, i::NEW_SPACE);
448 
449   Local<String> small_string = String::New(AsciiToTwoByteString("small"));
450   // We should refuse to externalize newly created small string.
451   CHECK(!small_string->CanMakeExternal());
452   // Trigger GCs so that the newly allocated string moves to old gen.
453   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
454   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
455   // Old space strings should be accepted.
456   CHECK(small_string->CanMakeExternal());
457 
458   small_string = String::New(AsciiToTwoByteString("small 2"));
459   // We should refuse externalizing newly created small string.
460   CHECK(!small_string->CanMakeExternal());
461   for (int i = 0; i < 100; i++) {
462     String::Value value(small_string);
463   }
464   // Frequently used strings should be accepted.
465   CHECK(small_string->CanMakeExternal());
466 
467   const int buf_size = 10 * 1024;
468   char* buf = i::NewArray<char>(buf_size);
469   memset(buf, 'a', buf_size);
470   buf[buf_size - 1] = '\0';
471   Local<String> large_string = String::New(AsciiToTwoByteString(buf));
472   i::DeleteArray(buf);
473   // Large strings should be immediately accepted.
474   CHECK(large_string->CanMakeExternal());
475 }
476 
477 
TEST(MakingExternalAsciiStringConditions)478 TEST(MakingExternalAsciiStringConditions) {
479   v8::HandleScope scope;
480   LocalContext env;
481 
482   // Free some space in the new space so that we can check freshness.
483   i::Heap::CollectGarbage(0, i::NEW_SPACE);
484   i::Heap::CollectGarbage(0, i::NEW_SPACE);
485 
486   Local<String> small_string = String::New("small");
487   // We should refuse to externalize newly created small string.
488   CHECK(!small_string->CanMakeExternal());
489   // Trigger GCs so that the newly allocated string moves to old gen.
490   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
491   i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
492   // Old space strings should be accepted.
493   CHECK(small_string->CanMakeExternal());
494 
495   small_string = String::New("small 2");
496   // We should refuse externalizing newly created small string.
497   CHECK(!small_string->CanMakeExternal());
498   for (int i = 0; i < 100; i++) {
499     String::Value value(small_string);
500   }
501   // Frequently used strings should be accepted.
502   CHECK(small_string->CanMakeExternal());
503 
504   const int buf_size = 10 * 1024;
505   char* buf = i::NewArray<char>(buf_size);
506   memset(buf, 'a', buf_size);
507   buf[buf_size - 1] = '\0';
508   Local<String> large_string = String::New(buf);
509   i::DeleteArray(buf);
510   // Large strings should be immediately accepted.
511   CHECK(large_string->CanMakeExternal());
512 }
513 
514 
THREADED_TEST(UsingExternalString)515 THREADED_TEST(UsingExternalString) {
516   {
517     v8::HandleScope scope;
518     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
519     Local<String> string =
520         String::NewExternal(new TestResource(two_byte_string));
521     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
522     // Trigger GCs so that the newly allocated string moves to old gen.
523     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
524     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
525     i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
526     CHECK(isymbol->IsSymbol());
527   }
528   i::Heap::CollectAllGarbage(false);
529   i::Heap::CollectAllGarbage(false);
530 }
531 
532 
THREADED_TEST(UsingExternalAsciiString)533 THREADED_TEST(UsingExternalAsciiString) {
534   {
535     v8::HandleScope scope;
536     const char* one_byte_string = "test string";
537     Local<String> string = String::NewExternal(
538         new TestAsciiResource(i::StrDup(one_byte_string)));
539     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
540     // Trigger GCs so that the newly allocated string moves to old gen.
541     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
542     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
543     i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
544     CHECK(isymbol->IsSymbol());
545   }
546   i::Heap::CollectAllGarbage(false);
547   i::Heap::CollectAllGarbage(false);
548 }
549 
550 
THREADED_TEST(ScavengeExternalString)551 THREADED_TEST(ScavengeExternalString) {
552   TestResource::dispose_count = 0;
553   {
554     v8::HandleScope scope;
555     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
556     Local<String> string =
557         String::NewExternal(new TestResource(two_byte_string));
558     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
559     i::Heap::CollectGarbage(0, i::NEW_SPACE);
560     CHECK(i::Heap::InNewSpace(*istring));
561     CHECK_EQ(0, TestResource::dispose_count);
562   }
563   i::Heap::CollectGarbage(0, i::NEW_SPACE);
564   CHECK_EQ(1, TestResource::dispose_count);
565 }
566 
567 
THREADED_TEST(ScavengeExternalAsciiString)568 THREADED_TEST(ScavengeExternalAsciiString) {
569   TestAsciiResource::dispose_count = 0;
570   {
571     v8::HandleScope scope;
572     const char* one_byte_string = "test string";
573     Local<String> string = String::NewExternal(
574         new TestAsciiResource(i::StrDup(one_byte_string)));
575     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
576     i::Heap::CollectGarbage(0, i::NEW_SPACE);
577     CHECK(i::Heap::InNewSpace(*istring));
578     CHECK_EQ(0, TestAsciiResource::dispose_count);
579   }
580   i::Heap::CollectGarbage(0, i::NEW_SPACE);
581   CHECK_EQ(1, TestAsciiResource::dispose_count);
582 }
583 
584 
THREADED_TEST(StringConcat)585 THREADED_TEST(StringConcat) {
586   {
587     v8::HandleScope scope;
588     LocalContext env;
589     const char* one_byte_string_1 = "function a_times_t";
590     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
591     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
592     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
593     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
594     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
595     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
596     Local<String> left = v8_str(one_byte_string_1);
597     Local<String> right = String::New(AsciiToTwoByteString(two_byte_string_1));
598     Local<String> source = String::Concat(left, right);
599     right = String::NewExternal(
600         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
601     source = String::Concat(source, right);
602     right = String::NewExternal(
603         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
604     source = String::Concat(source, right);
605     right = v8_str(one_byte_string_2);
606     source = String::Concat(source, right);
607     right = String::New(AsciiToTwoByteString(two_byte_string_2));
608     source = String::Concat(source, right);
609     right = String::NewExternal(
610         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
611     source = String::Concat(source, right);
612     Local<Script> script = Script::Compile(source);
613     Local<Value> value = script->Run();
614     CHECK(value->IsNumber());
615     CHECK_EQ(68, value->Int32Value());
616   }
617   v8::internal::CompilationCache::Clear();
618   i::Heap::CollectAllGarbage(false);
619   i::Heap::CollectAllGarbage(false);
620 }
621 
622 
THREADED_TEST(GlobalProperties)623 THREADED_TEST(GlobalProperties) {
624   v8::HandleScope scope;
625   LocalContext env;
626   v8::Handle<v8::Object> global = env->Global();
627   global->Set(v8_str("pi"), v8_num(3.1415926));
628   Local<Value> pi = global->Get(v8_str("pi"));
629   CHECK_EQ(3.1415926, pi->NumberValue());
630 }
631 
632 
handle_call(const v8::Arguments & args)633 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
634   ApiTestFuzzer::Fuzz();
635   return v8_num(102);
636 }
637 
638 
construct_call(const v8::Arguments & args)639 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
640   ApiTestFuzzer::Fuzz();
641   args.This()->Set(v8_str("x"), v8_num(1));
642   args.This()->Set(v8_str("y"), v8_num(2));
643   return args.This();
644 }
645 
THREADED_TEST(FunctionTemplate)646 THREADED_TEST(FunctionTemplate) {
647   v8::HandleScope scope;
648   LocalContext env;
649   {
650     Local<v8::FunctionTemplate> fun_templ =
651         v8::FunctionTemplate::New(handle_call);
652     Local<Function> fun = fun_templ->GetFunction();
653     env->Global()->Set(v8_str("obj"), fun);
654     Local<Script> script = v8_compile("obj()");
655     CHECK_EQ(102, script->Run()->Int32Value());
656   }
657   // Use SetCallHandler to initialize a function template, should work like the
658   // previous one.
659   {
660     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
661     fun_templ->SetCallHandler(handle_call);
662     Local<Function> fun = fun_templ->GetFunction();
663     env->Global()->Set(v8_str("obj"), fun);
664     Local<Script> script = v8_compile("obj()");
665     CHECK_EQ(102, script->Run()->Int32Value());
666   }
667   // Test constructor calls.
668   {
669     Local<v8::FunctionTemplate> fun_templ =
670         v8::FunctionTemplate::New(construct_call);
671     fun_templ->SetClassName(v8_str("funky"));
672     Local<Function> fun = fun_templ->GetFunction();
673     env->Global()->Set(v8_str("obj"), fun);
674     Local<Script> script = v8_compile("var s = new obj(); s.x");
675     CHECK_EQ(1, script->Run()->Int32Value());
676 
677     Local<Value> result = v8_compile("(new obj()).toString()")->Run();
678     CHECK_EQ(v8_str("[object funky]"), result);
679   }
680 }
681 
682 
THREADED_TEST(FindInstanceInPrototypeChain)683 THREADED_TEST(FindInstanceInPrototypeChain) {
684   v8::HandleScope scope;
685   LocalContext env;
686 
687   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
688   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
689   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
690   derived->Inherit(base);
691 
692   Local<v8::Function> base_function = base->GetFunction();
693   Local<v8::Function> derived_function = derived->GetFunction();
694   Local<v8::Function> other_function = other->GetFunction();
695 
696   Local<v8::Object> base_instance = base_function->NewInstance();
697   Local<v8::Object> derived_instance = derived_function->NewInstance();
698   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
699   Local<v8::Object> other_instance = other_function->NewInstance();
700   derived_instance2->Set(v8_str("__proto__"), derived_instance);
701   other_instance->Set(v8_str("__proto__"), derived_instance2);
702 
703   // base_instance is only an instance of base.
704   CHECK_EQ(base_instance,
705            base_instance->FindInstanceInPrototypeChain(base));
706   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
707   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
708 
709   // derived_instance is an instance of base and derived.
710   CHECK_EQ(derived_instance,
711            derived_instance->FindInstanceInPrototypeChain(base));
712   CHECK_EQ(derived_instance,
713            derived_instance->FindInstanceInPrototypeChain(derived));
714   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
715 
716   // other_instance is an instance of other and its immediate
717   // prototype derived_instance2 is an instance of base and derived.
718   // Note, derived_instance is an instance of base and derived too,
719   // but it comes after derived_instance2 in the prototype chain of
720   // other_instance.
721   CHECK_EQ(derived_instance2,
722            other_instance->FindInstanceInPrototypeChain(base));
723   CHECK_EQ(derived_instance2,
724            other_instance->FindInstanceInPrototypeChain(derived));
725   CHECK_EQ(other_instance,
726            other_instance->FindInstanceInPrototypeChain(other));
727 }
728 
729 
THREADED_TEST(TinyInteger)730 THREADED_TEST(TinyInteger) {
731   v8::HandleScope scope;
732   LocalContext env;
733   int32_t value = 239;
734   Local<v8::Integer> value_obj = v8::Integer::New(value);
735   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
736 }
737 
738 
THREADED_TEST(BigSmiInteger)739 THREADED_TEST(BigSmiInteger) {
740   v8::HandleScope scope;
741   LocalContext env;
742   int32_t value = i::Smi::kMaxValue;
743   // We cannot add one to a Smi::kMaxValue without wrapping.
744   if (i::kSmiValueSize < 32) {
745     CHECK(i::Smi::IsValid(value));
746     CHECK(!i::Smi::IsValid(value + 1));
747     Local<v8::Integer> value_obj = v8::Integer::New(value);
748     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
749   }
750 }
751 
752 
THREADED_TEST(BigInteger)753 THREADED_TEST(BigInteger) {
754   v8::HandleScope scope;
755   LocalContext env;
756   // We cannot add one to a Smi::kMaxValue without wrapping.
757   if (i::kSmiValueSize < 32) {
758     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
759     // The code will not be run in that case, due to the "if" guard.
760     int32_t value =
761         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
762     CHECK(value > i::Smi::kMaxValue);
763     CHECK(!i::Smi::IsValid(value));
764     Local<v8::Integer> value_obj = v8::Integer::New(value);
765     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
766   }
767 }
768 
769 
THREADED_TEST(TinyUnsignedInteger)770 THREADED_TEST(TinyUnsignedInteger) {
771   v8::HandleScope scope;
772   LocalContext env;
773   uint32_t value = 239;
774   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
775   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
776 }
777 
778 
THREADED_TEST(BigUnsignedSmiInteger)779 THREADED_TEST(BigUnsignedSmiInteger) {
780   v8::HandleScope scope;
781   LocalContext env;
782   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
783   CHECK(i::Smi::IsValid(value));
784   CHECK(!i::Smi::IsValid(value + 1));
785   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
786   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
787 }
788 
789 
THREADED_TEST(BigUnsignedInteger)790 THREADED_TEST(BigUnsignedInteger) {
791   v8::HandleScope scope;
792   LocalContext env;
793   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
794   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
795   CHECK(!i::Smi::IsValid(value));
796   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
797   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
798 }
799 
800 
THREADED_TEST(OutOfSignedRangeUnsignedInteger)801 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
802   v8::HandleScope scope;
803   LocalContext env;
804   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
805   uint32_t value = INT32_MAX_AS_UINT + 1;
806   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
807   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
808   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
809 }
810 
811 
THREADED_TEST(Number)812 THREADED_TEST(Number) {
813   v8::HandleScope scope;
814   LocalContext env;
815   double PI = 3.1415926;
816   Local<v8::Number> pi_obj = v8::Number::New(PI);
817   CHECK_EQ(PI, pi_obj->NumberValue());
818 }
819 
820 
THREADED_TEST(ToNumber)821 THREADED_TEST(ToNumber) {
822   v8::HandleScope scope;
823   LocalContext env;
824   Local<String> str = v8_str("3.1415926");
825   CHECK_EQ(3.1415926, str->NumberValue());
826   v8::Handle<v8::Boolean> t = v8::True();
827   CHECK_EQ(1.0, t->NumberValue());
828   v8::Handle<v8::Boolean> f = v8::False();
829   CHECK_EQ(0.0, f->NumberValue());
830 }
831 
832 
THREADED_TEST(Date)833 THREADED_TEST(Date) {
834   v8::HandleScope scope;
835   LocalContext env;
836   double PI = 3.1415926;
837   Local<Value> date_obj = v8::Date::New(PI);
838   CHECK_EQ(3.0, date_obj->NumberValue());
839 }
840 
841 
THREADED_TEST(Boolean)842 THREADED_TEST(Boolean) {
843   v8::HandleScope scope;
844   LocalContext env;
845   v8::Handle<v8::Boolean> t = v8::True();
846   CHECK(t->Value());
847   v8::Handle<v8::Boolean> f = v8::False();
848   CHECK(!f->Value());
849   v8::Handle<v8::Primitive> u = v8::Undefined();
850   CHECK(!u->BooleanValue());
851   v8::Handle<v8::Primitive> n = v8::Null();
852   CHECK(!n->BooleanValue());
853   v8::Handle<String> str1 = v8_str("");
854   CHECK(!str1->BooleanValue());
855   v8::Handle<String> str2 = v8_str("x");
856   CHECK(str2->BooleanValue());
857   CHECK(!v8::Number::New(0)->BooleanValue());
858   CHECK(v8::Number::New(-1)->BooleanValue());
859   CHECK(v8::Number::New(1)->BooleanValue());
860   CHECK(v8::Number::New(42)->BooleanValue());
861   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
862 }
863 
864 
DummyCallHandler(const v8::Arguments & args)865 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
866   ApiTestFuzzer::Fuzz();
867   return v8_num(13.4);
868 }
869 
870 
GetM(Local<String> name,const AccessorInfo &)871 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
872   ApiTestFuzzer::Fuzz();
873   return v8_num(876);
874 }
875 
876 
THREADED_TEST(GlobalPrototype)877 THREADED_TEST(GlobalPrototype) {
878   v8::HandleScope scope;
879   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
880   func_templ->PrototypeTemplate()->Set(
881       "dummy",
882       v8::FunctionTemplate::New(DummyCallHandler));
883   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
884   templ->Set("x", v8_num(200));
885   templ->SetAccessor(v8_str("m"), GetM);
886   LocalContext env(0, templ);
887   v8::Handle<v8::Object> obj = env->Global();
888   v8::Handle<Script> script = v8_compile("dummy()");
889   v8::Handle<Value> result = script->Run();
890   CHECK_EQ(13.4, result->NumberValue());
891   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
892   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
893 }
894 
895 
THREADED_TEST(ObjectTemplate)896 THREADED_TEST(ObjectTemplate) {
897   v8::HandleScope scope;
898   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
899   templ1->Set("x", v8_num(10));
900   templ1->Set("y", v8_num(13));
901   LocalContext env;
902   Local<v8::Object> instance1 = templ1->NewInstance();
903   env->Global()->Set(v8_str("p"), instance1);
904   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
905   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
906   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
907   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
908   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
909   templ2->Set("a", v8_num(12));
910   templ2->Set("b", templ1);
911   Local<v8::Object> instance2 = templ2->NewInstance();
912   env->Global()->Set(v8_str("q"), instance2);
913   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
914   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
915   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
916   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
917 }
918 
919 
GetFlabby(const v8::Arguments & args)920 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
921   ApiTestFuzzer::Fuzz();
922   return v8_num(17.2);
923 }
924 
925 
GetKnurd(Local<String> property,const AccessorInfo &)926 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
927   ApiTestFuzzer::Fuzz();
928   return v8_num(15.2);
929 }
930 
931 
THREADED_TEST(DescriptorInheritance)932 THREADED_TEST(DescriptorInheritance) {
933   v8::HandleScope scope;
934   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
935   super->PrototypeTemplate()->Set("flabby",
936                                   v8::FunctionTemplate::New(GetFlabby));
937   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
938 
939   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
940 
941   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
942   base1->Inherit(super);
943   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
944 
945   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
946   base2->Inherit(super);
947   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
948 
949   LocalContext env;
950 
951   env->Global()->Set(v8_str("s"), super->GetFunction());
952   env->Global()->Set(v8_str("base1"), base1->GetFunction());
953   env->Global()->Set(v8_str("base2"), base2->GetFunction());
954 
955   // Checks right __proto__ chain.
956   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
957   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
958 
959   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
960 
961   // Instance accessor should not be visible on function object or its prototype
962   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
963   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
964   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
965 
966   env->Global()->Set(v8_str("obj"),
967                      base1->GetFunction()->NewInstance());
968   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
969   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
970   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
971   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
972   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
973 
974   env->Global()->Set(v8_str("obj2"),
975                      base2->GetFunction()->NewInstance());
976   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
977   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
978   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
979   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
980   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
981 
982   // base1 and base2 cannot cross reference to each's prototype
983   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
984   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
985 }
986 
987 
988 int echo_named_call_count;
989 
990 
EchoNamedProperty(Local<String> name,const AccessorInfo & info)991 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
992                                            const AccessorInfo& info) {
993   ApiTestFuzzer::Fuzz();
994   CHECK_EQ(v8_str("data"), info.Data());
995   echo_named_call_count++;
996   return name;
997 }
998 
999 
THREADED_TEST(NamedPropertyHandlerGetter)1000 THREADED_TEST(NamedPropertyHandlerGetter) {
1001   echo_named_call_count = 0;
1002   v8::HandleScope scope;
1003   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1004   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
1005                                                      0, 0, 0, 0,
1006                                                      v8_str("data"));
1007   LocalContext env;
1008   env->Global()->Set(v8_str("obj"),
1009                      templ->GetFunction()->NewInstance());
1010   CHECK_EQ(echo_named_call_count, 0);
1011   v8_compile("obj.x")->Run();
1012   CHECK_EQ(echo_named_call_count, 1);
1013   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
1014   v8::Handle<Value> str = CompileRun(code);
1015   String::AsciiValue value(str);
1016   CHECK_EQ(*value, "oddlepoddle");
1017   // Check default behavior
1018   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
1019   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
1020   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
1021 }
1022 
1023 
1024 int echo_indexed_call_count = 0;
1025 
1026 
EchoIndexedProperty(uint32_t index,const AccessorInfo & info)1027 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
1028                                              const AccessorInfo& info) {
1029   ApiTestFuzzer::Fuzz();
1030   CHECK_EQ(v8_num(637), info.Data());
1031   echo_indexed_call_count++;
1032   return v8_num(index);
1033 }
1034 
1035 
THREADED_TEST(IndexedPropertyHandlerGetter)1036 THREADED_TEST(IndexedPropertyHandlerGetter) {
1037   v8::HandleScope scope;
1038   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1039   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
1040                                                        0, 0, 0, 0,
1041                                                        v8_num(637));
1042   LocalContext env;
1043   env->Global()->Set(v8_str("obj"),
1044                      templ->GetFunction()->NewInstance());
1045   Local<Script> script = v8_compile("obj[900]");
1046   CHECK_EQ(script->Run()->Int32Value(), 900);
1047 }
1048 
1049 
1050 v8::Handle<v8::Object> bottom;
1051 
CheckThisIndexedPropertyHandler(uint32_t index,const AccessorInfo & info)1052 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
1053     uint32_t index,
1054     const AccessorInfo& info) {
1055   ApiTestFuzzer::Fuzz();
1056   CHECK(info.This()->Equals(bottom));
1057   return v8::Handle<Value>();
1058 }
1059 
CheckThisNamedPropertyHandler(Local<String> name,const AccessorInfo & info)1060 static v8::Handle<Value> CheckThisNamedPropertyHandler(
1061     Local<String> name,
1062     const AccessorInfo& info) {
1063   ApiTestFuzzer::Fuzz();
1064   CHECK(info.This()->Equals(bottom));
1065   return v8::Handle<Value>();
1066 }
1067 
1068 
CheckThisIndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)1069 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1070                                                  Local<Value> value,
1071                                                  const AccessorInfo& info) {
1072   ApiTestFuzzer::Fuzz();
1073   CHECK(info.This()->Equals(bottom));
1074   return v8::Handle<Value>();
1075 }
1076 
1077 
CheckThisNamedPropertySetter(Local<String> property,Local<Value> value,const AccessorInfo & info)1078 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1079                                                Local<Value> value,
1080                                                const AccessorInfo& info) {
1081   ApiTestFuzzer::Fuzz();
1082   CHECK(info.This()->Equals(bottom));
1083   return v8::Handle<Value>();
1084 }
1085 
CheckThisIndexedPropertyQuery(uint32_t index,const AccessorInfo & info)1086 v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1087     uint32_t index,
1088     const AccessorInfo& info) {
1089   ApiTestFuzzer::Fuzz();
1090   CHECK(info.This()->Equals(bottom));
1091   return v8::Handle<v8::Boolean>();
1092 }
1093 
1094 
CheckThisNamedPropertyQuery(Local<String> property,const AccessorInfo & info)1095 v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1096                                                     const AccessorInfo& info) {
1097   ApiTestFuzzer::Fuzz();
1098   CHECK(info.This()->Equals(bottom));
1099   return v8::Handle<v8::Boolean>();
1100 }
1101 
1102 
CheckThisIndexedPropertyDeleter(uint32_t index,const AccessorInfo & info)1103 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1104     uint32_t index,
1105     const AccessorInfo& info) {
1106   ApiTestFuzzer::Fuzz();
1107   CHECK(info.This()->Equals(bottom));
1108   return v8::Handle<v8::Boolean>();
1109 }
1110 
1111 
CheckThisNamedPropertyDeleter(Local<String> property,const AccessorInfo & info)1112 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1113     Local<String> property,
1114     const AccessorInfo& info) {
1115   ApiTestFuzzer::Fuzz();
1116   CHECK(info.This()->Equals(bottom));
1117   return v8::Handle<v8::Boolean>();
1118 }
1119 
1120 
CheckThisIndexedPropertyEnumerator(const AccessorInfo & info)1121 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1122     const AccessorInfo& info) {
1123   ApiTestFuzzer::Fuzz();
1124   CHECK(info.This()->Equals(bottom));
1125   return v8::Handle<v8::Array>();
1126 }
1127 
1128 
CheckThisNamedPropertyEnumerator(const AccessorInfo & info)1129 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1130     const AccessorInfo& info) {
1131   ApiTestFuzzer::Fuzz();
1132   CHECK(info.This()->Equals(bottom));
1133   return v8::Handle<v8::Array>();
1134 }
1135 
1136 
THREADED_TEST(PropertyHandlerInPrototype)1137 THREADED_TEST(PropertyHandlerInPrototype) {
1138   v8::HandleScope scope;
1139   LocalContext env;
1140 
1141   // Set up a prototype chain with three interceptors.
1142   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1143   templ->InstanceTemplate()->SetIndexedPropertyHandler(
1144       CheckThisIndexedPropertyHandler,
1145       CheckThisIndexedPropertySetter,
1146       CheckThisIndexedPropertyQuery,
1147       CheckThisIndexedPropertyDeleter,
1148       CheckThisIndexedPropertyEnumerator);
1149 
1150   templ->InstanceTemplate()->SetNamedPropertyHandler(
1151       CheckThisNamedPropertyHandler,
1152       CheckThisNamedPropertySetter,
1153       CheckThisNamedPropertyQuery,
1154       CheckThisNamedPropertyDeleter,
1155       CheckThisNamedPropertyEnumerator);
1156 
1157   bottom = templ->GetFunction()->NewInstance();
1158   Local<v8::Object> top = templ->GetFunction()->NewInstance();
1159   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1160 
1161   bottom->Set(v8_str("__proto__"), middle);
1162   middle->Set(v8_str("__proto__"), top);
1163   env->Global()->Set(v8_str("obj"), bottom);
1164 
1165   // Indexed and named get.
1166   Script::Compile(v8_str("obj[0]"))->Run();
1167   Script::Compile(v8_str("obj.x"))->Run();
1168 
1169   // Indexed and named set.
1170   Script::Compile(v8_str("obj[1] = 42"))->Run();
1171   Script::Compile(v8_str("obj.y = 42"))->Run();
1172 
1173   // Indexed and named query.
1174   Script::Compile(v8_str("0 in obj"))->Run();
1175   Script::Compile(v8_str("'x' in obj"))->Run();
1176 
1177   // Indexed and named deleter.
1178   Script::Compile(v8_str("delete obj[0]"))->Run();
1179   Script::Compile(v8_str("delete obj.x"))->Run();
1180 
1181   // Enumerators.
1182   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1183 }
1184 
1185 
PrePropertyHandlerGet(Local<String> key,const AccessorInfo & info)1186 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1187                                                const AccessorInfo& info) {
1188   ApiTestFuzzer::Fuzz();
1189   if (v8_str("pre")->Equals(key)) {
1190     return v8_str("PrePropertyHandler: pre");
1191   }
1192   return v8::Handle<String>();
1193 }
1194 
1195 
PrePropertyHandlerHas(Local<String> key,const AccessorInfo &)1196 static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1197                                                      const AccessorInfo&) {
1198   if (v8_str("pre")->Equals(key)) {
1199     return v8::True();
1200   }
1201 
1202   return v8::Handle<v8::Boolean>();  // do not intercept the call
1203 }
1204 
1205 
THREADED_TEST(PrePropertyHandler)1206 THREADED_TEST(PrePropertyHandler) {
1207   v8::HandleScope scope;
1208   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1209   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1210                                                     0,
1211                                                     PrePropertyHandlerHas);
1212   LocalContext env(NULL, desc->InstanceTemplate());
1213   Script::Compile(v8_str(
1214       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1215   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1216   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1217   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1218   CHECK_EQ(v8_str("Object: on"), result_on);
1219   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1220   CHECK(result_post.IsEmpty());
1221 }
1222 
1223 
THREADED_TEST(UndefinedIsNotEnumerable)1224 THREADED_TEST(UndefinedIsNotEnumerable) {
1225   v8::HandleScope scope;
1226   LocalContext env;
1227   v8::Handle<Value> result = Script::Compile(v8_str(
1228       "this.propertyIsEnumerable(undefined)"))->Run();
1229   CHECK(result->IsFalse());
1230 }
1231 
1232 
1233 v8::Handle<Script> call_recursively_script;
1234 static const int kTargetRecursionDepth = 200;  // near maximum
1235 
1236 
CallScriptRecursivelyCall(const v8::Arguments & args)1237 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1238   ApiTestFuzzer::Fuzz();
1239   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1240   if (depth == kTargetRecursionDepth) return v8::Undefined();
1241   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1242   return call_recursively_script->Run();
1243 }
1244 
1245 
CallFunctionRecursivelyCall(const v8::Arguments & args)1246 static v8::Handle<Value> CallFunctionRecursivelyCall(
1247     const v8::Arguments& args) {
1248   ApiTestFuzzer::Fuzz();
1249   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1250   if (depth == kTargetRecursionDepth) {
1251     printf("[depth = %d]\n", depth);
1252     return v8::Undefined();
1253   }
1254   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1255   v8::Handle<Value> function =
1256       args.This()->Get(v8_str("callFunctionRecursively"));
1257   return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
1258 }
1259 
1260 
THREADED_TEST(DeepCrossLanguageRecursion)1261 THREADED_TEST(DeepCrossLanguageRecursion) {
1262   v8::HandleScope scope;
1263   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1264   global->Set(v8_str("callScriptRecursively"),
1265               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1266   global->Set(v8_str("callFunctionRecursively"),
1267               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1268   LocalContext env(NULL, global);
1269 
1270   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1271   call_recursively_script = v8_compile("callScriptRecursively()");
1272   v8::Handle<Value> result = call_recursively_script->Run();
1273   call_recursively_script = v8::Handle<Script>();
1274 
1275   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1276   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1277 }
1278 
1279 
1280 static v8::Handle<Value>
ThrowingPropertyHandlerGet(Local<String> key,const AccessorInfo &)1281     ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1282   ApiTestFuzzer::Fuzz();
1283   return v8::ThrowException(key);
1284 }
1285 
1286 
ThrowingPropertyHandlerSet(Local<String> key,Local<Value>,const AccessorInfo &)1287 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1288                                                     Local<Value>,
1289                                                     const AccessorInfo&) {
1290   v8::ThrowException(key);
1291   return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1292 }
1293 
1294 
THREADED_TEST(CallbackExceptionRegression)1295 THREADED_TEST(CallbackExceptionRegression) {
1296   v8::HandleScope scope;
1297   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1298   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1299                                ThrowingPropertyHandlerSet);
1300   LocalContext env;
1301   env->Global()->Set(v8_str("obj"), obj->NewInstance());
1302   v8::Handle<Value> otto = Script::Compile(v8_str(
1303       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1304   CHECK_EQ(v8_str("otto"), otto);
1305   v8::Handle<Value> netto = Script::Compile(v8_str(
1306       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1307   CHECK_EQ(v8_str("netto"), netto);
1308 }
1309 
1310 
THREADED_TEST(FunctionPrototype)1311 THREADED_TEST(FunctionPrototype) {
1312   v8::HandleScope scope;
1313   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1314   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1315   LocalContext env;
1316   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1317   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1318   CHECK_EQ(script->Run()->Int32Value(), 321);
1319 }
1320 
1321 
THREADED_TEST(InternalFields)1322 THREADED_TEST(InternalFields) {
1323   v8::HandleScope scope;
1324   LocalContext env;
1325 
1326   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1327   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1328   instance_templ->SetInternalFieldCount(1);
1329   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1330   CHECK_EQ(1, obj->InternalFieldCount());
1331   CHECK(obj->GetInternalField(0)->IsUndefined());
1332   obj->SetInternalField(0, v8_num(17));
1333   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1334 }
1335 
1336 
THREADED_TEST(InternalFieldsNativePointers)1337 THREADED_TEST(InternalFieldsNativePointers) {
1338   v8::HandleScope scope;
1339   LocalContext env;
1340 
1341   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1342   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1343   instance_templ->SetInternalFieldCount(1);
1344   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1345   CHECK_EQ(1, obj->InternalFieldCount());
1346   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1347 
1348   char* data = new char[100];
1349 
1350   void* aligned = data;
1351   CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1352   void* unaligned = data + 1;
1353   CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1354 
1355   // Check reading and writing aligned pointers.
1356   obj->SetPointerInInternalField(0, aligned);
1357   i::Heap::CollectAllGarbage(false);
1358   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1359 
1360   // Check reading and writing unaligned pointers.
1361   obj->SetPointerInInternalField(0, unaligned);
1362   i::Heap::CollectAllGarbage(false);
1363   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1364 
1365   delete[] data;
1366 }
1367 
1368 
THREADED_TEST(InternalFieldsNativePointersAndExternal)1369 THREADED_TEST(InternalFieldsNativePointersAndExternal) {
1370   v8::HandleScope scope;
1371   LocalContext env;
1372 
1373   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1374   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1375   instance_templ->SetInternalFieldCount(1);
1376   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1377   CHECK_EQ(1, obj->InternalFieldCount());
1378   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1379 
1380   char* data = new char[100];
1381 
1382   void* aligned = data;
1383   CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1384   void* unaligned = data + 1;
1385   CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1386 
1387   obj->SetPointerInInternalField(0, aligned);
1388   i::Heap::CollectAllGarbage(false);
1389   CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
1390 
1391   obj->SetPointerInInternalField(0, unaligned);
1392   i::Heap::CollectAllGarbage(false);
1393   CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
1394 
1395   obj->SetInternalField(0, v8::External::Wrap(aligned));
1396   i::Heap::CollectAllGarbage(false);
1397   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1398 
1399   obj->SetInternalField(0, v8::External::Wrap(unaligned));
1400   i::Heap::CollectAllGarbage(false);
1401   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1402 
1403   delete[] data;
1404 }
1405 
1406 
THREADED_TEST(IdentityHash)1407 THREADED_TEST(IdentityHash) {
1408   v8::HandleScope scope;
1409   LocalContext env;
1410 
1411   // Ensure that the test starts with an fresh heap to test whether the hash
1412   // code is based on the address.
1413   i::Heap::CollectAllGarbage(false);
1414   Local<v8::Object> obj = v8::Object::New();
1415   int hash = obj->GetIdentityHash();
1416   int hash1 = obj->GetIdentityHash();
1417   CHECK_EQ(hash, hash1);
1418   int hash2 = v8::Object::New()->GetIdentityHash();
1419   // Since the identity hash is essentially a random number two consecutive
1420   // objects should not be assigned the same hash code. If the test below fails
1421   // the random number generator should be evaluated.
1422   CHECK_NE(hash, hash2);
1423   i::Heap::CollectAllGarbage(false);
1424   int hash3 = v8::Object::New()->GetIdentityHash();
1425   // Make sure that the identity hash is not based on the initial address of
1426   // the object alone. If the test below fails the random number generator
1427   // should be evaluated.
1428   CHECK_NE(hash, hash3);
1429   int hash4 = obj->GetIdentityHash();
1430   CHECK_EQ(hash, hash4);
1431 }
1432 
1433 
THREADED_TEST(HiddenProperties)1434 THREADED_TEST(HiddenProperties) {
1435   v8::HandleScope scope;
1436   LocalContext env;
1437 
1438   v8::Local<v8::Object> obj = v8::Object::New();
1439   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1440   v8::Local<v8::String> empty = v8_str("");
1441   v8::Local<v8::String> prop_name = v8_str("prop_name");
1442 
1443   i::Heap::CollectAllGarbage(false);
1444 
1445   // Make sure delete of a non-existent hidden value works
1446   CHECK(obj->DeleteHiddenValue(key));
1447 
1448   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1449   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1450   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1451   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1452 
1453   i::Heap::CollectAllGarbage(false);
1454 
1455   // Make sure we do not find the hidden property.
1456   CHECK(!obj->Has(empty));
1457   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1458   CHECK(obj->Get(empty)->IsUndefined());
1459   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1460   CHECK(obj->Set(empty, v8::Integer::New(2003)));
1461   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1462   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1463 
1464   i::Heap::CollectAllGarbage(false);
1465 
1466   // Add another property and delete it afterwards to force the object in
1467   // slow case.
1468   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1469   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1470   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1471   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1472   CHECK(obj->Delete(prop_name));
1473   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1474 
1475   i::Heap::CollectAllGarbage(false);
1476 
1477   CHECK(obj->DeleteHiddenValue(key));
1478   CHECK(obj->GetHiddenValue(key).IsEmpty());
1479 }
1480 
1481 
1482 static bool interceptor_for_hidden_properties_called;
InterceptorForHiddenProperties(Local<String> name,const AccessorInfo & info)1483 static v8::Handle<Value> InterceptorForHiddenProperties(
1484     Local<String> name, const AccessorInfo& info) {
1485   interceptor_for_hidden_properties_called = true;
1486   return v8::Handle<Value>();
1487 }
1488 
1489 
THREADED_TEST(HiddenPropertiesWithInterceptors)1490 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1491   v8::HandleScope scope;
1492   LocalContext context;
1493 
1494   interceptor_for_hidden_properties_called = false;
1495 
1496   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1497 
1498   // Associate an interceptor with an object and start setting hidden values.
1499   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1500   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1501   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1502   Local<v8::Function> function = fun_templ->GetFunction();
1503   Local<v8::Object> obj = function->NewInstance();
1504   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1505   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1506   CHECK(!interceptor_for_hidden_properties_called);
1507 }
1508 
1509 
THREADED_TEST(External)1510 THREADED_TEST(External) {
1511   v8::HandleScope scope;
1512   int x = 3;
1513   Local<v8::External> ext = v8::External::New(&x);
1514   LocalContext env;
1515   env->Global()->Set(v8_str("ext"), ext);
1516   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1517   v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
1518   int* ptr = static_cast<int*>(reext->Value());
1519   CHECK_EQ(x, 3);
1520   *ptr = 10;
1521   CHECK_EQ(x, 10);
1522 
1523   // Make sure unaligned pointers are wrapped properly.
1524   char* data = i::StrDup("0123456789");
1525   Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1526   Local<v8::Value> one = v8::External::Wrap(&data[1]);
1527   Local<v8::Value> two = v8::External::Wrap(&data[2]);
1528   Local<v8::Value> three = v8::External::Wrap(&data[3]);
1529 
1530   char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1531   CHECK_EQ('0', *char_ptr);
1532   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1533   CHECK_EQ('1', *char_ptr);
1534   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1535   CHECK_EQ('2', *char_ptr);
1536   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1537   CHECK_EQ('3', *char_ptr);
1538   i::DeleteArray(data);
1539 }
1540 
1541 
THREADED_TEST(GlobalHandle)1542 THREADED_TEST(GlobalHandle) {
1543   v8::Persistent<String> global;
1544   {
1545     v8::HandleScope scope;
1546     Local<String> str = v8_str("str");
1547     global = v8::Persistent<String>::New(str);
1548   }
1549   CHECK_EQ(global->Length(), 3);
1550   global.Dispose();
1551 }
1552 
1553 
THREADED_TEST(ScriptException)1554 THREADED_TEST(ScriptException) {
1555   v8::HandleScope scope;
1556   LocalContext env;
1557   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1558   v8::TryCatch try_catch;
1559   Local<Value> result = script->Run();
1560   CHECK(result.IsEmpty());
1561   CHECK(try_catch.HasCaught());
1562   String::AsciiValue exception_value(try_catch.Exception());
1563   CHECK_EQ(*exception_value, "panama!");
1564 }
1565 
1566 
1567 bool message_received;
1568 
1569 
check_message(v8::Handle<v8::Message> message,v8::Handle<Value> data)1570 static void check_message(v8::Handle<v8::Message> message,
1571                           v8::Handle<Value> data) {
1572   CHECK_EQ(5.76, data->NumberValue());
1573   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1574   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1575   message_received = true;
1576 }
1577 
1578 
THREADED_TEST(MessageHandlerData)1579 THREADED_TEST(MessageHandlerData) {
1580   message_received = false;
1581   v8::HandleScope scope;
1582   CHECK(!message_received);
1583   v8::V8::AddMessageListener(check_message, v8_num(5.76));
1584   LocalContext context;
1585   v8::ScriptOrigin origin =
1586       v8::ScriptOrigin(v8_str("6.75"));
1587   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1588                                                   &origin);
1589   script->SetData(v8_str("7.56"));
1590   script->Run();
1591   CHECK(message_received);
1592   // clear out the message listener
1593   v8::V8::RemoveMessageListeners(check_message);
1594 }
1595 
1596 
THREADED_TEST(GetSetProperty)1597 THREADED_TEST(GetSetProperty) {
1598   v8::HandleScope scope;
1599   LocalContext context;
1600   context->Global()->Set(v8_str("foo"), v8_num(14));
1601   context->Global()->Set(v8_str("12"), v8_num(92));
1602   context->Global()->Set(v8::Integer::New(16), v8_num(32));
1603   context->Global()->Set(v8_num(13), v8_num(56));
1604   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1605   CHECK_EQ(14, foo->Int32Value());
1606   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1607   CHECK_EQ(92, twelve->Int32Value());
1608   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1609   CHECK_EQ(32, sixteen->Int32Value());
1610   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1611   CHECK_EQ(56, thirteen->Int32Value());
1612   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1613   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1614   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1615   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1616   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1617   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1618   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1619   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1620   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1621 }
1622 
1623 
THREADED_TEST(PropertyAttributes)1624 THREADED_TEST(PropertyAttributes) {
1625   v8::HandleScope scope;
1626   LocalContext context;
1627   // read-only
1628   Local<String> prop = v8_str("read_only");
1629   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1630   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1631   Script::Compile(v8_str("read_only = 9"))->Run();
1632   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1633   context->Global()->Set(prop, v8_num(10));
1634   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1635   // dont-delete
1636   prop = v8_str("dont_delete");
1637   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1638   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1639   Script::Compile(v8_str("delete dont_delete"))->Run();
1640   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1641 }
1642 
1643 
THREADED_TEST(Array)1644 THREADED_TEST(Array) {
1645   v8::HandleScope scope;
1646   LocalContext context;
1647   Local<v8::Array> array = v8::Array::New();
1648   CHECK_EQ(0, array->Length());
1649   CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
1650   CHECK(!array->Has(0));
1651   CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
1652   CHECK(!array->Has(100));
1653   array->Set(v8::Integer::New(2), v8_num(7));
1654   CHECK_EQ(3, array->Length());
1655   CHECK(!array->Has(0));
1656   CHECK(!array->Has(1));
1657   CHECK(array->Has(2));
1658   CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
1659   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1660   Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
1661   CHECK_EQ(3, arr->Length());
1662   CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
1663   CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
1664   CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
1665 }
1666 
1667 
HandleF(const v8::Arguments & args)1668 v8::Handle<Value> HandleF(const v8::Arguments& args) {
1669   v8::HandleScope scope;
1670   ApiTestFuzzer::Fuzz();
1671   Local<v8::Array> result = v8::Array::New(args.Length());
1672   for (int i = 0; i < args.Length(); i++)
1673     result->Set(v8::Integer::New(i), args[i]);
1674   return scope.Close(result);
1675 }
1676 
1677 
THREADED_TEST(Vector)1678 THREADED_TEST(Vector) {
1679   v8::HandleScope scope;
1680   Local<ObjectTemplate> global = ObjectTemplate::New();
1681   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1682   LocalContext context(0, global);
1683 
1684   const char* fun = "f()";
1685   Local<v8::Array> a0 =
1686       Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
1687   CHECK_EQ(0, a0->Length());
1688 
1689   const char* fun2 = "f(11)";
1690   Local<v8::Array> a1 =
1691       Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
1692   CHECK_EQ(1, a1->Length());
1693   CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
1694 
1695   const char* fun3 = "f(12, 13)";
1696   Local<v8::Array> a2 =
1697       Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
1698   CHECK_EQ(2, a2->Length());
1699   CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
1700   CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
1701 
1702   const char* fun4 = "f(14, 15, 16)";
1703   Local<v8::Array> a3 =
1704       Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
1705   CHECK_EQ(3, a3->Length());
1706   CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
1707   CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
1708   CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
1709 
1710   const char* fun5 = "f(17, 18, 19, 20)";
1711   Local<v8::Array> a4 =
1712       Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
1713   CHECK_EQ(4, a4->Length());
1714   CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
1715   CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
1716   CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
1717   CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
1718 }
1719 
1720 
THREADED_TEST(FunctionCall)1721 THREADED_TEST(FunctionCall) {
1722   v8::HandleScope scope;
1723   LocalContext context;
1724   CompileRun(
1725     "function Foo() {"
1726     "  var result = [];"
1727     "  for (var i = 0; i < arguments.length; i++) {"
1728     "    result.push(arguments[i]);"
1729     "  }"
1730     "  return result;"
1731     "}");
1732   Local<Function> Foo =
1733       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1734 
1735   v8::Handle<Value>* args0 = NULL;
1736   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1737   CHECK_EQ(0, a0->Length());
1738 
1739   v8::Handle<Value> args1[] = { v8_num(1.1) };
1740   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1741   CHECK_EQ(1, a1->Length());
1742   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1743 
1744   v8::Handle<Value> args2[] = { v8_num(2.2),
1745                                 v8_num(3.3) };
1746   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1747   CHECK_EQ(2, a2->Length());
1748   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1749   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1750 
1751   v8::Handle<Value> args3[] = { v8_num(4.4),
1752                                 v8_num(5.5),
1753                                 v8_num(6.6) };
1754   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1755   CHECK_EQ(3, a3->Length());
1756   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1757   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1758   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1759 
1760   v8::Handle<Value> args4[] = { v8_num(7.7),
1761                                 v8_num(8.8),
1762                                 v8_num(9.9),
1763                                 v8_num(10.11) };
1764   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1765   CHECK_EQ(4, a4->Length());
1766   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1767   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1768   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1769   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1770 }
1771 
1772 
1773 static const char* js_code_causing_out_of_memory =
1774     "var a = new Array(); while(true) a.push(a);";
1775 
1776 
1777 // These tests run for a long time and prevent us from running tests
1778 // that come after them so they cannot run in parallel.
TEST(OutOfMemory)1779 TEST(OutOfMemory) {
1780   // It's not possible to read a snapshot into a heap with different dimensions.
1781   if (v8::internal::Snapshot::IsEnabled()) return;
1782   // Set heap limits.
1783   static const int K = 1024;
1784   v8::ResourceConstraints constraints;
1785   constraints.set_max_young_space_size(256 * K);
1786   constraints.set_max_old_space_size(4 * K * K);
1787   v8::SetResourceConstraints(&constraints);
1788 
1789   // Execute a script that causes out of memory.
1790   v8::HandleScope scope;
1791   LocalContext context;
1792   v8::V8::IgnoreOutOfMemoryException();
1793   Local<Script> script =
1794       Script::Compile(String::New(js_code_causing_out_of_memory));
1795   Local<Value> result = script->Run();
1796 
1797   // Check for out of memory state.
1798   CHECK(result.IsEmpty());
1799   CHECK(context->HasOutOfMemoryException());
1800 }
1801 
1802 
ProvokeOutOfMemory(const v8::Arguments & args)1803 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1804   ApiTestFuzzer::Fuzz();
1805 
1806   v8::HandleScope scope;
1807   LocalContext context;
1808   Local<Script> script =
1809       Script::Compile(String::New(js_code_causing_out_of_memory));
1810   Local<Value> result = script->Run();
1811 
1812   // Check for out of memory state.
1813   CHECK(result.IsEmpty());
1814   CHECK(context->HasOutOfMemoryException());
1815 
1816   return result;
1817 }
1818 
1819 
TEST(OutOfMemoryNested)1820 TEST(OutOfMemoryNested) {
1821   // It's not possible to read a snapshot into a heap with different dimensions.
1822   if (v8::internal::Snapshot::IsEnabled()) return;
1823   // Set heap limits.
1824   static const int K = 1024;
1825   v8::ResourceConstraints constraints;
1826   constraints.set_max_young_space_size(256 * K);
1827   constraints.set_max_old_space_size(4 * K * K);
1828   v8::SetResourceConstraints(&constraints);
1829 
1830   v8::HandleScope scope;
1831   Local<ObjectTemplate> templ = ObjectTemplate::New();
1832   templ->Set(v8_str("ProvokeOutOfMemory"),
1833              v8::FunctionTemplate::New(ProvokeOutOfMemory));
1834   LocalContext context(0, templ);
1835   v8::V8::IgnoreOutOfMemoryException();
1836   Local<Value> result = CompileRun(
1837     "var thrown = false;"
1838     "try {"
1839     "  ProvokeOutOfMemory();"
1840     "} catch (e) {"
1841     "  thrown = true;"
1842     "}");
1843   // Check for out of memory state.
1844   CHECK(result.IsEmpty());
1845   CHECK(context->HasOutOfMemoryException());
1846 }
1847 
1848 
TEST(HugeConsStringOutOfMemory)1849 TEST(HugeConsStringOutOfMemory) {
1850   // It's not possible to read a snapshot into a heap with different dimensions.
1851   if (v8::internal::Snapshot::IsEnabled()) return;
1852   v8::HandleScope scope;
1853   LocalContext context;
1854   // Set heap limits.
1855   static const int K = 1024;
1856   v8::ResourceConstraints constraints;
1857   constraints.set_max_young_space_size(256 * K);
1858   constraints.set_max_old_space_size(2 * K * K);
1859   v8::SetResourceConstraints(&constraints);
1860 
1861   // Execute a script that causes out of memory.
1862   v8::V8::IgnoreOutOfMemoryException();
1863 
1864   // Build huge string. This should fail with out of memory exception.
1865   Local<Value> result = CompileRun(
1866     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1867     "for (var i = 0; i < 22; i++) { str = str + str; }");
1868 
1869   // Check for out of memory state.
1870   CHECK(result.IsEmpty());
1871   CHECK(context->HasOutOfMemoryException());
1872 }
1873 
1874 
THREADED_TEST(ConstructCall)1875 THREADED_TEST(ConstructCall) {
1876   v8::HandleScope scope;
1877   LocalContext context;
1878   CompileRun(
1879     "function Foo() {"
1880     "  var result = [];"
1881     "  for (var i = 0; i < arguments.length; i++) {"
1882     "    result.push(arguments[i]);"
1883     "  }"
1884     "  return result;"
1885     "}");
1886   Local<Function> Foo =
1887       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1888 
1889   v8::Handle<Value>* args0 = NULL;
1890   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1891   CHECK_EQ(0, a0->Length());
1892 
1893   v8::Handle<Value> args1[] = { v8_num(1.1) };
1894   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1895   CHECK_EQ(1, a1->Length());
1896   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1897 
1898   v8::Handle<Value> args2[] = { v8_num(2.2),
1899                                 v8_num(3.3) };
1900   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1901   CHECK_EQ(2, a2->Length());
1902   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1903   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1904 
1905   v8::Handle<Value> args3[] = { v8_num(4.4),
1906                                 v8_num(5.5),
1907                                 v8_num(6.6) };
1908   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1909   CHECK_EQ(3, a3->Length());
1910   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1911   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1912   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1913 
1914   v8::Handle<Value> args4[] = { v8_num(7.7),
1915                                 v8_num(8.8),
1916                                 v8_num(9.9),
1917                                 v8_num(10.11) };
1918   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1919   CHECK_EQ(4, a4->Length());
1920   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1921   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1922   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1923   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1924 }
1925 
1926 
CheckUncle(v8::TryCatch * try_catch)1927 static void CheckUncle(v8::TryCatch* try_catch) {
1928   CHECK(try_catch->HasCaught());
1929   String::AsciiValue str_value(try_catch->Exception());
1930   CHECK_EQ(*str_value, "uncle?");
1931   try_catch->Reset();
1932 }
1933 
1934 
THREADED_TEST(ConversionException)1935 THREADED_TEST(ConversionException) {
1936   v8::HandleScope scope;
1937   LocalContext env;
1938   CompileRun(
1939     "function TestClass() { };"
1940     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
1941     "var obj = new TestClass();");
1942   Local<Value> obj = env->Global()->Get(v8_str("obj"));
1943 
1944   v8::TryCatch try_catch;
1945 
1946   Local<Value> to_string_result = obj->ToString();
1947   CHECK(to_string_result.IsEmpty());
1948   CheckUncle(&try_catch);
1949 
1950   Local<Value> to_number_result = obj->ToNumber();
1951   CHECK(to_number_result.IsEmpty());
1952   CheckUncle(&try_catch);
1953 
1954   Local<Value> to_integer_result = obj->ToInteger();
1955   CHECK(to_integer_result.IsEmpty());
1956   CheckUncle(&try_catch);
1957 
1958   Local<Value> to_uint32_result = obj->ToUint32();
1959   CHECK(to_uint32_result.IsEmpty());
1960   CheckUncle(&try_catch);
1961 
1962   Local<Value> to_int32_result = obj->ToInt32();
1963   CHECK(to_int32_result.IsEmpty());
1964   CheckUncle(&try_catch);
1965 
1966   Local<Value> to_object_result = v8::Undefined()->ToObject();
1967   CHECK(to_object_result.IsEmpty());
1968   CHECK(try_catch.HasCaught());
1969   try_catch.Reset();
1970 
1971   int32_t int32_value = obj->Int32Value();
1972   CHECK_EQ(0, int32_value);
1973   CheckUncle(&try_catch);
1974 
1975   uint32_t uint32_value = obj->Uint32Value();
1976   CHECK_EQ(0, uint32_value);
1977   CheckUncle(&try_catch);
1978 
1979   double number_value = obj->NumberValue();
1980   CHECK_NE(0, IsNaN(number_value));
1981   CheckUncle(&try_catch);
1982 
1983   int64_t integer_value = obj->IntegerValue();
1984   CHECK_EQ(0.0, static_cast<double>(integer_value));
1985   CheckUncle(&try_catch);
1986 }
1987 
1988 
ThrowFromC(const v8::Arguments & args)1989 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
1990   ApiTestFuzzer::Fuzz();
1991   return v8::ThrowException(v8_str("konto"));
1992 }
1993 
1994 
CCatcher(const v8::Arguments & args)1995 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
1996   if (args.Length() < 1) return v8::Boolean::New(false);
1997   v8::HandleScope scope;
1998   v8::TryCatch try_catch;
1999   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
2000   CHECK(!try_catch.HasCaught() || result.IsEmpty());
2001   return v8::Boolean::New(try_catch.HasCaught());
2002 }
2003 
2004 
THREADED_TEST(APICatch)2005 THREADED_TEST(APICatch) {
2006   v8::HandleScope scope;
2007   Local<ObjectTemplate> templ = ObjectTemplate::New();
2008   templ->Set(v8_str("ThrowFromC"),
2009              v8::FunctionTemplate::New(ThrowFromC));
2010   LocalContext context(0, templ);
2011   CompileRun(
2012     "var thrown = false;"
2013     "try {"
2014     "  ThrowFromC();"
2015     "} catch (e) {"
2016     "  thrown = true;"
2017     "}");
2018   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
2019   CHECK(thrown->BooleanValue());
2020 }
2021 
2022 
THREADED_TEST(APIThrowTryCatch)2023 THREADED_TEST(APIThrowTryCatch) {
2024   v8::HandleScope scope;
2025   Local<ObjectTemplate> templ = ObjectTemplate::New();
2026   templ->Set(v8_str("ThrowFromC"),
2027              v8::FunctionTemplate::New(ThrowFromC));
2028   LocalContext context(0, templ);
2029   v8::TryCatch try_catch;
2030   CompileRun("ThrowFromC();");
2031   CHECK(try_catch.HasCaught());
2032 }
2033 
2034 
2035 // Test that a try-finally block doesn't shadow a try-catch block
2036 // when setting up an external handler.
2037 //
2038 // BUG(271): Some of the exception propagation does not work on the
2039 // ARM simulator because the simulator separates the C++ stack and the
2040 // JS stack.  This test therefore fails on the simulator.  The test is
2041 // not threaded to allow the threading tests to run on the simulator.
TEST(TryCatchInTryFinally)2042 TEST(TryCatchInTryFinally) {
2043   v8::HandleScope scope;
2044   Local<ObjectTemplate> templ = ObjectTemplate::New();
2045   templ->Set(v8_str("CCatcher"),
2046              v8::FunctionTemplate::New(CCatcher));
2047   LocalContext context(0, templ);
2048   Local<Value> result = CompileRun("try {"
2049                                    "  try {"
2050                                    "    CCatcher('throw 7;');"
2051                                    "  } finally {"
2052                                    "  }"
2053                                    "} catch (e) {"
2054                                    "}");
2055   CHECK(result->IsTrue());
2056 }
2057 
2058 
receive_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)2059 static void receive_message(v8::Handle<v8::Message> message,
2060                             v8::Handle<v8::Value> data) {
2061   message->Get();
2062   message_received = true;
2063 }
2064 
2065 
TEST(APIThrowMessage)2066 TEST(APIThrowMessage) {
2067   message_received = false;
2068   v8::HandleScope scope;
2069   v8::V8::AddMessageListener(receive_message);
2070   Local<ObjectTemplate> templ = ObjectTemplate::New();
2071   templ->Set(v8_str("ThrowFromC"),
2072              v8::FunctionTemplate::New(ThrowFromC));
2073   LocalContext context(0, templ);
2074   CompileRun("ThrowFromC();");
2075   CHECK(message_received);
2076   v8::V8::RemoveMessageListeners(check_message);
2077 }
2078 
2079 
TEST(APIThrowMessageAndVerboseTryCatch)2080 TEST(APIThrowMessageAndVerboseTryCatch) {
2081   message_received = false;
2082   v8::HandleScope scope;
2083   v8::V8::AddMessageListener(receive_message);
2084   Local<ObjectTemplate> templ = ObjectTemplate::New();
2085   templ->Set(v8_str("ThrowFromC"),
2086              v8::FunctionTemplate::New(ThrowFromC));
2087   LocalContext context(0, templ);
2088   v8::TryCatch try_catch;
2089   try_catch.SetVerbose(true);
2090   Local<Value> result = CompileRun("ThrowFromC();");
2091   CHECK(try_catch.HasCaught());
2092   CHECK(result.IsEmpty());
2093   CHECK(message_received);
2094   v8::V8::RemoveMessageListeners(check_message);
2095 }
2096 
2097 
THREADED_TEST(ExternalScriptException)2098 THREADED_TEST(ExternalScriptException) {
2099   v8::HandleScope scope;
2100   Local<ObjectTemplate> templ = ObjectTemplate::New();
2101   templ->Set(v8_str("ThrowFromC"),
2102              v8::FunctionTemplate::New(ThrowFromC));
2103   LocalContext context(0, templ);
2104 
2105   v8::TryCatch try_catch;
2106   Local<Script> script
2107       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2108   Local<Value> result = script->Run();
2109   CHECK(result.IsEmpty());
2110   CHECK(try_catch.HasCaught());
2111   String::AsciiValue exception_value(try_catch.Exception());
2112   CHECK_EQ("konto", *exception_value);
2113 }
2114 
2115 
2116 
CThrowCountDown(const v8::Arguments & args)2117 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2118   ApiTestFuzzer::Fuzz();
2119   CHECK_EQ(4, args.Length());
2120   int count = args[0]->Int32Value();
2121   int cInterval = args[2]->Int32Value();
2122   if (count == 0) {
2123     return v8::ThrowException(v8_str("FromC"));
2124   } else {
2125     Local<v8::Object> global = Context::GetCurrent()->Global();
2126     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2127     v8::Handle<Value> argv[] = { v8_num(count - 1),
2128                                  args[1],
2129                                  args[2],
2130                                  args[3] };
2131     if (count % cInterval == 0) {
2132       v8::TryCatch try_catch;
2133       Local<Value> result =
2134           v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2135       int expected = args[3]->Int32Value();
2136       if (try_catch.HasCaught()) {
2137         CHECK_EQ(expected, count);
2138         CHECK(result.IsEmpty());
2139         CHECK(!i::Top::has_scheduled_exception());
2140       } else {
2141         CHECK_NE(expected, count);
2142       }
2143       return result;
2144     } else {
2145       return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2146     }
2147   }
2148 }
2149 
2150 
JSCheck(const v8::Arguments & args)2151 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2152   ApiTestFuzzer::Fuzz();
2153   CHECK_EQ(3, args.Length());
2154   bool equality = args[0]->BooleanValue();
2155   int count = args[1]->Int32Value();
2156   int expected = args[2]->Int32Value();
2157   if (equality) {
2158     CHECK_EQ(count, expected);
2159   } else {
2160     CHECK_NE(count, expected);
2161   }
2162   return v8::Undefined();
2163 }
2164 
2165 
THREADED_TEST(EvalInTryFinally)2166 THREADED_TEST(EvalInTryFinally) {
2167   v8::HandleScope scope;
2168   LocalContext context;
2169   v8::TryCatch try_catch;
2170   CompileRun("(function() {"
2171              "  try {"
2172              "    eval('asldkf (*&^&*^');"
2173              "  } finally {"
2174              "    return;"
2175              "  }"
2176              "})()");
2177   CHECK(!try_catch.HasCaught());
2178 }
2179 
2180 
2181 // This test works by making a stack of alternating JavaScript and C
2182 // activations.  These activations set up exception handlers with regular
2183 // intervals, one interval for C activations and another for JavaScript
2184 // activations.  When enough activations have been created an exception is
2185 // thrown and we check that the right activation catches the exception and that
2186 // no other activations do.  The right activation is always the topmost one with
2187 // a handler, regardless of whether it is in JavaScript or C.
2188 //
2189 // The notation used to describe a test case looks like this:
2190 //
2191 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
2192 //
2193 // Each entry is an activation, either JS or C.  The index is the count at that
2194 // level.  Stars identify activations with exception handlers, the @ identifies
2195 // the exception handler that should catch the exception.
2196 //
2197 // BUG(271): Some of the exception propagation does not work on the
2198 // ARM simulator because the simulator separates the C++ stack and the
2199 // JS stack.  This test therefore fails on the simulator.  The test is
2200 // not threaded to allow the threading tests to run on the simulator.
TEST(ExceptionOrder)2201 TEST(ExceptionOrder) {
2202   v8::HandleScope scope;
2203   Local<ObjectTemplate> templ = ObjectTemplate::New();
2204   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2205   templ->Set(v8_str("CThrowCountDown"),
2206              v8::FunctionTemplate::New(CThrowCountDown));
2207   LocalContext context(0, templ);
2208   CompileRun(
2209     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2210     "  if (count == 0) throw 'FromJS';"
2211     "  if (count % jsInterval == 0) {"
2212     "    try {"
2213     "      var value = CThrowCountDown(count - 1,"
2214     "                                  jsInterval,"
2215     "                                  cInterval,"
2216     "                                  expected);"
2217     "      check(false, count, expected);"
2218     "      return value;"
2219     "    } catch (e) {"
2220     "      check(true, count, expected);"
2221     "    }"
2222     "  } else {"
2223     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2224     "  }"
2225     "}");
2226   Local<Function> fun =
2227       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2228 
2229   const int argc = 4;
2230   //                             count      jsInterval cInterval  expected
2231 
2232   // *JS[4] *C[3] @JS[2] C[1] JS[0]
2233   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2234   fun->Call(fun, argc, a0);
2235 
2236   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2237   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2238   fun->Call(fun, argc, a1);
2239 
2240   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2241   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2242   fun->Call(fun, argc, a2);
2243 
2244   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2245   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2246   fun->Call(fun, argc, a3);
2247 
2248   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2249   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2250   fun->Call(fun, argc, a4);
2251 
2252   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2253   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2254   fun->Call(fun, argc, a5);
2255 }
2256 
2257 
ThrowValue(const v8::Arguments & args)2258 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2259   ApiTestFuzzer::Fuzz();
2260   CHECK_EQ(1, args.Length());
2261   return v8::ThrowException(args[0]);
2262 }
2263 
2264 
THREADED_TEST(ThrowValues)2265 THREADED_TEST(ThrowValues) {
2266   v8::HandleScope scope;
2267   Local<ObjectTemplate> templ = ObjectTemplate::New();
2268   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2269   LocalContext context(0, templ);
2270   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2271     "function Run(obj) {"
2272     "  try {"
2273     "    Throw(obj);"
2274     "  } catch (e) {"
2275     "    return e;"
2276     "  }"
2277     "  return 'no exception';"
2278     "}"
2279     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2280   CHECK_EQ(5, result->Length());
2281   CHECK(result->Get(v8::Integer::New(0))->IsString());
2282   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2283   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2284   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2285   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2286   CHECK(result->Get(v8::Integer::New(3))->IsNull());
2287   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2288 }
2289 
2290 
THREADED_TEST(CatchZero)2291 THREADED_TEST(CatchZero) {
2292   v8::HandleScope scope;
2293   LocalContext context;
2294   v8::TryCatch try_catch;
2295   CHECK(!try_catch.HasCaught());
2296   Script::Compile(v8_str("throw 10"))->Run();
2297   CHECK(try_catch.HasCaught());
2298   CHECK_EQ(10, try_catch.Exception()->Int32Value());
2299   try_catch.Reset();
2300   CHECK(!try_catch.HasCaught());
2301   Script::Compile(v8_str("throw 0"))->Run();
2302   CHECK(try_catch.HasCaught());
2303   CHECK_EQ(0, try_catch.Exception()->Int32Value());
2304 }
2305 
2306 
THREADED_TEST(CatchExceptionFromWith)2307 THREADED_TEST(CatchExceptionFromWith) {
2308   v8::HandleScope scope;
2309   LocalContext context;
2310   v8::TryCatch try_catch;
2311   CHECK(!try_catch.HasCaught());
2312   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2313   CHECK(try_catch.HasCaught());
2314 }
2315 
2316 
THREADED_TEST(Equality)2317 THREADED_TEST(Equality) {
2318   v8::HandleScope scope;
2319   LocalContext context;
2320   // Check that equality works at all before relying on CHECK_EQ
2321   CHECK(v8_str("a")->Equals(v8_str("a")));
2322   CHECK(!v8_str("a")->Equals(v8_str("b")));
2323 
2324   CHECK_EQ(v8_str("a"), v8_str("a"));
2325   CHECK_NE(v8_str("a"), v8_str("b"));
2326   CHECK_EQ(v8_num(1), v8_num(1));
2327   CHECK_EQ(v8_num(1.00), v8_num(1));
2328   CHECK_NE(v8_num(1), v8_num(2));
2329 
2330   // Assume String is not symbol.
2331   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2332   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2333   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2334   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2335   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2336   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2337   Local<Value> not_a_number = v8_num(i::OS::nan_value());
2338   CHECK(!not_a_number->StrictEquals(not_a_number));
2339   CHECK(v8::False()->StrictEquals(v8::False()));
2340   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2341 
2342   v8::Handle<v8::Object> obj = v8::Object::New();
2343   v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2344   CHECK(alias->StrictEquals(obj));
2345   alias.Dispose();
2346 }
2347 
2348 
THREADED_TEST(MultiRun)2349 THREADED_TEST(MultiRun) {
2350   v8::HandleScope scope;
2351   LocalContext context;
2352   Local<Script> script = Script::Compile(v8_str("x"));
2353   for (int i = 0; i < 10; i++)
2354     script->Run();
2355 }
2356 
2357 
GetXValue(Local<String> name,const AccessorInfo & info)2358 static v8::Handle<Value> GetXValue(Local<String> name,
2359                                    const AccessorInfo& info) {
2360   ApiTestFuzzer::Fuzz();
2361   CHECK_EQ(info.Data(), v8_str("donut"));
2362   CHECK_EQ(name, v8_str("x"));
2363   return name;
2364 }
2365 
2366 
THREADED_TEST(SimplePropertyRead)2367 THREADED_TEST(SimplePropertyRead) {
2368   v8::HandleScope scope;
2369   Local<ObjectTemplate> templ = ObjectTemplate::New();
2370   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2371   LocalContext context;
2372   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2373   Local<Script> script = Script::Compile(v8_str("obj.x"));
2374   for (int i = 0; i < 10; i++) {
2375     Local<Value> result = script->Run();
2376     CHECK_EQ(result, v8_str("x"));
2377   }
2378 }
2379 
THREADED_TEST(DefinePropertyOnAPIAccessor)2380 THREADED_TEST(DefinePropertyOnAPIAccessor) {
2381   v8::HandleScope scope;
2382   Local<ObjectTemplate> templ = ObjectTemplate::New();
2383   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2384   LocalContext context;
2385   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2386 
2387   // Uses getOwnPropertyDescriptor to check the configurable status
2388   Local<Script> script_desc
2389     = Script::Compile(v8_str("var prop =Object.getOwnPropertyDescriptor( "
2390                              "obj, 'x');"
2391                              "prop.configurable;"));
2392   Local<Value> result = script_desc->Run();
2393   CHECK_EQ(result->BooleanValue(), true);
2394 
2395   // Redefine get - but still configurable
2396   Local<Script> script_define
2397     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
2398                              "            configurable: true };"
2399                              "Object.defineProperty(obj, 'x', desc);"
2400                              "obj.x"));
2401   result = script_define->Run();
2402   CHECK_EQ(result, v8_num(42));
2403 
2404   // Check that the accessor is still configurable
2405   result = script_desc->Run();
2406   CHECK_EQ(result->BooleanValue(), true);
2407 
2408   // Redefine to a non-configurable
2409   script_define
2410     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
2411                              "             configurable: false };"
2412                              "Object.defineProperty(obj, 'x', desc);"
2413                              "obj.x"));
2414   result = script_define->Run();
2415   CHECK_EQ(result, v8_num(43));
2416   result = script_desc->Run();
2417   CHECK_EQ(result->BooleanValue(), false);
2418 
2419   // Make sure that it is not possible to redefine again
2420   v8::TryCatch try_catch;
2421   result = script_define->Run();
2422   CHECK(try_catch.HasCaught());
2423   String::AsciiValue exception_value(try_catch.Exception());
2424   CHECK_EQ(*exception_value,
2425            "TypeError: Cannot redefine property: defineProperty");
2426 }
2427 
THREADED_TEST(DefinePropertyOnDefineGetterSetter)2428 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
2429   v8::HandleScope scope;
2430   Local<ObjectTemplate> templ = ObjectTemplate::New();
2431   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2432   LocalContext context;
2433   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2434 
2435   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
2436                                     "Object.getOwnPropertyDescriptor( "
2437                                     "obj, 'x');"
2438                                     "prop.configurable;"));
2439   Local<Value> result = script_desc->Run();
2440   CHECK_EQ(result->BooleanValue(), true);
2441 
2442   Local<Script> script_define =
2443     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
2444                            "            configurable: true };"
2445                            "Object.defineProperty(obj, 'x', desc);"
2446                            "obj.x"));
2447   result = script_define->Run();
2448   CHECK_EQ(result, v8_num(42));
2449 
2450 
2451   result = script_desc->Run();
2452   CHECK_EQ(result->BooleanValue(), true);
2453 
2454 
2455   script_define =
2456     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
2457                            "            configurable: false };"
2458                            "Object.defineProperty(obj, 'x', desc);"
2459                            "obj.x"));
2460   result = script_define->Run();
2461   CHECK_EQ(result, v8_num(43));
2462   result = script_desc->Run();
2463 
2464   CHECK_EQ(result->BooleanValue(), false);
2465 
2466   v8::TryCatch try_catch;
2467   result = script_define->Run();
2468   CHECK(try_catch.HasCaught());
2469   String::AsciiValue exception_value(try_catch.Exception());
2470   CHECK_EQ(*exception_value,
2471            "TypeError: Cannot redefine property: defineProperty");
2472 }
2473 
2474 
2475 
2476 
2477 
2478 v8::Persistent<Value> xValue;
2479 
2480 
SetXValue(Local<String> name,Local<Value> value,const AccessorInfo & info)2481 static void SetXValue(Local<String> name,
2482                       Local<Value> value,
2483                       const AccessorInfo& info) {
2484   CHECK_EQ(value, v8_num(4));
2485   CHECK_EQ(info.Data(), v8_str("donut"));
2486   CHECK_EQ(name, v8_str("x"));
2487   CHECK(xValue.IsEmpty());
2488   xValue = v8::Persistent<Value>::New(value);
2489 }
2490 
2491 
THREADED_TEST(SimplePropertyWrite)2492 THREADED_TEST(SimplePropertyWrite) {
2493   v8::HandleScope scope;
2494   Local<ObjectTemplate> templ = ObjectTemplate::New();
2495   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2496   LocalContext context;
2497   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2498   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2499   for (int i = 0; i < 10; i++) {
2500     CHECK(xValue.IsEmpty());
2501     script->Run();
2502     CHECK_EQ(v8_num(4), xValue);
2503     xValue.Dispose();
2504     xValue = v8::Persistent<Value>();
2505   }
2506 }
2507 
2508 
XPropertyGetter(Local<String> property,const AccessorInfo & info)2509 static v8::Handle<Value> XPropertyGetter(Local<String> property,
2510                                          const AccessorInfo& info) {
2511   ApiTestFuzzer::Fuzz();
2512   CHECK(info.Data()->IsUndefined());
2513   return property;
2514 }
2515 
2516 
THREADED_TEST(NamedInterceptorPropertyRead)2517 THREADED_TEST(NamedInterceptorPropertyRead) {
2518   v8::HandleScope scope;
2519   Local<ObjectTemplate> templ = ObjectTemplate::New();
2520   templ->SetNamedPropertyHandler(XPropertyGetter);
2521   LocalContext context;
2522   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2523   Local<Script> script = Script::Compile(v8_str("obj.x"));
2524   for (int i = 0; i < 10; i++) {
2525     Local<Value> result = script->Run();
2526     CHECK_EQ(result, v8_str("x"));
2527   }
2528 }
2529 
2530 
SetXOnPrototypeGetter(Local<String> property,const AccessorInfo & info)2531 static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
2532                                                const AccessorInfo& info) {
2533   // Set x on the prototype object and do not handle the get request.
2534   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
2535   v8::Handle<v8::Object>::Cast(proto)->Set(v8_str("x"), v8::Integer::New(23));
2536   return v8::Handle<Value>();
2537 }
2538 
2539 
2540 // This is a regression test for http://crbug.com/20104. Map
2541 // transitions should not interfere with post interceptor lookup.
THREADED_TEST(NamedInterceptorMapTransitionRead)2542 THREADED_TEST(NamedInterceptorMapTransitionRead) {
2543   v8::HandleScope scope;
2544   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
2545   Local<v8::ObjectTemplate> instance_template
2546       = function_template->InstanceTemplate();
2547   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
2548   LocalContext context;
2549   context->Global()->Set(v8_str("F"), function_template->GetFunction());
2550   // Create an instance of F and introduce a map transition for x.
2551   CompileRun("var o = new F(); o.x = 23;");
2552   // Create an instance of F and invoke the getter. The result should be 23.
2553   Local<Value> result = CompileRun("o = new F(); o.x");
2554   CHECK_EQ(result->Int32Value(), 23);
2555 }
2556 
2557 
IndexedPropertyGetter(uint32_t index,const AccessorInfo & info)2558 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2559                                                const AccessorInfo& info) {
2560   ApiTestFuzzer::Fuzz();
2561   if (index == 37) {
2562     return v8::Handle<Value>(v8_num(625));
2563   }
2564   return v8::Handle<Value>();
2565 }
2566 
2567 
IndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)2568 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2569                                                Local<Value> value,
2570                                                const AccessorInfo& info) {
2571   ApiTestFuzzer::Fuzz();
2572   if (index == 39) {
2573     return value;
2574   }
2575   return v8::Handle<Value>();
2576 }
2577 
2578 
THREADED_TEST(IndexedInterceptorWithIndexedAccessor)2579 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2580   v8::HandleScope scope;
2581   Local<ObjectTemplate> templ = ObjectTemplate::New();
2582   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2583                                    IndexedPropertySetter);
2584   LocalContext context;
2585   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2586   Local<Script> getter_script = Script::Compile(v8_str(
2587       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2588   Local<Script> setter_script = Script::Compile(v8_str(
2589       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2590       "obj[17] = 23;"
2591       "obj.foo;"));
2592   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2593       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2594       "obj[39] = 47;"
2595       "obj.foo;"));  // This setter should not run, due to the interceptor.
2596   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2597       "obj[37];"));
2598   Local<Value> result = getter_script->Run();
2599   CHECK_EQ(v8_num(5), result);
2600   result = setter_script->Run();
2601   CHECK_EQ(v8_num(23), result);
2602   result = interceptor_setter_script->Run();
2603   CHECK_EQ(v8_num(23), result);
2604   result = interceptor_getter_script->Run();
2605   CHECK_EQ(v8_num(625), result);
2606 }
2607 
2608 
IdentityIndexedPropertyGetter(uint32_t index,const AccessorInfo & info)2609 static v8::Handle<Value> IdentityIndexedPropertyGetter(
2610     uint32_t index,
2611     const AccessorInfo& info) {
2612   return v8::Integer::New(index);
2613 }
2614 
2615 
THREADED_TEST(IndexedInterceptorWithNoSetter)2616 THREADED_TEST(IndexedInterceptorWithNoSetter) {
2617   v8::HandleScope scope;
2618   Local<ObjectTemplate> templ = ObjectTemplate::New();
2619   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2620 
2621   LocalContext context;
2622   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2623 
2624   const char* code =
2625       "try {"
2626       "  obj[0] = 239;"
2627       "  for (var i = 0; i < 100; i++) {"
2628       "    var v = obj[0];"
2629       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
2630       "  }"
2631       "  'PASSED'"
2632       "} catch(e) {"
2633       "  e"
2634       "}";
2635   ExpectString(code, "PASSED");
2636 }
2637 
2638 
THREADED_TEST(IndexedInterceptorWithAccessorCheck)2639 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
2640   v8::HandleScope scope;
2641   Local<ObjectTemplate> templ = ObjectTemplate::New();
2642   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2643 
2644   LocalContext context;
2645   Local<v8::Object> obj = templ->NewInstance();
2646   obj->TurnOnAccessCheck();
2647   context->Global()->Set(v8_str("obj"), obj);
2648 
2649   const char* code =
2650       "try {"
2651       "  for (var i = 0; i < 100; i++) {"
2652       "    var v = obj[0];"
2653       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
2654       "  }"
2655       "  'PASSED'"
2656       "} catch(e) {"
2657       "  e"
2658       "}";
2659   ExpectString(code, "PASSED");
2660 }
2661 
2662 
THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn)2663 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
2664   i::FLAG_allow_natives_syntax = true;
2665   v8::HandleScope scope;
2666   Local<ObjectTemplate> templ = ObjectTemplate::New();
2667   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2668 
2669   LocalContext context;
2670   Local<v8::Object> obj = templ->NewInstance();
2671   context->Global()->Set(v8_str("obj"), obj);
2672 
2673   const char* code =
2674       "try {"
2675       "  for (var i = 0; i < 100; i++) {"
2676       "    var expected = i;"
2677       "    if (i == 5) {"
2678       "      %EnableAccessChecks(obj);"
2679       "      expected = undefined;"
2680       "    }"
2681       "    var v = obj[i];"
2682       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2683       "    if (i == 5) %DisableAccessChecks(obj);"
2684       "  }"
2685       "  'PASSED'"
2686       "} catch(e) {"
2687       "  e"
2688       "}";
2689   ExpectString(code, "PASSED");
2690 }
2691 
2692 
THREADED_TEST(IndexedInterceptorWithDifferentIndices)2693 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
2694   v8::HandleScope scope;
2695   Local<ObjectTemplate> templ = ObjectTemplate::New();
2696   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2697 
2698   LocalContext context;
2699   Local<v8::Object> obj = templ->NewInstance();
2700   context->Global()->Set(v8_str("obj"), obj);
2701 
2702   const char* code =
2703       "try {"
2704       "  for (var i = 0; i < 100; i++) {"
2705       "    var v = obj[i];"
2706       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2707       "  }"
2708       "  'PASSED'"
2709       "} catch(e) {"
2710       "  e"
2711       "}";
2712   ExpectString(code, "PASSED");
2713 }
2714 
2715 
THREADED_TEST(IndexedInterceptorWithNotSmiLookup)2716 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
2717   v8::HandleScope scope;
2718   Local<ObjectTemplate> templ = ObjectTemplate::New();
2719   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2720 
2721   LocalContext context;
2722   Local<v8::Object> obj = templ->NewInstance();
2723   context->Global()->Set(v8_str("obj"), obj);
2724 
2725   const char* code =
2726       "try {"
2727       "  for (var i = 0; i < 100; i++) {"
2728       "    var expected = i;"
2729       "    if (i == 50) {"
2730       "       i = 'foobar';"
2731       "       expected = undefined;"
2732       "    }"
2733       "    var v = obj[i];"
2734       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2735       "  }"
2736       "  'PASSED'"
2737       "} catch(e) {"
2738       "  e"
2739       "}";
2740   ExpectString(code, "PASSED");
2741 }
2742 
2743 
THREADED_TEST(IndexedInterceptorGoingMegamorphic)2744 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
2745   v8::HandleScope scope;
2746   Local<ObjectTemplate> templ = ObjectTemplate::New();
2747   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2748 
2749   LocalContext context;
2750   Local<v8::Object> obj = templ->NewInstance();
2751   context->Global()->Set(v8_str("obj"), obj);
2752 
2753   const char* code =
2754       "var original = obj;"
2755       "try {"
2756       "  for (var i = 0; i < 100; i++) {"
2757       "    var expected = i;"
2758       "    if (i == 50) {"
2759       "       obj = {50: 'foobar'};"
2760       "       expected = 'foobar';"
2761       "    }"
2762       "    var v = obj[i];"
2763       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2764       "    if (i == 50) obj = original;"
2765       "  }"
2766       "  'PASSED'"
2767       "} catch(e) {"
2768       "  e"
2769       "}";
2770   ExpectString(code, "PASSED");
2771 }
2772 
2773 
THREADED_TEST(IndexedInterceptorReceiverTurningSmi)2774 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
2775   v8::HandleScope scope;
2776   Local<ObjectTemplate> templ = ObjectTemplate::New();
2777   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2778 
2779   LocalContext context;
2780   Local<v8::Object> obj = templ->NewInstance();
2781   context->Global()->Set(v8_str("obj"), obj);
2782 
2783   const char* code =
2784       "var original = obj;"
2785       "try {"
2786       "  for (var i = 0; i < 100; i++) {"
2787       "    var expected = i;"
2788       "    if (i == 5) {"
2789       "       obj = 239;"
2790       "       expected = undefined;"
2791       "    }"
2792       "    var v = obj[i];"
2793       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
2794       "    if (i == 5) obj = original;"
2795       "  }"
2796       "  'PASSED'"
2797       "} catch(e) {"
2798       "  e"
2799       "}";
2800   ExpectString(code, "PASSED");
2801 }
2802 
2803 
THREADED_TEST(IndexedInterceptorOnProto)2804 THREADED_TEST(IndexedInterceptorOnProto) {
2805   v8::HandleScope scope;
2806   Local<ObjectTemplate> templ = ObjectTemplate::New();
2807   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
2808 
2809   LocalContext context;
2810   Local<v8::Object> obj = templ->NewInstance();
2811   context->Global()->Set(v8_str("obj"), obj);
2812 
2813   const char* code =
2814       "var o = {__proto__: obj};"
2815       "try {"
2816       "  for (var i = 0; i < 100; i++) {"
2817       "    var v = o[i];"
2818       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
2819       "  }"
2820       "  'PASSED'"
2821       "} catch(e) {"
2822       "  e"
2823       "}";
2824   ExpectString(code, "PASSED");
2825 }
2826 
2827 
THREADED_TEST(MultiContexts)2828 THREADED_TEST(MultiContexts) {
2829   v8::HandleScope scope;
2830   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
2831   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
2832 
2833   Local<String> password = v8_str("Password");
2834 
2835   // Create an environment
2836   LocalContext context0(0, templ);
2837   context0->SetSecurityToken(password);
2838   v8::Handle<v8::Object> global0 = context0->Global();
2839   global0->Set(v8_str("custom"), v8_num(1234));
2840   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2841 
2842   // Create an independent environment
2843   LocalContext context1(0, templ);
2844   context1->SetSecurityToken(password);
2845   v8::Handle<v8::Object> global1 = context1->Global();
2846   global1->Set(v8_str("custom"), v8_num(1234));
2847   CHECK_NE(global0, global1);
2848   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2849   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2850 
2851   // Now create a new context with the old global
2852   LocalContext context2(0, templ, global1);
2853   context2->SetSecurityToken(password);
2854   v8::Handle<v8::Object> global2 = context2->Global();
2855   CHECK_EQ(global1, global2);
2856   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
2857   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
2858 }
2859 
2860 
THREADED_TEST(FunctionPrototypeAcrossContexts)2861 THREADED_TEST(FunctionPrototypeAcrossContexts) {
2862   // Make sure that functions created by cloning boilerplates cannot
2863   // communicate through their __proto__ field.
2864 
2865   v8::HandleScope scope;
2866 
2867   LocalContext env0;
2868   v8::Handle<v8::Object> global0 =
2869       env0->Global();
2870   v8::Handle<v8::Object> object0 =
2871       v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
2872   v8::Handle<v8::Object> tostring0 =
2873       v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
2874   v8::Handle<v8::Object> proto0 =
2875       v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
2876   proto0->Set(v8_str("custom"), v8_num(1234));
2877 
2878   LocalContext env1;
2879   v8::Handle<v8::Object> global1 =
2880       env1->Global();
2881   v8::Handle<v8::Object> object1 =
2882       v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
2883   v8::Handle<v8::Object> tostring1 =
2884       v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
2885   v8::Handle<v8::Object> proto1 =
2886       v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
2887   CHECK(!proto1->Has(v8_str("custom")));
2888 }
2889 
2890 
THREADED_TEST(Regress892105)2891 THREADED_TEST(Regress892105) {
2892   // Make sure that object and array literals created by cloning
2893   // boilerplates cannot communicate through their __proto__
2894   // field. This is rather difficult to check, but we try to add stuff
2895   // to Object.prototype and Array.prototype and create a new
2896   // environment. This should succeed.
2897 
2898   v8::HandleScope scope;
2899 
2900   Local<String> source = v8_str("Object.prototype.obj = 1234;"
2901                                 "Array.prototype.arr = 4567;"
2902                                 "8901");
2903 
2904   LocalContext env0;
2905   Local<Script> script0 = Script::Compile(source);
2906   CHECK_EQ(8901.0, script0->Run()->NumberValue());
2907 
2908   LocalContext env1;
2909   Local<Script> script1 = Script::Compile(source);
2910   CHECK_EQ(8901.0, script1->Run()->NumberValue());
2911 }
2912 
2913 
THREADED_TEST(UndetectableObject)2914 THREADED_TEST(UndetectableObject) {
2915   v8::HandleScope scope;
2916   LocalContext env;
2917 
2918   Local<v8::FunctionTemplate> desc =
2919       v8::FunctionTemplate::New(0, v8::Handle<Value>());
2920   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
2921 
2922   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
2923   env->Global()->Set(v8_str("undetectable"), obj);
2924 
2925   ExpectString("undetectable.toString()", "[object Object]");
2926   ExpectString("typeof undetectable", "undefined");
2927   ExpectString("typeof(undetectable)", "undefined");
2928   ExpectBoolean("typeof undetectable == 'undefined'", true);
2929   ExpectBoolean("typeof undetectable == 'object'", false);
2930   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2931   ExpectBoolean("!undetectable", true);
2932 
2933   ExpectObject("true&&undetectable", obj);
2934   ExpectBoolean("false&&undetectable", false);
2935   ExpectBoolean("true||undetectable", true);
2936   ExpectObject("false||undetectable", obj);
2937 
2938   ExpectObject("undetectable&&true", obj);
2939   ExpectObject("undetectable&&false", obj);
2940   ExpectBoolean("undetectable||true", true);
2941   ExpectBoolean("undetectable||false", false);
2942 
2943   ExpectBoolean("undetectable==null", true);
2944   ExpectBoolean("null==undetectable", true);
2945   ExpectBoolean("undetectable==undefined", true);
2946   ExpectBoolean("undefined==undetectable", true);
2947   ExpectBoolean("undetectable==undetectable", true);
2948 
2949 
2950   ExpectBoolean("undetectable===null", false);
2951   ExpectBoolean("null===undetectable", false);
2952   ExpectBoolean("undetectable===undefined", false);
2953   ExpectBoolean("undefined===undetectable", false);
2954   ExpectBoolean("undetectable===undetectable", true);
2955 }
2956 
2957 
THREADED_TEST(UndetectableString)2958 THREADED_TEST(UndetectableString) {
2959   v8::HandleScope scope;
2960   LocalContext env;
2961 
2962   Local<String> obj = String::NewUndetectable("foo");
2963   env->Global()->Set(v8_str("undetectable"), obj);
2964 
2965   ExpectString("undetectable", "foo");
2966   ExpectString("typeof undetectable", "undefined");
2967   ExpectString("typeof(undetectable)", "undefined");
2968   ExpectBoolean("typeof undetectable == 'undefined'", true);
2969   ExpectBoolean("typeof undetectable == 'string'", false);
2970   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2971   ExpectBoolean("!undetectable", true);
2972 
2973   ExpectObject("true&&undetectable", obj);
2974   ExpectBoolean("false&&undetectable", false);
2975   ExpectBoolean("true||undetectable", true);
2976   ExpectObject("false||undetectable", obj);
2977 
2978   ExpectObject("undetectable&&true", obj);
2979   ExpectObject("undetectable&&false", obj);
2980   ExpectBoolean("undetectable||true", true);
2981   ExpectBoolean("undetectable||false", false);
2982 
2983   ExpectBoolean("undetectable==null", true);
2984   ExpectBoolean("null==undetectable", true);
2985   ExpectBoolean("undetectable==undefined", true);
2986   ExpectBoolean("undefined==undetectable", true);
2987   ExpectBoolean("undetectable==undetectable", true);
2988 
2989 
2990   ExpectBoolean("undetectable===null", false);
2991   ExpectBoolean("null===undetectable", false);
2992   ExpectBoolean("undetectable===undefined", false);
2993   ExpectBoolean("undefined===undetectable", false);
2994   ExpectBoolean("undetectable===undetectable", true);
2995 }
2996 
2997 
USE(T)2998 template <typename T> static void USE(T) { }
2999 
3000 
3001 // This test is not intended to be run, just type checked.
PersistentHandles()3002 static void PersistentHandles() {
3003   USE(PersistentHandles);
3004   Local<String> str = v8_str("foo");
3005   v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
3006   USE(p_str);
3007   Local<Script> scr = Script::Compile(v8_str(""));
3008   v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
3009   USE(p_scr);
3010   Local<ObjectTemplate> templ = ObjectTemplate::New();
3011   v8::Persistent<ObjectTemplate> p_templ =
3012     v8::Persistent<ObjectTemplate>::New(templ);
3013   USE(p_templ);
3014 }
3015 
3016 
HandleLogDelegator(const v8::Arguments & args)3017 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
3018   ApiTestFuzzer::Fuzz();
3019   return v8::Undefined();
3020 }
3021 
3022 
THREADED_TEST(GlobalObjectTemplate)3023 THREADED_TEST(GlobalObjectTemplate) {
3024   v8::HandleScope handle_scope;
3025   Local<ObjectTemplate> global_template = ObjectTemplate::New();
3026   global_template->Set(v8_str("JSNI_Log"),
3027                        v8::FunctionTemplate::New(HandleLogDelegator));
3028   v8::Persistent<Context> context = Context::New(0, global_template);
3029   Context::Scope context_scope(context);
3030   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
3031   context.Dispose();
3032 }
3033 
3034 
3035 static const char* kSimpleExtensionSource =
3036   "function Foo() {"
3037   "  return 4;"
3038   "}";
3039 
3040 
THREADED_TEST(SimpleExtensions)3041 THREADED_TEST(SimpleExtensions) {
3042   v8::HandleScope handle_scope;
3043   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
3044   const char* extension_names[] = { "simpletest" };
3045   v8::ExtensionConfiguration extensions(1, extension_names);
3046   v8::Handle<Context> context = Context::New(&extensions);
3047   Context::Scope lock(context);
3048   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3049   CHECK_EQ(result, v8::Integer::New(4));
3050 }
3051 
3052 
3053 static const char* kEvalExtensionSource1 =
3054   "function UseEval1() {"
3055   "  var x = 42;"
3056   "  return eval('x');"
3057   "}";
3058 
3059 
3060 static const char* kEvalExtensionSource2 =
3061   "(function() {"
3062   "  var x = 42;"
3063   "  function e() {"
3064   "    return eval('x');"
3065   "  }"
3066   "  this.UseEval2 = e;"
3067   "})()";
3068 
3069 
THREADED_TEST(UseEvalFromExtension)3070 THREADED_TEST(UseEvalFromExtension) {
3071   v8::HandleScope handle_scope;
3072   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
3073   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
3074   const char* extension_names[] = { "evaltest1", "evaltest2" };
3075   v8::ExtensionConfiguration extensions(2, extension_names);
3076   v8::Handle<Context> context = Context::New(&extensions);
3077   Context::Scope lock(context);
3078   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
3079   CHECK_EQ(result, v8::Integer::New(42));
3080   result = Script::Compile(v8_str("UseEval2()"))->Run();
3081   CHECK_EQ(result, v8::Integer::New(42));
3082 }
3083 
3084 
3085 static const char* kWithExtensionSource1 =
3086   "function UseWith1() {"
3087   "  var x = 42;"
3088   "  with({x:87}) { return x; }"
3089   "}";
3090 
3091 
3092 
3093 static const char* kWithExtensionSource2 =
3094   "(function() {"
3095   "  var x = 42;"
3096   "  function e() {"
3097   "    with ({x:87}) { return x; }"
3098   "  }"
3099   "  this.UseWith2 = e;"
3100   "})()";
3101 
3102 
THREADED_TEST(UseWithFromExtension)3103 THREADED_TEST(UseWithFromExtension) {
3104   v8::HandleScope handle_scope;
3105   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
3106   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
3107   const char* extension_names[] = { "withtest1", "withtest2" };
3108   v8::ExtensionConfiguration extensions(2, extension_names);
3109   v8::Handle<Context> context = Context::New(&extensions);
3110   Context::Scope lock(context);
3111   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
3112   CHECK_EQ(result, v8::Integer::New(87));
3113   result = Script::Compile(v8_str("UseWith2()"))->Run();
3114   CHECK_EQ(result, v8::Integer::New(87));
3115 }
3116 
3117 
THREADED_TEST(AutoExtensions)3118 THREADED_TEST(AutoExtensions) {
3119   v8::HandleScope handle_scope;
3120   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
3121   extension->set_auto_enable(true);
3122   v8::RegisterExtension(extension);
3123   v8::Handle<Context> context = Context::New();
3124   Context::Scope lock(context);
3125   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
3126   CHECK_EQ(result, v8::Integer::New(4));
3127 }
3128 
3129 
3130 static const char* kSyntaxErrorInExtensionSource =
3131     "[";
3132 
3133 
3134 // Test that a syntax error in an extension does not cause a fatal
3135 // error but results in an empty context.
THREADED_TEST(SyntaxErrorExtensions)3136 THREADED_TEST(SyntaxErrorExtensions) {
3137   v8::HandleScope handle_scope;
3138   v8::RegisterExtension(new Extension("syntaxerror",
3139                                       kSyntaxErrorInExtensionSource));
3140   const char* extension_names[] = { "syntaxerror" };
3141   v8::ExtensionConfiguration extensions(1, extension_names);
3142   v8::Handle<Context> context = Context::New(&extensions);
3143   CHECK(context.IsEmpty());
3144 }
3145 
3146 
3147 static const char* kExceptionInExtensionSource =
3148     "throw 42";
3149 
3150 
3151 // Test that an exception when installing an extension does not cause
3152 // a fatal error but results in an empty context.
THREADED_TEST(ExceptionExtensions)3153 THREADED_TEST(ExceptionExtensions) {
3154   v8::HandleScope handle_scope;
3155   v8::RegisterExtension(new Extension("exception",
3156                                       kExceptionInExtensionSource));
3157   const char* extension_names[] = { "exception" };
3158   v8::ExtensionConfiguration extensions(1, extension_names);
3159   v8::Handle<Context> context = Context::New(&extensions);
3160   CHECK(context.IsEmpty());
3161 }
3162 
3163 
CheckDependencies(const char * name,const char * expected)3164 static void CheckDependencies(const char* name, const char* expected) {
3165   v8::HandleScope handle_scope;
3166   v8::ExtensionConfiguration config(1, &name);
3167   LocalContext context(&config);
3168   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
3169 }
3170 
3171 
3172 /*
3173  * Configuration:
3174  *
3175  *     /-- B <--\
3176  * A <-          -- D <-- E
3177  *     \-- C <--/
3178  */
THREADED_TEST(ExtensionDependency)3179 THREADED_TEST(ExtensionDependency) {
3180   static const char* kEDeps[] = { "D" };
3181   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
3182   static const char* kDDeps[] = { "B", "C" };
3183   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
3184   static const char* kBCDeps[] = { "A" };
3185   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
3186   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
3187   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
3188   CheckDependencies("A", "undefinedA");
3189   CheckDependencies("B", "undefinedAB");
3190   CheckDependencies("C", "undefinedAC");
3191   CheckDependencies("D", "undefinedABCD");
3192   CheckDependencies("E", "undefinedABCDE");
3193   v8::HandleScope handle_scope;
3194   static const char* exts[2] = { "C", "E" };
3195   v8::ExtensionConfiguration config(2, exts);
3196   LocalContext context(&config);
3197   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
3198 }
3199 
3200 
3201 static const char* kExtensionTestScript =
3202   "native function A();"
3203   "native function B();"
3204   "native function C();"
3205   "function Foo(i) {"
3206   "  if (i == 0) return A();"
3207   "  if (i == 1) return B();"
3208   "  if (i == 2) return C();"
3209   "}";
3210 
3211 
CallFun(const v8::Arguments & args)3212 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
3213   ApiTestFuzzer::Fuzz();
3214   if (args.IsConstructCall()) {
3215     args.This()->Set(v8_str("data"), args.Data());
3216     return v8::Null();
3217   }
3218   return args.Data();
3219 }
3220 
3221 
3222 class FunctionExtension : public Extension {
3223  public:
FunctionExtension()3224   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
3225   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
3226       v8::Handle<String> name);
3227 };
3228 
3229 
3230 static int lookup_count = 0;
GetNativeFunction(v8::Handle<String> name)3231 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
3232       v8::Handle<String> name) {
3233   lookup_count++;
3234   if (name->Equals(v8_str("A"))) {
3235     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
3236   } else if (name->Equals(v8_str("B"))) {
3237     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
3238   } else if (name->Equals(v8_str("C"))) {
3239     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
3240   } else {
3241     return v8::Handle<v8::FunctionTemplate>();
3242   }
3243 }
3244 
3245 
THREADED_TEST(FunctionLookup)3246 THREADED_TEST(FunctionLookup) {
3247   v8::RegisterExtension(new FunctionExtension());
3248   v8::HandleScope handle_scope;
3249   static const char* exts[1] = { "functiontest" };
3250   v8::ExtensionConfiguration config(1, exts);
3251   LocalContext context(&config);
3252   CHECK_EQ(3, lookup_count);
3253   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
3254   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
3255   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
3256 }
3257 
3258 
THREADED_TEST(NativeFunctionConstructCall)3259 THREADED_TEST(NativeFunctionConstructCall) {
3260   v8::RegisterExtension(new FunctionExtension());
3261   v8::HandleScope handle_scope;
3262   static const char* exts[1] = { "functiontest" };
3263   v8::ExtensionConfiguration config(1, exts);
3264   LocalContext context(&config);
3265   for (int i = 0; i < 10; i++) {
3266     // Run a few times to ensure that allocation of objects doesn't
3267     // change behavior of a constructor function.
3268     CHECK_EQ(v8::Integer::New(8),
3269              Script::Compile(v8_str("(new A()).data"))->Run());
3270     CHECK_EQ(v8::Integer::New(7),
3271              Script::Compile(v8_str("(new B()).data"))->Run());
3272     CHECK_EQ(v8::Integer::New(6),
3273              Script::Compile(v8_str("(new C()).data"))->Run());
3274   }
3275 }
3276 
3277 
3278 static const char* last_location;
3279 static const char* last_message;
StoringErrorCallback(const char * location,const char * message)3280 void StoringErrorCallback(const char* location, const char* message) {
3281   if (last_location == NULL) {
3282     last_location = location;
3283     last_message = message;
3284   }
3285 }
3286 
3287 
3288 // ErrorReporting creates a circular extensions configuration and
3289 // tests that the fatal error handler gets called.  This renders V8
3290 // unusable and therefore this test cannot be run in parallel.
TEST(ErrorReporting)3291 TEST(ErrorReporting) {
3292   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
3293   static const char* aDeps[] = { "B" };
3294   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
3295   static const char* bDeps[] = { "A" };
3296   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
3297   last_location = NULL;
3298   v8::ExtensionConfiguration config(1, bDeps);
3299   v8::Handle<Context> context = Context::New(&config);
3300   CHECK(context.IsEmpty());
3301   CHECK_NE(last_location, NULL);
3302 }
3303 
3304 
3305 static const char* js_code_causing_huge_string_flattening =
3306     "var str = 'X';"
3307     "for (var i = 0; i < 30; i++) {"
3308     "  str = str + str;"
3309     "}"
3310     "str.match(/X/);";
3311 
3312 
OOMCallback(const char * location,const char * message)3313 void OOMCallback(const char* location, const char* message) {
3314   exit(0);
3315 }
3316 
3317 
TEST(RegexpOutOfMemory)3318 TEST(RegexpOutOfMemory) {
3319   // Execute a script that causes out of memory when flattening a string.
3320   v8::HandleScope scope;
3321   v8::V8::SetFatalErrorHandler(OOMCallback);
3322   LocalContext context;
3323   Local<Script> script =
3324       Script::Compile(String::New(js_code_causing_huge_string_flattening));
3325   last_location = NULL;
3326   Local<Value> result = script->Run();
3327 
3328   CHECK(false);  // Should not return.
3329 }
3330 
3331 
MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,v8::Handle<Value> data)3332 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
3333                                              v8::Handle<Value> data) {
3334   CHECK_EQ(v8::Undefined(), data);
3335   CHECK(message->GetScriptResourceName()->IsUndefined());
3336   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
3337   message->GetLineNumber();
3338   message->GetSourceLine();
3339 }
3340 
3341 
THREADED_TEST(ErrorWithMissingScriptInfo)3342 THREADED_TEST(ErrorWithMissingScriptInfo) {
3343   v8::HandleScope scope;
3344   LocalContext context;
3345   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
3346   Script::Compile(v8_str("throw Error()"))->Run();
3347   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
3348 }
3349 
3350 
3351 int global_index = 0;
3352 
3353 class Snorkel {
3354  public:
Snorkel()3355   Snorkel() { index_ = global_index++; }
3356   int index_;
3357 };
3358 
3359 class Whammy {
3360  public:
Whammy()3361   Whammy() {
3362     cursor_ = 0;
3363   }
~Whammy()3364   ~Whammy() {
3365     script_.Dispose();
3366   }
getScript()3367   v8::Handle<Script> getScript() {
3368     if (script_.IsEmpty())
3369       script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
3370     return Local<Script>(*script_);
3371   }
3372 
3373  public:
3374   static const int kObjectCount = 256;
3375   int cursor_;
3376   v8::Persistent<v8::Object> objects_[kObjectCount];
3377   v8::Persistent<Script> script_;
3378 };
3379 
HandleWeakReference(v8::Persistent<v8::Value> obj,void * data)3380 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
3381   Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
3382   delete snorkel;
3383   obj.ClearWeak();
3384 }
3385 
WhammyPropertyGetter(Local<String> name,const AccessorInfo & info)3386 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
3387                                        const AccessorInfo& info) {
3388   Whammy* whammy =
3389     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
3390 
3391   v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
3392 
3393   v8::Handle<v8::Object> obj = v8::Object::New();
3394   v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
3395   if (!prev.IsEmpty()) {
3396     prev->Set(v8_str("next"), obj);
3397     prev.MakeWeak(new Snorkel(), &HandleWeakReference);
3398     whammy->objects_[whammy->cursor_].Clear();
3399   }
3400   whammy->objects_[whammy->cursor_] = global;
3401   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
3402   return whammy->getScript()->Run();
3403 }
3404 
THREADED_TEST(WeakReference)3405 THREADED_TEST(WeakReference) {
3406   v8::HandleScope handle_scope;
3407   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
3408   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
3409                                  0, 0, 0, 0,
3410                                  v8::External::New(new Whammy()));
3411   const char* extension_list[] = { "v8/gc" };
3412   v8::ExtensionConfiguration extensions(1, extension_list);
3413   v8::Persistent<Context> context = Context::New(&extensions);
3414   Context::Scope context_scope(context);
3415 
3416   v8::Handle<v8::Object> interceptor = templ->NewInstance();
3417   context->Global()->Set(v8_str("whammy"), interceptor);
3418   const char* code =
3419       "var last;"
3420       "for (var i = 0; i < 10000; i++) {"
3421       "  var obj = whammy.length;"
3422       "  if (last) last.next = obj;"
3423       "  last = obj;"
3424       "}"
3425       "gc();"
3426       "4";
3427   v8::Handle<Value> result = CompileRun(code);
3428   CHECK_EQ(4.0, result->NumberValue());
3429 
3430   context.Dispose();
3431 }
3432 
3433 
3434 static bool in_scavenge = false;
3435 static int last = -1;
3436 
ForceScavenge(v8::Persistent<v8::Value> obj,void * data)3437 static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) {
3438   CHECK_EQ(-1, last);
3439   last = 0;
3440   obj.Dispose();
3441   obj.Clear();
3442   in_scavenge = true;
3443   i::Heap::PerformScavenge();
3444   in_scavenge = false;
3445   *(reinterpret_cast<bool*>(data)) = true;
3446 }
3447 
CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,void * data)3448 static void CheckIsNotInvokedInScavenge(v8::Persistent<v8::Value> obj,
3449                                         void* data) {
3450   CHECK_EQ(0, last);
3451   last = 1;
3452   *(reinterpret_cast<bool*>(data)) = in_scavenge;
3453   obj.Dispose();
3454   obj.Clear();
3455 }
3456 
THREADED_TEST(NoWeakRefCallbacksInScavenge)3457 THREADED_TEST(NoWeakRefCallbacksInScavenge) {
3458   // Test verifies that scavenge cannot invoke WeakReferenceCallbacks.
3459   // Calling callbacks from scavenges is unsafe as objects held by those
3460   // handlers might have become strongly reachable, but scavenge doesn't
3461   // check that.
3462   v8::Persistent<Context> context = Context::New();
3463   Context::Scope context_scope(context);
3464 
3465   v8::Persistent<v8::Object> object_a;
3466   v8::Persistent<v8::Object> object_b;
3467 
3468   {
3469     v8::HandleScope handle_scope;
3470     object_b = v8::Persistent<v8::Object>::New(v8::Object::New());
3471     object_a = v8::Persistent<v8::Object>::New(v8::Object::New());
3472   }
3473 
3474   bool object_a_disposed = false;
3475   object_a.MakeWeak(&object_a_disposed, &ForceScavenge);
3476   bool released_in_scavenge = false;
3477   object_b.MakeWeak(&released_in_scavenge, &CheckIsNotInvokedInScavenge);
3478 
3479   while (!object_a_disposed) {
3480     i::Heap::CollectAllGarbage(false);
3481   }
3482   CHECK(!released_in_scavenge);
3483 }
3484 
3485 
3486 v8::Handle<Function> args_fun;
3487 
3488 
ArgumentsTestCallback(const v8::Arguments & args)3489 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3490   ApiTestFuzzer::Fuzz();
3491   CHECK_EQ(args_fun, args.Callee());
3492   CHECK_EQ(3, args.Length());
3493   CHECK_EQ(v8::Integer::New(1), args[0]);
3494   CHECK_EQ(v8::Integer::New(2), args[1]);
3495   CHECK_EQ(v8::Integer::New(3), args[2]);
3496   CHECK_EQ(v8::Undefined(), args[3]);
3497   v8::HandleScope scope;
3498   i::Heap::CollectAllGarbage(false);
3499   return v8::Undefined();
3500 }
3501 
3502 
THREADED_TEST(Arguments)3503 THREADED_TEST(Arguments) {
3504   v8::HandleScope scope;
3505   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3506   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3507   LocalContext context(NULL, global);
3508   args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
3509   v8_compile("f(1, 2, 3)")->Run();
3510 }
3511 
3512 
NoBlockGetterX(Local<String> name,const AccessorInfo &)3513 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3514                                         const AccessorInfo&) {
3515   return v8::Handle<Value>();
3516 }
3517 
3518 
NoBlockGetterI(uint32_t index,const AccessorInfo &)3519 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3520                                         const AccessorInfo&) {
3521   return v8::Handle<Value>();
3522 }
3523 
3524 
PDeleter(Local<String> name,const AccessorInfo &)3525 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3526                                         const AccessorInfo&) {
3527   if (!name->Equals(v8_str("foo"))) {
3528     return v8::Handle<v8::Boolean>();  // not intercepted
3529   }
3530 
3531   return v8::False();  // intercepted, and don't delete the property
3532 }
3533 
3534 
IDeleter(uint32_t index,const AccessorInfo &)3535 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3536   if (index != 2) {
3537     return v8::Handle<v8::Boolean>();  // not intercepted
3538   }
3539 
3540   return v8::False();  // intercepted, and don't delete the property
3541 }
3542 
3543 
THREADED_TEST(Deleter)3544 THREADED_TEST(Deleter) {
3545   v8::HandleScope scope;
3546   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3547   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3548   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3549   LocalContext context;
3550   context->Global()->Set(v8_str("k"), obj->NewInstance());
3551   CompileRun(
3552     "k.foo = 'foo';"
3553     "k.bar = 'bar';"
3554     "k[2] = 2;"
3555     "k[4] = 4;");
3556   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3557   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3558 
3559   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3560   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3561 
3562   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3563   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3564 
3565   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3566   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3567 }
3568 
3569 
GetK(Local<String> name,const AccessorInfo &)3570 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3571   ApiTestFuzzer::Fuzz();
3572   if (name->Equals(v8_str("foo")) ||
3573       name->Equals(v8_str("bar")) ||
3574       name->Equals(v8_str("baz"))) {
3575     return v8::Undefined();
3576   }
3577   return v8::Handle<Value>();
3578 }
3579 
3580 
IndexedGetK(uint32_t index,const AccessorInfo &)3581 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3582   ApiTestFuzzer::Fuzz();
3583   if (index == 0 || index == 1) return v8::Undefined();
3584   return v8::Handle<Value>();
3585 }
3586 
3587 
NamedEnum(const AccessorInfo &)3588 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3589   ApiTestFuzzer::Fuzz();
3590   v8::Handle<v8::Array> result = v8::Array::New(3);
3591   result->Set(v8::Integer::New(0), v8_str("foo"));
3592   result->Set(v8::Integer::New(1), v8_str("bar"));
3593   result->Set(v8::Integer::New(2), v8_str("baz"));
3594   return result;
3595 }
3596 
3597 
IndexedEnum(const AccessorInfo &)3598 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3599   ApiTestFuzzer::Fuzz();
3600   v8::Handle<v8::Array> result = v8::Array::New(2);
3601   result->Set(v8::Integer::New(0), v8_str("0"));
3602   result->Set(v8::Integer::New(1), v8_str("1"));
3603   return result;
3604 }
3605 
3606 
THREADED_TEST(Enumerators)3607 THREADED_TEST(Enumerators) {
3608   v8::HandleScope scope;
3609   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3610   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3611   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3612   LocalContext context;
3613   context->Global()->Set(v8_str("k"), obj->NewInstance());
3614   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3615     "k[10] = 0;"
3616     "k.a = 0;"
3617     "k[5] = 0;"
3618     "k.b = 0;"
3619     "k[4294967295] = 0;"
3620     "k.c = 0;"
3621     "k[4294967296] = 0;"
3622     "k.d = 0;"
3623     "k[140000] = 0;"
3624     "k.e = 0;"
3625     "k[30000000000] = 0;"
3626     "k.f = 0;"
3627     "var result = [];"
3628     "for (var prop in k) {"
3629     "  result.push(prop);"
3630     "}"
3631     "result"));
3632   // Check that we get all the property names returned including the
3633   // ones from the enumerators in the right order: indexed properties
3634   // in numerical order, indexed interceptor properties, named
3635   // properties in insertion order, named interceptor properties.
3636   // This order is not mandated by the spec, so this test is just
3637   // documenting our behavior.
3638   CHECK_EQ(17, result->Length());
3639   // Indexed properties in numerical order.
3640   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3641   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3642   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3643   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3644   // Indexed interceptor properties in the order they are returned
3645   // from the enumerator interceptor.
3646   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3647   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3648   // Named properties in insertion order.
3649   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3650   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3651   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3652   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3653   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3654   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3655   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3656   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3657   // Named interceptor properties.
3658   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3659   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3660   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
3661 }
3662 
3663 
3664 int p_getter_count;
3665 int p_getter_count2;
3666 
3667 
PGetter(Local<String> name,const AccessorInfo & info)3668 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3669   ApiTestFuzzer::Fuzz();
3670   p_getter_count++;
3671   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3672   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3673   if (name->Equals(v8_str("p1"))) {
3674     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3675   } else if (name->Equals(v8_str("p2"))) {
3676     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3677   } else if (name->Equals(v8_str("p3"))) {
3678     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3679   } else if (name->Equals(v8_str("p4"))) {
3680     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3681   }
3682   return v8::Undefined();
3683 }
3684 
3685 
RunHolderTest(v8::Handle<v8::ObjectTemplate> obj)3686 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
3687   ApiTestFuzzer::Fuzz();
3688   LocalContext context;
3689   context->Global()->Set(v8_str("o1"), obj->NewInstance());
3690   CompileRun(
3691     "o1.__proto__ = { };"
3692     "var o2 = { __proto__: o1 };"
3693     "var o3 = { __proto__: o2 };"
3694     "var o4 = { __proto__: o3 };"
3695     "for (var i = 0; i < 10; i++) o4.p4;"
3696     "for (var i = 0; i < 10; i++) o3.p3;"
3697     "for (var i = 0; i < 10; i++) o2.p2;"
3698     "for (var i = 0; i < 10; i++) o1.p1;");
3699 }
3700 
3701 
PGetter2(Local<String> name,const AccessorInfo & info)3702 static v8::Handle<Value> PGetter2(Local<String> name,
3703                                   const AccessorInfo& info) {
3704   ApiTestFuzzer::Fuzz();
3705   p_getter_count2++;
3706   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3707   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3708   if (name->Equals(v8_str("p1"))) {
3709     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3710   } else if (name->Equals(v8_str("p2"))) {
3711     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3712   } else if (name->Equals(v8_str("p3"))) {
3713     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3714   } else if (name->Equals(v8_str("p4"))) {
3715     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3716   }
3717   return v8::Undefined();
3718 }
3719 
3720 
THREADED_TEST(GetterHolders)3721 THREADED_TEST(GetterHolders) {
3722   v8::HandleScope scope;
3723   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3724   obj->SetAccessor(v8_str("p1"), PGetter);
3725   obj->SetAccessor(v8_str("p2"), PGetter);
3726   obj->SetAccessor(v8_str("p3"), PGetter);
3727   obj->SetAccessor(v8_str("p4"), PGetter);
3728   p_getter_count = 0;
3729   RunHolderTest(obj);
3730   CHECK_EQ(40, p_getter_count);
3731 }
3732 
3733 
THREADED_TEST(PreInterceptorHolders)3734 THREADED_TEST(PreInterceptorHolders) {
3735   v8::HandleScope scope;
3736   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3737   obj->SetNamedPropertyHandler(PGetter2);
3738   p_getter_count2 = 0;
3739   RunHolderTest(obj);
3740   CHECK_EQ(40, p_getter_count2);
3741 }
3742 
3743 
THREADED_TEST(ObjectInstantiation)3744 THREADED_TEST(ObjectInstantiation) {
3745   v8::HandleScope scope;
3746   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
3747   templ->SetAccessor(v8_str("t"), PGetter2);
3748   LocalContext context;
3749   context->Global()->Set(v8_str("o"), templ->NewInstance());
3750   for (int i = 0; i < 100; i++) {
3751     v8::HandleScope inner_scope;
3752     v8::Handle<v8::Object> obj = templ->NewInstance();
3753     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
3754     context->Global()->Set(v8_str("o2"), obj);
3755     v8::Handle<Value> value =
3756         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
3757     CHECK_EQ(v8::True(), value);
3758     context->Global()->Set(v8_str("o"), obj);
3759   }
3760 }
3761 
3762 
THREADED_TEST(StringWrite)3763 THREADED_TEST(StringWrite) {
3764   v8::HandleScope scope;
3765   v8::Handle<String> str = v8_str("abcde");
3766 
3767   char buf[100];
3768   int len;
3769 
3770   memset(buf, 0x1, sizeof(buf));
3771   len = str->WriteAscii(buf);
3772   CHECK_EQ(len, 5);
3773   CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3774 
3775   memset(buf, 0x1, sizeof(buf));
3776   len = str->WriteAscii(buf, 0, 4);
3777   CHECK_EQ(len, 4);
3778   CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
3779 
3780   memset(buf, 0x1, sizeof(buf));
3781   len = str->WriteAscii(buf, 0, 5);
3782   CHECK_EQ(len, 5);
3783   CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
3784 
3785   memset(buf, 0x1, sizeof(buf));
3786   len = str->WriteAscii(buf, 0, 6);
3787   CHECK_EQ(len, 5);
3788   CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3789 
3790   memset(buf, 0x1, sizeof(buf));
3791   len = str->WriteAscii(buf, 4, -1);
3792   CHECK_EQ(len, 1);
3793   CHECK_EQ(strncmp("e\0", buf, 2), 0);
3794 
3795   memset(buf, 0x1, sizeof(buf));
3796   len = str->WriteAscii(buf, 4, 6);
3797   CHECK_EQ(len, 1);
3798   CHECK_EQ(strncmp("e\0", buf, 2), 0);
3799 
3800   memset(buf, 0x1, sizeof(buf));
3801   len = str->WriteAscii(buf, 4, 1);
3802   CHECK_EQ(len, 1);
3803   CHECK_EQ(strncmp("e\1", buf, 2), 0);
3804 }
3805 
3806 
THREADED_TEST(ToArrayIndex)3807 THREADED_TEST(ToArrayIndex) {
3808   v8::HandleScope scope;
3809   LocalContext context;
3810 
3811   v8::Handle<String> str = v8_str("42");
3812   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
3813   CHECK(!index.IsEmpty());
3814   CHECK_EQ(42.0, index->Uint32Value());
3815   str = v8_str("42asdf");
3816   index = str->ToArrayIndex();
3817   CHECK(index.IsEmpty());
3818   str = v8_str("-42");
3819   index = str->ToArrayIndex();
3820   CHECK(index.IsEmpty());
3821   str = v8_str("4294967295");
3822   index = str->ToArrayIndex();
3823   CHECK(!index.IsEmpty());
3824   CHECK_EQ(4294967295.0, index->Uint32Value());
3825   v8::Handle<v8::Number> num = v8::Number::New(1);
3826   index = num->ToArrayIndex();
3827   CHECK(!index.IsEmpty());
3828   CHECK_EQ(1.0, index->Uint32Value());
3829   num = v8::Number::New(-1);
3830   index = num->ToArrayIndex();
3831   CHECK(index.IsEmpty());
3832   v8::Handle<v8::Object> obj = v8::Object::New();
3833   index = obj->ToArrayIndex();
3834   CHECK(index.IsEmpty());
3835 }
3836 
3837 
THREADED_TEST(ErrorConstruction)3838 THREADED_TEST(ErrorConstruction) {
3839   v8::HandleScope scope;
3840   LocalContext context;
3841 
3842   v8::Handle<String> foo = v8_str("foo");
3843   v8::Handle<String> message = v8_str("message");
3844   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
3845   CHECK(range_error->IsObject());
3846   v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
3847   CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
3848   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
3849   CHECK(reference_error->IsObject());
3850   CHECK(
3851       v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
3852   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
3853   CHECK(syntax_error->IsObject());
3854   CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
3855   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
3856   CHECK(type_error->IsObject());
3857   CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
3858   v8::Handle<Value> error = v8::Exception::Error(foo);
3859   CHECK(error->IsObject());
3860   CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
3861 }
3862 
3863 
YGetter(Local<String> name,const AccessorInfo & info)3864 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
3865   ApiTestFuzzer::Fuzz();
3866   return v8_num(10);
3867 }
3868 
3869 
YSetter(Local<String> name,Local<Value> value,const AccessorInfo & info)3870 static void YSetter(Local<String> name,
3871                     Local<Value> value,
3872                     const AccessorInfo& info) {
3873   if (info.This()->Has(name)) {
3874     info.This()->Delete(name);
3875   }
3876   info.This()->Set(name, value);
3877 }
3878 
3879 
THREADED_TEST(DeleteAccessor)3880 THREADED_TEST(DeleteAccessor) {
3881   v8::HandleScope scope;
3882   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3883   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
3884   LocalContext context;
3885   v8::Handle<v8::Object> holder = obj->NewInstance();
3886   context->Global()->Set(v8_str("holder"), holder);
3887   v8::Handle<Value> result = CompileRun(
3888       "holder.y = 11; holder.y = 12; holder.y");
3889   CHECK_EQ(12, result->Uint32Value());
3890 }
3891 
3892 
THREADED_TEST(TypeSwitch)3893 THREADED_TEST(TypeSwitch) {
3894   v8::HandleScope scope;
3895   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
3896   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
3897   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
3898   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
3899   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
3900   LocalContext context;
3901   v8::Handle<v8::Object> obj0 = v8::Object::New();
3902   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
3903   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
3904   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
3905   for (int i = 0; i < 10; i++) {
3906     CHECK_EQ(0, type_switch->match(obj0));
3907     CHECK_EQ(1, type_switch->match(obj1));
3908     CHECK_EQ(2, type_switch->match(obj2));
3909     CHECK_EQ(3, type_switch->match(obj3));
3910     CHECK_EQ(3, type_switch->match(obj3));
3911     CHECK_EQ(2, type_switch->match(obj2));
3912     CHECK_EQ(1, type_switch->match(obj1));
3913     CHECK_EQ(0, type_switch->match(obj0));
3914   }
3915 }
3916 
3917 
3918 // For use within the TestSecurityHandler() test.
3919 static bool g_security_callback_result = false;
NamedSecurityTestCallback(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)3920 static bool NamedSecurityTestCallback(Local<v8::Object> global,
3921                                       Local<Value> name,
3922                                       v8::AccessType type,
3923                                       Local<Value> data) {
3924   // Always allow read access.
3925   if (type == v8::ACCESS_GET)
3926     return true;
3927 
3928   // Sometimes allow other access.
3929   return g_security_callback_result;
3930 }
3931 
3932 
IndexedSecurityTestCallback(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)3933 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
3934                                         uint32_t key,
3935                                         v8::AccessType type,
3936                                         Local<Value> data) {
3937   // Always allow read access.
3938   if (type == v8::ACCESS_GET)
3939     return true;
3940 
3941   // Sometimes allow other access.
3942   return g_security_callback_result;
3943 }
3944 
3945 
3946 static int trouble_nesting = 0;
TroubleCallback(const v8::Arguments & args)3947 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
3948   ApiTestFuzzer::Fuzz();
3949   trouble_nesting++;
3950 
3951   // Call a JS function that throws an uncaught exception.
3952   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
3953   Local<Value> trouble_callee = (trouble_nesting == 3) ?
3954     arg_this->Get(v8_str("trouble_callee")) :
3955     arg_this->Get(v8_str("trouble_caller"));
3956   CHECK(trouble_callee->IsFunction());
3957   return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
3958 }
3959 
3960 
3961 static int report_count = 0;
ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,v8::Handle<Value>)3962 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
3963                                              v8::Handle<Value>) {
3964   report_count++;
3965 }
3966 
3967 
3968 // Counts uncaught exceptions, but other tests running in parallel
3969 // also have uncaught exceptions.
TEST(ApiUncaughtException)3970 TEST(ApiUncaughtException) {
3971   report_count = 0;
3972   v8::HandleScope scope;
3973   LocalContext env;
3974   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
3975 
3976   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
3977   v8::Local<v8::Object> global = env->Global();
3978   global->Set(v8_str("trouble"), fun->GetFunction());
3979 
3980   Script::Compile(v8_str("function trouble_callee() {"
3981                          "  var x = null;"
3982                          "  return x.foo;"
3983                          "};"
3984                          "function trouble_caller() {"
3985                          "  trouble();"
3986                          "};"))->Run();
3987   Local<Value> trouble = global->Get(v8_str("trouble"));
3988   CHECK(trouble->IsFunction());
3989   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
3990   CHECK(trouble_callee->IsFunction());
3991   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
3992   CHECK(trouble_caller->IsFunction());
3993   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
3994   CHECK_EQ(1, report_count);
3995   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
3996 }
3997 
3998 static const char* script_resource_name = "ExceptionInNativeScript.js";
ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,v8::Handle<Value>)3999 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
4000                                                 v8::Handle<Value>) {
4001   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
4002   CHECK(!name_val.IsEmpty() && name_val->IsString());
4003   v8::String::AsciiValue name(message->GetScriptResourceName());
4004   CHECK_EQ(script_resource_name, *name);
4005   CHECK_EQ(3, message->GetLineNumber());
4006   v8::String::AsciiValue source_line(message->GetSourceLine());
4007   CHECK_EQ("  new o.foo();", *source_line);
4008 }
4009 
TEST(ExceptionInNativeScript)4010 TEST(ExceptionInNativeScript) {
4011   v8::HandleScope scope;
4012   LocalContext env;
4013   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
4014 
4015   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
4016   v8::Local<v8::Object> global = env->Global();
4017   global->Set(v8_str("trouble"), fun->GetFunction());
4018 
4019   Script::Compile(v8_str("function trouble() {\n"
4020                          "  var o = {};\n"
4021                          "  new o.foo();\n"
4022                          "};"), v8::String::New(script_resource_name))->Run();
4023   Local<Value> trouble = global->Get(v8_str("trouble"));
4024   CHECK(trouble->IsFunction());
4025   Function::Cast(*trouble)->Call(global, 0, NULL);
4026   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
4027 }
4028 
4029 
TEST(CompilationErrorUsingTryCatchHandler)4030 TEST(CompilationErrorUsingTryCatchHandler) {
4031   v8::HandleScope scope;
4032   LocalContext env;
4033   v8::TryCatch try_catch;
4034   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
4035   CHECK_NE(NULL, *try_catch.Exception());
4036   CHECK(try_catch.HasCaught());
4037 }
4038 
4039 
TEST(TryCatchFinallyUsingTryCatchHandler)4040 TEST(TryCatchFinallyUsingTryCatchHandler) {
4041   v8::HandleScope scope;
4042   LocalContext env;
4043   v8::TryCatch try_catch;
4044   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
4045   CHECK(!try_catch.HasCaught());
4046   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
4047   CHECK(try_catch.HasCaught());
4048   try_catch.Reset();
4049   Script::Compile(v8_str("(function() {"
4050                          "try { throw ''; } finally { return; }"
4051                          "})()"))->Run();
4052   CHECK(!try_catch.HasCaught());
4053   Script::Compile(v8_str("(function()"
4054                          "  { try { throw ''; } finally { throw 0; }"
4055                          "})()"))->Run();
4056   CHECK(try_catch.HasCaught());
4057 }
4058 
4059 
4060 // SecurityHandler can't be run twice
TEST(SecurityHandler)4061 TEST(SecurityHandler) {
4062   v8::HandleScope scope0;
4063   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4064   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
4065                                            IndexedSecurityTestCallback);
4066   // Create an environment
4067   v8::Persistent<Context> context0 =
4068     Context::New(NULL, global_template);
4069   context0->Enter();
4070 
4071   v8::Handle<v8::Object> global0 = context0->Global();
4072   v8::Handle<Script> script0 = v8_compile("foo = 111");
4073   script0->Run();
4074   global0->Set(v8_str("0"), v8_num(999));
4075   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
4076   CHECK_EQ(111, foo0->Int32Value());
4077   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
4078   CHECK_EQ(999, z0->Int32Value());
4079 
4080   // Create another environment, should fail security checks.
4081   v8::HandleScope scope1;
4082 
4083   v8::Persistent<Context> context1 =
4084     Context::New(NULL, global_template);
4085   context1->Enter();
4086 
4087   v8::Handle<v8::Object> global1 = context1->Global();
4088   global1->Set(v8_str("othercontext"), global0);
4089   // This set will fail the security check.
4090   v8::Handle<Script> script1 =
4091     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
4092   script1->Run();
4093   // This read will pass the security check.
4094   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
4095   CHECK_EQ(111, foo1->Int32Value());
4096   // This read will pass the security check.
4097   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
4098   CHECK_EQ(999, z1->Int32Value());
4099 
4100   // Create another environment, should pass security checks.
4101   { g_security_callback_result = true;  // allow security handler to pass.
4102     v8::HandleScope scope2;
4103     LocalContext context2;
4104     v8::Handle<v8::Object> global2 = context2->Global();
4105     global2->Set(v8_str("othercontext"), global0);
4106     v8::Handle<Script> script2 =
4107         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
4108     script2->Run();
4109     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
4110     CHECK_EQ(333, foo2->Int32Value());
4111     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
4112     CHECK_EQ(888, z2->Int32Value());
4113   }
4114 
4115   context1->Exit();
4116   context1.Dispose();
4117 
4118   context0->Exit();
4119   context0.Dispose();
4120 }
4121 
4122 
THREADED_TEST(SecurityChecks)4123 THREADED_TEST(SecurityChecks) {
4124   v8::HandleScope handle_scope;
4125   LocalContext env1;
4126   v8::Persistent<Context> env2 = Context::New();
4127 
4128   Local<Value> foo = v8_str("foo");
4129   Local<Value> bar = v8_str("bar");
4130 
4131   // Set to the same domain.
4132   env1->SetSecurityToken(foo);
4133 
4134   // Create a function in env1.
4135   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
4136   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
4137   CHECK(spy->IsFunction());
4138 
4139   // Create another function accessing global objects.
4140   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
4141   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
4142   CHECK(spy2->IsFunction());
4143 
4144   // Switch to env2 in the same domain and invoke spy on env2.
4145   {
4146     env2->SetSecurityToken(foo);
4147     // Enter env2
4148     Context::Scope scope_env2(env2);
4149     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
4150     CHECK(result->IsFunction());
4151   }
4152 
4153   {
4154     env2->SetSecurityToken(bar);
4155     Context::Scope scope_env2(env2);
4156 
4157     // Call cross_domain_call, it should throw an exception
4158     v8::TryCatch try_catch;
4159     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
4160     CHECK(try_catch.HasCaught());
4161   }
4162 
4163   env2.Dispose();
4164 }
4165 
4166 
4167 // Regression test case for issue 1183439.
THREADED_TEST(SecurityChecksForPrototypeChain)4168 THREADED_TEST(SecurityChecksForPrototypeChain) {
4169   v8::HandleScope scope;
4170   LocalContext current;
4171   v8::Persistent<Context> other = Context::New();
4172 
4173   // Change context to be able to get to the Object function in the
4174   // other context without hitting the security checks.
4175   v8::Local<Value> other_object;
4176   { Context::Scope scope(other);
4177     other_object = other->Global()->Get(v8_str("Object"));
4178     other->Global()->Set(v8_num(42), v8_num(87));
4179   }
4180 
4181   current->Global()->Set(v8_str("other"), other->Global());
4182   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
4183 
4184   // Make sure the security check fails here and we get an undefined
4185   // result instead of getting the Object function. Repeat in a loop
4186   // to make sure to exercise the IC code.
4187   v8::Local<Script> access_other0 = v8_compile("other.Object");
4188   v8::Local<Script> access_other1 = v8_compile("other[42]");
4189   for (int i = 0; i < 5; i++) {
4190     CHECK(!access_other0->Run()->Equals(other_object));
4191     CHECK(access_other0->Run()->IsUndefined());
4192     CHECK(!access_other1->Run()->Equals(v8_num(87)));
4193     CHECK(access_other1->Run()->IsUndefined());
4194   }
4195 
4196   // Create an object that has 'other' in its prototype chain and make
4197   // sure we cannot access the Object function indirectly through
4198   // that. Repeat in a loop to make sure to exercise the IC code.
4199   v8_compile("function F() { };"
4200              "F.prototype = other;"
4201              "var f = new F();")->Run();
4202   v8::Local<Script> access_f0 = v8_compile("f.Object");
4203   v8::Local<Script> access_f1 = v8_compile("f[42]");
4204   for (int j = 0; j < 5; j++) {
4205     CHECK(!access_f0->Run()->Equals(other_object));
4206     CHECK(access_f0->Run()->IsUndefined());
4207     CHECK(!access_f1->Run()->Equals(v8_num(87)));
4208     CHECK(access_f1->Run()->IsUndefined());
4209   }
4210 
4211   // Now it gets hairy: Set the prototype for the other global object
4212   // to be the current global object. The prototype chain for 'f' now
4213   // goes through 'other' but ends up in the current global object.
4214   { Context::Scope scope(other);
4215     other->Global()->Set(v8_str("__proto__"), current->Global());
4216   }
4217   // Set a named and an index property on the current global
4218   // object. To force the lookup to go through the other global object,
4219   // the properties must not exist in the other global object.
4220   current->Global()->Set(v8_str("foo"), v8_num(100));
4221   current->Global()->Set(v8_num(99), v8_num(101));
4222   // Try to read the properties from f and make sure that the access
4223   // gets stopped by the security checks on the other global object.
4224   Local<Script> access_f2 = v8_compile("f.foo");
4225   Local<Script> access_f3 = v8_compile("f[99]");
4226   for (int k = 0; k < 5; k++) {
4227     CHECK(!access_f2->Run()->Equals(v8_num(100)));
4228     CHECK(access_f2->Run()->IsUndefined());
4229     CHECK(!access_f3->Run()->Equals(v8_num(101)));
4230     CHECK(access_f3->Run()->IsUndefined());
4231   }
4232   other.Dispose();
4233 }
4234 
4235 
THREADED_TEST(CrossDomainDelete)4236 THREADED_TEST(CrossDomainDelete) {
4237   v8::HandleScope handle_scope;
4238   LocalContext env1;
4239   v8::Persistent<Context> env2 = Context::New();
4240 
4241   Local<Value> foo = v8_str("foo");
4242   Local<Value> bar = v8_str("bar");
4243 
4244   // Set to the same domain.
4245   env1->SetSecurityToken(foo);
4246   env2->SetSecurityToken(foo);
4247 
4248   env1->Global()->Set(v8_str("prop"), v8_num(3));
4249   env2->Global()->Set(v8_str("env1"), env1->Global());
4250 
4251   // Change env2 to a different domain and delete env1.prop.
4252   env2->SetSecurityToken(bar);
4253   {
4254     Context::Scope scope_env2(env2);
4255     Local<Value> result =
4256         Script::Compile(v8_str("delete env1.prop"))->Run();
4257     CHECK(result->IsFalse());
4258   }
4259 
4260   // Check that env1.prop still exists.
4261   Local<Value> v = env1->Global()->Get(v8_str("prop"));
4262   CHECK(v->IsNumber());
4263   CHECK_EQ(3, v->Int32Value());
4264 
4265   env2.Dispose();
4266 }
4267 
4268 
THREADED_TEST(CrossDomainIsPropertyEnumerable)4269 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
4270   v8::HandleScope handle_scope;
4271   LocalContext env1;
4272   v8::Persistent<Context> env2 = Context::New();
4273 
4274   Local<Value> foo = v8_str("foo");
4275   Local<Value> bar = v8_str("bar");
4276 
4277   // Set to the same domain.
4278   env1->SetSecurityToken(foo);
4279   env2->SetSecurityToken(foo);
4280 
4281   env1->Global()->Set(v8_str("prop"), v8_num(3));
4282   env2->Global()->Set(v8_str("env1"), env1->Global());
4283 
4284   // env1.prop is enumerable in env2.
4285   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
4286   {
4287     Context::Scope scope_env2(env2);
4288     Local<Value> result = Script::Compile(test)->Run();
4289     CHECK(result->IsTrue());
4290   }
4291 
4292   // Change env2 to a different domain and test again.
4293   env2->SetSecurityToken(bar);
4294   {
4295     Context::Scope scope_env2(env2);
4296     Local<Value> result = Script::Compile(test)->Run();
4297     CHECK(result->IsFalse());
4298   }
4299 
4300   env2.Dispose();
4301 }
4302 
4303 
THREADED_TEST(CrossDomainForIn)4304 THREADED_TEST(CrossDomainForIn) {
4305   v8::HandleScope handle_scope;
4306   LocalContext env1;
4307   v8::Persistent<Context> env2 = Context::New();
4308 
4309   Local<Value> foo = v8_str("foo");
4310   Local<Value> bar = v8_str("bar");
4311 
4312   // Set to the same domain.
4313   env1->SetSecurityToken(foo);
4314   env2->SetSecurityToken(foo);
4315 
4316   env1->Global()->Set(v8_str("prop"), v8_num(3));
4317   env2->Global()->Set(v8_str("env1"), env1->Global());
4318 
4319   // Change env2 to a different domain and set env1's global object
4320   // as the __proto__ of an object in env2 and enumerate properties
4321   // in for-in. It shouldn't enumerate properties on env1's global
4322   // object.
4323   env2->SetSecurityToken(bar);
4324   {
4325     Context::Scope scope_env2(env2);
4326     Local<Value> result =
4327         CompileRun("(function(){var obj = {'__proto__':env1};"
4328                    "for (var p in obj)"
4329                    "   if (p == 'prop') return false;"
4330                    "return true;})()");
4331     CHECK(result->IsTrue());
4332   }
4333   env2.Dispose();
4334 }
4335 
4336 
TEST(ContextDetachGlobal)4337 TEST(ContextDetachGlobal) {
4338   v8::HandleScope handle_scope;
4339   LocalContext env1;
4340   v8::Persistent<Context> env2 = Context::New();
4341 
4342   Local<v8::Object> global1 = env1->Global();
4343 
4344   Local<Value> foo = v8_str("foo");
4345 
4346   // Set to the same domain.
4347   env1->SetSecurityToken(foo);
4348   env2->SetSecurityToken(foo);
4349 
4350   // Enter env2
4351   env2->Enter();
4352 
4353   // Create a function in env2 and add a reference to it in env1.
4354   Local<v8::Object> global2 = env2->Global();
4355   global2->Set(v8_str("prop"), v8::Integer::New(1));
4356   CompileRun("function getProp() {return prop;}");
4357 
4358   env1->Global()->Set(v8_str("getProp"),
4359                       global2->Get(v8_str("getProp")));
4360 
4361   // Detach env2's global, and reuse the global object of env2
4362   env2->Exit();
4363   env2->DetachGlobal();
4364   // env2 has a new global object.
4365   CHECK(!env2->Global()->Equals(global2));
4366 
4367   v8::Persistent<Context> env3 =
4368       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4369   env3->SetSecurityToken(v8_str("bar"));
4370   env3->Enter();
4371 
4372   Local<v8::Object> global3 = env3->Global();
4373   CHECK_EQ(global2, global3);
4374   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
4375   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
4376   global3->Set(v8_str("prop"), v8::Integer::New(-1));
4377   global3->Set(v8_str("prop2"), v8::Integer::New(2));
4378   env3->Exit();
4379 
4380   // Call getProp in env1, and it should return the value 1
4381   {
4382     Local<Value> get_prop = global1->Get(v8_str("getProp"));
4383     CHECK(get_prop->IsFunction());
4384     v8::TryCatch try_catch;
4385     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
4386     CHECK(!try_catch.HasCaught());
4387     CHECK_EQ(1, r->Int32Value());
4388   }
4389 
4390   // Check that env3 is not accessible from env1
4391   {
4392     Local<Value> r = global3->Get(v8_str("prop2"));
4393     CHECK(r->IsUndefined());
4394   }
4395 
4396   env2.Dispose();
4397   env3.Dispose();
4398 }
4399 
4400 
TEST(DetachAndReattachGlobal)4401 TEST(DetachAndReattachGlobal) {
4402   v8::HandleScope scope;
4403   LocalContext env1;
4404 
4405   // Create second environment.
4406   v8::Persistent<Context> env2 = Context::New();
4407 
4408   Local<Value> foo = v8_str("foo");
4409 
4410   // Set same security token for env1 and env2.
4411   env1->SetSecurityToken(foo);
4412   env2->SetSecurityToken(foo);
4413 
4414   // Create a property on the global object in env2.
4415   {
4416     v8::Context::Scope scope(env2);
4417     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
4418   }
4419 
4420   // Create a reference to env2 global from env1 global.
4421   env1->Global()->Set(v8_str("other"), env2->Global());
4422 
4423   // Check that we have access to other.p in env2 from env1.
4424   Local<Value> result = CompileRun("other.p");
4425   CHECK(result->IsInt32());
4426   CHECK_EQ(42, result->Int32Value());
4427 
4428   // Hold on to global from env2 and detach global from env2.
4429   Local<v8::Object> global2 = env2->Global();
4430   env2->DetachGlobal();
4431 
4432   // Check that the global has been detached. No other.p property can
4433   // be found.
4434   result = CompileRun("other.p");
4435   CHECK(result->IsUndefined());
4436 
4437   // Reuse global2 for env3.
4438   v8::Persistent<Context> env3 =
4439       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
4440   CHECK_EQ(global2, env3->Global());
4441 
4442   // Start by using the same security token for env3 as for env1 and env2.
4443   env3->SetSecurityToken(foo);
4444 
4445   // Create a property on the global object in env3.
4446   {
4447     v8::Context::Scope scope(env3);
4448     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
4449   }
4450 
4451   // Check that other.p is now the property in env3 and that we have access.
4452   result = CompileRun("other.p");
4453   CHECK(result->IsInt32());
4454   CHECK_EQ(24, result->Int32Value());
4455 
4456   // Change security token for env3 to something different from env1 and env2.
4457   env3->SetSecurityToken(v8_str("bar"));
4458 
4459   // Check that we do not have access to other.p in env1. |other| is now
4460   // the global object for env3 which has a different security token,
4461   // so access should be blocked.
4462   result = CompileRun("other.p");
4463   CHECK(result->IsUndefined());
4464 
4465   // Detach the global for env3 and reattach it to env2.
4466   env3->DetachGlobal();
4467   env2->ReattachGlobal(global2);
4468 
4469   // Check that we have access to other.p again in env1.  |other| is now
4470   // the global object for env2 which has the same security token as env1.
4471   result = CompileRun("other.p");
4472   CHECK(result->IsInt32());
4473   CHECK_EQ(42, result->Int32Value());
4474 
4475   env2.Dispose();
4476   env3.Dispose();
4477 }
4478 
4479 
NamedAccessBlocker(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)4480 static bool NamedAccessBlocker(Local<v8::Object> global,
4481                                Local<Value> name,
4482                                v8::AccessType type,
4483                                Local<Value> data) {
4484   return Context::GetCurrent()->Global()->Equals(global);
4485 }
4486 
4487 
IndexedAccessBlocker(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)4488 static bool IndexedAccessBlocker(Local<v8::Object> global,
4489                                  uint32_t key,
4490                                  v8::AccessType type,
4491                                  Local<Value> data) {
4492   return Context::GetCurrent()->Global()->Equals(global);
4493 }
4494 
4495 
4496 static int g_echo_value = -1;
EchoGetter(Local<String> name,const AccessorInfo & info)4497 static v8::Handle<Value> EchoGetter(Local<String> name,
4498                                     const AccessorInfo& info) {
4499   return v8_num(g_echo_value);
4500 }
4501 
4502 
EchoSetter(Local<String> name,Local<Value> value,const AccessorInfo &)4503 static void EchoSetter(Local<String> name,
4504                        Local<Value> value,
4505                        const AccessorInfo&) {
4506   if (value->IsNumber())
4507     g_echo_value = value->Int32Value();
4508 }
4509 
4510 
UnreachableGetter(Local<String> name,const AccessorInfo & info)4511 static v8::Handle<Value> UnreachableGetter(Local<String> name,
4512                                            const AccessorInfo& info) {
4513   CHECK(false);  // This function should not be called..
4514   return v8::Undefined();
4515 }
4516 
4517 
UnreachableSetter(Local<String>,Local<Value>,const AccessorInfo &)4518 static void UnreachableSetter(Local<String>, Local<Value>,
4519                               const AccessorInfo&) {
4520   CHECK(false);  // This function should nto be called.
4521 }
4522 
4523 
THREADED_TEST(AccessControl)4524 THREADED_TEST(AccessControl) {
4525   v8::HandleScope handle_scope;
4526   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4527 
4528   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
4529                                            IndexedAccessBlocker);
4530 
4531   // Add an accessor accessible by cross-domain JS code.
4532   global_template->SetAccessor(
4533       v8_str("accessible_prop"),
4534       EchoGetter, EchoSetter,
4535       v8::Handle<Value>(),
4536       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
4537 
4538   // Add an accessor that is not accessible by cross-domain JS code.
4539   global_template->SetAccessor(v8_str("blocked_prop"),
4540                                UnreachableGetter, UnreachableSetter,
4541                                v8::Handle<Value>(),
4542                                v8::DEFAULT);
4543 
4544   // Create an environment
4545   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4546   context0->Enter();
4547 
4548   v8::Handle<v8::Object> global0 = context0->Global();
4549 
4550   v8::HandleScope scope1;
4551 
4552   v8::Persistent<Context> context1 = Context::New();
4553   context1->Enter();
4554 
4555   v8::Handle<v8::Object> global1 = context1->Global();
4556   global1->Set(v8_str("other"), global0);
4557 
4558   v8::Handle<Value> value;
4559 
4560   // Access blocked property
4561   value = v8_compile("other.blocked_prop = 1")->Run();
4562   value = v8_compile("other.blocked_prop")->Run();
4563   CHECK(value->IsUndefined());
4564 
4565   value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4566   CHECK(value->IsFalse());
4567 
4568   // Access accessible property
4569   value = v8_compile("other.accessible_prop = 3")->Run();
4570   CHECK(value->IsNumber());
4571   CHECK_EQ(3, value->Int32Value());
4572   CHECK_EQ(3, g_echo_value);
4573 
4574   value = v8_compile("other.accessible_prop")->Run();
4575   CHECK(value->IsNumber());
4576   CHECK_EQ(3, value->Int32Value());
4577 
4578   value =
4579     v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4580   CHECK(value->IsTrue());
4581 
4582   // Enumeration doesn't enumerate accessors from inaccessible objects in
4583   // the prototype chain even if the accessors are in themselves accessible.
4584   Local<Value> result =
4585       CompileRun("(function(){var obj = {'__proto__':other};"
4586                  "for (var p in obj)"
4587                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4588                  "     return false;"
4589                  "   }"
4590                  "return true;})()");
4591   CHECK(result->IsTrue());
4592 
4593   context1->Exit();
4594   context0->Exit();
4595   context1.Dispose();
4596   context0.Dispose();
4597 }
4598 
4599 
GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)4600 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
4601                                             Local<Value> name,
4602                                             v8::AccessType type,
4603                                             Local<Value> data) {
4604   return false;
4605 }
4606 
4607 
GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)4608 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
4609                                               uint32_t key,
4610                                               v8::AccessType type,
4611                                               Local<Value> data) {
4612   return false;
4613 }
4614 
4615 
THREADED_TEST(AccessControlGetOwnPropertyNames)4616 THREADED_TEST(AccessControlGetOwnPropertyNames) {
4617   v8::HandleScope handle_scope;
4618   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
4619 
4620   obj_template->Set(v8_str("x"), v8::Integer::New(42));
4621   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
4622                                         GetOwnPropertyNamesIndexedBlocker);
4623 
4624   // Create an environment
4625   v8::Persistent<Context> context0 = Context::New(NULL, obj_template);
4626   context0->Enter();
4627 
4628   v8::Handle<v8::Object> global0 = context0->Global();
4629 
4630   v8::HandleScope scope1;
4631 
4632   v8::Persistent<Context> context1 = Context::New();
4633   context1->Enter();
4634 
4635   v8::Handle<v8::Object> global1 = context1->Global();
4636   global1->Set(v8_str("other"), global0);
4637   global1->Set(v8_str("object"), obj_template->NewInstance());
4638 
4639   v8::Handle<Value> value;
4640 
4641   // Attempt to get the property names of the other global object and
4642   // of an object that requires access checks.  Accessing the other
4643   // global object should be blocked by access checks on the global
4644   // proxy object.  Accessing the object that requires access checks
4645   // is blocked by the access checks on the object itself.
4646   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
4647   CHECK(value->IsTrue());
4648 
4649   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
4650   CHECK(value->IsTrue());
4651 
4652   context1->Exit();
4653   context0->Exit();
4654   context1.Dispose();
4655   context0.Dispose();
4656 }
4657 
4658 
ConstTenGetter(Local<String> name,const AccessorInfo & info)4659 static v8::Handle<Value> ConstTenGetter(Local<String> name,
4660                                         const AccessorInfo& info) {
4661   return v8_num(10);
4662 }
4663 
4664 
THREADED_TEST(CrossDomainAccessors)4665 THREADED_TEST(CrossDomainAccessors) {
4666   v8::HandleScope handle_scope;
4667 
4668   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4669 
4670   v8::Handle<v8::ObjectTemplate> global_template =
4671       func_template->InstanceTemplate();
4672 
4673   v8::Handle<v8::ObjectTemplate> proto_template =
4674       func_template->PrototypeTemplate();
4675 
4676   // Add an accessor to proto that's accessible by cross-domain JS code.
4677   proto_template->SetAccessor(v8_str("accessible"),
4678                               ConstTenGetter, 0,
4679                               v8::Handle<Value>(),
4680                               v8::ALL_CAN_READ);
4681 
4682   // Add an accessor that is not accessible by cross-domain JS code.
4683   global_template->SetAccessor(v8_str("unreachable"),
4684                                UnreachableGetter, 0,
4685                                v8::Handle<Value>(),
4686                                v8::DEFAULT);
4687 
4688   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4689   context0->Enter();
4690 
4691   Local<v8::Object> global = context0->Global();
4692   // Add a normal property that shadows 'accessible'
4693   global->Set(v8_str("accessible"), v8_num(11));
4694 
4695   // Enter a new context.
4696   v8::HandleScope scope1;
4697   v8::Persistent<Context> context1 = Context::New();
4698   context1->Enter();
4699 
4700   v8::Handle<v8::Object> global1 = context1->Global();
4701   global1->Set(v8_str("other"), global);
4702 
4703   // Should return 10, instead of 11
4704   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4705   CHECK(value->IsNumber());
4706   CHECK_EQ(10, value->Int32Value());
4707 
4708   value = v8_compile("other.unreachable")->Run();
4709   CHECK(value->IsUndefined());
4710 
4711   context1->Exit();
4712   context0->Exit();
4713   context1.Dispose();
4714   context0.Dispose();
4715 }
4716 
4717 
4718 static int named_access_count = 0;
4719 static int indexed_access_count = 0;
4720 
NamedAccessCounter(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)4721 static bool NamedAccessCounter(Local<v8::Object> global,
4722                                Local<Value> name,
4723                                v8::AccessType type,
4724                                Local<Value> data) {
4725   named_access_count++;
4726   return true;
4727 }
4728 
4729 
IndexedAccessCounter(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)4730 static bool IndexedAccessCounter(Local<v8::Object> global,
4731                                  uint32_t key,
4732                                  v8::AccessType type,
4733                                  Local<Value> data) {
4734   indexed_access_count++;
4735   return true;
4736 }
4737 
4738 
4739 // This one is too easily disturbed by other tests.
TEST(AccessControlIC)4740 TEST(AccessControlIC) {
4741   named_access_count = 0;
4742   indexed_access_count = 0;
4743 
4744   v8::HandleScope handle_scope;
4745 
4746   // Create an environment.
4747   v8::Persistent<Context> context0 = Context::New();
4748   context0->Enter();
4749 
4750   // Create an object that requires access-check functions to be
4751   // called for cross-domain access.
4752   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4753   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4754                                            IndexedAccessCounter);
4755   Local<v8::Object> object = object_template->NewInstance();
4756 
4757   v8::HandleScope scope1;
4758 
4759   // Create another environment.
4760   v8::Persistent<Context> context1 = Context::New();
4761   context1->Enter();
4762 
4763   // Make easy access to the object from the other environment.
4764   v8::Handle<v8::Object> global1 = context1->Global();
4765   global1->Set(v8_str("obj"), object);
4766 
4767   v8::Handle<Value> value;
4768 
4769   // Check that the named access-control function is called every time.
4770   CompileRun("function testProp(obj) {"
4771              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
4772              "  for (var j = 0; j < 10; j++) obj.prop;"
4773              "  return obj.prop"
4774              "}");
4775   value = CompileRun("testProp(obj)");
4776   CHECK(value->IsNumber());
4777   CHECK_EQ(1, value->Int32Value());
4778   CHECK_EQ(21, named_access_count);
4779 
4780   // Check that the named access-control function is called every time.
4781   CompileRun("var p = 'prop';"
4782              "function testKeyed(obj) {"
4783              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
4784              "  for (var j = 0; j < 10; j++) obj[p];"
4785              "  return obj[p];"
4786              "}");
4787   // Use obj which requires access checks.  No inline caching is used
4788   // in that case.
4789   value = CompileRun("testKeyed(obj)");
4790   CHECK(value->IsNumber());
4791   CHECK_EQ(1, value->Int32Value());
4792   CHECK_EQ(42, named_access_count);
4793   // Force the inline caches into generic state and try again.
4794   CompileRun("testKeyed({ a: 0 })");
4795   CompileRun("testKeyed({ b: 0 })");
4796   value = CompileRun("testKeyed(obj)");
4797   CHECK(value->IsNumber());
4798   CHECK_EQ(1, value->Int32Value());
4799   CHECK_EQ(63, named_access_count);
4800 
4801   // Check that the indexed access-control function is called every time.
4802   CompileRun("function testIndexed(obj) {"
4803              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
4804              "  for (var j = 0; j < 10; j++) obj[0];"
4805              "  return obj[0]"
4806              "}");
4807   value = CompileRun("testIndexed(obj)");
4808   CHECK(value->IsNumber());
4809   CHECK_EQ(1, value->Int32Value());
4810   CHECK_EQ(21, indexed_access_count);
4811   // Force the inline caches into generic state.
4812   CompileRun("testIndexed(new Array(1))");
4813   // Test that the indexed access check is called.
4814   value = CompileRun("testIndexed(obj)");
4815   CHECK(value->IsNumber());
4816   CHECK_EQ(1, value->Int32Value());
4817   CHECK_EQ(42, indexed_access_count);
4818 
4819   // Check that the named access check is called when invoking
4820   // functions on an object that requires access checks.
4821   CompileRun("obj.f = function() {}");
4822   CompileRun("function testCallNormal(obj) {"
4823              "  for (var i = 0; i < 10; i++) obj.f();"
4824              "}");
4825   CompileRun("testCallNormal(obj)");
4826   CHECK_EQ(74, named_access_count);
4827 
4828   // Force obj into slow case.
4829   value = CompileRun("delete obj.prop");
4830   CHECK(value->BooleanValue());
4831   // Force inline caches into dictionary probing mode.
4832   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4833   // Test that the named access check is called.
4834   value = CompileRun("testProp(obj);");
4835   CHECK(value->IsNumber());
4836   CHECK_EQ(1, value->Int32Value());
4837   CHECK_EQ(96, named_access_count);
4838 
4839   // Force the call inline cache into dictionary probing mode.
4840   CompileRun("o.f = function() {}; testCallNormal(o)");
4841   // Test that the named access check is still called for each
4842   // invocation of the function.
4843   value = CompileRun("testCallNormal(obj)");
4844   CHECK_EQ(106, named_access_count);
4845 
4846   context1->Exit();
4847   context0->Exit();
4848   context1.Dispose();
4849   context0.Dispose();
4850 }
4851 
4852 
NamedAccessFlatten(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)4853 static bool NamedAccessFlatten(Local<v8::Object> global,
4854                                Local<Value> name,
4855                                v8::AccessType type,
4856                                Local<Value> data) {
4857   char buf[100];
4858   int len;
4859 
4860   CHECK(name->IsString());
4861 
4862   memset(buf, 0x1, sizeof(buf));
4863   len = Local<String>::Cast(name)->WriteAscii(buf);
4864   CHECK_EQ(4, len);
4865 
4866   uint16_t buf2[100];
4867 
4868   memset(buf, 0x1, sizeof(buf));
4869   len = Local<String>::Cast(name)->Write(buf2);
4870   CHECK_EQ(4, len);
4871 
4872   return true;
4873 }
4874 
4875 
IndexedAccessFlatten(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)4876 static bool IndexedAccessFlatten(Local<v8::Object> global,
4877                                  uint32_t key,
4878                                  v8::AccessType type,
4879                                  Local<Value> data) {
4880   return true;
4881 }
4882 
4883 
4884 // Regression test.  In access checks, operations that may cause
4885 // garbage collection are not allowed.  It used to be the case that
4886 // using the Write operation on a string could cause a garbage
4887 // collection due to flattening of the string.  This is no longer the
4888 // case.
THREADED_TEST(AccessControlFlatten)4889 THREADED_TEST(AccessControlFlatten) {
4890   named_access_count = 0;
4891   indexed_access_count = 0;
4892 
4893   v8::HandleScope handle_scope;
4894 
4895   // Create an environment.
4896   v8::Persistent<Context> context0 = Context::New();
4897   context0->Enter();
4898 
4899   // Create an object that requires access-check functions to be
4900   // called for cross-domain access.
4901   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4902   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
4903                                            IndexedAccessFlatten);
4904   Local<v8::Object> object = object_template->NewInstance();
4905 
4906   v8::HandleScope scope1;
4907 
4908   // Create another environment.
4909   v8::Persistent<Context> context1 = Context::New();
4910   context1->Enter();
4911 
4912   // Make easy access to the object from the other environment.
4913   v8::Handle<v8::Object> global1 = context1->Global();
4914   global1->Set(v8_str("obj"), object);
4915 
4916   v8::Handle<Value> value;
4917 
4918   value = v8_compile("var p = 'as' + 'df';")->Run();
4919   value = v8_compile("obj[p];")->Run();
4920 
4921   context1->Exit();
4922   context0->Exit();
4923   context1.Dispose();
4924   context0.Dispose();
4925 }
4926 
4927 
AccessControlNamedGetter(Local<String>,const AccessorInfo &)4928 static v8::Handle<Value> AccessControlNamedGetter(
4929     Local<String>, const AccessorInfo&) {
4930   return v8::Integer::New(42);
4931 }
4932 
4933 
AccessControlNamedSetter(Local<String>,Local<Value> value,const AccessorInfo &)4934 static v8::Handle<Value> AccessControlNamedSetter(
4935     Local<String>, Local<Value> value, const AccessorInfo&) {
4936   return value;
4937 }
4938 
4939 
AccessControlIndexedGetter(uint32_t index,const AccessorInfo & info)4940 static v8::Handle<Value> AccessControlIndexedGetter(
4941       uint32_t index,
4942       const AccessorInfo& info) {
4943   return v8_num(42);
4944 }
4945 
4946 
AccessControlIndexedSetter(uint32_t,Local<Value> value,const AccessorInfo &)4947 static v8::Handle<Value> AccessControlIndexedSetter(
4948     uint32_t, Local<Value> value, const AccessorInfo&) {
4949   return value;
4950 }
4951 
4952 
THREADED_TEST(AccessControlInterceptorIC)4953 THREADED_TEST(AccessControlInterceptorIC) {
4954   named_access_count = 0;
4955   indexed_access_count = 0;
4956 
4957   v8::HandleScope handle_scope;
4958 
4959   // Create an environment.
4960   v8::Persistent<Context> context0 = Context::New();
4961   context0->Enter();
4962 
4963   // Create an object that requires access-check functions to be
4964   // called for cross-domain access.  The object also has interceptors
4965   // interceptor.
4966   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4967   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4968                                            IndexedAccessCounter);
4969   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
4970                                            AccessControlNamedSetter);
4971   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
4972                                              AccessControlIndexedSetter);
4973   Local<v8::Object> object = object_template->NewInstance();
4974 
4975   v8::HandleScope scope1;
4976 
4977   // Create another environment.
4978   v8::Persistent<Context> context1 = Context::New();
4979   context1->Enter();
4980 
4981   // Make easy access to the object from the other environment.
4982   v8::Handle<v8::Object> global1 = context1->Global();
4983   global1->Set(v8_str("obj"), object);
4984 
4985   v8::Handle<Value> value;
4986 
4987   // Check that the named access-control function is called every time
4988   // eventhough there is an interceptor on the object.
4989   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
4990   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
4991                      "obj.x")->Run();
4992   CHECK(value->IsNumber());
4993   CHECK_EQ(42, value->Int32Value());
4994   CHECK_EQ(21, named_access_count);
4995 
4996   value = v8_compile("var p = 'x';")->Run();
4997   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
4998   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
4999                      "obj[p]")->Run();
5000   CHECK(value->IsNumber());
5001   CHECK_EQ(42, value->Int32Value());
5002   CHECK_EQ(42, named_access_count);
5003 
5004   // Check that the indexed access-control function is called every
5005   // time eventhough there is an interceptor on the object.
5006   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
5007   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
5008                      "obj[0]")->Run();
5009   CHECK(value->IsNumber());
5010   CHECK_EQ(42, value->Int32Value());
5011   CHECK_EQ(21, indexed_access_count);
5012 
5013   context1->Exit();
5014   context0->Exit();
5015   context1.Dispose();
5016   context0.Dispose();
5017 }
5018 
5019 
THREADED_TEST(Version)5020 THREADED_TEST(Version) {
5021   v8::V8::GetVersion();
5022 }
5023 
5024 
InstanceFunctionCallback(const v8::Arguments & args)5025 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
5026   ApiTestFuzzer::Fuzz();
5027   return v8_num(12);
5028 }
5029 
5030 
THREADED_TEST(InstanceProperties)5031 THREADED_TEST(InstanceProperties) {
5032   v8::HandleScope handle_scope;
5033   LocalContext context;
5034 
5035   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5036   Local<ObjectTemplate> instance = t->InstanceTemplate();
5037 
5038   instance->Set(v8_str("x"), v8_num(42));
5039   instance->Set(v8_str("f"),
5040                 v8::FunctionTemplate::New(InstanceFunctionCallback));
5041 
5042   Local<Value> o = t->GetFunction()->NewInstance();
5043 
5044   context->Global()->Set(v8_str("i"), o);
5045   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
5046   CHECK_EQ(42, value->Int32Value());
5047 
5048   value = Script::Compile(v8_str("i.f()"))->Run();
5049   CHECK_EQ(12, value->Int32Value());
5050 }
5051 
5052 
5053 static v8::Handle<Value>
GlobalObjectInstancePropertiesGet(Local<String> key,const AccessorInfo &)5054 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
5055   ApiTestFuzzer::Fuzz();
5056   return v8::Handle<Value>();
5057 }
5058 
5059 
THREADED_TEST(GlobalObjectInstanceProperties)5060 THREADED_TEST(GlobalObjectInstanceProperties) {
5061   v8::HandleScope handle_scope;
5062 
5063   Local<Value> global_object;
5064 
5065   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5066   t->InstanceTemplate()->SetNamedPropertyHandler(
5067       GlobalObjectInstancePropertiesGet);
5068   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5069   instance_template->Set(v8_str("x"), v8_num(42));
5070   instance_template->Set(v8_str("f"),
5071                          v8::FunctionTemplate::New(InstanceFunctionCallback));
5072 
5073   {
5074     LocalContext env(NULL, instance_template);
5075     // Hold on to the global object so it can be used again in another
5076     // environment initialization.
5077     global_object = env->Global();
5078 
5079     Local<Value> value = Script::Compile(v8_str("x"))->Run();
5080     CHECK_EQ(42, value->Int32Value());
5081     value = Script::Compile(v8_str("f()"))->Run();
5082     CHECK_EQ(12, value->Int32Value());
5083   }
5084 
5085   {
5086     // Create new environment reusing the global object.
5087     LocalContext env(NULL, instance_template, global_object);
5088     Local<Value> value = Script::Compile(v8_str("x"))->Run();
5089     CHECK_EQ(42, value->Int32Value());
5090     value = Script::Compile(v8_str("f()"))->Run();
5091     CHECK_EQ(12, value->Int32Value());
5092   }
5093 }
5094 
5095 
ShadowFunctionCallback(const v8::Arguments & args)5096 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
5097   ApiTestFuzzer::Fuzz();
5098   return v8_num(42);
5099 }
5100 
5101 
5102 static int shadow_y;
5103 static int shadow_y_setter_call_count;
5104 static int shadow_y_getter_call_count;
5105 
5106 
ShadowYSetter(Local<String>,Local<Value>,const AccessorInfo &)5107 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
5108   shadow_y_setter_call_count++;
5109   shadow_y = 42;
5110 }
5111 
5112 
ShadowYGetter(Local<String> name,const AccessorInfo & info)5113 static v8::Handle<Value> ShadowYGetter(Local<String> name,
5114                                        const AccessorInfo& info) {
5115   ApiTestFuzzer::Fuzz();
5116   shadow_y_getter_call_count++;
5117   return v8_num(shadow_y);
5118 }
5119 
5120 
ShadowIndexedGet(uint32_t index,const AccessorInfo & info)5121 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
5122                                           const AccessorInfo& info) {
5123   return v8::Handle<Value>();
5124 }
5125 
5126 
ShadowNamedGet(Local<String> key,const AccessorInfo &)5127 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
5128                                         const AccessorInfo&) {
5129   return v8::Handle<Value>();
5130 }
5131 
5132 
THREADED_TEST(ShadowObject)5133 THREADED_TEST(ShadowObject) {
5134   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
5135   v8::HandleScope handle_scope;
5136 
5137   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
5138   LocalContext context(NULL, global_template);
5139 
5140   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5141   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
5142   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
5143   Local<ObjectTemplate> proto = t->PrototypeTemplate();
5144   Local<ObjectTemplate> instance = t->InstanceTemplate();
5145 
5146   // Only allow calls of f on instances of t.
5147   Local<v8::Signature> signature = v8::Signature::New(t);
5148   proto->Set(v8_str("f"),
5149              v8::FunctionTemplate::New(ShadowFunctionCallback,
5150                                        Local<Value>(),
5151                                        signature));
5152   proto->Set(v8_str("x"), v8_num(12));
5153 
5154   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
5155 
5156   Local<Value> o = t->GetFunction()->NewInstance();
5157   context->Global()->Set(v8_str("__proto__"), o);
5158 
5159   Local<Value> value =
5160       Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
5161   CHECK(value->IsBoolean());
5162   CHECK(!value->BooleanValue());
5163 
5164   value = Script::Compile(v8_str("x"))->Run();
5165   CHECK_EQ(12, value->Int32Value());
5166 
5167   value = Script::Compile(v8_str("f()"))->Run();
5168   CHECK_EQ(42, value->Int32Value());
5169 
5170   Script::Compile(v8_str("y = 42"))->Run();
5171   CHECK_EQ(1, shadow_y_setter_call_count);
5172   value = Script::Compile(v8_str("y"))->Run();
5173   CHECK_EQ(1, shadow_y_getter_call_count);
5174   CHECK_EQ(42, value->Int32Value());
5175 }
5176 
5177 
THREADED_TEST(HiddenPrototype)5178 THREADED_TEST(HiddenPrototype) {
5179   v8::HandleScope handle_scope;
5180   LocalContext context;
5181 
5182   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5183   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5184   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5185   t1->SetHiddenPrototype(true);
5186   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5187   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5188   t2->SetHiddenPrototype(true);
5189   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5190   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5191   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5192 
5193   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5194   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5195   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5196   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5197 
5198   // Setting the prototype on an object skips hidden prototypes.
5199   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5200   o0->Set(v8_str("__proto__"), o1);
5201   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5202   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5203   o0->Set(v8_str("__proto__"), o2);
5204   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5205   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5206   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5207   o0->Set(v8_str("__proto__"), o3);
5208   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5209   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5210   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5211   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5212 
5213   // Getting the prototype of o0 should get the first visible one
5214   // which is o3.  Therefore, z should not be defined on the prototype
5215   // object.
5216   Local<Value> proto = o0->Get(v8_str("__proto__"));
5217   CHECK(proto->IsObject());
5218   CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
5219 }
5220 
5221 
THREADED_TEST(SetPrototype)5222 THREADED_TEST(SetPrototype) {
5223   v8::HandleScope handle_scope;
5224   LocalContext context;
5225 
5226   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
5227   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
5228   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
5229   t1->SetHiddenPrototype(true);
5230   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
5231   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
5232   t2->SetHiddenPrototype(true);
5233   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
5234   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
5235   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
5236 
5237   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
5238   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
5239   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
5240   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
5241 
5242   // Setting the prototype on an object does not skip hidden prototypes.
5243   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5244   CHECK(o0->SetPrototype(o1));
5245   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5246   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5247   CHECK(o1->SetPrototype(o2));
5248   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5249   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5250   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5251   CHECK(o2->SetPrototype(o3));
5252   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
5253   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
5254   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
5255   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
5256 
5257   // Getting the prototype of o0 should get the first visible one
5258   // which is o3.  Therefore, z should not be defined on the prototype
5259   // object.
5260   Local<Value> proto = o0->Get(v8_str("__proto__"));
5261   CHECK(proto->IsObject());
5262   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto), o3);
5263 
5264   // However, Object::GetPrototype ignores hidden prototype.
5265   Local<Value> proto0 = o0->GetPrototype();
5266   CHECK(proto0->IsObject());
5267   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto0), o1);
5268 
5269   Local<Value> proto1 = o1->GetPrototype();
5270   CHECK(proto1->IsObject());
5271   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto1), o2);
5272 
5273   Local<Value> proto2 = o2->GetPrototype();
5274   CHECK(proto2->IsObject());
5275   CHECK_EQ(v8::Handle<v8::Object>::Cast(proto2), o3);
5276 }
5277 
5278 
THREADED_TEST(SetPrototypeThrows)5279 THREADED_TEST(SetPrototypeThrows) {
5280   v8::HandleScope handle_scope;
5281   LocalContext context;
5282 
5283   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5284 
5285   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
5286   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
5287 
5288   CHECK(o0->SetPrototype(o1));
5289   // If setting the prototype leads to the cycle, SetPrototype should
5290   // return false and keep VM in sane state.
5291   v8::TryCatch try_catch;
5292   CHECK(!o1->SetPrototype(o0));
5293   CHECK(!try_catch.HasCaught());
5294   ASSERT(!i::Top::has_pending_exception());
5295 
5296   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
5297 }
5298 
5299 
THREADED_TEST(GetterSetterExceptions)5300 THREADED_TEST(GetterSetterExceptions) {
5301   v8::HandleScope handle_scope;
5302   LocalContext context;
5303   CompileRun(
5304     "function Foo() { };"
5305     "function Throw() { throw 5; };"
5306     "var x = { };"
5307     "x.__defineSetter__('set', Throw);"
5308     "x.__defineGetter__('get', Throw);");
5309   Local<v8::Object> x =
5310       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
5311   v8::TryCatch try_catch;
5312   x->Set(v8_str("set"), v8::Integer::New(8));
5313   x->Get(v8_str("get"));
5314   x->Set(v8_str("set"), v8::Integer::New(8));
5315   x->Get(v8_str("get"));
5316   x->Set(v8_str("set"), v8::Integer::New(8));
5317   x->Get(v8_str("get"));
5318   x->Set(v8_str("set"), v8::Integer::New(8));
5319   x->Get(v8_str("get"));
5320 }
5321 
5322 
THREADED_TEST(Constructor)5323 THREADED_TEST(Constructor) {
5324   v8::HandleScope handle_scope;
5325   LocalContext context;
5326   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5327   templ->SetClassName(v8_str("Fun"));
5328   Local<Function> cons = templ->GetFunction();
5329   context->Global()->Set(v8_str("Fun"), cons);
5330   Local<v8::Object> inst = cons->NewInstance();
5331   i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
5332   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
5333   CHECK(value->BooleanValue());
5334 }
5335 
THREADED_TEST(FunctionDescriptorException)5336 THREADED_TEST(FunctionDescriptorException) {
5337   v8::HandleScope handle_scope;
5338   LocalContext context;
5339   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5340   templ->SetClassName(v8_str("Fun"));
5341   Local<Function> cons = templ->GetFunction();
5342   context->Global()->Set(v8_str("Fun"), cons);
5343   Local<Value> value = CompileRun(
5344     "function test() {"
5345     "  try {"
5346     "    (new Fun()).blah()"
5347     "  } catch (e) {"
5348     "    var str = String(e);"
5349     "    if (str.indexOf('TypeError') == -1) return 1;"
5350     "    if (str.indexOf('[object Fun]') != -1) return 2;"
5351     "    if (str.indexOf('#<a Fun>') == -1) return 3;"
5352     "    return 0;"
5353     "  }"
5354     "  return 4;"
5355     "}"
5356     "test();");
5357   CHECK_EQ(0, value->Int32Value());
5358 }
5359 
5360 
THREADED_TEST(EvalAliasedDynamic)5361 THREADED_TEST(EvalAliasedDynamic) {
5362   v8::HandleScope scope;
5363   LocalContext current;
5364 
5365   // Tests where aliased eval can only be resolved dynamically.
5366   Local<Script> script =
5367       Script::Compile(v8_str("function f(x) { "
5368                              "  var foo = 2;"
5369                              "  with (x) { return eval('foo'); }"
5370                              "}"
5371                              "foo = 0;"
5372                              "result1 = f(new Object());"
5373                              "result2 = f(this);"
5374                              "var x = new Object();"
5375                              "x.eval = function(x) { return 1; };"
5376                              "result3 = f(x);"));
5377   script->Run();
5378   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
5379   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
5380   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
5381 
5382   v8::TryCatch try_catch;
5383   script =
5384     Script::Compile(v8_str("function f(x) { "
5385                            "  var bar = 2;"
5386                            "  with (x) { return eval('bar'); }"
5387                            "}"
5388                            "f(this)"));
5389   script->Run();
5390   CHECK(try_catch.HasCaught());
5391   try_catch.Reset();
5392 }
5393 
5394 
THREADED_TEST(CrossEval)5395 THREADED_TEST(CrossEval) {
5396   v8::HandleScope scope;
5397   LocalContext other;
5398   LocalContext current;
5399 
5400   Local<String> token = v8_str("<security token>");
5401   other->SetSecurityToken(token);
5402   current->SetSecurityToken(token);
5403 
5404   // Setup reference from current to other.
5405   current->Global()->Set(v8_str("other"), other->Global());
5406 
5407   // Check that new variables are introduced in other context.
5408   Local<Script> script =
5409       Script::Compile(v8_str("other.eval('var foo = 1234')"));
5410   script->Run();
5411   Local<Value> foo = other->Global()->Get(v8_str("foo"));
5412   CHECK_EQ(1234, foo->Int32Value());
5413   CHECK(!current->Global()->Has(v8_str("foo")));
5414 
5415   // Check that writing to non-existing properties introduces them in
5416   // the other context.
5417   script =
5418       Script::Compile(v8_str("other.eval('na = 1234')"));
5419   script->Run();
5420   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
5421   CHECK(!current->Global()->Has(v8_str("na")));
5422 
5423   // Check that global variables in current context are not visible in other
5424   // context.
5425   v8::TryCatch try_catch;
5426   script =
5427       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
5428   Local<Value> result = script->Run();
5429   CHECK(try_catch.HasCaught());
5430   try_catch.Reset();
5431 
5432   // Check that local variables in current context are not visible in other
5433   // context.
5434   script =
5435       Script::Compile(v8_str("(function() { "
5436                              "  var baz = 87;"
5437                              "  return other.eval('baz');"
5438                              "})();"));
5439   result = script->Run();
5440   CHECK(try_catch.HasCaught());
5441   try_catch.Reset();
5442 
5443   // Check that global variables in the other environment are visible
5444   // when evaluting code.
5445   other->Global()->Set(v8_str("bis"), v8_num(1234));
5446   script = Script::Compile(v8_str("other.eval('bis')"));
5447   CHECK_EQ(1234, script->Run()->Int32Value());
5448   CHECK(!try_catch.HasCaught());
5449 
5450   // Check that the 'this' pointer points to the global object evaluating
5451   // code.
5452   other->Global()->Set(v8_str("t"), other->Global());
5453   script = Script::Compile(v8_str("other.eval('this == t')"));
5454   result = script->Run();
5455   CHECK(result->IsTrue());
5456   CHECK(!try_catch.HasCaught());
5457 
5458   // Check that variables introduced in with-statement are not visible in
5459   // other context.
5460   script =
5461       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
5462   result = script->Run();
5463   CHECK(try_catch.HasCaught());
5464   try_catch.Reset();
5465 
5466   // Check that you cannot use 'eval.call' with another object than the
5467   // current global object.
5468   script =
5469       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
5470   result = script->Run();
5471   CHECK(try_catch.HasCaught());
5472 }
5473 
5474 
5475 // Test that calling eval in a context which has been detached from
5476 // its global throws an exception.  This behavior is consistent with
5477 // other JavaScript implementations.
THREADED_TEST(EvalInDetachedGlobal)5478 THREADED_TEST(EvalInDetachedGlobal) {
5479   v8::HandleScope scope;
5480 
5481   v8::Persistent<Context> context0 = Context::New();
5482   v8::Persistent<Context> context1 = Context::New();
5483 
5484   // Setup function in context0 that uses eval from context0.
5485   context0->Enter();
5486   v8::Handle<v8::Value> fun =
5487       CompileRun("var x = 42;"
5488                  "(function() {"
5489                  "  var e = eval;"
5490                  "  return function(s) { return e(s); }"
5491                  "})()");
5492   context0->Exit();
5493 
5494   // Put the function into context1 and call it before and after
5495   // detaching the global.  Before detaching, the call succeeds and
5496   // after detaching and exception is thrown.
5497   context1->Enter();
5498   context1->Global()->Set(v8_str("fun"), fun);
5499   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
5500   CHECK_EQ(42, x_value->Int32Value());
5501   context0->DetachGlobal();
5502   v8::TryCatch catcher;
5503   x_value = CompileRun("fun('x')");
5504   CHECK(x_value.IsEmpty());
5505   CHECK(catcher.HasCaught());
5506   context1->Exit();
5507 
5508   context1.Dispose();
5509   context0.Dispose();
5510 }
5511 
5512 
THREADED_TEST(CrossLazyLoad)5513 THREADED_TEST(CrossLazyLoad) {
5514   v8::HandleScope scope;
5515   LocalContext other;
5516   LocalContext current;
5517 
5518   Local<String> token = v8_str("<security token>");
5519   other->SetSecurityToken(token);
5520   current->SetSecurityToken(token);
5521 
5522   // Setup reference from current to other.
5523   current->Global()->Set(v8_str("other"), other->Global());
5524 
5525   // Trigger lazy loading in other context.
5526   Local<Script> script =
5527       Script::Compile(v8_str("other.eval('new Date(42)')"));
5528   Local<Value> value = script->Run();
5529   CHECK_EQ(42.0, value->NumberValue());
5530 }
5531 
5532 
call_as_function(const v8::Arguments & args)5533 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
5534   ApiTestFuzzer::Fuzz();
5535   if (args.IsConstructCall()) {
5536     if (args[0]->IsInt32()) {
5537        return v8_num(-args[0]->Int32Value());
5538     }
5539   }
5540 
5541   return args[0];
5542 }
5543 
5544 
5545 // Test that a call handler can be set for objects which will allow
5546 // non-function objects created through the API to be called as
5547 // functions.
THREADED_TEST(CallAsFunction)5548 THREADED_TEST(CallAsFunction) {
5549   v8::HandleScope scope;
5550   LocalContext context;
5551 
5552   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
5553   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
5554   instance_template->SetCallAsFunctionHandler(call_as_function);
5555   Local<v8::Object> instance = t->GetFunction()->NewInstance();
5556   context->Global()->Set(v8_str("obj"), instance);
5557   v8::TryCatch try_catch;
5558   Local<Value> value;
5559   CHECK(!try_catch.HasCaught());
5560 
5561   value = CompileRun("obj(42)");
5562   CHECK(!try_catch.HasCaught());
5563   CHECK_EQ(42, value->Int32Value());
5564 
5565   value = CompileRun("(function(o){return o(49)})(obj)");
5566   CHECK(!try_catch.HasCaught());
5567   CHECK_EQ(49, value->Int32Value());
5568 
5569   // test special case of call as function
5570   value = CompileRun("[obj]['0'](45)");
5571   CHECK(!try_catch.HasCaught());
5572   CHECK_EQ(45, value->Int32Value());
5573 
5574   value = CompileRun("obj.call = Function.prototype.call;"
5575                      "obj.call(null, 87)");
5576   CHECK(!try_catch.HasCaught());
5577   CHECK_EQ(87, value->Int32Value());
5578 
5579   // Regression tests for bug #1116356: Calling call through call/apply
5580   // must work for non-function receivers.
5581   const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
5582   value = CompileRun(apply_99);
5583   CHECK(!try_catch.HasCaught());
5584   CHECK_EQ(99, value->Int32Value());
5585 
5586   const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
5587   value = CompileRun(call_17);
5588   CHECK(!try_catch.HasCaught());
5589   CHECK_EQ(17, value->Int32Value());
5590 
5591   // Check that the call-as-function handler can be called through
5592   // new.
5593   value = CompileRun("new obj(43)");
5594   CHECK(!try_catch.HasCaught());
5595   CHECK_EQ(-43, value->Int32Value());
5596 }
5597 
5598 
CountHandles()5599 static int CountHandles() {
5600   return v8::HandleScope::NumberOfHandles();
5601 }
5602 
5603 
Recurse(int depth,int iterations)5604 static int Recurse(int depth, int iterations) {
5605   v8::HandleScope scope;
5606   if (depth == 0) return CountHandles();
5607   for (int i = 0; i < iterations; i++) {
5608     Local<v8::Number> n = v8::Integer::New(42);
5609   }
5610   return Recurse(depth - 1, iterations);
5611 }
5612 
5613 
THREADED_TEST(HandleIteration)5614 THREADED_TEST(HandleIteration) {
5615   static const int kIterations = 500;
5616   static const int kNesting = 200;
5617   CHECK_EQ(0, CountHandles());
5618   {
5619     v8::HandleScope scope1;
5620     CHECK_EQ(0, CountHandles());
5621     for (int i = 0; i < kIterations; i++) {
5622       Local<v8::Number> n = v8::Integer::New(42);
5623       CHECK_EQ(i + 1, CountHandles());
5624     }
5625 
5626     CHECK_EQ(kIterations, CountHandles());
5627     {
5628       v8::HandleScope scope2;
5629       for (int j = 0; j < kIterations; j++) {
5630         Local<v8::Number> n = v8::Integer::New(42);
5631         CHECK_EQ(j + 1 + kIterations, CountHandles());
5632       }
5633     }
5634     CHECK_EQ(kIterations, CountHandles());
5635   }
5636   CHECK_EQ(0, CountHandles());
5637   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
5638 }
5639 
5640 
InterceptorHasOwnPropertyGetter(Local<String> name,const AccessorInfo & info)5641 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
5642     Local<String> name,
5643     const AccessorInfo& info) {
5644   ApiTestFuzzer::Fuzz();
5645   return v8::Handle<Value>();
5646 }
5647 
5648 
THREADED_TEST(InterceptorHasOwnProperty)5649 THREADED_TEST(InterceptorHasOwnProperty) {
5650   v8::HandleScope scope;
5651   LocalContext context;
5652   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5653   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5654   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
5655   Local<Function> function = fun_templ->GetFunction();
5656   context->Global()->Set(v8_str("constructor"), function);
5657   v8::Handle<Value> value = CompileRun(
5658       "var o = new constructor();"
5659       "o.hasOwnProperty('ostehaps');");
5660   CHECK_EQ(false, value->BooleanValue());
5661   value = CompileRun(
5662       "o.ostehaps = 42;"
5663       "o.hasOwnProperty('ostehaps');");
5664   CHECK_EQ(true, value->BooleanValue());
5665   value = CompileRun(
5666       "var p = new constructor();"
5667       "p.hasOwnProperty('ostehaps');");
5668   CHECK_EQ(false, value->BooleanValue());
5669 }
5670 
5671 
InterceptorHasOwnPropertyGetterGC(Local<String> name,const AccessorInfo & info)5672 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
5673     Local<String> name,
5674     const AccessorInfo& info) {
5675   ApiTestFuzzer::Fuzz();
5676   i::Heap::CollectAllGarbage(false);
5677   return v8::Handle<Value>();
5678 }
5679 
5680 
THREADED_TEST(InterceptorHasOwnPropertyCausingGC)5681 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
5682   v8::HandleScope scope;
5683   LocalContext context;
5684   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
5685   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5686   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
5687   Local<Function> function = fun_templ->GetFunction();
5688   context->Global()->Set(v8_str("constructor"), function);
5689   // Let's first make some stuff so we can be sure to get a good GC.
5690   CompileRun(
5691       "function makestr(size) {"
5692       "  switch (size) {"
5693       "    case 1: return 'f';"
5694       "    case 2: return 'fo';"
5695       "    case 3: return 'foo';"
5696       "  }"
5697       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
5698       "}"
5699       "var x = makestr(12345);"
5700       "x = makestr(31415);"
5701       "x = makestr(23456);");
5702   v8::Handle<Value> value = CompileRun(
5703       "var o = new constructor();"
5704       "o.__proto__ = new String(x);"
5705       "o.hasOwnProperty('ostehaps');");
5706   CHECK_EQ(false, value->BooleanValue());
5707 }
5708 
5709 
5710 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
5711                                                  const AccessorInfo& info);
5712 
5713 
CheckInterceptorLoadIC(NamedPropertyGetter getter,const char * source,int expected)5714 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5715                                    const char* source,
5716                                    int expected) {
5717   v8::HandleScope scope;
5718   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5719   templ->SetNamedPropertyHandler(getter);
5720   LocalContext context;
5721   context->Global()->Set(v8_str("o"), templ->NewInstance());
5722   v8::Handle<Value> value = CompileRun(source);
5723   CHECK_EQ(expected, value->Int32Value());
5724 }
5725 
5726 
InterceptorLoadICGetter(Local<String> name,const AccessorInfo & info)5727 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5728                                                  const AccessorInfo& info) {
5729   ApiTestFuzzer::Fuzz();
5730   CHECK(v8_str("x")->Equals(name));
5731   return v8::Integer::New(42);
5732 }
5733 
5734 
5735 // This test should hit the load IC for the interceptor case.
THREADED_TEST(InterceptorLoadIC)5736 THREADED_TEST(InterceptorLoadIC) {
5737   CheckInterceptorLoadIC(InterceptorLoadICGetter,
5738     "var result = 0;"
5739     "for (var i = 0; i < 1000; i++) {"
5740     "  result = o.x;"
5741     "}",
5742     42);
5743 }
5744 
5745 
5746 // Below go several tests which verify that JITing for various
5747 // configurations of interceptor and explicit fields works fine
5748 // (those cases are special cased to get better performance).
5749 
InterceptorLoadXICGetter(Local<String> name,const AccessorInfo & info)5750 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5751                                                  const AccessorInfo& info) {
5752   ApiTestFuzzer::Fuzz();
5753   return v8_str("x")->Equals(name)
5754       ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5755 }
5756 
5757 
THREADED_TEST(InterceptorLoadICWithFieldOnHolder)5758 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5759   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5760     "var result = 0;"
5761     "o.y = 239;"
5762     "for (var i = 0; i < 1000; i++) {"
5763     "  result = o.y;"
5764     "}",
5765     239);
5766 }
5767 
5768 
THREADED_TEST(InterceptorLoadICWithSubstitutedProto)5769 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5770   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5771     "var result = 0;"
5772     "o.__proto__ = { 'y': 239 };"
5773     "for (var i = 0; i < 1000; i++) {"
5774     "  result = o.y + o.x;"
5775     "}",
5776     239 + 42);
5777 }
5778 
5779 
THREADED_TEST(InterceptorLoadICWithPropertyOnProto)5780 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5781   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5782     "var result = 0;"
5783     "o.__proto__.y = 239;"
5784     "for (var i = 0; i < 1000; i++) {"
5785     "  result = o.y + o.x;"
5786     "}",
5787     239 + 42);
5788 }
5789 
5790 
THREADED_TEST(InterceptorLoadICUndefined)5791 THREADED_TEST(InterceptorLoadICUndefined) {
5792   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5793     "var result = 0;"
5794     "for (var i = 0; i < 1000; i++) {"
5795     "  result = (o.y == undefined) ? 239 : 42;"
5796     "}",
5797     239);
5798 }
5799 
5800 
THREADED_TEST(InterceptorLoadICWithOverride)5801 THREADED_TEST(InterceptorLoadICWithOverride) {
5802   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5803     "fst = new Object();  fst.__proto__ = o;"
5804     "snd = new Object();  snd.__proto__ = fst;"
5805     "var result1 = 0;"
5806     "for (var i = 0; i < 1000;  i++) {"
5807     "  result1 = snd.x;"
5808     "}"
5809     "fst.x = 239;"
5810     "var result = 0;"
5811     "for (var i = 0; i < 1000; i++) {"
5812     "  result = snd.x;"
5813     "}"
5814     "result + result1",
5815     239 + 42);
5816 }
5817 
5818 
5819 // Test the case when we stored field into
5820 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICFieldNotNeeded)5821 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5822   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5823     "proto = new Object();"
5824     "o.__proto__ = proto;"
5825     "proto.x = 239;"
5826     "for (var i = 0; i < 1000; i++) {"
5827     "  o.x;"
5828     // Now it should be ICed and keep a reference to x defined on proto
5829     "}"
5830     "var result = 0;"
5831     "for (var i = 0; i < 1000; i++) {"
5832     "  result += o.x;"
5833     "}"
5834     "result;",
5835     42 * 1000);
5836 }
5837 
5838 
5839 // Test the case when we stored field into
5840 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedField)5841 THREADED_TEST(InterceptorLoadICInvalidatedField) {
5842   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5843     "proto1 = new Object();"
5844     "proto2 = new Object();"
5845     "o.__proto__ = proto1;"
5846     "proto1.__proto__ = proto2;"
5847     "proto2.y = 239;"
5848     "for (var i = 0; i < 1000; i++) {"
5849     "  o.y;"
5850     // Now it should be ICed and keep a reference to y defined on proto2
5851     "}"
5852     "proto1.y = 42;"
5853     "var result = 0;"
5854     "for (var i = 0; i < 1000; i++) {"
5855     "  result += o.y;"
5856     "}"
5857     "result;",
5858     42 * 1000);
5859 }
5860 
5861 
5862 // Test the case when we stored field into
5863 // a stub, but it got invalidated later on due to override on
5864 // global object which is between interceptor and fields' holders.
THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal)5865 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
5866   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5867     "o.__proto__ = this;"  // set a global to be a proto of o.
5868     "this.__proto__.y = 239;"
5869     "for (var i = 0; i < 10; i++) {"
5870     "  if (o.y != 239) throw 'oops: ' + o.y;"
5871     // Now it should be ICed and keep a reference to y defined on field_holder.
5872     "}"
5873     "this.y = 42;"  // Assign on a global.
5874     "var result = 0;"
5875     "for (var i = 0; i < 10; i++) {"
5876     "  result += o.y;"
5877     "}"
5878     "result;",
5879     42 * 10);
5880 }
5881 
5882 
Return239(Local<String> name,const AccessorInfo &)5883 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
5884   ApiTestFuzzer::Fuzz();
5885   return v8_num(239);
5886 }
5887 
5888 
SetOnThis(Local<String> name,Local<Value> value,const AccessorInfo & info)5889 static void SetOnThis(Local<String> name,
5890                       Local<Value> value,
5891                       const AccessorInfo& info) {
5892   info.This()->ForceSet(name, value);
5893 }
5894 
5895 
THREADED_TEST(InterceptorLoadICWithCallbackOnHolder)5896 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
5897   v8::HandleScope scope;
5898   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5899   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5900   templ->SetAccessor(v8_str("y"), Return239);
5901   LocalContext context;
5902   context->Global()->Set(v8_str("o"), templ->NewInstance());
5903   v8::Handle<Value> value = CompileRun(
5904       "var result = 0;"
5905       "for (var i = 0; i < 7; i++) {"
5906       "  result = o.y;"
5907       "}");
5908   CHECK_EQ(239, value->Int32Value());
5909 }
5910 
5911 
THREADED_TEST(InterceptorLoadICWithCallbackOnProto)5912 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
5913   v8::HandleScope scope;
5914   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5915   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5916   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5917   templ_p->SetAccessor(v8_str("y"), Return239);
5918 
5919   LocalContext context;
5920   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5921   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5922 
5923   v8::Handle<Value> value = CompileRun(
5924       "o.__proto__ = p;"
5925       "var result = 0;"
5926       "for (var i = 0; i < 7; i++) {"
5927       "  result = o.x + o.y;"
5928       "}");
5929   CHECK_EQ(239 + 42, value->Int32Value());
5930 }
5931 
5932 
THREADED_TEST(InterceptorLoadICForCallbackWithOverride)5933 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
5934   v8::HandleScope scope;
5935   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5936   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5937   templ->SetAccessor(v8_str("y"), Return239);
5938 
5939   LocalContext context;
5940   context->Global()->Set(v8_str("o"), templ->NewInstance());
5941 
5942   v8::Handle<Value> value = CompileRun(
5943     "fst = new Object();  fst.__proto__ = o;"
5944     "snd = new Object();  snd.__proto__ = fst;"
5945     "var result1 = 0;"
5946     "for (var i = 0; i < 7;  i++) {"
5947     "  result1 = snd.x;"
5948     "}"
5949     "fst.x = 239;"
5950     "var result = 0;"
5951     "for (var i = 0; i < 7; i++) {"
5952     "  result = snd.x;"
5953     "}"
5954     "result + result1");
5955   CHECK_EQ(239 + 42, value->Int32Value());
5956 }
5957 
5958 
5959 // Test the case when we stored callback into
5960 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICCallbackNotNeeded)5961 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
5962   v8::HandleScope scope;
5963   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5964   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5965   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5966   templ_p->SetAccessor(v8_str("y"), Return239);
5967 
5968   LocalContext context;
5969   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5970   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5971 
5972   v8::Handle<Value> value = CompileRun(
5973     "o.__proto__ = p;"
5974     "for (var i = 0; i < 7; i++) {"
5975     "  o.x;"
5976     // Now it should be ICed and keep a reference to x defined on p
5977     "}"
5978     "var result = 0;"
5979     "for (var i = 0; i < 7; i++) {"
5980     "  result += o.x;"
5981     "}"
5982     "result");
5983   CHECK_EQ(42 * 7, value->Int32Value());
5984 }
5985 
5986 
5987 // Test the case when we stored callback into
5988 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedCallback)5989 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
5990   v8::HandleScope scope;
5991   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5992   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5993   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5994   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5995 
5996   LocalContext context;
5997   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5998   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5999 
6000   v8::Handle<Value> value = CompileRun(
6001     "inbetween = new Object();"
6002     "o.__proto__ = inbetween;"
6003     "inbetween.__proto__ = p;"
6004     "for (var i = 0; i < 10; i++) {"
6005     "  o.y;"
6006     // Now it should be ICed and keep a reference to y defined on p
6007     "}"
6008     "inbetween.y = 42;"
6009     "var result = 0;"
6010     "for (var i = 0; i < 10; i++) {"
6011     "  result += o.y;"
6012     "}"
6013     "result");
6014   CHECK_EQ(42 * 10, value->Int32Value());
6015 }
6016 
6017 
6018 // Test the case when we stored callback into
6019 // a stub, but it got invalidated later on due to override on
6020 // global object which is between interceptor and callbacks' holders.
THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal)6021 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
6022   v8::HandleScope scope;
6023   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6024   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6025   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
6026   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
6027 
6028   LocalContext context;
6029   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6030   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
6031 
6032   v8::Handle<Value> value = CompileRun(
6033     "o.__proto__ = this;"
6034     "this.__proto__ = p;"
6035     "for (var i = 0; i < 10; i++) {"
6036     "  if (o.y != 239) throw 'oops: ' + o.y;"
6037     // Now it should be ICed and keep a reference to y defined on p
6038     "}"
6039     "this.y = 42;"
6040     "var result = 0;"
6041     "for (var i = 0; i < 10; i++) {"
6042     "  result += o.y;"
6043     "}"
6044     "result");
6045   CHECK_EQ(42 * 10, value->Int32Value());
6046 }
6047 
6048 
InterceptorLoadICGetter0(Local<String> name,const AccessorInfo & info)6049 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
6050                                                   const AccessorInfo& info) {
6051   ApiTestFuzzer::Fuzz();
6052   CHECK(v8_str("x")->Equals(name));
6053   return v8::Integer::New(0);
6054 }
6055 
6056 
THREADED_TEST(InterceptorReturningZero)6057 THREADED_TEST(InterceptorReturningZero) {
6058   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
6059      "o.x == undefined ? 1 : 0",
6060      0);
6061 }
6062 
6063 
InterceptorStoreICSetter(Local<String> key,Local<Value> value,const AccessorInfo &)6064 static v8::Handle<Value> InterceptorStoreICSetter(
6065     Local<String> key, Local<Value> value, const AccessorInfo&) {
6066   CHECK(v8_str("x")->Equals(key));
6067   CHECK_EQ(42, value->Int32Value());
6068   return value;
6069 }
6070 
6071 
6072 // This test should hit the store IC for the interceptor case.
THREADED_TEST(InterceptorStoreIC)6073 THREADED_TEST(InterceptorStoreIC) {
6074   v8::HandleScope scope;
6075   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6076   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
6077                                  InterceptorStoreICSetter);
6078   LocalContext context;
6079   context->Global()->Set(v8_str("o"), templ->NewInstance());
6080   v8::Handle<Value> value = CompileRun(
6081     "for (var i = 0; i < 1000; i++) {"
6082     "  o.x = 42;"
6083     "}");
6084 }
6085 
6086 
THREADED_TEST(InterceptorStoreICWithNoSetter)6087 THREADED_TEST(InterceptorStoreICWithNoSetter) {
6088   v8::HandleScope scope;
6089   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6090   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
6091   LocalContext context;
6092   context->Global()->Set(v8_str("o"), templ->NewInstance());
6093   v8::Handle<Value> value = CompileRun(
6094     "for (var i = 0; i < 1000; i++) {"
6095     "  o.y = 239;"
6096     "}"
6097     "42 + o.y");
6098   CHECK_EQ(239 + 42, value->Int32Value());
6099 }
6100 
6101 
6102 
6103 
6104 v8::Handle<Value> call_ic_function;
6105 v8::Handle<Value> call_ic_function2;
6106 v8::Handle<Value> call_ic_function3;
6107 
InterceptorCallICGetter(Local<String> name,const AccessorInfo & info)6108 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
6109                                                  const AccessorInfo& info) {
6110   ApiTestFuzzer::Fuzz();
6111   CHECK(v8_str("x")->Equals(name));
6112   return call_ic_function;
6113 }
6114 
6115 
6116 // This test should hit the call IC for the interceptor case.
THREADED_TEST(InterceptorCallIC)6117 THREADED_TEST(InterceptorCallIC) {
6118   v8::HandleScope scope;
6119   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6120   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
6121   LocalContext context;
6122   context->Global()->Set(v8_str("o"), templ->NewInstance());
6123   call_ic_function =
6124       v8_compile("function f(x) { return x + 1; }; f")->Run();
6125   v8::Handle<Value> value = CompileRun(
6126     "var result = 0;"
6127     "for (var i = 0; i < 1000; i++) {"
6128     "  result = o.x(41);"
6129     "}");
6130   CHECK_EQ(42, value->Int32Value());
6131 }
6132 
6133 
6134 // This test checks that if interceptor doesn't provide
6135 // a value, we can fetch regular value.
THREADED_TEST(InterceptorCallICSeesOthers)6136 THREADED_TEST(InterceptorCallICSeesOthers) {
6137   v8::HandleScope scope;
6138   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6139   templ->SetNamedPropertyHandler(NoBlockGetterX);
6140   LocalContext context;
6141   context->Global()->Set(v8_str("o"), templ->NewInstance());
6142   v8::Handle<Value> value = CompileRun(
6143     "o.x = function f(x) { return x + 1; };"
6144     "var result = 0;"
6145     "for (var i = 0; i < 7; i++) {"
6146     "  result = o.x(41);"
6147     "}");
6148   CHECK_EQ(42, value->Int32Value());
6149 }
6150 
6151 
6152 static v8::Handle<Value> call_ic_function4;
InterceptorCallICGetter4(Local<String> name,const AccessorInfo & info)6153 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
6154                                                   const AccessorInfo& info) {
6155   ApiTestFuzzer::Fuzz();
6156   CHECK(v8_str("x")->Equals(name));
6157   return call_ic_function4;
6158 }
6159 
6160 
6161 // This test checks that if interceptor provides a function,
6162 // even if we cached shadowed variant, interceptor's function
6163 // is invoked
THREADED_TEST(InterceptorCallICCacheableNotNeeded)6164 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
6165   v8::HandleScope scope;
6166   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6167   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
6168   LocalContext context;
6169   context->Global()->Set(v8_str("o"), templ->NewInstance());
6170   call_ic_function4 =
6171       v8_compile("function f(x) { return x - 1; }; f")->Run();
6172   v8::Handle<Value> value = CompileRun(
6173     "o.__proto__.x = function(x) { return x + 1; };"
6174     "var result = 0;"
6175     "for (var i = 0; i < 1000; i++) {"
6176     "  result = o.x(42);"
6177     "}");
6178   CHECK_EQ(41, value->Int32Value());
6179 }
6180 
6181 
6182 // Test the case when we stored cacheable lookup into
6183 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedCacheable)6184 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
6185   v8::HandleScope scope;
6186   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6187   templ->SetNamedPropertyHandler(NoBlockGetterX);
6188   LocalContext context;
6189   context->Global()->Set(v8_str("o"), templ->NewInstance());
6190   v8::Handle<Value> value = CompileRun(
6191     "proto1 = new Object();"
6192     "proto2 = new Object();"
6193     "o.__proto__ = proto1;"
6194     "proto1.__proto__ = proto2;"
6195     "proto2.y = function(x) { return x + 1; };"
6196     // Invoke it many times to compile a stub
6197     "for (var i = 0; i < 7; i++) {"
6198     "  o.y(42);"
6199     "}"
6200     "proto1.y = function(x) { return x - 1; };"
6201     "var result = 0;"
6202     "for (var i = 0; i < 7; i++) {"
6203     "  result += o.y(42);"
6204     "}");
6205   CHECK_EQ(41 * 7, value->Int32Value());
6206 }
6207 
6208 
6209 static v8::Handle<Value> call_ic_function5;
InterceptorCallICGetter5(Local<String> name,const AccessorInfo & info)6210 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
6211                                                   const AccessorInfo& info) {
6212   ApiTestFuzzer::Fuzz();
6213   if (v8_str("x")->Equals(name))
6214     return call_ic_function5;
6215   else
6216     return Local<Value>();
6217 }
6218 
6219 
6220 // This test checks that if interceptor doesn't provide a function,
6221 // cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed)6222 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
6223   v8::HandleScope scope;
6224   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6225   templ->SetNamedPropertyHandler(NoBlockGetterX);
6226   LocalContext context;
6227   context->Global()->Set(v8_str("o"), templ->NewInstance());
6228   v8::Handle<Value> value = CompileRun(
6229     "function inc(x) { return x + 1; };"
6230     "inc(1);"
6231     "o.x = inc;"
6232     "var result = 0;"
6233     "for (var i = 0; i < 1000; i++) {"
6234     "  result = o.x(42);"
6235     "}");
6236   CHECK_EQ(43, value->Int32Value());
6237 }
6238 
6239 
6240 // This test checks that if interceptor provides a function,
6241 // even if we cached constant function, interceptor's function
6242 // is invoked
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded)6243 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
6244   v8::HandleScope scope;
6245   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6246   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
6247   LocalContext context;
6248   context->Global()->Set(v8_str("o"), templ->NewInstance());
6249   call_ic_function5 =
6250       v8_compile("function f(x) { return x - 1; }; f")->Run();
6251   v8::Handle<Value> value = CompileRun(
6252     "function inc(x) { return x + 1; };"
6253     "inc(1);"
6254     "o.x = inc;"
6255     "var result = 0;"
6256     "for (var i = 0; i < 1000; i++) {"
6257     "  result = o.x(42);"
6258     "}");
6259   CHECK_EQ(41, value->Int32Value());
6260 }
6261 
6262 
6263 // Test the case when we stored constant function into
6264 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction)6265 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
6266   v8::HandleScope scope;
6267   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6268   templ->SetNamedPropertyHandler(NoBlockGetterX);
6269   LocalContext context;
6270   context->Global()->Set(v8_str("o"), templ->NewInstance());
6271   v8::Handle<Value> value = CompileRun(
6272     "function inc(x) { return x + 1; };"
6273     "inc(1);"
6274     "proto1 = new Object();"
6275     "proto2 = new Object();"
6276     "o.__proto__ = proto1;"
6277     "proto1.__proto__ = proto2;"
6278     "proto2.y = inc;"
6279     // Invoke it many times to compile a stub
6280     "for (var i = 0; i < 7; i++) {"
6281     "  o.y(42);"
6282     "}"
6283     "proto1.y = function(x) { return x - 1; };"
6284     "var result = 0;"
6285     "for (var i = 0; i < 7; i++) {"
6286     "  result += o.y(42);"
6287     "}");
6288   CHECK_EQ(41 * 7, value->Int32Value());
6289 }
6290 
6291 
6292 // Test the case when we stored constant function into
6293 // a stub, but it got invalidated later on due to override on
6294 // global object which is between interceptor and constant function' holders.
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal)6295 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
6296   v8::HandleScope scope;
6297   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6298   templ->SetNamedPropertyHandler(NoBlockGetterX);
6299   LocalContext context;
6300   context->Global()->Set(v8_str("o"), templ->NewInstance());
6301   v8::Handle<Value> value = CompileRun(
6302     "function inc(x) { return x + 1; };"
6303     "inc(1);"
6304     "o.__proto__ = this;"
6305     "this.__proto__.y = inc;"
6306     // Invoke it many times to compile a stub
6307     "for (var i = 0; i < 7; i++) {"
6308     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
6309     "}"
6310     "this.y = function(x) { return x - 1; };"
6311     "var result = 0;"
6312     "for (var i = 0; i < 7; i++) {"
6313     "  result += o.y(42);"
6314     "}");
6315   CHECK_EQ(41 * 7, value->Int32Value());
6316 }
6317 
6318 
6319 // Test the case when actual function to call sits on global object.
THREADED_TEST(InterceptorCallICCachedFromGlobal)6320 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
6321   v8::HandleScope scope;
6322   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
6323   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
6324 
6325   LocalContext context;
6326   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
6327 
6328   v8::Handle<Value> value = CompileRun(
6329     "try {"
6330     "  o.__proto__ = this;"
6331     "  for (var i = 0; i < 10; i++) {"
6332     "    var v = o.parseFloat('239');"
6333     "    if (v != 239) throw v;"
6334       // Now it should be ICed and keep a reference to parseFloat.
6335     "  }"
6336     "  var result = 0;"
6337     "  for (var i = 0; i < 10; i++) {"
6338     "    result += o.parseFloat('239');"
6339     "  }"
6340     "  result"
6341     "} catch(e) {"
6342     "  e"
6343     "};");
6344   CHECK_EQ(239 * 10, value->Int32Value());
6345 }
6346 
InterceptorCallICFastApi(Local<String> name,const AccessorInfo & info)6347 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
6348                                                   const AccessorInfo& info) {
6349   ApiTestFuzzer::Fuzz();
6350   int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data()));
6351   ++(*call_count);
6352   if ((*call_count) % 20 == 0) {
6353     v8::internal::Heap::CollectAllGarbage(true);
6354   }
6355   return v8::Handle<Value>();
6356 }
6357 
FastApiCallback_TrivialSignature(const v8::Arguments & args)6358 static v8::Handle<Value> FastApiCallback_TrivialSignature(
6359     const v8::Arguments& args) {
6360   ApiTestFuzzer::Fuzz();
6361   CHECK_EQ(args.This(), args.Holder());
6362   CHECK(args.Data()->Equals(v8_str("method_data")));
6363   return v8::Integer::New(args[0]->Int32Value() + 1);
6364 }
6365 
FastApiCallback_SimpleSignature(const v8::Arguments & args)6366 static v8::Handle<Value> FastApiCallback_SimpleSignature(
6367     const v8::Arguments& args) {
6368   ApiTestFuzzer::Fuzz();
6369   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
6370   CHECK(args.Data()->Equals(v8_str("method_data")));
6371   // Note, we're using HasRealNamedProperty instead of Has to avoid
6372   // invoking the interceptor again.
6373   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
6374   return v8::Integer::New(args[0]->Int32Value() + 1);
6375 }
6376 
6377 // Helper to maximize the odds of object moving.
GenerateSomeGarbage()6378 static void GenerateSomeGarbage() {
6379   CompileRun(
6380       "var garbage;"
6381       "for (var i = 0; i < 1000; i++) {"
6382       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
6383       "}"
6384       "garbage = undefined;");
6385 }
6386 
THREADED_TEST(InterceptorCallICFastApi_TrivialSignature)6387 THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) {
6388   int interceptor_call_count = 0;
6389   v8::HandleScope scope;
6390   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6391   v8::Handle<v8::FunctionTemplate> method_templ =
6392       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6393                                 v8_str("method_data"),
6394                                 v8::Handle<v8::Signature>());
6395   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6396   proto_templ->Set(v8_str("method"), method_templ);
6397   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6398   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6399                                  NULL, NULL, NULL, NULL,
6400                                  v8::External::Wrap(&interceptor_call_count));
6401   LocalContext context;
6402   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6403   GenerateSomeGarbage();
6404   context->Global()->Set(v8_str("o"), fun->NewInstance());
6405   v8::Handle<Value> value = CompileRun(
6406       "var result = 0;"
6407       "for (var i = 0; i < 100; i++) {"
6408       "  result = o.method(41);"
6409       "}");
6410   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6411   CHECK_EQ(100, interceptor_call_count);
6412 }
6413 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature)6414 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
6415   int interceptor_call_count = 0;
6416   v8::HandleScope scope;
6417   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6418   v8::Handle<v8::FunctionTemplate> method_templ =
6419       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6420                                 v8_str("method_data"),
6421                                 v8::Signature::New(fun_templ));
6422   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6423   proto_templ->Set(v8_str("method"), method_templ);
6424   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6425   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6426                                  NULL, NULL, NULL, NULL,
6427                                  v8::External::Wrap(&interceptor_call_count));
6428   LocalContext context;
6429   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6430   GenerateSomeGarbage();
6431   context->Global()->Set(v8_str("o"), fun->NewInstance());
6432   v8::Handle<Value> value = CompileRun(
6433       "o.foo = 17;"
6434       "var receiver = {};"
6435       "receiver.__proto__ = o;"
6436       "var result = 0;"
6437       "for (var i = 0; i < 100; i++) {"
6438       "  result = receiver.method(41);"
6439       "}");
6440   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6441   CHECK_EQ(100, interceptor_call_count);
6442 }
6443 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1)6444 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
6445   int interceptor_call_count = 0;
6446   v8::HandleScope scope;
6447   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6448   v8::Handle<v8::FunctionTemplate> method_templ =
6449       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6450                                 v8_str("method_data"),
6451                                 v8::Signature::New(fun_templ));
6452   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6453   proto_templ->Set(v8_str("method"), method_templ);
6454   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6455   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6456                                  NULL, NULL, NULL, NULL,
6457                                  v8::External::Wrap(&interceptor_call_count));
6458   LocalContext context;
6459   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6460   GenerateSomeGarbage();
6461   context->Global()->Set(v8_str("o"), fun->NewInstance());
6462   v8::Handle<Value> value = CompileRun(
6463       "o.foo = 17;"
6464       "var receiver = {};"
6465       "receiver.__proto__ = o;"
6466       "var result = 0;"
6467       "var saved_result = 0;"
6468       "for (var i = 0; i < 100; i++) {"
6469       "  result = receiver.method(41);"
6470       "  if (i == 50) {"
6471       "    saved_result = result;"
6472       "    receiver = {method: function(x) { return x - 1 }};"
6473       "  }"
6474       "}");
6475   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6476   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6477   CHECK_GE(interceptor_call_count, 50);
6478 }
6479 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2)6480 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
6481   int interceptor_call_count = 0;
6482   v8::HandleScope scope;
6483   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6484   v8::Handle<v8::FunctionTemplate> method_templ =
6485       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6486                                 v8_str("method_data"),
6487                                 v8::Signature::New(fun_templ));
6488   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6489   proto_templ->Set(v8_str("method"), method_templ);
6490   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6491   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6492                                  NULL, NULL, NULL, NULL,
6493                                  v8::External::Wrap(&interceptor_call_count));
6494   LocalContext context;
6495   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6496   GenerateSomeGarbage();
6497   context->Global()->Set(v8_str("o"), fun->NewInstance());
6498   v8::Handle<Value> value = CompileRun(
6499       "o.foo = 17;"
6500       "var receiver = {};"
6501       "receiver.__proto__ = o;"
6502       "var result = 0;"
6503       "var saved_result = 0;"
6504       "for (var i = 0; i < 100; i++) {"
6505       "  result = receiver.method(41);"
6506       "  if (i == 50) {"
6507       "    saved_result = result;"
6508       "    o.method = function(x) { return x - 1 };"
6509       "  }"
6510       "}");
6511   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6512   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6513   CHECK_GE(interceptor_call_count, 50);
6514 }
6515 
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError)6516 THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
6517   int interceptor_call_count = 0;
6518   v8::HandleScope scope;
6519   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6520   v8::Handle<v8::FunctionTemplate> method_templ =
6521       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6522                                 v8_str("method_data"),
6523                                 v8::Signature::New(fun_templ));
6524   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6525   proto_templ->Set(v8_str("method"), method_templ);
6526   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6527   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
6528                                  NULL, NULL, NULL, NULL,
6529                                  v8::External::Wrap(&interceptor_call_count));
6530   LocalContext context;
6531   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6532   GenerateSomeGarbage();
6533   context->Global()->Set(v8_str("o"), fun->NewInstance());
6534   v8::TryCatch try_catch;
6535   v8::Handle<Value> value = CompileRun(
6536       "o.foo = 17;"
6537       "var receiver = {};"
6538       "receiver.__proto__ = o;"
6539       "var result = 0;"
6540       "var saved_result = 0;"
6541       "for (var i = 0; i < 100; i++) {"
6542       "  result = receiver.method(41);"
6543       "  if (i == 50) {"
6544       "    saved_result = result;"
6545       "    receiver = {method: receiver.method};"
6546       "  }"
6547       "}");
6548   CHECK(try_catch.HasCaught());
6549   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
6550            try_catch.Exception()->ToString());
6551   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6552   CHECK_GE(interceptor_call_count, 50);
6553 }
6554 
THREADED_TEST(CallICFastApi_TrivialSignature)6555 THREADED_TEST(CallICFastApi_TrivialSignature) {
6556   v8::HandleScope scope;
6557   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6558   v8::Handle<v8::FunctionTemplate> method_templ =
6559       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
6560                                 v8_str("method_data"),
6561                                 v8::Handle<v8::Signature>());
6562   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6563   proto_templ->Set(v8_str("method"), method_templ);
6564   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6565   LocalContext context;
6566   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6567   GenerateSomeGarbage();
6568   context->Global()->Set(v8_str("o"), fun->NewInstance());
6569   v8::Handle<Value> value = CompileRun(
6570       "var result = 0;"
6571       "for (var i = 0; i < 100; i++) {"
6572       "  result = o.method(41);"
6573       "}");
6574 
6575   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6576 }
6577 
THREADED_TEST(CallICFastApi_SimpleSignature)6578 THREADED_TEST(CallICFastApi_SimpleSignature) {
6579   v8::HandleScope scope;
6580   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6581   v8::Handle<v8::FunctionTemplate> method_templ =
6582       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6583                                 v8_str("method_data"),
6584                                 v8::Signature::New(fun_templ));
6585   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6586   proto_templ->Set(v8_str("method"), method_templ);
6587   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6588   LocalContext context;
6589   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6590   GenerateSomeGarbage();
6591   context->Global()->Set(v8_str("o"), fun->NewInstance());
6592   v8::Handle<Value> value = CompileRun(
6593       "o.foo = 17;"
6594       "var receiver = {};"
6595       "receiver.__proto__ = o;"
6596       "var result = 0;"
6597       "for (var i = 0; i < 100; i++) {"
6598       "  result = receiver.method(41);"
6599       "}");
6600 
6601   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
6602 }
6603 
THREADED_TEST(CallICFastApi_SimpleSignature_Miss)6604 THREADED_TEST(CallICFastApi_SimpleSignature_Miss) {
6605   v8::HandleScope scope;
6606   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
6607   v8::Handle<v8::FunctionTemplate> method_templ =
6608       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
6609                                 v8_str("method_data"),
6610                                 v8::Signature::New(fun_templ));
6611   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
6612   proto_templ->Set(v8_str("method"), method_templ);
6613   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
6614   LocalContext context;
6615   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
6616   GenerateSomeGarbage();
6617   context->Global()->Set(v8_str("o"), fun->NewInstance());
6618   v8::Handle<Value> value = CompileRun(
6619       "o.foo = 17;"
6620       "var receiver = {};"
6621       "receiver.__proto__ = o;"
6622       "var result = 0;"
6623       "var saved_result = 0;"
6624       "for (var i = 0; i < 100; i++) {"
6625       "  result = receiver.method(41);"
6626       "  if (i == 50) {"
6627       "    saved_result = result;"
6628       "    receiver = {method: function(x) { return x - 1 }};"
6629       "  }"
6630       "}");
6631   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
6632   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
6633 }
6634 
6635 
6636 static int interceptor_call_count = 0;
6637 
InterceptorICRefErrorGetter(Local<String> name,const AccessorInfo & info)6638 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
6639                                                      const AccessorInfo& info) {
6640   ApiTestFuzzer::Fuzz();
6641   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
6642     return call_ic_function2;
6643   }
6644   return v8::Handle<Value>();
6645 }
6646 
6647 
6648 // This test should hit load and call ICs for the interceptor case.
6649 // Once in a while, the interceptor will reply that a property was not
6650 // found in which case we should get a reference error.
THREADED_TEST(InterceptorICReferenceErrors)6651 THREADED_TEST(InterceptorICReferenceErrors) {
6652   v8::HandleScope scope;
6653   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6654   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
6655   LocalContext context(0, templ, v8::Handle<Value>());
6656   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
6657   v8::Handle<Value> value = CompileRun(
6658     "function f() {"
6659     "  for (var i = 0; i < 1000; i++) {"
6660     "    try { x; } catch(e) { return true; }"
6661     "  }"
6662     "  return false;"
6663     "};"
6664     "f();");
6665   CHECK_EQ(true, value->BooleanValue());
6666   interceptor_call_count = 0;
6667   value = CompileRun(
6668     "function g() {"
6669     "  for (var i = 0; i < 1000; i++) {"
6670     "    try { x(42); } catch(e) { return true; }"
6671     "  }"
6672     "  return false;"
6673     "};"
6674     "g();");
6675   CHECK_EQ(true, value->BooleanValue());
6676 }
6677 
6678 
6679 static int interceptor_ic_exception_get_count = 0;
6680 
InterceptorICExceptionGetter(Local<String> name,const AccessorInfo & info)6681 static v8::Handle<Value> InterceptorICExceptionGetter(
6682     Local<String> name,
6683     const AccessorInfo& info) {
6684   ApiTestFuzzer::Fuzz();
6685   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
6686     return call_ic_function3;
6687   }
6688   if (interceptor_ic_exception_get_count == 20) {
6689     return v8::ThrowException(v8_num(42));
6690   }
6691   // Do not handle get for properties other than x.
6692   return v8::Handle<Value>();
6693 }
6694 
6695 // Test interceptor load/call IC where the interceptor throws an
6696 // exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions)6697 THREADED_TEST(InterceptorICGetterExceptions) {
6698   interceptor_ic_exception_get_count = 0;
6699   v8::HandleScope scope;
6700   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6701   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
6702   LocalContext context(0, templ, v8::Handle<Value>());
6703   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
6704   v8::Handle<Value> value = CompileRun(
6705     "function f() {"
6706     "  for (var i = 0; i < 100; i++) {"
6707     "    try { x; } catch(e) { return true; }"
6708     "  }"
6709     "  return false;"
6710     "};"
6711     "f();");
6712   CHECK_EQ(true, value->BooleanValue());
6713   interceptor_ic_exception_get_count = 0;
6714   value = CompileRun(
6715     "function f() {"
6716     "  for (var i = 0; i < 100; i++) {"
6717     "    try { x(42); } catch(e) { return true; }"
6718     "  }"
6719     "  return false;"
6720     "};"
6721     "f();");
6722   CHECK_EQ(true, value->BooleanValue());
6723 }
6724 
6725 
6726 static int interceptor_ic_exception_set_count = 0;
6727 
InterceptorICExceptionSetter(Local<String> key,Local<Value> value,const AccessorInfo &)6728 static v8::Handle<Value> InterceptorICExceptionSetter(
6729       Local<String> key, Local<Value> value, const AccessorInfo&) {
6730   ApiTestFuzzer::Fuzz();
6731   if (++interceptor_ic_exception_set_count > 20) {
6732     return v8::ThrowException(v8_num(42));
6733   }
6734   // Do not actually handle setting.
6735   return v8::Handle<Value>();
6736 }
6737 
6738 // Test interceptor store IC where the interceptor throws an exception
6739 // once in a while.
THREADED_TEST(InterceptorICSetterExceptions)6740 THREADED_TEST(InterceptorICSetterExceptions) {
6741   interceptor_ic_exception_set_count = 0;
6742   v8::HandleScope scope;
6743   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6744   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
6745   LocalContext context(0, templ, v8::Handle<Value>());
6746   v8::Handle<Value> value = CompileRun(
6747     "function f() {"
6748     "  for (var i = 0; i < 100; i++) {"
6749     "    try { x = 42; } catch(e) { return true; }"
6750     "  }"
6751     "  return false;"
6752     "};"
6753     "f();");
6754   CHECK_EQ(true, value->BooleanValue());
6755 }
6756 
6757 
6758 // Test that we ignore null interceptors.
THREADED_TEST(NullNamedInterceptor)6759 THREADED_TEST(NullNamedInterceptor) {
6760   v8::HandleScope scope;
6761   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6762   templ->SetNamedPropertyHandler(0);
6763   LocalContext context;
6764   templ->Set("x", v8_num(42));
6765   v8::Handle<v8::Object> obj = templ->NewInstance();
6766   context->Global()->Set(v8_str("obj"), obj);
6767   v8::Handle<Value> value = CompileRun("obj.x");
6768   CHECK(value->IsInt32());
6769   CHECK_EQ(42, value->Int32Value());
6770 }
6771 
6772 
6773 // Test that we ignore null interceptors.
THREADED_TEST(NullIndexedInterceptor)6774 THREADED_TEST(NullIndexedInterceptor) {
6775   v8::HandleScope scope;
6776   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6777   templ->SetIndexedPropertyHandler(0);
6778   LocalContext context;
6779   templ->Set("42", v8_num(42));
6780   v8::Handle<v8::Object> obj = templ->NewInstance();
6781   context->Global()->Set(v8_str("obj"), obj);
6782   v8::Handle<Value> value = CompileRun("obj[42]");
6783   CHECK(value->IsInt32());
6784   CHECK_EQ(42, value->Int32Value());
6785 }
6786 
6787 
ParentGetter(Local<String> name,const AccessorInfo & info)6788 static v8::Handle<Value> ParentGetter(Local<String> name,
6789                                       const AccessorInfo& info) {
6790   ApiTestFuzzer::Fuzz();
6791   return v8_num(1);
6792 }
6793 
6794 
ChildGetter(Local<String> name,const AccessorInfo & info)6795 static v8::Handle<Value> ChildGetter(Local<String> name,
6796                                      const AccessorInfo& info) {
6797   ApiTestFuzzer::Fuzz();
6798   return v8_num(42);
6799 }
6800 
6801 
THREADED_TEST(Overriding)6802 THREADED_TEST(Overriding) {
6803   v8::HandleScope scope;
6804   LocalContext context;
6805 
6806   // Parent template.
6807   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
6808   Local<ObjectTemplate> parent_instance_templ =
6809       parent_templ->InstanceTemplate();
6810   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
6811 
6812   // Template that inherits from the parent template.
6813   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
6814   Local<ObjectTemplate> child_instance_templ =
6815       child_templ->InstanceTemplate();
6816   child_templ->Inherit(parent_templ);
6817   // Override 'f'.  The child version of 'f' should get called for child
6818   // instances.
6819   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
6820   // Add 'g' twice.  The 'g' added last should get called for instances.
6821   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
6822   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
6823 
6824   // Add 'h' as an accessor to the proto template with ReadOnly attributes
6825   // so 'h' can be shadowed on the instance object.
6826   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
6827   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
6828       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
6829 
6830   // Add 'i' as an accessor to the instance template with ReadOnly attributes
6831   // but the attribute does not have effect because it is duplicated with
6832   // NULL setter.
6833   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
6834       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
6835 
6836 
6837 
6838   // Instantiate the child template.
6839   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
6840 
6841   // Check that the child function overrides the parent one.
6842   context->Global()->Set(v8_str("o"), instance);
6843   Local<Value> value = v8_compile("o.f")->Run();
6844   // Check that the 'g' that was added last is hit.
6845   CHECK_EQ(42, value->Int32Value());
6846   value = v8_compile("o.g")->Run();
6847   CHECK_EQ(42, value->Int32Value());
6848 
6849   // Check 'h' can be shadowed.
6850   value = v8_compile("o.h = 3; o.h")->Run();
6851   CHECK_EQ(3, value->Int32Value());
6852 
6853   // Check 'i' is cannot be shadowed or changed.
6854   value = v8_compile("o.i = 3; o.i")->Run();
6855   CHECK_EQ(42, value->Int32Value());
6856 }
6857 
6858 
IsConstructHandler(const v8::Arguments & args)6859 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
6860   ApiTestFuzzer::Fuzz();
6861   if (args.IsConstructCall()) {
6862     return v8::Boolean::New(true);
6863   }
6864   return v8::Boolean::New(false);
6865 }
6866 
6867 
THREADED_TEST(IsConstructCall)6868 THREADED_TEST(IsConstructCall) {
6869   v8::HandleScope scope;
6870 
6871   // Function template with call handler.
6872   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6873   templ->SetCallHandler(IsConstructHandler);
6874 
6875   LocalContext context;
6876 
6877   context->Global()->Set(v8_str("f"), templ->GetFunction());
6878   Local<Value> value = v8_compile("f()")->Run();
6879   CHECK(!value->BooleanValue());
6880   value = v8_compile("new f()")->Run();
6881   CHECK(value->BooleanValue());
6882 }
6883 
6884 
THREADED_TEST(ObjectProtoToString)6885 THREADED_TEST(ObjectProtoToString) {
6886   v8::HandleScope scope;
6887   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
6888   templ->SetClassName(v8_str("MyClass"));
6889 
6890   LocalContext context;
6891 
6892   Local<String> customized_tostring = v8_str("customized toString");
6893 
6894   // Replace Object.prototype.toString
6895   v8_compile("Object.prototype.toString = function() {"
6896                   "  return 'customized toString';"
6897                   "}")->Run();
6898 
6899   // Normal ToString call should call replaced Object.prototype.toString
6900   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
6901   Local<String> value = instance->ToString();
6902   CHECK(value->IsString() && value->Equals(customized_tostring));
6903 
6904   // ObjectProtoToString should not call replace toString function.
6905   value = instance->ObjectProtoToString();
6906   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
6907 
6908   // Check global
6909   value = context->Global()->ObjectProtoToString();
6910   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
6911 
6912   // Check ordinary object
6913   Local<Value> object = v8_compile("new Object()")->Run();
6914   value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
6915   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
6916 }
6917 
6918 
6919 bool ApiTestFuzzer::fuzzing_ = false;
6920 v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
6921   v8::internal::OS::CreateSemaphore(0);
6922 int ApiTestFuzzer::active_tests_;
6923 int ApiTestFuzzer::tests_being_run_;
6924 int ApiTestFuzzer::current_;
6925 
6926 
6927 // We are in a callback and want to switch to another thread (if we
6928 // are currently running the thread fuzzing test).
Fuzz()6929 void ApiTestFuzzer::Fuzz() {
6930   if (!fuzzing_) return;
6931   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
6932   test->ContextSwitch();
6933 }
6934 
6935 
6936 // Let the next thread go.  Since it is also waiting on the V8 lock it may
6937 // not start immediately.
NextThread()6938 bool ApiTestFuzzer::NextThread() {
6939   int test_position = GetNextTestNumber();
6940   const char* test_name = RegisterThreadedTest::nth(current_)->name();
6941   if (test_position == current_) {
6942     if (kLogThreading)
6943       printf("Stay with %s\n", test_name);
6944     return false;
6945   }
6946   if (kLogThreading) {
6947     printf("Switch from %s to %s\n",
6948            test_name,
6949            RegisterThreadedTest::nth(test_position)->name());
6950   }
6951   current_ = test_position;
6952   RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
6953   return true;
6954 }
6955 
6956 
Run()6957 void ApiTestFuzzer::Run() {
6958   // When it is our turn...
6959   gate_->Wait();
6960   {
6961     // ... get the V8 lock and start running the test.
6962     v8::Locker locker;
6963     CallTest();
6964   }
6965   // This test finished.
6966   active_ = false;
6967   active_tests_--;
6968   // If it was the last then signal that fact.
6969   if (active_tests_ == 0) {
6970     all_tests_done_->Signal();
6971   } else {
6972     // Otherwise select a new test and start that.
6973     NextThread();
6974   }
6975 }
6976 
6977 
6978 static unsigned linear_congruential_generator;
6979 
6980 
Setup(PartOfTest part)6981 void ApiTestFuzzer::Setup(PartOfTest part) {
6982   linear_congruential_generator = i::FLAG_testing_prng_seed;
6983   fuzzing_ = true;
6984   int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
6985   int end = (part == FIRST_PART)
6986       ? (RegisterThreadedTest::count() >> 1)
6987       : RegisterThreadedTest::count();
6988   active_tests_ = tests_being_run_ = end - start;
6989   for (int i = 0; i < tests_being_run_; i++) {
6990     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
6991   }
6992   for (int i = 0; i < active_tests_; i++) {
6993     RegisterThreadedTest::nth(i)->fuzzer_->Start();
6994   }
6995 }
6996 
6997 
CallTestNumber(int test_number)6998 static void CallTestNumber(int test_number) {
6999   (RegisterThreadedTest::nth(test_number)->callback())();
7000 }
7001 
7002 
RunAllTests()7003 void ApiTestFuzzer::RunAllTests() {
7004   // Set off the first test.
7005   current_ = -1;
7006   NextThread();
7007   // Wait till they are all done.
7008   all_tests_done_->Wait();
7009 }
7010 
7011 
GetNextTestNumber()7012 int ApiTestFuzzer::GetNextTestNumber() {
7013   int next_test;
7014   do {
7015     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
7016     linear_congruential_generator *= 1664525u;
7017     linear_congruential_generator += 1013904223u;
7018   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
7019   return next_test;
7020 }
7021 
7022 
ContextSwitch()7023 void ApiTestFuzzer::ContextSwitch() {
7024   // If the new thread is the same as the current thread there is nothing to do.
7025   if (NextThread()) {
7026     // Now it can start.
7027     v8::Unlocker unlocker;
7028     // Wait till someone starts us again.
7029     gate_->Wait();
7030     // And we're off.
7031   }
7032 }
7033 
7034 
TearDown()7035 void ApiTestFuzzer::TearDown() {
7036   fuzzing_ = false;
7037   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
7038     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
7039     if (fuzzer != NULL) fuzzer->Join();
7040   }
7041 }
7042 
7043 
7044 // Lets not be needlessly self-referential.
TEST(Threading)7045 TEST(Threading) {
7046   ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
7047   ApiTestFuzzer::RunAllTests();
7048   ApiTestFuzzer::TearDown();
7049 }
7050 
TEST(Threading2)7051 TEST(Threading2) {
7052   ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
7053   ApiTestFuzzer::RunAllTests();
7054   ApiTestFuzzer::TearDown();
7055 }
7056 
7057 
CallTest()7058 void ApiTestFuzzer::CallTest() {
7059   if (kLogThreading)
7060     printf("Start test %d\n", test_number_);
7061   CallTestNumber(test_number_);
7062   if (kLogThreading)
7063     printf("End test %d\n", test_number_);
7064 }
7065 
7066 
ThrowInJS(const v8::Arguments & args)7067 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
7068   CHECK(v8::Locker::IsLocked());
7069   ApiTestFuzzer::Fuzz();
7070   v8::Unlocker unlocker;
7071   const char* code = "throw 7;";
7072   {
7073     v8::Locker nested_locker;
7074     v8::HandleScope scope;
7075     v8::Handle<Value> exception;
7076     { v8::TryCatch try_catch;
7077       v8::Handle<Value> value = CompileRun(code);
7078       CHECK(value.IsEmpty());
7079       CHECK(try_catch.HasCaught());
7080       // Make sure to wrap the exception in a new handle because
7081       // the handle returned from the TryCatch is destroyed
7082       // when the TryCatch is destroyed.
7083       exception = Local<Value>::New(try_catch.Exception());
7084     }
7085     return v8::ThrowException(exception);
7086   }
7087 }
7088 
7089 
ThrowInJSNoCatch(const v8::Arguments & args)7090 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
7091   CHECK(v8::Locker::IsLocked());
7092   ApiTestFuzzer::Fuzz();
7093   v8::Unlocker unlocker;
7094   const char* code = "throw 7;";
7095   {
7096     v8::Locker nested_locker;
7097     v8::HandleScope scope;
7098     v8::Handle<Value> value = CompileRun(code);
7099     CHECK(value.IsEmpty());
7100     return v8_str("foo");
7101   }
7102 }
7103 
7104 
7105 // These are locking tests that don't need to be run again
7106 // as part of the locking aggregation tests.
TEST(NestedLockers)7107 TEST(NestedLockers) {
7108   v8::Locker locker;
7109   CHECK(v8::Locker::IsLocked());
7110   v8::HandleScope scope;
7111   LocalContext env;
7112   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
7113   Local<Function> fun = fun_templ->GetFunction();
7114   env->Global()->Set(v8_str("throw_in_js"), fun);
7115   Local<Script> script = v8_compile("(function () {"
7116                                     "  try {"
7117                                     "    throw_in_js();"
7118                                     "    return 42;"
7119                                     "  } catch (e) {"
7120                                     "    return e * 13;"
7121                                     "  }"
7122                                     "})();");
7123   CHECK_EQ(91, script->Run()->Int32Value());
7124 }
7125 
7126 
7127 // These are locking tests that don't need to be run again
7128 // as part of the locking aggregation tests.
TEST(NestedLockersNoTryCatch)7129 TEST(NestedLockersNoTryCatch) {
7130   v8::Locker locker;
7131   v8::HandleScope scope;
7132   LocalContext env;
7133   Local<v8::FunctionTemplate> fun_templ =
7134       v8::FunctionTemplate::New(ThrowInJSNoCatch);
7135   Local<Function> fun = fun_templ->GetFunction();
7136   env->Global()->Set(v8_str("throw_in_js"), fun);
7137   Local<Script> script = v8_compile("(function () {"
7138                                     "  try {"
7139                                     "    throw_in_js();"
7140                                     "    return 42;"
7141                                     "  } catch (e) {"
7142                                     "    return e * 13;"
7143                                     "  }"
7144                                     "})();");
7145   CHECK_EQ(91, script->Run()->Int32Value());
7146 }
7147 
7148 
THREADED_TEST(RecursiveLocking)7149 THREADED_TEST(RecursiveLocking) {
7150   v8::Locker locker;
7151   {
7152     v8::Locker locker2;
7153     CHECK(v8::Locker::IsLocked());
7154   }
7155 }
7156 
7157 
UnlockForAMoment(const v8::Arguments & args)7158 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
7159   ApiTestFuzzer::Fuzz();
7160   v8::Unlocker unlocker;
7161   return v8::Undefined();
7162 }
7163 
7164 
THREADED_TEST(LockUnlockLock)7165 THREADED_TEST(LockUnlockLock) {
7166   {
7167     v8::Locker locker;
7168     v8::HandleScope scope;
7169     LocalContext env;
7170     Local<v8::FunctionTemplate> fun_templ =
7171         v8::FunctionTemplate::New(UnlockForAMoment);
7172     Local<Function> fun = fun_templ->GetFunction();
7173     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7174     Local<Script> script = v8_compile("(function () {"
7175                                       "  unlock_for_a_moment();"
7176                                       "  return 42;"
7177                                       "})();");
7178     CHECK_EQ(42, script->Run()->Int32Value());
7179   }
7180   {
7181     v8::Locker locker;
7182     v8::HandleScope scope;
7183     LocalContext env;
7184     Local<v8::FunctionTemplate> fun_templ =
7185         v8::FunctionTemplate::New(UnlockForAMoment);
7186     Local<Function> fun = fun_templ->GetFunction();
7187     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
7188     Local<Script> script = v8_compile("(function () {"
7189                                       "  unlock_for_a_moment();"
7190                                       "  return 42;"
7191                                       "})();");
7192     CHECK_EQ(42, script->Run()->Int32Value());
7193   }
7194 }
7195 
7196 
GetGlobalObjectsCount()7197 static int GetGlobalObjectsCount() {
7198   int count = 0;
7199   v8::internal::HeapIterator it;
7200   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
7201     if (object->IsJSGlobalObject()) count++;
7202   return count;
7203 }
7204 
7205 
GetSurvivingGlobalObjectsCount()7206 static int GetSurvivingGlobalObjectsCount() {
7207   // We need to collect all garbage twice to be sure that everything
7208   // has been collected.  This is because inline caches are cleared in
7209   // the first garbage collection but some of the maps have already
7210   // been marked at that point.  Therefore some of the maps are not
7211   // collected until the second garbage collection.
7212   v8::internal::Heap::CollectAllGarbage(false);
7213   v8::internal::Heap::CollectAllGarbage(false);
7214   int count = GetGlobalObjectsCount();
7215 #ifdef DEBUG
7216   if (count > 0) v8::internal::Heap::TracePathToGlobal();
7217 #endif
7218   return count;
7219 }
7220 
7221 
TEST(DontLeakGlobalObjects)7222 TEST(DontLeakGlobalObjects) {
7223   // Regression test for issues 1139850 and 1174891.
7224 
7225   v8::V8::Initialize();
7226 
7227   int count = GetSurvivingGlobalObjectsCount();
7228 
7229   for (int i = 0; i < 5; i++) {
7230     { v8::HandleScope scope;
7231       LocalContext context;
7232     }
7233     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7234 
7235     { v8::HandleScope scope;
7236       LocalContext context;
7237       v8_compile("Date")->Run();
7238     }
7239     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7240 
7241     { v8::HandleScope scope;
7242       LocalContext context;
7243       v8_compile("/aaa/")->Run();
7244     }
7245     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7246 
7247     { v8::HandleScope scope;
7248       const char* extension_list[] = { "v8/gc" };
7249       v8::ExtensionConfiguration extensions(1, extension_list);
7250       LocalContext context(&extensions);
7251       v8_compile("gc();")->Run();
7252     }
7253     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
7254   }
7255 }
7256 
7257 
7258 v8::Persistent<v8::Object> some_object;
7259 v8::Persistent<v8::Object> bad_handle;
7260 
NewPersistentHandleCallback(v8::Persistent<v8::Value>,void *)7261 void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
7262   v8::HandleScope scope;
7263   bad_handle = v8::Persistent<v8::Object>::New(some_object);
7264 }
7265 
7266 
THREADED_TEST(NewPersistentHandleFromWeakCallback)7267 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
7268   LocalContext context;
7269 
7270   v8::Persistent<v8::Object> handle1, handle2;
7271   {
7272     v8::HandleScope scope;
7273     some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
7274     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7275     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7276   }
7277   // Note: order is implementation dependent alas: currently
7278   // global handle nodes are processed by PostGarbageCollectionProcessing
7279   // in reverse allocation order, so if second allocated handle is deleted,
7280   // weak callback of the first handle would be able to 'reallocate' it.
7281   handle1.MakeWeak(NULL, NewPersistentHandleCallback);
7282   handle2.Dispose();
7283   i::Heap::CollectAllGarbage(false);
7284 }
7285 
7286 
7287 v8::Persistent<v8::Object> to_be_disposed;
7288 
DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle,void *)7289 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
7290   to_be_disposed.Dispose();
7291   i::Heap::CollectAllGarbage(false);
7292 }
7293 
7294 
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc)7295 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
7296   LocalContext context;
7297 
7298   v8::Persistent<v8::Object> handle1, handle2;
7299   {
7300     v8::HandleScope scope;
7301     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7302     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7303   }
7304   handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
7305   to_be_disposed = handle2;
7306   i::Heap::CollectAllGarbage(false);
7307 }
7308 
DisposingCallback(v8::Persistent<v8::Value> handle,void *)7309 void DisposingCallback(v8::Persistent<v8::Value> handle, void*) {
7310   handle.Dispose();
7311 }
7312 
HandleCreatingCallback(v8::Persistent<v8::Value> handle,void *)7313 void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) {
7314   v8::HandleScope scope;
7315   v8::Persistent<v8::Object>::New(v8::Object::New());
7316 }
7317 
7318 
THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback)7319 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
7320   LocalContext context;
7321 
7322   v8::Persistent<v8::Object> handle1, handle2, handle3;
7323   {
7324     v8::HandleScope scope;
7325     handle3 = v8::Persistent<v8::Object>::New(v8::Object::New());
7326     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
7327     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
7328   }
7329   handle2.MakeWeak(NULL, DisposingCallback);
7330   handle3.MakeWeak(NULL, HandleCreatingCallback);
7331   i::Heap::CollectAllGarbage(false);
7332 }
7333 
7334 
THREADED_TEST(CheckForCrossContextObjectLiterals)7335 THREADED_TEST(CheckForCrossContextObjectLiterals) {
7336   v8::V8::Initialize();
7337 
7338   const int nof = 2;
7339   const char* sources[nof] = {
7340     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
7341     "Object()"
7342   };
7343 
7344   for (int i = 0; i < nof; i++) {
7345     const char* source = sources[i];
7346     { v8::HandleScope scope;
7347       LocalContext context;
7348       CompileRun(source);
7349     }
7350     { v8::HandleScope scope;
7351       LocalContext context;
7352       CompileRun(source);
7353     }
7354   }
7355 }
7356 
7357 
NestedScope(v8::Persistent<Context> env)7358 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
7359   v8::HandleScope inner;
7360   env->Enter();
7361   v8::Handle<Value> three = v8_num(3);
7362   v8::Handle<Value> value = inner.Close(three);
7363   env->Exit();
7364   return value;
7365 }
7366 
7367 
THREADED_TEST(NestedHandleScopeAndContexts)7368 THREADED_TEST(NestedHandleScopeAndContexts) {
7369   v8::HandleScope outer;
7370   v8::Persistent<Context> env = Context::New();
7371   env->Enter();
7372   v8::Handle<Value> value = NestedScope(env);
7373   v8::Handle<String> str = value->ToString();
7374   env->Exit();
7375   env.Dispose();
7376 }
7377 
7378 
THREADED_TEST(ExternalAllocatedMemory)7379 THREADED_TEST(ExternalAllocatedMemory) {
7380   v8::HandleScope outer;
7381   v8::Persistent<Context> env = Context::New();
7382   const int kSize = 1024*1024;
7383   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
7384   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
7385 }
7386 
7387 
THREADED_TEST(DisposeEnteredContext)7388 THREADED_TEST(DisposeEnteredContext) {
7389   v8::HandleScope scope;
7390   LocalContext outer;
7391   { v8::Persistent<v8::Context> inner = v8::Context::New();
7392     inner->Enter();
7393     inner.Dispose();
7394     inner.Clear();
7395     inner->Exit();
7396   }
7397 }
7398 
7399 
7400 // Regression test for issue 54, object templates with internal fields
7401 // but no accessors or interceptors did not get their internal field
7402 // count set on instances.
THREADED_TEST(Regress54)7403 THREADED_TEST(Regress54) {
7404   v8::HandleScope outer;
7405   LocalContext context;
7406   static v8::Persistent<v8::ObjectTemplate> templ;
7407   if (templ.IsEmpty()) {
7408     v8::HandleScope inner;
7409     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
7410     local->SetInternalFieldCount(1);
7411     templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
7412   }
7413   v8::Handle<v8::Object> result = templ->NewInstance();
7414   CHECK_EQ(1, result->InternalFieldCount());
7415 }
7416 
7417 
7418 // If part of the threaded tests, this test makes ThreadingTest fail
7419 // on mac.
TEST(CatchStackOverflow)7420 TEST(CatchStackOverflow) {
7421   v8::HandleScope scope;
7422   LocalContext context;
7423   v8::TryCatch try_catch;
7424   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
7425     "function f() {"
7426     "  return f();"
7427     "}"
7428     ""
7429     "f();"));
7430   v8::Handle<v8::Value> result = script->Run();
7431   CHECK(result.IsEmpty());
7432 }
7433 
7434 
CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,const char * resource_name,int line_offset)7435 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
7436                                     const char* resource_name,
7437                                     int line_offset) {
7438   v8::HandleScope scope;
7439   v8::TryCatch try_catch;
7440   v8::Handle<v8::Value> result = script->Run();
7441   CHECK(result.IsEmpty());
7442   CHECK(try_catch.HasCaught());
7443   v8::Handle<v8::Message> message = try_catch.Message();
7444   CHECK(!message.IsEmpty());
7445   CHECK_EQ(10 + line_offset, message->GetLineNumber());
7446   CHECK_EQ(91, message->GetStartPosition());
7447   CHECK_EQ(92, message->GetEndPosition());
7448   CHECK_EQ(2, message->GetStartColumn());
7449   CHECK_EQ(3, message->GetEndColumn());
7450   v8::String::AsciiValue line(message->GetSourceLine());
7451   CHECK_EQ("  throw 'nirk';", *line);
7452   v8::String::AsciiValue name(message->GetScriptResourceName());
7453   CHECK_EQ(resource_name, *name);
7454 }
7455 
7456 
THREADED_TEST(TryCatchSourceInfo)7457 THREADED_TEST(TryCatchSourceInfo) {
7458   v8::HandleScope scope;
7459   LocalContext context;
7460   v8::Handle<v8::String> source = v8::String::New(
7461       "function Foo() {\n"
7462       "  return Bar();\n"
7463       "}\n"
7464       "\n"
7465       "function Bar() {\n"
7466       "  return Baz();\n"
7467       "}\n"
7468       "\n"
7469       "function Baz() {\n"
7470       "  throw 'nirk';\n"
7471       "}\n"
7472       "\n"
7473       "Foo();\n");
7474 
7475   const char* resource_name;
7476   v8::Handle<v8::Script> script;
7477   resource_name = "test.js";
7478   script = v8::Script::Compile(source, v8::String::New(resource_name));
7479   CheckTryCatchSourceInfo(script, resource_name, 0);
7480 
7481   resource_name = "test1.js";
7482   v8::ScriptOrigin origin1(v8::String::New(resource_name));
7483   script = v8::Script::Compile(source, &origin1);
7484   CheckTryCatchSourceInfo(script, resource_name, 0);
7485 
7486   resource_name = "test2.js";
7487   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
7488   script = v8::Script::Compile(source, &origin2);
7489   CheckTryCatchSourceInfo(script, resource_name, 7);
7490 }
7491 
7492 
THREADED_TEST(CompilationCache)7493 THREADED_TEST(CompilationCache) {
7494   v8::HandleScope scope;
7495   LocalContext context;
7496   v8::Handle<v8::String> source0 = v8::String::New("1234");
7497   v8::Handle<v8::String> source1 = v8::String::New("1234");
7498   v8::Handle<v8::Script> script0 =
7499       v8::Script::Compile(source0, v8::String::New("test.js"));
7500   v8::Handle<v8::Script> script1 =
7501       v8::Script::Compile(source1, v8::String::New("test.js"));
7502   v8::Handle<v8::Script> script2 =
7503       v8::Script::Compile(source0);  // different origin
7504   CHECK_EQ(1234, script0->Run()->Int32Value());
7505   CHECK_EQ(1234, script1->Run()->Int32Value());
7506   CHECK_EQ(1234, script2->Run()->Int32Value());
7507 }
7508 
7509 
FunctionNameCallback(const v8::Arguments & args)7510 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
7511   ApiTestFuzzer::Fuzz();
7512   return v8_num(42);
7513 }
7514 
7515 
THREADED_TEST(CallbackFunctionName)7516 THREADED_TEST(CallbackFunctionName) {
7517   v8::HandleScope scope;
7518   LocalContext context;
7519   Local<ObjectTemplate> t = ObjectTemplate::New();
7520   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
7521   context->Global()->Set(v8_str("obj"), t->NewInstance());
7522   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
7523   CHECK(value->IsString());
7524   v8::String::AsciiValue name(value);
7525   CHECK_EQ("asdf", *name);
7526 }
7527 
7528 
THREADED_TEST(DateAccess)7529 THREADED_TEST(DateAccess) {
7530   v8::HandleScope scope;
7531   LocalContext context;
7532   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
7533   CHECK(date->IsDate());
7534   CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
7535 }
7536 
7537 
CheckProperties(v8::Handle<v8::Value> val,int elmc,const char * elmv[])7538 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
7539   v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
7540   v8::Handle<v8::Array> props = obj->GetPropertyNames();
7541   CHECK_EQ(elmc, props->Length());
7542   for (int i = 0; i < elmc; i++) {
7543     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
7544     CHECK_EQ(elmv[i], *elm);
7545   }
7546 }
7547 
7548 
THREADED_TEST(PropertyEnumeration)7549 THREADED_TEST(PropertyEnumeration) {
7550   v8::HandleScope scope;
7551   LocalContext context;
7552   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
7553       "var result = [];"
7554       "result[0] = {};"
7555       "result[1] = {a: 1, b: 2};"
7556       "result[2] = [1, 2, 3];"
7557       "var proto = {x: 1, y: 2, z: 3};"
7558       "var x = { __proto__: proto, w: 0, z: 1 };"
7559       "result[3] = x;"
7560       "result;"))->Run();
7561   v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
7562   CHECK_EQ(4, elms->Length());
7563   int elmc0 = 0;
7564   const char** elmv0 = NULL;
7565   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
7566   int elmc1 = 2;
7567   const char* elmv1[] = {"a", "b"};
7568   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
7569   int elmc2 = 3;
7570   const char* elmv2[] = {"0", "1", "2"};
7571   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
7572   int elmc3 = 4;
7573   const char* elmv3[] = {"w", "z", "x", "y"};
7574   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
7575 }
7576 
7577 
NamedSetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)7578 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
7579                                   Local<Value> name,
7580                                   v8::AccessType type,
7581                                   Local<Value> data) {
7582   return type != v8::ACCESS_SET;
7583 }
7584 
7585 
IndexedSetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)7586 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
7587                                     uint32_t key,
7588                                     v8::AccessType type,
7589                                     Local<Value> data) {
7590   return type != v8::ACCESS_SET;
7591 }
7592 
7593 
THREADED_TEST(DisableAccessChecksWhileConfiguring)7594 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
7595   v8::HandleScope scope;
7596   LocalContext context;
7597   Local<ObjectTemplate> templ = ObjectTemplate::New();
7598   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
7599                                  IndexedSetAccessBlocker);
7600   templ->Set(v8_str("x"), v8::True());
7601   Local<v8::Object> instance = templ->NewInstance();
7602   context->Global()->Set(v8_str("obj"), instance);
7603   Local<Value> value = CompileRun("obj.x");
7604   CHECK(value->BooleanValue());
7605 }
7606 
7607 
NamedGetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)7608 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
7609                                   Local<Value> name,
7610                                   v8::AccessType type,
7611                                   Local<Value> data) {
7612   return false;
7613 }
7614 
7615 
IndexedGetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)7616 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
7617                                     uint32_t key,
7618                                     v8::AccessType type,
7619                                     Local<Value> data) {
7620   return false;
7621 }
7622 
7623 
7624 
THREADED_TEST(AccessChecksReenabledCorrectly)7625 THREADED_TEST(AccessChecksReenabledCorrectly) {
7626   v8::HandleScope scope;
7627   LocalContext context;
7628   Local<ObjectTemplate> templ = ObjectTemplate::New();
7629   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
7630                                  IndexedGetAccessBlocker);
7631   templ->Set(v8_str("a"), v8_str("a"));
7632   // Add more than 8 (see kMaxFastProperties) properties
7633   // so that the constructor will force copying map.
7634   // Cannot sprintf, gcc complains unsafety.
7635   char buf[4];
7636   for (char i = '0'; i <= '9' ; i++) {
7637     buf[0] = i;
7638     for (char j = '0'; j <= '9'; j++) {
7639       buf[1] = j;
7640       for (char k = '0'; k <= '9'; k++) {
7641         buf[2] = k;
7642         buf[3] = 0;
7643         templ->Set(v8_str(buf), v8::Number::New(k));
7644       }
7645     }
7646   }
7647 
7648   Local<v8::Object> instance_1 = templ->NewInstance();
7649   context->Global()->Set(v8_str("obj_1"), instance_1);
7650 
7651   Local<Value> value_1 = CompileRun("obj_1.a");
7652   CHECK(value_1->IsUndefined());
7653 
7654   Local<v8::Object> instance_2 = templ->NewInstance();
7655   context->Global()->Set(v8_str("obj_2"), instance_2);
7656 
7657   Local<Value> value_2 = CompileRun("obj_2.a");
7658   CHECK(value_2->IsUndefined());
7659 }
7660 
7661 
7662 // This tests that access check information remains on the global
7663 // object template when creating contexts.
THREADED_TEST(AccessControlRepeatedContextCreation)7664 THREADED_TEST(AccessControlRepeatedContextCreation) {
7665   v8::HandleScope handle_scope;
7666   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7667   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
7668                                            IndexedSetAccessBlocker);
7669   i::Handle<i::ObjectTemplateInfo> internal_template =
7670       v8::Utils::OpenHandle(*global_template);
7671   CHECK(!internal_template->constructor()->IsUndefined());
7672   i::Handle<i::FunctionTemplateInfo> constructor(
7673       i::FunctionTemplateInfo::cast(internal_template->constructor()));
7674   CHECK(!constructor->access_check_info()->IsUndefined());
7675   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
7676   CHECK(!constructor->access_check_info()->IsUndefined());
7677 }
7678 
7679 
THREADED_TEST(TurnOnAccessCheck)7680 THREADED_TEST(TurnOnAccessCheck) {
7681   v8::HandleScope handle_scope;
7682 
7683   // Create an environment with access check to the global object disabled by
7684   // default.
7685   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7686   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
7687                                            IndexedGetAccessBlocker,
7688                                            v8::Handle<v8::Value>(),
7689                                            false);
7690   v8::Persistent<Context> context = Context::New(NULL, global_template);
7691   Context::Scope context_scope(context);
7692 
7693   // Set up a property and a number of functions.
7694   context->Global()->Set(v8_str("a"), v8_num(1));
7695   CompileRun("function f1() {return a;}"
7696              "function f2() {return a;}"
7697              "function g1() {return h();}"
7698              "function g2() {return h();}"
7699              "function h() {return 1;}");
7700   Local<Function> f1 =
7701       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
7702   Local<Function> f2 =
7703       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
7704   Local<Function> g1 =
7705       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
7706   Local<Function> g2 =
7707       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
7708   Local<Function> h =
7709       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
7710 
7711   // Get the global object.
7712   v8::Handle<v8::Object> global = context->Global();
7713 
7714   // Call f1 one time and f2 a number of times. This will ensure that f1 still
7715   // uses the runtime system to retreive property a whereas f2 uses global load
7716   // inline cache.
7717   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
7718   for (int i = 0; i < 4; i++) {
7719     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
7720   }
7721 
7722   // Same for g1 and g2.
7723   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
7724   for (int i = 0; i < 4; i++) {
7725     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
7726   }
7727 
7728   // Detach the global and turn on access check.
7729   context->DetachGlobal();
7730   context->Global()->TurnOnAccessCheck();
7731 
7732   // Failing access check to property get results in undefined.
7733   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
7734   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
7735 
7736   // Failing access check to function call results in exception.
7737   CHECK(g1->Call(global, 0, NULL).IsEmpty());
7738   CHECK(g2->Call(global, 0, NULL).IsEmpty());
7739 
7740   // No failing access check when just returning a constant.
7741   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
7742 }
7743 
7744 
7745 // This test verifies that pre-compilation (aka preparsing) can be called
7746 // without initializing the whole VM. Thus we cannot run this test in a
7747 // multi-threaded setup.
TEST(PreCompile)7748 TEST(PreCompile) {
7749   // TODO(155): This test would break without the initialization of V8. This is
7750   // a workaround for now to make this test not fail.
7751   v8::V8::Initialize();
7752   const char *script = "function foo(a) { return a+1; }";
7753   v8::ScriptData *sd =
7754       v8::ScriptData::PreCompile(script, i::StrLength(script));
7755   CHECK_NE(sd->Length(), 0);
7756   CHECK_NE(sd->Data(), NULL);
7757   CHECK(!sd->HasError());
7758   delete sd;
7759 }
7760 
7761 
TEST(PreCompileWithError)7762 TEST(PreCompileWithError) {
7763   v8::V8::Initialize();
7764   const char *script = "function foo(a) { return 1 * * 2; }";
7765   v8::ScriptData *sd =
7766       v8::ScriptData::PreCompile(script, i::StrLength(script));
7767   CHECK(sd->HasError());
7768   delete sd;
7769 }
7770 
7771 
TEST(Regress31661)7772 TEST(Regress31661) {
7773   v8::V8::Initialize();
7774   const char *script = " The Definintive Guide";
7775   v8::ScriptData *sd =
7776       v8::ScriptData::PreCompile(script, i::StrLength(script));
7777   CHECK(sd->HasError());
7778   delete sd;
7779 }
7780 
7781 
7782 // This tests that we do not allow dictionary load/call inline caches
7783 // to use functions that have not yet been compiled.  The potential
7784 // problem of loading a function that has not yet been compiled can
7785 // arise because we share code between contexts via the compilation
7786 // cache.
THREADED_TEST(DictionaryICLoadedFunction)7787 THREADED_TEST(DictionaryICLoadedFunction) {
7788   v8::HandleScope scope;
7789   // Test LoadIC.
7790   for (int i = 0; i < 2; i++) {
7791     LocalContext context;
7792     context->Global()->Set(v8_str("tmp"), v8::True());
7793     context->Global()->Delete(v8_str("tmp"));
7794     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
7795   }
7796   // Test CallIC.
7797   for (int i = 0; i < 2; i++) {
7798     LocalContext context;
7799     context->Global()->Set(v8_str("tmp"), v8::True());
7800     context->Global()->Delete(v8_str("tmp"));
7801     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
7802   }
7803 }
7804 
7805 
7806 // Test that cross-context new calls use the context of the callee to
7807 // create the new JavaScript object.
THREADED_TEST(CrossContextNew)7808 THREADED_TEST(CrossContextNew) {
7809   v8::HandleScope scope;
7810   v8::Persistent<Context> context0 = Context::New();
7811   v8::Persistent<Context> context1 = Context::New();
7812 
7813   // Allow cross-domain access.
7814   Local<String> token = v8_str("<security token>");
7815   context0->SetSecurityToken(token);
7816   context1->SetSecurityToken(token);
7817 
7818   // Set an 'x' property on the Object prototype and define a
7819   // constructor function in context0.
7820   context0->Enter();
7821   CompileRun("Object.prototype.x = 42; function C() {};");
7822   context0->Exit();
7823 
7824   // Call the constructor function from context0 and check that the
7825   // result has the 'x' property.
7826   context1->Enter();
7827   context1->Global()->Set(v8_str("other"), context0->Global());
7828   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
7829   CHECK(value->IsInt32());
7830   CHECK_EQ(42, value->Int32Value());
7831   context1->Exit();
7832 
7833   // Dispose the contexts to allow them to be garbage collected.
7834   context0.Dispose();
7835   context1.Dispose();
7836 }
7837 
7838 
7839 class RegExpInterruptTest {
7840  public:
RegExpInterruptTest()7841   RegExpInterruptTest() : block_(NULL) {}
~RegExpInterruptTest()7842   ~RegExpInterruptTest() { delete block_; }
RunTest()7843   void RunTest() {
7844     block_ = i::OS::CreateSemaphore(0);
7845     gc_count_ = 0;
7846     gc_during_regexp_ = 0;
7847     regexp_success_ = false;
7848     gc_success_ = false;
7849     GCThread gc_thread(this);
7850     gc_thread.Start();
7851     v8::Locker::StartPreemption(1);
7852 
7853     LongRunningRegExp();
7854     {
7855       v8::Unlocker unlock;
7856       gc_thread.Join();
7857     }
7858     v8::Locker::StopPreemption();
7859     CHECK(regexp_success_);
7860     CHECK(gc_success_);
7861   }
7862  private:
7863   // Number of garbage collections required.
7864   static const int kRequiredGCs = 5;
7865 
7866   class GCThread : public i::Thread {
7867    public:
GCThread(RegExpInterruptTest * test)7868     explicit GCThread(RegExpInterruptTest* test)
7869         : test_(test) {}
Run()7870     virtual void Run() {
7871       test_->CollectGarbage();
7872     }
7873    private:
7874      RegExpInterruptTest* test_;
7875   };
7876 
CollectGarbage()7877   void CollectGarbage() {
7878     block_->Wait();
7879     while (gc_during_regexp_ < kRequiredGCs) {
7880       {
7881         v8::Locker lock;
7882         // TODO(lrn): Perhaps create some garbage before collecting.
7883         i::Heap::CollectAllGarbage(false);
7884         gc_count_++;
7885       }
7886       i::OS::Sleep(1);
7887     }
7888     gc_success_ = true;
7889   }
7890 
LongRunningRegExp()7891   void LongRunningRegExp() {
7892     block_->Signal();  // Enable garbage collection thread on next preemption.
7893     int rounds = 0;
7894     while (gc_during_regexp_ < kRequiredGCs) {
7895       int gc_before = gc_count_;
7896       {
7897         // Match 15-30 "a"'s against 14 and a "b".
7898         const char* c_source =
7899             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7900             ".exec('aaaaaaaaaaaaaaab') === null";
7901         Local<String> source = String::New(c_source);
7902         Local<Script> script = Script::Compile(source);
7903         Local<Value> result = script->Run();
7904         if (!result->BooleanValue()) {
7905           gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
7906           return;
7907         }
7908       }
7909       {
7910         // Match 15-30 "a"'s against 15 and a "b".
7911         const char* c_source =
7912             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7913             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
7914         Local<String> source = String::New(c_source);
7915         Local<Script> script = Script::Compile(source);
7916         Local<Value> result = script->Run();
7917         if (!result->BooleanValue()) {
7918           gc_during_regexp_ = kRequiredGCs;
7919           return;
7920         }
7921       }
7922       int gc_after = gc_count_;
7923       gc_during_regexp_ += gc_after - gc_before;
7924       rounds++;
7925       i::OS::Sleep(1);
7926     }
7927     regexp_success_ = true;
7928   }
7929 
7930   i::Semaphore* block_;
7931   int gc_count_;
7932   int gc_during_regexp_;
7933   bool regexp_success_;
7934   bool gc_success_;
7935 };
7936 
7937 
7938 // Test that a regular expression execution can be interrupted and
7939 // survive a garbage collection.
TEST(RegExpInterruption)7940 TEST(RegExpInterruption) {
7941   v8::Locker lock;
7942   v8::V8::Initialize();
7943   v8::HandleScope scope;
7944   Local<Context> local_env;
7945   {
7946     LocalContext env;
7947     local_env = env.local();
7948   }
7949 
7950   // Local context should still be live.
7951   CHECK(!local_env.IsEmpty());
7952   local_env->Enter();
7953 
7954   // Should complete without problems.
7955   RegExpInterruptTest().RunTest();
7956 
7957   local_env->Exit();
7958 }
7959 
7960 
7961 class ApplyInterruptTest {
7962  public:
ApplyInterruptTest()7963   ApplyInterruptTest() : block_(NULL) {}
~ApplyInterruptTest()7964   ~ApplyInterruptTest() { delete block_; }
RunTest()7965   void RunTest() {
7966     block_ = i::OS::CreateSemaphore(0);
7967     gc_count_ = 0;
7968     gc_during_apply_ = 0;
7969     apply_success_ = false;
7970     gc_success_ = false;
7971     GCThread gc_thread(this);
7972     gc_thread.Start();
7973     v8::Locker::StartPreemption(1);
7974 
7975     LongRunningApply();
7976     {
7977       v8::Unlocker unlock;
7978       gc_thread.Join();
7979     }
7980     v8::Locker::StopPreemption();
7981     CHECK(apply_success_);
7982     CHECK(gc_success_);
7983   }
7984  private:
7985   // Number of garbage collections required.
7986   static const int kRequiredGCs = 2;
7987 
7988   class GCThread : public i::Thread {
7989    public:
GCThread(ApplyInterruptTest * test)7990     explicit GCThread(ApplyInterruptTest* test)
7991         : test_(test) {}
Run()7992     virtual void Run() {
7993       test_->CollectGarbage();
7994     }
7995    private:
7996      ApplyInterruptTest* test_;
7997   };
7998 
CollectGarbage()7999   void CollectGarbage() {
8000     block_->Wait();
8001     while (gc_during_apply_ < kRequiredGCs) {
8002       {
8003         v8::Locker lock;
8004         i::Heap::CollectAllGarbage(false);
8005         gc_count_++;
8006       }
8007       i::OS::Sleep(1);
8008     }
8009     gc_success_ = true;
8010   }
8011 
LongRunningApply()8012   void LongRunningApply() {
8013     block_->Signal();
8014     int rounds = 0;
8015     while (gc_during_apply_ < kRequiredGCs) {
8016       int gc_before = gc_count_;
8017       {
8018         const char* c_source =
8019             "function do_very_little(bar) {"
8020             "  this.foo = bar;"
8021             "}"
8022             "for (var i = 0; i < 100000; i++) {"
8023             "  do_very_little.apply(this, ['bar']);"
8024             "}";
8025         Local<String> source = String::New(c_source);
8026         Local<Script> script = Script::Compile(source);
8027         Local<Value> result = script->Run();
8028         // Check that no exception was thrown.
8029         CHECK(!result.IsEmpty());
8030       }
8031       int gc_after = gc_count_;
8032       gc_during_apply_ += gc_after - gc_before;
8033       rounds++;
8034     }
8035     apply_success_ = true;
8036   }
8037 
8038   i::Semaphore* block_;
8039   int gc_count_;
8040   int gc_during_apply_;
8041   bool apply_success_;
8042   bool gc_success_;
8043 };
8044 
8045 
8046 // Test that nothing bad happens if we get a preemption just when we were
8047 // about to do an apply().
TEST(ApplyInterruption)8048 TEST(ApplyInterruption) {
8049   v8::Locker lock;
8050   v8::V8::Initialize();
8051   v8::HandleScope scope;
8052   Local<Context> local_env;
8053   {
8054     LocalContext env;
8055     local_env = env.local();
8056   }
8057 
8058   // Local context should still be live.
8059   CHECK(!local_env.IsEmpty());
8060   local_env->Enter();
8061 
8062   // Should complete without problems.
8063   ApplyInterruptTest().RunTest();
8064 
8065   local_env->Exit();
8066 }
8067 
8068 
8069 // Verify that we can clone an object
TEST(ObjectClone)8070 TEST(ObjectClone) {
8071   v8::HandleScope scope;
8072   LocalContext env;
8073 
8074   const char* sample =
8075     "var rv = {};"      \
8076     "rv.alpha = 'hello';" \
8077     "rv.beta = 123;"     \
8078     "rv;";
8079 
8080   // Create an object, verify basics.
8081   Local<Value> val = CompileRun(sample);
8082   CHECK(val->IsObject());
8083   Local<v8::Object> obj = Local<v8::Object>::Cast(val);
8084   obj->Set(v8_str("gamma"), v8_str("cloneme"));
8085 
8086   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
8087   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8088   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
8089 
8090   // Clone it.
8091   Local<v8::Object> clone = obj->Clone();
8092   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
8093   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
8094   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
8095 
8096   // Set a property on the clone, verify each object.
8097   clone->Set(v8_str("beta"), v8::Integer::New(456));
8098   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
8099   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
8100 }
8101 
8102 
8103 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
8104  public:
AsciiVectorResource(i::Vector<const char> vector)8105   explicit AsciiVectorResource(i::Vector<const char> vector)
8106       : data_(vector) {}
~AsciiVectorResource()8107   virtual ~AsciiVectorResource() {}
length() const8108   virtual size_t length() const { return data_.length(); }
data() const8109   virtual const char* data() const { return data_.start(); }
8110  private:
8111   i::Vector<const char> data_;
8112 };
8113 
8114 
8115 class UC16VectorResource : public v8::String::ExternalStringResource {
8116  public:
UC16VectorResource(i::Vector<const i::uc16> vector)8117   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
8118       : data_(vector) {}
~UC16VectorResource()8119   virtual ~UC16VectorResource() {}
length() const8120   virtual size_t length() const { return data_.length(); }
data() const8121   virtual const i::uc16* data() const { return data_.start(); }
8122  private:
8123   i::Vector<const i::uc16> data_;
8124 };
8125 
8126 
MorphAString(i::String * string,AsciiVectorResource * ascii_resource,UC16VectorResource * uc16_resource)8127 static void MorphAString(i::String* string,
8128                          AsciiVectorResource* ascii_resource,
8129                          UC16VectorResource* uc16_resource) {
8130   CHECK(i::StringShape(string).IsExternal());
8131   if (string->IsAsciiRepresentation()) {
8132     // Check old map is not symbol or long.
8133     CHECK(string->map() == i::Heap::external_ascii_string_map());
8134     // Morph external string to be TwoByte string.
8135     string->set_map(i::Heap::external_string_map());
8136     i::ExternalTwoByteString* morphed =
8137          i::ExternalTwoByteString::cast(string);
8138     morphed->set_resource(uc16_resource);
8139   } else {
8140     // Check old map is not symbol or long.
8141     CHECK(string->map() == i::Heap::external_string_map());
8142     // Morph external string to be ASCII string.
8143     string->set_map(i::Heap::external_ascii_string_map());
8144     i::ExternalAsciiString* morphed =
8145          i::ExternalAsciiString::cast(string);
8146     morphed->set_resource(ascii_resource);
8147   }
8148 }
8149 
8150 
8151 // Test that we can still flatten a string if the components it is built up
8152 // from have been turned into 16 bit strings in the mean time.
THREADED_TEST(MorphCompositeStringTest)8153 THREADED_TEST(MorphCompositeStringTest) {
8154   const char* c_string = "Now is the time for all good men"
8155                          " to come to the aid of the party";
8156   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
8157   {
8158     v8::HandleScope scope;
8159     LocalContext env;
8160     AsciiVectorResource ascii_resource(
8161         i::Vector<const char>(c_string, i::StrLength(c_string)));
8162     UC16VectorResource uc16_resource(
8163         i::Vector<const uint16_t>(two_byte_string,
8164                                   i::StrLength(c_string)));
8165 
8166     Local<String> lhs(v8::Utils::ToLocal(
8167         i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8168     Local<String> rhs(v8::Utils::ToLocal(
8169         i::Factory::NewExternalStringFromAscii(&ascii_resource)));
8170 
8171     env->Global()->Set(v8_str("lhs"), lhs);
8172     env->Global()->Set(v8_str("rhs"), rhs);
8173 
8174     CompileRun(
8175         "var cons = lhs + rhs;"
8176         "var slice = lhs.substring(1, lhs.length - 1);"
8177         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
8178 
8179     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
8180     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
8181 
8182     // Now do some stuff to make sure the strings are flattened, etc.
8183     CompileRun(
8184         "/[^a-z]/.test(cons);"
8185         "/[^a-z]/.test(slice);"
8186         "/[^a-z]/.test(slice_on_cons);");
8187     const char* expected_cons =
8188         "Now is the time for all good men to come to the aid of the party"
8189         "Now is the time for all good men to come to the aid of the party";
8190     const char* expected_slice =
8191         "ow is the time for all good men to come to the aid of the part";
8192     const char* expected_slice_on_cons =
8193         "ow is the time for all good men to come to the aid of the party"
8194         "Now is the time for all good men to come to the aid of the part";
8195     CHECK_EQ(String::New(expected_cons),
8196              env->Global()->Get(v8_str("cons")));
8197     CHECK_EQ(String::New(expected_slice),
8198              env->Global()->Get(v8_str("slice")));
8199     CHECK_EQ(String::New(expected_slice_on_cons),
8200              env->Global()->Get(v8_str("slice_on_cons")));
8201   }
8202 }
8203 
8204 
TEST(CompileExternalTwoByteSource)8205 TEST(CompileExternalTwoByteSource) {
8206   v8::HandleScope scope;
8207   LocalContext context;
8208 
8209   // This is a very short list of sources, which currently is to check for a
8210   // regression caused by r2703.
8211   const char* ascii_sources[] = {
8212     "0.5",
8213     "-0.5",   // This mainly testes PushBack in the Scanner.
8214     "--0.5",  // This mainly testes PushBack in the Scanner.
8215     NULL
8216   };
8217 
8218   // Compile the sources as external two byte strings.
8219   for (int i = 0; ascii_sources[i] != NULL; i++) {
8220     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
8221     UC16VectorResource uc16_resource(
8222         i::Vector<const uint16_t>(two_byte_string,
8223                                   i::StrLength(ascii_sources[i])));
8224     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
8225     v8::Script::Compile(source);
8226   }
8227 }
8228 
8229 
8230 class RegExpStringModificationTest {
8231  public:
RegExpStringModificationTest()8232   RegExpStringModificationTest()
8233       : block_(i::OS::CreateSemaphore(0)),
8234         morphs_(0),
8235         morphs_during_regexp_(0),
8236         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
8237         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
~RegExpStringModificationTest()8238   ~RegExpStringModificationTest() { delete block_; }
RunTest()8239   void RunTest() {
8240     regexp_success_ = false;
8241     morph_success_ = false;
8242 
8243     // Initialize the contents of two_byte_content_ to be a uc16 representation
8244     // of "aaaaaaaaaaaaaab".
8245     for (int i = 0; i < 14; i++) {
8246       two_byte_content_[i] = 'a';
8247     }
8248     two_byte_content_[14] = 'b';
8249 
8250     // Create the input string for the regexp - the one we are going to change
8251     // properties of.
8252     input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
8253 
8254     // Inject the input as a global variable.
8255     i::Handle<i::String> input_name =
8256         i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
8257     i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
8258 
8259 
8260     MorphThread morph_thread(this);
8261     morph_thread.Start();
8262     v8::Locker::StartPreemption(1);
8263     LongRunningRegExp();
8264     {
8265       v8::Unlocker unlock;
8266       morph_thread.Join();
8267     }
8268     v8::Locker::StopPreemption();
8269     CHECK(regexp_success_);
8270     CHECK(morph_success_);
8271   }
8272  private:
8273 
8274   // Number of string modifications required.
8275   static const int kRequiredModifications = 5;
8276   static const int kMaxModifications = 100;
8277 
8278   class MorphThread : public i::Thread {
8279    public:
MorphThread(RegExpStringModificationTest * test)8280     explicit MorphThread(RegExpStringModificationTest* test)
8281         : test_(test) {}
Run()8282     virtual void Run() {
8283       test_->MorphString();
8284     }
8285    private:
8286      RegExpStringModificationTest* test_;
8287   };
8288 
MorphString()8289   void MorphString() {
8290     block_->Wait();
8291     while (morphs_during_regexp_ < kRequiredModifications &&
8292            morphs_ < kMaxModifications) {
8293       {
8294         v8::Locker lock;
8295         // Swap string between ascii and two-byte representation.
8296         i::String* string = *input_;
8297         MorphAString(string, &ascii_resource_, &uc16_resource_);
8298         morphs_++;
8299       }
8300       i::OS::Sleep(1);
8301     }
8302     morph_success_ = true;
8303   }
8304 
LongRunningRegExp()8305   void LongRunningRegExp() {
8306     block_->Signal();  // Enable morphing thread on next preemption.
8307     while (morphs_during_regexp_ < kRequiredModifications &&
8308            morphs_ < kMaxModifications) {
8309       int morphs_before = morphs_;
8310       {
8311         // Match 15-30 "a"'s against 14 and a "b".
8312         const char* c_source =
8313             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
8314             ".exec(input) === null";
8315         Local<String> source = String::New(c_source);
8316         Local<Script> script = Script::Compile(source);
8317         Local<Value> result = script->Run();
8318         CHECK(result->IsTrue());
8319       }
8320       int morphs_after = morphs_;
8321       morphs_during_regexp_ += morphs_after - morphs_before;
8322     }
8323     regexp_success_ = true;
8324   }
8325 
8326   i::uc16 two_byte_content_[15];
8327   i::Semaphore* block_;
8328   int morphs_;
8329   int morphs_during_regexp_;
8330   bool regexp_success_;
8331   bool morph_success_;
8332   i::Handle<i::String> input_;
8333   AsciiVectorResource ascii_resource_;
8334   UC16VectorResource uc16_resource_;
8335 };
8336 
8337 
8338 // Test that a regular expression execution can be interrupted and
8339 // the string changed without failing.
TEST(RegExpStringModification)8340 TEST(RegExpStringModification) {
8341   v8::Locker lock;
8342   v8::V8::Initialize();
8343   v8::HandleScope scope;
8344   Local<Context> local_env;
8345   {
8346     LocalContext env;
8347     local_env = env.local();
8348   }
8349 
8350   // Local context should still be live.
8351   CHECK(!local_env.IsEmpty());
8352   local_env->Enter();
8353 
8354   // Should complete without problems.
8355   RegExpStringModificationTest().RunTest();
8356 
8357   local_env->Exit();
8358 }
8359 
8360 
8361 // Test that we can set a property on the global object even if there
8362 // is a read-only property in the prototype chain.
TEST(ReadOnlyPropertyInGlobalProto)8363 TEST(ReadOnlyPropertyInGlobalProto) {
8364   v8::HandleScope scope;
8365   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8366   LocalContext context(0, templ);
8367   v8::Handle<v8::Object> global = context->Global();
8368   v8::Handle<v8::Object> global_proto =
8369       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
8370   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
8371   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
8372   // Check without 'eval' or 'with'.
8373   v8::Handle<v8::Value> res =
8374       CompileRun("function f() { x = 42; return x; }; f()");
8375   // Check with 'eval'.
8376   res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
8377   CHECK_EQ(v8::Integer::New(42), res);
8378   // Check with 'with'.
8379   res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
8380   CHECK_EQ(v8::Integer::New(42), res);
8381 }
8382 
8383 static int force_set_set_count = 0;
8384 static int force_set_get_count = 0;
8385 bool pass_on_get = false;
8386 
ForceSetGetter(v8::Local<v8::String> name,const v8::AccessorInfo & info)8387 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
8388                                             const v8::AccessorInfo& info) {
8389   force_set_get_count++;
8390   if (pass_on_get) {
8391     return v8::Handle<v8::Value>();
8392   } else {
8393     return v8::Int32::New(3);
8394   }
8395 }
8396 
ForceSetSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::AccessorInfo & info)8397 static void ForceSetSetter(v8::Local<v8::String> name,
8398                            v8::Local<v8::Value> value,
8399                            const v8::AccessorInfo& info) {
8400   force_set_set_count++;
8401 }
8402 
ForceSetInterceptSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::AccessorInfo & info)8403 static v8::Handle<v8::Value> ForceSetInterceptSetter(
8404     v8::Local<v8::String> name,
8405     v8::Local<v8::Value> value,
8406     const v8::AccessorInfo& info) {
8407   force_set_set_count++;
8408   return v8::Undefined();
8409 }
8410 
TEST(ForceSet)8411 TEST(ForceSet) {
8412   force_set_get_count = 0;
8413   force_set_set_count = 0;
8414   pass_on_get = false;
8415 
8416   v8::HandleScope scope;
8417   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8418   v8::Handle<v8::String> access_property = v8::String::New("a");
8419   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
8420   LocalContext context(NULL, templ);
8421   v8::Handle<v8::Object> global = context->Global();
8422 
8423   // Ordinary properties
8424   v8::Handle<v8::String> simple_property = v8::String::New("p");
8425   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
8426   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8427   // This should fail because the property is read-only
8428   global->Set(simple_property, v8::Int32::New(5));
8429   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8430   // This should succeed even though the property is read-only
8431   global->ForceSet(simple_property, v8::Int32::New(6));
8432   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
8433 
8434   // Accessors
8435   CHECK_EQ(0, force_set_set_count);
8436   CHECK_EQ(0, force_set_get_count);
8437   CHECK_EQ(3, global->Get(access_property)->Int32Value());
8438   // CHECK_EQ the property shouldn't override it, just call the setter
8439   // which in this case does nothing.
8440   global->Set(access_property, v8::Int32::New(7));
8441   CHECK_EQ(3, global->Get(access_property)->Int32Value());
8442   CHECK_EQ(1, force_set_set_count);
8443   CHECK_EQ(2, force_set_get_count);
8444   // Forcing the property to be set should override the accessor without
8445   // calling it
8446   global->ForceSet(access_property, v8::Int32::New(8));
8447   CHECK_EQ(8, global->Get(access_property)->Int32Value());
8448   CHECK_EQ(1, force_set_set_count);
8449   CHECK_EQ(2, force_set_get_count);
8450 }
8451 
TEST(ForceSetWithInterceptor)8452 TEST(ForceSetWithInterceptor) {
8453   force_set_get_count = 0;
8454   force_set_set_count = 0;
8455   pass_on_get = false;
8456 
8457   v8::HandleScope scope;
8458   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8459   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
8460   LocalContext context(NULL, templ);
8461   v8::Handle<v8::Object> global = context->Global();
8462 
8463   v8::Handle<v8::String> some_property = v8::String::New("a");
8464   CHECK_EQ(0, force_set_set_count);
8465   CHECK_EQ(0, force_set_get_count);
8466   CHECK_EQ(3, global->Get(some_property)->Int32Value());
8467   // Setting the property shouldn't override it, just call the setter
8468   // which in this case does nothing.
8469   global->Set(some_property, v8::Int32::New(7));
8470   CHECK_EQ(3, global->Get(some_property)->Int32Value());
8471   CHECK_EQ(1, force_set_set_count);
8472   CHECK_EQ(2, force_set_get_count);
8473   // Getting the property when the interceptor returns an empty handle
8474   // should yield undefined, since the property isn't present on the
8475   // object itself yet.
8476   pass_on_get = true;
8477   CHECK(global->Get(some_property)->IsUndefined());
8478   CHECK_EQ(1, force_set_set_count);
8479   CHECK_EQ(3, force_set_get_count);
8480   // Forcing the property to be set should cause the value to be
8481   // set locally without calling the interceptor.
8482   global->ForceSet(some_property, v8::Int32::New(8));
8483   CHECK_EQ(8, global->Get(some_property)->Int32Value());
8484   CHECK_EQ(1, force_set_set_count);
8485   CHECK_EQ(4, force_set_get_count);
8486   // Reenabling the interceptor should cause it to take precedence over
8487   // the property
8488   pass_on_get = false;
8489   CHECK_EQ(3, global->Get(some_property)->Int32Value());
8490   CHECK_EQ(1, force_set_set_count);
8491   CHECK_EQ(5, force_set_get_count);
8492   // The interceptor should also work for other properties
8493   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
8494   CHECK_EQ(1, force_set_set_count);
8495   CHECK_EQ(6, force_set_get_count);
8496 }
8497 
8498 
THREADED_TEST(ForceDelete)8499 THREADED_TEST(ForceDelete) {
8500   v8::HandleScope scope;
8501   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8502   LocalContext context(NULL, templ);
8503   v8::Handle<v8::Object> global = context->Global();
8504 
8505   // Ordinary properties
8506   v8::Handle<v8::String> simple_property = v8::String::New("p");
8507   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
8508   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8509   // This should fail because the property is dont-delete.
8510   CHECK(!global->Delete(simple_property));
8511   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
8512   // This should succeed even though the property is dont-delete.
8513   CHECK(global->ForceDelete(simple_property));
8514   CHECK(global->Get(simple_property)->IsUndefined());
8515 }
8516 
8517 
8518 static int force_delete_interceptor_count = 0;
8519 static bool pass_on_delete = false;
8520 
8521 
ForceDeleteDeleter(v8::Local<v8::String> name,const v8::AccessorInfo & info)8522 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
8523     v8::Local<v8::String> name,
8524     const v8::AccessorInfo& info) {
8525   force_delete_interceptor_count++;
8526   if (pass_on_delete) {
8527     return v8::Handle<v8::Boolean>();
8528   } else {
8529     return v8::True();
8530   }
8531 }
8532 
8533 
THREADED_TEST(ForceDeleteWithInterceptor)8534 THREADED_TEST(ForceDeleteWithInterceptor) {
8535   force_delete_interceptor_count = 0;
8536   pass_on_delete = false;
8537 
8538   v8::HandleScope scope;
8539   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
8540   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
8541   LocalContext context(NULL, templ);
8542   v8::Handle<v8::Object> global = context->Global();
8543 
8544   v8::Handle<v8::String> some_property = v8::String::New("a");
8545   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
8546 
8547   // Deleting a property should get intercepted and nothing should
8548   // happen.
8549   CHECK_EQ(0, force_delete_interceptor_count);
8550   CHECK(global->Delete(some_property));
8551   CHECK_EQ(1, force_delete_interceptor_count);
8552   CHECK_EQ(42, global->Get(some_property)->Int32Value());
8553   // Deleting the property when the interceptor returns an empty
8554   // handle should not delete the property since it is DontDelete.
8555   pass_on_delete = true;
8556   CHECK(!global->Delete(some_property));
8557   CHECK_EQ(2, force_delete_interceptor_count);
8558   CHECK_EQ(42, global->Get(some_property)->Int32Value());
8559   // Forcing the property to be deleted should delete the value
8560   // without calling the interceptor.
8561   CHECK(global->ForceDelete(some_property));
8562   CHECK(global->Get(some_property)->IsUndefined());
8563   CHECK_EQ(2, force_delete_interceptor_count);
8564 }
8565 
8566 
8567 // Make sure that forcing a delete invalidates any IC stubs, so we
8568 // don't read the hole value.
THREADED_TEST(ForceDeleteIC)8569 THREADED_TEST(ForceDeleteIC) {
8570   v8::HandleScope scope;
8571   LocalContext context;
8572   // Create a DontDelete variable on the global object.
8573   CompileRun("this.__proto__ = { foo: 'horse' };"
8574              "var foo = 'fish';"
8575              "function f() { return foo.length; }");
8576   // Initialize the IC for foo in f.
8577   CompileRun("for (var i = 0; i < 4; i++) f();");
8578   // Make sure the value of foo is correct before the deletion.
8579   CHECK_EQ(4, CompileRun("f()")->Int32Value());
8580   // Force the deletion of foo.
8581   CHECK(context->Global()->ForceDelete(v8_str("foo")));
8582   // Make sure the value for foo is read from the prototype, and that
8583   // we don't get in trouble with reading the deleted cell value
8584   // sentinel.
8585   CHECK_EQ(5, CompileRun("f()")->Int32Value());
8586 }
8587 
8588 
8589 v8::Persistent<Context> calling_context0;
8590 v8::Persistent<Context> calling_context1;
8591 v8::Persistent<Context> calling_context2;
8592 
8593 
8594 // Check that the call to the callback is initiated in
8595 // calling_context2, the directly calling context is calling_context1
8596 // and the callback itself is in calling_context0.
GetCallingContextCallback(const v8::Arguments & args)8597 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
8598   ApiTestFuzzer::Fuzz();
8599   CHECK(Context::GetCurrent() == calling_context0);
8600   CHECK(Context::GetCalling() == calling_context1);
8601   CHECK(Context::GetEntered() == calling_context2);
8602   return v8::Integer::New(42);
8603 }
8604 
8605 
THREADED_TEST(GetCallingContext)8606 THREADED_TEST(GetCallingContext) {
8607   v8::HandleScope scope;
8608 
8609   calling_context0 = Context::New();
8610   calling_context1 = Context::New();
8611   calling_context2 = Context::New();
8612 
8613   // Allow cross-domain access.
8614   Local<String> token = v8_str("<security token>");
8615   calling_context0->SetSecurityToken(token);
8616   calling_context1->SetSecurityToken(token);
8617   calling_context2->SetSecurityToken(token);
8618 
8619   // Create an object with a C++ callback in context0.
8620   calling_context0->Enter();
8621   Local<v8::FunctionTemplate> callback_templ =
8622       v8::FunctionTemplate::New(GetCallingContextCallback);
8623   calling_context0->Global()->Set(v8_str("callback"),
8624                                   callback_templ->GetFunction());
8625   calling_context0->Exit();
8626 
8627   // Expose context0 in context1 and setup a function that calls the
8628   // callback function.
8629   calling_context1->Enter();
8630   calling_context1->Global()->Set(v8_str("context0"),
8631                                   calling_context0->Global());
8632   CompileRun("function f() { context0.callback() }");
8633   calling_context1->Exit();
8634 
8635   // Expose context1 in context2 and call the callback function in
8636   // context0 indirectly through f in context1.
8637   calling_context2->Enter();
8638   calling_context2->Global()->Set(v8_str("context1"),
8639                                   calling_context1->Global());
8640   CompileRun("context1.f()");
8641   calling_context2->Exit();
8642 
8643   // Dispose the contexts to allow them to be garbage collected.
8644   calling_context0.Dispose();
8645   calling_context1.Dispose();
8646   calling_context2.Dispose();
8647   calling_context0.Clear();
8648   calling_context1.Clear();
8649   calling_context2.Clear();
8650 }
8651 
8652 
8653 // Check that a variable declaration with no explicit initialization
8654 // value does not shadow an existing property in the prototype chain.
8655 //
8656 // This is consistent with Firefox and Safari.
8657 //
8658 // See http://crbug.com/12548.
THREADED_TEST(InitGlobalVarInProtoChain)8659 THREADED_TEST(InitGlobalVarInProtoChain) {
8660   v8::HandleScope scope;
8661   LocalContext context;
8662   // Introduce a variable in the prototype chain.
8663   CompileRun("__proto__.x = 42");
8664   v8::Handle<v8::Value> result = CompileRun("var x; x");
8665   CHECK(!result->IsUndefined());
8666   CHECK_EQ(42, result->Int32Value());
8667 }
8668 
8669 
8670 // Regression test for issue 398.
8671 // If a function is added to an object, creating a constant function
8672 // field, and the result is cloned, replacing the constant function on the
8673 // original should not affect the clone.
8674 // See http://code.google.com/p/v8/issues/detail?id=398
THREADED_TEST(ReplaceConstantFunction)8675 THREADED_TEST(ReplaceConstantFunction) {
8676   v8::HandleScope scope;
8677   LocalContext context;
8678   v8::Handle<v8::Object> obj = v8::Object::New();
8679   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
8680   v8::Handle<v8::String> foo_string = v8::String::New("foo");
8681   obj->Set(foo_string, func_templ->GetFunction());
8682   v8::Handle<v8::Object> obj_clone = obj->Clone();
8683   obj_clone->Set(foo_string, v8::String::New("Hello"));
8684   CHECK(!obj->Get(foo_string)->IsUndefined());
8685 }
8686 
8687 
8688 // Regression test for http://crbug.com/16276.
THREADED_TEST(Regress16276)8689 THREADED_TEST(Regress16276) {
8690   v8::HandleScope scope;
8691   LocalContext context;
8692   // Force the IC in f to be a dictionary load IC.
8693   CompileRun("function f(obj) { return obj.x; }\n"
8694              "var obj = { x: { foo: 42 }, y: 87 };\n"
8695              "var x = obj.x;\n"
8696              "delete obj.y;\n"
8697              "for (var i = 0; i < 5; i++) f(obj);");
8698   // Detach the global object to make 'this' refer directly to the
8699   // global object (not the proxy), and make sure that the dictionary
8700   // load IC doesn't mess up loading directly from the global object.
8701   context->DetachGlobal();
8702   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
8703 }
8704 
8705 
THREADED_TEST(PixelArray)8706 THREADED_TEST(PixelArray) {
8707   v8::HandleScope scope;
8708   LocalContext context;
8709   const int kElementCount = 260;
8710   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
8711   i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
8712                                                               pixel_data);
8713   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8714   for (int i = 0; i < kElementCount; i++) {
8715     pixels->set(i, i % 256);
8716   }
8717   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8718   for (int i = 0; i < kElementCount; i++) {
8719     CHECK_EQ(i % 256, pixels->get(i));
8720     CHECK_EQ(i % 256, pixel_data[i]);
8721   }
8722 
8723   v8::Handle<v8::Object> obj = v8::Object::New();
8724   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
8725   // Set the elements to be the pixels.
8726   // jsobj->set_elements(*pixels);
8727   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
8728   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
8729   obj->Set(v8_str("field"), v8::Int32::New(1503));
8730   context->Global()->Set(v8_str("pixels"), obj);
8731   v8::Handle<v8::Value> result = CompileRun("pixels.field");
8732   CHECK_EQ(1503, result->Int32Value());
8733   result = CompileRun("pixels[1]");
8734   CHECK_EQ(1, result->Int32Value());
8735 
8736   result = CompileRun("var sum = 0;"
8737                       "for (var i = 0; i < 8; i++) {"
8738                       "  sum += pixels[i] = pixels[i] = -i;"
8739                       "}"
8740                       "sum;");
8741   CHECK_EQ(-28, result->Int32Value());
8742 
8743   result = CompileRun("var sum = 0;"
8744                       "for (var i = 0; i < 8; i++) {"
8745                       "  sum += pixels[i] = pixels[i] = 0;"
8746                       "}"
8747                       "sum;");
8748   CHECK_EQ(0, result->Int32Value());
8749 
8750   result = CompileRun("var sum = 0;"
8751                       "for (var i = 0; i < 8; i++) {"
8752                       "  sum += pixels[i] = pixels[i] = 255;"
8753                       "}"
8754                       "sum;");
8755   CHECK_EQ(8 * 255, result->Int32Value());
8756 
8757   result = CompileRun("var sum = 0;"
8758                       "for (var i = 0; i < 8; i++) {"
8759                       "  sum += pixels[i] = pixels[i] = 256 + i;"
8760                       "}"
8761                       "sum;");
8762   CHECK_EQ(2076, result->Int32Value());
8763 
8764   result = CompileRun("var sum = 0;"
8765                       "for (var i = 0; i < 8; i++) {"
8766                       "  sum += pixels[i] = pixels[i] = i;"
8767                       "}"
8768                       "sum;");
8769   CHECK_EQ(28, result->Int32Value());
8770 
8771   result = CompileRun("var sum = 0;"
8772                       "for (var i = 0; i < 8; i++) {"
8773                       "  sum += pixels[i];"
8774                       "}"
8775                       "sum;");
8776   CHECK_EQ(28, result->Int32Value());
8777 
8778   i::Handle<i::Smi> value(i::Smi::FromInt(2));
8779   i::SetElement(jsobj, 1, value);
8780   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
8781   *value.location() = i::Smi::FromInt(256);
8782   i::SetElement(jsobj, 1, value);
8783   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
8784   *value.location() = i::Smi::FromInt(-1);
8785   i::SetElement(jsobj, 1, value);
8786   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
8787 
8788   result = CompileRun("for (var i = 0; i < 8; i++) {"
8789                       "  pixels[i] = (i * 65) - 109;"
8790                       "}"
8791                       "pixels[1] + pixels[6];");
8792   CHECK_EQ(255, result->Int32Value());
8793   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
8794   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
8795   CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
8796   CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
8797   CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
8798   CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
8799   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
8800   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
8801   result = CompileRun("var sum = 0;"
8802                       "for (var i = 0; i < 8; i++) {"
8803                       "  sum += pixels[i];"
8804                       "}"
8805                       "sum;");
8806   CHECK_EQ(984, result->Int32Value());
8807 
8808   result = CompileRun("for (var i = 0; i < 8; i++) {"
8809                       "  pixels[i] = (i * 1.1);"
8810                       "}"
8811                       "pixels[1] + pixels[6];");
8812   CHECK_EQ(8, result->Int32Value());
8813   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
8814   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
8815   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
8816   CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
8817   CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
8818   CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
8819   CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
8820   CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
8821 
8822   result = CompileRun("for (var i = 0; i < 8; i++) {"
8823                       "  pixels[7] = undefined;"
8824                       "}"
8825                       "pixels[7];");
8826   CHECK_EQ(0, result->Int32Value());
8827   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
8828 
8829   result = CompileRun("for (var i = 0; i < 8; i++) {"
8830                       "  pixels[6] = '2.3';"
8831                       "}"
8832                       "pixels[6];");
8833   CHECK_EQ(2, result->Int32Value());
8834   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
8835 
8836   result = CompileRun("for (var i = 0; i < 8; i++) {"
8837                       "  pixels[5] = NaN;"
8838                       "}"
8839                       "pixels[5];");
8840   CHECK_EQ(0, result->Int32Value());
8841   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
8842 
8843   result = CompileRun("for (var i = 0; i < 8; i++) {"
8844                       "  pixels[8] = Infinity;"
8845                       "}"
8846                       "pixels[8];");
8847   CHECK_EQ(255, result->Int32Value());
8848   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
8849 
8850   result = CompileRun("for (var i = 0; i < 8; i++) {"
8851                       "  pixels[9] = -Infinity;"
8852                       "}"
8853                       "pixels[9];");
8854   CHECK_EQ(0, result->Int32Value());
8855   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
8856 
8857   result = CompileRun("pixels[3] = 33;"
8858                       "delete pixels[3];"
8859                       "pixels[3];");
8860   CHECK_EQ(33, result->Int32Value());
8861 
8862   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
8863                       "pixels[2] = 12; pixels[3] = 13;"
8864                       "pixels.__defineGetter__('2',"
8865                       "function() { return 120; });"
8866                       "pixels[2];");
8867   CHECK_EQ(12, result->Int32Value());
8868 
8869   result = CompileRun("var js_array = new Array(40);"
8870                       "js_array[0] = 77;"
8871                       "js_array;");
8872   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8873 
8874   result = CompileRun("pixels[1] = 23;"
8875                       "pixels.__proto__ = [];"
8876                       "js_array.__proto__ = pixels;"
8877                       "js_array.concat(pixels);");
8878   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
8879   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
8880 
8881   result = CompileRun("pixels[1] = 23;");
8882   CHECK_EQ(23, result->Int32Value());
8883 
8884   // Test for index greater than 255.  Regression test for:
8885   // http://code.google.com/p/chromium/issues/detail?id=26337.
8886   result = CompileRun("pixels[256] = 255;");
8887   CHECK_EQ(255, result->Int32Value());
8888   result = CompileRun("var i = 0;"
8889                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
8890                       "i");
8891   CHECK_EQ(255, result->Int32Value());
8892 
8893   free(pixel_data);
8894 }
8895 
8896 
8897 template <class ExternalArrayClass, class ElementType>
ExternalArrayTestHelper(v8::ExternalArrayType array_type,int64_t low,int64_t high)8898 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
8899                                     int64_t low,
8900                                     int64_t high) {
8901   v8::HandleScope scope;
8902   LocalContext context;
8903   const int kElementCount = 40;
8904   int element_size = 0;
8905   switch (array_type) {
8906     case v8::kExternalByteArray:
8907     case v8::kExternalUnsignedByteArray:
8908       element_size = 1;
8909       break;
8910     case v8::kExternalShortArray:
8911     case v8::kExternalUnsignedShortArray:
8912       element_size = 2;
8913       break;
8914     case v8::kExternalIntArray:
8915     case v8::kExternalUnsignedIntArray:
8916     case v8::kExternalFloatArray:
8917       element_size = 4;
8918       break;
8919     default:
8920       UNREACHABLE();
8921       break;
8922   }
8923   ElementType* array_data =
8924       static_cast<ElementType*>(malloc(kElementCount * element_size));
8925   i::Handle<ExternalArrayClass> array =
8926       i::Handle<ExternalArrayClass>::cast(
8927           i::Factory::NewExternalArray(kElementCount, array_type, array_data));
8928   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8929   for (int i = 0; i < kElementCount; i++) {
8930     array->set(i, static_cast<ElementType>(i));
8931   }
8932   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
8933   for (int i = 0; i < kElementCount; i++) {
8934     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i)));
8935     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
8936   }
8937 
8938   v8::Handle<v8::Object> obj = v8::Object::New();
8939   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
8940   // Set the elements to be the external array.
8941   obj->SetIndexedPropertiesToExternalArrayData(array_data,
8942                                                array_type,
8943                                                kElementCount);
8944   CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number()));
8945   obj->Set(v8_str("field"), v8::Int32::New(1503));
8946   context->Global()->Set(v8_str("ext_array"), obj);
8947   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
8948   CHECK_EQ(1503, result->Int32Value());
8949   result = CompileRun("ext_array[1]");
8950   CHECK_EQ(1, result->Int32Value());
8951 
8952   // Check pass through of assigned smis
8953   result = CompileRun("var sum = 0;"
8954                       "for (var i = 0; i < 8; i++) {"
8955                       "  sum += ext_array[i] = ext_array[i] = -i;"
8956                       "}"
8957                       "sum;");
8958   CHECK_EQ(-28, result->Int32Value());
8959 
8960   // Check assigned smis
8961   result = CompileRun("for (var i = 0; i < 8; i++) {"
8962                       "  ext_array[i] = i;"
8963                       "}"
8964                       "var sum = 0;"
8965                       "for (var i = 0; i < 8; i++) {"
8966                       "  sum += ext_array[i];"
8967                       "}"
8968                       "sum;");
8969   CHECK_EQ(28, result->Int32Value());
8970 
8971   // Check assigned smis in reverse order
8972   result = CompileRun("for (var i = 8; --i >= 0; ) {"
8973                       "  ext_array[i] = i;"
8974                       "}"
8975                       "var sum = 0;"
8976                       "for (var i = 0; i < 8; i++) {"
8977                       "  sum += ext_array[i];"
8978                       "}"
8979                       "sum;");
8980   CHECK_EQ(28, result->Int32Value());
8981 
8982   // Check pass through of assigned HeapNumbers
8983   result = CompileRun("var sum = 0;"
8984                       "for (var i = 0; i < 16; i+=2) {"
8985                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
8986                       "}"
8987                       "sum;");
8988   CHECK_EQ(-28, result->Int32Value());
8989 
8990   // Check assigned HeapNumbers
8991   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
8992                       "  ext_array[i] = (i * 0.5);"
8993                       "}"
8994                       "var sum = 0;"
8995                       "for (var i = 0; i < 16; i+=2) {"
8996                       "  sum += ext_array[i];"
8997                       "}"
8998                       "sum;");
8999   CHECK_EQ(28, result->Int32Value());
9000 
9001   // Check assigned HeapNumbers in reverse order
9002   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
9003                       "  ext_array[i] = (i * 0.5);"
9004                       "}"
9005                       "var sum = 0;"
9006                       "for (var i = 0; i < 16; i+=2) {"
9007                       "  sum += ext_array[i];"
9008                       "}"
9009                       "sum;");
9010   CHECK_EQ(28, result->Int32Value());
9011 
9012   i::ScopedVector<char> test_buf(1024);
9013 
9014   // Check legal boundary conditions.
9015   // The repeated loads and stores ensure the ICs are exercised.
9016   const char* boundary_program =
9017       "var res = 0;"
9018       "for (var i = 0; i < 16; i++) {"
9019       "  ext_array[i] = %lld;"
9020       "  if (i > 8) {"
9021       "    res = ext_array[i];"
9022       "  }"
9023       "}"
9024       "res;";
9025   i::OS::SNPrintF(test_buf,
9026                   boundary_program,
9027                   low);
9028   result = CompileRun(test_buf.start());
9029   CHECK_EQ(low, result->IntegerValue());
9030 
9031   i::OS::SNPrintF(test_buf,
9032                   boundary_program,
9033                   high);
9034   result = CompileRun(test_buf.start());
9035   CHECK_EQ(high, result->IntegerValue());
9036 
9037   // Check misprediction of type in IC.
9038   result = CompileRun("var tmp_array = ext_array;"
9039                       "var sum = 0;"
9040                       "for (var i = 0; i < 8; i++) {"
9041                       "  tmp_array[i] = i;"
9042                       "  sum += tmp_array[i];"
9043                       "  if (i == 4) {"
9044                       "    tmp_array = {};"
9045                       "  }"
9046                       "}"
9047                       "sum;");
9048   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
9049   CHECK_EQ(28, result->Int32Value());
9050 
9051   // Make sure out-of-range loads do not throw.
9052   i::OS::SNPrintF(test_buf,
9053                   "var caught_exception = false;"
9054                   "try {"
9055                   "  ext_array[%d];"
9056                   "} catch (e) {"
9057                   "  caught_exception = true;"
9058                   "}"
9059                   "caught_exception;",
9060                   kElementCount);
9061   result = CompileRun(test_buf.start());
9062   CHECK_EQ(false, result->BooleanValue());
9063 
9064   // Make sure out-of-range stores do not throw.
9065   i::OS::SNPrintF(test_buf,
9066                   "var caught_exception = false;"
9067                   "try {"
9068                   "  ext_array[%d] = 1;"
9069                   "} catch (e) {"
9070                   "  caught_exception = true;"
9071                   "}"
9072                   "caught_exception;",
9073                   kElementCount);
9074   result = CompileRun(test_buf.start());
9075   CHECK_EQ(false, result->BooleanValue());
9076 
9077   // Check other boundary conditions, values and operations.
9078   result = CompileRun("for (var i = 0; i < 8; i++) {"
9079                       "  ext_array[7] = undefined;"
9080                       "}"
9081                       "ext_array[7];");
9082   CHECK_EQ(0, result->Int32Value());
9083   CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number()));
9084 
9085   result = CompileRun("for (var i = 0; i < 8; i++) {"
9086                       "  ext_array[6] = '2.3';"
9087                       "}"
9088                       "ext_array[6];");
9089   CHECK_EQ(2, result->Int32Value());
9090   CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number()));
9091 
9092   if (array_type != v8::kExternalFloatArray) {
9093     // Though the specification doesn't state it, be explicit about
9094     // converting NaNs and +/-Infinity to zero.
9095     result = CompileRun("for (var i = 0; i < 8; i++) {"
9096                         "  ext_array[i] = 5;"
9097                         "}"
9098                         "for (var i = 0; i < 8; i++) {"
9099                         "  ext_array[i] = NaN;"
9100                         "}"
9101                         "ext_array[5];");
9102     CHECK_EQ(0, result->Int32Value());
9103     CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9104 
9105     result = CompileRun("for (var i = 0; i < 8; i++) {"
9106                         "  ext_array[i] = 5;"
9107                         "}"
9108                         "for (var i = 0; i < 8; i++) {"
9109                         "  ext_array[i] = Infinity;"
9110                         "}"
9111                         "ext_array[5];");
9112     CHECK_EQ(0, result->Int32Value());
9113     CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9114 
9115     result = CompileRun("for (var i = 0; i < 8; i++) {"
9116                         "  ext_array[i] = 5;"
9117                         "}"
9118                         "for (var i = 0; i < 8; i++) {"
9119                         "  ext_array[i] = -Infinity;"
9120                         "}"
9121                         "ext_array[5];");
9122     CHECK_EQ(0, result->Int32Value());
9123     CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
9124   }
9125 
9126   result = CompileRun("ext_array[3] = 33;"
9127                       "delete ext_array[3];"
9128                       "ext_array[3];");
9129   CHECK_EQ(33, result->Int32Value());
9130 
9131   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
9132                       "ext_array[2] = 12; ext_array[3] = 13;"
9133                       "ext_array.__defineGetter__('2',"
9134                       "function() { return 120; });"
9135                       "ext_array[2];");
9136   CHECK_EQ(12, result->Int32Value());
9137 
9138   result = CompileRun("var js_array = new Array(40);"
9139                       "js_array[0] = 77;"
9140                       "js_array;");
9141   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9142 
9143   result = CompileRun("ext_array[1] = 23;"
9144                       "ext_array.__proto__ = [];"
9145                       "js_array.__proto__ = ext_array;"
9146                       "js_array.concat(ext_array);");
9147   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
9148   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
9149 
9150   result = CompileRun("ext_array[1] = 23;");
9151   CHECK_EQ(23, result->Int32Value());
9152 
9153   // Test more complex manipulations which cause eax to contain values
9154   // that won't be completely overwritten by loads from the arrays.
9155   // This catches bugs in the instructions used for the KeyedLoadIC
9156   // for byte and word types.
9157   {
9158     const int kXSize = 300;
9159     const int kYSize = 300;
9160     const int kLargeElementCount = kXSize * kYSize * 4;
9161     ElementType* large_array_data =
9162         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
9163     i::Handle<ExternalArrayClass> large_array =
9164         i::Handle<ExternalArrayClass>::cast(
9165             i::Factory::NewExternalArray(kLargeElementCount,
9166                                          array_type,
9167                                          array_data));
9168     v8::Handle<v8::Object> large_obj = v8::Object::New();
9169     // Set the elements to be the external array.
9170     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
9171                                                        array_type,
9172                                                        kLargeElementCount);
9173     context->Global()->Set(v8_str("large_array"), large_obj);
9174     // Initialize contents of a few rows.
9175     for (int x = 0; x < 300; x++) {
9176       int row = 0;
9177       int offset = row * 300 * 4;
9178       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9179       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9180       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9181       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9182       row = 150;
9183       offset = row * 300 * 4;
9184       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9185       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9186       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9187       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9188       row = 298;
9189       offset = row * 300 * 4;
9190       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
9191       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
9192       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
9193       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
9194     }
9195     // The goal of the code below is to make "offset" large enough
9196     // that the computation of the index (which goes into eax) has
9197     // high bits set which will not be overwritten by a byte or short
9198     // load.
9199     result = CompileRun("var failed = false;"
9200                         "var offset = 0;"
9201                         "for (var i = 0; i < 300; i++) {"
9202                         "  if (large_array[4 * i] != 127 ||"
9203                         "      large_array[4 * i + 1] != 0 ||"
9204                         "      large_array[4 * i + 2] != 0 ||"
9205                         "      large_array[4 * i + 3] != 127) {"
9206                         "    failed = true;"
9207                         "  }"
9208                         "}"
9209                         "offset = 150 * 300 * 4;"
9210                         "for (var i = 0; i < 300; i++) {"
9211                         "  if (large_array[offset + 4 * i] != 127 ||"
9212                         "      large_array[offset + 4 * i + 1] != 0 ||"
9213                         "      large_array[offset + 4 * i + 2] != 0 ||"
9214                         "      large_array[offset + 4 * i + 3] != 127) {"
9215                         "    failed = true;"
9216                         "  }"
9217                         "}"
9218                         "offset = 298 * 300 * 4;"
9219                         "for (var i = 0; i < 300; i++) {"
9220                         "  if (large_array[offset + 4 * i] != 127 ||"
9221                         "      large_array[offset + 4 * i + 1] != 0 ||"
9222                         "      large_array[offset + 4 * i + 2] != 0 ||"
9223                         "      large_array[offset + 4 * i + 3] != 127) {"
9224                         "    failed = true;"
9225                         "  }"
9226                         "}"
9227                         "!failed;");
9228     CHECK_EQ(true, result->BooleanValue());
9229     free(large_array_data);
9230   }
9231 
9232   free(array_data);
9233 }
9234 
9235 
THREADED_TEST(ExternalByteArray)9236 THREADED_TEST(ExternalByteArray) {
9237   ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>(
9238       v8::kExternalByteArray,
9239       -128,
9240       127);
9241 }
9242 
9243 
THREADED_TEST(ExternalUnsignedByteArray)9244 THREADED_TEST(ExternalUnsignedByteArray) {
9245   ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>(
9246       v8::kExternalUnsignedByteArray,
9247       0,
9248       255);
9249 }
9250 
9251 
THREADED_TEST(ExternalShortArray)9252 THREADED_TEST(ExternalShortArray) {
9253   ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>(
9254       v8::kExternalShortArray,
9255       -32768,
9256       32767);
9257 }
9258 
9259 
THREADED_TEST(ExternalUnsignedShortArray)9260 THREADED_TEST(ExternalUnsignedShortArray) {
9261   ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>(
9262       v8::kExternalUnsignedShortArray,
9263       0,
9264       65535);
9265 }
9266 
9267 
THREADED_TEST(ExternalIntArray)9268 THREADED_TEST(ExternalIntArray) {
9269   ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>(
9270       v8::kExternalIntArray,
9271       INT_MIN,   // -2147483648
9272       INT_MAX);  //  2147483647
9273 }
9274 
9275 
THREADED_TEST(ExternalUnsignedIntArray)9276 THREADED_TEST(ExternalUnsignedIntArray) {
9277   ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>(
9278       v8::kExternalUnsignedIntArray,
9279       0,
9280       UINT_MAX);  // 4294967295
9281 }
9282 
9283 
THREADED_TEST(ExternalFloatArray)9284 THREADED_TEST(ExternalFloatArray) {
9285   ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>(
9286       v8::kExternalFloatArray,
9287       -500,
9288       500);
9289 }
9290 
9291 
THREADED_TEST(ExternalArrays)9292 THREADED_TEST(ExternalArrays) {
9293   TestExternalByteArray();
9294   TestExternalUnsignedByteArray();
9295   TestExternalShortArray();
9296   TestExternalUnsignedShortArray();
9297   TestExternalIntArray();
9298   TestExternalUnsignedIntArray();
9299   TestExternalFloatArray();
9300 }
9301 
9302 
THREADED_TEST(ScriptContextDependence)9303 THREADED_TEST(ScriptContextDependence) {
9304   v8::HandleScope scope;
9305   LocalContext c1;
9306   const char *source = "foo";
9307   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
9308   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
9309   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
9310   CHECK_EQ(dep->Run()->Int32Value(), 100);
9311   CHECK_EQ(indep->Run()->Int32Value(), 100);
9312   LocalContext c2;
9313   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
9314   CHECK_EQ(dep->Run()->Int32Value(), 100);
9315   CHECK_EQ(indep->Run()->Int32Value(), 101);
9316 }
9317 
9318 
THREADED_TEST(StackTrace)9319 THREADED_TEST(StackTrace) {
9320   v8::HandleScope scope;
9321   LocalContext context;
9322   v8::TryCatch try_catch;
9323   const char *source = "function foo() { FAIL.FAIL; }; foo();";
9324   v8::Handle<v8::String> src = v8::String::New(source);
9325   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
9326   v8::Script::New(src, origin)->Run();
9327   CHECK(try_catch.HasCaught());
9328   v8::String::Utf8Value stack(try_catch.StackTrace());
9329   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
9330 }
9331 
9332 
9333 // Test that idle notification can be handled and eventually returns true.
THREADED_TEST(IdleNotification)9334 THREADED_TEST(IdleNotification) {
9335   bool rv = false;
9336   for (int i = 0; i < 100; i++) {
9337     rv = v8::V8::IdleNotification();
9338     if (rv)
9339       break;
9340   }
9341   CHECK(rv == true);
9342 }
9343 
9344 
9345 static uint32_t* stack_limit;
9346 
GetStackLimitCallback(const v8::Arguments & args)9347 static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
9348   stack_limit = reinterpret_cast<uint32_t*>(i::StackGuard::climit());
9349   return v8::Undefined();
9350 }
9351 
9352 
9353 // Uses the address of a local variable to determine the stack top now.
9354 // Given a size, returns an address that is that far from the current
9355 // top of stack.
ComputeStackLimit(uint32_t size)9356 static uint32_t* ComputeStackLimit(uint32_t size) {
9357   uint32_t* answer = &size - (size / sizeof(size));
9358   // If the size is very large and the stack is very near the bottom of
9359   // memory then the calculation above may wrap around and give an address
9360   // that is above the (downwards-growing) stack.  In that case we return
9361   // a very low address.
9362   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
9363   return answer;
9364 }
9365 
9366 
TEST(SetResourceConstraints)9367 TEST(SetResourceConstraints) {
9368   static const int K = 1024;
9369   uint32_t* set_limit = ComputeStackLimit(128 * K);
9370 
9371   // Set stack limit.
9372   v8::ResourceConstraints constraints;
9373   constraints.set_stack_limit(set_limit);
9374   CHECK(v8::SetResourceConstraints(&constraints));
9375 
9376   // Execute a script.
9377   v8::HandleScope scope;
9378   LocalContext env;
9379   Local<v8::FunctionTemplate> fun_templ =
9380       v8::FunctionTemplate::New(GetStackLimitCallback);
9381   Local<Function> fun = fun_templ->GetFunction();
9382   env->Global()->Set(v8_str("get_stack_limit"), fun);
9383   CompileRun("get_stack_limit();");
9384 
9385   CHECK(stack_limit == set_limit);
9386 }
9387 
9388 
TEST(SetResourceConstraintsInThread)9389 TEST(SetResourceConstraintsInThread) {
9390   uint32_t* set_limit;
9391   {
9392     v8::Locker locker;
9393     static const int K = 1024;
9394     set_limit = ComputeStackLimit(128 * K);
9395 
9396     // Set stack limit.
9397     v8::ResourceConstraints constraints;
9398     constraints.set_stack_limit(set_limit);
9399     CHECK(v8::SetResourceConstraints(&constraints));
9400 
9401     // Execute a script.
9402     v8::HandleScope scope;
9403     LocalContext env;
9404     Local<v8::FunctionTemplate> fun_templ =
9405         v8::FunctionTemplate::New(GetStackLimitCallback);
9406     Local<Function> fun = fun_templ->GetFunction();
9407     env->Global()->Set(v8_str("get_stack_limit"), fun);
9408     CompileRun("get_stack_limit();");
9409 
9410     CHECK(stack_limit == set_limit);
9411   }
9412   {
9413     v8::Locker locker;
9414     CHECK(stack_limit == set_limit);
9415   }
9416 }
9417 
9418 
THREADED_TEST(GetHeapStatistics)9419 THREADED_TEST(GetHeapStatistics) {
9420   v8::HandleScope scope;
9421   LocalContext c1;
9422   v8::HeapStatistics heap_statistics;
9423   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
9424   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
9425   v8::V8::GetHeapStatistics(&heap_statistics);
9426   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
9427   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
9428 }
9429 
9430 
DoubleFromBits(uint64_t value)9431 static double DoubleFromBits(uint64_t value) {
9432   double target;
9433 #ifdef BIG_ENDIAN_FLOATING_POINT
9434   const int kIntSize = 4;
9435   // Somebody swapped the lower and higher half of doubles.
9436   memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
9437   memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
9438 #else
9439   memcpy(&target, &value, sizeof(target));
9440 #endif
9441   return target;
9442 }
9443 
9444 
DoubleToBits(double value)9445 static uint64_t DoubleToBits(double value) {
9446   uint64_t target;
9447 #ifdef BIG_ENDIAN_FLOATING_POINT
9448   const int kIntSize = 4;
9449   // Somebody swapped the lower and higher half of doubles.
9450   memcpy(&target, reinterpret_cast<char*>(&value) + kIntSize, kIntSize);
9451   memcpy(reinterpret_cast<char*>(&target) + kIntSize, &value, kIntSize);
9452 #else
9453   memcpy(&target, &value, sizeof(target));
9454 #endif
9455   return target;
9456 }
9457 
9458 
DoubleToDateTime(double input)9459 static double DoubleToDateTime(double input) {
9460   double date_limit = 864e13;
9461   if (IsNaN(input) || input < -date_limit || input > date_limit) {
9462     return i::OS::nan_value();
9463   }
9464   return (input < 0) ? -(floor(-input)) : floor(input);
9465 }
9466 
9467 // We don't have a consistent way to write 64-bit constants syntactically, so we
9468 // split them into two 32-bit constants and combine them programmatically.
DoubleFromBits(uint32_t high_bits,uint32_t low_bits)9469 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
9470   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
9471 }
9472 
9473 
THREADED_TEST(QuietSignalingNaNs)9474 THREADED_TEST(QuietSignalingNaNs) {
9475   v8::HandleScope scope;
9476   LocalContext context;
9477   v8::TryCatch try_catch;
9478 
9479   // Special double values.
9480   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
9481   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
9482   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
9483   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
9484   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
9485   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
9486   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
9487 
9488   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
9489   // on either side of the epoch.
9490   double date_limit = 864e13;
9491 
9492   double test_values[] = {
9493       snan,
9494       qnan,
9495       infinity,
9496       max_normal,
9497       date_limit + 1,
9498       date_limit,
9499       min_normal,
9500       max_denormal,
9501       min_denormal,
9502       0,
9503       -0,
9504       -min_denormal,
9505       -max_denormal,
9506       -min_normal,
9507       -date_limit,
9508       -date_limit - 1,
9509       -max_normal,
9510       -infinity,
9511       -qnan,
9512       -snan
9513   };
9514   int num_test_values = 20;
9515 
9516   for (int i = 0; i < num_test_values; i++) {
9517     double test_value = test_values[i];
9518 
9519     // Check that Number::New preserves non-NaNs and quiets SNaNs.
9520     v8::Handle<v8::Value> number = v8::Number::New(test_value);
9521     double stored_number = number->NumberValue();
9522     if (!IsNaN(test_value)) {
9523       CHECK_EQ(test_value, stored_number);
9524     } else {
9525       uint64_t stored_bits = DoubleToBits(stored_number);
9526       // Check if quiet nan (bits 51..62 all set).
9527       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
9528     }
9529 
9530     // Check that Date::New preserves non-NaNs in the date range and
9531     // quiets SNaNs.
9532     v8::Handle<v8::Value> date = v8::Date::New(test_value);
9533     double expected_stored_date = DoubleToDateTime(test_value);
9534     double stored_date = date->NumberValue();
9535     if (!IsNaN(expected_stored_date)) {
9536       CHECK_EQ(expected_stored_date, stored_date);
9537     } else {
9538       uint64_t stored_bits = DoubleToBits(stored_date);
9539       // Check if quiet nan (bits 51..62 all set).
9540       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
9541     }
9542   }
9543 }
9544 
9545 
SpaghettiIncident(const v8::Arguments & args)9546 static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
9547   v8::HandleScope scope;
9548   v8::TryCatch tc;
9549   v8::Handle<v8::String> str = args[0]->ToString();
9550   if (tc.HasCaught())
9551     return tc.ReThrow();
9552   return v8::Undefined();
9553 }
9554 
9555 
9556 // Test that an exception can be propagated down through a spaghetti
9557 // stack using ReThrow.
THREADED_TEST(SpaghettiStackReThrow)9558 THREADED_TEST(SpaghettiStackReThrow) {
9559   v8::HandleScope scope;
9560   LocalContext context;
9561   context->Global()->Set(
9562       v8::String::New("s"),
9563       v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
9564   v8::TryCatch try_catch;
9565   CompileRun(
9566       "var i = 0;"
9567       "var o = {"
9568       "  toString: function () {"
9569       "    if (i == 10) {"
9570       "      throw 'Hey!';"
9571       "    } else {"
9572       "      i++;"
9573       "      return s(o);"
9574       "    }"
9575       "  }"
9576       "};"
9577       "s(o);");
9578   CHECK(try_catch.HasCaught());
9579   v8::String::Utf8Value value(try_catch.Exception());
9580   CHECK_EQ(0, strcmp(*value, "Hey!"));
9581 }
9582 
9583 
TEST(Regress528)9584 TEST(Regress528) {
9585   v8::V8::Initialize();
9586 
9587   v8::HandleScope scope;
9588   v8::Persistent<Context> context;
9589   v8::Persistent<Context> other_context;
9590   int gc_count;
9591 
9592   // Create a context used to keep the code from aging in the compilation
9593   // cache.
9594   other_context = Context::New();
9595 
9596   // Context-dependent context data creates reference from the compilation
9597   // cache to the global object.
9598   const char* source_simple = "1";
9599   context = Context::New();
9600   {
9601     v8::HandleScope scope;
9602 
9603     context->Enter();
9604     Local<v8::String> obj = v8::String::New("");
9605     context->SetData(obj);
9606     CompileRun(source_simple);
9607     context->Exit();
9608   }
9609   context.Dispose();
9610   for (gc_count = 1; gc_count < 10; gc_count++) {
9611     other_context->Enter();
9612     CompileRun(source_simple);
9613     other_context->Exit();
9614     v8::internal::Heap::CollectAllGarbage(false);
9615     if (GetGlobalObjectsCount() == 1) break;
9616   }
9617   CHECK_GE(2, gc_count);
9618   CHECK_EQ(1, GetGlobalObjectsCount());
9619 
9620   // Eval in a function creates reference from the compilation cache to the
9621   // global object.
9622   const char* source_eval = "function f(){eval('1')}; f()";
9623   context = Context::New();
9624   {
9625     v8::HandleScope scope;
9626 
9627     context->Enter();
9628     CompileRun(source_eval);
9629     context->Exit();
9630   }
9631   context.Dispose();
9632   for (gc_count = 1; gc_count < 10; gc_count++) {
9633     other_context->Enter();
9634     CompileRun(source_eval);
9635     other_context->Exit();
9636     v8::internal::Heap::CollectAllGarbage(false);
9637     if (GetGlobalObjectsCount() == 1) break;
9638   }
9639   CHECK_GE(2, gc_count);
9640   CHECK_EQ(1, GetGlobalObjectsCount());
9641 
9642   // Looking up the line number for an exception creates reference from the
9643   // compilation cache to the global object.
9644   const char* source_exception = "function f(){throw 1;} f()";
9645   context = Context::New();
9646   {
9647     v8::HandleScope scope;
9648 
9649     context->Enter();
9650     v8::TryCatch try_catch;
9651     CompileRun(source_exception);
9652     CHECK(try_catch.HasCaught());
9653     v8::Handle<v8::Message> message = try_catch.Message();
9654     CHECK(!message.IsEmpty());
9655     CHECK_EQ(1, message->GetLineNumber());
9656     context->Exit();
9657   }
9658   context.Dispose();
9659   for (gc_count = 1; gc_count < 10; gc_count++) {
9660     other_context->Enter();
9661     CompileRun(source_exception);
9662     other_context->Exit();
9663     v8::internal::Heap::CollectAllGarbage(false);
9664     if (GetGlobalObjectsCount() == 1) break;
9665   }
9666   CHECK_GE(2, gc_count);
9667   CHECK_EQ(1, GetGlobalObjectsCount());
9668 
9669   other_context.Dispose();
9670 }
9671 
9672 
THREADED_TEST(ScriptOrigin)9673 THREADED_TEST(ScriptOrigin) {
9674   v8::HandleScope scope;
9675   LocalContext env;
9676   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
9677   v8::Handle<v8::String> script = v8::String::New(
9678       "function f() {}\n\nfunction g() {}");
9679   v8::Script::Compile(script, &origin)->Run();
9680   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
9681       env->Global()->Get(v8::String::New("f")));
9682   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
9683       env->Global()->Get(v8::String::New("g")));
9684 
9685   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
9686   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName()));
9687   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
9688 
9689   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
9690   CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName()));
9691   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
9692 }
9693 
9694 
THREADED_TEST(ScriptLineNumber)9695 THREADED_TEST(ScriptLineNumber) {
9696   v8::HandleScope scope;
9697   LocalContext env;
9698   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
9699   v8::Handle<v8::String> script = v8::String::New(
9700       "function f() {}\n\nfunction g() {}");
9701   v8::Script::Compile(script, &origin)->Run();
9702   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
9703       env->Global()->Get(v8::String::New("f")));
9704   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
9705       env->Global()->Get(v8::String::New("g")));
9706   CHECK_EQ(0, f->GetScriptLineNumber());
9707   CHECK_EQ(2, g->GetScriptLineNumber());
9708 }
9709 
9710 
GetterWhichReturns42(Local<String> name,const AccessorInfo & info)9711 static v8::Handle<Value> GetterWhichReturns42(Local<String> name,
9712                                               const AccessorInfo& info) {
9713   return v8_num(42);
9714 }
9715 
9716 
SetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const AccessorInfo & info)9717 static void SetterWhichSetsYOnThisTo23(Local<String> name,
9718                                        Local<Value> value,
9719                                        const AccessorInfo& info) {
9720   info.This()->Set(v8_str("y"), v8_num(23));
9721 }
9722 
9723 
THREADED_TEST(SetterOnConstructorPrototype)9724 THREADED_TEST(SetterOnConstructorPrototype) {
9725   v8::HandleScope scope;
9726   Local<ObjectTemplate> templ = ObjectTemplate::New();
9727   templ->SetAccessor(v8_str("x"),
9728                      GetterWhichReturns42,
9729                      SetterWhichSetsYOnThisTo23);
9730   LocalContext context;
9731   context->Global()->Set(v8_str("P"), templ->NewInstance());
9732   CompileRun("function C1() {"
9733              "  this.x = 23;"
9734              "};"
9735              "C1.prototype = P;"
9736              "function C2() {"
9737              "  this.x = 23"
9738              "};"
9739              "C2.prototype = { };"
9740              "C2.prototype.__proto__ = P;");
9741 
9742   v8::Local<v8::Script> script;
9743   script = v8::Script::Compile(v8_str("new C1();"));
9744   for (int i = 0; i < 10; i++) {
9745     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
9746     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
9747     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
9748   }
9749 
9750   script = v8::Script::Compile(v8_str("new C2();"));
9751   for (int i = 0; i < 10; i++) {
9752     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
9753     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
9754     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
9755   }
9756 }
9757 
9758 
NamedPropertyGetterWhichReturns42(Local<String> name,const AccessorInfo & info)9759 static v8::Handle<Value> NamedPropertyGetterWhichReturns42(
9760     Local<String> name, const AccessorInfo& info) {
9761   return v8_num(42);
9762 }
9763 
9764 
NamedPropertySetterWhichSetsYOnThisTo23(Local<String> name,Local<Value> value,const AccessorInfo & info)9765 static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23(
9766     Local<String> name, Local<Value> value, const AccessorInfo& info) {
9767   if (name->Equals(v8_str("x"))) {
9768     info.This()->Set(v8_str("y"), v8_num(23));
9769   }
9770   return v8::Handle<Value>();
9771 }
9772 
9773 
THREADED_TEST(InterceptorOnConstructorPrototype)9774 THREADED_TEST(InterceptorOnConstructorPrototype) {
9775   v8::HandleScope scope;
9776   Local<ObjectTemplate> templ = ObjectTemplate::New();
9777   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
9778                                  NamedPropertySetterWhichSetsYOnThisTo23);
9779   LocalContext context;
9780   context->Global()->Set(v8_str("P"), templ->NewInstance());
9781   CompileRun("function C1() {"
9782              "  this.x = 23;"
9783              "};"
9784              "C1.prototype = P;"
9785              "function C2() {"
9786              "  this.x = 23"
9787              "};"
9788              "C2.prototype = { };"
9789              "C2.prototype.__proto__ = P;");
9790 
9791   v8::Local<v8::Script> script;
9792   script = v8::Script::Compile(v8_str("new C1();"));
9793   for (int i = 0; i < 10; i++) {
9794     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
9795     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
9796     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
9797   }
9798 
9799   script = v8::Script::Compile(v8_str("new C2();"));
9800   for (int i = 0; i < 10; i++) {
9801     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
9802     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
9803     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
9804   }
9805 }
9806