• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2007-2008 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 <stdlib.h>
29 
30 #include "v8.h"
31 
32 #include "api.h"
33 #include "compilation-cache.h"
34 #include "snapshot.h"
35 #include "platform.h"
36 #include "top.h"
37 #include "cctest.h"
38 
IsNaN(double x)39 static bool IsNaN(double x) {
40 #ifdef WIN32
41   return _isnan(x);
42 #else
43   return isnan(x);
44 #endif
45 }
46 
47 using ::v8::ObjectTemplate;
48 using ::v8::Value;
49 using ::v8::Context;
50 using ::v8::Local;
51 using ::v8::String;
52 using ::v8::Script;
53 using ::v8::Function;
54 using ::v8::AccessorInfo;
55 using ::v8::Extension;
56 
57 namespace i = ::v8::internal;
58 
v8_num(double x)59 static Local<Value> v8_num(double x) {
60   return v8::Number::New(x);
61 }
62 
63 
v8_str(const char * x)64 static Local<String> v8_str(const char* x) {
65   return String::New(x);
66 }
67 
68 
v8_compile(const char * x)69 static Local<Script> v8_compile(const char* x) {
70   return Script::Compile(v8_str(x));
71 }
72 
73 
74 // A LocalContext holds a reference to a v8::Context.
75 class LocalContext {
76  public:
LocalContext(v8::ExtensionConfiguration * extensions=0,v8::Handle<ObjectTemplate> global_template=v8::Handle<ObjectTemplate> (),v8::Handle<Value> global_object=v8::Handle<Value> ())77   LocalContext(v8::ExtensionConfiguration* extensions = 0,
78                v8::Handle<ObjectTemplate> global_template =
79                    v8::Handle<ObjectTemplate>(),
80                v8::Handle<Value> global_object = v8::Handle<Value>())
81     : context_(Context::New(extensions, global_template, global_object)) {
82     context_->Enter();
83   }
84 
~LocalContext()85   virtual ~LocalContext() {
86     context_->Exit();
87     context_.Dispose();
88   }
89 
operator ->()90   Context* operator->() { return *context_; }
operator *()91   Context* operator*() { return *context_; }
local()92   Local<Context> local() { return Local<Context>::New(context_); }
IsReady()93   bool IsReady() { return !context_.IsEmpty(); }
94 
95  private:
96   v8::Persistent<Context> context_;
97 };
98 
99 
100 // Switches between all the Api tests using the threading support.
101 // In order to get a surprising but repeatable pattern of thread
102 // switching it has extra semaphores to control the order in which
103 // the tests alternate, not relying solely on the big V8 lock.
104 //
105 // A test is augmented with calls to ApiTestFuzzer::Fuzz() in its
106 // callbacks.  This will have no effect when we are not running the
107 // thread fuzzing test.  In the thread fuzzing test it will
108 // pseudorandomly select a successor thread and switch execution
109 // to that thread, suspending the current test.
110 class ApiTestFuzzer: public v8::internal::Thread {
111  public:
112   void CallTest();
ApiTestFuzzer(int num)113   explicit ApiTestFuzzer(int num)
114       : test_number_(num),
115         gate_(v8::internal::OS::CreateSemaphore(0)),
116         active_(true) {
117   }
~ApiTestFuzzer()118   ~ApiTestFuzzer() { delete gate_; }
119 
120   // The ApiTestFuzzer is also a Thread, so it has a Run method.
121   virtual void Run();
122 
123   enum PartOfTest { FIRST_PART, SECOND_PART };
124 
125   static void Setup(PartOfTest part);
126   static void RunAllTests();
127   static void TearDown();
128   // This method switches threads if we are running the Threading test.
129   // Otherwise it does nothing.
130   static void Fuzz();
131  private:
132   static bool fuzzing_;
133   static int tests_being_run_;
134   static int current_;
135   static int active_tests_;
136   static bool NextThread();
137   int test_number_;
138   v8::internal::Semaphore* gate_;
139   bool active_;
140   void ContextSwitch();
141   static int GetNextTestNumber();
142   static v8::internal::Semaphore* all_tests_done_;
143 };
144 
145 
146 #define THREADED_TEST(Name)                                          \
147   static void Test##Name();                                          \
148   RegisterThreadedTest register_##Name(Test##Name);                  \
149   /* */ TEST(Name)
150 
151 
152 class RegisterThreadedTest {
153  public:
RegisterThreadedTest(CcTest::TestFunction * callback)154   explicit RegisterThreadedTest(CcTest::TestFunction* callback)
155       : fuzzer_(NULL), callback_(callback) {
156     prev_ = first_;
157     first_ = this;
158     count_++;
159   }
count()160   static int count() { return count_; }
nth(int i)161   static RegisterThreadedTest* nth(int i) {
162     CHECK(i < count());
163     RegisterThreadedTest* current = first_;
164     while (i > 0) {
165       i--;
166       current = current->prev_;
167     }
168     return current;
169   }
callback()170   CcTest::TestFunction* callback() { return callback_; }
171   ApiTestFuzzer* fuzzer_;
172 
173  private:
174   static RegisterThreadedTest* first_;
175   static int count_;
176   CcTest::TestFunction* callback_;
177   RegisterThreadedTest* prev_;
178 };
179 
180 
181 RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;
182 int RegisterThreadedTest::count_ = 0;
183 
184 
185 static int signature_callback_count;
IncrementingSignatureCallback(const v8::Arguments & args)186 static v8::Handle<Value> IncrementingSignatureCallback(
187     const v8::Arguments& args) {
188   ApiTestFuzzer::Fuzz();
189   signature_callback_count++;
190   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
191   for (int i = 0; i < args.Length(); i++)
192     result->Set(v8::Integer::New(i), args[i]);
193   return result;
194 }
195 
196 
SignatureCallback(const v8::Arguments & args)197 static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) {
198   ApiTestFuzzer::Fuzz();
199   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
200   for (int i = 0; i < args.Length(); i++) {
201     result->Set(v8::Integer::New(i), args[i]);
202   }
203   return result;
204 }
205 
206 
THREADED_TEST(Handles)207 THREADED_TEST(Handles) {
208   v8::HandleScope scope;
209   Local<Context> local_env;
210   {
211     LocalContext env;
212     local_env = env.local();
213   }
214 
215   // Local context should still be live.
216   CHECK(!local_env.IsEmpty());
217   local_env->Enter();
218 
219   v8::Handle<v8::Primitive> undef = v8::Undefined();
220   CHECK(!undef.IsEmpty());
221   CHECK(undef->IsUndefined());
222 
223   const char* c_source = "1 + 2 + 3";
224   Local<String> source = String::New(c_source);
225   Local<Script> script = Script::Compile(source);
226   CHECK_EQ(6, script->Run()->Int32Value());
227 
228   local_env->Exit();
229 }
230 
231 
232 // Helper function that compiles and runs the source.
CompileRun(const char * source)233 static Local<Value> CompileRun(const char* source) {
234   return Script::Compile(String::New(source))->Run();
235 }
236 
THREADED_TEST(ReceiverSignature)237 THREADED_TEST(ReceiverSignature) {
238   v8::HandleScope scope;
239   LocalContext env;
240   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
241   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
242   fun->PrototypeTemplate()->Set(
243       v8_str("m"),
244       v8::FunctionTemplate::New(IncrementingSignatureCallback,
245                                 v8::Handle<Value>(),
246                                 sig));
247   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
248   signature_callback_count = 0;
249   CompileRun(
250       "var o = new Fun();"
251       "o.m();");
252   CHECK_EQ(1, signature_callback_count);
253   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
254   sub_fun->Inherit(fun);
255   env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
256   CompileRun(
257       "var o = new SubFun();"
258       "o.m();");
259   CHECK_EQ(2, signature_callback_count);
260 
261   v8::TryCatch try_catch;
262   CompileRun(
263       "var o = { };"
264       "o.m = Fun.prototype.m;"
265       "o.m();");
266   CHECK_EQ(2, signature_callback_count);
267   CHECK(try_catch.HasCaught());
268   try_catch.Reset();
269   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
270   sub_fun->Inherit(fun);
271   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
272   CompileRun(
273       "var o = new UnrelFun();"
274       "o.m = Fun.prototype.m;"
275       "o.m();");
276   CHECK_EQ(2, signature_callback_count);
277   CHECK(try_catch.HasCaught());
278 }
279 
280 
281 
282 
THREADED_TEST(ArgumentSignature)283 THREADED_TEST(ArgumentSignature) {
284   v8::HandleScope scope;
285   LocalContext env;
286   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
287   cons->SetClassName(v8_str("Cons"));
288   v8::Handle<v8::Signature> sig =
289       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
290   v8::Handle<v8::FunctionTemplate> fun =
291       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
292   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
293   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
294 
295   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
296   CHECK(value1->IsTrue());
297 
298   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
299   CHECK(value2->IsTrue());
300 
301   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
302   CHECK(value3->IsTrue());
303 
304   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
305   cons1->SetClassName(v8_str("Cons1"));
306   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
307   cons2->SetClassName(v8_str("Cons2"));
308   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
309   cons3->SetClassName(v8_str("Cons3"));
310 
311   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
312   v8::Handle<v8::Signature> wsig =
313       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
314   v8::Handle<v8::FunctionTemplate> fun2 =
315       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
316 
317   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
318   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
319   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
320   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
321   v8::Handle<Value> value4 = CompileRun(
322       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
323       "'[object Cons1],[object Cons2],[object Cons3]'");
324   CHECK(value4->IsTrue());
325 
326   v8::Handle<Value> value5 = CompileRun(
327       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
328   CHECK(value5->IsTrue());
329 
330   v8::Handle<Value> value6 = CompileRun(
331       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
332   CHECK(value6->IsTrue());
333 
334   v8::Handle<Value> value7 = CompileRun(
335       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
336       "'[object Cons1],[object Cons2],[object Cons3],d';");
337   CHECK(value7->IsTrue());
338 
339   v8::Handle<Value> value8 = CompileRun(
340       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
341   CHECK(value8->IsTrue());
342 }
343 
344 
THREADED_TEST(HulIgennem)345 THREADED_TEST(HulIgennem) {
346   v8::HandleScope scope;
347   LocalContext env;
348   v8::Handle<v8::Primitive> undef = v8::Undefined();
349   Local<String> undef_str = undef->ToString();
350   char* value = i::NewArray<char>(undef_str->Length() + 1);
351   undef_str->WriteAscii(value);
352   CHECK_EQ(0, strcmp(value, "undefined"));
353   i::DeleteArray(value);
354 }
355 
356 
THREADED_TEST(Access)357 THREADED_TEST(Access) {
358   v8::HandleScope scope;
359   LocalContext env;
360   Local<v8::Object> obj = v8::Object::New();
361   Local<Value> foo_before = obj->Get(v8_str("foo"));
362   CHECK(foo_before->IsUndefined());
363   Local<String> bar_str = v8_str("bar");
364   obj->Set(v8_str("foo"), bar_str);
365   Local<Value> foo_after = obj->Get(v8_str("foo"));
366   CHECK(!foo_after->IsUndefined());
367   CHECK(foo_after->IsString());
368   CHECK_EQ(bar_str, foo_after);
369 }
370 
371 
THREADED_TEST(Script)372 THREADED_TEST(Script) {
373   v8::HandleScope scope;
374   LocalContext env;
375   const char* c_source = "1 + 2 + 3";
376   Local<String> source = String::New(c_source);
377   Local<Script> script = Script::Compile(source);
378   CHECK_EQ(6, script->Run()->Int32Value());
379 }
380 
381 
AsciiToTwoByteString(const char * source)382 static uint16_t* AsciiToTwoByteString(const char* source) {
383   size_t array_length = strlen(source) + 1;
384   uint16_t* converted = i::NewArray<uint16_t>(array_length);
385   for (size_t i = 0; i < array_length; i++) converted[i] = source[i];
386   return converted;
387 }
388 
389 
390 class TestResource: public String::ExternalStringResource {
391  public:
392   static int dispose_count;
393 
TestResource(uint16_t * data)394   explicit TestResource(uint16_t* data)
395       : data_(data), length_(0) {
396     while (data[length_]) ++length_;
397   }
398 
~TestResource()399   ~TestResource() {
400     i::DeleteArray(data_);
401     ++dispose_count;
402   }
403 
data() const404   const uint16_t* data() const {
405     return data_;
406   }
407 
length() const408   size_t length() const {
409     return length_;
410   }
411  private:
412   uint16_t* data_;
413   size_t length_;
414 };
415 
416 
417 int TestResource::dispose_count = 0;
418 
419 
420 class TestAsciiResource: public String::ExternalAsciiStringResource {
421  public:
422   static int dispose_count;
423 
TestAsciiResource(const char * data)424   explicit TestAsciiResource(const char* data)
425       : data_(data),
426         length_(strlen(data)) { }
427 
~TestAsciiResource()428   ~TestAsciiResource() {
429     i::DeleteArray(data_);
430     ++dispose_count;
431   }
432 
data() const433   const char* data() const {
434     return data_;
435   }
436 
length() const437   size_t length() const {
438     return length_;
439   }
440  private:
441   const char* data_;
442   size_t length_;
443 };
444 
445 
446 int TestAsciiResource::dispose_count = 0;
447 
448 
THREADED_TEST(ScriptUsingStringResource)449 THREADED_TEST(ScriptUsingStringResource) {
450   TestResource::dispose_count = 0;
451   const char* c_source = "1 + 2 * 3";
452   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
453   {
454     v8::HandleScope scope;
455     LocalContext env;
456     TestResource* resource = new TestResource(two_byte_source);
457     Local<String> source = String::NewExternal(resource);
458     Local<Script> script = Script::Compile(source);
459     Local<Value> value = script->Run();
460     CHECK(value->IsNumber());
461     CHECK_EQ(7, value->Int32Value());
462     CHECK(source->IsExternal());
463     CHECK_EQ(resource,
464              static_cast<TestResource*>(source->GetExternalStringResource()));
465     v8::internal::Heap::CollectAllGarbage(false);
466     CHECK_EQ(0, TestResource::dispose_count);
467   }
468   v8::internal::CompilationCache::Clear();
469   v8::internal::Heap::CollectAllGarbage(false);
470   CHECK_EQ(1, TestResource::dispose_count);
471 }
472 
473 
THREADED_TEST(ScriptUsingAsciiStringResource)474 THREADED_TEST(ScriptUsingAsciiStringResource) {
475   TestAsciiResource::dispose_count = 0;
476   const char* c_source = "1 + 2 * 3";
477   {
478     v8::HandleScope scope;
479     LocalContext env;
480     Local<String> source =
481         String::NewExternal(new TestAsciiResource(i::StrDup(c_source)));
482     Local<Script> script = Script::Compile(source);
483     Local<Value> value = script->Run();
484     CHECK(value->IsNumber());
485     CHECK_EQ(7, value->Int32Value());
486     v8::internal::Heap::CollectAllGarbage(false);
487     CHECK_EQ(0, TestAsciiResource::dispose_count);
488   }
489   v8::internal::CompilationCache::Clear();
490   v8::internal::Heap::CollectAllGarbage(false);
491   CHECK_EQ(1, TestAsciiResource::dispose_count);
492 }
493 
494 
THREADED_TEST(ScriptMakingExternalString)495 THREADED_TEST(ScriptMakingExternalString) {
496   TestResource::dispose_count = 0;
497   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
498   {
499     v8::HandleScope scope;
500     LocalContext env;
501     Local<String> source = String::New(two_byte_source);
502     bool success = source->MakeExternal(new TestResource(two_byte_source));
503     CHECK(success);
504     Local<Script> script = Script::Compile(source);
505     Local<Value> value = script->Run();
506     CHECK(value->IsNumber());
507     CHECK_EQ(7, value->Int32Value());
508     v8::internal::Heap::CollectAllGarbage(false);
509     CHECK_EQ(0, TestResource::dispose_count);
510   }
511   v8::internal::CompilationCache::Clear();
512   v8::internal::Heap::CollectAllGarbage(false);
513   CHECK_EQ(1, TestResource::dispose_count);
514 }
515 
516 
THREADED_TEST(ScriptMakingExternalAsciiString)517 THREADED_TEST(ScriptMakingExternalAsciiString) {
518   TestAsciiResource::dispose_count = 0;
519   const char* c_source = "1 + 2 * 3";
520   {
521     v8::HandleScope scope;
522     LocalContext env;
523     Local<String> source = v8_str(c_source);
524     bool success = source->MakeExternal(
525         new TestAsciiResource(i::StrDup(c_source)));
526     CHECK(success);
527     Local<Script> script = Script::Compile(source);
528     Local<Value> value = script->Run();
529     CHECK(value->IsNumber());
530     CHECK_EQ(7, value->Int32Value());
531     v8::internal::Heap::CollectAllGarbage(false);
532     CHECK_EQ(0, TestAsciiResource::dispose_count);
533   }
534   v8::internal::CompilationCache::Clear();
535   v8::internal::Heap::CollectAllGarbage(false);
536   CHECK_EQ(1, TestAsciiResource::dispose_count);
537 }
538 
539 
THREADED_TEST(UsingExternalString)540 THREADED_TEST(UsingExternalString) {
541   {
542     v8::HandleScope scope;
543     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
544     Local<String> string =
545         String::NewExternal(new TestResource(two_byte_string));
546     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
547     // Trigger GCs so that the newly allocated string moves to old gen.
548     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
549     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
550     i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
551     CHECK(isymbol->IsSymbol());
552   }
553   i::Heap::CollectAllGarbage(false);
554   i::Heap::CollectAllGarbage(false);
555 }
556 
557 
THREADED_TEST(UsingExternalAsciiString)558 THREADED_TEST(UsingExternalAsciiString) {
559   {
560     v8::HandleScope scope;
561     const char* one_byte_string = "test string";
562     Local<String> string = String::NewExternal(
563         new TestAsciiResource(i::StrDup(one_byte_string)));
564     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
565     // Trigger GCs so that the newly allocated string moves to old gen.
566     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in survivor space now
567     i::Heap::CollectGarbage(0, i::NEW_SPACE);  // in old gen now
568     i::Handle<i::String> isymbol = i::Factory::SymbolFromString(istring);
569     CHECK(isymbol->IsSymbol());
570   }
571   i::Heap::CollectAllGarbage(false);
572   i::Heap::CollectAllGarbage(false);
573 }
574 
575 
THREADED_TEST(GlobalProperties)576 THREADED_TEST(GlobalProperties) {
577   v8::HandleScope scope;
578   LocalContext env;
579   v8::Handle<v8::Object> global = env->Global();
580   global->Set(v8_str("pi"), v8_num(3.1415926));
581   Local<Value> pi = global->Get(v8_str("pi"));
582   CHECK_EQ(3.1415926, pi->NumberValue());
583 }
584 
585 
handle_call(const v8::Arguments & args)586 static v8::Handle<Value> handle_call(const v8::Arguments& args) {
587   ApiTestFuzzer::Fuzz();
588   return v8_num(102);
589 }
590 
591 
construct_call(const v8::Arguments & args)592 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
593   ApiTestFuzzer::Fuzz();
594   args.This()->Set(v8_str("x"), v8_num(1));
595   args.This()->Set(v8_str("y"), v8_num(2));
596   return args.This();
597 }
598 
THREADED_TEST(FunctionTemplate)599 THREADED_TEST(FunctionTemplate) {
600   v8::HandleScope scope;
601   LocalContext env;
602   {
603     Local<v8::FunctionTemplate> fun_templ =
604         v8::FunctionTemplate::New(handle_call);
605     Local<Function> fun = fun_templ->GetFunction();
606     env->Global()->Set(v8_str("obj"), fun);
607     Local<Script> script = v8_compile("obj()");
608     CHECK_EQ(102, script->Run()->Int32Value());
609   }
610   // Use SetCallHandler to initialize a function template, should work like the
611   // previous one.
612   {
613     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
614     fun_templ->SetCallHandler(handle_call);
615     Local<Function> fun = fun_templ->GetFunction();
616     env->Global()->Set(v8_str("obj"), fun);
617     Local<Script> script = v8_compile("obj()");
618     CHECK_EQ(102, script->Run()->Int32Value());
619   }
620   // Test constructor calls.
621   {
622     Local<v8::FunctionTemplate> fun_templ =
623         v8::FunctionTemplate::New(construct_call);
624     fun_templ->SetClassName(v8_str("funky"));
625     Local<Function> fun = fun_templ->GetFunction();
626     env->Global()->Set(v8_str("obj"), fun);
627     Local<Script> script = v8_compile("var s = new obj(); s.x");
628     CHECK_EQ(1, script->Run()->Int32Value());
629 
630     Local<Value> result = v8_compile("(new obj()).toString()")->Run();
631     CHECK_EQ(v8_str("[object funky]"), result);
632   }
633 }
634 
635 
THREADED_TEST(FindInstanceInPrototypeChain)636 THREADED_TEST(FindInstanceInPrototypeChain) {
637   v8::HandleScope scope;
638   LocalContext env;
639 
640   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
641   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
642   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
643   derived->Inherit(base);
644 
645   Local<v8::Function> base_function = base->GetFunction();
646   Local<v8::Function> derived_function = derived->GetFunction();
647   Local<v8::Function> other_function = other->GetFunction();
648 
649   Local<v8::Object> base_instance = base_function->NewInstance();
650   Local<v8::Object> derived_instance = derived_function->NewInstance();
651   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
652   Local<v8::Object> other_instance = other_function->NewInstance();
653   derived_instance2->Set(v8_str("__proto__"), derived_instance);
654   other_instance->Set(v8_str("__proto__"), derived_instance2);
655 
656   // base_instance is only an instance of base.
657   CHECK_EQ(base_instance,
658            base_instance->FindInstanceInPrototypeChain(base));
659   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
660   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
661 
662   // derived_instance is an instance of base and derived.
663   CHECK_EQ(derived_instance,
664            derived_instance->FindInstanceInPrototypeChain(base));
665   CHECK_EQ(derived_instance,
666            derived_instance->FindInstanceInPrototypeChain(derived));
667   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
668 
669   // other_instance is an instance of other and its immediate
670   // prototype derived_instance2 is an instance of base and derived.
671   // Note, derived_instance is an instance of base and derived too,
672   // but it comes after derived_instance2 in the prototype chain of
673   // other_instance.
674   CHECK_EQ(derived_instance2,
675            other_instance->FindInstanceInPrototypeChain(base));
676   CHECK_EQ(derived_instance2,
677            other_instance->FindInstanceInPrototypeChain(derived));
678   CHECK_EQ(other_instance,
679            other_instance->FindInstanceInPrototypeChain(other));
680 }
681 
682 
handle_property(Local<String> name,const AccessorInfo &)683 static v8::Handle<Value> handle_property(Local<String> name,
684                                          const AccessorInfo&) {
685   ApiTestFuzzer::Fuzz();
686   return v8_num(900);
687 }
688 
689 
THREADED_TEST(PropertyHandler)690 THREADED_TEST(PropertyHandler) {
691   v8::HandleScope scope;
692   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
693   fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
694   LocalContext env;
695   Local<Function> fun = fun_templ->GetFunction();
696   env->Global()->Set(v8_str("Fun"), fun);
697   Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
698   CHECK_EQ(900, getter->Run()->Int32Value());
699   Local<Script> setter = v8_compile("obj.foo = 901;");
700   CHECK_EQ(901, setter->Run()->Int32Value());
701 }
702 
703 
THREADED_TEST(Number)704 THREADED_TEST(Number) {
705   v8::HandleScope scope;
706   LocalContext env;
707   double PI = 3.1415926;
708   Local<v8::Number> pi_obj = v8::Number::New(PI);
709   CHECK_EQ(PI, pi_obj->NumberValue());
710 }
711 
712 
THREADED_TEST(ToNumber)713 THREADED_TEST(ToNumber) {
714   v8::HandleScope scope;
715   LocalContext env;
716   Local<String> str = v8_str("3.1415926");
717   CHECK_EQ(3.1415926, str->NumberValue());
718   v8::Handle<v8::Boolean> t = v8::True();
719   CHECK_EQ(1.0, t->NumberValue());
720   v8::Handle<v8::Boolean> f = v8::False();
721   CHECK_EQ(0.0, f->NumberValue());
722 }
723 
724 
THREADED_TEST(Date)725 THREADED_TEST(Date) {
726   v8::HandleScope scope;
727   LocalContext env;
728   double PI = 3.1415926;
729   Local<Value> date_obj = v8::Date::New(PI);
730   CHECK_EQ(3.0, date_obj->NumberValue());
731 }
732 
733 
THREADED_TEST(Boolean)734 THREADED_TEST(Boolean) {
735   v8::HandleScope scope;
736   LocalContext env;
737   v8::Handle<v8::Boolean> t = v8::True();
738   CHECK(t->Value());
739   v8::Handle<v8::Boolean> f = v8::False();
740   CHECK(!f->Value());
741   v8::Handle<v8::Primitive> u = v8::Undefined();
742   CHECK(!u->BooleanValue());
743   v8::Handle<v8::Primitive> n = v8::Null();
744   CHECK(!n->BooleanValue());
745   v8::Handle<String> str1 = v8_str("");
746   CHECK(!str1->BooleanValue());
747   v8::Handle<String> str2 = v8_str("x");
748   CHECK(str2->BooleanValue());
749   CHECK(!v8::Number::New(0)->BooleanValue());
750   CHECK(v8::Number::New(-1)->BooleanValue());
751   CHECK(v8::Number::New(1)->BooleanValue());
752   CHECK(v8::Number::New(42)->BooleanValue());
753   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
754 }
755 
756 
DummyCallHandler(const v8::Arguments & args)757 static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) {
758   ApiTestFuzzer::Fuzz();
759   return v8_num(13.4);
760 }
761 
762 
GetM(Local<String> name,const AccessorInfo &)763 static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) {
764   ApiTestFuzzer::Fuzz();
765   return v8_num(876);
766 }
767 
768 
THREADED_TEST(GlobalPrototype)769 THREADED_TEST(GlobalPrototype) {
770   v8::HandleScope scope;
771   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
772   func_templ->PrototypeTemplate()->Set(
773       "dummy",
774       v8::FunctionTemplate::New(DummyCallHandler));
775   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
776   templ->Set("x", v8_num(200));
777   templ->SetAccessor(v8_str("m"), GetM);
778   LocalContext env(0, templ);
779   v8::Handle<v8::Object> obj = env->Global();
780   v8::Handle<Script> script = v8_compile("dummy()");
781   v8::Handle<Value> result = script->Run();
782   CHECK_EQ(13.4, result->NumberValue());
783   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
784   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
785 }
786 
787 
GetIntValue(Local<String> property,const AccessorInfo & info)788 static v8::Handle<Value> GetIntValue(Local<String> property,
789                                      const AccessorInfo& info) {
790   ApiTestFuzzer::Fuzz();
791   int* value =
792       static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
793   return v8_num(*value);
794 }
795 
SetIntValue(Local<String> property,Local<Value> value,const AccessorInfo & info)796 static void SetIntValue(Local<String> property,
797                         Local<Value> value,
798                         const AccessorInfo& info) {
799   int* field =
800       static_cast<int*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
801   *field = value->Int32Value();
802 }
803 
804 int foo, bar, baz;
805 
THREADED_TEST(GlobalVariableAccess)806 THREADED_TEST(GlobalVariableAccess) {
807   foo = 0;
808   bar = -4;
809   baz = 10;
810   v8::HandleScope scope;
811   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
812   templ->InstanceTemplate()->SetAccessor(v8_str("foo"),
813                                          GetIntValue,
814                                          SetIntValue,
815                                          v8::External::New(&foo));
816   templ->InstanceTemplate()->SetAccessor(v8_str("bar"),
817                                          GetIntValue,
818                                          SetIntValue,
819                                          v8::External::New(&bar));
820   templ->InstanceTemplate()->SetAccessor(v8_str("baz"),
821                                          GetIntValue,
822                                          SetIntValue,
823                                          v8::External::New(&baz));
824   LocalContext env(0, templ->InstanceTemplate());
825   v8_compile("foo = (++bar) + baz")->Run();
826   CHECK_EQ(bar, -3);
827   CHECK_EQ(foo, 7);
828 }
829 
830 
THREADED_TEST(ObjectTemplate)831 THREADED_TEST(ObjectTemplate) {
832   v8::HandleScope scope;
833   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
834   templ1->Set("x", v8_num(10));
835   templ1->Set("y", v8_num(13));
836   LocalContext env;
837   Local<v8::Object> instance1 = templ1->NewInstance();
838   env->Global()->Set(v8_str("p"), instance1);
839   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
840   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
841   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
842   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
843   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
844   templ2->Set("a", v8_num(12));
845   templ2->Set("b", templ1);
846   Local<v8::Object> instance2 = templ2->NewInstance();
847   env->Global()->Set(v8_str("q"), instance2);
848   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
849   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
850   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
851   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
852 }
853 
854 
GetFlabby(const v8::Arguments & args)855 static v8::Handle<Value> GetFlabby(const v8::Arguments& args) {
856   ApiTestFuzzer::Fuzz();
857   return v8_num(17.2);
858 }
859 
860 
GetKnurd(Local<String> property,const AccessorInfo &)861 static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) {
862   ApiTestFuzzer::Fuzz();
863   return v8_num(15.2);
864 }
865 
866 
THREADED_TEST(DescriptorInheritance)867 THREADED_TEST(DescriptorInheritance) {
868   v8::HandleScope scope;
869   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
870   super->PrototypeTemplate()->Set("flabby",
871                                   v8::FunctionTemplate::New(GetFlabby));
872   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
873 
874   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
875 
876   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
877   base1->Inherit(super);
878   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
879 
880   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
881   base2->Inherit(super);
882   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
883 
884   LocalContext env;
885 
886   env->Global()->Set(v8_str("s"), super->GetFunction());
887   env->Global()->Set(v8_str("base1"), base1->GetFunction());
888   env->Global()->Set(v8_str("base2"), base2->GetFunction());
889 
890   // Checks right __proto__ chain.
891   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
892   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
893 
894   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
895 
896   // Instance accessor should not be visible on function object or its prototype
897   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
898   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
899   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
900 
901   env->Global()->Set(v8_str("obj"),
902                      base1->GetFunction()->NewInstance());
903   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
904   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
905   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
906   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
907   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
908 
909   env->Global()->Set(v8_str("obj2"),
910                      base2->GetFunction()->NewInstance());
911   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
912   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
913   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
914   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
915   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
916 
917   // base1 and base2 cannot cross reference to each's prototype
918   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
919   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
920 }
921 
922 
923 int echo_named_call_count;
924 
925 
EchoNamedProperty(Local<String> name,const AccessorInfo & info)926 static v8::Handle<Value> EchoNamedProperty(Local<String> name,
927                                            const AccessorInfo& info) {
928   ApiTestFuzzer::Fuzz();
929   CHECK_EQ(v8_str("data"), info.Data());
930   echo_named_call_count++;
931   return name;
932 }
933 
934 
THREADED_TEST(NamedPropertyHandlerGetter)935 THREADED_TEST(NamedPropertyHandlerGetter) {
936   echo_named_call_count = 0;
937   v8::HandleScope scope;
938   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
939   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
940                                                      0, 0, 0, 0,
941                                                      v8_str("data"));
942   LocalContext env;
943   env->Global()->Set(v8_str("obj"),
944                      templ->GetFunction()->NewInstance());
945   CHECK_EQ(echo_named_call_count, 0);
946   v8_compile("obj.x")->Run();
947   CHECK_EQ(echo_named_call_count, 1);
948   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
949   v8::Handle<Value> str = CompileRun(code);
950   String::AsciiValue value(str);
951   CHECK_EQ(*value, "oddlepoddle");
952   // Check default behavior
953   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
954   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
955   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
956 }
957 
958 
959 int echo_indexed_call_count = 0;
960 
961 
EchoIndexedProperty(uint32_t index,const AccessorInfo & info)962 static v8::Handle<Value> EchoIndexedProperty(uint32_t index,
963                                              const AccessorInfo& info) {
964   ApiTestFuzzer::Fuzz();
965   CHECK_EQ(v8_num(637), info.Data());
966   echo_indexed_call_count++;
967   return v8_num(index);
968 }
969 
970 
THREADED_TEST(IndexedPropertyHandlerGetter)971 THREADED_TEST(IndexedPropertyHandlerGetter) {
972   v8::HandleScope scope;
973   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
974   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
975                                                        0, 0, 0, 0,
976                                                        v8_num(637));
977   LocalContext env;
978   env->Global()->Set(v8_str("obj"),
979                      templ->GetFunction()->NewInstance());
980   Local<Script> script = v8_compile("obj[900]");
981   CHECK_EQ(script->Run()->Int32Value(), 900);
982 }
983 
984 
985 v8::Handle<v8::Object> bottom;
986 
CheckThisIndexedPropertyHandler(uint32_t index,const AccessorInfo & info)987 static v8::Handle<Value> CheckThisIndexedPropertyHandler(
988     uint32_t index,
989     const AccessorInfo& info) {
990   ApiTestFuzzer::Fuzz();
991   CHECK(info.This()->Equals(bottom));
992   return v8::Handle<Value>();
993 }
994 
CheckThisNamedPropertyHandler(Local<String> name,const AccessorInfo & info)995 static v8::Handle<Value> CheckThisNamedPropertyHandler(
996     Local<String> name,
997     const AccessorInfo& info) {
998   ApiTestFuzzer::Fuzz();
999   CHECK(info.This()->Equals(bottom));
1000   return v8::Handle<Value>();
1001 }
1002 
1003 
CheckThisIndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)1004 v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index,
1005                                                  Local<Value> value,
1006                                                  const AccessorInfo& info) {
1007   ApiTestFuzzer::Fuzz();
1008   CHECK(info.This()->Equals(bottom));
1009   return v8::Handle<Value>();
1010 }
1011 
1012 
CheckThisNamedPropertySetter(Local<String> property,Local<Value> value,const AccessorInfo & info)1013 v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property,
1014                                                Local<Value> value,
1015                                                const AccessorInfo& info) {
1016   ApiTestFuzzer::Fuzz();
1017   CHECK(info.This()->Equals(bottom));
1018   return v8::Handle<Value>();
1019 }
1020 
CheckThisIndexedPropertyQuery(uint32_t index,const AccessorInfo & info)1021 v8::Handle<v8::Boolean> CheckThisIndexedPropertyQuery(
1022     uint32_t index,
1023     const AccessorInfo& info) {
1024   ApiTestFuzzer::Fuzz();
1025   CHECK(info.This()->Equals(bottom));
1026   return v8::Handle<v8::Boolean>();
1027 }
1028 
1029 
CheckThisNamedPropertyQuery(Local<String> property,const AccessorInfo & info)1030 v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
1031                                                     const AccessorInfo& info) {
1032   ApiTestFuzzer::Fuzz();
1033   CHECK(info.This()->Equals(bottom));
1034   return v8::Handle<v8::Boolean>();
1035 }
1036 
1037 
CheckThisIndexedPropertyDeleter(uint32_t index,const AccessorInfo & info)1038 v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter(
1039     uint32_t index,
1040     const AccessorInfo& info) {
1041   ApiTestFuzzer::Fuzz();
1042   CHECK(info.This()->Equals(bottom));
1043   return v8::Handle<v8::Boolean>();
1044 }
1045 
1046 
CheckThisNamedPropertyDeleter(Local<String> property,const AccessorInfo & info)1047 v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter(
1048     Local<String> property,
1049     const AccessorInfo& info) {
1050   ApiTestFuzzer::Fuzz();
1051   CHECK(info.This()->Equals(bottom));
1052   return v8::Handle<v8::Boolean>();
1053 }
1054 
1055 
CheckThisIndexedPropertyEnumerator(const AccessorInfo & info)1056 v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator(
1057     const AccessorInfo& info) {
1058   ApiTestFuzzer::Fuzz();
1059   CHECK(info.This()->Equals(bottom));
1060   return v8::Handle<v8::Array>();
1061 }
1062 
1063 
CheckThisNamedPropertyEnumerator(const AccessorInfo & info)1064 v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator(
1065     const AccessorInfo& info) {
1066   ApiTestFuzzer::Fuzz();
1067   CHECK(info.This()->Equals(bottom));
1068   return v8::Handle<v8::Array>();
1069 }
1070 
1071 
THREADED_TEST(PropertyHandlerInPrototype)1072 THREADED_TEST(PropertyHandlerInPrototype) {
1073   v8::HandleScope scope;
1074   LocalContext env;
1075 
1076   // Set up a prototype chain with three interceptors.
1077   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1078   templ->InstanceTemplate()->SetIndexedPropertyHandler(
1079       CheckThisIndexedPropertyHandler,
1080       CheckThisIndexedPropertySetter,
1081       CheckThisIndexedPropertyQuery,
1082       CheckThisIndexedPropertyDeleter,
1083       CheckThisIndexedPropertyEnumerator);
1084 
1085   templ->InstanceTemplate()->SetNamedPropertyHandler(
1086       CheckThisNamedPropertyHandler,
1087       CheckThisNamedPropertySetter,
1088       CheckThisNamedPropertyQuery,
1089       CheckThisNamedPropertyDeleter,
1090       CheckThisNamedPropertyEnumerator);
1091 
1092   bottom = templ->GetFunction()->NewInstance();
1093   Local<v8::Object> top = templ->GetFunction()->NewInstance();
1094   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
1095 
1096   bottom->Set(v8_str("__proto__"), middle);
1097   middle->Set(v8_str("__proto__"), top);
1098   env->Global()->Set(v8_str("obj"), bottom);
1099 
1100   // Indexed and named get.
1101   Script::Compile(v8_str("obj[0]"))->Run();
1102   Script::Compile(v8_str("obj.x"))->Run();
1103 
1104   // Indexed and named set.
1105   Script::Compile(v8_str("obj[1] = 42"))->Run();
1106   Script::Compile(v8_str("obj.y = 42"))->Run();
1107 
1108   // Indexed and named query.
1109   Script::Compile(v8_str("0 in obj"))->Run();
1110   Script::Compile(v8_str("'x' in obj"))->Run();
1111 
1112   // Indexed and named deleter.
1113   Script::Compile(v8_str("delete obj[0]"))->Run();
1114   Script::Compile(v8_str("delete obj.x"))->Run();
1115 
1116   // Enumerators.
1117   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
1118 }
1119 
1120 
PrePropertyHandlerGet(Local<String> key,const AccessorInfo & info)1121 static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key,
1122                                                const AccessorInfo& info) {
1123   ApiTestFuzzer::Fuzz();
1124   if (v8_str("pre")->Equals(key)) {
1125     return v8_str("PrePropertyHandler: pre");
1126   }
1127   return v8::Handle<String>();
1128 }
1129 
1130 
PrePropertyHandlerHas(Local<String> key,const AccessorInfo &)1131 static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
1132                                                      const AccessorInfo&) {
1133   if (v8_str("pre")->Equals(key)) {
1134     return v8::True();
1135   }
1136 
1137   return v8::Handle<v8::Boolean>();  // do not intercept the call
1138 }
1139 
1140 
THREADED_TEST(PrePropertyHandler)1141 THREADED_TEST(PrePropertyHandler) {
1142   v8::HandleScope scope;
1143   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
1144   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
1145                                                     0,
1146                                                     PrePropertyHandlerHas);
1147   LocalContext env(NULL, desc->InstanceTemplate());
1148   Script::Compile(v8_str(
1149       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
1150   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
1151   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
1152   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
1153   CHECK_EQ(v8_str("Object: on"), result_on);
1154   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
1155   CHECK(result_post.IsEmpty());
1156 }
1157 
1158 
THREADED_TEST(UndefinedIsNotEnumerable)1159 THREADED_TEST(UndefinedIsNotEnumerable) {
1160   v8::HandleScope scope;
1161   LocalContext env;
1162   v8::Handle<Value> result = Script::Compile(v8_str(
1163       "this.propertyIsEnumerable(undefined)"))->Run();
1164   CHECK(result->IsFalse());
1165 }
1166 
1167 
1168 v8::Handle<Script> call_recursively_script;
1169 static const int kTargetRecursionDepth = 300;  // near maximum
1170 
1171 
CallScriptRecursivelyCall(const v8::Arguments & args)1172 static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) {
1173   ApiTestFuzzer::Fuzz();
1174   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1175   if (depth == kTargetRecursionDepth) return v8::Undefined();
1176   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1177   return call_recursively_script->Run();
1178 }
1179 
1180 
CallFunctionRecursivelyCall(const v8::Arguments & args)1181 static v8::Handle<Value> CallFunctionRecursivelyCall(
1182     const v8::Arguments& args) {
1183   ApiTestFuzzer::Fuzz();
1184   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1185   if (depth == kTargetRecursionDepth) {
1186     printf("[depth = %d]\n", depth);
1187     return v8::Undefined();
1188   }
1189   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
1190   v8::Handle<Value> function =
1191       args.This()->Get(v8_str("callFunctionRecursively"));
1192   return v8::Handle<Function>::Cast(function)->Call(args.This(), 0, NULL);
1193 }
1194 
1195 
THREADED_TEST(DeepCrossLanguageRecursion)1196 THREADED_TEST(DeepCrossLanguageRecursion) {
1197   v8::HandleScope scope;
1198   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
1199   global->Set(v8_str("callScriptRecursively"),
1200               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
1201   global->Set(v8_str("callFunctionRecursively"),
1202               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
1203   LocalContext env(NULL, global);
1204 
1205   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1206   call_recursively_script = v8_compile("callScriptRecursively()");
1207   v8::Handle<Value> result = call_recursively_script->Run();
1208   call_recursively_script = v8::Handle<Script>();
1209 
1210   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
1211   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
1212 }
1213 
1214 
1215 static v8::Handle<Value>
ThrowingPropertyHandlerGet(Local<String> key,const AccessorInfo &)1216     ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) {
1217   ApiTestFuzzer::Fuzz();
1218   return v8::ThrowException(key);
1219 }
1220 
1221 
ThrowingPropertyHandlerSet(Local<String> key,Local<Value>,const AccessorInfo &)1222 static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key,
1223                                                     Local<Value>,
1224                                                     const AccessorInfo&) {
1225   v8::ThrowException(key);
1226   return v8::Undefined();  // not the same as v8::Handle<v8::Value>()
1227 }
1228 
1229 
THREADED_TEST(CallbackExceptionRegression)1230 THREADED_TEST(CallbackExceptionRegression) {
1231   v8::HandleScope scope;
1232   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1233   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
1234                                ThrowingPropertyHandlerSet);
1235   LocalContext env;
1236   env->Global()->Set(v8_str("obj"), obj->NewInstance());
1237   v8::Handle<Value> otto = Script::Compile(v8_str(
1238       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
1239   CHECK_EQ(v8_str("otto"), otto);
1240   v8::Handle<Value> netto = Script::Compile(v8_str(
1241       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
1242   CHECK_EQ(v8_str("netto"), netto);
1243 }
1244 
1245 
ThrowingGetAccessor(Local<String> name,const AccessorInfo & info)1246 static v8::Handle<Value> ThrowingGetAccessor(Local<String> name,
1247                                              const AccessorInfo& info) {
1248   ApiTestFuzzer::Fuzz();
1249   return v8::ThrowException(v8_str("g"));
1250 }
1251 
1252 
ThrowingSetAccessor(Local<String> name,Local<Value> value,const AccessorInfo & info)1253 static void ThrowingSetAccessor(Local<String> name,
1254                                 Local<Value> value,
1255                                 const AccessorInfo& info) {
1256   v8::ThrowException(value);
1257 }
1258 
1259 
THREADED_TEST(Regress1054726)1260 THREADED_TEST(Regress1054726) {
1261   v8::HandleScope scope;
1262   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
1263   obj->SetAccessor(v8_str("x"),
1264                    ThrowingGetAccessor,
1265                    ThrowingSetAccessor,
1266                    Local<Value>());
1267 
1268   LocalContext env;
1269   env->Global()->Set(v8_str("obj"), obj->NewInstance());
1270 
1271   // Use the throwing property setter/getter in a loop to force
1272   // the accessor ICs to be initialized.
1273   v8::Handle<Value> result;
1274   result = Script::Compile(v8_str(
1275       "var result = '';"
1276       "for (var i = 0; i < 5; i++) {"
1277       "  try { obj.x; } catch (e) { result += e; }"
1278       "}; result"))->Run();
1279   CHECK_EQ(v8_str("ggggg"), result);
1280 
1281   result = Script::Compile(String::New(
1282       "var result = '';"
1283       "for (var i = 0; i < 5; i++) {"
1284       "  try { obj.x = i; } catch (e) { result += e; }"
1285       "}; result"))->Run();
1286   CHECK_EQ(v8_str("01234"), result);
1287 }
1288 
1289 
THREADED_TEST(FunctionPrototype)1290 THREADED_TEST(FunctionPrototype) {
1291   v8::HandleScope scope;
1292   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
1293   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
1294   LocalContext env;
1295   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
1296   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
1297   CHECK_EQ(script->Run()->Int32Value(), 321);
1298 }
1299 
1300 
THREADED_TEST(InternalFields)1301 THREADED_TEST(InternalFields) {
1302   v8::HandleScope scope;
1303   LocalContext env;
1304 
1305   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1306   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1307   instance_templ->SetInternalFieldCount(1);
1308   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1309   CHECK_EQ(1, obj->InternalFieldCount());
1310   CHECK(obj->GetInternalField(0)->IsUndefined());
1311   obj->SetInternalField(0, v8_num(17));
1312   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
1313 }
1314 
1315 
THREADED_TEST(InternalFieldsNativePointers)1316 THREADED_TEST(InternalFieldsNativePointers) {
1317   v8::HandleScope scope;
1318   LocalContext env;
1319 
1320   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
1321   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
1322   instance_templ->SetInternalFieldCount(1);
1323   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
1324   CHECK_EQ(1, obj->InternalFieldCount());
1325   CHECK(obj->GetPointerFromInternalField(0) == NULL);
1326 
1327   char* data = new char[100];
1328 
1329   void* aligned = data;
1330   CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
1331   void* unaligned = data + 1;
1332   CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
1333 
1334   // Check reading and writing aligned pointers.
1335   obj->SetPointerInInternalField(0, aligned);
1336   i::Heap::CollectAllGarbage(false);
1337   CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
1338 
1339   // Check reading and writing unaligned pointers.
1340   obj->SetPointerInInternalField(0, unaligned);
1341   i::Heap::CollectAllGarbage(false);
1342   CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
1343 
1344   delete[] data;
1345 }
1346 
1347 
THREADED_TEST(IdentityHash)1348 THREADED_TEST(IdentityHash) {
1349   v8::HandleScope scope;
1350   LocalContext env;
1351 
1352   // Ensure that the test starts with an fresh heap to test whether the hash
1353   // code is based on the address.
1354   i::Heap::CollectAllGarbage(false);
1355   Local<v8::Object> obj = v8::Object::New();
1356   int hash = obj->GetIdentityHash();
1357   int hash1 = obj->GetIdentityHash();
1358   CHECK_EQ(hash, hash1);
1359   int hash2 = v8::Object::New()->GetIdentityHash();
1360   // Since the identity hash is essentially a random number two consecutive
1361   // objects should not be assigned the same hash code. If the test below fails
1362   // the random number generator should be evaluated.
1363   CHECK_NE(hash, hash2);
1364   i::Heap::CollectAllGarbage(false);
1365   int hash3 = v8::Object::New()->GetIdentityHash();
1366   // Make sure that the identity hash is not based on the initial address of
1367   // the object alone. If the test below fails the random number generator
1368   // should be evaluated.
1369   CHECK_NE(hash, hash3);
1370   int hash4 = obj->GetIdentityHash();
1371   CHECK_EQ(hash, hash4);
1372 }
1373 
1374 
THREADED_TEST(HiddenProperties)1375 THREADED_TEST(HiddenProperties) {
1376   v8::HandleScope scope;
1377   LocalContext env;
1378 
1379   v8::Local<v8::Object> obj = v8::Object::New();
1380   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1381   v8::Local<v8::String> empty = v8_str("");
1382   v8::Local<v8::String> prop_name = v8_str("prop_name");
1383 
1384   i::Heap::CollectAllGarbage(false);
1385 
1386   // Make sure delete of a non-existent hidden value works
1387   CHECK(obj->DeleteHiddenValue(key));
1388 
1389   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
1390   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
1391   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
1392   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1393 
1394   i::Heap::CollectAllGarbage(false);
1395 
1396   // Make sure we do not find the hidden property.
1397   CHECK(!obj->Has(empty));
1398   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1399   CHECK(obj->Get(empty)->IsUndefined());
1400   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1401   CHECK(obj->Set(empty, v8::Integer::New(2003)));
1402   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1403   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
1404 
1405   i::Heap::CollectAllGarbage(false);
1406 
1407   // Add another property and delete it afterwards to force the object in
1408   // slow case.
1409   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
1410   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1411   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
1412   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1413   CHECK(obj->Delete(prop_name));
1414   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
1415 
1416   i::Heap::CollectAllGarbage(false);
1417 
1418   CHECK(obj->DeleteHiddenValue(key));
1419   CHECK(obj->GetHiddenValue(key).IsEmpty());
1420 }
1421 
1422 
InterceptorForHiddenProperties(Local<String> name,const AccessorInfo & info)1423 static v8::Handle<Value> InterceptorForHiddenProperties(
1424     Local<String> name, const AccessorInfo& info) {
1425   // Make sure objects move.
1426   bool saved_always_compact = i::FLAG_always_compact;
1427   if (!i::FLAG_never_compact) {
1428     i::FLAG_always_compact = true;
1429   }
1430   // The whole goal of this interceptor is to cause a GC during local property
1431   // lookup.
1432   i::Heap::CollectAllGarbage(false);
1433   i::FLAG_always_compact = saved_always_compact;
1434   return v8::Handle<Value>();
1435 }
1436 
1437 
THREADED_TEST(HiddenPropertiesWithInterceptors)1438 THREADED_TEST(HiddenPropertiesWithInterceptors) {
1439   v8::HandleScope scope;
1440   LocalContext context;
1441 
1442   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
1443 
1444   // Associate an interceptor with an object and start setting hidden values.
1445   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1446   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
1447   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
1448   Local<v8::Function> function = fun_templ->GetFunction();
1449   Local<v8::Object> obj = function->NewInstance();
1450   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
1451   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
1452 }
1453 
1454 
THREADED_TEST(External)1455 THREADED_TEST(External) {
1456   v8::HandleScope scope;
1457   int x = 3;
1458   Local<v8::External> ext = v8::External::New(&x);
1459   LocalContext env;
1460   env->Global()->Set(v8_str("ext"), ext);
1461   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
1462   v8::Handle<v8::External> reext = v8::Handle<v8::External>::Cast(reext_obj);
1463   int* ptr = static_cast<int*>(reext->Value());
1464   CHECK_EQ(x, 3);
1465   *ptr = 10;
1466   CHECK_EQ(x, 10);
1467 
1468   // Make sure unaligned pointers are wrapped properly.
1469   char* data = i::StrDup("0123456789");
1470   Local<v8::Value> zero = v8::External::Wrap(&data[0]);
1471   Local<v8::Value> one = v8::External::Wrap(&data[1]);
1472   Local<v8::Value> two = v8::External::Wrap(&data[2]);
1473   Local<v8::Value> three = v8::External::Wrap(&data[3]);
1474 
1475   char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero));
1476   CHECK_EQ('0', *char_ptr);
1477   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one));
1478   CHECK_EQ('1', *char_ptr);
1479   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two));
1480   CHECK_EQ('2', *char_ptr);
1481   char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three));
1482   CHECK_EQ('3', *char_ptr);
1483   i::DeleteArray(data);
1484 }
1485 
1486 
THREADED_TEST(GlobalHandle)1487 THREADED_TEST(GlobalHandle) {
1488   v8::Persistent<String> global;
1489   {
1490     v8::HandleScope scope;
1491     Local<String> str = v8_str("str");
1492     global = v8::Persistent<String>::New(str);
1493   }
1494   CHECK_EQ(global->Length(), 3);
1495   global.Dispose();
1496 }
1497 
1498 
THREADED_TEST(ScriptException)1499 THREADED_TEST(ScriptException) {
1500   v8::HandleScope scope;
1501   LocalContext env;
1502   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
1503   v8::TryCatch try_catch;
1504   Local<Value> result = script->Run();
1505   CHECK(result.IsEmpty());
1506   CHECK(try_catch.HasCaught());
1507   String::AsciiValue exception_value(try_catch.Exception());
1508   CHECK_EQ(*exception_value, "panama!");
1509 }
1510 
1511 
1512 bool message_received;
1513 
1514 
check_message(v8::Handle<v8::Message> message,v8::Handle<Value> data)1515 static void check_message(v8::Handle<v8::Message> message,
1516                           v8::Handle<Value> data) {
1517   CHECK_EQ(5.76, data->NumberValue());
1518   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
1519   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
1520   message_received = true;
1521 }
1522 
1523 
THREADED_TEST(MessageHandlerData)1524 THREADED_TEST(MessageHandlerData) {
1525   message_received = false;
1526   v8::HandleScope scope;
1527   CHECK(!message_received);
1528   v8::V8::AddMessageListener(check_message, v8_num(5.76));
1529   LocalContext context;
1530   v8::ScriptOrigin origin =
1531       v8::ScriptOrigin(v8_str("6.75"));
1532   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
1533                                                   &origin);
1534   script->SetData(v8_str("7.56"));
1535   script->Run();
1536   CHECK(message_received);
1537   // clear out the message listener
1538   v8::V8::RemoveMessageListeners(check_message);
1539 }
1540 
1541 
THREADED_TEST(GetSetProperty)1542 THREADED_TEST(GetSetProperty) {
1543   v8::HandleScope scope;
1544   LocalContext context;
1545   context->Global()->Set(v8_str("foo"), v8_num(14));
1546   context->Global()->Set(v8_str("12"), v8_num(92));
1547   context->Global()->Set(v8::Integer::New(16), v8_num(32));
1548   context->Global()->Set(v8_num(13), v8_num(56));
1549   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
1550   CHECK_EQ(14, foo->Int32Value());
1551   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
1552   CHECK_EQ(92, twelve->Int32Value());
1553   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
1554   CHECK_EQ(32, sixteen->Int32Value());
1555   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
1556   CHECK_EQ(56, thirteen->Int32Value());
1557   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
1558   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
1559   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
1560   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
1561   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
1562   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
1563   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
1564   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
1565   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
1566 }
1567 
1568 
THREADED_TEST(PropertyAttributes)1569 THREADED_TEST(PropertyAttributes) {
1570   v8::HandleScope scope;
1571   LocalContext context;
1572   // read-only
1573   Local<String> prop = v8_str("read_only");
1574   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
1575   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1576   Script::Compile(v8_str("read_only = 9"))->Run();
1577   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1578   context->Global()->Set(prop, v8_num(10));
1579   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
1580   // dont-delete
1581   prop = v8_str("dont_delete");
1582   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
1583   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1584   Script::Compile(v8_str("delete dont_delete"))->Run();
1585   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
1586 }
1587 
1588 
THREADED_TEST(Array)1589 THREADED_TEST(Array) {
1590   v8::HandleScope scope;
1591   LocalContext context;
1592   Local<v8::Array> array = v8::Array::New();
1593   CHECK_EQ(0, array->Length());
1594   CHECK(array->Get(v8::Integer::New(0))->IsUndefined());
1595   CHECK(!array->Has(0));
1596   CHECK(array->Get(v8::Integer::New(100))->IsUndefined());
1597   CHECK(!array->Has(100));
1598   array->Set(v8::Integer::New(2), v8_num(7));
1599   CHECK_EQ(3, array->Length());
1600   CHECK(!array->Has(0));
1601   CHECK(!array->Has(1));
1602   CHECK(array->Has(2));
1603   CHECK_EQ(7, array->Get(v8::Integer::New(2))->Int32Value());
1604   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
1605   Local<v8::Array> arr = Local<v8::Array>::Cast(obj);
1606   CHECK_EQ(3, arr->Length());
1607   CHECK_EQ(1, arr->Get(v8::Integer::New(0))->Int32Value());
1608   CHECK_EQ(2, arr->Get(v8::Integer::New(1))->Int32Value());
1609   CHECK_EQ(3, arr->Get(v8::Integer::New(2))->Int32Value());
1610 }
1611 
1612 
HandleF(const v8::Arguments & args)1613 v8::Handle<Value> HandleF(const v8::Arguments& args) {
1614   v8::HandleScope scope;
1615   ApiTestFuzzer::Fuzz();
1616   Local<v8::Array> result = v8::Array::New(args.Length());
1617   for (int i = 0; i < args.Length(); i++)
1618     result->Set(v8::Integer::New(i), args[i]);
1619   return scope.Close(result);
1620 }
1621 
1622 
THREADED_TEST(Vector)1623 THREADED_TEST(Vector) {
1624   v8::HandleScope scope;
1625   Local<ObjectTemplate> global = ObjectTemplate::New();
1626   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
1627   LocalContext context(0, global);
1628 
1629   const char* fun = "f()";
1630   Local<v8::Array> a0 =
1631       Local<v8::Array>::Cast(Script::Compile(String::New(fun))->Run());
1632   CHECK_EQ(0, a0->Length());
1633 
1634   const char* fun2 = "f(11)";
1635   Local<v8::Array> a1 =
1636       Local<v8::Array>::Cast(Script::Compile(String::New(fun2))->Run());
1637   CHECK_EQ(1, a1->Length());
1638   CHECK_EQ(11, a1->Get(v8::Integer::New(0))->Int32Value());
1639 
1640   const char* fun3 = "f(12, 13)";
1641   Local<v8::Array> a2 =
1642       Local<v8::Array>::Cast(Script::Compile(String::New(fun3))->Run());
1643   CHECK_EQ(2, a2->Length());
1644   CHECK_EQ(12, a2->Get(v8::Integer::New(0))->Int32Value());
1645   CHECK_EQ(13, a2->Get(v8::Integer::New(1))->Int32Value());
1646 
1647   const char* fun4 = "f(14, 15, 16)";
1648   Local<v8::Array> a3 =
1649       Local<v8::Array>::Cast(Script::Compile(String::New(fun4))->Run());
1650   CHECK_EQ(3, a3->Length());
1651   CHECK_EQ(14, a3->Get(v8::Integer::New(0))->Int32Value());
1652   CHECK_EQ(15, a3->Get(v8::Integer::New(1))->Int32Value());
1653   CHECK_EQ(16, a3->Get(v8::Integer::New(2))->Int32Value());
1654 
1655   const char* fun5 = "f(17, 18, 19, 20)";
1656   Local<v8::Array> a4 =
1657       Local<v8::Array>::Cast(Script::Compile(String::New(fun5))->Run());
1658   CHECK_EQ(4, a4->Length());
1659   CHECK_EQ(17, a4->Get(v8::Integer::New(0))->Int32Value());
1660   CHECK_EQ(18, a4->Get(v8::Integer::New(1))->Int32Value());
1661   CHECK_EQ(19, a4->Get(v8::Integer::New(2))->Int32Value());
1662   CHECK_EQ(20, a4->Get(v8::Integer::New(3))->Int32Value());
1663 }
1664 
1665 
THREADED_TEST(FunctionCall)1666 THREADED_TEST(FunctionCall) {
1667   v8::HandleScope scope;
1668   LocalContext context;
1669   CompileRun(
1670     "function Foo() {"
1671     "  var result = [];"
1672     "  for (var i = 0; i < arguments.length; i++) {"
1673     "    result.push(arguments[i]);"
1674     "  }"
1675     "  return result;"
1676     "}");
1677   Local<Function> Foo =
1678       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1679 
1680   v8::Handle<Value>* args0 = NULL;
1681   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
1682   CHECK_EQ(0, a0->Length());
1683 
1684   v8::Handle<Value> args1[] = { v8_num(1.1) };
1685   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
1686   CHECK_EQ(1, a1->Length());
1687   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1688 
1689   v8::Handle<Value> args2[] = { v8_num(2.2),
1690                                 v8_num(3.3) };
1691   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
1692   CHECK_EQ(2, a2->Length());
1693   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1694   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1695 
1696   v8::Handle<Value> args3[] = { v8_num(4.4),
1697                                 v8_num(5.5),
1698                                 v8_num(6.6) };
1699   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
1700   CHECK_EQ(3, a3->Length());
1701   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1702   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1703   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1704 
1705   v8::Handle<Value> args4[] = { v8_num(7.7),
1706                                 v8_num(8.8),
1707                                 v8_num(9.9),
1708                                 v8_num(10.11) };
1709   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
1710   CHECK_EQ(4, a4->Length());
1711   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1712   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1713   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1714   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1715 }
1716 
1717 
1718 static const char* js_code_causing_out_of_memory =
1719     "var a = new Array(); while(true) a.push(a);";
1720 
1721 
1722 // These tests run for a long time and prevent us from running tests
1723 // that come after them so they cannot run in parallel.
TEST(OutOfMemory)1724 TEST(OutOfMemory) {
1725   // It's not possible to read a snapshot into a heap with different dimensions.
1726   if (v8::internal::Snapshot::IsEnabled()) return;
1727   // Set heap limits.
1728   static const int K = 1024;
1729   v8::ResourceConstraints constraints;
1730   constraints.set_max_young_space_size(256 * K);
1731   constraints.set_max_old_space_size(4 * K * K);
1732   v8::SetResourceConstraints(&constraints);
1733 
1734   // Execute a script that causes out of memory.
1735   v8::HandleScope scope;
1736   LocalContext context;
1737   v8::V8::IgnoreOutOfMemoryException();
1738   Local<Script> script =
1739       Script::Compile(String::New(js_code_causing_out_of_memory));
1740   Local<Value> result = script->Run();
1741 
1742   // Check for out of memory state.
1743   CHECK(result.IsEmpty());
1744   CHECK(context->HasOutOfMemoryException());
1745 }
1746 
1747 
ProvokeOutOfMemory(const v8::Arguments & args)1748 v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) {
1749   ApiTestFuzzer::Fuzz();
1750 
1751   v8::HandleScope scope;
1752   LocalContext context;
1753   Local<Script> script =
1754       Script::Compile(String::New(js_code_causing_out_of_memory));
1755   Local<Value> result = script->Run();
1756 
1757   // Check for out of memory state.
1758   CHECK(result.IsEmpty());
1759   CHECK(context->HasOutOfMemoryException());
1760 
1761   return result;
1762 }
1763 
1764 
TEST(OutOfMemoryNested)1765 TEST(OutOfMemoryNested) {
1766   // It's not possible to read a snapshot into a heap with different dimensions.
1767   if (v8::internal::Snapshot::IsEnabled()) return;
1768   // Set heap limits.
1769   static const int K = 1024;
1770   v8::ResourceConstraints constraints;
1771   constraints.set_max_young_space_size(256 * K);
1772   constraints.set_max_old_space_size(4 * K * K);
1773   v8::SetResourceConstraints(&constraints);
1774 
1775   v8::HandleScope scope;
1776   Local<ObjectTemplate> templ = ObjectTemplate::New();
1777   templ->Set(v8_str("ProvokeOutOfMemory"),
1778              v8::FunctionTemplate::New(ProvokeOutOfMemory));
1779   LocalContext context(0, templ);
1780   v8::V8::IgnoreOutOfMemoryException();
1781   Local<Value> result = CompileRun(
1782     "var thrown = false;"
1783     "try {"
1784     "  ProvokeOutOfMemory();"
1785     "} catch (e) {"
1786     "  thrown = true;"
1787     "}");
1788   // Check for out of memory state.
1789   CHECK(result.IsEmpty());
1790   CHECK(context->HasOutOfMemoryException());
1791 }
1792 
1793 
TEST(HugeConsStringOutOfMemory)1794 TEST(HugeConsStringOutOfMemory) {
1795   // It's not possible to read a snapshot into a heap with different dimensions.
1796   if (v8::internal::Snapshot::IsEnabled()) return;
1797   v8::HandleScope scope;
1798   LocalContext context;
1799   // Set heap limits.
1800   static const int K = 1024;
1801   v8::ResourceConstraints constraints;
1802   constraints.set_max_young_space_size(256 * K);
1803   constraints.set_max_old_space_size(2 * K * K);
1804   v8::SetResourceConstraints(&constraints);
1805 
1806   // Execute a script that causes out of memory.
1807   v8::V8::IgnoreOutOfMemoryException();
1808 
1809   // Build huge string. This should fail with out of memory exception.
1810   Local<Value> result = CompileRun(
1811     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
1812     "for (var i = 0; i < 21; i++) { str = str + str; }");
1813 
1814   // Check for out of memory state.
1815   CHECK(result.IsEmpty());
1816   CHECK(context->HasOutOfMemoryException());
1817 }
1818 
1819 
THREADED_TEST(ConstructCall)1820 THREADED_TEST(ConstructCall) {
1821   v8::HandleScope scope;
1822   LocalContext context;
1823   CompileRun(
1824     "function Foo() {"
1825     "  var result = [];"
1826     "  for (var i = 0; i < arguments.length; i++) {"
1827     "    result.push(arguments[i]);"
1828     "  }"
1829     "  return result;"
1830     "}");
1831   Local<Function> Foo =
1832       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
1833 
1834   v8::Handle<Value>* args0 = NULL;
1835   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
1836   CHECK_EQ(0, a0->Length());
1837 
1838   v8::Handle<Value> args1[] = { v8_num(1.1) };
1839   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
1840   CHECK_EQ(1, a1->Length());
1841   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
1842 
1843   v8::Handle<Value> args2[] = { v8_num(2.2),
1844                                 v8_num(3.3) };
1845   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
1846   CHECK_EQ(2, a2->Length());
1847   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
1848   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
1849 
1850   v8::Handle<Value> args3[] = { v8_num(4.4),
1851                                 v8_num(5.5),
1852                                 v8_num(6.6) };
1853   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
1854   CHECK_EQ(3, a3->Length());
1855   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
1856   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
1857   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
1858 
1859   v8::Handle<Value> args4[] = { v8_num(7.7),
1860                                 v8_num(8.8),
1861                                 v8_num(9.9),
1862                                 v8_num(10.11) };
1863   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
1864   CHECK_EQ(4, a4->Length());
1865   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
1866   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
1867   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
1868   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
1869 }
1870 
1871 
CheckUncle(v8::TryCatch * try_catch)1872 static void CheckUncle(v8::TryCatch* try_catch) {
1873   CHECK(try_catch->HasCaught());
1874   String::AsciiValue str_value(try_catch->Exception());
1875   CHECK_EQ(*str_value, "uncle?");
1876   try_catch->Reset();
1877 }
1878 
1879 
THREADED_TEST(ConversionException)1880 THREADED_TEST(ConversionException) {
1881   v8::HandleScope scope;
1882   LocalContext env;
1883   CompileRun(
1884     "function TestClass() { };"
1885     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
1886     "var obj = new TestClass();");
1887   Local<Value> obj = env->Global()->Get(v8_str("obj"));
1888 
1889   v8::TryCatch try_catch;
1890 
1891   Local<Value> to_string_result = obj->ToString();
1892   CHECK(to_string_result.IsEmpty());
1893   CheckUncle(&try_catch);
1894 
1895   Local<Value> to_number_result = obj->ToNumber();
1896   CHECK(to_number_result.IsEmpty());
1897   CheckUncle(&try_catch);
1898 
1899   Local<Value> to_integer_result = obj->ToInteger();
1900   CHECK(to_integer_result.IsEmpty());
1901   CheckUncle(&try_catch);
1902 
1903   Local<Value> to_uint32_result = obj->ToUint32();
1904   CHECK(to_uint32_result.IsEmpty());
1905   CheckUncle(&try_catch);
1906 
1907   Local<Value> to_int32_result = obj->ToInt32();
1908   CHECK(to_int32_result.IsEmpty());
1909   CheckUncle(&try_catch);
1910 
1911   Local<Value> to_object_result = v8::Undefined()->ToObject();
1912   CHECK(to_object_result.IsEmpty());
1913   CHECK(try_catch.HasCaught());
1914   try_catch.Reset();
1915 
1916   int32_t int32_value = obj->Int32Value();
1917   CHECK_EQ(0, int32_value);
1918   CheckUncle(&try_catch);
1919 
1920   uint32_t uint32_value = obj->Uint32Value();
1921   CHECK_EQ(0, uint32_value);
1922   CheckUncle(&try_catch);
1923 
1924   double number_value = obj->NumberValue();
1925   CHECK_NE(0, IsNaN(number_value));
1926   CheckUncle(&try_catch);
1927 
1928   int64_t integer_value = obj->IntegerValue();
1929   CHECK_EQ(0.0, static_cast<double>(integer_value));
1930   CheckUncle(&try_catch);
1931 }
1932 
1933 
ThrowFromC(const v8::Arguments & args)1934 v8::Handle<Value> ThrowFromC(const v8::Arguments& args) {
1935   ApiTestFuzzer::Fuzz();
1936   return v8::ThrowException(v8_str("konto"));
1937 }
1938 
1939 
CCatcher(const v8::Arguments & args)1940 v8::Handle<Value> CCatcher(const v8::Arguments& args) {
1941   if (args.Length() < 1) return v8::Boolean::New(false);
1942   v8::HandleScope scope;
1943   v8::TryCatch try_catch;
1944   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
1945   CHECK(!try_catch.HasCaught() || result.IsEmpty());
1946   return v8::Boolean::New(try_catch.HasCaught());
1947 }
1948 
1949 
THREADED_TEST(APICatch)1950 THREADED_TEST(APICatch) {
1951   v8::HandleScope scope;
1952   Local<ObjectTemplate> templ = ObjectTemplate::New();
1953   templ->Set(v8_str("ThrowFromC"),
1954              v8::FunctionTemplate::New(ThrowFromC));
1955   LocalContext context(0, templ);
1956   CompileRun(
1957     "var thrown = false;"
1958     "try {"
1959     "  ThrowFromC();"
1960     "} catch (e) {"
1961     "  thrown = true;"
1962     "}");
1963   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
1964   CHECK(thrown->BooleanValue());
1965 }
1966 
1967 
THREADED_TEST(APIThrowTryCatch)1968 THREADED_TEST(APIThrowTryCatch) {
1969   v8::HandleScope scope;
1970   Local<ObjectTemplate> templ = ObjectTemplate::New();
1971   templ->Set(v8_str("ThrowFromC"),
1972              v8::FunctionTemplate::New(ThrowFromC));
1973   LocalContext context(0, templ);
1974   v8::TryCatch try_catch;
1975   CompileRun("ThrowFromC();");
1976   CHECK(try_catch.HasCaught());
1977 }
1978 
1979 
1980 // Test that a try-finally block doesn't shadow a try-catch block
1981 // when setting up an external handler.
1982 //
1983 // BUG(271): Some of the exception propagation does not work on the
1984 // ARM simulator because the simulator separates the C++ stack and the
1985 // JS stack.  This test therefore fails on the simulator.  The test is
1986 // not threaded to allow the threading tests to run on the simulator.
TEST(TryCatchInTryFinally)1987 TEST(TryCatchInTryFinally) {
1988   v8::HandleScope scope;
1989   Local<ObjectTemplate> templ = ObjectTemplate::New();
1990   templ->Set(v8_str("CCatcher"),
1991              v8::FunctionTemplate::New(CCatcher));
1992   LocalContext context(0, templ);
1993   Local<Value> result = CompileRun("try {"
1994                                    "  try {"
1995                                    "    CCatcher('throw 7;');"
1996                                    "  } finally {"
1997                                    "  }"
1998                                    "} catch (e) {"
1999                                    "}");
2000   CHECK(result->IsTrue());
2001 }
2002 
2003 
receive_message(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)2004 static void receive_message(v8::Handle<v8::Message> message,
2005                             v8::Handle<v8::Value> data) {
2006   message->Get();
2007   message_received = true;
2008 }
2009 
2010 
TEST(APIThrowMessage)2011 TEST(APIThrowMessage) {
2012   message_received = false;
2013   v8::HandleScope scope;
2014   v8::V8::AddMessageListener(receive_message);
2015   Local<ObjectTemplate> templ = ObjectTemplate::New();
2016   templ->Set(v8_str("ThrowFromC"),
2017              v8::FunctionTemplate::New(ThrowFromC));
2018   LocalContext context(0, templ);
2019   CompileRun("ThrowFromC();");
2020   CHECK(message_received);
2021   v8::V8::RemoveMessageListeners(check_message);
2022 }
2023 
2024 
TEST(APIThrowMessageAndVerboseTryCatch)2025 TEST(APIThrowMessageAndVerboseTryCatch) {
2026   message_received = false;
2027   v8::HandleScope scope;
2028   v8::V8::AddMessageListener(receive_message);
2029   Local<ObjectTemplate> templ = ObjectTemplate::New();
2030   templ->Set(v8_str("ThrowFromC"),
2031              v8::FunctionTemplate::New(ThrowFromC));
2032   LocalContext context(0, templ);
2033   v8::TryCatch try_catch;
2034   try_catch.SetVerbose(true);
2035   Local<Value> result = CompileRun("ThrowFromC();");
2036   CHECK(try_catch.HasCaught());
2037   CHECK(result.IsEmpty());
2038   CHECK(message_received);
2039   v8::V8::RemoveMessageListeners(check_message);
2040 }
2041 
2042 
THREADED_TEST(ExternalScriptException)2043 THREADED_TEST(ExternalScriptException) {
2044   v8::HandleScope scope;
2045   Local<ObjectTemplate> templ = ObjectTemplate::New();
2046   templ->Set(v8_str("ThrowFromC"),
2047              v8::FunctionTemplate::New(ThrowFromC));
2048   LocalContext context(0, templ);
2049 
2050   v8::TryCatch try_catch;
2051   Local<Script> script
2052       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
2053   Local<Value> result = script->Run();
2054   CHECK(result.IsEmpty());
2055   CHECK(try_catch.HasCaught());
2056   String::AsciiValue exception_value(try_catch.Exception());
2057   CHECK_EQ("konto", *exception_value);
2058 }
2059 
2060 
2061 
CThrowCountDown(const v8::Arguments & args)2062 v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) {
2063   ApiTestFuzzer::Fuzz();
2064   CHECK_EQ(4, args.Length());
2065   int count = args[0]->Int32Value();
2066   int cInterval = args[2]->Int32Value();
2067   if (count == 0) {
2068     return v8::ThrowException(v8_str("FromC"));
2069   } else {
2070     Local<v8::Object> global = Context::GetCurrent()->Global();
2071     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
2072     v8::Handle<Value> argv[] = { v8_num(count - 1),
2073                                  args[1],
2074                                  args[2],
2075                                  args[3] };
2076     if (count % cInterval == 0) {
2077       v8::TryCatch try_catch;
2078       Local<Value> result =
2079           v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2080       int expected = args[3]->Int32Value();
2081       if (try_catch.HasCaught()) {
2082         CHECK_EQ(expected, count);
2083         CHECK(result.IsEmpty());
2084         CHECK(!i::Top::has_scheduled_exception());
2085       } else {
2086         CHECK_NE(expected, count);
2087       }
2088       return result;
2089     } else {
2090       return v8::Handle<Function>::Cast(fun)->Call(global, 4, argv);
2091     }
2092   }
2093 }
2094 
2095 
JSCheck(const v8::Arguments & args)2096 v8::Handle<Value> JSCheck(const v8::Arguments& args) {
2097   ApiTestFuzzer::Fuzz();
2098   CHECK_EQ(3, args.Length());
2099   bool equality = args[0]->BooleanValue();
2100   int count = args[1]->Int32Value();
2101   int expected = args[2]->Int32Value();
2102   if (equality) {
2103     CHECK_EQ(count, expected);
2104   } else {
2105     CHECK_NE(count, expected);
2106   }
2107   return v8::Undefined();
2108 }
2109 
2110 
THREADED_TEST(EvalInTryFinally)2111 THREADED_TEST(EvalInTryFinally) {
2112   v8::HandleScope scope;
2113   LocalContext context;
2114   v8::TryCatch try_catch;
2115   CompileRun("(function() {"
2116              "  try {"
2117              "    eval('asldkf (*&^&*^');"
2118              "  } finally {"
2119              "    return;"
2120              "  }"
2121              "})()");
2122   CHECK(!try_catch.HasCaught());
2123 }
2124 
2125 
2126 // This test works by making a stack of alternating JavaScript and C
2127 // activations.  These activations set up exception handlers with regular
2128 // intervals, one interval for C activations and another for JavaScript
2129 // activations.  When enough activations have been created an exception is
2130 // thrown and we check that the right activation catches the exception and that
2131 // no other activations do.  The right activation is always the topmost one with
2132 // a handler, regardless of whether it is in JavaScript or C.
2133 //
2134 // The notation used to describe a test case looks like this:
2135 //
2136 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
2137 //
2138 // Each entry is an activation, either JS or C.  The index is the count at that
2139 // level.  Stars identify activations with exception handlers, the @ identifies
2140 // the exception handler that should catch the exception.
2141 //
2142 // BUG(271): Some of the exception propagation does not work on the
2143 // ARM simulator because the simulator separates the C++ stack and the
2144 // JS stack.  This test therefore fails on the simulator.  The test is
2145 // not threaded to allow the threading tests to run on the simulator.
TEST(ExceptionOrder)2146 TEST(ExceptionOrder) {
2147   v8::HandleScope scope;
2148   Local<ObjectTemplate> templ = ObjectTemplate::New();
2149   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
2150   templ->Set(v8_str("CThrowCountDown"),
2151              v8::FunctionTemplate::New(CThrowCountDown));
2152   LocalContext context(0, templ);
2153   CompileRun(
2154     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
2155     "  if (count == 0) throw 'FromJS';"
2156     "  if (count % jsInterval == 0) {"
2157     "    try {"
2158     "      var value = CThrowCountDown(count - 1,"
2159     "                                  jsInterval,"
2160     "                                  cInterval,"
2161     "                                  expected);"
2162     "      check(false, count, expected);"
2163     "      return value;"
2164     "    } catch (e) {"
2165     "      check(true, count, expected);"
2166     "    }"
2167     "  } else {"
2168     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
2169     "  }"
2170     "}");
2171   Local<Function> fun =
2172       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
2173 
2174   const int argc = 4;
2175   //                             count      jsInterval cInterval  expected
2176 
2177   // *JS[4] *C[3] @JS[2] C[1] JS[0]
2178   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
2179   fun->Call(fun, argc, a0);
2180 
2181   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
2182   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
2183   fun->Call(fun, argc, a1);
2184 
2185   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
2186   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
2187   fun->Call(fun, argc, a2);
2188 
2189   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
2190   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
2191   fun->Call(fun, argc, a3);
2192 
2193   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
2194   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
2195   fun->Call(fun, argc, a4);
2196 
2197   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
2198   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
2199   fun->Call(fun, argc, a5);
2200 }
2201 
2202 
ThrowValue(const v8::Arguments & args)2203 v8::Handle<Value> ThrowValue(const v8::Arguments& args) {
2204   ApiTestFuzzer::Fuzz();
2205   CHECK_EQ(1, args.Length());
2206   return v8::ThrowException(args[0]);
2207 }
2208 
2209 
THREADED_TEST(ThrowValues)2210 THREADED_TEST(ThrowValues) {
2211   v8::HandleScope scope;
2212   Local<ObjectTemplate> templ = ObjectTemplate::New();
2213   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
2214   LocalContext context(0, templ);
2215   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
2216     "function Run(obj) {"
2217     "  try {"
2218     "    Throw(obj);"
2219     "  } catch (e) {"
2220     "    return e;"
2221     "  }"
2222     "  return 'no exception';"
2223     "}"
2224     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
2225   CHECK_EQ(5, result->Length());
2226   CHECK(result->Get(v8::Integer::New(0))->IsString());
2227   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
2228   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
2229   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
2230   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
2231   CHECK(result->Get(v8::Integer::New(3))->IsNull());
2232   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
2233 }
2234 
2235 
THREADED_TEST(CatchZero)2236 THREADED_TEST(CatchZero) {
2237   v8::HandleScope scope;
2238   LocalContext context;
2239   v8::TryCatch try_catch;
2240   CHECK(!try_catch.HasCaught());
2241   Script::Compile(v8_str("throw 10"))->Run();
2242   CHECK(try_catch.HasCaught());
2243   CHECK_EQ(10, try_catch.Exception()->Int32Value());
2244   try_catch.Reset();
2245   CHECK(!try_catch.HasCaught());
2246   Script::Compile(v8_str("throw 0"))->Run();
2247   CHECK(try_catch.HasCaught());
2248   CHECK_EQ(0, try_catch.Exception()->Int32Value());
2249 }
2250 
2251 
THREADED_TEST(CatchExceptionFromWith)2252 THREADED_TEST(CatchExceptionFromWith) {
2253   v8::HandleScope scope;
2254   LocalContext context;
2255   v8::TryCatch try_catch;
2256   CHECK(!try_catch.HasCaught());
2257   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
2258   CHECK(try_catch.HasCaught());
2259 }
2260 
2261 
THREADED_TEST(Equality)2262 THREADED_TEST(Equality) {
2263   v8::HandleScope scope;
2264   LocalContext context;
2265   // Check that equality works at all before relying on CHECK_EQ
2266   CHECK(v8_str("a")->Equals(v8_str("a")));
2267   CHECK(!v8_str("a")->Equals(v8_str("b")));
2268 
2269   CHECK_EQ(v8_str("a"), v8_str("a"));
2270   CHECK_NE(v8_str("a"), v8_str("b"));
2271   CHECK_EQ(v8_num(1), v8_num(1));
2272   CHECK_EQ(v8_num(1.00), v8_num(1));
2273   CHECK_NE(v8_num(1), v8_num(2));
2274 
2275   // Assume String is not symbol.
2276   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
2277   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
2278   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
2279   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
2280   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
2281   CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
2282   Local<Value> not_a_number = v8_num(i::OS::nan_value());
2283   CHECK(!not_a_number->StrictEquals(not_a_number));
2284   CHECK(v8::False()->StrictEquals(v8::False()));
2285   CHECK(!v8::False()->StrictEquals(v8::Undefined()));
2286 
2287   v8::Handle<v8::Object> obj = v8::Object::New();
2288   v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj);
2289   CHECK(alias->StrictEquals(obj));
2290   alias.Dispose();
2291 }
2292 
2293 
THREADED_TEST(MultiRun)2294 THREADED_TEST(MultiRun) {
2295   v8::HandleScope scope;
2296   LocalContext context;
2297   Local<Script> script = Script::Compile(v8_str("x"));
2298   for (int i = 0; i < 10; i++)
2299     script->Run();
2300 }
2301 
2302 
GetXValue(Local<String> name,const AccessorInfo & info)2303 static v8::Handle<Value> GetXValue(Local<String> name,
2304                                    const AccessorInfo& info) {
2305   ApiTestFuzzer::Fuzz();
2306   CHECK_EQ(info.Data(), v8_str("donut"));
2307   CHECK_EQ(name, v8_str("x"));
2308   return name;
2309 }
2310 
2311 
THREADED_TEST(SimplePropertyRead)2312 THREADED_TEST(SimplePropertyRead) {
2313   v8::HandleScope scope;
2314   Local<ObjectTemplate> templ = ObjectTemplate::New();
2315   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
2316   LocalContext context;
2317   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2318   Local<Script> script = Script::Compile(v8_str("obj.x"));
2319   for (int i = 0; i < 10; i++) {
2320     Local<Value> result = script->Run();
2321     CHECK_EQ(result, v8_str("x"));
2322   }
2323 }
2324 
2325 
2326 v8::Persistent<Value> xValue;
2327 
2328 
SetXValue(Local<String> name,Local<Value> value,const AccessorInfo & info)2329 static void SetXValue(Local<String> name,
2330                       Local<Value> value,
2331                       const AccessorInfo& info) {
2332   CHECK_EQ(value, v8_num(4));
2333   CHECK_EQ(info.Data(), v8_str("donut"));
2334   CHECK_EQ(name, v8_str("x"));
2335   CHECK(xValue.IsEmpty());
2336   xValue = v8::Persistent<Value>::New(value);
2337 }
2338 
2339 
THREADED_TEST(SimplePropertyWrite)2340 THREADED_TEST(SimplePropertyWrite) {
2341   v8::HandleScope scope;
2342   Local<ObjectTemplate> templ = ObjectTemplate::New();
2343   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
2344   LocalContext context;
2345   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2346   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
2347   for (int i = 0; i < 10; i++) {
2348     CHECK(xValue.IsEmpty());
2349     script->Run();
2350     CHECK_EQ(v8_num(4), xValue);
2351     xValue.Dispose();
2352     xValue = v8::Persistent<Value>();
2353   }
2354 }
2355 
2356 
XPropertyGetter(Local<String> property,const AccessorInfo & info)2357 static v8::Handle<Value> XPropertyGetter(Local<String> property,
2358                                          const AccessorInfo& info) {
2359   ApiTestFuzzer::Fuzz();
2360   CHECK(info.Data()->IsUndefined());
2361   return property;
2362 }
2363 
2364 
THREADED_TEST(NamedInterceptorPropertyRead)2365 THREADED_TEST(NamedInterceptorPropertyRead) {
2366   v8::HandleScope scope;
2367   Local<ObjectTemplate> templ = ObjectTemplate::New();
2368   templ->SetNamedPropertyHandler(XPropertyGetter);
2369   LocalContext context;
2370   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2371   Local<Script> script = Script::Compile(v8_str("obj.x"));
2372   for (int i = 0; i < 10; i++) {
2373     Local<Value> result = script->Run();
2374     CHECK_EQ(result, v8_str("x"));
2375   }
2376 }
2377 
2378 
IndexedPropertyGetter(uint32_t index,const AccessorInfo & info)2379 static v8::Handle<Value> IndexedPropertyGetter(uint32_t index,
2380                                                const AccessorInfo& info) {
2381   ApiTestFuzzer::Fuzz();
2382   if (index == 37) {
2383     return v8::Handle<Value>(v8_num(625));
2384   }
2385   return v8::Handle<Value>();
2386 }
2387 
2388 
IndexedPropertySetter(uint32_t index,Local<Value> value,const AccessorInfo & info)2389 static v8::Handle<Value> IndexedPropertySetter(uint32_t index,
2390                                                Local<Value> value,
2391                                                const AccessorInfo& info) {
2392   ApiTestFuzzer::Fuzz();
2393   if (index == 39) {
2394     return value;
2395   }
2396   return v8::Handle<Value>();
2397 }
2398 
2399 
THREADED_TEST(IndexedInterceptorWithIndexedAccessor)2400 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
2401   v8::HandleScope scope;
2402   Local<ObjectTemplate> templ = ObjectTemplate::New();
2403   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
2404                                    IndexedPropertySetter);
2405   LocalContext context;
2406   context->Global()->Set(v8_str("obj"), templ->NewInstance());
2407   Local<Script> getter_script = Script::Compile(v8_str(
2408       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
2409   Local<Script> setter_script = Script::Compile(v8_str(
2410       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
2411       "obj[17] = 23;"
2412       "obj.foo;"));
2413   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
2414       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
2415       "obj[39] = 47;"
2416       "obj.foo;"));  // This setter should not run, due to the interceptor.
2417   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
2418       "obj[37];"));
2419   Local<Value> result = getter_script->Run();
2420   CHECK_EQ(v8_num(5), result);
2421   result = setter_script->Run();
2422   CHECK_EQ(v8_num(23), result);
2423   result = interceptor_setter_script->Run();
2424   CHECK_EQ(v8_num(23), result);
2425   result = interceptor_getter_script->Run();
2426   CHECK_EQ(v8_num(625), result);
2427 }
2428 
2429 
THREADED_TEST(MultiContexts)2430 THREADED_TEST(MultiContexts) {
2431   v8::HandleScope scope;
2432   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
2433   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
2434 
2435   Local<String> password = v8_str("Password");
2436 
2437   // Create an environment
2438   LocalContext context0(0, templ);
2439   context0->SetSecurityToken(password);
2440   v8::Handle<v8::Object> global0 = context0->Global();
2441   global0->Set(v8_str("custom"), v8_num(1234));
2442   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2443 
2444   // Create an independent environment
2445   LocalContext context1(0, templ);
2446   context1->SetSecurityToken(password);
2447   v8::Handle<v8::Object> global1 = context1->Global();
2448   global1->Set(v8_str("custom"), v8_num(1234));
2449   CHECK_NE(global0, global1);
2450   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
2451   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
2452 
2453   // Now create a new context with the old global
2454   LocalContext context2(0, templ, global1);
2455   context2->SetSecurityToken(password);
2456   v8::Handle<v8::Object> global2 = context2->Global();
2457   CHECK_EQ(global1, global2);
2458   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
2459   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
2460 }
2461 
2462 
THREADED_TEST(FunctionPrototypeAcrossContexts)2463 THREADED_TEST(FunctionPrototypeAcrossContexts) {
2464   // Make sure that functions created by cloning boilerplates cannot
2465   // communicate through their __proto__ field.
2466 
2467   v8::HandleScope scope;
2468 
2469   LocalContext env0;
2470   v8::Handle<v8::Object> global0 =
2471       env0->Global();
2472   v8::Handle<v8::Object> object0 =
2473       v8::Handle<v8::Object>::Cast(global0->Get(v8_str("Object")));
2474   v8::Handle<v8::Object> tostring0 =
2475       v8::Handle<v8::Object>::Cast(object0->Get(v8_str("toString")));
2476   v8::Handle<v8::Object> proto0 =
2477       v8::Handle<v8::Object>::Cast(tostring0->Get(v8_str("__proto__")));
2478   proto0->Set(v8_str("custom"), v8_num(1234));
2479 
2480   LocalContext env1;
2481   v8::Handle<v8::Object> global1 =
2482       env1->Global();
2483   v8::Handle<v8::Object> object1 =
2484       v8::Handle<v8::Object>::Cast(global1->Get(v8_str("Object")));
2485   v8::Handle<v8::Object> tostring1 =
2486       v8::Handle<v8::Object>::Cast(object1->Get(v8_str("toString")));
2487   v8::Handle<v8::Object> proto1 =
2488       v8::Handle<v8::Object>::Cast(tostring1->Get(v8_str("__proto__")));
2489   CHECK(!proto1->Has(v8_str("custom")));
2490 }
2491 
2492 
THREADED_TEST(Regress892105)2493 THREADED_TEST(Regress892105) {
2494   // Make sure that object and array literals created by cloning
2495   // boilerplates cannot communicate through their __proto__
2496   // field. This is rather difficult to check, but we try to add stuff
2497   // to Object.prototype and Array.prototype and create a new
2498   // environment. This should succeed.
2499 
2500   v8::HandleScope scope;
2501 
2502   Local<String> source = v8_str("Object.prototype.obj = 1234;"
2503                                 "Array.prototype.arr = 4567;"
2504                                 "8901");
2505 
2506   LocalContext env0;
2507   Local<Script> script0 = Script::Compile(source);
2508   CHECK_EQ(8901.0, script0->Run()->NumberValue());
2509 
2510   LocalContext env1;
2511   Local<Script> script1 = Script::Compile(source);
2512   CHECK_EQ(8901.0, script1->Run()->NumberValue());
2513 }
2514 
2515 
ExpectString(const char * code,const char * expected)2516 static void ExpectString(const char* code, const char* expected) {
2517   Local<Value> result = CompileRun(code);
2518   CHECK(result->IsString());
2519   String::AsciiValue ascii(result);
2520   CHECK_EQ(0, strcmp(*ascii, expected));
2521 }
2522 
2523 
ExpectBoolean(const char * code,bool expected)2524 static void ExpectBoolean(const char* code, bool expected) {
2525   Local<Value> result = CompileRun(code);
2526   CHECK(result->IsBoolean());
2527   CHECK_EQ(expected, result->BooleanValue());
2528 }
2529 
2530 
ExpectObject(const char * code,Local<Value> expected)2531 static void ExpectObject(const char* code, Local<Value> expected) {
2532   Local<Value> result = CompileRun(code);
2533   CHECK(result->Equals(expected));
2534 }
2535 
2536 
THREADED_TEST(UndetectableObject)2537 THREADED_TEST(UndetectableObject) {
2538   v8::HandleScope scope;
2539   LocalContext env;
2540 
2541   Local<v8::FunctionTemplate> desc =
2542       v8::FunctionTemplate::New(0, v8::Handle<Value>());
2543   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
2544 
2545   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
2546   env->Global()->Set(v8_str("undetectable"), obj);
2547 
2548   ExpectString("undetectable.toString()", "[object Object]");
2549   ExpectString("typeof undetectable", "undefined");
2550   ExpectString("typeof(undetectable)", "undefined");
2551   ExpectBoolean("typeof undetectable == 'undefined'", true);
2552   ExpectBoolean("typeof undetectable == 'object'", false);
2553   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2554   ExpectBoolean("!undetectable", true);
2555 
2556   ExpectObject("true&&undetectable", obj);
2557   ExpectBoolean("false&&undetectable", false);
2558   ExpectBoolean("true||undetectable", true);
2559   ExpectObject("false||undetectable", obj);
2560 
2561   ExpectObject("undetectable&&true", obj);
2562   ExpectObject("undetectable&&false", obj);
2563   ExpectBoolean("undetectable||true", true);
2564   ExpectBoolean("undetectable||false", false);
2565 
2566   ExpectBoolean("undetectable==null", true);
2567   ExpectBoolean("null==undetectable", true);
2568   ExpectBoolean("undetectable==undefined", true);
2569   ExpectBoolean("undefined==undetectable", true);
2570   ExpectBoolean("undetectable==undetectable", true);
2571 
2572 
2573   ExpectBoolean("undetectable===null", false);
2574   ExpectBoolean("null===undetectable", false);
2575   ExpectBoolean("undetectable===undefined", false);
2576   ExpectBoolean("undefined===undetectable", false);
2577   ExpectBoolean("undetectable===undetectable", true);
2578 }
2579 
2580 
THREADED_TEST(UndetectableString)2581 THREADED_TEST(UndetectableString) {
2582   v8::HandleScope scope;
2583   LocalContext env;
2584 
2585   Local<String> obj = String::NewUndetectable("foo");
2586   env->Global()->Set(v8_str("undetectable"), obj);
2587 
2588   ExpectString("undetectable", "foo");
2589   ExpectString("typeof undetectable", "undefined");
2590   ExpectString("typeof(undetectable)", "undefined");
2591   ExpectBoolean("typeof undetectable == 'undefined'", true);
2592   ExpectBoolean("typeof undetectable == 'string'", false);
2593   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
2594   ExpectBoolean("!undetectable", true);
2595 
2596   ExpectObject("true&&undetectable", obj);
2597   ExpectBoolean("false&&undetectable", false);
2598   ExpectBoolean("true||undetectable", true);
2599   ExpectObject("false||undetectable", obj);
2600 
2601   ExpectObject("undetectable&&true", obj);
2602   ExpectObject("undetectable&&false", obj);
2603   ExpectBoolean("undetectable||true", true);
2604   ExpectBoolean("undetectable||false", false);
2605 
2606   ExpectBoolean("undetectable==null", true);
2607   ExpectBoolean("null==undetectable", true);
2608   ExpectBoolean("undetectable==undefined", true);
2609   ExpectBoolean("undefined==undetectable", true);
2610   ExpectBoolean("undetectable==undetectable", true);
2611 
2612 
2613   ExpectBoolean("undetectable===null", false);
2614   ExpectBoolean("null===undetectable", false);
2615   ExpectBoolean("undetectable===undefined", false);
2616   ExpectBoolean("undefined===undetectable", false);
2617   ExpectBoolean("undetectable===undetectable", true);
2618 }
2619 
2620 
USE(T)2621 template <typename T> static void USE(T) { }
2622 
2623 
2624 // This test is not intended to be run, just type checked.
PersistentHandles()2625 static void PersistentHandles() {
2626   USE(PersistentHandles);
2627   Local<String> str = v8_str("foo");
2628   v8::Persistent<String> p_str = v8::Persistent<String>::New(str);
2629   USE(p_str);
2630   Local<Script> scr = Script::Compile(v8_str(""));
2631   v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr);
2632   USE(p_scr);
2633   Local<ObjectTemplate> templ = ObjectTemplate::New();
2634   v8::Persistent<ObjectTemplate> p_templ =
2635     v8::Persistent<ObjectTemplate>::New(templ);
2636   USE(p_templ);
2637 }
2638 
2639 
HandleLogDelegator(const v8::Arguments & args)2640 static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) {
2641   ApiTestFuzzer::Fuzz();
2642   return v8::Undefined();
2643 }
2644 
2645 
THREADED_TEST(GlobalObjectTemplate)2646 THREADED_TEST(GlobalObjectTemplate) {
2647   v8::HandleScope handle_scope;
2648   Local<ObjectTemplate> global_template = ObjectTemplate::New();
2649   global_template->Set(v8_str("JSNI_Log"),
2650                        v8::FunctionTemplate::New(HandleLogDelegator));
2651   v8::Persistent<Context> context = Context::New(0, global_template);
2652   Context::Scope context_scope(context);
2653   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
2654   context.Dispose();
2655 }
2656 
2657 
2658 static const char* kSimpleExtensionSource =
2659   "function Foo() {"
2660   "  return 4;"
2661   "}";
2662 
2663 
THREADED_TEST(SimpleExtensions)2664 THREADED_TEST(SimpleExtensions) {
2665   v8::HandleScope handle_scope;
2666   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
2667   const char* extension_names[] = { "simpletest" };
2668   v8::ExtensionConfiguration extensions(1, extension_names);
2669   v8::Handle<Context> context = Context::New(&extensions);
2670   Context::Scope lock(context);
2671   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2672   CHECK_EQ(result, v8::Integer::New(4));
2673 }
2674 
2675 
2676 static const char* kEvalExtensionSource1 =
2677   "function UseEval1() {"
2678   "  var x = 42;"
2679   "  return eval('x');"
2680   "}";
2681 
2682 
2683 static const char* kEvalExtensionSource2 =
2684   "(function() {"
2685   "  var x = 42;"
2686   "  function e() {"
2687   "    return eval('x');"
2688   "  }"
2689   "  this.UseEval2 = e;"
2690   "})()";
2691 
2692 
THREADED_TEST(UseEvalFromExtension)2693 THREADED_TEST(UseEvalFromExtension) {
2694   v8::HandleScope handle_scope;
2695   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
2696   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
2697   const char* extension_names[] = { "evaltest1", "evaltest2" };
2698   v8::ExtensionConfiguration extensions(2, extension_names);
2699   v8::Handle<Context> context = Context::New(&extensions);
2700   Context::Scope lock(context);
2701   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
2702   CHECK_EQ(result, v8::Integer::New(42));
2703   result = Script::Compile(v8_str("UseEval2()"))->Run();
2704   CHECK_EQ(result, v8::Integer::New(42));
2705 }
2706 
2707 
2708 static const char* kWithExtensionSource1 =
2709   "function UseWith1() {"
2710   "  var x = 42;"
2711   "  with({x:87}) { return x; }"
2712   "}";
2713 
2714 
2715 
2716 static const char* kWithExtensionSource2 =
2717   "(function() {"
2718   "  var x = 42;"
2719   "  function e() {"
2720   "    with ({x:87}) { return x; }"
2721   "  }"
2722   "  this.UseWith2 = e;"
2723   "})()";
2724 
2725 
THREADED_TEST(UseWithFromExtension)2726 THREADED_TEST(UseWithFromExtension) {
2727   v8::HandleScope handle_scope;
2728   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
2729   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
2730   const char* extension_names[] = { "withtest1", "withtest2" };
2731   v8::ExtensionConfiguration extensions(2, extension_names);
2732   v8::Handle<Context> context = Context::New(&extensions);
2733   Context::Scope lock(context);
2734   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
2735   CHECK_EQ(result, v8::Integer::New(87));
2736   result = Script::Compile(v8_str("UseWith2()"))->Run();
2737   CHECK_EQ(result, v8::Integer::New(87));
2738 }
2739 
2740 
THREADED_TEST(AutoExtensions)2741 THREADED_TEST(AutoExtensions) {
2742   v8::HandleScope handle_scope;
2743   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
2744   extension->set_auto_enable(true);
2745   v8::RegisterExtension(extension);
2746   v8::Handle<Context> context = Context::New();
2747   Context::Scope lock(context);
2748   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
2749   CHECK_EQ(result, v8::Integer::New(4));
2750 }
2751 
2752 
CheckDependencies(const char * name,const char * expected)2753 static void CheckDependencies(const char* name, const char* expected) {
2754   v8::HandleScope handle_scope;
2755   v8::ExtensionConfiguration config(1, &name);
2756   LocalContext context(&config);
2757   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
2758 }
2759 
2760 
2761 /*
2762  * Configuration:
2763  *
2764  *     /-- B <--\
2765  * A <-          -- D <-- E
2766  *     \-- C <--/
2767  */
THREADED_TEST(ExtensionDependency)2768 THREADED_TEST(ExtensionDependency) {
2769   static const char* kEDeps[] = { "D" };
2770   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
2771   static const char* kDDeps[] = { "B", "C" };
2772   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
2773   static const char* kBCDeps[] = { "A" };
2774   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
2775   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
2776   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
2777   CheckDependencies("A", "undefinedA");
2778   CheckDependencies("B", "undefinedAB");
2779   CheckDependencies("C", "undefinedAC");
2780   CheckDependencies("D", "undefinedABCD");
2781   CheckDependencies("E", "undefinedABCDE");
2782   v8::HandleScope handle_scope;
2783   static const char* exts[2] = { "C", "E" };
2784   v8::ExtensionConfiguration config(2, exts);
2785   LocalContext context(&config);
2786   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
2787 }
2788 
2789 
2790 static const char* kExtensionTestScript =
2791   "native function A();"
2792   "native function B();"
2793   "native function C();"
2794   "function Foo(i) {"
2795   "  if (i == 0) return A();"
2796   "  if (i == 1) return B();"
2797   "  if (i == 2) return C();"
2798   "}";
2799 
2800 
CallFun(const v8::Arguments & args)2801 static v8::Handle<Value> CallFun(const v8::Arguments& args) {
2802   ApiTestFuzzer::Fuzz();
2803   return args.Data();
2804 }
2805 
2806 
2807 class FunctionExtension : public Extension {
2808  public:
FunctionExtension()2809   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
2810   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
2811       v8::Handle<String> name);
2812 };
2813 
2814 
2815 static int lookup_count = 0;
GetNativeFunction(v8::Handle<String> name)2816 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
2817       v8::Handle<String> name) {
2818   lookup_count++;
2819   if (name->Equals(v8_str("A"))) {
2820     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
2821   } else if (name->Equals(v8_str("B"))) {
2822     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
2823   } else if (name->Equals(v8_str("C"))) {
2824     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
2825   } else {
2826     return v8::Handle<v8::FunctionTemplate>();
2827   }
2828 }
2829 
2830 
THREADED_TEST(FunctionLookup)2831 THREADED_TEST(FunctionLookup) {
2832   v8::RegisterExtension(new FunctionExtension());
2833   v8::HandleScope handle_scope;
2834   static const char* exts[1] = { "functiontest" };
2835   v8::ExtensionConfiguration config(1, exts);
2836   LocalContext context(&config);
2837   CHECK_EQ(3, lookup_count);
2838   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
2839   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
2840   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
2841 }
2842 
2843 
2844 static const char* last_location;
2845 static const char* last_message;
StoringErrorCallback(const char * location,const char * message)2846 void StoringErrorCallback(const char* location, const char* message) {
2847   if (last_location == NULL) {
2848     last_location = location;
2849     last_message = message;
2850   }
2851 }
2852 
2853 
2854 // ErrorReporting creates a circular extensions configuration and
2855 // tests that the fatal error handler gets called.  This renders V8
2856 // unusable and therefore this test cannot be run in parallel.
TEST(ErrorReporting)2857 TEST(ErrorReporting) {
2858   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
2859   static const char* aDeps[] = { "B" };
2860   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
2861   static const char* bDeps[] = { "A" };
2862   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
2863   last_location = NULL;
2864   v8::ExtensionConfiguration config(1, bDeps);
2865   v8::Handle<Context> context = Context::New(&config);
2866   CHECK(context.IsEmpty());
2867   CHECK_NE(last_location, NULL);
2868 }
2869 
2870 
2871 static const char* js_code_causing_huge_string_flattening =
2872     "var str = 'X';"
2873     "for (var i = 0; i < 30; i++) {"
2874     "  str = str + str;"
2875     "}"
2876     "str.match(/X/);";
2877 
2878 
OOMCallback(const char * location,const char * message)2879 void OOMCallback(const char* location, const char* message) {
2880   exit(0);
2881 }
2882 
2883 
TEST(RegexpOutOfMemory)2884 TEST(RegexpOutOfMemory) {
2885   // Execute a script that causes out of memory when flattening a string.
2886   v8::HandleScope scope;
2887   v8::V8::SetFatalErrorHandler(OOMCallback);
2888   LocalContext context;
2889   Local<Script> script =
2890       Script::Compile(String::New(js_code_causing_huge_string_flattening));
2891   last_location = NULL;
2892   Local<Value> result = script->Run();
2893 
2894   CHECK(false);  // Should not return.
2895 }
2896 
2897 
MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,v8::Handle<Value> data)2898 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
2899                                              v8::Handle<Value> data) {
2900   CHECK_EQ(v8::Undefined(), data);
2901   CHECK(message->GetScriptResourceName()->IsUndefined());
2902   CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
2903   message->GetLineNumber();
2904   message->GetSourceLine();
2905 }
2906 
2907 
THREADED_TEST(ErrorWithMissingScriptInfo)2908 THREADED_TEST(ErrorWithMissingScriptInfo) {
2909   v8::HandleScope scope;
2910   LocalContext context;
2911   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
2912   Script::Compile(v8_str("throw Error()"))->Run();
2913   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
2914 }
2915 
2916 
2917 int global_index = 0;
2918 
2919 class Snorkel {
2920  public:
Snorkel()2921   Snorkel() { index_ = global_index++; }
2922   int index_;
2923 };
2924 
2925 class Whammy {
2926  public:
Whammy()2927   Whammy() {
2928     cursor_ = 0;
2929   }
~Whammy()2930   ~Whammy() {
2931     script_.Dispose();
2932   }
getScript()2933   v8::Handle<Script> getScript() {
2934     if (script_.IsEmpty())
2935       script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo"));
2936     return Local<Script>(*script_);
2937   }
2938 
2939  public:
2940   static const int kObjectCount = 256;
2941   int cursor_;
2942   v8::Persistent<v8::Object> objects_[kObjectCount];
2943   v8::Persistent<Script> script_;
2944 };
2945 
HandleWeakReference(v8::Persistent<v8::Value> obj,void * data)2946 static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) {
2947   Snorkel* snorkel = reinterpret_cast<Snorkel*>(data);
2948   delete snorkel;
2949   obj.ClearWeak();
2950 }
2951 
WhammyPropertyGetter(Local<String> name,const AccessorInfo & info)2952 v8::Handle<Value> WhammyPropertyGetter(Local<String> name,
2953                                        const AccessorInfo& info) {
2954   Whammy* whammy =
2955     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
2956 
2957   v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_];
2958 
2959   v8::Handle<v8::Object> obj = v8::Object::New();
2960   v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj);
2961   if (!prev.IsEmpty()) {
2962     prev->Set(v8_str("next"), obj);
2963     prev.MakeWeak(new Snorkel(), &HandleWeakReference);
2964     whammy->objects_[whammy->cursor_].Clear();
2965   }
2966   whammy->objects_[whammy->cursor_] = global;
2967   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
2968   return whammy->getScript()->Run();
2969 }
2970 
THREADED_TEST(WeakReference)2971 THREADED_TEST(WeakReference) {
2972   v8::HandleScope handle_scope;
2973   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
2974   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
2975                                  0, 0, 0, 0,
2976                                  v8::External::New(new Whammy()));
2977   const char* extension_list[] = { "v8/gc" };
2978   v8::ExtensionConfiguration extensions(1, extension_list);
2979   v8::Persistent<Context> context = Context::New(&extensions);
2980   Context::Scope context_scope(context);
2981 
2982   v8::Handle<v8::Object> interceptor = templ->NewInstance();
2983   context->Global()->Set(v8_str("whammy"), interceptor);
2984   const char* code =
2985       "var last;"
2986       "for (var i = 0; i < 10000; i++) {"
2987       "  var obj = whammy.length;"
2988       "  if (last) last.next = obj;"
2989       "  last = obj;"
2990       "}"
2991       "gc();"
2992       "4";
2993   v8::Handle<Value> result = CompileRun(code);
2994   CHECK_EQ(4.0, result->NumberValue());
2995 
2996   context.Dispose();
2997 }
2998 
2999 
3000 v8::Handle<Function> args_fun;
3001 
3002 
ArgumentsTestCallback(const v8::Arguments & args)3003 static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) {
3004   ApiTestFuzzer::Fuzz();
3005   CHECK_EQ(args_fun, args.Callee());
3006   CHECK_EQ(3, args.Length());
3007   CHECK_EQ(v8::Integer::New(1), args[0]);
3008   CHECK_EQ(v8::Integer::New(2), args[1]);
3009   CHECK_EQ(v8::Integer::New(3), args[2]);
3010   CHECK_EQ(v8::Undefined(), args[3]);
3011   v8::HandleScope scope;
3012   i::Heap::CollectAllGarbage(false);
3013   return v8::Undefined();
3014 }
3015 
3016 
THREADED_TEST(Arguments)3017 THREADED_TEST(Arguments) {
3018   v8::HandleScope scope;
3019   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
3020   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
3021   LocalContext context(NULL, global);
3022   args_fun = v8::Handle<Function>::Cast(context->Global()->Get(v8_str("f")));
3023   v8_compile("f(1, 2, 3)")->Run();
3024 }
3025 
3026 
3027 static int x_register = 0;
3028 static v8::Handle<v8::Object> x_receiver;
3029 static v8::Handle<v8::Object> x_holder;
3030 
3031 
XGetter(Local<String> name,const AccessorInfo & info)3032 static v8::Handle<Value> XGetter(Local<String> name, const AccessorInfo& info) {
3033   ApiTestFuzzer::Fuzz();
3034   CHECK_EQ(x_receiver, info.This());
3035   CHECK_EQ(x_holder, info.Holder());
3036   return v8_num(x_register);
3037 }
3038 
3039 
XSetter(Local<String> name,Local<Value> value,const AccessorInfo & info)3040 static void XSetter(Local<String> name,
3041                     Local<Value> value,
3042                     const AccessorInfo& info) {
3043   CHECK_EQ(x_holder, info.This());
3044   CHECK_EQ(x_holder, info.Holder());
3045   x_register = value->Int32Value();
3046 }
3047 
3048 
THREADED_TEST(AccessorIC)3049 THREADED_TEST(AccessorIC) {
3050   v8::HandleScope scope;
3051   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3052   obj->SetAccessor(v8_str("x"), XGetter, XSetter);
3053   LocalContext context;
3054   x_holder = obj->NewInstance();
3055   context->Global()->Set(v8_str("holder"), x_holder);
3056   x_receiver = v8::Object::New();
3057   context->Global()->Set(v8_str("obj"), x_receiver);
3058   v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(CompileRun(
3059     "obj.__proto__ = holder;"
3060     "var result = [];"
3061     "for (var i = 0; i < 10; i++) {"
3062     "  holder.x = i;"
3063     "  result.push(obj.x);"
3064     "}"
3065     "result"));
3066   CHECK_EQ(10, array->Length());
3067   for (int i = 0; i < 10; i++) {
3068     v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
3069     CHECK_EQ(v8::Integer::New(i), entry);
3070   }
3071 }
3072 
3073 
NoBlockGetterX(Local<String> name,const AccessorInfo &)3074 static v8::Handle<Value> NoBlockGetterX(Local<String> name,
3075                                         const AccessorInfo&) {
3076   return v8::Handle<Value>();
3077 }
3078 
3079 
NoBlockGetterI(uint32_t index,const AccessorInfo &)3080 static v8::Handle<Value> NoBlockGetterI(uint32_t index,
3081                                         const AccessorInfo&) {
3082   return v8::Handle<Value>();
3083 }
3084 
3085 
PDeleter(Local<String> name,const AccessorInfo &)3086 static v8::Handle<v8::Boolean> PDeleter(Local<String> name,
3087                                         const AccessorInfo&) {
3088   if (!name->Equals(v8_str("foo"))) {
3089     return v8::Handle<v8::Boolean>();  // not intercepted
3090   }
3091 
3092   return v8::False();  // intercepted, and don't delete the property
3093 }
3094 
3095 
IDeleter(uint32_t index,const AccessorInfo &)3096 static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) {
3097   if (index != 2) {
3098     return v8::Handle<v8::Boolean>();  // not intercepted
3099   }
3100 
3101   return v8::False();  // intercepted, and don't delete the property
3102 }
3103 
3104 
THREADED_TEST(Deleter)3105 THREADED_TEST(Deleter) {
3106   v8::HandleScope scope;
3107   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3108   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
3109   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
3110   LocalContext context;
3111   context->Global()->Set(v8_str("k"), obj->NewInstance());
3112   CompileRun(
3113     "k.foo = 'foo';"
3114     "k.bar = 'bar';"
3115     "k[2] = 2;"
3116     "k[4] = 4;");
3117   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
3118   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
3119 
3120   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
3121   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
3122 
3123   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
3124   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
3125 
3126   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
3127   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
3128 }
3129 
3130 
GetK(Local<String> name,const AccessorInfo &)3131 static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) {
3132   ApiTestFuzzer::Fuzz();
3133   if (name->Equals(v8_str("foo")) ||
3134       name->Equals(v8_str("bar")) ||
3135       name->Equals(v8_str("baz"))) {
3136     return v8::Undefined();
3137   }
3138   return v8::Handle<Value>();
3139 }
3140 
3141 
IndexedGetK(uint32_t index,const AccessorInfo &)3142 static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) {
3143   ApiTestFuzzer::Fuzz();
3144   if (index == 0 || index == 1) return v8::Undefined();
3145   return v8::Handle<Value>();
3146 }
3147 
3148 
NamedEnum(const AccessorInfo &)3149 static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) {
3150   ApiTestFuzzer::Fuzz();
3151   v8::Handle<v8::Array> result = v8::Array::New(3);
3152   result->Set(v8::Integer::New(0), v8_str("foo"));
3153   result->Set(v8::Integer::New(1), v8_str("bar"));
3154   result->Set(v8::Integer::New(2), v8_str("baz"));
3155   return result;
3156 }
3157 
3158 
IndexedEnum(const AccessorInfo &)3159 static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) {
3160   ApiTestFuzzer::Fuzz();
3161   v8::Handle<v8::Array> result = v8::Array::New(2);
3162   result->Set(v8::Integer::New(0), v8_str("0"));
3163   result->Set(v8::Integer::New(1), v8_str("1"));
3164   return result;
3165 }
3166 
3167 
THREADED_TEST(Enumerators)3168 THREADED_TEST(Enumerators) {
3169   v8::HandleScope scope;
3170   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3171   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
3172   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
3173   LocalContext context;
3174   context->Global()->Set(v8_str("k"), obj->NewInstance());
3175   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
3176     "k[10] = 0;"
3177     "k.a = 0;"
3178     "k[5] = 0;"
3179     "k.b = 0;"
3180     "k[4294967295] = 0;"
3181     "k.c = 0;"
3182     "k[4294967296] = 0;"
3183     "k.d = 0;"
3184     "k[140000] = 0;"
3185     "k.e = 0;"
3186     "k[30000000000] = 0;"
3187     "k.f = 0;"
3188     "var result = [];"
3189     "for (var prop in k) {"
3190     "  result.push(prop);"
3191     "}"
3192     "result"));
3193   // Check that we get all the property names returned including the
3194   // ones from the enumerators in the right order: indexed properties
3195   // in numerical order, indexed interceptor properties, named
3196   // properties in insertion order, named interceptor properties.
3197   // This order is not mandated by the spec, so this test is just
3198   // documenting our behavior.
3199   CHECK_EQ(17, result->Length());
3200   // Indexed properties in numerical order.
3201   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
3202   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
3203   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
3204   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
3205   // Indexed interceptor properties in the order they are returned
3206   // from the enumerator interceptor.
3207   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
3208   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
3209   // Named properties in insertion order.
3210   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
3211   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
3212   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
3213   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
3214   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
3215   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
3216   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
3217   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
3218   // Named interceptor properties.
3219   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
3220   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
3221   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
3222 }
3223 
3224 
3225 int p_getter_count;
3226 int p_getter_count2;
3227 
3228 
PGetter(Local<String> name,const AccessorInfo & info)3229 static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) {
3230   ApiTestFuzzer::Fuzz();
3231   p_getter_count++;
3232   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3233   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3234   if (name->Equals(v8_str("p1"))) {
3235     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3236   } else if (name->Equals(v8_str("p2"))) {
3237     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3238   } else if (name->Equals(v8_str("p3"))) {
3239     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3240   } else if (name->Equals(v8_str("p4"))) {
3241     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3242   }
3243   return v8::Undefined();
3244 }
3245 
3246 
RunHolderTest(v8::Handle<v8::ObjectTemplate> obj)3247 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
3248   ApiTestFuzzer::Fuzz();
3249   LocalContext context;
3250   context->Global()->Set(v8_str("o1"), obj->NewInstance());
3251   CompileRun(
3252     "o1.__proto__ = { };"
3253     "var o2 = { __proto__: o1 };"
3254     "var o3 = { __proto__: o2 };"
3255     "var o4 = { __proto__: o3 };"
3256     "for (var i = 0; i < 10; i++) o4.p4;"
3257     "for (var i = 0; i < 10; i++) o3.p3;"
3258     "for (var i = 0; i < 10; i++) o2.p2;"
3259     "for (var i = 0; i < 10; i++) o1.p1;");
3260 }
3261 
3262 
PGetter2(Local<String> name,const AccessorInfo & info)3263 static v8::Handle<Value> PGetter2(Local<String> name,
3264                                   const AccessorInfo& info) {
3265   ApiTestFuzzer::Fuzz();
3266   p_getter_count2++;
3267   v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
3268   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
3269   if (name->Equals(v8_str("p1"))) {
3270     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
3271   } else if (name->Equals(v8_str("p2"))) {
3272     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
3273   } else if (name->Equals(v8_str("p3"))) {
3274     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
3275   } else if (name->Equals(v8_str("p4"))) {
3276     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
3277   }
3278   return v8::Undefined();
3279 }
3280 
3281 
THREADED_TEST(GetterHolders)3282 THREADED_TEST(GetterHolders) {
3283   v8::HandleScope scope;
3284   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3285   obj->SetAccessor(v8_str("p1"), PGetter);
3286   obj->SetAccessor(v8_str("p2"), PGetter);
3287   obj->SetAccessor(v8_str("p3"), PGetter);
3288   obj->SetAccessor(v8_str("p4"), PGetter);
3289   p_getter_count = 0;
3290   RunHolderTest(obj);
3291   CHECK_EQ(40, p_getter_count);
3292 }
3293 
3294 
THREADED_TEST(PreInterceptorHolders)3295 THREADED_TEST(PreInterceptorHolders) {
3296   v8::HandleScope scope;
3297   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3298   obj->SetNamedPropertyHandler(PGetter2);
3299   p_getter_count2 = 0;
3300   RunHolderTest(obj);
3301   CHECK_EQ(40, p_getter_count2);
3302 }
3303 
3304 
THREADED_TEST(ObjectInstantiation)3305 THREADED_TEST(ObjectInstantiation) {
3306   v8::HandleScope scope;
3307   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
3308   templ->SetAccessor(v8_str("t"), PGetter2);
3309   LocalContext context;
3310   context->Global()->Set(v8_str("o"), templ->NewInstance());
3311   for (int i = 0; i < 100; i++) {
3312     v8::HandleScope inner_scope;
3313     v8::Handle<v8::Object> obj = templ->NewInstance();
3314     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
3315     context->Global()->Set(v8_str("o2"), obj);
3316     v8::Handle<Value> value =
3317         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
3318     CHECK_EQ(v8::True(), value);
3319     context->Global()->Set(v8_str("o"), obj);
3320   }
3321 }
3322 
3323 
THREADED_TEST(StringWrite)3324 THREADED_TEST(StringWrite) {
3325   v8::HandleScope scope;
3326   v8::Handle<String> str = v8_str("abcde");
3327 
3328   char buf[100];
3329   int len;
3330 
3331   memset(buf, 0x1, sizeof(buf));
3332   len = str->WriteAscii(buf);
3333   CHECK_EQ(len, 5);
3334   CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3335 
3336   memset(buf, 0x1, sizeof(buf));
3337   len = str->WriteAscii(buf, 0, 4);
3338   CHECK_EQ(len, 4);
3339   CHECK_EQ(strncmp("abcd\1", buf, 5), 0);
3340 
3341   memset(buf, 0x1, sizeof(buf));
3342   len = str->WriteAscii(buf, 0, 5);
3343   CHECK_EQ(len, 5);
3344   CHECK_EQ(strncmp("abcde\1", buf, 6), 0);
3345 
3346   memset(buf, 0x1, sizeof(buf));
3347   len = str->WriteAscii(buf, 0, 6);
3348   CHECK_EQ(len, 5);
3349   CHECK_EQ(strncmp("abcde\0", buf, 6), 0);
3350 
3351   memset(buf, 0x1, sizeof(buf));
3352   len = str->WriteAscii(buf, 4, -1);
3353   CHECK_EQ(len, 1);
3354   CHECK_EQ(strncmp("e\0", buf, 2), 0);
3355 
3356   memset(buf, 0x1, sizeof(buf));
3357   len = str->WriteAscii(buf, 4, 6);
3358   CHECK_EQ(len, 1);
3359   CHECK_EQ(strncmp("e\0", buf, 2), 0);
3360 
3361   memset(buf, 0x1, sizeof(buf));
3362   len = str->WriteAscii(buf, 4, 1);
3363   CHECK_EQ(len, 1);
3364   CHECK_EQ(strncmp("e\1", buf, 2), 0);
3365 }
3366 
3367 
THREADED_TEST(ToArrayIndex)3368 THREADED_TEST(ToArrayIndex) {
3369   v8::HandleScope scope;
3370   LocalContext context;
3371 
3372   v8::Handle<String> str = v8_str("42");
3373   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
3374   CHECK(!index.IsEmpty());
3375   CHECK_EQ(42.0, index->Uint32Value());
3376   str = v8_str("42asdf");
3377   index = str->ToArrayIndex();
3378   CHECK(index.IsEmpty());
3379   str = v8_str("-42");
3380   index = str->ToArrayIndex();
3381   CHECK(index.IsEmpty());
3382   str = v8_str("4294967295");
3383   index = str->ToArrayIndex();
3384   CHECK(!index.IsEmpty());
3385   CHECK_EQ(4294967295.0, index->Uint32Value());
3386   v8::Handle<v8::Number> num = v8::Number::New(1);
3387   index = num->ToArrayIndex();
3388   CHECK(!index.IsEmpty());
3389   CHECK_EQ(1.0, index->Uint32Value());
3390   num = v8::Number::New(-1);
3391   index = num->ToArrayIndex();
3392   CHECK(index.IsEmpty());
3393   v8::Handle<v8::Object> obj = v8::Object::New();
3394   index = obj->ToArrayIndex();
3395   CHECK(index.IsEmpty());
3396 }
3397 
3398 
THREADED_TEST(ErrorConstruction)3399 THREADED_TEST(ErrorConstruction) {
3400   v8::HandleScope scope;
3401   LocalContext context;
3402 
3403   v8::Handle<String> foo = v8_str("foo");
3404   v8::Handle<String> message = v8_str("message");
3405   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
3406   CHECK(range_error->IsObject());
3407   v8::Handle<v8::Object> range_obj(v8::Handle<v8::Object>::Cast(range_error));
3408   CHECK(v8::Handle<v8::Object>::Cast(range_error)->Get(message)->Equals(foo));
3409   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
3410   CHECK(reference_error->IsObject());
3411   CHECK(
3412       v8::Handle<v8::Object>::Cast(reference_error)->Get(message)->Equals(foo));
3413   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
3414   CHECK(syntax_error->IsObject());
3415   CHECK(v8::Handle<v8::Object>::Cast(syntax_error)->Get(message)->Equals(foo));
3416   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
3417   CHECK(type_error->IsObject());
3418   CHECK(v8::Handle<v8::Object>::Cast(type_error)->Get(message)->Equals(foo));
3419   v8::Handle<Value> error = v8::Exception::Error(foo);
3420   CHECK(error->IsObject());
3421   CHECK(v8::Handle<v8::Object>::Cast(error)->Get(message)->Equals(foo));
3422 }
3423 
3424 
YGetter(Local<String> name,const AccessorInfo & info)3425 static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) {
3426   ApiTestFuzzer::Fuzz();
3427   return v8_num(10);
3428 }
3429 
3430 
YSetter(Local<String> name,Local<Value> value,const AccessorInfo & info)3431 static void YSetter(Local<String> name,
3432                     Local<Value> value,
3433                     const AccessorInfo& info) {
3434   if (info.This()->Has(name)) {
3435     info.This()->Delete(name);
3436   }
3437   info.This()->Set(name, value);
3438 }
3439 
3440 
THREADED_TEST(DeleteAccessor)3441 THREADED_TEST(DeleteAccessor) {
3442   v8::HandleScope scope;
3443   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
3444   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
3445   LocalContext context;
3446   v8::Handle<v8::Object> holder = obj->NewInstance();
3447   context->Global()->Set(v8_str("holder"), holder);
3448   v8::Handle<Value> result = CompileRun(
3449       "holder.y = 11; holder.y = 12; holder.y");
3450   CHECK_EQ(12, result->Uint32Value());
3451 }
3452 
3453 
THREADED_TEST(TypeSwitch)3454 THREADED_TEST(TypeSwitch) {
3455   v8::HandleScope scope;
3456   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
3457   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
3458   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
3459   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
3460   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
3461   LocalContext context;
3462   v8::Handle<v8::Object> obj0 = v8::Object::New();
3463   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
3464   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
3465   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
3466   for (int i = 0; i < 10; i++) {
3467     CHECK_EQ(0, type_switch->match(obj0));
3468     CHECK_EQ(1, type_switch->match(obj1));
3469     CHECK_EQ(2, type_switch->match(obj2));
3470     CHECK_EQ(3, type_switch->match(obj3));
3471     CHECK_EQ(3, type_switch->match(obj3));
3472     CHECK_EQ(2, type_switch->match(obj2));
3473     CHECK_EQ(1, type_switch->match(obj1));
3474     CHECK_EQ(0, type_switch->match(obj0));
3475   }
3476 }
3477 
3478 
3479 // For use within the TestSecurityHandler() test.
3480 static bool g_security_callback_result = false;
NamedSecurityTestCallback(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)3481 static bool NamedSecurityTestCallback(Local<v8::Object> global,
3482                                       Local<Value> name,
3483                                       v8::AccessType type,
3484                                       Local<Value> data) {
3485   // Always allow read access.
3486   if (type == v8::ACCESS_GET)
3487     return true;
3488 
3489   // Sometimes allow other access.
3490   return g_security_callback_result;
3491 }
3492 
3493 
IndexedSecurityTestCallback(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)3494 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
3495                                         uint32_t key,
3496                                         v8::AccessType type,
3497                                         Local<Value> data) {
3498   // Always allow read access.
3499   if (type == v8::ACCESS_GET)
3500     return true;
3501 
3502   // Sometimes allow other access.
3503   return g_security_callback_result;
3504 }
3505 
3506 
3507 static int trouble_nesting = 0;
TroubleCallback(const v8::Arguments & args)3508 static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) {
3509   ApiTestFuzzer::Fuzz();
3510   trouble_nesting++;
3511 
3512   // Call a JS function that throws an uncaught exception.
3513   Local<v8::Object> arg_this = Context::GetCurrent()->Global();
3514   Local<Value> trouble_callee = (trouble_nesting == 3) ?
3515     arg_this->Get(v8_str("trouble_callee")) :
3516     arg_this->Get(v8_str("trouble_caller"));
3517   CHECK(trouble_callee->IsFunction());
3518   return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL);
3519 }
3520 
3521 
3522 static int report_count = 0;
ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,v8::Handle<Value>)3523 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
3524                                              v8::Handle<Value>) {
3525   report_count++;
3526 }
3527 
3528 
3529 // Counts uncaught exceptions, but other tests running in parallel
3530 // also have uncaught exceptions.
TEST(ApiUncaughtException)3531 TEST(ApiUncaughtException) {
3532   report_count = 0;
3533   v8::HandleScope scope;
3534   LocalContext env;
3535   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
3536 
3537   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
3538   v8::Local<v8::Object> global = env->Global();
3539   global->Set(v8_str("trouble"), fun->GetFunction());
3540 
3541   Script::Compile(v8_str("function trouble_callee() {"
3542                          "  var x = null;"
3543                          "  return x.foo;"
3544                          "};"
3545                          "function trouble_caller() {"
3546                          "  trouble();"
3547                          "};"))->Run();
3548   Local<Value> trouble = global->Get(v8_str("trouble"));
3549   CHECK(trouble->IsFunction());
3550   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
3551   CHECK(trouble_callee->IsFunction());
3552   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
3553   CHECK(trouble_caller->IsFunction());
3554   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
3555   CHECK_EQ(1, report_count);
3556   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
3557 }
3558 
3559 
TEST(CompilationErrorUsingTryCatchHandler)3560 TEST(CompilationErrorUsingTryCatchHandler) {
3561   v8::HandleScope scope;
3562   LocalContext env;
3563   v8::TryCatch try_catch;
3564   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
3565   CHECK_NE(NULL, *try_catch.Exception());
3566   CHECK(try_catch.HasCaught());
3567 }
3568 
3569 
TEST(TryCatchFinallyUsingTryCatchHandler)3570 TEST(TryCatchFinallyUsingTryCatchHandler) {
3571   v8::HandleScope scope;
3572   LocalContext env;
3573   v8::TryCatch try_catch;
3574   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
3575   CHECK(!try_catch.HasCaught());
3576   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
3577   CHECK(try_catch.HasCaught());
3578   try_catch.Reset();
3579   Script::Compile(v8_str("(function() {"
3580                          "try { throw ''; } finally { return; }"
3581                          "})()"))->Run();
3582   CHECK(!try_catch.HasCaught());
3583   Script::Compile(v8_str("(function()"
3584                          "  { try { throw ''; } finally { throw 0; }"
3585                          "})()"))->Run();
3586   CHECK(try_catch.HasCaught());
3587 }
3588 
3589 
3590 // SecurityHandler can't be run twice
TEST(SecurityHandler)3591 TEST(SecurityHandler) {
3592   v8::HandleScope scope0;
3593   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3594   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
3595                                            IndexedSecurityTestCallback);
3596   // Create an environment
3597   v8::Persistent<Context> context0 =
3598     Context::New(NULL, global_template);
3599   context0->Enter();
3600 
3601   v8::Handle<v8::Object> global0 = context0->Global();
3602   v8::Handle<Script> script0 = v8_compile("foo = 111");
3603   script0->Run();
3604   global0->Set(v8_str("0"), v8_num(999));
3605   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
3606   CHECK_EQ(111, foo0->Int32Value());
3607   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
3608   CHECK_EQ(999, z0->Int32Value());
3609 
3610   // Create another environment, should fail security checks.
3611   v8::HandleScope scope1;
3612 
3613   v8::Persistent<Context> context1 =
3614     Context::New(NULL, global_template);
3615   context1->Enter();
3616 
3617   v8::Handle<v8::Object> global1 = context1->Global();
3618   global1->Set(v8_str("othercontext"), global0);
3619   // This set will fail the security check.
3620   v8::Handle<Script> script1 =
3621     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
3622   script1->Run();
3623   // This read will pass the security check.
3624   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
3625   CHECK_EQ(111, foo1->Int32Value());
3626   // This read will pass the security check.
3627   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
3628   CHECK_EQ(999, z1->Int32Value());
3629 
3630   // Create another environment, should pass security checks.
3631   { g_security_callback_result = true;  // allow security handler to pass.
3632     v8::HandleScope scope2;
3633     LocalContext context2;
3634     v8::Handle<v8::Object> global2 = context2->Global();
3635     global2->Set(v8_str("othercontext"), global0);
3636     v8::Handle<Script> script2 =
3637         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
3638     script2->Run();
3639     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
3640     CHECK_EQ(333, foo2->Int32Value());
3641     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
3642     CHECK_EQ(888, z2->Int32Value());
3643   }
3644 
3645   context1->Exit();
3646   context1.Dispose();
3647 
3648   context0->Exit();
3649   context0.Dispose();
3650 }
3651 
3652 
THREADED_TEST(SecurityChecks)3653 THREADED_TEST(SecurityChecks) {
3654   v8::HandleScope handle_scope;
3655   LocalContext env1;
3656   v8::Persistent<Context> env2 = Context::New();
3657 
3658   Local<Value> foo = v8_str("foo");
3659   Local<Value> bar = v8_str("bar");
3660 
3661   // Set to the same domain.
3662   env1->SetSecurityToken(foo);
3663 
3664   // Create a function in env1.
3665   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
3666   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
3667   CHECK(spy->IsFunction());
3668 
3669   // Create another function accessing global objects.
3670   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
3671   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
3672   CHECK(spy2->IsFunction());
3673 
3674   // Switch to env2 in the same domain and invoke spy on env2.
3675   {
3676     env2->SetSecurityToken(foo);
3677     // Enter env2
3678     Context::Scope scope_env2(env2);
3679     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
3680     CHECK(result->IsFunction());
3681   }
3682 
3683   {
3684     env2->SetSecurityToken(bar);
3685     Context::Scope scope_env2(env2);
3686 
3687     // Call cross_domain_call, it should throw an exception
3688     v8::TryCatch try_catch;
3689     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
3690     CHECK(try_catch.HasCaught());
3691   }
3692 
3693   env2.Dispose();
3694 }
3695 
3696 
3697 // Regression test case for issue 1183439.
THREADED_TEST(SecurityChecksForPrototypeChain)3698 THREADED_TEST(SecurityChecksForPrototypeChain) {
3699   v8::HandleScope scope;
3700   LocalContext current;
3701   v8::Persistent<Context> other = Context::New();
3702 
3703   // Change context to be able to get to the Object function in the
3704   // other context without hitting the security checks.
3705   v8::Local<Value> other_object;
3706   { Context::Scope scope(other);
3707     other_object = other->Global()->Get(v8_str("Object"));
3708     other->Global()->Set(v8_num(42), v8_num(87));
3709   }
3710 
3711   current->Global()->Set(v8_str("other"), other->Global());
3712   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
3713 
3714   // Make sure the security check fails here and we get an undefined
3715   // result instead of getting the Object function. Repeat in a loop
3716   // to make sure to exercise the IC code.
3717   v8::Local<Script> access_other0 = v8_compile("other.Object");
3718   v8::Local<Script> access_other1 = v8_compile("other[42]");
3719   for (int i = 0; i < 5; i++) {
3720     CHECK(!access_other0->Run()->Equals(other_object));
3721     CHECK(access_other0->Run()->IsUndefined());
3722     CHECK(!access_other1->Run()->Equals(v8_num(87)));
3723     CHECK(access_other1->Run()->IsUndefined());
3724   }
3725 
3726   // Create an object that has 'other' in its prototype chain and make
3727   // sure we cannot access the Object function indirectly through
3728   // that. Repeat in a loop to make sure to exercise the IC code.
3729   v8_compile("function F() { };"
3730              "F.prototype = other;"
3731              "var f = new F();")->Run();
3732   v8::Local<Script> access_f0 = v8_compile("f.Object");
3733   v8::Local<Script> access_f1 = v8_compile("f[42]");
3734   for (int j = 0; j < 5; j++) {
3735     CHECK(!access_f0->Run()->Equals(other_object));
3736     CHECK(access_f0->Run()->IsUndefined());
3737     CHECK(!access_f1->Run()->Equals(v8_num(87)));
3738     CHECK(access_f1->Run()->IsUndefined());
3739   }
3740 
3741   // Now it gets hairy: Set the prototype for the other global object
3742   // to be the current global object. The prototype chain for 'f' now
3743   // goes through 'other' but ends up in the current global object.
3744   { Context::Scope scope(other);
3745     other->Global()->Set(v8_str("__proto__"), current->Global());
3746   }
3747   // Set a named and an index property on the current global
3748   // object. To force the lookup to go through the other global object,
3749   // the properties must not exist in the other global object.
3750   current->Global()->Set(v8_str("foo"), v8_num(100));
3751   current->Global()->Set(v8_num(99), v8_num(101));
3752   // Try to read the properties from f and make sure that the access
3753   // gets stopped by the security checks on the other global object.
3754   Local<Script> access_f2 = v8_compile("f.foo");
3755   Local<Script> access_f3 = v8_compile("f[99]");
3756   for (int k = 0; k < 5; k++) {
3757     CHECK(!access_f2->Run()->Equals(v8_num(100)));
3758     CHECK(access_f2->Run()->IsUndefined());
3759     CHECK(!access_f3->Run()->Equals(v8_num(101)));
3760     CHECK(access_f3->Run()->IsUndefined());
3761   }
3762   other.Dispose();
3763 }
3764 
3765 
THREADED_TEST(CrossDomainDelete)3766 THREADED_TEST(CrossDomainDelete) {
3767   v8::HandleScope handle_scope;
3768   LocalContext env1;
3769   v8::Persistent<Context> env2 = Context::New();
3770 
3771   Local<Value> foo = v8_str("foo");
3772   Local<Value> bar = v8_str("bar");
3773 
3774   // Set to the same domain.
3775   env1->SetSecurityToken(foo);
3776   env2->SetSecurityToken(foo);
3777 
3778   env1->Global()->Set(v8_str("prop"), v8_num(3));
3779   env2->Global()->Set(v8_str("env1"), env1->Global());
3780 
3781   // Change env2 to a different domain and delete env1.prop.
3782   env2->SetSecurityToken(bar);
3783   {
3784     Context::Scope scope_env2(env2);
3785     Local<Value> result =
3786         Script::Compile(v8_str("delete env1.prop"))->Run();
3787     CHECK(result->IsFalse());
3788   }
3789 
3790   // Check that env1.prop still exists.
3791   Local<Value> v = env1->Global()->Get(v8_str("prop"));
3792   CHECK(v->IsNumber());
3793   CHECK_EQ(3, v->Int32Value());
3794 
3795   env2.Dispose();
3796 }
3797 
3798 
THREADED_TEST(CrossDomainIsPropertyEnumerable)3799 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
3800   v8::HandleScope handle_scope;
3801   LocalContext env1;
3802   v8::Persistent<Context> env2 = Context::New();
3803 
3804   Local<Value> foo = v8_str("foo");
3805   Local<Value> bar = v8_str("bar");
3806 
3807   // Set to the same domain.
3808   env1->SetSecurityToken(foo);
3809   env2->SetSecurityToken(foo);
3810 
3811   env1->Global()->Set(v8_str("prop"), v8_num(3));
3812   env2->Global()->Set(v8_str("env1"), env1->Global());
3813 
3814   // env1.prop is enumerable in env2.
3815   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
3816   {
3817     Context::Scope scope_env2(env2);
3818     Local<Value> result = Script::Compile(test)->Run();
3819     CHECK(result->IsTrue());
3820   }
3821 
3822   // Change env2 to a different domain and test again.
3823   env2->SetSecurityToken(bar);
3824   {
3825     Context::Scope scope_env2(env2);
3826     Local<Value> result = Script::Compile(test)->Run();
3827     CHECK(result->IsFalse());
3828   }
3829 
3830   env2.Dispose();
3831 }
3832 
3833 
THREADED_TEST(CrossDomainForIn)3834 THREADED_TEST(CrossDomainForIn) {
3835   v8::HandleScope handle_scope;
3836   LocalContext env1;
3837   v8::Persistent<Context> env2 = Context::New();
3838 
3839   Local<Value> foo = v8_str("foo");
3840   Local<Value> bar = v8_str("bar");
3841 
3842   // Set to the same domain.
3843   env1->SetSecurityToken(foo);
3844   env2->SetSecurityToken(foo);
3845 
3846   env1->Global()->Set(v8_str("prop"), v8_num(3));
3847   env2->Global()->Set(v8_str("env1"), env1->Global());
3848 
3849   // Change env2 to a different domain and set env1's global object
3850   // as the __proto__ of an object in env2 and enumerate properties
3851   // in for-in. It shouldn't enumerate properties on env1's global
3852   // object.
3853   env2->SetSecurityToken(bar);
3854   {
3855     Context::Scope scope_env2(env2);
3856     Local<Value> result =
3857         CompileRun("(function(){var obj = {'__proto__':env1};"
3858                    "for (var p in obj)"
3859                    "   if (p == 'prop') return false;"
3860                    "return true;})()");
3861     CHECK(result->IsTrue());
3862   }
3863   env2.Dispose();
3864 }
3865 
3866 
TEST(ContextDetachGlobal)3867 TEST(ContextDetachGlobal) {
3868   v8::HandleScope handle_scope;
3869   LocalContext env1;
3870   v8::Persistent<Context> env2 = Context::New();
3871 
3872   Local<v8::Object> global1 = env1->Global();
3873 
3874   Local<Value> foo = v8_str("foo");
3875 
3876   // Set to the same domain.
3877   env1->SetSecurityToken(foo);
3878   env2->SetSecurityToken(foo);
3879 
3880   // Enter env2
3881   env2->Enter();
3882 
3883   // Create a function in env1
3884   Local<v8::Object> global2 = env2->Global();
3885   global2->Set(v8_str("prop"), v8::Integer::New(1));
3886   CompileRun("function getProp() {return prop;}");
3887 
3888   env1->Global()->Set(v8_str("getProp"),
3889                       global2->Get(v8_str("getProp")));
3890 
3891   // Detach env1's global, and reuse the global object of env1
3892   env2->Exit();
3893   env2->DetachGlobal();
3894   // env2 has a new global object.
3895   CHECK(!env2->Global()->Equals(global2));
3896 
3897   v8::Persistent<Context> env3 =
3898       Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2);
3899   env3->SetSecurityToken(v8_str("bar"));
3900   env3->Enter();
3901 
3902   Local<v8::Object> global3 = env3->Global();
3903   CHECK_EQ(global2, global3);
3904   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
3905   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
3906   global3->Set(v8_str("prop"), v8::Integer::New(-1));
3907   global3->Set(v8_str("prop2"), v8::Integer::New(2));
3908   env3->Exit();
3909 
3910   // Call getProp in env1, and it should return the value 1
3911   {
3912     Local<Value> get_prop = global1->Get(v8_str("getProp"));
3913     CHECK(get_prop->IsFunction());
3914     v8::TryCatch try_catch;
3915     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
3916     CHECK(!try_catch.HasCaught());
3917     CHECK_EQ(1, r->Int32Value());
3918   }
3919 
3920   // Check that env3 is not accessible from env1
3921   {
3922     Local<Value> r = global3->Get(v8_str("prop2"));
3923     CHECK(r->IsUndefined());
3924   }
3925 
3926   env2.Dispose();
3927   env3.Dispose();
3928 }
3929 
3930 
NamedAccessBlocker(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)3931 static bool NamedAccessBlocker(Local<v8::Object> global,
3932                                Local<Value> name,
3933                                v8::AccessType type,
3934                                Local<Value> data) {
3935   return Context::GetCurrent()->Global()->Equals(global);
3936 }
3937 
3938 
IndexedAccessBlocker(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)3939 static bool IndexedAccessBlocker(Local<v8::Object> global,
3940                                  uint32_t key,
3941                                  v8::AccessType type,
3942                                  Local<Value> data) {
3943   return Context::GetCurrent()->Global()->Equals(global);
3944 }
3945 
3946 
3947 static int g_echo_value = -1;
EchoGetter(Local<String> name,const AccessorInfo & info)3948 static v8::Handle<Value> EchoGetter(Local<String> name,
3949                                     const AccessorInfo& info) {
3950   return v8_num(g_echo_value);
3951 }
3952 
3953 
EchoSetter(Local<String> name,Local<Value> value,const AccessorInfo &)3954 static void EchoSetter(Local<String> name,
3955                        Local<Value> value,
3956                        const AccessorInfo&) {
3957   if (value->IsNumber())
3958     g_echo_value = value->Int32Value();
3959 }
3960 
3961 
UnreachableGetter(Local<String> name,const AccessorInfo & info)3962 static v8::Handle<Value> UnreachableGetter(Local<String> name,
3963                                            const AccessorInfo& info) {
3964   CHECK(false);  // This function should not be called..
3965   return v8::Undefined();
3966 }
3967 
3968 
UnreachableSetter(Local<String>,Local<Value>,const AccessorInfo &)3969 static void UnreachableSetter(Local<String>, Local<Value>,
3970                               const AccessorInfo&) {
3971   CHECK(false);  // This function should nto be called.
3972 }
3973 
3974 
THREADED_TEST(AccessControl)3975 THREADED_TEST(AccessControl) {
3976   v8::HandleScope handle_scope;
3977   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
3978 
3979   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
3980                                            IndexedAccessBlocker);
3981 
3982   // Add an accessor accessible by cross-domain JS code.
3983   global_template->SetAccessor(
3984       v8_str("accessible_prop"),
3985       EchoGetter, EchoSetter,
3986       v8::Handle<Value>(),
3987       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
3988 
3989   // Add an accessor that is not accessible by cross-domain JS code.
3990   global_template->SetAccessor(v8_str("blocked_prop"),
3991                                UnreachableGetter, UnreachableSetter,
3992                                v8::Handle<Value>(),
3993                                v8::DEFAULT);
3994 
3995   // Create an environment
3996   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
3997   context0->Enter();
3998 
3999   v8::Handle<v8::Object> global0 = context0->Global();
4000 
4001   v8::HandleScope scope1;
4002 
4003   v8::Persistent<Context> context1 = Context::New();
4004   context1->Enter();
4005 
4006   v8::Handle<v8::Object> global1 = context1->Global();
4007   global1->Set(v8_str("other"), global0);
4008 
4009   v8::Handle<Value> value;
4010 
4011   // Access blocked property
4012   value = v8_compile("other.blocked_prop = 1")->Run();
4013   value = v8_compile("other.blocked_prop")->Run();
4014   CHECK(value->IsUndefined());
4015 
4016   value = v8_compile("propertyIsEnumerable.call(other, 'blocked_prop')")->Run();
4017   CHECK(value->IsFalse());
4018 
4019   // Access accessible property
4020   value = v8_compile("other.accessible_prop = 3")->Run();
4021   CHECK(value->IsNumber());
4022   CHECK_EQ(3, value->Int32Value());
4023 
4024   value = v8_compile("other.accessible_prop")->Run();
4025   CHECK(value->IsNumber());
4026   CHECK_EQ(3, value->Int32Value());
4027 
4028   value =
4029     v8_compile("propertyIsEnumerable.call(other, 'accessible_prop')")->Run();
4030   CHECK(value->IsTrue());
4031 
4032   // Enumeration doesn't enumerate accessors from inaccessible objects in
4033   // the prototype chain even if the accessors are in themselves accessible.
4034   Local<Value> result =
4035       CompileRun("(function(){var obj = {'__proto__':other};"
4036                  "for (var p in obj)"
4037                  "   if (p == 'accessible_prop' || p == 'blocked_prop') {"
4038                  "     return false;"
4039                  "   }"
4040                  "return true;})()");
4041   CHECK(result->IsTrue());
4042 
4043   context1->Exit();
4044   context0->Exit();
4045   context1.Dispose();
4046   context0.Dispose();
4047 }
4048 
4049 
ConstTenGetter(Local<String> name,const AccessorInfo & info)4050 static v8::Handle<Value> ConstTenGetter(Local<String> name,
4051                                         const AccessorInfo& info) {
4052   return v8_num(10);
4053 }
4054 
4055 
THREADED_TEST(CrossDomainAccessors)4056 THREADED_TEST(CrossDomainAccessors) {
4057   v8::HandleScope handle_scope;
4058 
4059   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
4060 
4061   v8::Handle<v8::ObjectTemplate> global_template =
4062       func_template->InstanceTemplate();
4063 
4064   v8::Handle<v8::ObjectTemplate> proto_template =
4065       func_template->PrototypeTemplate();
4066 
4067   // Add an accessor to proto that's accessible by cross-domain JS code.
4068   proto_template->SetAccessor(v8_str("accessible"),
4069                               ConstTenGetter, 0,
4070                               v8::Handle<Value>(),
4071                               v8::ALL_CAN_READ);
4072 
4073   // Add an accessor that is not accessible by cross-domain JS code.
4074   global_template->SetAccessor(v8_str("unreachable"),
4075                                UnreachableGetter, 0,
4076                                v8::Handle<Value>(),
4077                                v8::DEFAULT);
4078 
4079   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
4080   context0->Enter();
4081 
4082   Local<v8::Object> global = context0->Global();
4083   // Add a normal property that shadows 'accessible'
4084   global->Set(v8_str("accessible"), v8_num(11));
4085 
4086   // Enter a new context.
4087   v8::HandleScope scope1;
4088   v8::Persistent<Context> context1 = Context::New();
4089   context1->Enter();
4090 
4091   v8::Handle<v8::Object> global1 = context1->Global();
4092   global1->Set(v8_str("other"), global);
4093 
4094   // Should return 10, instead of 11
4095   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
4096   CHECK(value->IsNumber());
4097   CHECK_EQ(10, value->Int32Value());
4098 
4099   value = v8_compile("other.unreachable")->Run();
4100   CHECK(value->IsUndefined());
4101 
4102   context1->Exit();
4103   context0->Exit();
4104   context1.Dispose();
4105   context0.Dispose();
4106 }
4107 
4108 
4109 static int named_access_count = 0;
4110 static int indexed_access_count = 0;
4111 
NamedAccessCounter(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)4112 static bool NamedAccessCounter(Local<v8::Object> global,
4113                                Local<Value> name,
4114                                v8::AccessType type,
4115                                Local<Value> data) {
4116   named_access_count++;
4117   return true;
4118 }
4119 
4120 
IndexedAccessCounter(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)4121 static bool IndexedAccessCounter(Local<v8::Object> global,
4122                                  uint32_t key,
4123                                  v8::AccessType type,
4124                                  Local<Value> data) {
4125   indexed_access_count++;
4126   return true;
4127 }
4128 
4129 
4130 // This one is too easily disturbed by other tests.
TEST(AccessControlIC)4131 TEST(AccessControlIC) {
4132   named_access_count = 0;
4133   indexed_access_count = 0;
4134 
4135   v8::HandleScope handle_scope;
4136 
4137   // Create an environment.
4138   v8::Persistent<Context> context0 = Context::New();
4139   context0->Enter();
4140 
4141   // Create an object that requires access-check functions to be
4142   // called for cross-domain access.
4143   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4144   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4145                                            IndexedAccessCounter);
4146   Local<v8::Object> object = object_template->NewInstance();
4147 
4148   v8::HandleScope scope1;
4149 
4150   // Create another environment.
4151   v8::Persistent<Context> context1 = Context::New();
4152   context1->Enter();
4153 
4154   // Make easy access to the object from the other environment.
4155   v8::Handle<v8::Object> global1 = context1->Global();
4156   global1->Set(v8_str("obj"), object);
4157 
4158   v8::Handle<Value> value;
4159 
4160   // Check that the named access-control function is called every time.
4161   CompileRun("function testProp(obj) {"
4162              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
4163              "  for (var j = 0; j < 10; j++) obj.prop;"
4164              "  return obj.prop"
4165              "}");
4166   value = CompileRun("testProp(obj)");
4167   CHECK(value->IsNumber());
4168   CHECK_EQ(1, value->Int32Value());
4169   CHECK_EQ(21, named_access_count);
4170 
4171   // Check that the named access-control function is called every time.
4172   CompileRun("var p = 'prop';"
4173              "function testKeyed(obj) {"
4174              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
4175              "  for (var j = 0; j < 10; j++) obj[p];"
4176              "  return obj[p];"
4177              "}");
4178   // Use obj which requires access checks.  No inline caching is used
4179   // in that case.
4180   value = CompileRun("testKeyed(obj)");
4181   CHECK(value->IsNumber());
4182   CHECK_EQ(1, value->Int32Value());
4183   CHECK_EQ(42, named_access_count);
4184   // Force the inline caches into generic state and try again.
4185   CompileRun("testKeyed({ a: 0 })");
4186   CompileRun("testKeyed({ b: 0 })");
4187   value = CompileRun("testKeyed(obj)");
4188   CHECK(value->IsNumber());
4189   CHECK_EQ(1, value->Int32Value());
4190   CHECK_EQ(63, named_access_count);
4191 
4192   // Check that the indexed access-control function is called every time.
4193   CompileRun("function testIndexed(obj) {"
4194              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
4195              "  for (var j = 0; j < 10; j++) obj[0];"
4196              "  return obj[0]"
4197              "}");
4198   value = CompileRun("testIndexed(obj)");
4199   CHECK(value->IsNumber());
4200   CHECK_EQ(1, value->Int32Value());
4201   CHECK_EQ(21, indexed_access_count);
4202   // Force the inline caches into generic state.
4203   CompileRun("testIndexed(new Array(1))");
4204   // Test that the indexed access check is called.
4205   value = CompileRun("testIndexed(obj)");
4206   CHECK(value->IsNumber());
4207   CHECK_EQ(1, value->Int32Value());
4208   CHECK_EQ(42, indexed_access_count);
4209 
4210   // Check that the named access check is called when invoking
4211   // functions on an object that requires access checks.
4212   CompileRun("obj.f = function() {}");
4213   CompileRun("function testCallNormal(obj) {"
4214              "  for (var i = 0; i < 10; i++) obj.f();"
4215              "}");
4216   CompileRun("testCallNormal(obj)");
4217   CHECK_EQ(74, named_access_count);
4218 
4219   // Force obj into slow case.
4220   value = CompileRun("delete obj.prop");
4221   CHECK(value->BooleanValue());
4222   // Force inline caches into dictionary probing mode.
4223   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
4224   // Test that the named access check is called.
4225   value = CompileRun("testProp(obj);");
4226   CHECK(value->IsNumber());
4227   CHECK_EQ(1, value->Int32Value());
4228   CHECK_EQ(96, named_access_count);
4229 
4230   // Force the call inline cache into dictionary probing mode.
4231   CompileRun("o.f = function() {}; testCallNormal(o)");
4232   // Test that the named access check is still called for each
4233   // invocation of the function.
4234   value = CompileRun("testCallNormal(obj)");
4235   CHECK_EQ(106, named_access_count);
4236 
4237   context1->Exit();
4238   context0->Exit();
4239   context1.Dispose();
4240   context0.Dispose();
4241 }
4242 
4243 
NamedAccessFlatten(Local<v8::Object> global,Local<Value> name,v8::AccessType type,Local<Value> data)4244 static bool NamedAccessFlatten(Local<v8::Object> global,
4245                                Local<Value> name,
4246                                v8::AccessType type,
4247                                Local<Value> data) {
4248   char buf[100];
4249   int len;
4250 
4251   CHECK(name->IsString());
4252 
4253   memset(buf, 0x1, sizeof(buf));
4254   len = Local<String>::Cast(name)->WriteAscii(buf);
4255   CHECK_EQ(4, len);
4256 
4257   uint16_t buf2[100];
4258 
4259   memset(buf, 0x1, sizeof(buf));
4260   len = Local<String>::Cast(name)->Write(buf2);
4261   CHECK_EQ(4, len);
4262 
4263   return true;
4264 }
4265 
4266 
IndexedAccessFlatten(Local<v8::Object> global,uint32_t key,v8::AccessType type,Local<Value> data)4267 static bool IndexedAccessFlatten(Local<v8::Object> global,
4268                                  uint32_t key,
4269                                  v8::AccessType type,
4270                                  Local<Value> data) {
4271   return true;
4272 }
4273 
4274 
4275 // Regression test.  In access checks, operations that may cause
4276 // garbage collection are not allowed.  It used to be the case that
4277 // using the Write operation on a string could cause a garbage
4278 // collection due to flattening of the string.  This is no longer the
4279 // case.
THREADED_TEST(AccessControlFlatten)4280 THREADED_TEST(AccessControlFlatten) {
4281   named_access_count = 0;
4282   indexed_access_count = 0;
4283 
4284   v8::HandleScope handle_scope;
4285 
4286   // Create an environment.
4287   v8::Persistent<Context> context0 = Context::New();
4288   context0->Enter();
4289 
4290   // Create an object that requires access-check functions to be
4291   // called for cross-domain access.
4292   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4293   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
4294                                            IndexedAccessFlatten);
4295   Local<v8::Object> object = object_template->NewInstance();
4296 
4297   v8::HandleScope scope1;
4298 
4299   // Create another environment.
4300   v8::Persistent<Context> context1 = Context::New();
4301   context1->Enter();
4302 
4303   // Make easy access to the object from the other environment.
4304   v8::Handle<v8::Object> global1 = context1->Global();
4305   global1->Set(v8_str("obj"), object);
4306 
4307   v8::Handle<Value> value;
4308 
4309   value = v8_compile("var p = 'as' + 'df';")->Run();
4310   value = v8_compile("obj[p];")->Run();
4311 
4312   context1->Exit();
4313   context0->Exit();
4314   context1.Dispose();
4315   context0.Dispose();
4316 }
4317 
4318 
AccessControlNamedGetter(Local<String>,const AccessorInfo &)4319 static v8::Handle<Value> AccessControlNamedGetter(
4320     Local<String>, const AccessorInfo&) {
4321   return v8::Integer::New(42);
4322 }
4323 
4324 
AccessControlNamedSetter(Local<String>,Local<Value> value,const AccessorInfo &)4325 static v8::Handle<Value> AccessControlNamedSetter(
4326     Local<String>, Local<Value> value, const AccessorInfo&) {
4327   return value;
4328 }
4329 
4330 
AccessControlIndexedGetter(uint32_t index,const AccessorInfo & info)4331 static v8::Handle<Value> AccessControlIndexedGetter(
4332       uint32_t index,
4333       const AccessorInfo& info) {
4334   return v8_num(42);
4335 }
4336 
4337 
AccessControlIndexedSetter(uint32_t,Local<Value> value,const AccessorInfo &)4338 static v8::Handle<Value> AccessControlIndexedSetter(
4339     uint32_t, Local<Value> value, const AccessorInfo&) {
4340   return value;
4341 }
4342 
4343 
THREADED_TEST(AccessControlInterceptorIC)4344 THREADED_TEST(AccessControlInterceptorIC) {
4345   named_access_count = 0;
4346   indexed_access_count = 0;
4347 
4348   v8::HandleScope handle_scope;
4349 
4350   // Create an environment.
4351   v8::Persistent<Context> context0 = Context::New();
4352   context0->Enter();
4353 
4354   // Create an object that requires access-check functions to be
4355   // called for cross-domain access.  The object also has interceptors
4356   // interceptor.
4357   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
4358   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
4359                                            IndexedAccessCounter);
4360   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
4361                                            AccessControlNamedSetter);
4362   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
4363                                              AccessControlIndexedSetter);
4364   Local<v8::Object> object = object_template->NewInstance();
4365 
4366   v8::HandleScope scope1;
4367 
4368   // Create another environment.
4369   v8::Persistent<Context> context1 = Context::New();
4370   context1->Enter();
4371 
4372   // Make easy access to the object from the other environment.
4373   v8::Handle<v8::Object> global1 = context1->Global();
4374   global1->Set(v8_str("obj"), object);
4375 
4376   v8::Handle<Value> value;
4377 
4378   // Check that the named access-control function is called every time
4379   // eventhough there is an interceptor on the object.
4380   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
4381   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
4382                      "obj.x")->Run();
4383   CHECK(value->IsNumber());
4384   CHECK_EQ(42, value->Int32Value());
4385   CHECK_EQ(21, named_access_count);
4386 
4387   value = v8_compile("var p = 'x';")->Run();
4388   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
4389   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
4390                      "obj[p]")->Run();
4391   CHECK(value->IsNumber());
4392   CHECK_EQ(42, value->Int32Value());
4393   CHECK_EQ(42, named_access_count);
4394 
4395   // Check that the indexed access-control function is called every
4396   // time eventhough there is an interceptor on the object.
4397   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
4398   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
4399                      "obj[0]")->Run();
4400   CHECK(value->IsNumber());
4401   CHECK_EQ(42, value->Int32Value());
4402   CHECK_EQ(21, indexed_access_count);
4403 
4404   context1->Exit();
4405   context0->Exit();
4406   context1.Dispose();
4407   context0.Dispose();
4408 }
4409 
4410 
THREADED_TEST(Version)4411 THREADED_TEST(Version) {
4412   v8::V8::GetVersion();
4413 }
4414 
4415 
InstanceFunctionCallback(const v8::Arguments & args)4416 static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) {
4417   ApiTestFuzzer::Fuzz();
4418   return v8_num(12);
4419 }
4420 
4421 
THREADED_TEST(InstanceProperties)4422 THREADED_TEST(InstanceProperties) {
4423   v8::HandleScope handle_scope;
4424   LocalContext context;
4425 
4426   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4427   Local<ObjectTemplate> instance = t->InstanceTemplate();
4428 
4429   instance->Set(v8_str("x"), v8_num(42));
4430   instance->Set(v8_str("f"),
4431                 v8::FunctionTemplate::New(InstanceFunctionCallback));
4432 
4433   Local<Value> o = t->GetFunction()->NewInstance();
4434 
4435   context->Global()->Set(v8_str("i"), o);
4436   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
4437   CHECK_EQ(42, value->Int32Value());
4438 
4439   value = Script::Compile(v8_str("i.f()"))->Run();
4440   CHECK_EQ(12, value->Int32Value());
4441 }
4442 
4443 
4444 static v8::Handle<Value>
GlobalObjectInstancePropertiesGet(Local<String> key,const AccessorInfo &)4445 GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) {
4446   ApiTestFuzzer::Fuzz();
4447   return v8::Handle<Value>();
4448 }
4449 
4450 
THREADED_TEST(GlobalObjectInstanceProperties)4451 THREADED_TEST(GlobalObjectInstanceProperties) {
4452   v8::HandleScope handle_scope;
4453 
4454   Local<Value> global_object;
4455 
4456   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4457   t->InstanceTemplate()->SetNamedPropertyHandler(
4458       GlobalObjectInstancePropertiesGet);
4459   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4460   instance_template->Set(v8_str("x"), v8_num(42));
4461   instance_template->Set(v8_str("f"),
4462                          v8::FunctionTemplate::New(InstanceFunctionCallback));
4463 
4464   {
4465     LocalContext env(NULL, instance_template);
4466     // Hold on to the global object so it can be used again in another
4467     // environment initialization.
4468     global_object = env->Global();
4469 
4470     Local<Value> value = Script::Compile(v8_str("x"))->Run();
4471     CHECK_EQ(42, value->Int32Value());
4472     value = Script::Compile(v8_str("f()"))->Run();
4473     CHECK_EQ(12, value->Int32Value());
4474   }
4475 
4476   {
4477     // Create new environment reusing the global object.
4478     LocalContext env(NULL, instance_template, global_object);
4479     Local<Value> value = Script::Compile(v8_str("x"))->Run();
4480     CHECK_EQ(42, value->Int32Value());
4481     value = Script::Compile(v8_str("f()"))->Run();
4482     CHECK_EQ(12, value->Int32Value());
4483   }
4484 }
4485 
4486 
ShadowFunctionCallback(const v8::Arguments & args)4487 static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) {
4488   ApiTestFuzzer::Fuzz();
4489   return v8_num(42);
4490 }
4491 
4492 
4493 static int shadow_y;
4494 static int shadow_y_setter_call_count;
4495 static int shadow_y_getter_call_count;
4496 
4497 
ShadowYSetter(Local<String>,Local<Value>,const AccessorInfo &)4498 static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) {
4499   shadow_y_setter_call_count++;
4500   shadow_y = 42;
4501 }
4502 
4503 
ShadowYGetter(Local<String> name,const AccessorInfo & info)4504 static v8::Handle<Value> ShadowYGetter(Local<String> name,
4505                                        const AccessorInfo& info) {
4506   ApiTestFuzzer::Fuzz();
4507   shadow_y_getter_call_count++;
4508   return v8_num(shadow_y);
4509 }
4510 
4511 
ShadowIndexedGet(uint32_t index,const AccessorInfo & info)4512 static v8::Handle<Value> ShadowIndexedGet(uint32_t index,
4513                                           const AccessorInfo& info) {
4514   return v8::Handle<Value>();
4515 }
4516 
4517 
ShadowNamedGet(Local<String> key,const AccessorInfo &)4518 static v8::Handle<Value> ShadowNamedGet(Local<String> key,
4519                                         const AccessorInfo&) {
4520   return v8::Handle<Value>();
4521 }
4522 
4523 
THREADED_TEST(ShadowObject)4524 THREADED_TEST(ShadowObject) {
4525   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
4526   v8::HandleScope handle_scope;
4527 
4528   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
4529   LocalContext context(NULL, global_template);
4530 
4531   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4532   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
4533   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
4534   Local<ObjectTemplate> proto = t->PrototypeTemplate();
4535   Local<ObjectTemplate> instance = t->InstanceTemplate();
4536 
4537   // Only allow calls of f on instances of t.
4538   Local<v8::Signature> signature = v8::Signature::New(t);
4539   proto->Set(v8_str("f"),
4540              v8::FunctionTemplate::New(ShadowFunctionCallback,
4541                                        Local<Value>(),
4542                                        signature));
4543   proto->Set(v8_str("x"), v8_num(12));
4544 
4545   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
4546 
4547   Local<Value> o = t->GetFunction()->NewInstance();
4548   context->Global()->Set(v8_str("__proto__"), o);
4549 
4550   Local<Value> value =
4551       Script::Compile(v8_str("propertyIsEnumerable(0)"))->Run();
4552   CHECK(value->IsBoolean());
4553   CHECK(!value->BooleanValue());
4554 
4555   value = Script::Compile(v8_str("x"))->Run();
4556   CHECK_EQ(12, value->Int32Value());
4557 
4558   value = Script::Compile(v8_str("f()"))->Run();
4559   CHECK_EQ(42, value->Int32Value());
4560 
4561   Script::Compile(v8_str("y = 42"))->Run();
4562   CHECK_EQ(1, shadow_y_setter_call_count);
4563   value = Script::Compile(v8_str("y"))->Run();
4564   CHECK_EQ(1, shadow_y_getter_call_count);
4565   CHECK_EQ(42, value->Int32Value());
4566 }
4567 
4568 
THREADED_TEST(HiddenPrototype)4569 THREADED_TEST(HiddenPrototype) {
4570   v8::HandleScope handle_scope;
4571   LocalContext context;
4572 
4573   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4574   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
4575   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4576   t1->SetHiddenPrototype(true);
4577   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
4578   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4579   t2->SetHiddenPrototype(true);
4580   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
4581   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4582   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
4583 
4584   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
4585   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
4586   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
4587   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
4588 
4589   // Setting the prototype on an object skips hidden prototypes.
4590   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4591   o0->Set(v8_str("__proto__"), o1);
4592   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4593   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4594   o0->Set(v8_str("__proto__"), o2);
4595   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4596   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4597   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4598   o0->Set(v8_str("__proto__"), o3);
4599   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
4600   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
4601   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
4602   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
4603 
4604   // Getting the prototype of o0 should get the first visible one
4605   // which is o3.  Therefore, z should not be defined on the prototype
4606   // object.
4607   Local<Value> proto = o0->Get(v8_str("__proto__"));
4608   CHECK(proto->IsObject());
4609   CHECK(Local<v8::Object>::Cast(proto)->Get(v8_str("z"))->IsUndefined());
4610 }
4611 
4612 
THREADED_TEST(GetterSetterExceptions)4613 THREADED_TEST(GetterSetterExceptions) {
4614   v8::HandleScope handle_scope;
4615   LocalContext context;
4616   CompileRun(
4617     "function Foo() { };"
4618     "function Throw() { throw 5; };"
4619     "var x = { };"
4620     "x.__defineSetter__('set', Throw);"
4621     "x.__defineGetter__('get', Throw);");
4622   Local<v8::Object> x =
4623       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
4624   v8::TryCatch try_catch;
4625   x->Set(v8_str("set"), v8::Integer::New(8));
4626   x->Get(v8_str("get"));
4627   x->Set(v8_str("set"), v8::Integer::New(8));
4628   x->Get(v8_str("get"));
4629   x->Set(v8_str("set"), v8::Integer::New(8));
4630   x->Get(v8_str("get"));
4631   x->Set(v8_str("set"), v8::Integer::New(8));
4632   x->Get(v8_str("get"));
4633 }
4634 
4635 
THREADED_TEST(Constructor)4636 THREADED_TEST(Constructor) {
4637   v8::HandleScope handle_scope;
4638   LocalContext context;
4639   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4640   templ->SetClassName(v8_str("Fun"));
4641   Local<Function> cons = templ->GetFunction();
4642   context->Global()->Set(v8_str("Fun"), cons);
4643   Local<v8::Object> inst = cons->NewInstance();
4644   i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst);
4645   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
4646   CHECK(value->BooleanValue());
4647 }
4648 
THREADED_TEST(FunctionDescriptorException)4649 THREADED_TEST(FunctionDescriptorException) {
4650   v8::HandleScope handle_scope;
4651   LocalContext context;
4652   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
4653   templ->SetClassName(v8_str("Fun"));
4654   Local<Function> cons = templ->GetFunction();
4655   context->Global()->Set(v8_str("Fun"), cons);
4656   Local<Value> value = CompileRun(
4657     "function test() {"
4658     "  try {"
4659     "    (new Fun()).blah()"
4660     "  } catch (e) {"
4661     "    var str = String(e);"
4662     "    if (str.indexOf('TypeError') == -1) return 1;"
4663     "    if (str.indexOf('[object Fun]') != -1) return 2;"
4664     "    if (str.indexOf('#<a Fun>') == -1) return 3;"
4665     "    return 0;"
4666     "  }"
4667     "  return 4;"
4668     "}"
4669     "test();");
4670   CHECK_EQ(0, value->Int32Value());
4671 }
4672 
4673 
THREADED_TEST(EvalAliasedDynamic)4674 THREADED_TEST(EvalAliasedDynamic) {
4675   v8::HandleScope scope;
4676   LocalContext current;
4677 
4678   // Tests where aliased eval can only be resolved dynamically.
4679   Local<Script> script =
4680       Script::Compile(v8_str("function f(x) { "
4681                              "  var foo = 2;"
4682                              "  with (x) { return eval('foo'); }"
4683                              "}"
4684                              "foo = 0;"
4685                              "result1 = f(new Object());"
4686                              "result2 = f(this);"
4687                              "var x = new Object();"
4688                              "x.eval = function(x) { return 1; };"
4689                              "result3 = f(x);"));
4690   script->Run();
4691   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
4692   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
4693   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
4694 
4695   v8::TryCatch try_catch;
4696   script =
4697     Script::Compile(v8_str("function f(x) { "
4698                            "  var bar = 2;"
4699                            "  with (x) { return eval('bar'); }"
4700                            "}"
4701                            "f(this)"));
4702   script->Run();
4703   CHECK(try_catch.HasCaught());
4704   try_catch.Reset();
4705 }
4706 
4707 
THREADED_TEST(CrossEval)4708 THREADED_TEST(CrossEval) {
4709   v8::HandleScope scope;
4710   LocalContext other;
4711   LocalContext current;
4712 
4713   Local<String> token = v8_str("<security token>");
4714   other->SetSecurityToken(token);
4715   current->SetSecurityToken(token);
4716 
4717   // Setup reference from current to other.
4718   current->Global()->Set(v8_str("other"), other->Global());
4719 
4720   // Check that new variables are introduced in other context.
4721   Local<Script> script =
4722       Script::Compile(v8_str("other.eval('var foo = 1234')"));
4723   script->Run();
4724   Local<Value> foo = other->Global()->Get(v8_str("foo"));
4725   CHECK_EQ(1234, foo->Int32Value());
4726   CHECK(!current->Global()->Has(v8_str("foo")));
4727 
4728   // Check that writing to non-existing properties introduces them in
4729   // the other context.
4730   script =
4731       Script::Compile(v8_str("other.eval('na = 1234')"));
4732   script->Run();
4733   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
4734   CHECK(!current->Global()->Has(v8_str("na")));
4735 
4736   // Check that global variables in current context are not visible in other
4737   // context.
4738   v8::TryCatch try_catch;
4739   script =
4740       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
4741   Local<Value> result = script->Run();
4742   CHECK(try_catch.HasCaught());
4743   try_catch.Reset();
4744 
4745   // Check that local variables in current context are not visible in other
4746   // context.
4747   script =
4748       Script::Compile(v8_str("(function() { "
4749                              "  var baz = 87;"
4750                              "  return other.eval('baz');"
4751                              "})();"));
4752   result = script->Run();
4753   CHECK(try_catch.HasCaught());
4754   try_catch.Reset();
4755 
4756   // Check that global variables in the other environment are visible
4757   // when evaluting code.
4758   other->Global()->Set(v8_str("bis"), v8_num(1234));
4759   script = Script::Compile(v8_str("other.eval('bis')"));
4760   CHECK_EQ(1234, script->Run()->Int32Value());
4761   CHECK(!try_catch.HasCaught());
4762 
4763   // Check that the 'this' pointer points to the global object evaluating
4764   // code.
4765   other->Global()->Set(v8_str("t"), other->Global());
4766   script = Script::Compile(v8_str("other.eval('this == t')"));
4767   result = script->Run();
4768   CHECK(result->IsTrue());
4769   CHECK(!try_catch.HasCaught());
4770 
4771   // Check that variables introduced in with-statement are not visible in
4772   // other context.
4773   script =
4774       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
4775   result = script->Run();
4776   CHECK(try_catch.HasCaught());
4777   try_catch.Reset();
4778 
4779   // Check that you cannot use 'eval.call' with another object than the
4780   // current global object.
4781   script =
4782       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
4783   result = script->Run();
4784   CHECK(try_catch.HasCaught());
4785 }
4786 
4787 
4788 // Test that calling eval in a context which has been detached from
4789 // its global throws an exception.  This behavior is consistent with
4790 // other JavaScript implementations.
THREADED_TEST(EvalInDetachedGlobal)4791 THREADED_TEST(EvalInDetachedGlobal) {
4792   v8::HandleScope scope;
4793 
4794   v8::Persistent<Context> context0 = Context::New();
4795   v8::Persistent<Context> context1 = Context::New();
4796 
4797   // Setup function in context0 that uses eval from context0.
4798   context0->Enter();
4799   v8::Handle<v8::Value> fun =
4800       CompileRun("var x = 42;"
4801                  "(function() {"
4802                  "  var e = eval;"
4803                  "  return function(s) { return e(s); }"
4804                  "})()");
4805   context0->Exit();
4806 
4807   // Put the function into context1 and call it before and after
4808   // detaching the global.  Before detaching, the call succeeds and
4809   // after detaching and exception is thrown.
4810   context1->Enter();
4811   context1->Global()->Set(v8_str("fun"), fun);
4812   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
4813   CHECK_EQ(42, x_value->Int32Value());
4814   context0->DetachGlobal();
4815   v8::TryCatch catcher;
4816   x_value = CompileRun("fun('x')");
4817   CHECK(x_value.IsEmpty());
4818   CHECK(catcher.HasCaught());
4819   context1->Exit();
4820 
4821   context1.Dispose();
4822   context0.Dispose();
4823 }
4824 
4825 
THREADED_TEST(CrossLazyLoad)4826 THREADED_TEST(CrossLazyLoad) {
4827   v8::HandleScope scope;
4828   LocalContext other;
4829   LocalContext current;
4830 
4831   Local<String> token = v8_str("<security token>");
4832   other->SetSecurityToken(token);
4833   current->SetSecurityToken(token);
4834 
4835   // Setup reference from current to other.
4836   current->Global()->Set(v8_str("other"), other->Global());
4837 
4838   // Trigger lazy loading in other context.
4839   Local<Script> script =
4840       Script::Compile(v8_str("other.eval('new Date(42)')"));
4841   Local<Value> value = script->Run();
4842   CHECK_EQ(42.0, value->NumberValue());
4843 }
4844 
4845 
call_as_function(const v8::Arguments & args)4846 static v8::Handle<Value> call_as_function(const v8::Arguments& args) {
4847   ApiTestFuzzer::Fuzz();
4848   if (args.IsConstructCall()) {
4849     if (args[0]->IsInt32()) {
4850        return v8_num(-args[0]->Int32Value());
4851     }
4852   }
4853 
4854   return args[0];
4855 }
4856 
4857 
4858 // Test that a call handler can be set for objects which will allow
4859 // non-function objects created through the API to be called as
4860 // functions.
THREADED_TEST(CallAsFunction)4861 THREADED_TEST(CallAsFunction) {
4862   v8::HandleScope scope;
4863   LocalContext context;
4864 
4865   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
4866   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
4867   instance_template->SetCallAsFunctionHandler(call_as_function);
4868   Local<v8::Object> instance = t->GetFunction()->NewInstance();
4869   context->Global()->Set(v8_str("obj"), instance);
4870   v8::TryCatch try_catch;
4871   Local<Value> value;
4872   CHECK(!try_catch.HasCaught());
4873 
4874   value = CompileRun("obj(42)");
4875   CHECK(!try_catch.HasCaught());
4876   CHECK_EQ(42, value->Int32Value());
4877 
4878   value = CompileRun("(function(o){return o(49)})(obj)");
4879   CHECK(!try_catch.HasCaught());
4880   CHECK_EQ(49, value->Int32Value());
4881 
4882   // test special case of call as function
4883   value = CompileRun("[obj]['0'](45)");
4884   CHECK(!try_catch.HasCaught());
4885   CHECK_EQ(45, value->Int32Value());
4886 
4887   value = CompileRun("obj.call = Function.prototype.call;"
4888                      "obj.call(null, 87)");
4889   CHECK(!try_catch.HasCaught());
4890   CHECK_EQ(87, value->Int32Value());
4891 
4892   // Regression tests for bug #1116356: Calling call through call/apply
4893   // must work for non-function receivers.
4894   const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
4895   value = CompileRun(apply_99);
4896   CHECK(!try_catch.HasCaught());
4897   CHECK_EQ(99, value->Int32Value());
4898 
4899   const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
4900   value = CompileRun(call_17);
4901   CHECK(!try_catch.HasCaught());
4902   CHECK_EQ(17, value->Int32Value());
4903 
4904   // Check that the call-as-function handler can be called through
4905   // new.  Currently, there is no way to check in the call-as-function
4906   // handler if it has been called through new or not.
4907   value = CompileRun("new obj(43)");
4908   CHECK(!try_catch.HasCaught());
4909   CHECK_EQ(-43, value->Int32Value());
4910 }
4911 
4912 
CountHandles()4913 static int CountHandles() {
4914   return v8::HandleScope::NumberOfHandles();
4915 }
4916 
4917 
Recurse(int depth,int iterations)4918 static int Recurse(int depth, int iterations) {
4919   v8::HandleScope scope;
4920   if (depth == 0) return CountHandles();
4921   for (int i = 0; i < iterations; i++) {
4922     Local<v8::Number> n = v8::Integer::New(42);
4923   }
4924   return Recurse(depth - 1, iterations);
4925 }
4926 
4927 
THREADED_TEST(HandleIteration)4928 THREADED_TEST(HandleIteration) {
4929   static const int kIterations = 500;
4930   static const int kNesting = 200;
4931   CHECK_EQ(0, CountHandles());
4932   {
4933     v8::HandleScope scope1;
4934     CHECK_EQ(0, CountHandles());
4935     for (int i = 0; i < kIterations; i++) {
4936       Local<v8::Number> n = v8::Integer::New(42);
4937       CHECK_EQ(i + 1, CountHandles());
4938     }
4939 
4940     CHECK_EQ(kIterations, CountHandles());
4941     {
4942       v8::HandleScope scope2;
4943       for (int j = 0; j < kIterations; j++) {
4944         Local<v8::Number> n = v8::Integer::New(42);
4945         CHECK_EQ(j + 1 + kIterations, CountHandles());
4946       }
4947     }
4948     CHECK_EQ(kIterations, CountHandles());
4949   }
4950   CHECK_EQ(0, CountHandles());
4951   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
4952 }
4953 
4954 
InterceptorHasOwnPropertyGetter(Local<String> name,const AccessorInfo & info)4955 static v8::Handle<Value> InterceptorHasOwnPropertyGetter(
4956     Local<String> name,
4957     const AccessorInfo& info) {
4958   ApiTestFuzzer::Fuzz();
4959   return v8::Handle<Value>();
4960 }
4961 
4962 
THREADED_TEST(InterceptorHasOwnProperty)4963 THREADED_TEST(InterceptorHasOwnProperty) {
4964   v8::HandleScope scope;
4965   LocalContext context;
4966   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
4967   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
4968   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
4969   Local<Function> function = fun_templ->GetFunction();
4970   context->Global()->Set(v8_str("constructor"), function);
4971   v8::Handle<Value> value = CompileRun(
4972       "var o = new constructor();"
4973       "o.hasOwnProperty('ostehaps');");
4974   CHECK_EQ(false, value->BooleanValue());
4975   value = CompileRun(
4976       "o.ostehaps = 42;"
4977       "o.hasOwnProperty('ostehaps');");
4978   CHECK_EQ(true, value->BooleanValue());
4979   value = CompileRun(
4980       "var p = new constructor();"
4981       "p.hasOwnProperty('ostehaps');");
4982   CHECK_EQ(false, value->BooleanValue());
4983 }
4984 
4985 
InterceptorHasOwnPropertyGetterGC(Local<String> name,const AccessorInfo & info)4986 static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC(
4987     Local<String> name,
4988     const AccessorInfo& info) {
4989   ApiTestFuzzer::Fuzz();
4990   i::Heap::CollectAllGarbage(false);
4991   return v8::Handle<Value>();
4992 }
4993 
4994 
THREADED_TEST(InterceptorHasOwnPropertyCausingGC)4995 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
4996   v8::HandleScope scope;
4997   LocalContext context;
4998   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
4999   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
5000   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
5001   Local<Function> function = fun_templ->GetFunction();
5002   context->Global()->Set(v8_str("constructor"), function);
5003   // Let's first make some stuff so we can be sure to get a good GC.
5004   CompileRun(
5005       "function makestr(size) {"
5006       "  switch (size) {"
5007       "    case 1: return 'f';"
5008       "    case 2: return 'fo';"
5009       "    case 3: return 'foo';"
5010       "  }"
5011       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
5012       "}"
5013       "var x = makestr(12345);"
5014       "x = makestr(31415);"
5015       "x = makestr(23456);");
5016   v8::Handle<Value> value = CompileRun(
5017       "var o = new constructor();"
5018       "o.__proto__ = new String(x);"
5019       "o.hasOwnProperty('ostehaps');");
5020   CHECK_EQ(false, value->BooleanValue());
5021 }
5022 
5023 
5024 typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property,
5025                                                  const AccessorInfo& info);
5026 
5027 
CheckInterceptorLoadIC(NamedPropertyGetter getter,const char * source,int expected)5028 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
5029                                    const char* source,
5030                                    int expected) {
5031   v8::HandleScope scope;
5032   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5033   templ->SetNamedPropertyHandler(getter);
5034   LocalContext context;
5035   context->Global()->Set(v8_str("o"), templ->NewInstance());
5036   v8::Handle<Value> value = CompileRun(source);
5037   CHECK_EQ(expected, value->Int32Value());
5038 }
5039 
5040 
InterceptorLoadICGetter(Local<String> name,const AccessorInfo & info)5041 static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name,
5042                                                  const AccessorInfo& info) {
5043   ApiTestFuzzer::Fuzz();
5044   CHECK(v8_str("x")->Equals(name));
5045   return v8::Integer::New(42);
5046 }
5047 
5048 
5049 // This test should hit the load IC for the interceptor case.
THREADED_TEST(InterceptorLoadIC)5050 THREADED_TEST(InterceptorLoadIC) {
5051   CheckInterceptorLoadIC(InterceptorLoadICGetter,
5052     "var result = 0;"
5053     "for (var i = 0; i < 1000; i++) {"
5054     "  result = o.x;"
5055     "}",
5056     42);
5057 }
5058 
5059 
5060 // Below go several tests which verify that JITing for various
5061 // configurations of interceptor and explicit fields works fine
5062 // (those cases are special cased to get better performance).
5063 
InterceptorLoadXICGetter(Local<String> name,const AccessorInfo & info)5064 static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name,
5065                                                  const AccessorInfo& info) {
5066   ApiTestFuzzer::Fuzz();
5067   return v8_str("x")->Equals(name)
5068       ? v8::Integer::New(42) : v8::Handle<v8::Value>();
5069 }
5070 
5071 
THREADED_TEST(InterceptorLoadICWithFieldOnHolder)5072 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
5073   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5074     "var result = 0;"
5075     "o.y = 239;"
5076     "for (var i = 0; i < 1000; i++) {"
5077     "  result = o.y;"
5078     "}",
5079     239);
5080 }
5081 
5082 
THREADED_TEST(InterceptorLoadICWithSubstitutedProto)5083 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
5084   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5085     "var result = 0;"
5086     "o.__proto__ = { 'y': 239 };"
5087     "for (var i = 0; i < 1000; i++) {"
5088     "  result = o.y + o.x;"
5089     "}",
5090     239 + 42);
5091 }
5092 
5093 
THREADED_TEST(InterceptorLoadICWithPropertyOnProto)5094 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
5095   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5096     "var result = 0;"
5097     "o.__proto__.y = 239;"
5098     "for (var i = 0; i < 1000; i++) {"
5099     "  result = o.y + o.x;"
5100     "}",
5101     239 + 42);
5102 }
5103 
5104 
THREADED_TEST(InterceptorLoadICUndefined)5105 THREADED_TEST(InterceptorLoadICUndefined) {
5106   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5107     "var result = 0;"
5108     "for (var i = 0; i < 1000; i++) {"
5109     "  result = (o.y == undefined) ? 239 : 42;"
5110     "}",
5111     239);
5112 }
5113 
5114 
THREADED_TEST(InterceptorLoadICWithOverride)5115 THREADED_TEST(InterceptorLoadICWithOverride) {
5116   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5117     "fst = new Object();  fst.__proto__ = o;"
5118     "snd = new Object();  snd.__proto__ = fst;"
5119     "var result1 = 0;"
5120     "for (var i = 0; i < 1000;  i++) {"
5121     "  result1 = snd.x;"
5122     "}"
5123     "fst.x = 239;"
5124     "var result = 0;"
5125     "for (var i = 0; i < 1000; i++) {"
5126     "  result = snd.x;"
5127     "}"
5128     "result + result1",
5129     239 + 42);
5130 }
5131 
5132 
5133 // Test the case when we stored field into
5134 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICFieldNotNeeded)5135 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
5136   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5137     "proto = new Object();"
5138     "o.__proto__ = proto;"
5139     "proto.x = 239;"
5140     "for (var i = 0; i < 1000; i++) {"
5141     "  o.x;"
5142     // Now it should be ICed and keep a reference to x defined on proto
5143     "}"
5144     "var result = 0;"
5145     "for (var i = 0; i < 1000; i++) {"
5146     "  result += o.x;"
5147     "}"
5148     "result;",
5149     42 * 1000);
5150 }
5151 
5152 
5153 // Test the case when we stored field into
5154 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedField)5155 THREADED_TEST(InterceptorLoadICInvalidatedField) {
5156   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5157     "proto1 = new Object();"
5158     "proto2 = new Object();"
5159     "o.__proto__ = proto1;"
5160     "proto1.__proto__ = proto2;"
5161     "proto2.y = 239;"
5162     "for (var i = 0; i < 1000; i++) {"
5163     "  o.y;"
5164     // Now it should be ICed and keep a reference to y defined on proto2
5165     "}"
5166     "proto1.y = 42;"
5167     "var result = 0;"
5168     "for (var i = 0; i < 1000; i++) {"
5169     "  result += o.y;"
5170     "}"
5171     "result;",
5172     42 * 1000);
5173 }
5174 
5175 
5176 // Test the case when we stored field into
5177 // a stub, but it got invalidated later on due to override on
5178 // global object which is between interceptor and fields' holders.
THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal)5179 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
5180   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
5181     "o.__proto__ = this;"  // set a global to be a proto of o.
5182     "this.__proto__.y = 239;"
5183     "for (var i = 0; i < 10; i++) {"
5184     "  if (o.y != 239) throw 'oops: ' + o.y;"
5185     // Now it should be ICed and keep a reference to y defined on field_holder.
5186     "}"
5187     "this.y = 42;"  // Assign on a global.
5188     "var result = 0;"
5189     "for (var i = 0; i < 10; i++) {"
5190     "  result += o.y;"
5191     "}"
5192     "result;",
5193     42 * 10);
5194 }
5195 
5196 
Return239(Local<String> name,const AccessorInfo &)5197 static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
5198   ApiTestFuzzer::Fuzz();
5199   return v8_num(239);
5200 }
5201 
5202 
SetOnThis(Local<String> name,Local<Value> value,const AccessorInfo & info)5203 static void SetOnThis(Local<String> name,
5204                       Local<Value> value,
5205                       const AccessorInfo& info) {
5206   info.This()->ForceSet(name, value);
5207 }
5208 
5209 
THREADED_TEST(InterceptorLoadICWithCallbackOnHolder)5210 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
5211   v8::HandleScope scope;
5212   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5213   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5214   templ->SetAccessor(v8_str("y"), Return239);
5215   LocalContext context;
5216   context->Global()->Set(v8_str("o"), templ->NewInstance());
5217   v8::Handle<Value> value = CompileRun(
5218       "var result = 0;"
5219       "for (var i = 0; i < 7; i++) {"
5220       "  result = o.y;"
5221       "}");
5222   CHECK_EQ(239, value->Int32Value());
5223 }
5224 
5225 
THREADED_TEST(InterceptorLoadICWithCallbackOnProto)5226 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
5227   v8::HandleScope scope;
5228   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5229   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5230   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5231   templ_p->SetAccessor(v8_str("y"), Return239);
5232 
5233   LocalContext context;
5234   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5235   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5236 
5237   v8::Handle<Value> value = CompileRun(
5238       "o.__proto__ = p;"
5239       "var result = 0;"
5240       "for (var i = 0; i < 7; i++) {"
5241       "  result = o.x + o.y;"
5242       "}");
5243   CHECK_EQ(239 + 42, value->Int32Value());
5244 }
5245 
5246 
THREADED_TEST(InterceptorLoadICForCallbackWithOverride)5247 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
5248   v8::HandleScope scope;
5249   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5250   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5251   templ->SetAccessor(v8_str("y"), Return239);
5252 
5253   LocalContext context;
5254   context->Global()->Set(v8_str("o"), templ->NewInstance());
5255 
5256   v8::Handle<Value> value = CompileRun(
5257     "fst = new Object();  fst.__proto__ = o;"
5258     "snd = new Object();  snd.__proto__ = fst;"
5259     "var result1 = 0;"
5260     "for (var i = 0; i < 7;  i++) {"
5261     "  result1 = snd.x;"
5262     "}"
5263     "fst.x = 239;"
5264     "var result = 0;"
5265     "for (var i = 0; i < 7; i++) {"
5266     "  result = snd.x;"
5267     "}"
5268     "result + result1");
5269   CHECK_EQ(239 + 42, value->Int32Value());
5270 }
5271 
5272 
5273 // Test the case when we stored callback into
5274 // a stub, but interceptor produced value on its own.
THREADED_TEST(InterceptorLoadICCallbackNotNeeded)5275 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
5276   v8::HandleScope scope;
5277   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5278   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5279   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5280   templ_p->SetAccessor(v8_str("y"), Return239);
5281 
5282   LocalContext context;
5283   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5284   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5285 
5286   v8::Handle<Value> value = CompileRun(
5287     "o.__proto__ = p;"
5288     "for (var i = 0; i < 7; i++) {"
5289     "  o.x;"
5290     // Now it should be ICed and keep a reference to x defined on p
5291     "}"
5292     "var result = 0;"
5293     "for (var i = 0; i < 7; i++) {"
5294     "  result += o.x;"
5295     "}"
5296     "result");
5297   CHECK_EQ(42 * 7, value->Int32Value());
5298 }
5299 
5300 
5301 // Test the case when we stored callback into
5302 // a stub, but it got invalidated later on.
THREADED_TEST(InterceptorLoadICInvalidatedCallback)5303 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
5304   v8::HandleScope scope;
5305   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5306   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5307   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5308   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5309 
5310   LocalContext context;
5311   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5312   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5313 
5314   v8::Handle<Value> value = CompileRun(
5315     "inbetween = new Object();"
5316     "o.__proto__ = inbetween;"
5317     "inbetween.__proto__ = p;"
5318     "for (var i = 0; i < 10; i++) {"
5319     "  o.y;"
5320     // Now it should be ICed and keep a reference to y defined on p
5321     "}"
5322     "inbetween.y = 42;"
5323     "var result = 0;"
5324     "for (var i = 0; i < 10; i++) {"
5325     "  result += o.y;"
5326     "}"
5327     "result");
5328   CHECK_EQ(42 * 10, value->Int32Value());
5329 }
5330 
5331 
5332 // Test the case when we stored callback into
5333 // a stub, but it got invalidated later on due to override on
5334 // global object which is between interceptor and callbacks' holders.
THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal)5335 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
5336   v8::HandleScope scope;
5337   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
5338   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5339   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
5340   templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
5341 
5342   LocalContext context;
5343   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
5344   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
5345 
5346   v8::Handle<Value> value = CompileRun(
5347     "o.__proto__ = this;"
5348     "this.__proto__ = p;"
5349     "for (var i = 0; i < 10; i++) {"
5350     "  if (o.y != 239) throw 'oops: ' + o.y;"
5351     // Now it should be ICed and keep a reference to y defined on p
5352     "}"
5353     "this.y = 42;"
5354     "var result = 0;"
5355     "for (var i = 0; i < 10; i++) {"
5356     "  result += o.y;"
5357     "}"
5358     "result");
5359   CHECK_EQ(42 * 10, value->Int32Value());
5360 }
5361 
5362 
InterceptorLoadICGetter0(Local<String> name,const AccessorInfo & info)5363 static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
5364                                                   const AccessorInfo& info) {
5365   ApiTestFuzzer::Fuzz();
5366   CHECK(v8_str("x")->Equals(name));
5367   return v8::Integer::New(0);
5368 }
5369 
5370 
THREADED_TEST(InterceptorReturningZero)5371 THREADED_TEST(InterceptorReturningZero) {
5372   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
5373      "o.x == undefined ? 1 : 0",
5374      0);
5375 }
5376 
5377 
InterceptorStoreICSetter(Local<String> key,Local<Value> value,const AccessorInfo &)5378 static v8::Handle<Value> InterceptorStoreICSetter(
5379     Local<String> key, Local<Value> value, const AccessorInfo&) {
5380   CHECK(v8_str("x")->Equals(key));
5381   CHECK_EQ(42, value->Int32Value());
5382   return value;
5383 }
5384 
5385 
5386 // This test should hit the store IC for the interceptor case.
THREADED_TEST(InterceptorStoreIC)5387 THREADED_TEST(InterceptorStoreIC) {
5388   v8::HandleScope scope;
5389   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5390   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
5391                                  InterceptorStoreICSetter);
5392   LocalContext context;
5393   context->Global()->Set(v8_str("o"), templ->NewInstance());
5394   v8::Handle<Value> value = CompileRun(
5395     "for (var i = 0; i < 1000; i++) {"
5396     "  o.x = 42;"
5397     "}");
5398 }
5399 
5400 
THREADED_TEST(InterceptorStoreICWithNoSetter)5401 THREADED_TEST(InterceptorStoreICWithNoSetter) {
5402   v8::HandleScope scope;
5403   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5404   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
5405   LocalContext context;
5406   context->Global()->Set(v8_str("o"), templ->NewInstance());
5407   v8::Handle<Value> value = CompileRun(
5408     "for (var i = 0; i < 1000; i++) {"
5409     "  o.y = 239;"
5410     "}"
5411     "42 + o.y");
5412   CHECK_EQ(239 + 42, value->Int32Value());
5413 }
5414 
5415 
5416 
5417 
5418 v8::Handle<Value> call_ic_function;
5419 v8::Handle<Value> call_ic_function2;
5420 v8::Handle<Value> call_ic_function3;
5421 
InterceptorCallICGetter(Local<String> name,const AccessorInfo & info)5422 static v8::Handle<Value> InterceptorCallICGetter(Local<String> name,
5423                                                  const AccessorInfo& info) {
5424   ApiTestFuzzer::Fuzz();
5425   CHECK(v8_str("x")->Equals(name));
5426   return call_ic_function;
5427 }
5428 
5429 
5430 // This test should hit the call IC for the interceptor case.
THREADED_TEST(InterceptorCallIC)5431 THREADED_TEST(InterceptorCallIC) {
5432   v8::HandleScope scope;
5433   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5434   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
5435   LocalContext context;
5436   context->Global()->Set(v8_str("o"), templ->NewInstance());
5437   call_ic_function =
5438       v8_compile("function f(x) { return x + 1; }; f")->Run();
5439   v8::Handle<Value> value = CompileRun(
5440     "var result = 0;"
5441     "for (var i = 0; i < 1000; i++) {"
5442     "  result = o.x(41);"
5443     "}");
5444   CHECK_EQ(42, value->Int32Value());
5445 }
5446 
5447 
5448 // This test checks that if interceptor doesn't provide
5449 // a value, we can fetch regular value.
THREADED_TEST(InterceptorCallICSeesOthers)5450 THREADED_TEST(InterceptorCallICSeesOthers) {
5451   v8::HandleScope scope;
5452   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5453   templ->SetNamedPropertyHandler(NoBlockGetterX);
5454   LocalContext context;
5455   context->Global()->Set(v8_str("o"), templ->NewInstance());
5456   v8::Handle<Value> value = CompileRun(
5457     "o.x = function f(x) { return x + 1; };"
5458     "var result = 0;"
5459     "for (var i = 0; i < 7; i++) {"
5460     "  result = o.x(41);"
5461     "}");
5462   CHECK_EQ(42, value->Int32Value());
5463 }
5464 
5465 
5466 static v8::Handle<Value> call_ic_function4;
InterceptorCallICGetter4(Local<String> name,const AccessorInfo & info)5467 static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
5468                                                   const AccessorInfo& info) {
5469   ApiTestFuzzer::Fuzz();
5470   CHECK(v8_str("x")->Equals(name));
5471   return call_ic_function4;
5472 }
5473 
5474 
5475 // This test checks that if interceptor provides a function,
5476 // even if we cached shadowed variant, interceptor's function
5477 // is invoked
THREADED_TEST(InterceptorCallICCacheableNotNeeded)5478 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
5479   v8::HandleScope scope;
5480   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5481   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
5482   LocalContext context;
5483   context->Global()->Set(v8_str("o"), templ->NewInstance());
5484   call_ic_function4 =
5485       v8_compile("function f(x) { return x - 1; }; f")->Run();
5486   v8::Handle<Value> value = CompileRun(
5487     "o.__proto__.x = function(x) { return x + 1; };"
5488     "var result = 0;"
5489     "for (var i = 0; i < 1000; i++) {"
5490     "  result = o.x(42);"
5491     "}");
5492   CHECK_EQ(41, value->Int32Value());
5493 }
5494 
5495 
5496 // Test the case when we stored cacheable lookup into
5497 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedCacheable)5498 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
5499   v8::HandleScope scope;
5500   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5501   templ->SetNamedPropertyHandler(NoBlockGetterX);
5502   LocalContext context;
5503   context->Global()->Set(v8_str("o"), templ->NewInstance());
5504   v8::Handle<Value> value = CompileRun(
5505     "proto1 = new Object();"
5506     "proto2 = new Object();"
5507     "o.__proto__ = proto1;"
5508     "proto1.__proto__ = proto2;"
5509     "proto2.y = function(x) { return x + 1; };"
5510     // Invoke it many times to compile a stub
5511     "for (var i = 0; i < 7; i++) {"
5512     "  o.y(42);"
5513     "}"
5514     "proto1.y = function(x) { return x - 1; };"
5515     "var result = 0;"
5516     "for (var i = 0; i < 7; i++) {"
5517     "  result += o.y(42);"
5518     "}");
5519   CHECK_EQ(41 * 7, value->Int32Value());
5520 }
5521 
5522 
5523 static v8::Handle<Value> call_ic_function5;
InterceptorCallICGetter5(Local<String> name,const AccessorInfo & info)5524 static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
5525                                                   const AccessorInfo& info) {
5526   ApiTestFuzzer::Fuzz();
5527   if (v8_str("x")->Equals(name))
5528     return call_ic_function5;
5529   else
5530     return Local<Value>();
5531 }
5532 
5533 
5534 // This test checks that if interceptor doesn't provide a function,
5535 // cached constant function is used
THREADED_TEST(InterceptorCallICConstantFunctionUsed)5536 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
5537   v8::HandleScope scope;
5538   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5539   templ->SetNamedPropertyHandler(NoBlockGetterX);
5540   LocalContext context;
5541   context->Global()->Set(v8_str("o"), templ->NewInstance());
5542   v8::Handle<Value> value = CompileRun(
5543     "function inc(x) { return x + 1; };"
5544     "inc(1);"
5545     "o.x = inc;"
5546     "var result = 0;"
5547     "for (var i = 0; i < 1000; i++) {"
5548     "  result = o.x(42);"
5549     "}");
5550   CHECK_EQ(43, value->Int32Value());
5551 }
5552 
5553 
5554 // This test checks that if interceptor provides a function,
5555 // even if we cached constant function, interceptor's function
5556 // is invoked
THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded)5557 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
5558   v8::HandleScope scope;
5559   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5560   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
5561   LocalContext context;
5562   context->Global()->Set(v8_str("o"), templ->NewInstance());
5563   call_ic_function5 =
5564       v8_compile("function f(x) { return x - 1; }; f")->Run();
5565   v8::Handle<Value> value = CompileRun(
5566     "function inc(x) { return x + 1; };"
5567     "inc(1);"
5568     "o.x = inc;"
5569     "var result = 0;"
5570     "for (var i = 0; i < 1000; i++) {"
5571     "  result = o.x(42);"
5572     "}");
5573   CHECK_EQ(41, value->Int32Value());
5574 }
5575 
5576 
5577 // Test the case when we stored constant function into
5578 // a stub, but it got invalidated later on
THREADED_TEST(InterceptorCallICInvalidatedConstantFunction)5579 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
5580   v8::HandleScope scope;
5581   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5582   templ->SetNamedPropertyHandler(NoBlockGetterX);
5583   LocalContext context;
5584   context->Global()->Set(v8_str("o"), templ->NewInstance());
5585   v8::Handle<Value> value = CompileRun(
5586     "function inc(x) { return x + 1; };"
5587     "inc(1);"
5588     "proto1 = new Object();"
5589     "proto2 = new Object();"
5590     "o.__proto__ = proto1;"
5591     "proto1.__proto__ = proto2;"
5592     "proto2.y = inc;"
5593     // Invoke it many times to compile a stub
5594     "for (var i = 0; i < 7; i++) {"
5595     "  o.y(42);"
5596     "}"
5597     "proto1.y = function(x) { return x - 1; };"
5598     "var result = 0;"
5599     "for (var i = 0; i < 7; i++) {"
5600     "  result += o.y(42);"
5601     "}");
5602   CHECK_EQ(41 * 7, value->Int32Value());
5603 }
5604 
5605 
5606 // Test the case when we stored constant function into
5607 // a stub, but it got invalidated later on due to override on
5608 // global object which is between interceptor and constant function' holders.
THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal)5609 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
5610   v8::HandleScope scope;
5611   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5612   templ->SetNamedPropertyHandler(NoBlockGetterX);
5613   LocalContext context;
5614   context->Global()->Set(v8_str("o"), templ->NewInstance());
5615   v8::Handle<Value> value = CompileRun(
5616     "function inc(x) { return x + 1; };"
5617     "inc(1);"
5618     "o.__proto__ = this;"
5619     "this.__proto__.y = inc;"
5620     // Invoke it many times to compile a stub
5621     "for (var i = 0; i < 7; i++) {"
5622     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
5623     "}"
5624     "this.y = function(x) { return x - 1; };"
5625     "var result = 0;"
5626     "for (var i = 0; i < 7; i++) {"
5627     "  result += o.y(42);"
5628     "}");
5629   CHECK_EQ(41 * 7, value->Int32Value());
5630 }
5631 
5632 
5633 static int interceptor_call_count = 0;
5634 
InterceptorICRefErrorGetter(Local<String> name,const AccessorInfo & info)5635 static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
5636                                                      const AccessorInfo& info) {
5637   ApiTestFuzzer::Fuzz();
5638   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
5639     return call_ic_function2;
5640   }
5641   return v8::Handle<Value>();
5642 }
5643 
5644 
5645 // This test should hit load and call ICs for the interceptor case.
5646 // Once in a while, the interceptor will reply that a property was not
5647 // found in which case we should get a reference error.
THREADED_TEST(InterceptorICReferenceErrors)5648 THREADED_TEST(InterceptorICReferenceErrors) {
5649   v8::HandleScope scope;
5650   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5651   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
5652   LocalContext context(0, templ, v8::Handle<Value>());
5653   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
5654   v8::Handle<Value> value = CompileRun(
5655     "function f() {"
5656     "  for (var i = 0; i < 1000; i++) {"
5657     "    try { x; } catch(e) { return true; }"
5658     "  }"
5659     "  return false;"
5660     "};"
5661     "f();");
5662   CHECK_EQ(true, value->BooleanValue());
5663   interceptor_call_count = 0;
5664   value = CompileRun(
5665     "function g() {"
5666     "  for (var i = 0; i < 1000; i++) {"
5667     "    try { x(42); } catch(e) { return true; }"
5668     "  }"
5669     "  return false;"
5670     "};"
5671     "g();");
5672   CHECK_EQ(true, value->BooleanValue());
5673 }
5674 
5675 
5676 static int interceptor_ic_exception_get_count = 0;
5677 
InterceptorICExceptionGetter(Local<String> name,const AccessorInfo & info)5678 static v8::Handle<Value> InterceptorICExceptionGetter(
5679     Local<String> name,
5680     const AccessorInfo& info) {
5681   ApiTestFuzzer::Fuzz();
5682   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
5683     return call_ic_function3;
5684   }
5685   if (interceptor_ic_exception_get_count == 20) {
5686     return v8::ThrowException(v8_num(42));
5687   }
5688   // Do not handle get for properties other than x.
5689   return v8::Handle<Value>();
5690 }
5691 
5692 // Test interceptor load/call IC where the interceptor throws an
5693 // exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions)5694 THREADED_TEST(InterceptorICGetterExceptions) {
5695   interceptor_ic_exception_get_count = 0;
5696   v8::HandleScope scope;
5697   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5698   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
5699   LocalContext context(0, templ, v8::Handle<Value>());
5700   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
5701   v8::Handle<Value> value = CompileRun(
5702     "function f() {"
5703     "  for (var i = 0; i < 100; i++) {"
5704     "    try { x; } catch(e) { return true; }"
5705     "  }"
5706     "  return false;"
5707     "};"
5708     "f();");
5709   CHECK_EQ(true, value->BooleanValue());
5710   interceptor_ic_exception_get_count = 0;
5711   value = CompileRun(
5712     "function f() {"
5713     "  for (var i = 0; i < 100; i++) {"
5714     "    try { x(42); } catch(e) { return true; }"
5715     "  }"
5716     "  return false;"
5717     "};"
5718     "f();");
5719   CHECK_EQ(true, value->BooleanValue());
5720 }
5721 
5722 
5723 static int interceptor_ic_exception_set_count = 0;
5724 
InterceptorICExceptionSetter(Local<String> key,Local<Value> value,const AccessorInfo &)5725 static v8::Handle<Value> InterceptorICExceptionSetter(
5726       Local<String> key, Local<Value> value, const AccessorInfo&) {
5727   ApiTestFuzzer::Fuzz();
5728   if (++interceptor_ic_exception_set_count > 20) {
5729     return v8::ThrowException(v8_num(42));
5730   }
5731   // Do not actually handle setting.
5732   return v8::Handle<Value>();
5733 }
5734 
5735 // Test interceptor store IC where the interceptor throws an exception
5736 // once in a while.
THREADED_TEST(InterceptorICSetterExceptions)5737 THREADED_TEST(InterceptorICSetterExceptions) {
5738   interceptor_ic_exception_set_count = 0;
5739   v8::HandleScope scope;
5740   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5741   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
5742   LocalContext context(0, templ, v8::Handle<Value>());
5743   v8::Handle<Value> value = CompileRun(
5744     "function f() {"
5745     "  for (var i = 0; i < 100; i++) {"
5746     "    try { x = 42; } catch(e) { return true; }"
5747     "  }"
5748     "  return false;"
5749     "};"
5750     "f();");
5751   CHECK_EQ(true, value->BooleanValue());
5752 }
5753 
5754 
5755 // Test that we ignore null interceptors.
THREADED_TEST(NullNamedInterceptor)5756 THREADED_TEST(NullNamedInterceptor) {
5757   v8::HandleScope scope;
5758   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5759   templ->SetNamedPropertyHandler(0);
5760   LocalContext context;
5761   templ->Set("x", v8_num(42));
5762   v8::Handle<v8::Object> obj = templ->NewInstance();
5763   context->Global()->Set(v8_str("obj"), obj);
5764   v8::Handle<Value> value = CompileRun("obj.x");
5765   CHECK(value->IsInt32());
5766   CHECK_EQ(42, value->Int32Value());
5767 }
5768 
5769 
5770 // Test that we ignore null interceptors.
THREADED_TEST(NullIndexedInterceptor)5771 THREADED_TEST(NullIndexedInterceptor) {
5772   v8::HandleScope scope;
5773   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
5774   templ->SetIndexedPropertyHandler(0);
5775   LocalContext context;
5776   templ->Set("42", v8_num(42));
5777   v8::Handle<v8::Object> obj = templ->NewInstance();
5778   context->Global()->Set(v8_str("obj"), obj);
5779   v8::Handle<Value> value = CompileRun("obj[42]");
5780   CHECK(value->IsInt32());
5781   CHECK_EQ(42, value->Int32Value());
5782 }
5783 
5784 
ParentGetter(Local<String> name,const AccessorInfo & info)5785 static v8::Handle<Value> ParentGetter(Local<String> name,
5786                                       const AccessorInfo& info) {
5787   ApiTestFuzzer::Fuzz();
5788   return v8_num(1);
5789 }
5790 
5791 
ChildGetter(Local<String> name,const AccessorInfo & info)5792 static v8::Handle<Value> ChildGetter(Local<String> name,
5793                                      const AccessorInfo& info) {
5794   ApiTestFuzzer::Fuzz();
5795   return v8_num(42);
5796 }
5797 
5798 
THREADED_TEST(Overriding)5799 THREADED_TEST(Overriding) {
5800   v8::HandleScope scope;
5801   LocalContext context;
5802 
5803   // Parent template.
5804   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
5805   Local<ObjectTemplate> parent_instance_templ =
5806       parent_templ->InstanceTemplate();
5807   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
5808 
5809   // Template that inherits from the parent template.
5810   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
5811   Local<ObjectTemplate> child_instance_templ =
5812       child_templ->InstanceTemplate();
5813   child_templ->Inherit(parent_templ);
5814   // Override 'f'.  The child version of 'f' should get called for child
5815   // instances.
5816   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
5817   // Add 'g' twice.  The 'g' added last should get called for instances.
5818   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
5819   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
5820 
5821   // Add 'h' as an accessor to the proto template with ReadOnly attributes
5822   // so 'h' can be shadowed on the instance object.
5823   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
5824   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
5825       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5826 
5827   // Add 'i' as an accessor to the instance template with ReadOnly attributes
5828   // but the attribute does not have effect because it is duplicated with
5829   // NULL setter.
5830   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
5831       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
5832 
5833 
5834 
5835   // Instantiate the child template.
5836   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
5837 
5838   // Check that the child function overrides the parent one.
5839   context->Global()->Set(v8_str("o"), instance);
5840   Local<Value> value = v8_compile("o.f")->Run();
5841   // Check that the 'g' that was added last is hit.
5842   CHECK_EQ(42, value->Int32Value());
5843   value = v8_compile("o.g")->Run();
5844   CHECK_EQ(42, value->Int32Value());
5845 
5846   // Check 'h' can be shadowed.
5847   value = v8_compile("o.h = 3; o.h")->Run();
5848   CHECK_EQ(3, value->Int32Value());
5849 
5850   // Check 'i' is cannot be shadowed or changed.
5851   value = v8_compile("o.i = 3; o.i")->Run();
5852   CHECK_EQ(42, value->Int32Value());
5853 }
5854 
5855 
IsConstructHandler(const v8::Arguments & args)5856 static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) {
5857   ApiTestFuzzer::Fuzz();
5858   if (args.IsConstructCall()) {
5859     return v8::Boolean::New(true);
5860   }
5861   return v8::Boolean::New(false);
5862 }
5863 
5864 
THREADED_TEST(IsConstructCall)5865 THREADED_TEST(IsConstructCall) {
5866   v8::HandleScope scope;
5867 
5868   // Function template with call handler.
5869   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5870   templ->SetCallHandler(IsConstructHandler);
5871 
5872   LocalContext context;
5873 
5874   context->Global()->Set(v8_str("f"), templ->GetFunction());
5875   Local<Value> value = v8_compile("f()")->Run();
5876   CHECK(!value->BooleanValue());
5877   value = v8_compile("new f()")->Run();
5878   CHECK(value->BooleanValue());
5879 }
5880 
5881 
THREADED_TEST(ObjectProtoToString)5882 THREADED_TEST(ObjectProtoToString) {
5883   v8::HandleScope scope;
5884   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
5885   templ->SetClassName(v8_str("MyClass"));
5886 
5887   LocalContext context;
5888 
5889   Local<String> customized_tostring = v8_str("customized toString");
5890 
5891   // Replace Object.prototype.toString
5892   v8_compile("Object.prototype.toString = function() {"
5893                   "  return 'customized toString';"
5894                   "}")->Run();
5895 
5896   // Normal ToString call should call replaced Object.prototype.toString
5897   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
5898   Local<String> value = instance->ToString();
5899   CHECK(value->IsString() && value->Equals(customized_tostring));
5900 
5901   // ObjectProtoToString should not call replace toString function.
5902   value = instance->ObjectProtoToString();
5903   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
5904 
5905   // Check global
5906   value = context->Global()->ObjectProtoToString();
5907   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
5908 
5909   // Check ordinary object
5910   Local<Value> object = v8_compile("new Object()")->Run();
5911   value = Local<v8::Object>::Cast(object)->ObjectProtoToString();
5912   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
5913 }
5914 
5915 
5916 bool ApiTestFuzzer::fuzzing_ = false;
5917 v8::internal::Semaphore* ApiTestFuzzer::all_tests_done_=
5918   v8::internal::OS::CreateSemaphore(0);
5919 int ApiTestFuzzer::active_tests_;
5920 int ApiTestFuzzer::tests_being_run_;
5921 int ApiTestFuzzer::current_;
5922 
5923 
5924 // We are in a callback and want to switch to another thread (if we
5925 // are currently running the thread fuzzing test).
Fuzz()5926 void ApiTestFuzzer::Fuzz() {
5927   if (!fuzzing_) return;
5928   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
5929   test->ContextSwitch();
5930 }
5931 
5932 
5933 // Let the next thread go.  Since it is also waiting on the V8 lock it may
5934 // not start immediately.
NextThread()5935 bool ApiTestFuzzer::NextThread() {
5936   int test_position = GetNextTestNumber();
5937   int test_number = RegisterThreadedTest::nth(current_)->fuzzer_->test_number_;
5938   if (test_position == current_) {
5939     printf("Stay with %d\n", test_number);
5940     return false;
5941   }
5942   printf("Switch from %d to %d\n",
5943          current_ < 0 ? 0 : test_number, test_position < 0 ? 0 : test_number);
5944   current_ = test_position;
5945   RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
5946   return true;
5947 }
5948 
5949 
Run()5950 void ApiTestFuzzer::Run() {
5951   // When it is our turn...
5952   gate_->Wait();
5953   {
5954     // ... get the V8 lock and start running the test.
5955     v8::Locker locker;
5956     CallTest();
5957   }
5958   // This test finished.
5959   active_ = false;
5960   active_tests_--;
5961   // If it was the last then signal that fact.
5962   if (active_tests_ == 0) {
5963     all_tests_done_->Signal();
5964   } else {
5965     // Otherwise select a new test and start that.
5966     NextThread();
5967   }
5968 }
5969 
5970 
5971 static unsigned linear_congruential_generator;
5972 
5973 
Setup(PartOfTest part)5974 void ApiTestFuzzer::Setup(PartOfTest part) {
5975   linear_congruential_generator = i::FLAG_testing_prng_seed;
5976   fuzzing_ = true;
5977   int start = (part == FIRST_PART) ? 0 : (RegisterThreadedTest::count() >> 1);
5978   int end = (part == FIRST_PART)
5979       ? (RegisterThreadedTest::count() >> 1)
5980       : RegisterThreadedTest::count();
5981   active_tests_ = tests_being_run_ = end - start;
5982   for (int i = 0; i < tests_being_run_; i++) {
5983     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
5984   }
5985   for (int i = 0; i < active_tests_; i++) {
5986     RegisterThreadedTest::nth(i)->fuzzer_->Start();
5987   }
5988 }
5989 
5990 
CallTestNumber(int test_number)5991 static void CallTestNumber(int test_number) {
5992   (RegisterThreadedTest::nth(test_number)->callback())();
5993 }
5994 
5995 
RunAllTests()5996 void ApiTestFuzzer::RunAllTests() {
5997   // Set off the first test.
5998   current_ = -1;
5999   NextThread();
6000   // Wait till they are all done.
6001   all_tests_done_->Wait();
6002 }
6003 
6004 
GetNextTestNumber()6005 int ApiTestFuzzer::GetNextTestNumber() {
6006   int next_test;
6007   do {
6008     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
6009     linear_congruential_generator *= 1664525u;
6010     linear_congruential_generator += 1013904223u;
6011   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
6012   return next_test;
6013 }
6014 
6015 
ContextSwitch()6016 void ApiTestFuzzer::ContextSwitch() {
6017   // If the new thread is the same as the current thread there is nothing to do.
6018   if (NextThread()) {
6019     // Now it can start.
6020     v8::Unlocker unlocker;
6021     // Wait till someone starts us again.
6022     gate_->Wait();
6023     // And we're off.
6024   }
6025 }
6026 
6027 
TearDown()6028 void ApiTestFuzzer::TearDown() {
6029   fuzzing_ = false;
6030   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
6031     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
6032     if (fuzzer != NULL) fuzzer->Join();
6033   }
6034 }
6035 
6036 
6037 // Lets not be needlessly self-referential.
TEST(Threading)6038 TEST(Threading) {
6039   ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART);
6040   ApiTestFuzzer::RunAllTests();
6041   ApiTestFuzzer::TearDown();
6042 }
6043 
TEST(Threading2)6044 TEST(Threading2) {
6045   ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART);
6046   ApiTestFuzzer::RunAllTests();
6047   ApiTestFuzzer::TearDown();
6048 }
6049 
6050 
CallTest()6051 void ApiTestFuzzer::CallTest() {
6052   printf("Start test %d\n", test_number_);
6053   CallTestNumber(test_number_);
6054   printf("End test %d\n", test_number_);
6055 }
6056 
6057 
ThrowInJS(const v8::Arguments & args)6058 static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) {
6059   CHECK(v8::Locker::IsLocked());
6060   ApiTestFuzzer::Fuzz();
6061   v8::Unlocker unlocker;
6062   const char* code = "throw 7;";
6063   {
6064     v8::Locker nested_locker;
6065     v8::HandleScope scope;
6066     v8::Handle<Value> exception;
6067     { v8::TryCatch try_catch;
6068       v8::Handle<Value> value = CompileRun(code);
6069       CHECK(value.IsEmpty());
6070       CHECK(try_catch.HasCaught());
6071       // Make sure to wrap the exception in a new handle because
6072       // the handle returned from the TryCatch is destroyed
6073       // when the TryCatch is destroyed.
6074       exception = Local<Value>::New(try_catch.Exception());
6075     }
6076     return v8::ThrowException(exception);
6077   }
6078 }
6079 
6080 
ThrowInJSNoCatch(const v8::Arguments & args)6081 static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) {
6082   CHECK(v8::Locker::IsLocked());
6083   ApiTestFuzzer::Fuzz();
6084   v8::Unlocker unlocker;
6085   const char* code = "throw 7;";
6086   {
6087     v8::Locker nested_locker;
6088     v8::HandleScope scope;
6089     v8::Handle<Value> value = CompileRun(code);
6090     CHECK(value.IsEmpty());
6091     return v8_str("foo");
6092   }
6093 }
6094 
6095 
6096 // These are locking tests that don't need to be run again
6097 // as part of the locking aggregation tests.
TEST(NestedLockers)6098 TEST(NestedLockers) {
6099   v8::Locker locker;
6100   CHECK(v8::Locker::IsLocked());
6101   v8::HandleScope scope;
6102   LocalContext env;
6103   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
6104   Local<Function> fun = fun_templ->GetFunction();
6105   env->Global()->Set(v8_str("throw_in_js"), fun);
6106   Local<Script> script = v8_compile("(function () {"
6107                                     "  try {"
6108                                     "    throw_in_js();"
6109                                     "    return 42;"
6110                                     "  } catch (e) {"
6111                                     "    return e * 13;"
6112                                     "  }"
6113                                     "})();");
6114   CHECK_EQ(91, script->Run()->Int32Value());
6115 }
6116 
6117 
6118 // These are locking tests that don't need to be run again
6119 // as part of the locking aggregation tests.
TEST(NestedLockersNoTryCatch)6120 TEST(NestedLockersNoTryCatch) {
6121   v8::Locker locker;
6122   v8::HandleScope scope;
6123   LocalContext env;
6124   Local<v8::FunctionTemplate> fun_templ =
6125       v8::FunctionTemplate::New(ThrowInJSNoCatch);
6126   Local<Function> fun = fun_templ->GetFunction();
6127   env->Global()->Set(v8_str("throw_in_js"), fun);
6128   Local<Script> script = v8_compile("(function () {"
6129                                     "  try {"
6130                                     "    throw_in_js();"
6131                                     "    return 42;"
6132                                     "  } catch (e) {"
6133                                     "    return e * 13;"
6134                                     "  }"
6135                                     "})();");
6136   CHECK_EQ(91, script->Run()->Int32Value());
6137 }
6138 
6139 
THREADED_TEST(RecursiveLocking)6140 THREADED_TEST(RecursiveLocking) {
6141   v8::Locker locker;
6142   {
6143     v8::Locker locker2;
6144     CHECK(v8::Locker::IsLocked());
6145   }
6146 }
6147 
6148 
UnlockForAMoment(const v8::Arguments & args)6149 static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) {
6150   ApiTestFuzzer::Fuzz();
6151   v8::Unlocker unlocker;
6152   return v8::Undefined();
6153 }
6154 
6155 
THREADED_TEST(LockUnlockLock)6156 THREADED_TEST(LockUnlockLock) {
6157   {
6158     v8::Locker locker;
6159     v8::HandleScope scope;
6160     LocalContext env;
6161     Local<v8::FunctionTemplate> fun_templ =
6162         v8::FunctionTemplate::New(UnlockForAMoment);
6163     Local<Function> fun = fun_templ->GetFunction();
6164     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6165     Local<Script> script = v8_compile("(function () {"
6166                                       "  unlock_for_a_moment();"
6167                                       "  return 42;"
6168                                       "})();");
6169     CHECK_EQ(42, script->Run()->Int32Value());
6170   }
6171   {
6172     v8::Locker locker;
6173     v8::HandleScope scope;
6174     LocalContext env;
6175     Local<v8::FunctionTemplate> fun_templ =
6176         v8::FunctionTemplate::New(UnlockForAMoment);
6177     Local<Function> fun = fun_templ->GetFunction();
6178     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
6179     Local<Script> script = v8_compile("(function () {"
6180                                       "  unlock_for_a_moment();"
6181                                       "  return 42;"
6182                                       "})();");
6183     CHECK_EQ(42, script->Run()->Int32Value());
6184   }
6185 }
6186 
6187 
GetSurvivingGlobalObjectsCount()6188 static int GetSurvivingGlobalObjectsCount() {
6189   int count = 0;
6190   // We need to collect all garbage twice to be sure that everything
6191   // has been collected.  This is because inline caches are cleared in
6192   // the first garbage collection but some of the maps have already
6193   // been marked at that point.  Therefore some of the maps are not
6194   // collected until the second garbage collection.
6195   v8::internal::Heap::CollectAllGarbage(false);
6196   v8::internal::Heap::CollectAllGarbage(false);
6197   v8::internal::HeapIterator it;
6198   while (it.has_next()) {
6199     v8::internal::HeapObject* object = it.next();
6200     if (object->IsJSGlobalObject()) {
6201       count++;
6202     }
6203   }
6204 #ifdef DEBUG
6205   if (count > 0) v8::internal::Heap::TracePathToGlobal();
6206 #endif
6207   return count;
6208 }
6209 
6210 
TEST(DontLeakGlobalObjects)6211 TEST(DontLeakGlobalObjects) {
6212   // Regression test for issues 1139850 and 1174891.
6213 
6214   v8::V8::Initialize();
6215 
6216   int count = GetSurvivingGlobalObjectsCount();
6217 
6218   for (int i = 0; i < 5; i++) {
6219     { v8::HandleScope scope;
6220       LocalContext context;
6221     }
6222     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6223 
6224     { v8::HandleScope scope;
6225       LocalContext context;
6226       v8_compile("Date")->Run();
6227     }
6228     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6229 
6230     { v8::HandleScope scope;
6231       LocalContext context;
6232       v8_compile("/aaa/")->Run();
6233     }
6234     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6235 
6236     { v8::HandleScope scope;
6237       const char* extension_list[] = { "v8/gc" };
6238       v8::ExtensionConfiguration extensions(1, extension_list);
6239       LocalContext context(&extensions);
6240       v8_compile("gc();")->Run();
6241     }
6242     CHECK_EQ(count, GetSurvivingGlobalObjectsCount());
6243   }
6244 }
6245 
6246 
6247 v8::Persistent<v8::Object> some_object;
6248 v8::Persistent<v8::Object> bad_handle;
6249 
NewPersistentHandleCallback(v8::Persistent<v8::Value>,void *)6250 void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
6251   v8::HandleScope scope;
6252   bad_handle = v8::Persistent<v8::Object>::New(some_object);
6253 }
6254 
6255 
THREADED_TEST(NewPersistentHandleFromWeakCallback)6256 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
6257   LocalContext context;
6258 
6259   v8::Persistent<v8::Object> handle1, handle2;
6260   {
6261     v8::HandleScope scope;
6262     some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
6263     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6264     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6265   }
6266   // Note: order is implementation dependent alas: currently
6267   // global handle nodes are processed by PostGarbageCollectionProcessing
6268   // in reverse allocation order, so if second allocated handle is deleted,
6269   // weak callback of the first handle would be able to 'reallocate' it.
6270   handle1.MakeWeak(NULL, NewPersistentHandleCallback);
6271   handle2.Dispose();
6272   i::Heap::CollectAllGarbage(false);
6273 }
6274 
6275 
6276 v8::Persistent<v8::Object> to_be_disposed;
6277 
DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle,void *)6278 void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
6279   to_be_disposed.Dispose();
6280   i::Heap::CollectAllGarbage(false);
6281 }
6282 
6283 
THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc)6284 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
6285   LocalContext context;
6286 
6287   v8::Persistent<v8::Object> handle1, handle2;
6288   {
6289     v8::HandleScope scope;
6290     handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
6291     handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
6292   }
6293   handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
6294   to_be_disposed = handle2;
6295   i::Heap::CollectAllGarbage(false);
6296 }
6297 
6298 
THREADED_TEST(CheckForCrossContextObjectLiterals)6299 THREADED_TEST(CheckForCrossContextObjectLiterals) {
6300   v8::V8::Initialize();
6301 
6302   const int nof = 2;
6303   const char* sources[nof] = {
6304     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
6305     "Object()"
6306   };
6307 
6308   for (int i = 0; i < nof; i++) {
6309     const char* source = sources[i];
6310     { v8::HandleScope scope;
6311       LocalContext context;
6312       CompileRun(source);
6313     }
6314     { v8::HandleScope scope;
6315       LocalContext context;
6316       CompileRun(source);
6317     }
6318   }
6319 }
6320 
6321 
NestedScope(v8::Persistent<Context> env)6322 static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) {
6323   v8::HandleScope inner;
6324   env->Enter();
6325   v8::Handle<Value> three = v8_num(3);
6326   v8::Handle<Value> value = inner.Close(three);
6327   env->Exit();
6328   return value;
6329 }
6330 
6331 
THREADED_TEST(NestedHandleScopeAndContexts)6332 THREADED_TEST(NestedHandleScopeAndContexts) {
6333   v8::HandleScope outer;
6334   v8::Persistent<Context> env = Context::New();
6335   env->Enter();
6336   v8::Handle<Value> value = NestedScope(env);
6337   v8::Handle<String> str = value->ToString();
6338   env->Exit();
6339   env.Dispose();
6340 }
6341 
6342 
THREADED_TEST(ExternalAllocatedMemory)6343 THREADED_TEST(ExternalAllocatedMemory) {
6344   v8::HandleScope outer;
6345   v8::Persistent<Context> env = Context::New();
6346   const int kSize = 1024*1024;
6347   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
6348   CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
6349 }
6350 
6351 
THREADED_TEST(DisposeEnteredContext)6352 THREADED_TEST(DisposeEnteredContext) {
6353   v8::HandleScope scope;
6354   LocalContext outer;
6355   { v8::Persistent<v8::Context> inner = v8::Context::New();
6356     inner->Enter();
6357     inner.Dispose();
6358     inner.Clear();
6359     inner->Exit();
6360   }
6361 }
6362 
6363 
6364 // Regression test for issue 54, object templates with internal fields
6365 // but no accessors or interceptors did not get their internal field
6366 // count set on instances.
THREADED_TEST(Regress54)6367 THREADED_TEST(Regress54) {
6368   v8::HandleScope outer;
6369   LocalContext context;
6370   static v8::Persistent<v8::ObjectTemplate> templ;
6371   if (templ.IsEmpty()) {
6372     v8::HandleScope inner;
6373     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
6374     local->SetInternalFieldCount(1);
6375     templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local));
6376   }
6377   v8::Handle<v8::Object> result = templ->NewInstance();
6378   CHECK_EQ(1, result->InternalFieldCount());
6379 }
6380 
6381 
6382 // If part of the threaded tests, this test makes ThreadingTest fail
6383 // on mac.
TEST(CatchStackOverflow)6384 TEST(CatchStackOverflow) {
6385   v8::HandleScope scope;
6386   LocalContext context;
6387   v8::TryCatch try_catch;
6388   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
6389     "function f() {"
6390     "  return f();"
6391     "}"
6392     ""
6393     "f();"));
6394   v8::Handle<v8::Value> result = script->Run();
6395   CHECK(result.IsEmpty());
6396 }
6397 
6398 
CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,const char * resource_name,int line_offset)6399 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
6400                                     const char* resource_name,
6401                                     int line_offset) {
6402   v8::HandleScope scope;
6403   v8::TryCatch try_catch;
6404   v8::Handle<v8::Value> result = script->Run();
6405   CHECK(result.IsEmpty());
6406   CHECK(try_catch.HasCaught());
6407   v8::Handle<v8::Message> message = try_catch.Message();
6408   CHECK(!message.IsEmpty());
6409   CHECK_EQ(10 + line_offset, message->GetLineNumber());
6410   CHECK_EQ(91, message->GetStartPosition());
6411   CHECK_EQ(92, message->GetEndPosition());
6412   CHECK_EQ(2, message->GetStartColumn());
6413   CHECK_EQ(3, message->GetEndColumn());
6414   v8::String::AsciiValue line(message->GetSourceLine());
6415   CHECK_EQ("  throw 'nirk';", *line);
6416   v8::String::AsciiValue name(message->GetScriptResourceName());
6417   CHECK_EQ(resource_name, *name);
6418 }
6419 
6420 
THREADED_TEST(TryCatchSourceInfo)6421 THREADED_TEST(TryCatchSourceInfo) {
6422   v8::HandleScope scope;
6423   LocalContext context;
6424   v8::Handle<v8::String> source = v8::String::New(
6425       "function Foo() {\n"
6426       "  return Bar();\n"
6427       "}\n"
6428       "\n"
6429       "function Bar() {\n"
6430       "  return Baz();\n"
6431       "}\n"
6432       "\n"
6433       "function Baz() {\n"
6434       "  throw 'nirk';\n"
6435       "}\n"
6436       "\n"
6437       "Foo();\n");
6438 
6439   const char* resource_name;
6440   v8::Handle<v8::Script> script;
6441   resource_name = "test.js";
6442   script = v8::Script::Compile(source, v8::String::New(resource_name));
6443   CheckTryCatchSourceInfo(script, resource_name, 0);
6444 
6445   resource_name = "test1.js";
6446   v8::ScriptOrigin origin1(v8::String::New(resource_name));
6447   script = v8::Script::Compile(source, &origin1);
6448   CheckTryCatchSourceInfo(script, resource_name, 0);
6449 
6450   resource_name = "test2.js";
6451   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
6452   script = v8::Script::Compile(source, &origin2);
6453   CheckTryCatchSourceInfo(script, resource_name, 7);
6454 }
6455 
6456 
THREADED_TEST(CompilationCache)6457 THREADED_TEST(CompilationCache) {
6458   v8::HandleScope scope;
6459   LocalContext context;
6460   v8::Handle<v8::String> source0 = v8::String::New("1234");
6461   v8::Handle<v8::String> source1 = v8::String::New("1234");
6462   v8::Handle<v8::Script> script0 =
6463       v8::Script::Compile(source0, v8::String::New("test.js"));
6464   v8::Handle<v8::Script> script1 =
6465       v8::Script::Compile(source1, v8::String::New("test.js"));
6466   v8::Handle<v8::Script> script2 =
6467       v8::Script::Compile(source0);  // different origin
6468   CHECK_EQ(1234, script0->Run()->Int32Value());
6469   CHECK_EQ(1234, script1->Run()->Int32Value());
6470   CHECK_EQ(1234, script2->Run()->Int32Value());
6471 }
6472 
6473 
FunctionNameCallback(const v8::Arguments & args)6474 static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) {
6475   ApiTestFuzzer::Fuzz();
6476   return v8_num(42);
6477 }
6478 
6479 
THREADED_TEST(CallbackFunctionName)6480 THREADED_TEST(CallbackFunctionName) {
6481   v8::HandleScope scope;
6482   LocalContext context;
6483   Local<ObjectTemplate> t = ObjectTemplate::New();
6484   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
6485   context->Global()->Set(v8_str("obj"), t->NewInstance());
6486   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
6487   CHECK(value->IsString());
6488   v8::String::AsciiValue name(value);
6489   CHECK_EQ("asdf", *name);
6490 }
6491 
6492 
THREADED_TEST(DateAccess)6493 THREADED_TEST(DateAccess) {
6494   v8::HandleScope scope;
6495   LocalContext context;
6496   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
6497   CHECK(date->IsDate());
6498   CHECK_EQ(1224744689038.0, v8::Handle<v8::Date>::Cast(date)->NumberValue());
6499 }
6500 
6501 
CheckProperties(v8::Handle<v8::Value> val,int elmc,const char * elmv[])6502 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
6503   v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val);
6504   v8::Handle<v8::Array> props = obj->GetPropertyNames();
6505   CHECK_EQ(elmc, props->Length());
6506   for (int i = 0; i < elmc; i++) {
6507     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
6508     CHECK_EQ(elmv[i], *elm);
6509   }
6510 }
6511 
6512 
THREADED_TEST(PropertyEnumeration)6513 THREADED_TEST(PropertyEnumeration) {
6514   v8::HandleScope scope;
6515   LocalContext context;
6516   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
6517       "var result = [];"
6518       "result[0] = {};"
6519       "result[1] = {a: 1, b: 2};"
6520       "result[2] = [1, 2, 3];"
6521       "var proto = {x: 1, y: 2, z: 3};"
6522       "var x = { __proto__: proto, w: 0, z: 1 };"
6523       "result[3] = x;"
6524       "result;"))->Run();
6525   v8::Handle<v8::Array> elms = v8::Handle<v8::Array>::Cast(obj);
6526   CHECK_EQ(4, elms->Length());
6527   int elmc0 = 0;
6528   const char** elmv0 = NULL;
6529   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
6530   int elmc1 = 2;
6531   const char* elmv1[] = {"a", "b"};
6532   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
6533   int elmc2 = 3;
6534   const char* elmv2[] = {"0", "1", "2"};
6535   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
6536   int elmc3 = 4;
6537   const char* elmv3[] = {"w", "z", "x", "y"};
6538   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
6539 }
6540 
6541 
AccessorProhibitsOverwritingGetter(Local<String> name,const AccessorInfo & info)6542 static v8::Handle<Value> AccessorProhibitsOverwritingGetter(
6543     Local<String> name,
6544     const AccessorInfo& info) {
6545   ApiTestFuzzer::Fuzz();
6546   return v8::True();
6547 }
6548 
6549 
THREADED_TEST(AccessorProhibitsOverwriting)6550 THREADED_TEST(AccessorProhibitsOverwriting) {
6551   v8::HandleScope scope;
6552   LocalContext context;
6553   Local<ObjectTemplate> templ = ObjectTemplate::New();
6554   templ->SetAccessor(v8_str("x"),
6555                      AccessorProhibitsOverwritingGetter,
6556                      0,
6557                      v8::Handle<Value>(),
6558                      v8::PROHIBITS_OVERWRITING,
6559                      v8::ReadOnly);
6560   Local<v8::Object> instance = templ->NewInstance();
6561   context->Global()->Set(v8_str("obj"), instance);
6562   Local<Value> value = CompileRun(
6563       "obj.__defineGetter__('x', function() { return false; });"
6564       "obj.x");
6565   CHECK(value->BooleanValue());
6566   value = CompileRun(
6567       "var setter_called = false;"
6568       "obj.__defineSetter__('x', function() { setter_called = true; });"
6569       "obj.x = 42;"
6570       "setter_called");
6571   CHECK(!value->BooleanValue());
6572   value = CompileRun(
6573       "obj2 = {};"
6574       "obj2.__proto__ = obj;"
6575       "obj2.__defineGetter__('x', function() { return false; });"
6576       "obj2.x");
6577   CHECK(value->BooleanValue());
6578   value = CompileRun(
6579       "var setter_called = false;"
6580       "obj2 = {};"
6581       "obj2.__proto__ = obj;"
6582       "obj2.__defineSetter__('x', function() { setter_called = true; });"
6583       "obj2.x = 42;"
6584       "setter_called");
6585   CHECK(!value->BooleanValue());
6586 }
6587 
6588 
NamedSetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)6589 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
6590                                   Local<Value> name,
6591                                   v8::AccessType type,
6592                                   Local<Value> data) {
6593   return type != v8::ACCESS_SET;
6594 }
6595 
6596 
IndexedSetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)6597 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
6598                                     uint32_t key,
6599                                     v8::AccessType type,
6600                                     Local<Value> data) {
6601   return type != v8::ACCESS_SET;
6602 }
6603 
6604 
THREADED_TEST(DisableAccessChecksWhileConfiguring)6605 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
6606   v8::HandleScope scope;
6607   LocalContext context;
6608   Local<ObjectTemplate> templ = ObjectTemplate::New();
6609   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6610                                  IndexedSetAccessBlocker);
6611   templ->Set(v8_str("x"), v8::True());
6612   Local<v8::Object> instance = templ->NewInstance();
6613   context->Global()->Set(v8_str("obj"), instance);
6614   Local<Value> value = CompileRun("obj.x");
6615   CHECK(value->BooleanValue());
6616 }
6617 
6618 
NamedGetAccessBlocker(Local<v8::Object> obj,Local<Value> name,v8::AccessType type,Local<Value> data)6619 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
6620                                   Local<Value> name,
6621                                   v8::AccessType type,
6622                                   Local<Value> data) {
6623   return false;
6624 }
6625 
6626 
IndexedGetAccessBlocker(Local<v8::Object> obj,uint32_t key,v8::AccessType type,Local<Value> data)6627 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
6628                                     uint32_t key,
6629                                     v8::AccessType type,
6630                                     Local<Value> data) {
6631   return false;
6632 }
6633 
6634 
6635 
THREADED_TEST(AccessChecksReenabledCorrectly)6636 THREADED_TEST(AccessChecksReenabledCorrectly) {
6637   v8::HandleScope scope;
6638   LocalContext context;
6639   Local<ObjectTemplate> templ = ObjectTemplate::New();
6640   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6641                                  IndexedGetAccessBlocker);
6642   templ->Set(v8_str("a"), v8_str("a"));
6643   // Add more than 8 (see kMaxFastProperties) properties
6644   // so that the constructor will force copying map.
6645   // Cannot sprintf, gcc complains unsafety.
6646   char buf[4];
6647   for (char i = '0'; i <= '9' ; i++) {
6648     buf[0] = i;
6649     for (char j = '0'; j <= '9'; j++) {
6650       buf[1] = j;
6651       for (char k = '0'; k <= '9'; k++) {
6652         buf[2] = k;
6653         buf[3] = 0;
6654         templ->Set(v8_str(buf), v8::Number::New(k));
6655       }
6656     }
6657   }
6658 
6659   Local<v8::Object> instance_1 = templ->NewInstance();
6660   context->Global()->Set(v8_str("obj_1"), instance_1);
6661 
6662   Local<Value> value_1 = CompileRun("obj_1.a");
6663   CHECK(value_1->IsUndefined());
6664 
6665   Local<v8::Object> instance_2 = templ->NewInstance();
6666   context->Global()->Set(v8_str("obj_2"), instance_2);
6667 
6668   Local<Value> value_2 = CompileRun("obj_2.a");
6669   CHECK(value_2->IsUndefined());
6670 }
6671 
6672 
6673 // This tests that access check information remains on the global
6674 // object template when creating contexts.
THREADED_TEST(AccessControlRepeatedContextCreation)6675 THREADED_TEST(AccessControlRepeatedContextCreation) {
6676   v8::HandleScope handle_scope;
6677   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6678   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
6679                                            IndexedSetAccessBlocker);
6680   i::Handle<i::ObjectTemplateInfo> internal_template =
6681       v8::Utils::OpenHandle(*global_template);
6682   CHECK(!internal_template->constructor()->IsUndefined());
6683   i::Handle<i::FunctionTemplateInfo> constructor(
6684       i::FunctionTemplateInfo::cast(internal_template->constructor()));
6685   CHECK(!constructor->access_check_info()->IsUndefined());
6686   v8::Persistent<Context> context0 = Context::New(NULL, global_template);
6687   CHECK(!constructor->access_check_info()->IsUndefined());
6688 }
6689 
6690 
THREADED_TEST(TurnOnAccessCheck)6691 THREADED_TEST(TurnOnAccessCheck) {
6692   v8::HandleScope handle_scope;
6693 
6694   // Create an environment with access check to the global object disabled by
6695   // default.
6696   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
6697   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
6698                                            IndexedGetAccessBlocker,
6699                                            v8::Handle<v8::Value>(),
6700                                            false);
6701   v8::Persistent<Context> context = Context::New(NULL, global_template);
6702   Context::Scope context_scope(context);
6703 
6704   // Set up a property and a number of functions.
6705   context->Global()->Set(v8_str("a"), v8_num(1));
6706   CompileRun("function f1() {return a;}"
6707              "function f2() {return a;}"
6708              "function g1() {return h();}"
6709              "function g2() {return h();}"
6710              "function h() {return 1;}");
6711   Local<Function> f1 =
6712       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
6713   Local<Function> f2 =
6714       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
6715   Local<Function> g1 =
6716       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
6717   Local<Function> g2 =
6718       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
6719   Local<Function> h =
6720       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
6721 
6722   // Get the global object.
6723   v8::Handle<v8::Object> global = context->Global();
6724 
6725   // Call f1 one time and f2 a number of times. This will ensure that f1 still
6726   // uses the runtime system to retreive property a whereas f2 uses global load
6727   // inline cache.
6728   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
6729   for (int i = 0; i < 4; i++) {
6730     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
6731   }
6732 
6733   // Same for g1 and g2.
6734   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
6735   for (int i = 0; i < 4; i++) {
6736     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
6737   }
6738 
6739   // Detach the global and turn on access check.
6740   context->DetachGlobal();
6741   context->Global()->TurnOnAccessCheck();
6742 
6743   // Failing access check to property get results in undefined.
6744   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
6745   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
6746 
6747   // Failing access check to function call results in exception.
6748   CHECK(g1->Call(global, 0, NULL).IsEmpty());
6749   CHECK(g2->Call(global, 0, NULL).IsEmpty());
6750 
6751   // No failing access check when just returning a constant.
6752   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
6753 }
6754 
6755 
6756 // This test verifies that pre-compilation (aka preparsing) can be called
6757 // without initializing the whole VM. Thus we cannot run this test in a
6758 // multi-threaded setup.
TEST(PreCompile)6759 TEST(PreCompile) {
6760   // TODO(155): This test would break without the initialization of V8. This is
6761   // a workaround for now to make this test not fail.
6762   v8::V8::Initialize();
6763   const char *script = "function foo(a) { return a+1; }";
6764   v8::ScriptData *sd = v8::ScriptData::PreCompile(script, strlen(script));
6765   CHECK_NE(sd->Length(), 0);
6766   CHECK_NE(sd->Data(), NULL);
6767   delete sd;
6768 }
6769 
6770 
6771 // This tests that we do not allow dictionary load/call inline caches
6772 // to use functions that have not yet been compiled.  The potential
6773 // problem of loading a function that has not yet been compiled can
6774 // arise because we share code between contexts via the compilation
6775 // cache.
THREADED_TEST(DictionaryICLoadedFunction)6776 THREADED_TEST(DictionaryICLoadedFunction) {
6777   v8::HandleScope scope;
6778   // Test LoadIC.
6779   for (int i = 0; i < 2; i++) {
6780     LocalContext context;
6781     context->Global()->Set(v8_str("tmp"), v8::True());
6782     context->Global()->Delete(v8_str("tmp"));
6783     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
6784   }
6785   // Test CallIC.
6786   for (int i = 0; i < 2; i++) {
6787     LocalContext context;
6788     context->Global()->Set(v8_str("tmp"), v8::True());
6789     context->Global()->Delete(v8_str("tmp"));
6790     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
6791   }
6792 }
6793 
6794 
6795 // Test that cross-context new calls use the context of the callee to
6796 // create the new JavaScript object.
THREADED_TEST(CrossContextNew)6797 THREADED_TEST(CrossContextNew) {
6798   v8::HandleScope scope;
6799   v8::Persistent<Context> context0 = Context::New();
6800   v8::Persistent<Context> context1 = Context::New();
6801 
6802   // Allow cross-domain access.
6803   Local<String> token = v8_str("<security token>");
6804   context0->SetSecurityToken(token);
6805   context1->SetSecurityToken(token);
6806 
6807   // Set an 'x' property on the Object prototype and define a
6808   // constructor function in context0.
6809   context0->Enter();
6810   CompileRun("Object.prototype.x = 42; function C() {};");
6811   context0->Exit();
6812 
6813   // Call the constructor function from context0 and check that the
6814   // result has the 'x' property.
6815   context1->Enter();
6816   context1->Global()->Set(v8_str("other"), context0->Global());
6817   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
6818   CHECK(value->IsInt32());
6819   CHECK_EQ(42, value->Int32Value());
6820   context1->Exit();
6821 
6822   // Dispose the contexts to allow them to be garbage collected.
6823   context0.Dispose();
6824   context1.Dispose();
6825 }
6826 
6827 
6828 class RegExpInterruptTest {
6829  public:
RegExpInterruptTest()6830   RegExpInterruptTest() : block_(NULL) {}
~RegExpInterruptTest()6831   ~RegExpInterruptTest() { delete block_; }
RunTest()6832   void RunTest() {
6833     block_ = i::OS::CreateSemaphore(0);
6834     gc_count_ = 0;
6835     gc_during_regexp_ = 0;
6836     regexp_success_ = false;
6837     gc_success_ = false;
6838     GCThread gc_thread(this);
6839     gc_thread.Start();
6840     v8::Locker::StartPreemption(1);
6841 
6842     LongRunningRegExp();
6843     {
6844       v8::Unlocker unlock;
6845       gc_thread.Join();
6846     }
6847     v8::Locker::StopPreemption();
6848     CHECK(regexp_success_);
6849     CHECK(gc_success_);
6850   }
6851  private:
6852   // Number of garbage collections required.
6853   static const int kRequiredGCs = 5;
6854 
6855   class GCThread : public i::Thread {
6856    public:
GCThread(RegExpInterruptTest * test)6857     explicit GCThread(RegExpInterruptTest* test)
6858         : test_(test) {}
Run()6859     virtual void Run() {
6860       test_->CollectGarbage();
6861     }
6862    private:
6863      RegExpInterruptTest* test_;
6864   };
6865 
CollectGarbage()6866   void CollectGarbage() {
6867     block_->Wait();
6868     while (gc_during_regexp_ < kRequiredGCs) {
6869       {
6870         v8::Locker lock;
6871         // TODO(lrn): Perhaps create some garbage before collecting.
6872         i::Heap::CollectAllGarbage(false);
6873         gc_count_++;
6874       }
6875       i::OS::Sleep(1);
6876     }
6877     gc_success_ = true;
6878   }
6879 
LongRunningRegExp()6880   void LongRunningRegExp() {
6881     block_->Signal();  // Enable garbage collection thread on next preemption.
6882     int rounds = 0;
6883     while (gc_during_regexp_ < kRequiredGCs) {
6884       int gc_before = gc_count_;
6885       {
6886         // Match 15-30 "a"'s against 14 and a "b".
6887         const char* c_source =
6888             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
6889             ".exec('aaaaaaaaaaaaaaab') === null";
6890         Local<String> source = String::New(c_source);
6891         Local<Script> script = Script::Compile(source);
6892         Local<Value> result = script->Run();
6893         if (!result->BooleanValue()) {
6894           gc_during_regexp_ = kRequiredGCs;  // Allow gc thread to exit.
6895           return;
6896         }
6897       }
6898       {
6899         // Match 15-30 "a"'s against 15 and a "b".
6900         const char* c_source =
6901             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
6902             ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
6903         Local<String> source = String::New(c_source);
6904         Local<Script> script = Script::Compile(source);
6905         Local<Value> result = script->Run();
6906         if (!result->BooleanValue()) {
6907           gc_during_regexp_ = kRequiredGCs;
6908           return;
6909         }
6910       }
6911       int gc_after = gc_count_;
6912       gc_during_regexp_ += gc_after - gc_before;
6913       rounds++;
6914       i::OS::Sleep(1);
6915     }
6916     regexp_success_ = true;
6917   }
6918 
6919   i::Semaphore* block_;
6920   int gc_count_;
6921   int gc_during_regexp_;
6922   bool regexp_success_;
6923   bool gc_success_;
6924 };
6925 
6926 
6927 // Test that a regular expression execution can be interrupted and
6928 // survive a garbage collection.
TEST(RegExpInterruption)6929 TEST(RegExpInterruption) {
6930   v8::Locker lock;
6931   v8::V8::Initialize();
6932   v8::HandleScope scope;
6933   Local<Context> local_env;
6934   {
6935     LocalContext env;
6936     local_env = env.local();
6937   }
6938 
6939   // Local context should still be live.
6940   CHECK(!local_env.IsEmpty());
6941   local_env->Enter();
6942 
6943   // Should complete without problems.
6944   RegExpInterruptTest().RunTest();
6945 
6946   local_env->Exit();
6947 }
6948 
6949 
6950 class ApplyInterruptTest {
6951  public:
ApplyInterruptTest()6952   ApplyInterruptTest() : block_(NULL) {}
~ApplyInterruptTest()6953   ~ApplyInterruptTest() { delete block_; }
RunTest()6954   void RunTest() {
6955     block_ = i::OS::CreateSemaphore(0);
6956     gc_count_ = 0;
6957     gc_during_apply_ = 0;
6958     apply_success_ = false;
6959     gc_success_ = false;
6960     GCThread gc_thread(this);
6961     gc_thread.Start();
6962     v8::Locker::StartPreemption(1);
6963 
6964     LongRunningApply();
6965     {
6966       v8::Unlocker unlock;
6967       gc_thread.Join();
6968     }
6969     v8::Locker::StopPreemption();
6970     CHECK(apply_success_);
6971     CHECK(gc_success_);
6972   }
6973  private:
6974   // Number of garbage collections required.
6975   static const int kRequiredGCs = 2;
6976 
6977   class GCThread : public i::Thread {
6978    public:
GCThread(ApplyInterruptTest * test)6979     explicit GCThread(ApplyInterruptTest* test)
6980         : test_(test) {}
Run()6981     virtual void Run() {
6982       test_->CollectGarbage();
6983     }
6984    private:
6985      ApplyInterruptTest* test_;
6986   };
6987 
CollectGarbage()6988   void CollectGarbage() {
6989     block_->Wait();
6990     while (gc_during_apply_ < kRequiredGCs) {
6991       {
6992         v8::Locker lock;
6993         i::Heap::CollectAllGarbage(false);
6994         gc_count_++;
6995       }
6996       i::OS::Sleep(1);
6997     }
6998     gc_success_ = true;
6999   }
7000 
LongRunningApply()7001   void LongRunningApply() {
7002     block_->Signal();
7003     int rounds = 0;
7004     while (gc_during_apply_ < kRequiredGCs) {
7005       int gc_before = gc_count_;
7006       {
7007         const char* c_source =
7008             "function do_very_little(bar) {"
7009             "  this.foo = bar;"
7010             "}"
7011             "for (var i = 0; i < 100000; i++) {"
7012             "  do_very_little.apply(this, ['bar']);"
7013             "}";
7014         Local<String> source = String::New(c_source);
7015         Local<Script> script = Script::Compile(source);
7016         Local<Value> result = script->Run();
7017         // Check that no exception was thrown.
7018         CHECK(!result.IsEmpty());
7019       }
7020       int gc_after = gc_count_;
7021       gc_during_apply_ += gc_after - gc_before;
7022       rounds++;
7023     }
7024     apply_success_ = true;
7025   }
7026 
7027   i::Semaphore* block_;
7028   int gc_count_;
7029   int gc_during_apply_;
7030   bool apply_success_;
7031   bool gc_success_;
7032 };
7033 
7034 
7035 // Test that nothing bad happens if we get a preemption just when we were
7036 // about to do an apply().
TEST(ApplyInterruption)7037 TEST(ApplyInterruption) {
7038   v8::Locker lock;
7039   v8::V8::Initialize();
7040   v8::HandleScope scope;
7041   Local<Context> local_env;
7042   {
7043     LocalContext env;
7044     local_env = env.local();
7045   }
7046 
7047   // Local context should still be live.
7048   CHECK(!local_env.IsEmpty());
7049   local_env->Enter();
7050 
7051   // Should complete without problems.
7052   ApplyInterruptTest().RunTest();
7053 
7054   local_env->Exit();
7055 }
7056 
7057 
7058 // Verify that we can clone an object
TEST(ObjectClone)7059 TEST(ObjectClone) {
7060   v8::HandleScope scope;
7061   LocalContext env;
7062 
7063   const char* sample =
7064     "var rv = {};"      \
7065     "rv.alpha = 'hello';" \
7066     "rv.beta = 123;"     \
7067     "rv;";
7068 
7069   // Create an object, verify basics.
7070   Local<Value> val = CompileRun(sample);
7071   CHECK(val->IsObject());
7072   Local<v8::Object> obj = Local<v8::Object>::Cast(val);
7073   obj->Set(v8_str("gamma"), v8_str("cloneme"));
7074 
7075   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
7076   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7077   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
7078 
7079   // Clone it.
7080   Local<v8::Object> clone = obj->Clone();
7081   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
7082   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
7083   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
7084 
7085   // Set a property on the clone, verify each object.
7086   clone->Set(v8_str("beta"), v8::Integer::New(456));
7087   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
7088   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
7089 }
7090 
7091 
7092 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
7093  public:
AsciiVectorResource(i::Vector<const char> vector)7094   explicit AsciiVectorResource(i::Vector<const char> vector)
7095       : data_(vector) {}
~AsciiVectorResource()7096   virtual ~AsciiVectorResource() {}
length() const7097   virtual size_t length() const { return data_.length(); }
data() const7098   virtual const char* data() const { return data_.start(); }
7099  private:
7100   i::Vector<const char> data_;
7101 };
7102 
7103 
7104 class UC16VectorResource : public v8::String::ExternalStringResource {
7105  public:
UC16VectorResource(i::Vector<const i::uc16> vector)7106   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
7107       : data_(vector) {}
~UC16VectorResource()7108   virtual ~UC16VectorResource() {}
length() const7109   virtual size_t length() const { return data_.length(); }
data() const7110   virtual const i::uc16* data() const { return data_.start(); }
7111  private:
7112   i::Vector<const i::uc16> data_;
7113 };
7114 
7115 
MorphAString(i::String * string,AsciiVectorResource * ascii_resource,UC16VectorResource * uc16_resource)7116 static void MorphAString(i::String* string,
7117                          AsciiVectorResource* ascii_resource,
7118                          UC16VectorResource* uc16_resource) {
7119   CHECK(i::StringShape(string).IsExternal());
7120   if (string->IsAsciiRepresentation()) {
7121     // Check old map is not symbol or long.
7122     CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
7123           string->map() == i::Heap::medium_external_ascii_string_map());
7124     // Morph external string to be TwoByte string.
7125     if (string->length() <= i::String::kMaxShortStringSize) {
7126       string->set_map(i::Heap::short_external_string_map());
7127     } else {
7128       string->set_map(i::Heap::medium_external_string_map());
7129     }
7130     i::ExternalTwoByteString* morphed =
7131          i::ExternalTwoByteString::cast(string);
7132     morphed->set_resource(uc16_resource);
7133   } else {
7134     // Check old map is not symbol or long.
7135     CHECK(string->map() == i::Heap::short_external_string_map() ||
7136           string->map() == i::Heap::medium_external_string_map());
7137     // Morph external string to be ASCII string.
7138     if (string->length() <= i::String::kMaxShortStringSize) {
7139       string->set_map(i::Heap::short_external_ascii_string_map());
7140     } else {
7141       string->set_map(i::Heap::medium_external_ascii_string_map());
7142     }
7143     i::ExternalAsciiString* morphed =
7144          i::ExternalAsciiString::cast(string);
7145     morphed->set_resource(ascii_resource);
7146   }
7147 }
7148 
7149 
7150 // Test that we can still flatten a string if the components it is built up
7151 // from have been turned into 16 bit strings in the mean time.
THREADED_TEST(MorphCompositeStringTest)7152 THREADED_TEST(MorphCompositeStringTest) {
7153   const char* c_string = "Now is the time for all good men"
7154                          " to come to the aid of the party";
7155   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
7156   {
7157     v8::HandleScope scope;
7158     LocalContext env;
7159     AsciiVectorResource ascii_resource(
7160         i::Vector<const char>(c_string, strlen(c_string)));
7161     UC16VectorResource uc16_resource(
7162         i::Vector<const uint16_t>(two_byte_string, strlen(c_string)));
7163 
7164     Local<String> lhs(v8::Utils::ToLocal(
7165         i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7166     Local<String> rhs(v8::Utils::ToLocal(
7167         i::Factory::NewExternalStringFromAscii(&ascii_resource)));
7168 
7169     env->Global()->Set(v8_str("lhs"), lhs);
7170     env->Global()->Set(v8_str("rhs"), rhs);
7171 
7172     CompileRun(
7173         "var cons = lhs + rhs;"
7174         "var slice = lhs.substring(1, lhs.length - 1);"
7175         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
7176 
7177     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
7178     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
7179 
7180     // Now do some stuff to make sure the strings are flattened, etc.
7181     CompileRun(
7182         "/[^a-z]/.test(cons);"
7183         "/[^a-z]/.test(slice);"
7184         "/[^a-z]/.test(slice_on_cons);");
7185     const char* expected_cons =
7186         "Now is the time for all good men to come to the aid of the party"
7187         "Now is the time for all good men to come to the aid of the party";
7188     const char* expected_slice =
7189         "ow is the time for all good men to come to the aid of the part";
7190     const char* expected_slice_on_cons =
7191         "ow is the time for all good men to come to the aid of the party"
7192         "Now is the time for all good men to come to the aid of the part";
7193     CHECK_EQ(String::New(expected_cons),
7194              env->Global()->Get(v8_str("cons")));
7195     CHECK_EQ(String::New(expected_slice),
7196              env->Global()->Get(v8_str("slice")));
7197     CHECK_EQ(String::New(expected_slice_on_cons),
7198              env->Global()->Get(v8_str("slice_on_cons")));
7199   }
7200 }
7201 
7202 
TEST(CompileExternalTwoByteSource)7203 TEST(CompileExternalTwoByteSource) {
7204   v8::HandleScope scope;
7205   LocalContext context;
7206 
7207   // This is a very short list of sources, which currently is to check for a
7208   // regression caused by r2703.
7209   const char* ascii_sources[] = {
7210     "0.5",
7211     "-0.5",   // This mainly testes PushBack in the Scanner.
7212     "--0.5",  // This mainly testes PushBack in the Scanner.
7213     NULL
7214   };
7215 
7216   // Compile the sources as external two byte strings.
7217   for (int i = 0; ascii_sources[i] != NULL; i++) {
7218     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
7219     UC16VectorResource uc16_resource(
7220         i::Vector<const uint16_t>(two_byte_string, strlen(ascii_sources[i])));
7221     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
7222     v8::Script::Compile(source);
7223   }
7224 }
7225 
7226 
7227 class RegExpStringModificationTest {
7228  public:
RegExpStringModificationTest()7229   RegExpStringModificationTest()
7230       : block_(i::OS::CreateSemaphore(0)),
7231         morphs_(0),
7232         morphs_during_regexp_(0),
7233         ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
7234         uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
~RegExpStringModificationTest()7235   ~RegExpStringModificationTest() { delete block_; }
RunTest()7236   void RunTest() {
7237     regexp_success_ = false;
7238     morph_success_ = false;
7239 
7240     // Initialize the contents of two_byte_content_ to be a uc16 representation
7241     // of "aaaaaaaaaaaaaab".
7242     for (int i = 0; i < 14; i++) {
7243       two_byte_content_[i] = 'a';
7244     }
7245     two_byte_content_[14] = 'b';
7246 
7247     // Create the input string for the regexp - the one we are going to change
7248     // properties of.
7249     input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_);
7250 
7251     // Inject the input as a global variable.
7252     i::Handle<i::String> input_name =
7253         i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5));
7254     i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE);
7255 
7256 
7257     MorphThread morph_thread(this);
7258     morph_thread.Start();
7259     v8::Locker::StartPreemption(1);
7260     LongRunningRegExp();
7261     {
7262       v8::Unlocker unlock;
7263       morph_thread.Join();
7264     }
7265     v8::Locker::StopPreemption();
7266     CHECK(regexp_success_);
7267     CHECK(morph_success_);
7268   }
7269  private:
7270 
7271   // Number of string modifications required.
7272   static const int kRequiredModifications = 5;
7273   static const int kMaxModifications = 100;
7274 
7275   class MorphThread : public i::Thread {
7276    public:
MorphThread(RegExpStringModificationTest * test)7277     explicit MorphThread(RegExpStringModificationTest* test)
7278         : test_(test) {}
Run()7279     virtual void Run() {
7280       test_->MorphString();
7281     }
7282    private:
7283      RegExpStringModificationTest* test_;
7284   };
7285 
MorphString()7286   void MorphString() {
7287     block_->Wait();
7288     while (morphs_during_regexp_ < kRequiredModifications &&
7289            morphs_ < kMaxModifications) {
7290       {
7291         v8::Locker lock;
7292         // Swap string between ascii and two-byte representation.
7293         i::String* string = *input_;
7294         MorphAString(string, &ascii_resource_, &uc16_resource_);
7295         morphs_++;
7296       }
7297       i::OS::Sleep(1);
7298     }
7299     morph_success_ = true;
7300   }
7301 
LongRunningRegExp()7302   void LongRunningRegExp() {
7303     block_->Signal();  // Enable morphing thread on next preemption.
7304     while (morphs_during_regexp_ < kRequiredModifications &&
7305            morphs_ < kMaxModifications) {
7306       int morphs_before = morphs_;
7307       {
7308         // Match 15-30 "a"'s against 14 and a "b".
7309         const char* c_source =
7310             "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
7311             ".exec(input) === null";
7312         Local<String> source = String::New(c_source);
7313         Local<Script> script = Script::Compile(source);
7314         Local<Value> result = script->Run();
7315         CHECK(result->IsTrue());
7316       }
7317       int morphs_after = morphs_;
7318       morphs_during_regexp_ += morphs_after - morphs_before;
7319     }
7320     regexp_success_ = true;
7321   }
7322 
7323   i::uc16 two_byte_content_[15];
7324   i::Semaphore* block_;
7325   int morphs_;
7326   int morphs_during_regexp_;
7327   bool regexp_success_;
7328   bool morph_success_;
7329   i::Handle<i::String> input_;
7330   AsciiVectorResource ascii_resource_;
7331   UC16VectorResource uc16_resource_;
7332 };
7333 
7334 
7335 // Test that a regular expression execution can be interrupted and
7336 // the string changed without failing.
TEST(RegExpStringModification)7337 TEST(RegExpStringModification) {
7338   v8::Locker lock;
7339   v8::V8::Initialize();
7340   v8::HandleScope scope;
7341   Local<Context> local_env;
7342   {
7343     LocalContext env;
7344     local_env = env.local();
7345   }
7346 
7347   // Local context should still be live.
7348   CHECK(!local_env.IsEmpty());
7349   local_env->Enter();
7350 
7351   // Should complete without problems.
7352   RegExpStringModificationTest().RunTest();
7353 
7354   local_env->Exit();
7355 }
7356 
7357 
7358 // Test that we can set a property on the global object even if there
7359 // is a read-only property in the prototype chain.
TEST(ReadOnlyPropertyInGlobalProto)7360 TEST(ReadOnlyPropertyInGlobalProto) {
7361   v8::HandleScope scope;
7362   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7363   LocalContext context(0, templ);
7364   v8::Handle<v8::Object> global = context->Global();
7365   v8::Handle<v8::Object> global_proto =
7366       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
7367   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
7368   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
7369   // Check without 'eval' or 'with'.
7370   v8::Handle<v8::Value> res =
7371       CompileRun("function f() { x = 42; return x; }; f()");
7372   // Check with 'eval'.
7373   res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()");
7374   CHECK_EQ(v8::Integer::New(42), res);
7375   // Check with 'with'.
7376   res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()");
7377   CHECK_EQ(v8::Integer::New(42), res);
7378 }
7379 
7380 static int force_set_set_count = 0;
7381 static int force_set_get_count = 0;
7382 bool pass_on_get = false;
7383 
ForceSetGetter(v8::Local<v8::String> name,const v8::AccessorInfo & info)7384 static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name,
7385                                             const v8::AccessorInfo& info) {
7386   force_set_get_count++;
7387   if (pass_on_get) {
7388     return v8::Handle<v8::Value>();
7389   } else {
7390     return v8::Int32::New(3);
7391   }
7392 }
7393 
ForceSetSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::AccessorInfo & info)7394 static void ForceSetSetter(v8::Local<v8::String> name,
7395                            v8::Local<v8::Value> value,
7396                            const v8::AccessorInfo& info) {
7397   force_set_set_count++;
7398 }
7399 
ForceSetInterceptSetter(v8::Local<v8::String> name,v8::Local<v8::Value> value,const v8::AccessorInfo & info)7400 static v8::Handle<v8::Value> ForceSetInterceptSetter(
7401     v8::Local<v8::String> name,
7402     v8::Local<v8::Value> value,
7403     const v8::AccessorInfo& info) {
7404   force_set_set_count++;
7405   return v8::Undefined();
7406 }
7407 
TEST(ForceSet)7408 TEST(ForceSet) {
7409   force_set_get_count = 0;
7410   force_set_set_count = 0;
7411   pass_on_get = false;
7412 
7413   v8::HandleScope scope;
7414   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7415   v8::Handle<v8::String> access_property = v8::String::New("a");
7416   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
7417   LocalContext context(NULL, templ);
7418   v8::Handle<v8::Object> global = context->Global();
7419 
7420   // Ordinary properties
7421   v8::Handle<v8::String> simple_property = v8::String::New("p");
7422   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
7423   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7424   // This should fail because the property is read-only
7425   global->Set(simple_property, v8::Int32::New(5));
7426   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7427   // This should succeed even though the property is read-only
7428   global->ForceSet(simple_property, v8::Int32::New(6));
7429   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
7430 
7431   // Accessors
7432   CHECK_EQ(0, force_set_set_count);
7433   CHECK_EQ(0, force_set_get_count);
7434   CHECK_EQ(3, global->Get(access_property)->Int32Value());
7435   // CHECK_EQ the property shouldn't override it, just call the setter
7436   // which in this case does nothing.
7437   global->Set(access_property, v8::Int32::New(7));
7438   CHECK_EQ(3, global->Get(access_property)->Int32Value());
7439   CHECK_EQ(1, force_set_set_count);
7440   CHECK_EQ(2, force_set_get_count);
7441   // Forcing the property to be set should override the accessor without
7442   // calling it
7443   global->ForceSet(access_property, v8::Int32::New(8));
7444   CHECK_EQ(8, global->Get(access_property)->Int32Value());
7445   CHECK_EQ(1, force_set_set_count);
7446   CHECK_EQ(2, force_set_get_count);
7447 }
7448 
TEST(ForceSetWithInterceptor)7449 TEST(ForceSetWithInterceptor) {
7450   force_set_get_count = 0;
7451   force_set_set_count = 0;
7452   pass_on_get = false;
7453 
7454   v8::HandleScope scope;
7455   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7456   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
7457   LocalContext context(NULL, templ);
7458   v8::Handle<v8::Object> global = context->Global();
7459 
7460   v8::Handle<v8::String> some_property = v8::String::New("a");
7461   CHECK_EQ(0, force_set_set_count);
7462   CHECK_EQ(0, force_set_get_count);
7463   CHECK_EQ(3, global->Get(some_property)->Int32Value());
7464   // Setting the property shouldn't override it, just call the setter
7465   // which in this case does nothing.
7466   global->Set(some_property, v8::Int32::New(7));
7467   CHECK_EQ(3, global->Get(some_property)->Int32Value());
7468   CHECK_EQ(1, force_set_set_count);
7469   CHECK_EQ(2, force_set_get_count);
7470   // Getting the property when the interceptor returns an empty handle
7471   // should yield undefined, since the property isn't present on the
7472   // object itself yet.
7473   pass_on_get = true;
7474   CHECK(global->Get(some_property)->IsUndefined());
7475   CHECK_EQ(1, force_set_set_count);
7476   CHECK_EQ(3, force_set_get_count);
7477   // Forcing the property to be set should cause the value to be
7478   // set locally without calling the interceptor.
7479   global->ForceSet(some_property, v8::Int32::New(8));
7480   CHECK_EQ(8, global->Get(some_property)->Int32Value());
7481   CHECK_EQ(1, force_set_set_count);
7482   CHECK_EQ(4, force_set_get_count);
7483   // Reenabling the interceptor should cause it to take precedence over
7484   // the property
7485   pass_on_get = false;
7486   CHECK_EQ(3, global->Get(some_property)->Int32Value());
7487   CHECK_EQ(1, force_set_set_count);
7488   CHECK_EQ(5, force_set_get_count);
7489   // The interceptor should also work for other properties
7490   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
7491   CHECK_EQ(1, force_set_set_count);
7492   CHECK_EQ(6, force_set_get_count);
7493 }
7494 
7495 
THREADED_TEST(ForceDelete)7496 THREADED_TEST(ForceDelete) {
7497   v8::HandleScope scope;
7498   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7499   LocalContext context(NULL, templ);
7500   v8::Handle<v8::Object> global = context->Global();
7501 
7502   // Ordinary properties
7503   v8::Handle<v8::String> simple_property = v8::String::New("p");
7504   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
7505   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7506   // This should fail because the property is dont-delete.
7507   CHECK(!global->Delete(simple_property));
7508   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
7509   // This should succeed even though the property is dont-delete.
7510   CHECK(global->ForceDelete(simple_property));
7511   CHECK(global->Get(simple_property)->IsUndefined());
7512 }
7513 
7514 
7515 static int force_delete_interceptor_count = 0;
7516 static bool pass_on_delete = false;
7517 
7518 
ForceDeleteDeleter(v8::Local<v8::String> name,const v8::AccessorInfo & info)7519 static v8::Handle<v8::Boolean> ForceDeleteDeleter(
7520     v8::Local<v8::String> name,
7521     const v8::AccessorInfo& info) {
7522   force_delete_interceptor_count++;
7523   if (pass_on_delete) {
7524     return v8::Handle<v8::Boolean>();
7525   } else {
7526     return v8::True();
7527   }
7528 }
7529 
7530 
THREADED_TEST(ForceDeleteWithInterceptor)7531 THREADED_TEST(ForceDeleteWithInterceptor) {
7532   force_delete_interceptor_count = 0;
7533   pass_on_delete = false;
7534 
7535   v8::HandleScope scope;
7536   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
7537   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
7538   LocalContext context(NULL, templ);
7539   v8::Handle<v8::Object> global = context->Global();
7540 
7541   v8::Handle<v8::String> some_property = v8::String::New("a");
7542   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
7543 
7544   // Deleting a property should get intercepted and nothing should
7545   // happen.
7546   CHECK_EQ(0, force_delete_interceptor_count);
7547   CHECK(global->Delete(some_property));
7548   CHECK_EQ(1, force_delete_interceptor_count);
7549   CHECK_EQ(42, global->Get(some_property)->Int32Value());
7550   // Deleting the property when the interceptor returns an empty
7551   // handle should not delete the property since it is DontDelete.
7552   pass_on_delete = true;
7553   CHECK(!global->Delete(some_property));
7554   CHECK_EQ(2, force_delete_interceptor_count);
7555   CHECK_EQ(42, global->Get(some_property)->Int32Value());
7556   // Forcing the property to be deleted should delete the value
7557   // without calling the interceptor.
7558   CHECK(global->ForceDelete(some_property));
7559   CHECK(global->Get(some_property)->IsUndefined());
7560   CHECK_EQ(2, force_delete_interceptor_count);
7561 }
7562 
7563 
7564 // Make sure that forcing a delete invalidates any IC stubs, so we
7565 // don't read the hole value.
THREADED_TEST(ForceDeleteIC)7566 THREADED_TEST(ForceDeleteIC) {
7567   v8::HandleScope scope;
7568   LocalContext context;
7569   // Create a DontDelete variable on the global object.
7570   CompileRun("this.__proto__ = { foo: 'horse' };"
7571              "var foo = 'fish';"
7572              "function f() { return foo.length; }");
7573   // Initialize the IC for foo in f.
7574   CompileRun("for (var i = 0; i < 4; i++) f();");
7575   // Make sure the value of foo is correct before the deletion.
7576   CHECK_EQ(4, CompileRun("f()")->Int32Value());
7577   // Force the deletion of foo.
7578   CHECK(context->Global()->ForceDelete(v8_str("foo")));
7579   // Make sure the value for foo is read from the prototype, and that
7580   // we don't get in trouble with reading the deleted cell value
7581   // sentinel.
7582   CHECK_EQ(5, CompileRun("f()")->Int32Value());
7583 }
7584 
7585 
7586 v8::Persistent<Context> calling_context0;
7587 v8::Persistent<Context> calling_context1;
7588 v8::Persistent<Context> calling_context2;
7589 
7590 
7591 // Check that the call to the callback is initiated in
7592 // calling_context2, the directly calling context is calling_context1
7593 // and the callback itself is in calling_context0.
GetCallingContextCallback(const v8::Arguments & args)7594 static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) {
7595   ApiTestFuzzer::Fuzz();
7596   CHECK(Context::GetCurrent() == calling_context0);
7597   CHECK(Context::GetCalling() == calling_context1);
7598   CHECK(Context::GetEntered() == calling_context2);
7599   return v8::Integer::New(42);
7600 }
7601 
7602 
THREADED_TEST(GetCallingContext)7603 THREADED_TEST(GetCallingContext) {
7604   v8::HandleScope scope;
7605 
7606   calling_context0 = Context::New();
7607   calling_context1 = Context::New();
7608   calling_context2 = Context::New();
7609 
7610   // Allow cross-domain access.
7611   Local<String> token = v8_str("<security token>");
7612   calling_context0->SetSecurityToken(token);
7613   calling_context1->SetSecurityToken(token);
7614   calling_context2->SetSecurityToken(token);
7615 
7616   // Create an object with a C++ callback in context0.
7617   calling_context0->Enter();
7618   Local<v8::FunctionTemplate> callback_templ =
7619       v8::FunctionTemplate::New(GetCallingContextCallback);
7620   calling_context0->Global()->Set(v8_str("callback"),
7621                                   callback_templ->GetFunction());
7622   calling_context0->Exit();
7623 
7624   // Expose context0 in context1 and setup a function that calls the
7625   // callback function.
7626   calling_context1->Enter();
7627   calling_context1->Global()->Set(v8_str("context0"),
7628                                   calling_context0->Global());
7629   CompileRun("function f() { context0.callback() }");
7630   calling_context1->Exit();
7631 
7632   // Expose context1 in context2 and call the callback function in
7633   // context0 indirectly through f in context1.
7634   calling_context2->Enter();
7635   calling_context2->Global()->Set(v8_str("context1"),
7636                                   calling_context1->Global());
7637   CompileRun("context1.f()");
7638   calling_context2->Exit();
7639 
7640   // Dispose the contexts to allow them to be garbage collected.
7641   calling_context0.Dispose();
7642   calling_context1.Dispose();
7643   calling_context2.Dispose();
7644   calling_context0.Clear();
7645   calling_context1.Clear();
7646   calling_context2.Clear();
7647 }
7648 
7649 
7650 // Check that a variable declaration with no explicit initialization
7651 // value does not shadow an existing property in the prototype chain.
7652 //
7653 // This is consistent with Firefox and Safari.
7654 //
7655 // See http://crbug.com/12548.
THREADED_TEST(InitGlobalVarInProtoChain)7656 THREADED_TEST(InitGlobalVarInProtoChain) {
7657   v8::HandleScope scope;
7658   LocalContext context;
7659   // Introduce a variable in the prototype chain.
7660   CompileRun("__proto__.x = 42");
7661   v8::Handle<v8::Value> result = CompileRun("var x; x");
7662   CHECK(!result->IsUndefined());
7663   CHECK_EQ(42, result->Int32Value());
7664 }
7665 
7666 
7667 // Regression test for issue 398.
7668 // If a function is added to an object, creating a constant function
7669 // field, and the result is cloned, replacing the constant function on the
7670 // original should not affect the clone.
7671 // See http://code.google.com/p/v8/issues/detail?id=398
THREADED_TEST(ReplaceConstantFunction)7672 THREADED_TEST(ReplaceConstantFunction) {
7673   v8::HandleScope scope;
7674   LocalContext context;
7675   v8::Handle<v8::Object> obj = v8::Object::New();
7676   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
7677   v8::Handle<v8::String> foo_string = v8::String::New("foo");
7678   obj->Set(foo_string, func_templ->GetFunction());
7679   v8::Handle<v8::Object> obj_clone = obj->Clone();
7680   obj_clone->Set(foo_string, v8::String::New("Hello"));
7681   CHECK(!obj->Get(foo_string)->IsUndefined());
7682 }
7683 
7684 
7685 // Regression test for http://crbug.com/16276.
THREADED_TEST(Regress16276)7686 THREADED_TEST(Regress16276) {
7687   v8::HandleScope scope;
7688   LocalContext context;
7689   // Force the IC in f to be a dictionary load IC.
7690   CompileRun("function f(obj) { return obj.x; }\n"
7691              "var obj = { x: { foo: 42 }, y: 87 };\n"
7692              "var x = obj.x;\n"
7693              "delete obj.y;\n"
7694              "for (var i = 0; i < 5; i++) f(obj);");
7695   // Detach the global object to make 'this' refer directly to the
7696   // global object (not the proxy), and make sure that the dictionary
7697   // load IC doesn't mess up loading directly from the global object.
7698   context->DetachGlobal();
7699   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
7700 }
7701 
7702 
THREADED_TEST(PixelArray)7703 THREADED_TEST(PixelArray) {
7704   v8::HandleScope scope;
7705   LocalContext context;
7706   const int kElementCount = 40;
7707   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
7708   i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount,
7709                                                               pixel_data);
7710   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7711   for (int i = 0; i < kElementCount; i++) {
7712     pixels->set(i, i);
7713   }
7714   i::Heap::CollectAllGarbage(false);  // Force GC to trigger verification.
7715   for (int i = 0; i < kElementCount; i++) {
7716     CHECK_EQ(i, pixels->get(i));
7717     CHECK_EQ(i, pixel_data[i]);
7718   }
7719 
7720   v8::Handle<v8::Object> obj = v8::Object::New();
7721   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
7722   // Set the elements to be the pixels.
7723   // jsobj->set_elements(*pixels);
7724   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
7725   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7726   obj->Set(v8_str("field"), v8::Int32::New(1503));
7727   context->Global()->Set(v8_str("pixels"), obj);
7728   v8::Handle<v8::Value> result = CompileRun("pixels.field");
7729   CHECK_EQ(1503, result->Int32Value());
7730   result = CompileRun("pixels[1]");
7731   CHECK_EQ(1, result->Int32Value());
7732   result = CompileRun("var sum = 0;"
7733                       "for (var i = 0; i < 8; i++) {"
7734                       "  sum += pixels[i];"
7735                       "}"
7736                       "sum;");
7737   CHECK_EQ(28, result->Int32Value());
7738 
7739   i::Handle<i::Smi> value(i::Smi::FromInt(2));
7740   i::SetElement(jsobj, 1, value);
7741   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1))->value());
7742   *value.location() = i::Smi::FromInt(256);
7743   i::SetElement(jsobj, 1, value);
7744   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(1))->value());
7745   *value.location() = i::Smi::FromInt(-1);
7746   i::SetElement(jsobj, 1, value);
7747   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7748 
7749   result = CompileRun("for (var i = 0; i < 8; i++) {"
7750                       "  pixels[i] = (i * 65) - 109;"
7751                       "}"
7752                       "pixels[1] + pixels[6];");
7753   CHECK_EQ(255, result->Int32Value());
7754   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7755   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1))->value());
7756   CHECK_EQ(21, i::Smi::cast(jsobj->GetElement(2))->value());
7757   CHECK_EQ(86, i::Smi::cast(jsobj->GetElement(3))->value());
7758   CHECK_EQ(151, i::Smi::cast(jsobj->GetElement(4))->value());
7759   CHECK_EQ(216, i::Smi::cast(jsobj->GetElement(5))->value());
7760   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(6))->value());
7761   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(7))->value());
7762   result = CompileRun("var sum = 0;"
7763                       "for (var i = 0; i < 8; i++) {"
7764                       "  sum += pixels[i];"
7765                       "}"
7766                       "sum;");
7767   CHECK_EQ(984, result->Int32Value());
7768 
7769   result = CompileRun("for (var i = 0; i < 8; i++) {"
7770                       "  pixels[i] = (i * 1.1);"
7771                       "}"
7772                       "pixels[1] + pixels[6];");
7773   CHECK_EQ(8, result->Int32Value());
7774   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0))->value());
7775   CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1))->value());
7776   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2))->value());
7777   CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3))->value());
7778   CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4))->value());
7779   CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5))->value());
7780   CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6))->value());
7781   CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7))->value());
7782 
7783   result = CompileRun("for (var i = 0; i < 8; i++) {"
7784                       "  pixels[7] = undefined;"
7785                       "}"
7786                       "pixels[7];");
7787   CHECK_EQ(0, result->Int32Value());
7788   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7))->value());
7789 
7790   result = CompileRun("for (var i = 0; i < 8; i++) {"
7791                       "  pixels[6] = '2.3';"
7792                       "}"
7793                       "pixels[6];");
7794   CHECK_EQ(2, result->Int32Value());
7795   CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6))->value());
7796 
7797   result = CompileRun("for (var i = 0; i < 8; i++) {"
7798                       "  pixels[5] = NaN;"
7799                       "}"
7800                       "pixels[5];");
7801   CHECK_EQ(0, result->Int32Value());
7802   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5))->value());
7803 
7804   result = CompileRun("for (var i = 0; i < 8; i++) {"
7805                       "  pixels[8] = Infinity;"
7806                       "}"
7807                       "pixels[8];");
7808   CHECK_EQ(255, result->Int32Value());
7809   CHECK_EQ(255, i::Smi::cast(jsobj->GetElement(8))->value());
7810 
7811   result = CompileRun("for (var i = 0; i < 8; i++) {"
7812                       "  pixels[9] = -Infinity;"
7813                       "}"
7814                       "pixels[9];");
7815   CHECK_EQ(0, result->Int32Value());
7816   CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9))->value());
7817 
7818   result = CompileRun("pixels[3] = 33;"
7819                       "delete pixels[3];"
7820                       "pixels[3];");
7821   CHECK_EQ(33, result->Int32Value());
7822 
7823   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
7824                       "pixels[2] = 12; pixels[3] = 13;"
7825                       "pixels.__defineGetter__('2',"
7826                       "function() { return 120; });"
7827                       "pixels[2];");
7828   CHECK_EQ(12, result->Int32Value());
7829 
7830   result = CompileRun("var js_array = new Array(40);"
7831                       "js_array[0] = 77;"
7832                       "js_array;");
7833   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
7834 
7835   result = CompileRun("pixels[1] = 23;"
7836                       "pixels.__proto__ = [];"
7837                       "js_array.__proto__ = pixels;"
7838                       "js_array.concat(pixels);");
7839   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
7840   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
7841 
7842   free(pixel_data);
7843 }
7844 
7845 
THREADED_TEST(ScriptContextDependence)7846 THREADED_TEST(ScriptContextDependence) {
7847   v8::HandleScope scope;
7848   LocalContext c1;
7849   const char *source = "foo";
7850   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
7851   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
7852   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
7853   CHECK_EQ(dep->Run()->Int32Value(), 100);
7854   CHECK_EQ(indep->Run()->Int32Value(), 100);
7855   LocalContext c2;
7856   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
7857   CHECK_EQ(dep->Run()->Int32Value(), 100);
7858   CHECK_EQ(indep->Run()->Int32Value(), 101);
7859 }
7860 
7861 
THREADED_TEST(StackTrace)7862 THREADED_TEST(StackTrace) {
7863   v8::HandleScope scope;
7864   LocalContext context;
7865   v8::TryCatch try_catch;
7866   const char *source = "function foo() { FAIL.FAIL; }; foo();";
7867   v8::Handle<v8::String> src = v8::String::New(source);
7868   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
7869   v8::Script::New(src, origin)->Run();
7870   CHECK(try_catch.HasCaught());
7871   v8::String::Utf8Value stack(try_catch.StackTrace());
7872   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
7873 }
7874 
7875 
7876 // Test that idle notification can be handled when V8 has not yet been
7877 // set up.
THREADED_TEST(IdleNotification)7878 THREADED_TEST(IdleNotification) {
7879   for (int i = 0; i < 100; i++) v8::V8::IdleNotification(true);
7880   for (int i = 0; i < 100; i++) v8::V8::IdleNotification(false);
7881 }
7882